<commit_before>/**
 * Module Name: Github
 * Description: Retrieves interesting Github information
 */
var request = require('request'),
    _ = require('underscore')._;

var github = function(dbot) {
    var commands = {
        '~repocount': function(event) {
        // TODO: add handling for non existent user
            var reqUrl = "https://api.github.com/users/" + event.params[1] + "/repos";
            request(reqUrl, function(error, response, body) {
            var result = JSON.parse(body);
			event.reply(event.params[1] + " has " + result.length + " public repositories.");
            });
        },
        '~repo': function(event) {
            var repo = "";
            if (typeof event.params[1] == 'undefined') {
                repo = dbot.config.github.defaultrepo;
            } else {
                repo = event.params[1];
            }

            var reqUrl = "https://api.github.com/";
            reqUrl += "repos/" + repo;

            request(reqUrl, function(error, response, body) {
                var data = JSON.parse(body);
                if (data["fork"] == true) {
                   event.reply(dbot.t("forkedrepo",data));
                } else {
                    event.reply(dbot.t("unforkedrepo",data));
                }
                // TODO: move this shizz into an api call
                var longurl = "http://github.com/" + repo;
                request({method: 'POST', uri: 'http://git.io', form:{url: longurl}}, function(error, response, body){
                    event.reply(dbot.t('location')+" "+response.headers["location"]);
                });
            });
        },
        '~gstatus': function(event) {
            var reqUrl = "https://status.github.com/api/last-message.json";
            request(reqUrl, function(error,response,body){
                var data = JSON.parse(body);
                event.reply(dbot.t("status"+data["status"]));
                event.reply(data["body"]);
            });
        },
        '~milestone': function(event) {
            var repo = dbot.config.github.defaultrepo;
            var reqUrl = "https://api.github.com/repos/";
            reqUrl += repo + "/milestones";

            request(reqUrl, function(error, response, body) {
                var data = JSON.parse(body);
                for (var section in data) {
                    var milestone = data[section];
                    if (milestone["title"] == event.params[1]){
                        var str = "Milestone " + milestone["title"];
                        var progress = milestone["closed_issues"] / (milestone["open_issues"] + milestone["closed_issues"]);
                        progress = Math.round(progress*100);
                        var bar = "[";
                        for (var i = 1; i < 10; i++) {
                            if  ((progress / (i*10)) > 1) {
                                bar += "█";
                            } else {
                                bar += " ";
                            }
                        }
                        bar += "]";
                        str += " is " + bar + progress + "% complete";

                        var longurl = "http://github.com/" + repo + "/issues?milestone=" + milestone["number"];
                        request({method: 'POST', uri: 'http://git.io', form:{url: longurl}}, function(error, response, body){
                            event.reply(response.headers["location"]);
                        });
                        event.reply(str);
                        break;
                    }
                }
           });
        },
/*        '~repo': function(event) {
            var repo = "";
            if (typeof event.params[1] == 'undefined') {
                repo = dbot.config.github.defaultrepo;
            } else {
                repo = event.params[1];
            }

            var reqUrl = "https://api.github.com/";
            reqUrl += "repos/" + repo;

            request(reqUrl, function(error, response, body) {
                var data = JSON.parse(body);
                var str = "";
                str += data["name"] + " is a ";
                if (data["fork"] == true) {
                    str += "forked ";
                }
                str += data["language"];
                str += " repo with ";
                str += data["open_issues"] + " unresolved issues. ";
                str += "[" + data["forks"] + "F " + data["watchers"] + "W]";

                event.reply(str);
            });
        },*/
        '~repocount': function(event) {
        // TODO: add handling for non existent user
            var reqUrl = "https://api.github.com/users/" + event.params[1] + "/repos";
            request(reqUrl, function(error, response, body) {
            var result = JSON.parse(body);
			event.reply(event.params[1] + " has " + result.length + " public repositories.");
            });
        }
    };
    this.commands = commands;

    this.on = 'PRIVMSG';
};

exports.fetch = function(dbot) {
    return new github(dbot);
};
<commit_msg>remove duped commented out code<commit_after>/**
 * Module Name: Github
 * Description: Retrieves interesting Github information
 */
var request = require('request'),
    _ = require('underscore')._;

var github = function(dbot) {
    var commands = {
        '~repocount': function(event) {
        // TODO: add handling for non existent user
            var reqUrl = "https://api.github.com/users/" + event.params[1] + "/repos";
            request(reqUrl, function(error, response, body) {
            var result = JSON.parse(body);
			event.reply(event.params[1] + " has " + result.length + " public repositories.");
            });
        },
        '~repo': function(event) {
            var repo = "";
            if (typeof event.params[1] == 'undefined') {
                repo = dbot.config.github.defaultrepo;
            } else {
                repo = event.params[1];
            }

            var reqUrl = "https://api.github.com/";
            reqUrl += "repos/" + repo;

            request(reqUrl, function(error, response, body) {
                var data = JSON.parse(body);
                if (data["fork"] == true) {
                   event.reply(dbot.t("forkedrepo",data));
                } else {
                    event.reply(dbot.t("unforkedrepo",data));
                }
                // TODO: move this shizz into an api call
                var longurl = "http://github.com/" + repo;
                request({method: 'POST', uri: 'http://git.io', form:{url: longurl}}, function(error, response, body){
                    event.reply(dbot.t('location')+" "+response.headers["location"]);
                });
            });
        },
        '~gstatus': function(event) {
            var reqUrl = "https://status.github.com/api/last-message.json";
            request(reqUrl, function(error,response,body){
                var data = JSON.parse(body);
                event.reply(dbot.t("status"+data["status"]));
                event.reply(data["body"]);
            });
        },
        '~milestone': function(event) {
            var repo = dbot.config.github.defaultrepo;
            var reqUrl = "https://api.github.com/repos/";
            reqUrl += repo + "/milestones";

            request(reqUrl, function(error, response, body) {
                var data = JSON.parse(body);
                for (var section in data) {
                    var milestone = data[section];
                    if (milestone["title"] == event.params[1]){
                        var str = "Milestone " + milestone["title"];
                        var progress = milestone["closed_issues"] / (milestone["open_issues"] + milestone["closed_issues"]);
                        progress = Math.round(progress*100);
                        var bar = "[";
                        for (var i = 1; i < 10; i++) {
                            if  ((progress / (i*10)) > 1) {
                                bar += "█";
                            } else {
                                bar += " ";
                            }
                        }
                        bar += "]";
                        str += " is " + bar + progress + "% complete";

                        var longurl = "http://github.com/" + repo + "/issues?milestone=" + milestone["number"];
                        request({method: 'POST', uri: 'http://git.io', form:{url: longurl}}, function(error, response, body){
                            event.reply(response.headers["location"]);
                        });
                        event.reply(str);
                        break;
                    }
                }
           });
        },
        '~repocount': function(event) {
        // TODO: add handling for non existent user
            var reqUrl = "https://api.github.com/users/" + event.params[1] + "/repos";
            request(reqUrl, function(error, response, body) {
            var result = JSON.parse(body);
			event.reply(event.params[1] + " has " + result.length + " public repositories.");
            });
        }
    };
    this.commands = commands;

    this.on = 'PRIVMSG';
};

exports.fetch = function(dbot) {
    return new github(dbot);
};
<|endoftext|>


<commit_before>/**
 * Tatoeba Project, free collaborative creation of multilingual corpuses project
 * Copyright (C) 2009  HO Ngoc Phuong Trang <tranglich@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
*/

function check(fieldName, string){
    var inputId = fieldName.charAt(0).toUpperCase() + fieldName.substr(1);

    $("#registration"+inputId).removeClass("error").removeClass("valid").addClass("checking");

    $.post(
        "http://" + self.location.hostname + ":" + self.location.port + "/users/check_" + fieldName + "/" + string
        , {}
        , function(data){
            if(data.match('valid')){
                $("#registration"+inputId).removeClass("checking").removeClass("error").addClass("valid");
            }else{
                $("#registration"+inputId).removeClass("checking").removeClass("valid").addClass("error");
            }
        }
    );
}

function triggerChecking(fieldName, inputText){
    // we need to set some delay before checking in the database
    clearTimeout($.data(this, "timer"));
    var ms = 500;
    var wait = setTimeout(function() {
      check(fieldName, inputText);
    }, ms);
    $.data(this, "timer", wait);
}

