Skip to content

Instantly share code, notes, and snippets.

@kosalvann
Created June 17, 2020 04:14
Show Gist options
  • Select an option

  • Save kosalvann/c36ea719f299b0c46019d48abd225fda to your computer and use it in GitHub Desktop.

Select an option

Save kosalvann/c36ea719f299b0c46019d48abd225fda to your computer and use it in GitHub Desktop.

Revisions

  1. kosalvann created this gist Jun 17, 2020.
    877 changes: 877 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,877 @@
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta name="description" content="A random password generator tool">
    <meta name="viewport" content="width=device-width">
    <title>Random Password Generator</title>
    <link href="https://fonts.googleapis.com/css2?family=Material+Icons&PT+Mono&Roboto:wght@400;700&display=swap" rel="stylesheet">
    <style id="jsbin-css">
    *, :after, :before {
    font-size: 0.90rem;
    font-family: 'Roboto', arial, sans-serif;
    box-sizing: border-box;
    -moz-osx-font-smoothing: grayscale;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    }

    html, body {
    padding: 0;
    margin: 0;
    background-color: #ffffff;
    height: 100%;
    box-sizing: border-box;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    }
    body {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: #f3f7fa;
    background: linear-gradient(345deg, #f3f7fa 0%, #ffffff 100%);
    }
    body * {
    color: #2a354f;
    font-family: 'Roboto', arial, sans-serif;
    line-height: 1.43;
    letter-spacing: 0.025em;
    box-sizing: border-box;
    -webkit-transition: all 0.5s;
    transition: all 0.5s;
    }
    #app {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 20px;
    width: 80%;
    height: 100%;
    font-size: 15px;
    font-family: arial,sans-serif;
    line-height: 1.2;
    }
    h2 {
    display: flex;
    flex-direction: row;
    align-items: center;
    font-size: 18px;
    color: #2b78fe;
    letter-spacing: -0.015em;
    font-weight: 600;
    line-height: 1.8;
    }
    h2 .material-icons {
    margin-right: 6px;
    color: #2b78fe;
    }
    .container {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 100%;
    background-color: #ffffff;
    border-radius: 5px;
    border: 1px solid #ddd;
    }
    section {
    display: flex;
    flex-direction: row;
    align-items: stretch;
    justify-content: center;
    width: 100%;
    }
    section.head {
    border-bottom: 1px solid #ddd;
    }
    .password {
    display: flex;
    align-items: center;
    flex: 1;
    padding: 10px 20px;
    font-size: 17px;
    font-family: 'PT Mono', monospace;
    color: #666;
    letter-spacing: 0.05em;
    border: 0 none;
    outline: none;
    border-top-left-radius:5px;
    -webkit-transition: all 0.5s;
    transition: all 0.5s;
    }
    .head.selected .password {
    color: #000;
    background: #f6f6f6;
    }
    .head .icon {
    padding: 10px;
    cursor: pointer;
    border-left: 1px solid #ddd;
    }
    .head.selected .icon {
    color: #11ab7c;
    }
    section.settings {
    padding: 20px;
    }
    section.settings > div {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    margin: 0 7px;
    }
    section.settings .material-icons {
    margin-right: 5px;
    color: #2a354f;
    }
    section.settings .symbols {
    cursor: pointer;
    }
    .material-icons {
    font-family: 'Material Icons';
    font-weight: normal;
    font-style: normal;
    font-size: 24px;
    display: inline-block;
    line-height: 1;
    text-transform: none;
    letter-spacing: normal;
    word-wrap: normal;
    white-space: nowrap;
    direction: ltr;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    -moz-osx-font-smoothing: grayscale;
    font-feature-settings: 'liga';
    }

    section.range {
    flex-direction: row;
    align-items: center;
    justify-content: center;
    border-bottom: 1px solid #ddd;
    padding-right: 20px;
    }
    section.range .output {
    flex: 1 auto;
    text-align: center;
    margin-right: 20px;
    padding: 10px 20px;
    font-size: 13px;
    color: #ddd;
    border-right: 1px solid #ddd;
    }
    section.range .output .value {
    font-size: 17px;
    font-weight: 600;
    font-family: 'PT Mono', monospace;
    color: #333;
    }
    input[type="range"] {
    -webkit-appearance: none;
    width: 85%;
    height: 100%;
    background: transparent;
    }
    input[type="range"]:focus {
    outline: none;
    }
    input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    height: 24px;
    width: 24px;
    border-radius: 50%;
    background: #ffffff;
    margin-top: -10px;
    border: 2px solid rgba(0, 0, 0, 0.2);
    cursor: pointer;
    }
    input[type="range"]::-webkit-slider-runnable-track {
    width: 60%;
    height: 5px;
    background: rgba(0, 0, 0, 0.1);
    border-radius: 3rem;
    cursor: pointer;
    }
    input[type="range"]::-ms-track {
    width: 60%;
    cursor: pointer;
    height: 9px;
    -ms-transition: all 0.5s;
    transition: all 0.5s;
    background: transparent;
    border-color: transparent;
    color: transparent;
    }
    input[type="range"]::-ms-thumb {
    height: 16px;
    width: 16px;
    border-radius: 50%;
    background: #ffffff;
    margin-top: -5px;
    box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
    cursor: pointer;
    }
    input[type="range"]::-ms-fill-lower {
    background: #bdbdbd;
    border-radius: 3rem;
    }
    input[type="range"]:focus::-ms-fill-lower {
    background: #ff6e40;
    }
    input[type="range"]::-ms-fill-upper {
    background: #bdbdbd;
    border-radius: 3rem;
    }
    input[type="range"]:focus::-ms-fill-upper {
    background: #ff6e40;
    }
    input[type="range"]::-moz-range-thumb {
    height: 16px;
    width: 16px;
    border-radius: 50%;
    background: #ffffff;
    margin-top: -5px;
    box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
    cursor: pointer;
    }
    input[type="range"]::-moz-range-track {
    width: 60%;
    height: 9px;
    background: #bdbdbd;
    border-radius: 3rem;
    -moz-transition: all 0.5s;
    transition: all 0.5s;
    cursor: pointer;
    }
    input[type="range"]:hover::-moz-range-track {
    background: #ff6e40;
    }

    /*
    * Media Query
    */
    @media only screen and (max-width: 528px) {
    #app,
    .container {
    width: 100%;
    }
    h2 {
    font-size: 17px
    }
    section.head {
    flex-direction: column;
    }
    .password {
    flex: 1;
    border-top-right-radius: 5px;
    text-align: center;
    }
    .head .button.icon {
    display: none;
    }
    }
    </style>
    </head>
    <body>
    <div id="app">
    <h2><span class="material-icons">security</span>Password Generator</h2>
    <div class="container">
    <section class="head">
    <input class="password" id="password" readonly="readonly"/>
    <span class="copy button material-icons icon">sync</span>
    </section>
    <section class="range">
    <div class="output">
    <div>Length</div>
    <span class="value">16</span>
    </div>
    <input id="slider" type="range" min="6" max="35" value="16">
    </section>
    <section class="settings">
    <div class="letters">
    <span class="material-icons">radio_button_checked</span>
    <label>Letters</label>
    </div>
    <div class="numbers">
    <span class="material-icons">radio_button_checked</span>
    <label>Numbers</label>
    </div>
    <div class="symbols">
    <span class="material-icons">radio_button_unchecked</span>
    <label>Symbols</label>
    </div>
    </section>
    </div>
    </div>
    <script id="jsbin-javascript">
    let // Global variables
    headSection = document.querySelector('.head')
    , password = document.querySelector('.password')
    , button = document.querySelector('.copy.button')
    , symbolsButton = document.querySelector('.settings .symbols')
    , symbolsCheckBox = document.querySelector('.symbols .material-icons')
    , slider = document.querySelector('#slider')
    , sliderValue = document.querySelector('.output .value')
    // The initial state of the settings
    , selectionState = {
    'symbols': false
    };

    /*
    * The alphanumeric characters and symbols
    * used to generate passwords
    */
    const CHARSET = {
    'numeric' : '0123456789',
    'alpha': 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
    'symbols': '/^_@&[<->]\:{.+},$'
    };


    /*
    * Load the functions to generate the password
    */
    window.onload = (e) => {
    password.value = renderPassword(slider.value, selectionState['symbols']);
    // Regenerate password on these events
    changePasswordOnSlide(e);
    reloadPassword(e);
    symbolButtonHandler(e);
    };


    /*
    * Toggle the symbol button between true/false state
    */
    const symbolButtonHandler = (e) => {
    symbolsButton.addEventListener('click', (e) => {
    let renderSymbol = selectionState['symbols'] = !selectionState['symbols'];
    password.value = renderPassword(slider.value, renderSymbol);

    // Disable/enable symbols in password
    symbolsCheckBox.textContent
    = selectionState['symbols']
    ? 'radio_button_checked'
    : 'radio_button_unchecked';
    });
    }


    /*
    * Handle the copy-to-clipboard functionality
    */
    const copyToClipboard = () => {
    // Select & copy the password value
    button.innerText = 'assignment_turned_in';
    password.select();
    document.execCommand('copy');
    // Return to original state
    setTimeout(() => {
    button.innerText = 'sync';
    headSection.classList.remove('selected');
    }, 400);
    }


    /*
    * The logic to generate a random string
    *
    * @param charset String characters use for the password
    * @param len The desired length of the password via the slider
    */
    const generatePassword = (charset, len) => {
    var result = "";
    for (var i = 0; i < len; i++) {
    result += charset[Math.floor(Math.random() * 52 + 1)];
    }
    // Ensure we only return the exact length
    return result.substr(0, len);
    }


    /*
    * The logic to regenerate password when using the slider
    */
    const changePasswordOnSlide = (e) => {
    slider.oninput = (e) => {
    sliderValue.textContent = slider.value;
    setTimeout(() => {
    // Generate password on slide
    password.value = renderPassword(slider.value);
    headSection.classList.add('selected');
    copyToClipboard();
    // Return to original state
    setTimeout(() => {
    headSection.classList.remove('selected');
    }, 400);
    }, 0)
    };
    }


    /*
    * The logic to regenerate password when
    * the reload button is clicked
    */
    const reloadPassword = (e) => {
    button.addEventListener('click', (e) => {
    setTimeout(() => {
    copyToClipboard();
    }, 0
    , password.value = renderPassword(slider.value)
    , headSection.classList.add('selected')
    )
    })
    }


    /*
    * Determine if the symbol is enabled and merge all of the combined
    * alphanumeric characters and symbol from the charset
    *
    * @param len The desired length of the password via the slider
    * @param renderSymbols Determined if symbol are included in the password
    */
    const renderPassword = (len, renderSymbols = selectionState['symbols']) => {
    let charSet = CHARSET['numeric'].split('').concat(
    renderSymbols ? CHARSET['symbols'].split('') : [],
    CHARSET['alpha'].split('')
    );
    return generatePassword(charSet, len)
    }
    </script>


    <script id="jsbin-source-css" type="text/css">*, :after, :before {
    font-size: 0.90rem;
    font-family: 'Roboto', arial, sans-serif;
    box-sizing: border-box;
    -moz-osx-font-smoothing: grayscale;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    }

    html, body {
    padding: 0;
    margin: 0;
    background-color: #ffffff;
    height: 100%;
    box-sizing: border-box;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    }
    body {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: #f3f7fa;
    background: linear-gradient(345deg, #f3f7fa 0%, #ffffff 100%);
    }
    body * {
    color: #2a354f;
    font-family: 'Roboto', arial, sans-serif;
    line-height: 1.43;
    letter-spacing: 0.025em;
    box-sizing: border-box;
    -webkit-transition: all 0.5s;
    transition: all 0.5s;
    }
    #app {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 20px;
    width: 80%;
    height: 100%;
    font-size: 15px;
    font-family: arial,sans-serif;
    line-height: 1.2;
    }
    h2 {
    display: flex;
    flex-direction: row;
    align-items: center;
    font-size: 18px;
    color: #2b78fe;
    letter-spacing: -0.015em;
    font-weight: 600;
    line-height: 1.8;
    }
    h2 .material-icons {
    margin-right: 6px;
    color: #2b78fe;
    }
    .container {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 100%;
    background-color: #ffffff;
    border-radius: 5px;
    border: 1px solid #ddd;
    }
    section {
    display: flex;
    flex-direction: row;
    align-items: stretch;
    justify-content: center;
    width: 100%;
    }
    section.head {
    border-bottom: 1px solid #ddd;
    }
    .password {
    display: flex;
    align-items: center;
    flex: 1;
    padding: 10px 20px;
    font-size: 17px;
    font-family: 'PT Mono', monospace;
    color: #666;
    letter-spacing: 0.05em;
    border: 0 none;
    outline: none;
    border-top-left-radius:5px;
    -webkit-transition: all 0.5s;
    transition: all 0.5s;
    }
    .head.selected .password {
    color: #000;
    background: #f6f6f6;
    }
    .head .icon {
    padding: 10px;
    cursor: pointer;
    border-left: 1px solid #ddd;
    }
    .head.selected .icon {
    color: #11ab7c;
    }
    section.settings {
    padding: 20px;
    }
    section.settings > div {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    margin: 0 7px;
    }
    section.settings .material-icons {
    margin-right: 5px;
    color: #2a354f;
    }
    section.settings .symbols {
    cursor: pointer;
    }
    .material-icons {
    font-family: 'Material Icons';
    font-weight: normal;
    font-style: normal;
    font-size: 24px;
    display: inline-block;
    line-height: 1;
    text-transform: none;
    letter-spacing: normal;
    word-wrap: normal;
    white-space: nowrap;
    direction: ltr;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    -moz-osx-font-smoothing: grayscale;
    font-feature-settings: 'liga';
    }

    section.range {
    flex-direction: row;
    align-items: center;
    justify-content: center;
    border-bottom: 1px solid #ddd;
    padding-right: 20px;
    }
    section.range .output {
    flex: 1 auto;
    text-align: center;
    margin-right: 20px;
    padding: 10px 20px;
    font-size: 13px;
    color: #ddd;
    border-right: 1px solid #ddd;
    }
    section.range .output .value {
    font-size: 17px;
    font-weight: 600;
    font-family: 'PT Mono', monospace;
    color: #333;
    }
    input[type="range"] {
    -webkit-appearance: none;
    width: 85%;
    height: 100%;
    background: transparent;
    }
    input[type="range"]:focus {
    outline: none;
    }
    input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    height: 24px;
    width: 24px;
    border-radius: 50%;
    background: #ffffff;
    margin-top: -10px;
    border: 2px solid rgba(0, 0, 0, 0.2);
    cursor: pointer;
    }
    input[type="range"]::-webkit-slider-runnable-track {
    width: 60%;
    height: 5px;
    background: rgba(0, 0, 0, 0.1);
    border-radius: 3rem;
    cursor: pointer;
    }
    input[type="range"]::-ms-track {
    width: 60%;
    cursor: pointer;
    height: 9px;
    -ms-transition: all 0.5s;
    transition: all 0.5s;
    background: transparent;
    border-color: transparent;
    color: transparent;
    }
    input[type="range"]::-ms-thumb {
    height: 16px;
    width: 16px;
    border-radius: 50%;
    background: #ffffff;
    margin-top: -5px;
    box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
    cursor: pointer;
    }
    input[type="range"]::-ms-fill-lower {
    background: #bdbdbd;
    border-radius: 3rem;
    }
    input[type="range"]:focus::-ms-fill-lower {
    background: #ff6e40;
    }
    input[type="range"]::-ms-fill-upper {
    background: #bdbdbd;
    border-radius: 3rem;
    }
    input[type="range"]:focus::-ms-fill-upper {
    background: #ff6e40;
    }
    input[type="range"]::-moz-range-thumb {
    height: 16px;
    width: 16px;
    border-radius: 50%;
    background: #ffffff;
    margin-top: -5px;
    box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
    cursor: pointer;
    }
    input[type="range"]::-moz-range-track {
    width: 60%;
    height: 9px;
    background: #bdbdbd;
    border-radius: 3rem;
    -moz-transition: all 0.5s;
    transition: all 0.5s;
    cursor: pointer;
    }
    input[type="range"]:hover::-moz-range-track {
    background: #ff6e40;
    }

    /*
    * Media Query
    */
    @media only screen and (max-width: 528px) {
    #app,
    .container {
    width: 100%;
    }
    h2 {
    font-size: 17px
    }
    section.head {
    flex-direction: column;
    }
    .password {
    flex: 1;
    border-top-right-radius: 5px;
    text-align: center;
    }
    .head .button.icon {
    display: none;
    }
    }




    </script>

    <script id="jsbin-source-javascript" type="text/javascript">let // Global variables
    headSection = document.querySelector('.head')
    , password = document.querySelector('.password')
    , button = document.querySelector('.copy.button')
    , symbolsButton = document.querySelector('.settings .symbols')
    , symbolsCheckBox = document.querySelector('.symbols .material-icons')
    , slider = document.querySelector('#slider')
    , sliderValue = document.querySelector('.output .value')
    // The initial state of the settings
    , selectionState = {
    'symbols': false
    };

    /*
    * The alphanumeric characters and symbols
    * used to generate passwords
    */
    const CHARSET = {
    'numeric' : '0123456789',
    'alpha': 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
    'symbols': '/^_@&[<->]\:{.+},$'
    };


    /*
    * Load the functions to generate the password
    */
    window.onload = (e) => {
    password.value = renderPassword(slider.value, selectionState['symbols']);
    // Regenerate password on these events
    changePasswordOnSlide(e);
    reloadPassword(e);
    symbolButtonHandler(e);
    };


    /*
    * Toggle the symbol button between true/false state
    */
    const symbolButtonHandler = (e) => {
    symbolsButton.addEventListener('click', (e) => {
    let renderSymbol = selectionState['symbols'] = !selectionState['symbols'];
    password.value = renderPassword(slider.value, renderSymbol);

    // Disable/enable symbols in password
    symbolsCheckBox.textContent
    = selectionState['symbols']
    ? 'radio_button_checked'
    : 'radio_button_unchecked';
    });
    }


    /*
    * Handle the copy-to-clipboard functionality
    */
    const copyToClipboard = () => {
    // Select & copy the password value
    button.innerText = 'assignment_turned_in';
    password.select();
    document.execCommand('copy');
    // Return to original state
    setTimeout(() => {
    button.innerText = 'sync';
    headSection.classList.remove('selected');
    }, 400);
    }


    /*
    * The logic to generate a random string
    *
    * @param charset String characters use for the password
    * @param len The desired length of the password via the slider
    */
    const generatePassword = (charset, len) => {
    var result = "";
    for (var i = 0; i < len; i++) {
    result += charset[Math.floor(Math.random() * 52 + 1)];
    }
    // Ensure we only return the exact length
    return result.substr(0, len);
    }


    /*
    * The logic to regenerate password when using the slider
    */
    const changePasswordOnSlide = (e) => {
    slider.oninput = (e) => {
    sliderValue.textContent = slider.value;
    setTimeout(() => {
    // Generate password on slide
    password.value = renderPassword(slider.value);
    headSection.classList.add('selected');
    copyToClipboard();
    // Return to original state
    setTimeout(() => {
    headSection.classList.remove('selected');
    }, 400);
    }, 0)
    };
    }


    /*
    * The logic to regenerate password when
    * the reload button is clicked
    */
    const reloadPassword = (e) => {
    button.addEventListener('click', (e) => {
    setTimeout(() => {
    copyToClipboard();
    }, 0
    , password.value = renderPassword(slider.value)
    , headSection.classList.add('selected')
    )
    })
    }


    /*
    * Determine if the symbol is enabled and merge all of the combined
    * alphanumeric characters and symbol from the charset
    *
    * @param len The desired length of the password via the slider
    * @param renderSymbols Determined if symbol are included in the password
    */
    const renderPassword = (len, renderSymbols = selectionState['symbols']) => {
    let charSet = CHARSET['numeric'].split('').concat(
    renderSymbols ? CHARSET['symbols'].split('') : [],
    CHARSET['alpha'].split('')
    );
    return generatePassword(charSet, len)
    }















    </script></body>
    </html>
    269 changes: 269 additions & 0 deletions jsbin.juriwij.css
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,269 @@
    *, :after, :before {
    font-size: 0.90rem;
    font-family: 'Roboto', arial, sans-serif;
    box-sizing: border-box;
    -moz-osx-font-smoothing: grayscale;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    }

    html, body {
    padding: 0;
    margin: 0;
    background-color: #ffffff;
    height: 100%;
    box-sizing: border-box;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    }
    body {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: #f3f7fa;
    background: linear-gradient(345deg, #f3f7fa 0%, #ffffff 100%);
    }
    body * {
    color: #2a354f;
    font-family: 'Roboto', arial, sans-serif;
    line-height: 1.43;
    letter-spacing: 0.025em;
    box-sizing: border-box;
    -webkit-transition: all 0.5s;
    transition: all 0.5s;
    }
    #app {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 20px;
    width: 80%;
    height: 100%;
    font-size: 15px;
    font-family: arial,sans-serif;
    line-height: 1.2;
    }
    h2 {
    display: flex;
    flex-direction: row;
    align-items: center;
    font-size: 18px;
    color: #2b78fe;
    letter-spacing: -0.015em;
    font-weight: 600;
    line-height: 1.8;
    }
    h2 .material-icons {
    margin-right: 6px;
    color: #2b78fe;
    }
    .container {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 100%;
    background-color: #ffffff;
    border-radius: 5px;
    border: 1px solid #ddd;
    }
    section {
    display: flex;
    flex-direction: row;
    align-items: stretch;
    justify-content: center;
    width: 100%;
    }
    section.head {
    border-bottom: 1px solid #ddd;
    }
    .password {
    display: flex;
    align-items: center;
    flex: 1;
    padding: 10px 20px;
    font-size: 17px;
    font-family: 'PT Mono', monospace;
    color: #666;
    letter-spacing: 0.05em;
    border: 0 none;
    outline: none;
    border-top-left-radius:5px;
    -webkit-transition: all 0.5s;
    transition: all 0.5s;
    }
    .head.selected .password {
    color: #000;
    background: #f6f6f6;
    }
    .head .icon {
    padding: 10px;
    cursor: pointer;
    border-left: 1px solid #ddd;
    }
    .head.selected .icon {
    color: #11ab7c;
    }
    section.settings {
    padding: 20px;
    }
    section.settings > div {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    margin: 0 7px;
    }
    section.settings .material-icons {
    margin-right: 5px;
    color: #2a354f;
    }
    section.settings .symbols {
    cursor: pointer;
    }
    .material-icons {
    font-family: 'Material Icons';
    font-weight: normal;
    font-style: normal;
    font-size: 24px;
    display: inline-block;
    line-height: 1;
    text-transform: none;
    letter-spacing: normal;
    word-wrap: normal;
    white-space: nowrap;
    direction: ltr;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    -moz-osx-font-smoothing: grayscale;
    font-feature-settings: 'liga';
    }

    section.range {
    flex-direction: row;
    align-items: center;
    justify-content: center;
    border-bottom: 1px solid #ddd;
    padding-right: 20px;
    }
    section.range .output {
    flex: 1 auto;
    text-align: center;
    margin-right: 20px;
    padding: 10px 20px;
    font-size: 13px;
    color: #ddd;
    border-right: 1px solid #ddd;
    }
    section.range .output .value {
    font-size: 17px;
    font-weight: 600;
    font-family: 'PT Mono', monospace;
    color: #333;
    }
    input[type="range"] {
    -webkit-appearance: none;
    width: 85%;
    height: 100%;
    background: transparent;
    }
    input[type="range"]:focus {
    outline: none;
    }
    input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    height: 24px;
    width: 24px;
    border-radius: 50%;
    background: #ffffff;
    margin-top: -10px;
    border: 2px solid rgba(0, 0, 0, 0.2);
    cursor: pointer;
    }
    input[type="range"]::-webkit-slider-runnable-track {
    width: 60%;
    height: 5px;
    background: rgba(0, 0, 0, 0.1);
    border-radius: 3rem;
    cursor: pointer;
    }
    input[type="range"]::-ms-track {
    width: 60%;
    cursor: pointer;
    height: 9px;
    -ms-transition: all 0.5s;
    transition: all 0.5s;
    background: transparent;
    border-color: transparent;
    color: transparent;
    }
    input[type="range"]::-ms-thumb {
    height: 16px;
    width: 16px;
    border-radius: 50%;
    background: #ffffff;
    margin-top: -5px;
    box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
    cursor: pointer;
    }
    input[type="range"]::-ms-fill-lower {
    background: #bdbdbd;
    border-radius: 3rem;
    }
    input[type="range"]:focus::-ms-fill-lower {
    background: #ff6e40;
    }
    input[type="range"]::-ms-fill-upper {
    background: #bdbdbd;
    border-radius: 3rem;
    }
    input[type="range"]:focus::-ms-fill-upper {
    background: #ff6e40;
    }
    input[type="range"]::-moz-range-thumb {
    height: 16px;
    width: 16px;
    border-radius: 50%;
    background: #ffffff;
    margin-top: -5px;
    box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
    cursor: pointer;
    }
    input[type="range"]::-moz-range-track {
    width: 60%;
    height: 9px;
    background: #bdbdbd;
    border-radius: 3rem;
    -moz-transition: all 0.5s;
    transition: all 0.5s;
    cursor: pointer;
    }
    input[type="range"]:hover::-moz-range-track {
    background: #ff6e40;
    }

    /*
    * Media Query
    */
    @media only screen and (max-width: 528px) {
    #app,
    .container {
    width: 100%;
    }
    h2 {
    font-size: 17px
    }
    section.head {
    flex-direction: column;
    }
    .password {
    flex: 1;
    border-top-right-radius: 5px;
    text-align: center;
    }
    .head .button.icon {
    display: none;
    }
    }
    135 changes: 135 additions & 0 deletions jsbin.juriwij.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,135 @@
    let // Global variables
    headSection = document.querySelector('.head')
    , password = document.querySelector('.password')
    , button = document.querySelector('.copy.button')
    , symbolsButton = document.querySelector('.settings .symbols')
    , symbolsCheckBox = document.querySelector('.symbols .material-icons')
    , slider = document.querySelector('#slider')
    , sliderValue = document.querySelector('.output .value')
    // The initial state of the settings
    , selectionState = {
    'symbols': false
    };

    /*
    * The alphanumeric characters and symbols
    * used to generate passwords
    */
    const CHARSET = {
    'numeric' : '0123456789',
    'alpha': 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
    'symbols': '/^_@&[<->]\:{.+},$'
    };


    /*
    * Load the functions to generate the password
    */
    window.onload = (e) => {
    password.value = renderPassword(slider.value, selectionState['symbols']);
    // Regenerate password on these events
    changePasswordOnSlide(e);
    reloadPassword(e);
    symbolButtonHandler(e);
    };


    /*
    * Toggle the symbol button between true/false state
    */
    const symbolButtonHandler = (e) => {
    symbolsButton.addEventListener('click', (e) => {
    let renderSymbol = selectionState['symbols'] = !selectionState['symbols'];
    password.value = renderPassword(slider.value, renderSymbol);

    // Disable/enable symbols in password
    symbolsCheckBox.textContent
    = selectionState['symbols']
    ? 'radio_button_checked'
    : 'radio_button_unchecked';
    });
    }


    /*
    * Handle the copy-to-clipboard functionality
    */
    const copyToClipboard = () => {
    // Select & copy the password value
    button.innerText = 'assignment_turned_in';
    password.select();
    document.execCommand('copy');
    // Return to original state
    setTimeout(() => {
    button.innerText = 'sync';
    headSection.classList.remove('selected');
    }, 400);
    }


    /*
    * The logic to generate a random string
    *
    * @param charset String characters use for the password
    * @param len The desired length of the password via the slider
    */
    const generatePassword = (charset, len) => {
    var result = "";
    for (var i = 0; i < len; i++) {
    result += charset[Math.floor(Math.random() * 52 + 1)];
    }
    // Ensure we only return the exact length
    return result.substr(0, len);
    }


    /*
    * The logic to regenerate password when using the slider
    */
    const changePasswordOnSlide = (e) => {
    slider.oninput = (e) => {
    sliderValue.textContent = slider.value;
    setTimeout(() => {
    // Generate password on slide
    password.value = renderPassword(slider.value);
    headSection.classList.add('selected');
    copyToClipboard();
    // Return to original state
    setTimeout(() => {
    headSection.classList.remove('selected');
    }, 400);
    }, 0)
    };
    }


    /*
    * The logic to regenerate password when
    * the reload button is clicked
    */
    const reloadPassword = (e) => {
    button.addEventListener('click', (e) => {
    setTimeout(() => {
    copyToClipboard();
    }, 0
    , password.value = renderPassword(slider.value)
    , headSection.classList.add('selected')
    )
    })
    }


    /*
    * Determine if the symbol is enabled and merge all of the combined
    * alphanumeric characters and symbol from the charset
    *
    * @param len The desired length of the password via the slider
    * @param renderSymbols Determined if symbol are included in the password
    */
    const renderPassword = (len, renderSymbols = selectionState['symbols']) => {
    let charSet = CHARSET['numeric'].split('').concat(
    renderSymbols ? CHARSET['symbols'].split('') : [],
    CHARSET['alpha'].split('')
    );
    return generatePassword(charSet, len)
    }