$(document).ready(function()
{
    /************************
     *    Username validation
     ************************/
    $("#registrationUsername").keyup(function(e){
        var correctUsername = /[A-Za-z_]{2,20}/;

        if(e.keyCode > 40 || e.keyCode == 8 || e.keyCode == 13){     // so we don't take account keys like shift, home, end, etc...
                                                                    // But we accept backspace.

            var username = $(this).val();

            if(username.match(correctUsername)){

                triggerChecking('username', username);

            }else{

                $(this).removeClass("valid").addClass("error");

            }

        }

    });

    /************************
     *    Password validation
     ************************/
    $("#registrationPassword").keyup(function(e){
        var correctPassword  = /(.){4,}/;

        if(e.keyCode > 40 || e.keyCode == 8 || e.keyCode == 13){     // so we don't take account keys like shift, home, end, etc...
                                                                    // But we accept backspace.
            var password = $(this).val();

            if(password.match(correctPassword)){

                $(this).removeClass("error").addClass("valid");

            }else{

                $(this).removeClass("valid").addClass("error");

            }
        }

    });

    /************************
     *    Email validation
     ************************/
    $("#registrationEmail").keyup(function(e){
        var correctEmail  = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;

        if(e.keyCode > 40 || e.keyCode == 8 || e.keyCode == 13){     // so we don't take account keys like shift, home, end, etc...
                                                                    // But we accept backspace and enter

            var email = $(this).val();

            if(email.match(correctEmail)){

                triggerChecking('email', email);

            }else{

                $(this).removeClass("valid").addClass("error");

            }

        }

    });

});
<commit_msg>Fix for check_registration.js. There were some extra end-of-comment characters. Did a little bit of refactoring as well, but it will have to be finished.<commit_after>/**
 * Tatoeba Project, free collaborative creation of multilingual corpuses project
 * Copyright (C) 2009  HO Ngoc Phuong Trang <tranglich@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

// TODO This still needs some refactoring...

$(document).ready(function()
{
    /*
     * Check in database if the value already exists.
     */
    function check(fieldName, string){
        var inputId = fieldName.charAt(0).toUpperCase() + fieldName.substr(1);

        $("#registration"+inputId).attr("class", "checking");

        $.post(
            "http://" + self.location.hostname + ":" + self.location.port + "/users/check_" + fieldName + "/" + string
            , {}
            , function(data){
                if(data.match('valid')){
                    $("#registration"+inputId).attr("class", "valid");
                }else{
                    $("#registration"+inputId).attr("class", "error");
                }
            }
        );
    }

    /*
     * Timer, to add a delay before checking in database.
     */
    function triggerChecking(fieldName, inputText){
        clearTimeout($.data(this, "timer"));
        var ms = 500;
        var wait = setTimeout(
            function() {
                check(fieldName, inputText);
            },
            ms
        );
        $.data(this, "timer", wait);
    }

    /*
     * Username validation
     */
    $("#registrationUsername").keyup(function(e){
        var correctUsername = /[A-Za-z_]{2,20}/;

        if(e.keyCode > 40 || e.keyCode == 8 || e.keyCode == 13){     // so we don't take account keys like shift, home, end, etc...
                                                                    // But we accept backspace.

            var username = $(this).val();

            if(username.match(correctUsername)){

                triggerChecking('username', username);

            }else{

                $(this).attr("class", "error");

            }

        }

    });

    /*
     * Password validation
     */
    $("#registrationPassword").keyup(function(e){
        var correctPassword  = /(.){4,}/;

        if(e.keyCode > 40 || e.keyCode == 8 || e.keyCode == 13){     // so we don't take account keys like shift, home, end, etc...
                                                                    // But we accept backspace.
            var password = $(this).val();

            if(password.match(correctPassword)){

                $(this).attr("class", "valid");

            }else{

                $(this).attr("class", "error");

            }
        }

    });

    /*
     * Email validation
     */
    $("#registrationEmail").keyup(function(e){
        var correctEmail  = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;

        if(e.keyCode > 40 || e.keyCode == 8 || e.keyCode == 13){     // so we don't take account keys like shift, home, end, etc...
                                                                    // But we accept backspace and enter

            var email = $(this).val();

            if(email.match(correctEmail)){

                triggerChecking('email', email);

            }else{

                $(this).attr("class", "error");

            }

        }

    });

});
<|endoftext|>


<commit_before>

function Node (id) { // :: Int -> Node
  this.id = id
  this.acceptors = []
  this.proposal = null
  this.value = null
  this.stateLog = []
  this.roles = []
}

function Cluster (nodes) {
  this.nodes = nodes
  this.learners = []
  this.acceptors = []
  this.proposers = []
  if (nodes) {
    nodes.ForEach(function (node, _, __) {
     if (node.roles.indexOf('Learner') > -1) {
      this.learners.push(node.id)
     } else if (nodes.roles..indexOf('Acceptor') > -1) {
      this.acceptors.push(node.id)
     } else if (nodes.roles..indexOf('Proposer') > -1) {
      this.proposers.push(node.id)
     }
    })
  }
}

function initializeProposer (node, cluster, initProposal) {
  node.roles.push('Proposer')
  node.propose = function (proposal) {}
  if (initProposal) { node.propose(initProposal) }
}

function initializeAcceptor (node, cluster) {
  node.roles.push('Acceptor')
  // Sync stateLog with acceptors in cluster
}

function initializeLearner (node, cluster) {
  node.roles.push('Learner')
}
<commit_msg>Cleanup.<commit_after>
function Node (id) { // :: Int -> Node
  this.id = id
  this.acceptors = []
  this.proposal = null
  this.value = null
  this.stateLog = []
  this.roles = []
}

function Cluster (nodes) { // :: [Node] -> Cluster
  this.nodes = nodes
  this.learners = []
  this.acceptors = []
  this.proposers = []
  if (nodes) {
    nodes.ForEach(function (node, _, __) {
     if (node.roles.indexOf('Learner') > -1) {
      this.learners.push(node.id)
     } else if (nodes.roles.indexOf('Acceptor') > -1) {
      this.acceptors.push(node.id)
     } else if (nodes.roles.indexOf('Proposer') > -1) {
      this.proposers.push(node.id)
     }
    })
  }
}

function initializeProposer (node, cluster, initProposal) { // :: Node -> Cluster -> [Char] ->
  node.roles.push('Proposer')
  node.propose = function (proposal) {}
  if (initProposal) { node.propose(initProposal) }
}

function initializeAcceptor (node, cluster) { // :: Node -> Cluster ->
  node.roles.push('Acceptor')
  // Sync stateLog with acceptors in cluster
}

function initializeLearner (node, cluster) { // :: Node -> Cluster ->
  node.roles.push('Learner')
}
<|endoftext|>


<commit_before>function getGeoIRI() {
  var srid = document.getElementById("srid").value;
//  var geometryWKT = document.getElementById("geometry-wkt").value.replace(/\s/g, '_').replace(/\+/g, '%2B');
  var geometryWKT = encodeWKT(normaliseWKT(document.getElementById("geometry-wkt").value));
  var pathPrefix = document.getElementById("geoiri").action;
  window.location.href = pathPrefix + '/id/geometry/' + srid + '/' + geometryWKT;
}
// Removes unnecessary white spaces from the WKT string.
function normaliseWKT(wkt) {
  return wkt.trim().replace(/[\s]*([\(\),])[\s]*/g, '$1').replace(/[\s]+/g, ' ');
}
// Encodes the WKT string to be used in the URI path.
function encodeWKT(wkt) {
  return wkt.replace(/\s/g, '_').replace(/\+/g, '%2B');
}
<commit_msg>Normalised WKT strings for GeoIRI made lowercase.<commit_after>function getGeoIRI() {
  var srid = document.getElementById("srid").value;
//  var geometryWKT = document.getElementById("geometry-wkt").value.replace(/\s/g, '_').replace(/\+/g, '%2B');
  var geometryWKT = encodeWKT(normaliseWKT(document.getElementById("geometry-wkt").value));
  var pathPrefix = document.getElementById("geoiri").action;
  window.location.href = pathPrefix + '/id/geometry/' + srid + '/' + geometryWKT;
}
// Removes unnecessary white spaces from the WKT string.
function normaliseWKT(wkt) {
  return wkt.trim().replace(/[\s]*([\(\),])[\s]*/g, '$1').replace(/[\s]+/g, ' ').toLowerCase();
}
// Encodes the WKT string to be used in the URI path.
function encodeWKT(wkt) {
  return wkt.replace(/\s/g, '_').replace(/\+/g, '%2B');
}
<|endoftext|>


<commit_before>/*
 *
 * Home
 *
 */

import React from 'react';
import Helmet from 'react-helmet';
import {Link} from 'react-router';
import {Paper} from 'material-ui/Paper';

export default class Home extends React.PureComponent {
  render() {
               const divStyle={
                background: "#80C5DB",
                fontFamily: "Raleway",
                display: "flex",
                flexDirection:"column",
                overflow: "hidden",

              }

                const nonHeadingFontStyle={
                fontFamily: "Cabin",
                margin: "auto auto",
             }

              const headerStyle={
                fontSize: ".8em",
                margin: "0 0",
                display: "flex",
                flexDirection: "column",
                zIndex: "9999",
                margin: "3em 2em",
                justifyContent: "flex-end",
              }
                  const headerShapeStyle= {
                    width: "0",
                    height:"0",
                    border: "0 solid transparent",
                    borderWidth:"100vh",
                    borderTop: "15vh solid #828CEC",
                    position: "fixed",
                  }

                  const headerOneStyle={
                    fontSize: "1.5em",
                  }

              const mainStyle={
                height: "100vh",
                display: "flex",
                flexDirection:"column",
                marginTop: "15%",
              }

                  const blogStyle={
                   margin: "40px",
                   background:"#69BAC2",
                   width: "60%",
                   marginLeft: "40%",
                  }

                    const blogTitleStyle={
                      margin: "1em",
                      marginBottom: "0",
                      }

                      const blogGroupStyle={
                        display: "inline-flex",
                        margin: "-1.25em 1em 1em 1em",
                    }
                          const blogCardStyle={
                            padding: ".5em",
                            margin: ".5em",
                            display: "block",
                          }

                  const aboutStyle={
                  background:"#E7F4F5",
                  padding: ".5em",
                  width: "30%",
                  height: "auto",
                }
                    const aboutTextBlockStyle= {
                      margin: "1em 1em 0 1em",
                    }

               const footerStyle={
                 background:"#8DE0CA",
                 color: "#669daf",
                 position: "fixed",
                 display: "flex",
                 flexDirection: "column",
                 bottom: "0",
                 width: "100%",
                 height: "5em",
                 padding: ".5em",
              }

                    const footerFontStyle={
                      fontFamily: "Cabin",
                      justifyContent: "space-between",
                      margin: "auto",
                    }
                    const socialLinksStyle= {
                      display: 'flex',
                      flexDirection: "row",
                      listStyleType: "none",
                      justifyContent: "space-between",
                      margin: "0 40vw",

                    }

        return (

         <Helmet title="a.chalker " meta={[ { name: 'description', content: 'Description of Home' }]}/>

 Audora Chalker

              <Link to="/"> Home </Link>

 Blog

                     Lorem 1

 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

                       Ipsum 2

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

                       Dolor 3

Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.

 About Me

 Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

📧

  X

  X

  X

  audora chalker. made with ❤ & ☕

    );
  }
}
<commit_msg>LAYOUT PERFECTION 👌<commit_after>/*
 *
 * Home
 *
 */

import React from 'react';
import Helmet from 'react-helmet';
import {Link} from 'react-router';
import Responsive from 'react-responsive';
import {Paper} from 'material-ui/Paper';

export default class Home extends React.PureComponent {
  render() {
               const divStyle={
                background: "#80C5DB",
                fontFamily: "Raleway",
                display: "flex",
                flexDirection:"column",
                overflow: "hidden",

              }

                const nonHeadingFontStyle={
                fontFamily: "Cabin",
                margin: "auto auto",
             }

              const headerStyle={
                fontSize: ".8em",
                display: "flex",
                flexDirection: "column",
                zIndex: "2",

              }
                  const headerShapeStyle= {
                    width: "0",
                    height:"0",
                    border: "0 solid transparent",
                    borderWidth:"100vh",
                    borderTop: "15vh solid #828CEC",
                    position: "fixed",
                    zIndex: "4",
                  }

                  const headerTextBlockStyle= {
                    position: "fixed",
                    margin: "3vh 0 0 0",
                    padding: "0 0 0 1em",
                    width: "30vw",
                    }

                  const headerOneStyle={
                    fontSize: "1.5em",
                    color: "#fff",
                  }

              const mainStyle={
                height: "100%",
                display: "flex",
                flexDirection:"column",

              }

                  const blogStyle={
                   margin: "20vh 0 10% 40%",
                   background:"#69BAC2",
                   width: "60%",
                   display: "flex",

                  }

                    const blogTitleStyle={
                      margin: "1em 1em 1em 1.5em",

                      }

                      const blogGroupStyle={
                        display: "inline-flex",
                        margin: "-1.25em 1em 1em 1em",
                        flexWrap: "wrap",
                        flexDirection: "row",
                    }
                          const blogCardStyle={
                            padding: ".5em",
                            margin: ".5em",
                            display: "block",
                          }

                  const aboutStyle={
                  background:"#E7F4F5",
                  padding: ".5em",
                  width: "30%",
                  marginBottom:"10%",
                  display: "flex",
                  zIndex: "3",
                }
                    const aboutTextBlockStyle= {
                      margin: "1em",

                    }

               const footerStyle={
                 background:"#8DE0CA",
                 color: "#669daf",
                 display: "flex",
                 flexDirection: "column",
                 bottom: "0",
                 width: "100%",
                 height: "5em",
                 padding: ".5em",
              }

                    const footerFontStyle={
                      fontFamily: "Cabin",
                      justifyContent: "space-between",
                      margin: "auto",
                    }
                    const socialLinksStyle= {
                      display: 'flex',
                      flexDirection: "row",
                      listStyleType: "none",
                      justifyContent: "space-between",
                      margin: "0 40vw",

                    }

        return (

         <Helmet title="a.chalker " meta={[ { name: 'description', content: 'Description of Home' }]}/>

 Audora Chalker

                  <Link to="/"> Home </Link>

 Blog

                     Lorem 1

 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

                       Ipsum 2

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

                       Dolor 3

Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.

 About Me

 Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

📧

  X

  X

  X

  audora chalker. made with ❤ & ☕

    );
  }
}
<|endoftext|>


<commit_before>/**
 * GitHub jQuery plugin
 *
 * @copyright (c)2005-2010, WDT Media Corp (http://wdtmedia.net)
 * @license http://www.opensource.org/licenses/mit-license.php The MIT License
 * @link http://github.com/jadb/jquery-tab-slider
 * @author jadb
 */
(function($){
	$.fn.github = function(args) {
		// available api calls
		var apis = {
			repo: 'http://github.com/api/v2/json/repos/show/%user%/%repo%',
			repos: 'http://github.com/api/v2/json/repos/show/%user%',
			watched: 'http://github.com/api/v2/json/repos/watched/%user%',
		};
		// structure of data returned for every api call
		var data = {
			repo: [],
			repos: ['description', 'fork', 'forks', 'homepage', 'name', 'open_issues', 'owner', 'url', 'watchers'],
			watched: ['description', 'fork', 'forks', 'homepage', 'name', 'open_issues', 'owner', 'url', 'watchers'],
		}
		// options
		var defaults = {
			api: 'repos',
			max: 0,
			repo: null,
			filters: [],
			forks: false,
			owner: true,
			tpl: '

%name%

%description%
Forks: %forks% | Watchers: %watchers% | Homepage: %homepage%

',
			user: null,
		};
		// merge args and defaults
		var opts = $.extend(true, defaults, args);

		var html = '';
		var container = this;

		// filter owned repos from watched ones
		if ('watched' == opts.api) {
			opts.owner = false;
		} else if ('forked' == opts.api) {
			opts.api = 'repos';
			opts.forks = true;
			opts.owner = false;
		}

		// build api's url
		var url = apis[opts.api].replace('%user%', opts.user).replace('%repo%', opts.repo);

		$.getJSON(url, 'callback=?', function(response, textStatus) {
			$.each(response.repositories, function(i, repo) {
				console.log(repo.fork);
				if (
					// filter forks out
					(!opts.forks && true === repo.fork)
					// filter owned repos from watched ones
					|| (!opts.owner && opts.user === repo.owner && 'watched' == opts.api)
					// filter for only forked repos
					|| (!opts.owner && opts.forks && !repo.fork)
					) {
					return;
				}

				// regex filter repos by name
				for (var i in opts.filters) {
					if (typeof opts.filters[i] == 'string') {
						opts.filters[i] = new RegExp(opts.filters[i]);
					}
					if (repo.name.match(opts.filters[i], "i")) {
						return;
					}
				}

				html = html + opts.tpl;
				$.each(data[opts.api], function(i, field) {
					var value = repo[field];
					if (typeof value == 'string') {
						value = value.replace(/</g, '<').replace(/>/g, '>');
					}
					html = html.replace('%' + field + '%', value);
				});
			});
			container.html(html);
		});
	}
})(jQuery);<commit_msg>ADD: repo's owner to the repo's name for watched repositories<commit_after>/**
 * GitHub jQuery plugin
 *
 * @copyright (c)2005-2010, WDT Media Corp (http://wdtmedia.net)
 * @license http://www.opensource.org/licenses/mit-license.php The MIT License
 * @link http://github.com/jadb/jquery-tab-slider
 * @author jadb
 */
(function($){
	$.fn.github = function(args) {
		// available api calls
		var apis = {
			repo: 'http://github.com/api/v2/json/repos/show/%user%/%repo%',
			repos: 'http://github.com/api/v2/json/repos/show/%user%',
			watched: 'http://github.com/api/v2/json/repos/watched/%user%',
		};
		// structure of data returned for every api call
		var data = {
			repo: [],
			repos: ['description', 'fork', 'forks', 'homepage', 'name', 'open_issues', 'owner', 'url', 'watchers'],
			watched: ['description', 'fork', 'forks', 'homepage', 'name', 'open_issues', 'owner', 'url', 'watchers'],
		}
		// options
		var defaults = {
			api: 'repos',
			max: 0,
			repo: null,
			filters: [],
			forks: false,
			owner: true,
			tpl: '

%name%

%description%
Forks: %forks% | Watchers: %watchers% | Homepage: %homepage%

',
			user: null,
		};
		// merge args and defaults
		var opts = $.extend(true, defaults, args);

		var html = '';
		var container = this;

		// filter owned repos from watched ones
		if ('watched' == opts.api) {
			opts.owner = false;
			opts.tpl = (opts.tpl).replace('%name%', '%owner%/%name%');
		} else if ('forked' == opts.api) {
			opts.api = 'repos';
			opts.forks = true;
			opts.owner = false;
		}

		// build api's url
		var url = apis[opts.api].replace('%user%', opts.user).replace('%repo%', opts.repo);

		$.getJSON(url, 'callback=?', function(response, textStatus) {
			$.each(response.repositories, function(i, repo) {
				console.log(repo.fork);
				if (
					// filter forks out
					(!opts.forks && true === repo.fork)
					// filter owned repos from watched ones
					|| (!opts.owner && opts.user === repo.owner && 'watched' == opts.api)
					// filter for only forked repos
					|| (!opts.owner && opts.forks && !repo.fork)
					) {
					return;
				}

				// regex filter repos by name
				for (var i in opts.filters) {
					if (typeof opts.filters[i] == 'string') {
						opts.filters[i] = new RegExp(opts.filters[i]);
					}
					if (repo.name.match(opts.filters[i], "i")) {
						return;
					}
				}

				html = html + opts.tpl;
				$.each(data[opts.api], function(i, field) {
					var value = repo[field];
					if (typeof value == 'string') {
						value = value.replace(/</g, '<').replace(/>/g, '>');
					}
					html = html.replace('%' + field + '%', value);
				});
			});
			container.html(html);
		});
	}
})(jQuery);<|endoftext|>


<commit_before>/*jslint indent: 2, plusplus: true */
/*global $: false, document: false, togglbutton: false, createTag:false, window: false, MutationObserver: false */

'use strict';

var checkTimer,
  timeWait = 10;
window.MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;

function removeButton(toolbarElement) {
  if (toolbarElement.innerHTML.indexOf('class="toggl-button tfsTogglButton') > -1) {
    var lastNode = toolbarElement.childNodes[0].lastChild;
    if (lastNode.innerHTML.indexOf('timer') > -1) {
      toolbarElement.childNodes[0].removeChild(lastNode);
    }
  }
}

function createTFSEvilHackElement(hackElement, titleHolder) {
  var div = createTag('div', 'empty'),
    a = createTag('a', 'emptylink'),
    where = hackElement,
    title = titleHolder,
    findNew,
    findNewLink;

  if (where.innerHTML.indexOf('class="emptylink"') === -1) {
    where.insertBefore(div, title);
    findNew = where.querySelector('.empty');
    findNew.appendChild(a);
    findNewLink = where.querySelector('.emptylink');
    findNewLink.setAttribute("href", "javascript:void()");
    findNewLink.innerHTML = " ";
    findNew.setAttribute("style", "float:left");
  }
}

function createTFSButton(homeElement) {
  var y, link,
    descriptionTitle = "",
    home,
    titleHolder,
    numberPattern,
    toolbars;

  home = homeElement;
  if (home.innerHTML !== "") {
    titleHolder = home.querySelector('.info-text-wrapper');

    numberPattern = /\d+/g;
    descriptionTitle = titleHolder.childNodes[1].innerText + " (TFS Workitem ID: " + titleHolder.childNodes[0].innerText.match(numberPattern) + ")";

    link = togglbutton.createTimerLink({
      className: 'tfsTogglButton',
      description: descriptionTitle
    });

    toolbars = home.parentNode.querySelectorAll('.toolbar');
    if (toolbars.length === 0) {
      toolbars = home.parentNode.parentNode.querySelectorAll('.toolbar');
    }
    for (y = 0; y < toolbars.length; y++) {
      removeButton(toolbars[y]);
      toolbars[y].firstChild.appendChild(link);
    }

    createTFSEvilHackElement(home, titleHolder);
  }

}

var observer = new MutationObserver(function (mutation) {
    var obj = mutation[0].target;
    window.clearTimeout(checkTimer);
    checkTimer = window.setTimeout(function () {
      createTFSButton(obj);
    }, timeWait);
  }),
  config = {
    attributes: true
  };

function createObserver(element) {
  observer.observe(element, config);
}

togglbutton.render('.workitem-info-bar:not(.toggl)', {
  observe: true
}, function () {
  var target = document.querySelectorAll('.workitem-info-bar'),
    y;

  checkTimer = window.setTimeout(function () {
    createTFSButton(target[0]);
  }, timeWait);

  for (y = 0; y < target.length; y++) {
    createObserver(target[y]);
  }

  // observer.disconnect();
});<commit_msg>Removed obsolete Mutation variables<commit_after>/*jslint indent: 2, plusplus: true */
/*global $: false, document: false, togglbutton: false, createTag:false, window: false, MutationObserver: false */

'use strict';

var checkTimer,
  timeWait = 10;

function removeButton(toolbarElement) {
  if (toolbarElement.innerHTML.indexOf('class="toggl-button tfsTogglButton') > -1) {
    var lastNode = toolbarElement.childNodes[0].lastChild;
    if (lastNode.innerHTML.indexOf('timer') > -1) {
      toolbarElement.childNodes[0].removeChild(lastNode);
    }
  }
}

function createTFSEvilHackElement(hackElement, titleHolder) {
  var div = createTag('div', 'empty'),
    a = createTag('a', 'emptylink'),
    where = hackElement,
    title = titleHolder,
    findNew,
    findNewLink;

  if (where.innerHTML.indexOf('class="emptylink"') === -1) {
    where.insertBefore(div, title);
    findNew = where.querySelector('.empty');
    findNew.appendChild(a);
    findNewLink = where.querySelector('.emptylink');
    findNewLink.setAttribute("href", "javascript:void()");
    findNewLink.innerHTML = " ";
    findNew.setAttribute("style", "float:left");
  }
}

function createTFSButton(homeElement) {
  var y, link,
    descriptionTitle = "",
    home,
    titleHolder,
    numberPattern,
    toolbars;

  home = homeElement;
  if (home.innerHTML !== "") {
    titleHolder = home.querySelector('.info-text-wrapper');

    numberPattern = /\d+/g;
    descriptionTitle = titleHolder.childNodes[1].innerText + " (TFS Workitem ID: " + titleHolder.childNodes[0].innerText.match(numberPattern) + ")";

    link = togglbutton.createTimerLink({
      className: 'tfsTogglButton',
      description: descriptionTitle
    });

    toolbars = home.parentNode.querySelectorAll('.toolbar');
    if (toolbars.length === 0) {
      toolbars = home.parentNode.parentNode.querySelectorAll('.toolbar');
    }
    for (y = 0; y < toolbars.length; y++) {
      removeButton(toolbars[y]);
      toolbars[y].firstChild.appendChild(link);
    }

    createTFSEvilHackElement(home, titleHolder);
  }

}

var observer = new MutationObserver(function (mutation) {
    var obj = mutation[0].target;
    window.clearTimeout(checkTimer);
    checkTimer = window.setTimeout(function () {
      createTFSButton(obj);
    }, timeWait);
  }),
  config = {
    attributes: true
  };

function createObserver(element) {
  observer.observe(element, config);
}

togglbutton.render('.workitem-info-bar:not(.toggl)', {
  observe: true
}, function () {
  var target = document.querySelectorAll('.workitem-info-bar'),
    y;

  checkTimer = window.setTimeout(function () {
    createTFSButton(target[0]);
  }, timeWait);

  for (y = 0; y < target.length; y++) {
    createObserver(target[y]);
  }

  // observer.disconnect();
});<|endoftext|>


<commit_before>// account.js

var org = {

	// added on script load
	config: {
						endpoint: { hzws: 'http://api.spokanelibrary.org/v2/hzws/' }
					 }

	// added on authentication
	,user: {}

	// called on script load
	,init: function() {
		_self = this;

		// setup variables
		this.user = $('#spl-account-summary').data('account');
		//console.log(this.user);

		// init ui
		this.initMyAccount();

	} // init()

, initMyAccount: function() {

		this.initTabs();

		this.initCko();

		this.initHolds();

		this.initProfile();

  } // initMyAccount()

, initTabs: function() {
		// apply hash onload
		if ( window.location.hash ) {
			$('a[href="'+window.location.hash+'"]').tab('show')
		}

		// apply hashchange on tab event
		//$('body').on('click', '[data-toggle="tab"]', function(e) {
		$('[data-toggle="tab"]').click(function(e) {
			window.location.hash = $(this).attr('href');
		});

	} // initTabs()

, initCko: function() {
		var $form = $('#spl-form-cko');

		this.toggleCheckboxGroup('.spl-field-cko-select-all'
														,'.spl-field-cko-select-item');

		$form.on('submit', function(e) {
			if ( 'ajax' == $(this).data('process') ) {
				e.preventDefault();

				var barcodes = new Array;
				$('.spl-field-cko-select-item:checked').each(function() {
					barcodes.push( $(this).data('barcode') );
				});

				if ( barcodes.length > 0 ) {
					_self.ckoRenew(barcodes);
				} else {
					alert('Please select item(s) to renew.');
				}
			}

		});

	} // initCko()

, ckoRenew: function(barcodes) {
		var $form = $('#spl-form-cko');
		var $submit = $('.spl-submit-cko');
		var $hidden = $('#spl-field-cko-renewal');

		$submit.button('loading'); //$submit.button('reset');
		$.ajax({
	    url: this.config.endpoint.hzws+'renew' //'renew' //'trace'
    , data: { params: { token: this.user.sessionToken
    									,	barcodes: barcodes
    									}
    				}
	  })
	  .done(function(obj) {
	  	// pass results through
			$hidden.val(JSON.stringify(obj));
			$form.data('process', 'http').submit();
	  })
	  .fail(function() {
	  })
	  .always(function() {
	  });

	} // ckoRenew()

, initHolds: function() {
		this.initHoldsPending();

	} // initHolds()

, initHoldsPending: function() {
		var $date = $('.spl-field-holds-pending-date');
		$date.on('change', function(e) {
			console.log( $(this).val() );
			//if ( $(this).val() ) {
				//$suspend.attr('disabled', false);
			//}
		});

		asd
		var $form = $('#spl-form-holds-pending');

		this.toggleCheckboxGroup('.spl-field-holds-pending-select-all'
														,'.spl-field-holds-pending-select-item');

		$('.spl-field-holds-pending-control').click(function(e) {
			$form.data('action', $(this).data('action')).submit();
		});

		$form.on('submit', function(e) {
			if ( 'ajax' == $(this).data('process') ) {
				e.preventDefault();

				var holdkeys = new Array;
				$('.spl-field-holds-pending-select-item:checked').each(function() {
					holdkeys.push( $(this).data('holdkey') );
				});

				if ( holdkeys.length > 0 ) {
					_self.holdsPendingUpdate($(this).data('action'), holdkeys);
					$(this).data('action', '');
				} else {
					alert('Please select hold(s).');
				}

			}

		});

	} // initHoldsPending()

, holdsPendingUpdate: function(action, holdkeys) {
		var $form = $('#spl-form-holds-pending');
		var $submit = $('.spl-field-holds-pending-control');
		var $hidden = $('#spl-field-holds-pending-update');

		var $suspend = $('.spl-field-holds-pending-suspend');

		var $date = $('.spl-field-holds-pending-date');

		$submit.button('loading'); //$submit.button('reset');

		var data = { params: {token: this.user.sessionToken
	    									,	holdKeys: holdkeys
	    									}
	    					}

		var endpoint;
		switch ( action ) {
			case 'cancel':
				endpoint = 'cancelHolds';
				break;
			case 'pickup':
				endpoint = 'changePickupLocations';
				data.params.newLocation = 'hy';
				break;
			case 'suspend':
				endpoint = 'suspendHolds';
				data.params.suspendEndDate = $date.val();
				break;
			default:
				endpoint = null;
				break;
		}

		if ( null != typeof(endpoint) ) {
			$.ajax({
		    url: this.config.endpoint.hzws+endpoint
	    , data: data
		  })
		  .done(function(obj) {
		  	// pass results through
				$hidden.val(JSON.stringify(obj));
				console.log(obj);
				$submit.button('reset');
				//$form.data('process', 'http').submit();
		  })
		  .fail(function() {
		  })
		  .always(function() {
		  });
		}

	} // holdsPendingUpdate()

, initProfile: function() {
		this.initProfileEmail();
		this.initProfilePin();

	} // initProfile()

, initProfileEmail: function() {
		// it turns out hzws has no methods for updating email
		// will need addres ord? or maybe just select on old address?
		var $form = $('#spl-form-profile-email');
		var $email = $('#spl-field-profile-email');
		var $submit = $('#spl-submit-profile-email');

		$form.validate();

		$form.on('submit', function(e) {
			e.preventDefault();
			if ( $form.valid() ) {
				/*
				console.log( _self.user.borrower );
				console.log( _self.user.sessionToken );
				console.log( $email.val() );
				$submit.button('loading');
				*/
			}
		});

	} // initProfileEmail()

, initProfilePin: function() {
	// note: we will need a new session token here (loginUserResetMyPin)
	var $form = $('#spl-form-profile-pin');

	var $submit = $('#spl-submit-profile-pin');

	$form.validate({
		rules: {
			pinConfirm: {
	      equalTo: "#spl-field-profile-pin-new"
	    }
  	}
	});

		$form.on('submit', function(e) {
			e.preventDefault();
			if ( $form.valid() ) {
				/*
				console.log( _self.user.borrower );
				console.log( _self.user.sessionToken );
				console.log( $email.val() );
				$submit.button('loading');
				*/
			}
		});

} // initProfilePin()

, toggleCheckboxGroup: function(all, item) {
		var $selectAll = $(all);
		var $selectItem = $(item);

		$selectAll.on('change', function(e) {
			if ( $(this).is(':checked') ) {
				$selectAll.prop('checked', true);
				$selectItem.prop('checked', true);
			} else {
				$selectAll.prop('checked', false);
				$selectItem.prop('checked', false);
			}
		});
	}

};
<commit_msg>suspend<commit_after>// account.js

var org = {

	// added on script load
	config: {
						endpoint: { hzws: 'http://api.spokanelibrary.org/v2/hzws/' }
					 }

	// added on authentication
	,user: {}

	// called on script load
	,init: function() {
		_self = this;

		// setup variables
		this.user = $('#spl-account-summary').data('account');
		//console.log(this.user);

		// init ui
		this.initMyAccount();

	} // init()

, initMyAccount: function() {

		this.initTabs();

		this.initCko();

		this.initHolds();

		this.initProfile();

  } // initMyAccount()

, initTabs: function() {
		// apply hash onload
		if ( window.location.hash ) {
			$('a[href="'+window.location.hash+'"]').tab('show')
		}

		// apply hashchange on tab event
		//$('body').on('click', '[data-toggle="tab"]', function(e) {
		$('[data-toggle="tab"]').click(function(e) {
			window.location.hash = $(this).attr('href');
		});

	} // initTabs()

, initCko: function() {
		var $form = $('#spl-form-cko');

		this.toggleCheckboxGroup('.spl-field-cko-select-all'
														,'.spl-field-cko-select-item');

		$form.on('submit', function(e) {
			if ( 'ajax' == $(this).data('process') ) {
				e.preventDefault();

				var barcodes = new Array;
				$('.spl-field-cko-select-item:checked').each(function() {
					barcodes.push( $(this).data('barcode') );
				});

				if ( barcodes.length > 0 ) {
					_self.ckoRenew(barcodes);
				} else {
					alert('Please select item(s) to renew.');
				}
			}

		});

	} // initCko()

, ckoRenew: function(barcodes) {
		var $form = $('#spl-form-cko');
		var $submit = $('.spl-submit-cko');
		var $hidden = $('#spl-field-cko-renewal');

		$submit.button('loading'); //$submit.button('reset');
		$.ajax({
	    url: this.config.endpoint.hzws+'renew' //'renew' //'trace'
    , data: { params: { token: this.user.sessionToken
    									,	barcodes: barcodes
    									}
    				}
	  })
	  .done(function(obj) {
	  	// pass results through
			$hidden.val(JSON.stringify(obj));
			$form.data('process', 'http').submit();
	  })
	  .fail(function() {
	  })
	  .always(function() {
	  });

	} // ckoRenew()

, initHolds: function() {
		this.initHoldsPending();

	} // initHolds()

, initHoldsPending: function() {
		var $date = $('.spl-field-holds-pending-date');
		$date.on('change', function(e) {
			console.log( $(this).val() );
			//if ( $(this).val() ) {
				//$suspend.attr('disabled', false);
			//}
		});

		var $form = $('#spl-form-holds-pending');

		this.toggleCheckboxGroup('.spl-field-holds-pending-select-all'
														,'.spl-field-holds-pending-select-item');

		$('.spl-field-holds-pending-control').click(function(e) {
			$form.data('action', $(this).data('action')).submit();
		});

		$form.on('submit', function(e) {
			if ( 'ajax' == $(this).data('process') ) {
				e.preventDefault();

				var holdkeys = new Array;
				$('.spl-field-holds-pending-select-item:checked').each(function() {
					holdkeys.push( $(this).data('holdkey') );
				});

				if ( holdkeys.length > 0 ) {
					_self.holdsPendingUpdate($(this).data('action'), holdkeys);
					$(this).data('action', '');
				} else {
					alert('Please select hold(s).');
				}

			}

		});

	} // initHoldsPending()

, holdsPendingUpdate: function(action, holdkeys) {
		var $form = $('#spl-form-holds-pending');
		var $submit = $('.spl-field-holds-pending-control');
		var $hidden = $('#spl-field-holds-pending-update');

		var $suspend = $('.spl-field-holds-pending-suspend');

		var $date = $('.spl-field-holds-pending-date');

		$submit.button('loading'); //$submit.button('reset');

		var data = { params: {token: this.user.sessionToken
	    									,	holdKeys: holdkeys
	    									}
	    					}

		var endpoint;
		switch ( action ) {
			case 'cancel':
				endpoint = 'cancelHolds';
				break;
			case 'pickup':
				endpoint = 'changePickupLocations';
				data.params.newLocation = 'hy';
				break;
			case 'suspend':
				endpoint = 'suspendHolds';
				data.params.suspendEndDate = $date.val();
				break;
			default:
				endpoint = null;
				break;
		}

		if ( null != typeof(endpoint) ) {
			$.ajax({
		    url: this.config.endpoint.hzws+endpoint
	    , data: data
		  })
		  .done(function(obj) {
		  	// pass results through
				$hidden.val(JSON.stringify(obj));
				console.log(obj);
				$submit.button('reset');
				//$form.data('process', 'http').submit();
		  })
		  .fail(function() {
		  })
		  .always(function() {
		  });
		}

	} // holdsPendingUpdate()

, initProfile: function() {
		this.initProfileEmail();
		this.initProfilePin();

	} // initProfile()

, initProfileEmail: function() {
		// it turns out hzws has no methods for updating email
		// will need addres ord? or maybe just select on old address?
		var $form = $('#spl-form-profile-email');
		var $email = $('#spl-field-profile-email');
		var $submit = $('#spl-submit-profile-email');

		$form.validate();

		$form.on('submit', function(e) {
			e.preventDefault();
			if ( $form.valid() ) {
				/*
				console.log( _self.user.borrower );
				console.log( _self.user.sessionToken );
				console.log( $email.val() );
				$submit.button('loading');
				*/
			}
		});

	} // initProfileEmail()

, initProfilePin: function() {
	// note: we will need a new session token here (loginUserResetMyPin)
	var $form = $('#spl-form-profile-pin');

	var $submit = $('#spl-submit-profile-pin');

	$form.validate({
		rules: {
			pinConfirm: {
	      equalTo: "#spl-field-profile-pin-new"
	    }
  	}
	});

		$form.on('submit', function(e) {
			e.preventDefault();
			if ( $form.valid() ) {
				/*
				console.log( _self.user.borrower );
				console.log( _self.user.sessionToken );
				console.log( $email.val() );
				$submit.button('loading');
				*/
			}
		});

} // initProfilePin()

, toggleCheckboxGroup: function(all, item) {
		var $selectAll = $(all);
		var $selectItem = $(item);

		$selectAll.on('change', function(e) {
			if ( $(this).is(':checked') ) {
				$selectAll.prop('checked', true);
				$selectItem.prop('checked', true);
			} else {
				$selectAll.prop('checked', false);
				$selectItem.prop('checked', false);
			}
		});
	}

};
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc function
 * @name schooldataApp.controller:AboutCtrl
 * @description
 * # AboutCtrl
 * Controller of the schooldataApp
 */
angular.module('schooldataApp')
  .controller('SchoolCtrl', ['$scope', '$routeParams', 'es', function ($scope, $routeParams, es) {
    $scope.schoolId = $routeParams.schoolId;

    $scope.schoolData = {};
    $scope.error = null;
    $scope.loading = null;

    var body = {};
    body.query = {
    	bool: {
    		must : [{
	    	query_string: {
	            default_field: 'school.bsn',
	            query: $routeParams.schoolId
	        }}]
    }};

    body.size = 1;

    this.loadSchool = function() {
    	$scope.loading = 1;
    	$scope.error = null;
	    es.search({
		        index: sp.config.elasticsearch.index,
		        type: 'school',
		        body: body
		    }).then(function (returned) {
		    	$scope.schoolData = {}; // reset from possible previous value
		    	// we found the school
		    	if (returned.hits.total > 0) {
		    		$scope.schoolData = returned.hits.hits[0]._source;
		    	} else {
		    		$scope.error = "";
		    	}
		    	$scope.loading = null;
		    }, function(error) {
		    	$scope.error = "";
		    	$scope.loading = null;
		    	console.log(error.message);
	    });
    };

    this.loadSchool();

  }]);
<commit_msg>Fix indention<commit_after>'use strict';

/**
 * @ngdoc function
 * @name schooldataApp.controller:AboutCtrl
 * @description
 * # AboutCtrl
 * Controller of the schooldataApp
 */
angular.module('schooldataApp')
  .controller('SchoolCtrl', ['$scope', '$routeParams', 'es', function ($scope, $routeParams, es) {
    $scope.schoolId = $routeParams.schoolId;

    $scope.schoolData = {};
    $scope.error = null;
    $scope.loading = null;

    var body = {};
    body.query = {
        bool: {
            must : [{
            query_string: {
                default_field: 'school.bsn',
                query: $routeParams.schoolId
            }}]
    }};

    body.size = 1;

    this.loadSchool = function() {
        $scope.loading = 1;
        $scope.error = null;
        es.search({
                index: sp.config.elasticsearch.index,
                type: 'school',
                body: body
            }).then(function (returned) {
                $scope.schoolData = {}; // reset from possible previous value
                // we found the school
                if (returned.hits.total > 0) {
                    $scope.schoolData = returned.hits.hits[0]._source;
                } else {
                    $scope.error = "";
                }
                $scope.loading = null;
            }, function(error) {
                $scope.error = "";
                $scope.loading = null;
                console.log(error.message);
        });
    };

    this.loadSchool();

  }]);
<|endoftext|>


<commit_before>// Copyright 2016-2020, University of Colorado Boulder

// Note: This file is a mashup of two ported Java files: Carousel and
// EnergySystemElementCarousel. Carousel.java was not ported to avoid confusion
// with the PhET Sun Carousel.js UI component.

/**
 * This type implements a model-based carousel for positionable model elements. Model elements are positioned based
 * on the current selection, and an API is provided that allows clients to change those selection. Changes to the
 * selected element are animated.
 *
 * @author John Blanco
 * @author Andrew Adare
 * @author Jesse Greenberg
 */

import BooleanProperty from '../../../../axon/js/BooleanProperty.js';
import EnumerationProperty from '../../../../axon/js/EnumerationProperty.js';
import NumberProperty from '../../../../axon/js/NumberProperty.js';
import Utils from '../../../../dot/js/Utils.js';
import Vector2 from '../../../../dot/js/Vector2.js';
import Tandem from '../../../../tandem/js/Tandem.js';
import Easing from '../../../../twixt/js/Easing.js';
import energyFormsAndChanges from '../../energyFormsAndChanges.js';

// constants
const TRANSITION_DURATION = 0.75; // in seconds

class EnergySystemElementCarousel {

  /**
   * @param {EnergySystemElement[]} elements - array of elements to add to this carousel
   * @param {Enumeration} elementNames - the names of the elements being added
   * @param {Vector2} selectedElementPosition - position where the selected model element should be
   * @param {Vector2} offsetBetweenElements - offset between elements in the carousel
   * @param {Tandem} tandem
   */
  constructor( elements, elementNames, selectedElementPosition, offsetBetweenElements, tandem ) {

    // @public (read-only) {Vector2} - the position in model space where the currently selected element should be
    this.selectedElementPosition = selectedElementPosition;

    // @private {Vector2} - the offset between elements whose position is managed by this carousel
    this.offsetBetweenElements = offsetBetweenElements;

    // @public (read-only) {EnergySystemElement[]} - list of the elements whose position is managed by this carousel
    this.managedElements = [];

    // @public (read-only) {Enumeration} - names that correspond to each element
    this.elementNames = elementNames;

    // add each element to the array of managed elements
    elements.forEach( element => this.add( element ) );

    /**
     * calculates the valid target indices for this carousel
     *
     * @param {number} numberOfElements
     * @returns {number[]}
     */
    const getValidTargetIndices = numberOfElements => {
      const validTargetIndices = [];
      _.times( numberOfElements, index => {
        validTargetIndices.push( index );
      } );
      return validTargetIndices;
    };

    assert && assert( this.managedElements.length === this.elementNames.VALUES.length,
      'The number of managed elements must equal the number of element name enumeration values' );

    // @public (read-only) {NumberProperty} - indicates which element on the carousel is currently selected by index.
    // this index is the ground truth for managing the currently selected element, but is controlled by
    // targetElementNameProperty below.
    this.targetIndexProperty = new NumberProperty( 0, {
      validValues: getValidTargetIndices( this.managedElements.length )
    } );

    // @public (read-only) {EnumerationProperty} - this is for phet-io Studio so that Clients can select an element
    // by name instead of index
    this.targetElementNameProperty = new EnumerationProperty( elementNames, elementNames.VALUES[ 0 ], {
      tandem: tandem.createTandem( 'targetElementNameProperty' ),
      phetioDocumentation: 'indicates which element on the carousel is currently selected by name'
    } );

    // @public (read-only) {BooleanProperty}
    this.animationInProgressProperty = new BooleanProperty( false, {
      tandem: tandem.createTandem( 'animationInProgressProperty' ),
      phetioReadOnly: true,
      phetioDocumentation: 'indicates whether an animation from one carousel position to another is in progress'
    } );

    // @private - variables needed to manage carousel transitions
    this.elapsedTransitionTime = 0; // in seconds
    this.currentCarouselOffset = new Vector2( 0, 0 ); // in meters
    this.initialCarouselOffset = new Vector2( 0, 0 ); // in meters

    // set the variables needed for animation each time the target changes
    this.targetElementNameProperty.lazyLink( targetElement => {

      // update the target index
      this.targetIndexProperty.set( _.findIndex( this.elementNames.VALUES, targetElement ) );

      // set vars for the transition
      this.elapsedTransitionTime = 0;
      this.initialCarouselOffset = this.currentCarouselOffset;
      this.animationInProgressProperty.set( true );
    } );

    // activate and deactivate energy system elements as they come into the center position
    this.animationInProgressProperty.lazyLink( animationInProgress => {

      // prevent deactivation from overwriting state values, see https://github.com/phetsims/energy-forms-and-changes/issues/337
      // activation can create extra EnergyChunks or clear them (which are instrumented since https://github.com/phetsims/energy-forms-and-changes/issues/350)
      if ( phet.joist.sim.isSettingPhetioStateProperty.value ) {
        return;
      }
      if ( animationInProgress ) {

        // deactivate elements while things are moving
        this.managedElements.forEach( element => {
          if ( element.activeProperty.value ) {
            element.deactivate();
          }
        } );
      }
      else {

        // activate the element that is now in the active position
        this.getElement( this.targetIndexProperty.value ).activate();
      }
    } );

    // REVIEW-phetio: This seems fragile and, while the comment is good, it's hard to figure out why it works, and the
    // hard-coded number seems suspect.  It would be better to have a private method like finishInProgressAnimations()
    // or something like that.
    // Don't animate the system elements when setting state for better user experience when launching the sim.
    Tandem.PHET_IO_ENABLED && phet.phetio.phetioEngine.phetioStateEngine.stateSetEmitter.addListener( () => {
      this.elapsedTransitionTime = 1;
    } );
  }

  /**
   * add element to list of managed elements
   * @param {EnergySystemElement} element - energy system element to be added to carousel
   * @private
   */
  add( element ) {

    // set the element's position to be at the end of the carousel
    if ( this.managedElements.length === 0 ) {
      element.positionProperty.set( this.selectedElementPosition );
    }
    else {
      const lastElement = this.managedElements[ this.managedElements.length - 1 ];
      element.positionProperty.set( lastElement.positionProperty.value.plus( this.offsetBetweenElements ) );
    }

    // add element to the list of managed elements
    this.managedElements.push( element );

    // update opacities
    this.updateManagedElementOpacities();
  }

  /**
   * get an element from carousel by index
   * @param  {number} index Requested position in array of EnergySystemElements
   * @returns {EnergySystemElement}
   * @public
   */
  getElement( index ) {
    assert && assert( index < this.managedElements.length, `carousel index out of range: ${index}` );
    return this.managedElements[ index ];
  }

  /**
   * get the currently selected element from carousel
   * @returns {EnergySystemElement|null}
   * @public
   */
  getSelectedElement() {
    const i = this.targetIndexProperty.get();
    if ( i < this.managedElements.length ) {
      return this.managedElements[ i ];
    }
    return null;
  }

  /**
   * step this model element
   * @param {number} dt - time step, in seconds
   * @public
   */
  step( dt ) {
    if ( !this.atTargetPosition() ) {
      this.elapsedTransitionTime += dt;
      const targetCarouselOffset = this.offsetBetweenElements.times( -this.targetIndexProperty.get() );
      const totalTravelVector = targetCarouselOffset.minus( this.initialCarouselOffset );
      const transitionProportion = Utils.clamp( this.elapsedTransitionTime / TRANSITION_DURATION, 0, 1 );
      this.currentCarouselOffset =
        this.initialCarouselOffset.plus( totalTravelVector.times( Easing.CUBIC_IN_OUT.value( transitionProportion ) ) );
      this.updateManagedElementPositions();

      if ( transitionProportion === 1 ) {
        this.currentCarouselOffset = targetCarouselOffset;
      }

      if ( this.currentCarouselOffset === targetCarouselOffset ) {
        this.animationInProgressProperty.set( false );
      }
      this.updateManagedElementOpacities();
    }
  }

  /**
   * sets the position in model space of each element based on the state of the carousel
   * @private
   */
  updateManagedElementPositions() {
    for ( let i = 0; i < this.managedElements.length; i++ ) {
      let position = this.selectedElementPosition.plus( this.offsetBetweenElements.times( i ) );
      position = position.plus( this.currentCarouselOffset );
      this.managedElements[ i ].positionProperty.set( position );
    }
  }

  /**
   * sets the opacity of each element based on the state of the carousel. elements fade out as they get farther from
   * the active, selected position
   * @private
   */
  updateManagedElementOpacities() {
    this.managedElements.forEach( managedElement => {
      const distanceToSelection = managedElement.positionProperty.value.distance( this.selectedElementPosition );
      const opacity = Utils.clamp( 1 - ( distanceToSelection / this.offsetBetweenElements.magnitude ), 0, 1 );
      managedElement.opacityProperty.set( opacity );
    } );
  }

  /**
   * whether the current selected element is in its destination spot
   * @private
   * @returns {boolean}
   */
  atTargetPosition() {
    const targetCarouselOffset = this.offsetBetweenElements.times( -this.targetIndexProperty.value );
    return this.currentCarouselOffset.equals( targetCarouselOffset );
  }
}

energyFormsAndChanges.register( 'EnergySystemElementCarousel', EnergySystemElementCarousel );
export default EnergySystemElementCarousel;
<commit_msg>update to TODO and add issue, https://github.com/phetsims/energy-forms-and-changes/issues/401<commit_after>// Copyright 2016-2020, University of Colorado Boulder

// Note: This file is a mashup of two ported Java files: Carousel and
// EnergySystemElementCarousel. Carousel.java was not ported to avoid confusion
// with the PhET Sun Carousel.js UI component.

/**
 * This type implements a model-based carousel for positionable model elements. Model elements are positioned based
 * on the current selection, and an API is provided that allows clients to change those selection. Changes to the
 * selected element are animated.
 *
 * @author John Blanco
 * @author Andrew Adare
 * @author Jesse Greenberg
 */

import BooleanProperty from '../../../../axon/js/BooleanProperty.js';
import EnumerationProperty from '../../../../axon/js/EnumerationProperty.js';
import NumberProperty from '../../../../axon/js/NumberProperty.js';
import Utils from '../../../../dot/js/Utils.js';
import Vector2 from '../../../../dot/js/Vector2.js';
import Tandem from '../../../../tandem/js/Tandem.js';
import Easing from '../../../../twixt/js/Easing.js';
import energyFormsAndChanges from '../../energyFormsAndChanges.js';

// constants
const TRANSITION_DURATION = 0.75; // in seconds

class EnergySystemElementCarousel {

  /**
   * @param {EnergySystemElement[]} elements - array of elements to add to this carousel
   * @param {Enumeration} elementNames - the names of the elements being added
   * @param {Vector2} selectedElementPosition - position where the selected model element should be
   * @param {Vector2} offsetBetweenElements - offset between elements in the carousel
   * @param {Tandem} tandem
   */
  constructor( elements, elementNames, selectedElementPosition, offsetBetweenElements, tandem ) {

    // @public (read-only) {Vector2} - the position in model space where the currently selected element should be
    this.selectedElementPosition = selectedElementPosition;

    // @private {Vector2} - the offset between elements whose position is managed by this carousel
    this.offsetBetweenElements = offsetBetweenElements;

    // @public (read-only) {EnergySystemElement[]} - list of the elements whose position is managed by this carousel
    this.managedElements = [];

    // @public (read-only) {Enumeration} - names that correspond to each element
    this.elementNames = elementNames;

    // add each element to the array of managed elements
    elements.forEach( element => this.add( element ) );

    /**
     * calculates the valid target indices for this carousel
     *
     * @param {number} numberOfElements
     * @returns {number[]}
     */
    const getValidTargetIndices = numberOfElements => {
      const validTargetIndices = [];
      _.times( numberOfElements, index => {
        validTargetIndices.push( index );
      } );
      return validTargetIndices;
    };

    assert && assert( this.managedElements.length === this.elementNames.VALUES.length,
      'The number of managed elements must equal the number of element name enumeration values' );

    // @public (read-only) {NumberProperty} - indicates which element on the carousel is currently selected by index.
    // this index is the ground truth for managing the currently selected element, but is controlled by
    // targetElementNameProperty below.
    this.targetIndexProperty = new NumberProperty( 0, {
      validValues: getValidTargetIndices( this.managedElements.length )
    } );

    // @public (read-only) {EnumerationProperty} - this is for phet-io Studio so that Clients can select an element
    // by name instead of index
    this.targetElementNameProperty = new EnumerationProperty( elementNames, elementNames.VALUES[ 0 ], {
      tandem: tandem.createTandem( 'targetElementNameProperty' ),
      phetioDocumentation: 'indicates which element on the carousel is currently selected by name'
    } );

    // @public (read-only) {BooleanProperty}
    this.animationInProgressProperty = new BooleanProperty( false, {
      tandem: tandem.createTandem( 'animationInProgressProperty' ),
      phetioReadOnly: true,
      phetioDocumentation: 'indicates whether an animation from one carousel position to another is in progress'
    } );

    // @private - variables needed to manage carousel transitions
    this.elapsedTransitionTime = 0; // in seconds
    this.currentCarouselOffset = new Vector2( 0, 0 ); // in meters
    this.initialCarouselOffset = new Vector2( 0, 0 ); // in meters

    // set the variables needed for animation each time the target changes
    this.targetElementNameProperty.lazyLink( targetElement => {

      // update the target index
      this.targetIndexProperty.set( _.findIndex( this.elementNames.VALUES, targetElement ) );

      // set vars for the transition
      this.elapsedTransitionTime = 0;
      this.initialCarouselOffset = this.currentCarouselOffset;
      this.animationInProgressProperty.set( true );
    } );

    // activate and deactivate energy system elements as they come into the center position
    this.animationInProgressProperty.lazyLink( animationInProgress => {

      // prevent deactivation from overwriting state values, see https://github.com/phetsims/energy-forms-and-changes/issues/337
      // activation can create extra EnergyChunks or clear them (which are instrumented since https://github.com/phetsims/energy-forms-and-changes/issues/350)
      if ( phet.joist.sim.isSettingPhetioStateProperty.value ) {
        return;
      }
      if ( animationInProgress ) {

        // deactivate elements while things are moving
        this.managedElements.forEach( element => {
          if ( element.activeProperty.value ) {
            element.deactivate();
          }
        } );
      }
      else {

        // activate the element that is now in the active position
        this.getElement( this.targetIndexProperty.value ).activate();
      }
    } );

    // TODO: (from jbphet) This seems fragile and, while the comment is good, it's hard to figure out why it works, and the
    // TODO: hard-coded number seems suspect.  It would be better to have a private method like finishInProgressAnimations()
    // TODO: or something like that. See https://github.com/phetsims/energy-forms-and-changes/issues/401
    // Don't animate the system elements when setting state for better user experience when launching the sim.
    Tandem.PHET_IO_ENABLED && phet.phetio.phetioEngine.phetioStateEngine.stateSetEmitter.addListener( () => {
      this.elapsedTransitionTime = 1;
    } );
  }

  /**
   * add element to list of managed elements
   * @param {EnergySystemElement} element - energy system element to be added to carousel
   * @private
   */
  add( element ) {

    // set the element's position to be at the end of the carousel
    if ( this.managedElements.length === 0 ) {
      element.positionProperty.set( this.selectedElementPosition );
    }
    else {
      const lastElement = this.managedElements[ this.managedElements.length - 1 ];
      element.positionProperty.set( lastElement.positionProperty.value.plus( this.offsetBetweenElements ) );
    }

    // add element to the list of managed elements
    this.managedElements.push( element );

    // update opacities
    this.updateManagedElementOpacities();
  }

  /**
   * get an element from carousel by index
   * @param  {number} index Requested position in array of EnergySystemElements
   * @returns {EnergySystemElement}
   * @public
   */
  getElement( index ) {
    assert && assert( index < this.managedElements.length, `carousel index out of range: ${index}` );
    return this.managedElements[ index ];
  }

  /**
   * get the currently selected element from carousel
   * @returns {EnergySystemElement|null}
   * @public
   */
  getSelectedElement() {
    const i = this.targetIndexProperty.get();
    if ( i < this.managedElements.length ) {
      return this.managedElements[ i ];
    }
    return null;
  }

  /**
   * step this model element
   * @param {number} dt - time step, in seconds
   * @public
   */
  step( dt ) {
    if ( !this.atTargetPosition() ) {
      this.elapsedTransitionTime += dt;
      const targetCarouselOffset = this.offsetBetweenElements.times( -this.targetIndexProperty.get() );
      const totalTravelVector = targetCarouselOffset.minus( this.initialCarouselOffset );
      const transitionProportion = Utils.clamp( this.elapsedTransitionTime / TRANSITION_DURATION, 0, 1 );
      this.currentCarouselOffset =
        this.initialCarouselOffset.plus( totalTravelVector.times( Easing.CUBIC_IN_OUT.value( transitionProportion ) ) );
      this.updateManagedElementPositions();

      if ( transitionProportion === 1 ) {
        this.currentCarouselOffset = targetCarouselOffset;
      }

      if ( this.currentCarouselOffset === targetCarouselOffset ) {
        this.animationInProgressProperty.set( false );
      }
      this.updateManagedElementOpacities();
    }
  }

  /**
   * sets the position in model space of each element based on the state of the carousel
   * @private
   */
  updateManagedElementPositions() {
    for ( let i = 0; i < this.managedElements.length; i++ ) {
      let position = this.selectedElementPosition.plus( this.offsetBetweenElements.times( i ) );
      position = position.plus( this.currentCarouselOffset );
      this.managedElements[ i ].positionProperty.set( position );
    }
  }

  /**
   * sets the opacity of each element based on the state of the carousel. elements fade out as they get farther from
   * the active, selected position
   * @private
   */
  updateManagedElementOpacities() {
    this.managedElements.forEach( managedElement => {
      const distanceToSelection = managedElement.positionProperty.value.distance( this.selectedElementPosition );
      const opacity = Utils.clamp( 1 - ( distanceToSelection / this.offsetBetweenElements.magnitude ), 0, 1 );
      managedElement.opacityProperty.set( opacity );
    } );
  }

  /**
   * whether the current selected element is in its destination spot
   * @private
   * @returns {boolean}
   */
  atTargetPosition() {
    const targetCarouselOffset = this.offsetBetweenElements.times( -this.targetIndexProperty.value );
    return this.currentCarouselOffset.equals( targetCarouselOffset );
  }
}

energyFormsAndChanges.register( 'EnergySystemElementCarousel', EnergySystemElementCarousel );
export default EnergySystemElementCarousel;
<|endoftext|>


<commit_before>const $i = document.getElementById.bind(document)

onload()

function onload() {
  const shortcutsTable = $i('shortcutsTable')
  $i('save_btn').addEventListener('click', save)
  $i('restore_defaults_btn').addEventListener('click', (event) => {
    browser.storage.sync.set({
      'shortcuts': default_shortcuts
    })
  })
  $i('new_btn').addEventListener('click', (event) => {
    shortcutsTable.appendChild(newShortcutLine())
  })
  browser.storage.sync.get('shortcuts', ({
    shortcuts
  }) => {
    const shortcutLines = buildShortcuts(shortcuts)
    for (line of shortcutLines) {
      shortcutsTable.appendChild(line)
    }
    [...document.querySelectorAll('.remove_btn')].forEach((removeBtnNode) => {
      removeBtnNode.addEventListener('click', removeShortcutLine)
    })
  })
}

function removeShortcutLine(event) {
  const tr = event.target.parentNode.parentNode
  tr.parentNode.removeChild(tr)
}

function newShortcutLine() {
  const template = $i('templateKeyOption').cloneNode(true);
  template.hidden = false
  template.id = undefined
  template.querySelector('.remove_btn').addEventListener('click', removeShortcutLine)
  return template
}

function buildShortcuts(shortcuts = default_shortcuts) {
  return shortcuts.map((shortcut) => {
    template = newShortcutLine()
    template.querySelector('.val_name').value = shortcut.name
    template.querySelector('.val_key').value = shortcut.key
    template.querySelector('.val_path').value = shortcut.path
    return template
  })
}

function save(event) {
  const form = $i('shortcutsForm')
  if (!form.checkValidity()) {
    const targetClassList = event.target.classList
    if (targetClassList.contains('shake-btn')) {
      targetClassList.remove('shake-btn')
      void event.target.offsetWidth // hack to restart animation (forces reflow)
    }
    targetClassList.add('shake-btn')
    event.preventDefault()
    return
  }
  const toSetting = (trNode) => {
    let path = trNode.querySelector('.val_path').value
    path = path[0] == '/' ? path : '/' + path
    return {
      name: trNode.querySelector('.val_name').value,
      key: trNode.querySelector('.val_key').value,
      path: path
    }
  }
  const shortcuts = [...document.getElementById('shortcutsTable').children]
  browser.storage.sync.set({
    'shortcuts': shortcuts.map(toSetting)
  })
}

function remove(event) {
  const tr = event.target.parentNode.parentNode
  tr.parentNode.removeChild(tr)
}
<commit_msg>fix options<commit_after>const $i = document.getElementById.bind(document)

onload()

function onload() {
  const shortcutsTable = $i('shortcutsTable')
  $i('save_btn').addEventListener('click', save)
  $i('restore_defaults_btn').addEventListener('click', (event) => {
    browser.storage.sync.set({
      'shortcuts': default_shortcuts
    })
  })
  $i('new_btn').addEventListener('click', (event) => {
    shortcutsTable.appendChild(newShortcutLine())
  })
  browser.storage.sync.get('shortcuts').then(function({
    shortcuts
  }) {
    const shortcutLines = buildShortcuts(shortcuts)
    for (line of shortcutLines) {
      shortcutsTable.appendChild(line)
    }
    [...document.querySelectorAll('.remove_btn')].forEach((removeBtnNode) => {
      removeBtnNode.addEventListener('click', removeShortcutLine)
    })
  })
}

function removeShortcutLine(event) {
  const tr = event.target.parentNode.parentNode
  tr.parentNode.removeChild(tr)
}

function newShortcutLine() {
  const template = $i('templateKeyOption').cloneNode(true);
  template.hidden = false
  template.id = undefined
  template.querySelector('.remove_btn').addEventListener('click', removeShortcutLine)
  return template
}

function buildShortcuts(shortcuts = default_shortcuts) {
  return shortcuts.map((shortcut) => {
    template = newShortcutLine()
    template.querySelector('.val_name').value = shortcut.name
    template.querySelector('.val_key').value = shortcut.key
    template.querySelector('.val_path').value = shortcut.path
    return template
  })
}

function save(event) {
  const form = $i('shortcutsForm')
  if (!form.checkValidity()) {
    const targetClassList = event.target.classList
    if (targetClassList.contains('shake-btn')) {
      targetClassList.remove('shake-btn')
      void event.target.offsetWidth // hack to restart animation (forces reflow)
    }
    targetClassList.add('shake-btn')
    event.preventDefault()
    return
  }
  const toSetting = (trNode) => {
    let path = trNode.querySelector('.val_path').value
    path = path[0] == '/' ? path : '/' + path
    return {
      name: trNode.querySelector('.val_name').value,
      key: trNode.querySelector('.val_key').value,
      path: path
    }
  }
  const shortcuts = [...document.getElementById('shortcutsTable').children]
  browser.storage.sync.set({
    'shortcuts': shortcuts.map(toSetting)
  })
}

function remove(event) {
  const tr = event.target.parentNode.parentNode
  tr.parentNode.removeChild(tr)
}
<|endoftext|>