<commit_before>var northPoll = angular.module('northPoll', [
  'ui.router',
  'chart.js',
  'btford.socket-io'
]);

// Ui-router
northPoll.config(function ($stateProvider) {
  $stateProvider.state('listPolls', {
    templateUrl: 'views/partials/polls.jade',
    url: ''
  });
  $stateProvider.state('answerInstancePoll', {
    templateUrl: 'views/partials/answer.jade',
    url: ''
  });
  $stateProvider.state('statsInstancePoll', {
    templateUrl: 'views/partials/statsPoll.jade',
    url: ''
  });
  $stateProvider.state('createPoll', {
    templateUrl: 'views/partials/create_poll.jade',
    url: 'createPoll'
  })
});

northPoll.factory('ActualInstanceOfPoll', function () {
  return {instance: '', poll: ''};
});

northPoll.factory('mySocket', function (socketFactory) {
  return socketFactory();
});

// Stat controller
northPoll.controller("statsAppController", function ($http, $scope) {
  $http.get("/api/polls/stats").then(function (response) {
    $scope.total = response.data.nb_total;
    $scope.recent = response.data.nb_recent;
    $scope.open = response.data.nb_open;
  });
});

// Angular chart JS
northPoll.controller("statsInstanceController", function ($scope, $http, ActualInstanceOfPoll, mySocket) {

  $scope.instanceName = ActualInstanceOfPoll.instance.name;
  $scope.pollName = ActualInstanceOfPoll.poll.name;

  $scope.questions = [];

  mySocket.forward('updateVotes', $scope);

  $scope.$on('socket:updateVotes', function(ev, data) {
    $scope.questions = data;
  });

  mySocket.emit('salut');

  $http.get("/api/polls/" + ActualInstanceOfPoll.poll.id + "/questions").then(function (response) {
    response.data.questions.forEach(function (question, idx, arrResp) {
      var nbChoices = 0;
      var idxQuest = idx;
      $scope.questions.push({
        nb_answers:null,
        question_text:question.text,
        labels:[],
        data:[],
        percentage:[]
      });

      $http.get(
        "/api/polls/" + ActualInstanceOfPoll.poll.id +
        "/instances/" + ActualInstanceOfPoll.instance.id +
        "/results/questions/" + question.id
      )
        .then(function (response) {
          $scope.questions[idxQuest].nb_answers = response.data.nb_answers;

          response.data.results.forEach(function (choice, idx, arr) {
            $scope.questions[idxQuest].labels.push(choice.text);
            $scope.questions[idxQuest].data.push(choice.nb_chosen);
            nbChoices += choice.nb_chosen;
            $scope.questions[idxQuest].percentage.push(choice.nb_chosen * 100);
            if(idxQuest === arrResp.length - 1 && idx === arr.length - 1) {
              $scope.questions.forEach(function(question, idx, arr) {
                question.percentage.forEach(function(percentageChoice, idx, arr) {
                  question.percentage[idx] = percentageChoice / nbChoices;
                  console.log($scope.questions);
                });
              });
            }
          });
        });
    });
  });

});

northPoll.controller("pollsController", function ($scope, $http, ActualInstanceOfPoll) {

  $scope.setActualInstanceOfPoll = function (inst, poll) {
    ActualInstanceOfPoll.instance = inst;
    ActualInstanceOfPoll.poll = poll;
  }

  $scope.participateInInstance = function (instance, poll) {
    $scope.setActualInstanceOfPoll(instance, poll);
  }

  $scope.statsOfAnInstance = function (instance, poll) {
    $scope.setActualInstanceOfPoll(instance, poll);
  }

  $scope.polls = [];
  $http.get("/api/polls/open").then(function (response) {
    $scope.polls = $scope.polls.concat(response.data.polls);

    $http.get("/api/polls/draft").then(function (response) {
      var nb_draft = response.data.polls.length;
      $scope.polls = $scope.polls.concat(response.data.polls);

      $http.get("/api/polls/closed").then(function (response) {
        $scope.polls = $scope.polls.concat(response.data.polls);
      });

      var inserted = 0;
      $scope.polls.forEach(function (poll, idx, arr) {
        poll.instances = [];
        if (poll.state != 'draft') {
          $http.get('/api/polls/' + poll.id + '/instances').then(function (resp) {
            poll.instances = resp.data.instances;
            inserted++;
            if (inserted == arr.length - nb_draft) {
              //console.log($scope.polls);
            }
          });
        }
      });
    });
  });

});

northPoll.controller("PollController", function ($scope, $http) {

    $scope.pollActionString = "Créer le sondage";
    $scope.pollActionDisabled = false;
    $scope.formVisible = true;
    $scope.questionVisible = false;
    $scope.questionAvailable = false;
    $scope.deletePossible = false;
    $scope.instancesVisible = false;
    $scope.isPublic = false;
    $scope.questionAdded = false;

    /* Variables to indicate if the fields in the form are valid or not. By defautl they are. When the user tries to post the form we will check the validity and change those variable accordingly. */
    $scope.pollNameValid = true;
    $scope.adminNameValid = true;
    $scope.adminPasswordValid = true;
    $scope.adminPasswordConfirmationValid = true;
    $scope.userPasswordValid = true;
    $scope.userPasswordConfirmationValid = true;

    $scope.pollId = "none";

    /* If the user is creating is creating a poll, we post the new poll informations, in the other case we update the poll */
    $scope.pollAction = function() {

        if ($scope.pollActionString == "Créer le sondage"){
            $http({
                url: "/api/polls/",
                method: "POST",
                data: {name: $scope.pollName, creator : $scope.adminName, admin_password : $scope.adminPassword, user_password : $scope.userPassword, public_results : $scope.isPublic}
            }).success(function (data, status, headers, config) {
                // We retrieve the pollId.
                $scope.pollId = data.id;
                // New actions are now available.
                $scope.pollActionString = "Appliquer les modifications";
                $scope.pollActionDisabled = true;
                //$scope.deletePossible = true;
                $scope.questionAvailable = true;
            }).error(function (data, status, headers, config) {
                alert("Erreur lors de l'envoi");
            });
        }

        else
        {
            // TODO : Update form
        }
    }

    $scope.createQuestion = function(){
        $scope.formVisible = false;
        $scope.questionVisible = true;
        $scope.instancesVisible = false;
    }

    $scope.modifyPoll = function(){
        $scope.formVisible = true;
        $scope.questionVisible = false;
        //if($scope.questionAdded){$scope.instancesVisible = true;}
    }

    $scope.choices = [];
    $scope.isCorrect = false;
    $scope.isOptional = false;

    $scope.addChoice = function() {
        $scope.choices.push({text : $scope.choiceText, correct : $scope.isCorrect});
        $scope.choiceText = "";
        $scope.isCorrect = false;
        $scope.maxChoices = 1;
    }

    $scope.addQuestion = function(){
        $scope.choices.push({text : $scope.choiceText, correct : $scope.isCorrect});
        $http({
            url: "/api/polls/" + $scope.pollId + "/questions",
            method: "POST",
            data: {text: $scope.questionText, choices_available : $scope.maxChoices, optional : $scope.isOptional, choices : $scope.choices}
        }).success(function (data, status, headers, config) {
            $scope.choices = [];
            $scope.choiceText = "";
            $scope.isCorrect = false;
            $scope.isOptional = false;
            $scope.maxChoices = 1;
            $scope.questionText = "";
            $scope.questionAdded = true;
            alert("Question ajoutée");
        }).error(function (data, status, headers, config) {
            alert("Erreur lors de l'envoi");
        });
    }

    $scope.addInstance = function(){
        $http({
            url: "/api/polls/" + $scope.pollId + "/instances",
            method: "POST",
            data: {name: $scope.instanceName}
        }).success(function (data, status, headers, config) {
            alert("Nouvelle instance créée");
        }).error(function (data, status, headers, config) {
            alert("Erreur lors de l'envoi");
        });
    }
});

northPoll.controller("AnswerCtrl", function ($scope, $http, ActualInstanceOfPoll, mySocket) {
  $scope.select = function (choice) {
    if (choice.selected || $scope.question.remainingChoices > 0) {
      $scope.question.remainingChoices += (choice.selected ? 1 : -1)
      choice.selected = !choice.selected;
    }

    $scope.nextDisabled = !$scope.optional && $scope.question.remainingChoices == $scope.question.choices_available;
  }

  $scope.load = function () {
    // Chargement des données de la question
    $scope.question = $scope.questions[$scope.currentQuestion];
    $scope.optional = $scope.question.optional;

    // Mise à jour des variables de contrôle
    if ($scope.question.remainingChoices == undefined) {
      $scope.question.remainingChoices = $scope.question.choices_available;
    }
    $scope.nextOrSubmit = ($scope.currentQuestion < $scope.questions.length - 1 ? "Suivant" : "Envoyer");
    $scope.nextDisabled = !$scope.optional && $scope.question.remainingChoices == $scope.question.choices_available;
    $scope.prevDisabled = $scope.currentQuestion == 0;
  }

  $scope.previous = function () {
    $scope.currentQuestion--;
    $scope.load();
  }

  $scope.next = function () {

    if ($scope.currentQuestion < $scope.questions.length - 1) {
      $scope.currentQuestion++;
      $scope.load();
    }
    else {
      $scope.results = [];
      // Compilation des résultats
      for (var i in $scope.questions) {
        var question = $scope.questions[i];
        var result = {};
        result.question = question.text;
        result.choices = [];
        for (var j in question.choices) {
          var choice = question.choices[j];
          if (choice.selected != undefined && choice.selected) {
            result.choices.push(choice.text);
          }
        }
        $scope.results.push(result);
      }

      console.log($scope.results);
      $http({
        url: "/api/polls/" + $scope.pollid + "/instances/" + $scope.instanceid + "/results",
        method: "POST",
        data: {results: $scope.results}
      }).success(function (data, status, headers, config) {
        console.log($scope.results);
        alert("Envoyé");
      }).error(function (data, status, headers, config) {
        alert("Erreur lors de l'envoi");
      });
    }
  }

  $scope.pollid = ActualInstanceOfPoll.poll.id;
  $scope.instanceid = ActualInstanceOfPoll.instance.id;

  $http({
    url: "/api/polls/" + $scope.pollid + "/questions",
    method: "GET"
  }).success(function (data, status, headers, config) {
    $scope.questions = data.questions;
    $scope.currentQuestion = -1;
    $scope.results = [];
    $scope.next();
  });
});
<commit_msg>Commentaires de app.js<commit_after>var northPoll = angular.module('northPoll', [
  'ui.router',
  'chart.js',
  'btford.socket-io'
]);

// Ui-router
northPoll.config(function ($stateProvider) {
  $stateProvider.state('listPolls', {
    templateUrl: 'views/partials/polls.jade',
    url: ''
  });
  $stateProvider.state('answerInstancePoll', {
    templateUrl: 'views/partials/answer.jade',
    url: ''
  });
  $stateProvider.state('statsInstancePoll', {
    templateUrl: 'views/partials/statsPoll.jade',
    url: ''
  });
  $stateProvider.state('createPoll', {
    templateUrl: 'views/partials/create_poll.jade',
    url: 'createPoll'
  })
});

northPoll.factory('ActualInstanceOfPoll', function () {
  return {instance: '', poll: ''};
});

northPoll.factory('mySocket', function (socketFactory) {
  return socketFactory();
});

// Stat controller
northPoll.controller("statsAppController", function ($http, $scope) {
  $http.get("/api/polls/stats").then(function (response) {
    $scope.total = response.data.nb_total;
    $scope.recent = response.data.nb_recent;
    $scope.open = response.data.nb_open;
  });
});

// Angular chart JS
northPoll.controller("statsInstanceController", function ($scope, $http, ActualInstanceOfPoll, mySocket) {

  $scope.instanceName = ActualInstanceOfPoll.instance.name;
  $scope.pollName = ActualInstanceOfPoll.poll.name;

  $scope.questions = [];

  mySocket.forward('updateVotes', $scope);

  $scope.$on('socket:updateVotes', function(ev, data) {
    $scope.questions = data;
  });

  mySocket.emit('salut');

  $http.get("/api/polls/" + ActualInstanceOfPoll.poll.id + "/questions").then(function (response) {
    response.data.questions.forEach(function (question, idx, arrResp) {
      var nbChoices = 0;
      var idxQuest = idx;
      $scope.questions.push({
        nb_answers:null,
        question_text:question.text,
        labels:[],
        data:[],
        percentage:[]
      });

      $http.get(
        "/api/polls/" + ActualInstanceOfPoll.poll.id +
        "/instances/" + ActualInstanceOfPoll.instance.id +
        "/results/questions/" + question.id
      )
        .then(function (response) {
          $scope.questions[idxQuest].nb_answers = response.data.nb_answers;

          response.data.results.forEach(function (choice, idx, arr) {
            $scope.questions[idxQuest].labels.push(choice.text);
            $scope.questions[idxQuest].data.push(choice.nb_chosen);
            nbChoices += choice.nb_chosen;
            $scope.questions[idxQuest].percentage.push(choice.nb_chosen * 100);
            if(idxQuest === arrResp.length - 1 && idx === arr.length - 1) {
              $scope.questions.forEach(function(question, idx, arr) {
                question.percentage.forEach(function(percentageChoice, idx, arr) {
                  question.percentage[idx] = percentageChoice / nbChoices;
                  console.log($scope.questions);
                });
              });
            }
          });
        });
    });
  });

});

northPoll.controller("pollsController", function ($scope, $http, ActualInstanceOfPoll) {

  $scope.setActualInstanceOfPoll = function (inst, poll) {
    ActualInstanceOfPoll.instance = inst;
    ActualInstanceOfPoll.poll = poll;
  }

  $scope.participateInInstance = function (instance, poll) {
    $scope.setActualInstanceOfPoll(instance, poll);
  }

  $scope.statsOfAnInstance = function (instance, poll) {
    $scope.setActualInstanceOfPoll(instance, poll);
  }

  $scope.polls = [];
  $http.get("/api/polls/open").then(function (response) {
    $scope.polls = $scope.polls.concat(response.data.polls);

    $http.get("/api/polls/draft").then(function (response) {
      var nb_draft = response.data.polls.length;
      $scope.polls = $scope.polls.concat(response.data.polls);

      $http.get("/api/polls/closed").then(function (response) {
        $scope.polls = $scope.polls.concat(response.data.polls);
      });

      var inserted = 0;
      $scope.polls.forEach(function (poll, idx, arr) {
        poll.instances = [];
        if (poll.state != 'draft') {
          $http.get('/api/polls/' + poll.id + '/instances').then(function (resp) {
            poll.instances = resp.data.instances;
            inserted++;
            if (inserted == arr.length - nb_draft) {
              //console.log($scope.polls);
            }
          });
        }
      });
    });
  });

});

northPoll.controller("PollController", function ($scope, $http) {

    $scope.pollActionString = "Créer le sondage";
    $scope.pollActionDisabled = false;
    $scope.formVisible = true;
    $scope.questionVisible = false;
    $scope.questionAvailable = false;
    $scope.deletePossible = false;
    $scope.instancesVisible = false;
    $scope.isPublic = false;
    $scope.questionAdded = false;

    /* Variables to indicate if the fields in the form are valid or not. By defautl they are. When the user tries to post the form we will check the validity and change those variable accordingly. */
    $scope.pollNameValid = true;
    $scope.adminNameValid = true;
    $scope.adminPasswordValid = true;
    $scope.adminPasswordConfirmationValid = true;
    $scope.userPasswordValid = true;
    $scope.userPasswordConfirmationValid = true;

    $scope.pollId = "none";

    /* If the user is creating is creating a poll, we post the new poll informations, in the other case we update the poll */
    $scope.pollAction = function() {

        if ($scope.pollActionString == "Créer le sondage"){
            $http({
                url: "/api/polls/",
                method: "POST",
                data: {name: $scope.pollName, creator : $scope.adminName, admin_password : $scope.adminPassword, user_password : $scope.userPassword, public_results : $scope.isPublic}
            }).success(function (data, status, headers, config) {
                // We retrieve the pollId.
                $scope.pollId = data.id;
                // New actions are now available.
                $scope.pollActionString = "Appliquer les modifications";
                $scope.pollActionDisabled = true;
                //$scope.deletePossible = true;
                $scope.questionAvailable = true;
            }).error(function (data, status, headers, config) {
                alert("Erreur lors de l'envoi");
            });
        }

        else
        {
            // TODO : Update form
        }
    }

    $scope.createQuestion = function(){
        $scope.formVisible = false;
        $scope.questionVisible = true;
        $scope.instancesVisible = false;
    }

    $scope.modifyPoll = function(){
        $scope.formVisible = true;
        $scope.questionVisible = false;
        //if($scope.questionAdded){$scope.instancesVisible = true;}
    }

    $scope.choices = [];
    $scope.isCorrect = false;
    $scope.isOptional = false;

    $scope.addChoice = function() {
        $scope.choices.push({text : $scope.choiceText, correct : $scope.isCorrect});
        $scope.choiceText = "";
        $scope.isCorrect = false;
        $scope.maxChoices = 1;
    }

    $scope.addQuestion = function(){
        $scope.choices.push({text : $scope.choiceText, correct : $scope.isCorrect});
        $http({
            url: "/api/polls/" + $scope.pollId + "/questions",
            method: "POST",
            data: {text: $scope.questionText, choices_available : $scope.maxChoices, optional : $scope.isOptional, choices : $scope.choices}
        }).success(function (data, status, headers, config) {
            $scope.choices = [];
            $scope.choiceText = "";
            $scope.isCorrect = false;
            $scope.isOptional = false;
            $scope.maxChoices = 1;
            $scope.questionText = "";
            $scope.questionAdded = true;
            alert("Question ajoutée");
        }).error(function (data, status, headers, config) {
            alert("Erreur lors de l'envoi");
        });
    }

    $scope.addInstance = function(){
        $http({
            url: "/api/polls/" + $scope.pollId + "/instances",
            method: "POST",
            data: {name: $scope.instanceName}
        }).success(function (data, status, headers, config) {
            alert("Nouvelle instance créée");
        }).error(function (data, status, headers, config) {
            alert("Erreur lors de l'envoi");
        });
    }
});

// This angular controller will handle the response process. It is responsible of everything related to the answer fragment of the page.
northPoll.controller("AnswerCtrl", function ($scope, $http, ActualInstanceOfPoll, mySocket) {

  // This function handles the click on a choice
  $scope.select = function (choice) {

    // If the choice can be selected or is currently selected
    if (choice.selected || $scope.question.remainingChoices > 0) {

      // We toggle the choice on or off
      $scope.question.remainingChoices += (choice.selected ? 1 : -1)
      choice.selected = !choice.selected;
    }

    // Will enable or disable the "Next" button
    $scope.nextDisabled = !$scope.optional && $scope.question.remainingChoices == $scope.question.choices_available;
  }

  // This function will refresh the answer view (question, choice, etc) each time the user changes question
  $scope.load = function () {
    // Loading the question and its parameters
    $scope.question = $scope.questions[$scope.currentQuestion];
    $scope.optional = $scope.question.optional;

    // We update the control variables that enable/disable interface controls
    if ($scope.question.remainingChoices == undefined) {
      $scope.question.remainingChoices = $scope.question.choices_available;
    }
    $scope.nextOrSubmit = ($scope.currentQuestion < $scope.questions.length - 1 ? "Suivant" : "Envoyer");
    $scope.nextDisabled = !$scope.optional && $scope.question.remainingChoices == $scope.question.choices_available;
    $scope.prevDisabled = $scope.currentQuestion == 0;
  }

  // This function is called when the user clicks on "Previous" button, we simply decrement the counter and refresh the view
  $scope.previous = function () {
    $scope.currentQuestion--;
    $scope.load();
  }

  // This function is called when the user clicks on "Next" button
  $scope.next = function () {

    // If there are more quesrtions to answer, we simply increment the counter and load the next one
    if ($scope.currentQuestion < $scope.questions.length - 1) {
      $scope.currentQuestion++;
      $scope.load();
    }

    // Otherwise, we have to send the data to the server
    else {
      // Result array
      $scope.results = [];

      // We can now walk through the questions and pack the answers on the array
      for (var i in $scope.questions) {
        var question = $scope.questions[i];
        var result = {};
        result.question = question.text;
        result.choices = [];

        // We store each selected choice
        for (var j in question.choices) {
          var choice = question.choices[j];
          if (choice.selected != undefined && choice.selected) {
            result.choices.push(choice.text);
          }
        }
        $scope.results.push(result);
      }

      // We can now send the HTTP request to submit the answers
      $http({
        url: "/api/polls/" + $scope.pollid + "/instances/" + $scope.instanceid + "/results",
        method: "POST",
        data: {results: $scope.results}
      }).success(function (data, status, headers, config) {
        console.log($scope.results);
        alert("Envoyé");
      }).error(function (data, status, headers, config) {
        alert("Erreur lors de l'envoi");
      });
    }
  }

  // initialization, we need to get all the question of the selected choice, so we proceed an HTTP request to get them
  $scope.pollid = ActualInstanceOfPoll.poll.id;
  $scope.instanceid = ActualInstanceOfPoll.instance.id;

  $http({
    url: "/api/polls/" + $scope.pollid + "/questions",
    method: "GET"
  }).success(function (data, status, headers, config) {

    // On success, we store the data and the answer process can begin
    $scope.questions = data.questions;
    $scope.currentQuestion = -1;
    $scope.results = [];
    $scope.next();
  });
});
<|endoftext|>


<commit_before>var packageSizes = [{name:"test", size:"100"}, {name:"test2", size:"200"}];

function init() {
    updatePackageSizes();
    updatePackageSizeOptions();
}

function addEntry() {
    var entry = $(document.createElement("div"))
    entry.appendTo("#add_list");

    entry.append("Package: ");
    var pkgSelect = document.createElement("select");
    pkgSelect.setAttribute("onchange", "updateTotal()");

    packageSizes.forEach(function(each) {
        packageSize = document.createElement("option");
        packageSize.innerHTML = each.name + " (" + each.size + ")";
        pkgSelect.appendChild(packageSize);

        $(packageSize).data("name", each.name);
        $(packageSize).data("size", each.size);
    });

    entry.append(pkgSelect);

    entry.append(" Amount: ");
    input = document.createElement("input");
    input.setAttribute("type", "text");
    input.setAttribute("onkeyup", "updateTotal()");
    entry.append(input);

    entry.append(" Location: ");
    var input = document.createElement("input");
    input.setAttribute("type", "text");
    entry.append(input);
}

// Get an array of entries
function getEntryList() {
    var a = [];

    $("#add_list").children().each(function() {
        var entry = {};

        entry.packageName = $(this).children("select").children("option:selected").data("name");
        entry.packageSize = $(this).children("select").children("option:selected").data("size");
        entry.amount = $(this).children("input").val();
        entry.location = $(this).children("input").next().val();
        a.push(entry);
    });

    return a;
}

// Get an array of entries
function getPackageSizeList() {
    return packageSizes;
}

// Update the total text
function updateTotal() {
    $("#total_text").text(calculateTotal());
}

function calculateTotal() {
    var total = 0;

    $("#add_list").children("div").each(function() { // each entry
        var size = parseInt($(this).children("select").children("option:selected").data("size")) || 0;
        var amount = parseInt($(this).children("input").val()) || 0;
        total += size * amount;
    });

    return total;
}

function submitAdd() {
    // post to submit route
    // return to last page
    console.log("Submit: " + calculateTotal());
}

function updatePackageSizes() {
    // retrieve package sizes from backend
    // update packageSizes
    updatePackageSizeOptions();
}

function updatePackageSizeOptions() {
    // update options
    $("#add_list").children().each(function() {
        var entry = $(this).children("select");

        packageSizes.forEach(function(each) {
            packageSize = document.createElement("option");
            packageSize.innerHTML = each.name + " (" + each.size + ")";
            entry.append(packageSize);
        });
    });
}

function submitNewPackageSize() {
    var name = $("#pkg_name").val();
    var size = parseInt($("#pkg_size").val()) || -1;

    if (name == "" || size == -1) {
        console.log("Error: Submit new package size.");
        return;
    }

    console.log("Submit new package size: " + name + ", " + size);

    // if successful, updatePackageSizeOptions()
}
<commit_msg>IM-80<commit_after>var packageSizes = [{name:"test", size:"100"}, {name:"test2", size:"200"}];

function init() {
    updatePackageSizes();
    updatePackageSizeOptions();
}

function addEntry() {
    var entry = $(document.createElement("div"));
    entry.appendTo("#add_list");

    entry.append("Package: ");
    var pkgSelect = document.createElement("select");
    pkgSelect.setAttribute("onchange", "updateTotal()");

    packageSizes.forEach(function(each) {
        packageSize = document.createElement("option");
        packageSize.innerHTML = each.name + " (" + each.size + ")";
        pkgSelect.appendChild(packageSize);

        $(packageSize).data("name", each.name);
        $(packageSize).data("size", each.size);
    });

    entry.append(pkgSelect);

    entry.append(" Amount: ");
    input = document.createElement("input");
    input.setAttribute("type", "text");
    input.setAttribute("onkeyup", "updateTotal()");
    entry.append(input);

    entry.append(" Location: ");
    var input = document.createElement("input");
    input.setAttribute("type", "text");
    entry.append(input);
}

// Get an array of entries
function getEntryList() {
    var a = [];

    $("#add_list").children().each(function() {
        var entry = {};

        entry.packageName = $(this).children("select").children("option:selected").data("name");
        entry.packageSize = $(this).children("select").children("option:selected").data("size");
        entry.amount = $(this).children("input").val();
        entry.location = $(this).children("input").next().val();
        a.push(entry);
    });

    return a;
}

// Get an array of entries
function getPackageSizeList() {
    return packageSizes;
}

// Update the total text
function updateTotal() {
    $("#total_text").text(calculateTotal());
}

function calculateTotal() {
    var total = 0;

    $("#add_list").children("div").each(function() { // each entry
        var size = parseInt($(this).children("select").children("option:selected").data("size")) || 0;
        var amount = parseInt($(this).children("input").val()) || 0;
        total += size * amount;
    });

    return total;
}

function submitAdd() {
    // post to submit route
    // return to last page
    console.log("Submit: " + calculateTotal());
}

function updatePackageSizes() {
    // retrieve package sizes from backend
    // update packageSizes
    updatePackageSizeOptions();
}

function updatePackageSizeOptions() {
    // update options
    $("#add_list").children().each(function() {
        var entry = $(this).children("select");

        packageSizes.forEach(function(each) {
            packageSize = document.createElement("option");
            packageSize.innerHTML = each.name + " (" + each.size + ")";
            entry.append(packageSize);
        });
    });
}

function submitNewPackageSize() {
    var name = $("#pkg_name").val();
    var size = parseInt($("#pkg_size").val()) || -1;

    if (name == "" || size == -1) {
        console.log("Error: Submit new package size.");
        return;
    }

    console.log("Submit new package size: " + name + ", " + size);

    // if successful, updatePackageSizeOptions()
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

/* eslint-disable guard-for-in */
import {AttributeManager} from 'luma.gl';
import {addIterator, areEqualShallow, log} from '../utils';
import isDeepEqual from 'lodash.isequal';
import assert from 'assert';
import ViewportMercator from 'viewport-mercator-project';

/*
 * @param {string} props.id - layer name
 * @param {array}  props.data - array of data instances
 * @param {number} props.width - viewport width, synced with MapboxGL
 * @param {number} props.height - viewport width, synced with MapboxGL
 * @param {bool} props.isPickable - whether layer response to mouse event
 * @param {bool} props.opacity - opacity of the layer
 */
const DEFAULT_PROPS = {
  key: 0,
  opacity: 0.8,
  numInstances: undefined,
  data: [],
  isPickable: false,
  deepCompare: false,
  disableMercatorProjector: false,
  getValue: x => x,
  onHover: () => {},
  onClick: () => {},
  // Update triggers: a key change detection mechanism in deck.gl
  //
  // The value of `updateTriggers` is a map with fields corresponding to
  // attribute names (or `all`). Each field has a value which is an object,
  // it can contain any amount of data. The data for each field is compared
  // shallowly, and if a change is detected, the attribute is invalidated
  // (all attributes are invalidated if the `all` key is used.)
  // Note: updateTriggers are ignored by normal shallow comparison, so it is
  // OK for the app to mint a new object on every render.
  updateTriggers: {}
};

const ATTRIBUTES = {
  instancePickingColors:
    {size: 3, '0': 'pickRed', '1': 'pickGreen', '2': 'pickBlue'}
};

let counter = 0;

export default class BaseLayer {

  static get attributes() {
    return ATTRIBUTES;
  }

  /**
   * @classdesc
   * Base Layer class
   *
   * @class
   * @param {object} props - See docs above
   */
  /* eslint-disable max-statements */
  constructor(props) {

    props = {
      ...DEFAULT_PROPS,
      ...props
    };

    // Add iterator to objects
    // TODO - Modifying props is an anti-pattern
    if (props.data) {
      addIterator(props.data);
      assert(props.data[Symbol.iterator], 'data prop must have an iterator');
    }

    this.props = props;

    this.checkProp(props.data, 'data');
    this.checkProp(props.id, 'id');
    this.checkProp(props.width, 'width');
    this.checkProp(props.height, 'height');
    this.checkProp(props.latitude, 'latitude');
    this.checkProp(props.longitude, 'longitude');
    this.checkProp(props.zoom, 'zoom');

    this.count = counter++;
  }
  /* eslint-enable max-statements */

  // //////////////////////////////////////////////////
  // LIFECYCLE METHODS, overridden by the layer subclasses

  // Called once to set up the initial state
  initializeState() {
  }

  // gl context is now available
  didMount() {
  }

  shouldUpdate(oldProps, newProps) {
    // Check update triggers, and invalidate props accordingly
    if (this.checkUpdateTriggers(oldProps, newProps)) {
      return true;
    }
    // If any props have changed, ignoring updateTriggers objects
    // (updateTriggers are expected to be reminted on every update)
    const equalShallow = areEqualShallow(newProps, oldProps, {
      ignore: {updateTriggers: true}
    });
    if (!equalShallow) {
      if (newProps.data !== oldProps.data) {
        this.setState({dataChanged: true});
      }
      return true;
    }
    if (newProps.deepCompare && !isDeepEqual(newProps.data, oldProps.data)) {
      // Support optional deep compare of data
      // Note: this is quite inefficient, app should use buffer props instead
      this.setState({dataChanged: true});
      return true;
    }
    return false;
  }

  // Default implementation, all attributeManager will be updated
  willReceiveProps(oldProps, newProps) {
    const {attributeManager} = this.state;
    if (this.state.dataChanged) {
      attributeManager.invalidateAll();
    }
  }

  // gl context still available
  willUnmount() {
  }

  // END LIFECYCLE METHODS
  // //////////////////////////////////////////////////

  // Public API

  setNeedsRedraw(redraw = true) {
    if (this.state) {
      this.state.needsRedraw = redraw;
    }
  }

  // Checks state of attributes and model
  // TODO - is attribute manager needed? - Model should be enough.
  getNeedsRedraw({clearRedrawFlags = false} = {}) {
    // this method may be called by the render loop as soon a the layer
    // has been created, so guard against uninitialized state
    if (!this.state) {
      return false;
    }

    const {attributeManager, model} = this.state;
    let redraw = false;
    redraw = redraw || this.state.needsRedraw;
    this.state.needsRedraw = this.state.needsRedraw && !clearRedrawFlags;

    redraw = redraw || attributeManager.getNeedsRedraw({clearRedrawFlags});
    redraw = redraw || model.getNeedsRedraw({clearRedrawFlags});
    return redraw;
  }

  // Updates selected state members and marks the object for redraw
  setState(updateObject) {
    Object.assign(this.state, updateObject);
    this.state.needsRedraw = true;
  }

  // Updates selected state members and marks the object for redraw
  setUniforms(uniformMap) {
    if (this.state.model) {
      this.state.model.setUniforms(uniformMap);
    }
    // TODO - set needsRedraw on the model?
    this.state.needsRedraw = true;
    log(3, 'layer.setUniforms', uniformMap);
  }

  // Use iteration (the only required capability on data) to get first element
  getFirstObject() {
    const {data} = this.props;
    for (const object of data) {
      return object;
    }
    return null;
  }

  // INTERNAL METHODS

  // Deduces numer of instances. Intention is to support:
  // - Explicit setting of numInstances
  // - Auto-deduction for ES6 containers that define a size member
  // - Auto-deduction for Classic Arrays via the built-in length attribute
  // - Auto-deduction via arrays
  getNumInstances(props) {
    props = props || this.props;

    // First check if the layer has set its own value
    if (this.state && this.state.numInstances !== undefined) {
      return this.state.numInstances;
    }

    // Check if app has provided an explicit value
    if (props.numInstances !== undefined) {
      return props.numInstances;
    }

    const {data} = props;

    // Check if ES6 collection "count" function is available
    if (data && typeof data.count === 'function') {
      return data.count();
    }

    // Check if ES6 collection "size" attribute is set
    if (data && data.size !== undefined) {
      return data.size;
    }

    // Check if array length attribute is set
    // Note: checking this last since some ES6 collections (Immutable.js)
    // emit profuse warnings when trying to access `length` attribute
    if (data && data.length !== undefined) {
      return data.length;
    }

    throw new Error('Could not deduce numInstances');
  }

  // Internal Helpers

  checkProps(oldProps, newProps) {
    // Note: dataChanged might already be set
    if (newProps.data !== oldProps.data) {
      // Figure out data length
      this.state.dataChanged = true;
    }

    const viewportChanged =
      newProps.width !== oldProps.width ||
      newProps.height !== oldProps.height ||
      newProps.latitude !== oldProps.latitude ||
      newProps.longitude !== oldProps.longitude ||
      newProps.zoom !== oldProps.zoom;

    this.setState({viewportChanged});
  }

  updateAttributes(props) {
    const {attributeManager, model} = this.state;
    const numInstances = this.getNumInstances(props);
    // Figure out data length
    attributeManager.update({
      numInstances,
      bufferMap: props,
      context: this,
      // Don't worry about non-attribute props
      ignoreUnknownAttributes: true
    });
    if (model) {
      const changedAttributes =
        attributeManager.getChangedAttributes({clearChangedFlags: true});
      model.setAttributes(changedAttributes);
    }
  }

  updateBaseUniforms() {
    this.setUniforms({
      // apply gamma to opacity to make it visually "linear"
      opacity: Math.pow(this.props.opacity, 1 / 2.2)
    });
  }

  // Check if any update triggers have changed, and invalidate
  // attributes accordingly.
  checkUpdateTriggers(oldProps, newProps) {
    let change = false;
    const {attributeManager} = this.state;
    for (const propName in newProps.updateTriggers) {
      const oldTriggers = oldProps.updateTriggers[propName];
      const newTriggers = newProps.updateTriggers[propName];
      if (!areEqualShallow(oldTriggers, newTriggers)) {
        if (propName === 'all') {
          attributeManager.invalidateAll();
          change = true;
        } else {
          attributeManager.invalidate(propName);
          change = true;
        }
      }
    }
    return change;
  }

  // LAYER MANAGER API

  // Called by layer manager when a new layer is found
  /* eslint-disable max-statements */
  initializeLayer({gl}) {
    assert(gl);
    this.state = {gl};

    // Initialize state only once
    this.setState({
      attributeManager: new AttributeManager({id: this.props.id}),
      model: null,
      needsRedraw: true,
      dataChanged: true
    });

    const {attributeManager} = this.state;
    // All instanced layers get instancePickingColors attribute by default
    // Their shaders can use it to render a picking scene
    attributeManager.addInstanced(ATTRIBUTES, {
      instancePickingColors: {update: this.calculateInstancePickingColors}
    });

    this.setViewport();
    this.initializeState();
    assert(this.state.model, 'Model must be set in initializeState');
    this.setViewport();

    // TODO - the app must be able to override

    // Add any subclass attributes
    this.updateAttributes(this.props);
    this.updateBaseUniforms();

    const {model} = this.state;
    model.setInstanceCount(this.getNumInstances());
    model.id = this.props.id;
    model.program.id = `${this.props.id}-program`;
    model.geometry.id = `${this.props.id}-geometry`;

    // Create a model for the layer
    this._updateModel({gl});

    // Call life cycle method
    this.didMount();
  }
  /* eslint-enable max-statements */

  // Called by layer manager when existing layer is getting new props
  updateLayer(oldProps, newProps) {
    // Calculate standard change flags
    this.checkProps(oldProps, newProps);

    // Check if any props have changed
    if (this.shouldUpdate(oldProps, newProps)) {
      if (this.state.viewportChanged) {
        this.setViewport();
      }

      // Let the subclass mark what is needed for update
      this.willReceiveProps(oldProps, newProps);
      // Run the attribute updaters
      this.updateAttributes(newProps);
      // Update the uniforms
      this.updateBaseUniforms();

      if (this.state.model) {
        this.state.model.setInstanceCount(this.getNumInstances());
      }
    }

    this.state.dataChanged = false;
    this.state.viewportChanged = false;
  }

  // Called by manager when layer is about to be disposed
  // Note: not guaranteed to be called on application shutdown
  finalizeLayer() {
    this.willUnmount();
  }

  calculateInstancePickingColors(attribute, numInstances) {
    const {value, size} = attribute;
    // add 1 to index to seperate from no selection
    for (let i = 0; i < numInstances; i++) {
      const pickingColor = this.encodePickingColor(i);
      value[i * size + 0] = pickingColor[0];
      value[i * size + 1] = pickingColor[1];
      value[i * size + 2] = pickingColor[2];
    }
  }

  decodePickingColor(color) {
    assert(color instanceof Uint8Array);
    const [i1, i2, i3] = color;
    // 1 was added to seperate from no selection
    const index = i1 + i2 * 256 + i3 * 65536 - 1;
    return index;
  }

  encodePickingColor(i) {
    return [
      (i + 1) % 256,
      Math.floor((i + 1) / 256) % 256,
      Math.floor((i + 1) / 256 / 256) % 256
    ];
  }

  // VIRTUAL METHOD - Override to add or modify `info` object in sublayer
  // The sublayer may know what object e.g. lat,lon corresponds to using math
  // etc even when picking does not work
  onGetHoverInfo(info) {
    const {color} = info;
    info.index = this.decodePickingColor(color);
    // If props.data is an indexable array, get the object
    if (Array.isArray(this.props.data)) {
      info.object = this.props.data[info.index];
    }
    info.geoCoords = this.unproject({x: info.x, y: info.y});
    return info;
  }

  onHover(info) {
    const {color} = info;

    const selectedPickingColor = new Float32Array(3);
    selectedPickingColor[0] = color[0];
    selectedPickingColor[1] = color[1];
    selectedPickingColor[2] = color[2];
    this.setUniforms({selectedPickingColor});

    info = this.onGetHoverInfo(info);
    return this.props.onHover(info);
  }

  onClick(info) {
    info = this.onGetHoverInfo(info);
    return this.props.onClick(info);
  }

  // INTERNAL METHODS
  _updateModel({gl}) {
    const {model, attributeManager, uniforms} = this.state;

    assert(model);
    model.setAttributes(attributeManager.getAttributes());
    model.setUniforms(uniforms);
    // whether current layer responds to mouse events
    model.setPickable(this.props.isPickable);
  }

  checkProp(property, propertyName) {
    if (property === undefined || property === null) {
      throw new Error(`Property ${propertyName} undefined in layer ${this.props.id}`);
    }
  }

  // MAP LAYER FUNCTIONALITY
  setViewport() {
    const {
      width, height, latitude, longitude, zoom,
      disableMercatorProjector
    } = this.props;

    this.setState({
      viewport: {x: 0, y: 0, width, height},
      mercator: ViewportMercator({
        width, height, latitude, longitude, zoom,
        tileSize: 512
      })
    });

    this.setUniforms({
      viewport: [0, 0, width, height],
      mercatorScale: Math.pow(2, zoom),
      mercatorCenter: [longitude, latitude],
      disableMercatorProjector: disableMercatorProjector ? 1 : 0
    });

    log(3, this.state.viewport, latitude, longitude, zoom);
  }

  /**
   * Position conversion is done in shader, so in many cases there is no need
   * for this function
   * @param {Object|Array} latLng - Either [lat,lng] or {lat, lon}
   * @return {Object} - x, y
   */
  project(latLng) {
    const {mercator} = this.state;
    const [x, y] = Array.isArray(latLng) ?
      mercator.project([latLng[1], latLng[0]]) :
      mercator.project([latLng.lon, latLng.lat]);
    return {x, y};
  }

  unproject(xy) {
    const {mercator} = this.state;
    const [lon, lat] = Array.isArray(xy) ?
      mercator.unproject(xy) :
      mercator.unproject([xy.x, xy.y]);
    return {lat, lon};
  }
}
<commit_msg>Fix for instancePickingColor calculation, fixes picking<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

/* eslint-disable guard-for-in */
import {AttributeManager} from 'luma.gl';
import {addIterator, areEqualShallow, log} from '../utils';
import isDeepEqual from 'lodash.isequal';
import assert from 'assert';
import ViewportMercator from 'viewport-mercator-project';

/*
 * @param {string} props.id - layer name
 * @param {array}  props.data - array of data instances
 * @param {number} props.width - viewport width, synced with MapboxGL
 * @param {number} props.height - viewport width, synced with MapboxGL
 * @param {bool} props.isPickable - whether layer response to mouse event
 * @param {bool} props.opacity - opacity of the layer
 */
const DEFAULT_PROPS = {
  key: 0,
  opacity: 0.8,
  numInstances: undefined,
  data: [],
  isPickable: false,
  deepCompare: false,
  disableMercatorProjector: false,
  getValue: x => x,
  onHover: () => {},
  onClick: () => {},
  // Update triggers: a key change detection mechanism in deck.gl
  //
  // The value of `updateTriggers` is a map with fields corresponding to
  // attribute names (or `all`). Each field has a value which is an object,
  // it can contain any amount of data. The data for each field is compared
  // shallowly, and if a change is detected, the attribute is invalidated
  // (all attributes are invalidated if the `all` key is used.)
  // Note: updateTriggers are ignored by normal shallow comparison, so it is
  // OK for the app to mint a new object on every render.
  updateTriggers: {}
};

const ATTRIBUTES = {
  instancePickingColors:
    {size: 3, '0': 'pickRed', '1': 'pickGreen', '2': 'pickBlue'}
};

let counter = 0;

export default class BaseLayer {

  static get attributes() {
    return ATTRIBUTES;
  }

  /**
   * @classdesc
   * Base Layer class
   *
   * @class
   * @param {object} props - See docs above
   */
  /* eslint-disable max-statements */
  constructor(props) {

    props = {
      ...DEFAULT_PROPS,
      ...props
    };

    // Add iterator to objects
    // TODO - Modifying props is an anti-pattern
    if (props.data) {
      addIterator(props.data);
      assert(props.data[Symbol.iterator], 'data prop must have an iterator');
    }

    this.props = props;

    this.checkProp(props.data, 'data');
    this.checkProp(props.id, 'id');
    this.checkProp(props.width, 'width');
    this.checkProp(props.height, 'height');
    this.checkProp(props.latitude, 'latitude');
    this.checkProp(props.longitude, 'longitude');
    this.checkProp(props.zoom, 'zoom');

    this.count = counter++;
  }
  /* eslint-enable max-statements */

  // //////////////////////////////////////////////////
  // LIFECYCLE METHODS, overridden by the layer subclasses

  // Called once to set up the initial state
  initializeState() {
  }

  // gl context is now available
  didMount() {
  }

  shouldUpdate(oldProps, newProps) {
    // Check update triggers, and invalidate props accordingly
    if (this.checkUpdateTriggers(oldProps, newProps)) {
      return true;
    }
    // If any props have changed, ignoring updateTriggers objects
    // (updateTriggers are expected to be reminted on every update)
    const equalShallow = areEqualShallow(newProps, oldProps, {
      ignore: {updateTriggers: true}
    });
    if (!equalShallow) {
      if (newProps.data !== oldProps.data) {
        this.setState({dataChanged: true});
      }
      return true;
    }
    if (newProps.deepCompare && !isDeepEqual(newProps.data, oldProps.data)) {
      // Support optional deep compare of data
      // Note: this is quite inefficient, app should use buffer props instead
      this.setState({dataChanged: true});
      return true;
    }
    return false;
  }

  // Default implementation, all attributeManager will be updated
  willReceiveProps(oldProps, newProps) {
    const {attributeManager} = this.state;
    if (this.state.dataChanged) {
      attributeManager.invalidateAll();
    }
  }

  // gl context still available
  willUnmount() {
  }

  // END LIFECYCLE METHODS
  // //////////////////////////////////////////////////

  // Public API

  setNeedsRedraw(redraw = true) {
    if (this.state) {
      this.state.needsRedraw = redraw;
    }
  }

  // Checks state of attributes and model
  // TODO - is attribute manager needed? - Model should be enough.
  getNeedsRedraw({clearRedrawFlags = false} = {}) {
    // this method may be called by the render loop as soon a the layer
    // has been created, so guard against uninitialized state
    if (!this.state) {
      return false;
    }

    const {attributeManager, model} = this.state;
    let redraw = false;
    redraw = redraw || this.state.needsRedraw;
    this.state.needsRedraw = this.state.needsRedraw && !clearRedrawFlags;

    redraw = redraw || attributeManager.getNeedsRedraw({clearRedrawFlags});
    redraw = redraw || model.getNeedsRedraw({clearRedrawFlags});
    return redraw;
  }

  // Updates selected state members and marks the object for redraw
  setState(updateObject) {
    Object.assign(this.state, updateObject);
    this.state.needsRedraw = true;
  }

  // Updates selected state members and marks the object for redraw
  setUniforms(uniformMap) {
    if (this.state.model) {
      this.state.model.setUniforms(uniformMap);
    }
    // TODO - set needsRedraw on the model?
    this.state.needsRedraw = true;
    log(3, 'layer.setUniforms', uniformMap);
  }

  // Use iteration (the only required capability on data) to get first element
  getFirstObject() {
    const {data} = this.props;
    for (const object of data) {
      return object;
    }
    return null;
  }

  // INTERNAL METHODS

  // Deduces numer of instances. Intention is to support:
  // - Explicit setting of numInstances
  // - Auto-deduction for ES6 containers that define a size member
  // - Auto-deduction for Classic Arrays via the built-in length attribute
  // - Auto-deduction via arrays
  getNumInstances(props) {
    props = props || this.props;

    // First check if the layer has set its own value
    if (this.state && this.state.numInstances !== undefined) {
      return this.state.numInstances;
    }

    // Check if app has provided an explicit value
    if (props.numInstances !== undefined) {
      return props.numInstances;
    }

    const {data} = props;

    // Check if ES6 collection "count" function is available
    if (data && typeof data.count === 'function') {
      return data.count();
    }

    // Check if ES6 collection "size" attribute is set
    if (data && data.size !== undefined) {
      return data.size;
    }

    // Check if array length attribute is set
    // Note: checking this last since some ES6 collections (Immutable.js)
    // emit profuse warnings when trying to access `length` attribute
    if (data && data.length !== undefined) {
      return data.length;
    }

    throw new Error('Could not deduce numInstances');
  }

  // Internal Helpers

  checkProps(oldProps, newProps) {
    // Note: dataChanged might already be set
    if (newProps.data !== oldProps.data) {
      // Figure out data length
      this.state.dataChanged = true;
    }

    const viewportChanged =
      newProps.width !== oldProps.width ||
      newProps.height !== oldProps.height ||
      newProps.latitude !== oldProps.latitude ||
      newProps.longitude !== oldProps.longitude ||
      newProps.zoom !== oldProps.zoom;

    this.setState({viewportChanged});
  }

  updateAttributes(props) {
    const {attributeManager, model} = this.state;
    const numInstances = this.getNumInstances(props);
    // Figure out data length
    attributeManager.update({
      numInstances,
      bufferMap: props,
      context: this,
      // Don't worry about non-attribute props
      ignoreUnknownAttributes: true
    });
    if (model) {
      const changedAttributes =
        attributeManager.getChangedAttributes({clearChangedFlags: true});
      model.setAttributes(changedAttributes);
    }
  }

  updateBaseUniforms() {
    this.setUniforms({
      // apply gamma to opacity to make it visually "linear"
      opacity: Math.pow(this.props.opacity, 1 / 2.2)
    });
  }

  // Check if any update triggers have changed, and invalidate
  // attributes accordingly.
  checkUpdateTriggers(oldProps, newProps) {
    let change = false;
    const {attributeManager} = this.state;
    for (const propName in newProps.updateTriggers) {
      const oldTriggers = oldProps.updateTriggers[propName];
      const newTriggers = newProps.updateTriggers[propName];
      if (!areEqualShallow(oldTriggers, newTriggers)) {
        if (propName === 'all') {
          attributeManager.invalidateAll();
          change = true;
        } else {
          attributeManager.invalidate(propName);
          change = true;
        }
      }
    }
    return change;
  }

  // LAYER MANAGER API

  // Called by layer manager when a new layer is found
  /* eslint-disable max-statements */
  initializeLayer({gl}) {
    assert(gl);
    this.state = {gl};

    // Initialize state only once
    this.setState({
      attributeManager: new AttributeManager({id: this.props.id}),
      model: null,
      needsRedraw: true,
      dataChanged: true
    });

    const {attributeManager} = this.state;
    // All instanced layers get instancePickingColors attribute by default
    // Their shaders can use it to render a picking scene
    attributeManager.addInstanced(ATTRIBUTES, {
      instancePickingColors: {update: this.calculateInstancePickingColors}
    });

    this.setViewport();
    this.initializeState();
    assert(this.state.model, 'Model must be set in initializeState');
    this.setViewport();

    // TODO - the app must be able to override

    // Add any subclass attributes
    this.updateAttributes(this.props);
    this.updateBaseUniforms();

    const {model} = this.state;
    model.setInstanceCount(this.getNumInstances());
    model.id = this.props.id;
    model.program.id = `${this.props.id}-program`;
    model.geometry.id = `${this.props.id}-geometry`;

    // Create a model for the layer
    this._updateModel({gl});

    // Call life cycle method
    this.didMount();
  }
  /* eslint-enable max-statements */

  // Called by layer manager when existing layer is getting new props
  updateLayer(oldProps, newProps) {
    // Calculate standard change flags
    this.checkProps(oldProps, newProps);

    // Check if any props have changed
    if (this.shouldUpdate(oldProps, newProps)) {
      if (this.state.viewportChanged) {
        this.setViewport();
      }

      // Let the subclass mark what is needed for update
      this.willReceiveProps(oldProps, newProps);
      // Run the attribute updaters
      this.updateAttributes(newProps);
      // Update the uniforms
      this.updateBaseUniforms();

      if (this.state.model) {
        this.state.model.setInstanceCount(this.getNumInstances());
      }
    }

    this.state.dataChanged = false;
    this.state.viewportChanged = false;
  }

  // Called by manager when layer is about to be disposed
  // Note: not guaranteed to be called on application shutdown
  finalizeLayer() {
    this.willUnmount();
  }

  calculateInstancePickingColors(attribute, {numInstances}) {
    const {value, size} = attribute;
    // add 1 to index to seperate from no selection
    for (let i = 0; i < numInstances; i++) {
      const pickingColor = this.encodePickingColor(i);
      value[i * size + 0] = pickingColor[0];
      value[i * size + 1] = pickingColor[1];
      value[i * size + 2] = pickingColor[2];
    }
  }

  decodePickingColor(color) {
    assert(color instanceof Uint8Array);
    const [i1, i2, i3] = color;
    // 1 was added to seperate from no selection
    const index = i1 + i2 * 256 + i3 * 65536 - 1;
    return index;
  }

  encodePickingColor(i) {
    return [
      (i + 1) % 256,
      Math.floor((i + 1) / 256) % 256,
      Math.floor((i + 1) / 256 / 256) % 256
    ];
  }

  // VIRTUAL METHOD - Override to add or modify `info` object in sublayer
  // The sublayer may know what object e.g. lat,lon corresponds to using math
  // etc even when picking does not work
  onGetHoverInfo(info) {
    const {color} = info;
    info.index = this.decodePickingColor(color);
    // If props.data is an indexable array, get the object
    if (Array.isArray(this.props.data)) {
      info.object = this.props.data[info.index];
    }
    info.geoCoords = this.unproject({x: info.x, y: info.y});
    return info;
  }

  onHover(info) {
    const {color} = info;

    const selectedPickingColor = new Float32Array(3);
    selectedPickingColor[0] = color[0];
    selectedPickingColor[1] = color[1];
    selectedPickingColor[2] = color[2];
    this.setUniforms({selectedPickingColor});

    info = this.onGetHoverInfo(info);
    return this.props.onHover(info);
  }

  onClick(info) {
    info = this.onGetHoverInfo(info);
    return this.props.onClick(info);
  }

  // INTERNAL METHODS
  _updateModel({gl}) {
    const {model, attributeManager, uniforms} = this.state;

    assert(model);
    model.setAttributes(attributeManager.getAttributes());
    model.setUniforms(uniforms);
    // whether current layer responds to mouse events
    model.setPickable(this.props.isPickable);
  }

  checkProp(property, propertyName) {
    if (property === undefined || property === null) {
      throw new Error(`Property ${propertyName} undefined in layer ${this.props.id}`);
    }
  }

  // MAP LAYER FUNCTIONALITY
  setViewport() {
    const {
      width, height, latitude, longitude, zoom,
      disableMercatorProjector
    } = this.props;

    this.setState({
      viewport: {x: 0, y: 0, width, height},
      mercator: ViewportMercator({
        width, height, latitude, longitude, zoom,
        tileSize: 512
      })
    });

    this.setUniforms({
      viewport: [0, 0, width, height],
      mercatorScale: Math.pow(2, zoom),
      mercatorCenter: [longitude, latitude],
      disableMercatorProjector: disableMercatorProjector ? 1 : 0
    });

    log(3, this.state.viewport, latitude, longitude, zoom);
  }

  /**
   * Position conversion is done in shader, so in many cases there is no need
   * for this function
   * @param {Object|Array} latLng - Either [lat,lng] or {lat, lon}
   * @return {Object} - x, y
   */
  project(latLng) {
    const {mercator} = this.state;
    const [x, y] = Array.isArray(latLng) ?
      mercator.project([latLng[1], latLng[0]]) :
      mercator.project([latLng.lon, latLng.lat]);
    return {x, y};
  }

  unproject(xy) {
    const {mercator} = this.state;
    const [lon, lat] = Array.isArray(xy) ?
      mercator.unproject(xy) :
      mercator.unproject([xy.x, xy.y]);
    return {lat, lon};
  }
}
<|endoftext|>


<commit_before>import { loadModule } from "../utils/system"

var JSZip = loadModule({global: "JSZip", commonjs: "jszip"});

const ZIP_SIGNATURE = [0x50, 0x4B, 0x03, 0x04];

//=========================================================
// Base class of readers
//=========================================================

export class AbstractReader {

    constructor() {
        this.reset();
    }

    reset() {
        this.offset = 0;
    }

    readByte() {
        return this.read(1)[0];
    }

    read(length) {
        var data = this.peek(length);
        this.skip(length);
        return data;
    }

    peek(length) {
        return this.peekOffset(this.offset, length);
    }

    skip(length) {
        this.offset += length;
        if (this.offset > this.getLength()) {
            throw new Error("Unexpected end of input.");
        }
    }

    contains(signature) {
        var data = this.peek(signature.length);
        if (data.length !== signature.length) {
            return false;
        }
        for (var i = 0; i < signature.length; i++) {
            if (data[i] !== signature[i]) {
                return false;
            }
        }
        return true;
    }

    check(signature) {
        if (!this.contains(signature)) {
            throw new Error("Invalid input signature.");
        }
        this.skip(signature.length);
    }

    tryUnzip(data, onSuccess) {
        if (this.contains(ZIP_SIGNATURE)) {
            if (!JSZip) {
                throw new Error("Unable to unzip data: JSZip library is not available.");
            }
            var files = JSZip(data).file(/^.*\.nes$/);
            if (files.length > 0) {
                onSuccess(files[0]);
            }
        }
    }

}
<commit_msg>Add support for loading zipped .nes files.<commit_after>import { loadModule } from "../utils/system"

var JSZip = loadModule({global: "JSZip", commonjs: "jszip"});

const ZIP_SIGNATURE = [0x50, 0x4B, 0x03, 0x04];

//=========================================================
// Base class of readers
//=========================================================

export class AbstractReader {

    constructor() {
        this.reset();
    }

    reset() {
        this.offset = 0;
    }

    readByte() {
        return this.read(1)[0];
    }

    read(length) {
        var data = this.peek(length);
        this.skip(length);
        return data;
    }

    peek(length) {
        return this.peekOffset(this.offset, length);
    }

    skip(length) {
        this.offset += length;
        if (this.offset > this.getLength()) {
            throw new Error("Unexpected end of input.");
        }
    }

    contains(signature) {
        var data = this.peek(signature.length);
        if (data.length !== signature.length) {
            return false;
        }
        for (var i = 0; i < signature.length; i++) {
            if (data[i] !== signature[i]) {
                return false;
            }
        }
        return true;
    }

    check(signature) {
        if (!this.contains(signature)) {
            throw new Error("Invalid input signature.");
        }
        this.skip(signature.length);
    }

    tryUnzip(data, onSuccess) {
        if (this.contains(ZIP_SIGNATURE)) {
            if (!JSZip) {
                throw new Error("Unable to unzip data: JSZip library is not available.");
            }
            var files = JSZip(data).file(/^.*\.nes$/i);
            if (files.length > 0) {
                onSuccess(files[0]);
            }
        }
    }

}
<|endoftext|>


<commit_before>
jQuery("#data_output").hide();

var init_states = function(states_input) {
  var states = {}
  var states_order = []
  for ( var i=0, len=states_input.length; i<len; i++ ) {
    var state = states_input[i].split(",");
    if (state.length == 4) {
      states[state[0]] = state[1];
      states_order.push(state[0]);
    }
  }

  return {states: states, states_order: states_order};
}

var init_board = function(stories) {
  var board = {};
  for ( var i=0, len=stories.length; i<len; i++ ) {
    var story = stories[i].split(",");
    var state = story[0];
    if (story.length == 3) {
      if (! board[state]) {
        board[state] = [];
      }
      board[state].push(story);
    }
  }
  return board;
}

var create_list = function(board, state) {
  var list = jQuery("

");
  if (board[state]) {
    for (var i=0, len=board[state].length; i<len; i++) {
      var item_id = board[state][i][1].replace(/^S([\d]+).*/, "$1");
      var title = board[state][i][2].replace(/ /g, "_").toLowerCase();
      console.debug("item_id: " + item_id);
      console.debug("title: " + title);
      var story_element = jQuery("

" + board[state][i][1] + " " + board[state][i][2] + "
Edit Item

");
      story_element.data("story",  board[state][i]);
      list.append(story_element);
    }
  }
  return list
}

var create_column = function(board, state, headline) {
  var state_column = jQuery("

");
  state_column.append(jQuery("
" + headline + "
"));
  state_column.append(create_list(board, state));
  state_column.data("state", state);
  return state_column;
}

var drop_handler = function() {
  var children = this.parent().children();
  var item_ordering = "";

  for (var i = 0, len = children.length; i < len; i++) {
    item_ordering += "&item_ordering[]=" + children[i].textContent.replace(/^S([\d]+).*/, "$1");
  }

  var item_id = this.text().replace(/^S([\d]+).*/, "$1");
  var lane_id = this.parent().attr("id").replace(/^L([\d]+).*/, "$1");
  Hobo.ajaxRequest( window.location.href + "?lane_id=" + lane_id + "&item_id=" + item_id + item_ordering,
                    [],
                    { params: { lane_id: lane_id, item_id: item_id },
                      action: 'show',
                      controller: 'projects',
                      method: 'get',
                      message: "Please wait"
                    } );
}

var create_board = function(app_data) {
  var table = jQuery("

");
  var ids = "";
  for (j=0; j< app_data.states_order.length; j++) {
    var state = app_data.states_order[j]
    ids += "#" + state + ",";
    var state_column = create_column(app_data.board, state, app_data.states[state])
    table.append(state_column)
  }
  jQuery(ids, table).dragsort({ dragBetween: true, dragEnd: drop_handler });
  return table;
}

var create_box_colors = function(states_input) {
  var styles = jQuery('');
  for ( var i=0, len=states_input.length; i<len; i++ ) {
    var state = states_input[i].split(",");
    if (state.length == 4) {
      styles.append("#" + state[0] + " .box { background-color: " + state[2] + " ; color: " + state[3] + ";}");
    }
  }

  return styles;
}

var state_data = init_states(jQuery("#states").text().split("\n"));
var app_data = { board: init_board(jQuery("#stories").text().split("\n")), states: state_data.states, states_order: state_data.states_order}
jQuery("#output").empty();
jQuery("#output").append(create_box_colors(jQuery("#states").text().split("\n")));
jQuery("#output").append(create_board(app_data));

<commit_msg>* Remove console log debugging<commit_after>
jQuery("#data_output").hide();

var init_states = function(states_input) {
  var states = {}
  var states_order = []
  for ( var i=0, len=states_input.length; i<len; i++ ) {
    var state = states_input[i].split(",");
    if (state.length == 4) {
      states[state[0]] = state[1];
      states_order.push(state[0]);
    }
  }

  return {states: states, states_order: states_order};
}

var init_board = function(stories) {
  var board = {};
  for ( var i=0, len=stories.length; i<len; i++ ) {
    var story = stories[i].split(",");
    var state = story[0];
    if (story.length == 3) {
      if (! board[state]) {
        board[state] = [];
      }
      board[state].push(story);
    }
  }
  return board;
}

var create_list = function(board, state) {
  var list = jQuery("

");
  if (board[state]) {
    for (var i=0, len=board[state].length; i<len; i++) {
      var item_id = board[state][i][1].replace(/^S([\d]+).*/, "$1");
      var title = board[state][i][2].replace(/ /g, "_").toLowerCase();
      var story_element = jQuery("

" + board[state][i][1] + " " + board[state][i][2] + "
Edit Item

");
      story_element.data("story",  board[state][i]);
      list.append(story_element);
    }
  }
  return list
}

var create_column = function(board, state, headline) {
  var state_column = jQuery("

");
  state_column.append(jQuery("
" + headline + "
"));
  state_column.append(create_list(board, state));
  state_column.data("state", state);
  return state_column;
}

var drop_handler = function() {
  var children = this.parent().children();
  var item_ordering = "";

  for (var i = 0, len = children.length; i < len; i++) {
    item_ordering += "&item_ordering[]=" + children[i].textContent.replace(/^S([\d]+).*/, "$1");
  }

  var item_id = this.text().replace(/^S([\d]+).*/, "$1");
  var lane_id = this.parent().attr("id").replace(/^L([\d]+).*/, "$1");
  Hobo.ajaxRequest( window.location.href + "?lane_id=" + lane_id + "&item_id=" + item_id + item_ordering,
                    [],
                    { params: { lane_id: lane_id, item_id: item_id },
                      action: 'show',
                      controller: 'projects',
                      method: 'get',
                      message: "Please wait"
                    } );
}

var create_board = function(app_data) {
  var table = jQuery("

");
  var ids = "";
  for (j=0; j< app_data.states_order.length; j++) {
    var state = app_data.states_order[j]
    ids += "#" + state + ",";
    var state_column = create_column(app_data.board, state, app_data.states[state])
    table.append(state_column)
  }
  jQuery(ids, table).dragsort({ dragBetween: true, dragEnd: drop_handler });
  return table;
}

var create_box_colors = function(states_input) {
  var styles = jQuery('');
  for ( var i=0, len=states_input.length; i<len; i++ ) {
    var state = states_input[i].split(",");
    if (state.length == 4) {
      styles.append("#" + state[0] + " .box { background-color: " + state[2] + " ; color: " + state[3] + ";}");
    }
  }

  return styles;
}

var state_data = init_states(jQuery("#states").text().split("\n"));
var app_data = { board: init_board(jQuery("#stories").text().split("\n")), states: state_data.states, states_order: state_data.states_order}
jQuery("#output").empty();
jQuery("#output").append(create_box_colors(jQuery("#states").text().split("\n")));
jQuery("#output").append(create_board(app_data));

<|endoftext|>


<commit_before>'use strict';

jasmine.getFixtures().fixturesPath = 'base/test/fixtures';

var createWidget = require('./utils/createWidget');
var mockAjax = require('./utils/mockAjax');
var interact = require('./utils/commonInteractions');

/**
 * Tests for mobile and responsive
 */
describe('Mobile & responsive', function() {

  beforeEach(function(){
    loadFixtures('main.html');
    jasmine.Ajax.install();
    mockAjax.all();
    $('body').width(400);
  });

  afterEach(function() {
    jasmine.Ajax.uninstall();
  });

  it('should be able change day in mobile mode by clicking arrows', function(done) {

    createWidget({
      name: 'John Doe'
    });

    expect($('.fc-basicDay-view')).toBeInDOM()
    var currentDay = $('.fc-day-header')[0].textContent;

    var displayNameRect = $('.bookingjs-displayname')[0].getBoundingClientRect();
    var clickableArrowRect = $('.fc-next-button')[0].getBoundingClientRect();

    var overlap = !(displayNameRect.right < clickableArrowRect.left ||
                displayNameRect.left > clickableArrowRect.right ||
                displayNameRect.bottom < clickableArrowRect.top ||
                displayNameRect.top > clickableArrowRect.bottom)
    expect(overlap).toBe(false);

    setTimeout(function() {

      var calEventStart = interact.clickNextArrow();

      setTimeout(function() {

        var nextDay = $('.fc-day-header')[0].textContent;
        expect(currentDay).not.toBe(nextDay);
        done();

      }, 100);
    }, 200);

  });

});
<commit_msg>reset browserwidth again after last test<commit_after>'use strict';

jasmine.getFixtures().fixturesPath = 'base/test/fixtures';

var createWidget = require('./utils/createWidget');
var mockAjax = require('./utils/mockAjax');
var interact = require('./utils/commonInteractions');

var browserWidth;

/**
 * Tests for mobile and responsive
 */
describe('Mobile & responsive', function() {

  beforeEach(function(){
    loadFixtures('main.html');
    jasmine.Ajax.install();
    mockAjax.all();
    browserWidth = $('body').width();
    $('body').width(400);
  });

  afterEach(function() {
    jasmine.Ajax.uninstall();
    $('body').width(browserWidth);
  });

  it('should be able change day in mobile mode by clicking arrows', function(done) {

    createWidget({
      name: 'John Doe'
    });

    expect($('.fc-basicDay-view')).toBeInDOM()
    var currentDay = $('.fc-day-header')[0].textContent;

    var displayNameRect = $('.bookingjs-displayname')[0].getBoundingClientRect();
    var clickableArrowRect = $('.fc-next-button')[0].getBoundingClientRect();

    var overlap = !(displayNameRect.right < clickableArrowRect.left ||
                displayNameRect.left > clickableArrowRect.right ||
                displayNameRect.bottom < clickableArrowRect.top ||
                displayNameRect.top > clickableArrowRect.bottom)
    expect(overlap).toBe(false);

    setTimeout(function() {

      var calEventStart = interact.clickNextArrow();

      setTimeout(function() {

        var nextDay = $('.fc-day-header')[0].textContent;
        expect(currentDay).not.toBe(nextDay);
        done();

      }, 100);
    }, 200);

  });

});
<|endoftext|>


<commit_before>'use babel';
'use strict';

import { Collection } from 'discord.js';

// Handle loading all GuildStorage objects
export default class GuildStorageRegistry extends Collection
{
	constructor()
	{
		super();
	}

	// Allow guild lookup by Guild object or id string
	get(guild)
	{
		return super.get(guild.id ? guild.id : guild);
	}

	// Return a collection of of guilds with a specific setting value
	findAllBySetting(key, value)
	{
		let collection = new Collection();
		this.forEach(guild =>
		{
			if (guild.getSetting(key) === value) collection.set(guild.id, guild);
		});
		if (collection.size === 0) return null;
		return collection;
	}

	// Reset all guild settings to default
	resetAllGuildSettings(defaults)
	{
		super.forEach(guild => guild.resetSettings(defaults));
	}
}
<commit_msg>Fix description comment<commit_after>'use babel';
'use strict';

import { Collection } from 'discord.js';

// Handle storage of all GuildStorage objects
export default class GuildStorageRegistry extends Collection
{
	constructor()
	{
		super();
	}

	// Allow guild lookup by Guild object or id string
	get(guild)
	{
		return super.get(guild.id ? guild.id : guild);
	}

	// Return a collection of of guilds with a specific setting value
	findAllBySetting(key, value)
	{
		let collection = new Collection();
		this.forEach(guild =>
		{
			if (guild.getSetting(key) === value) collection.set(guild.id, guild);
		});
		if (collection.size === 0) return null;
		return collection;
	}

	// Reset all guild settings to default
	resetAllGuildSettings(defaults)
	{
		super.forEach(guild => guild.resetSettings(defaults));
	}
}
<|endoftext|>


<commit_before>'use strict';

/**
 * hojs
 *
 * @author Zongmin Lei <leizongmin@gmail.com>
 */

import validator from 'validator';

export default function (registerType) {

  registerType('Boolean', {
    checker: (v) => typeof v === 'boolean' || (typeof v === 'string' && validator.isBoolean(v)),
    formatter: (v) => String(v).toLowerCase() === 'true' ? true : false,
    description: 'boolean',
    isDefault: true,
  });

  registerType('Date', {
    checker: (v) => v instanceof Date || (typeof v === 'string' && validator.isDate(v)),
    formatter: (v) => new Date(v),
    description: 'Date',
    isDefault: true,
  });

  registerType('String', {
    checker: (v) => typeof v === 'string',
    description: 'String',
    isDefault: true,
  });

  registerType('Number', {
    checker: (v) => !isNaN(v),
    formatter: (v) => Number(v),
    description: 'Number',
    isDefault: true,
  });

  registerType('Integer', {
    checker: (v) => validator.isInt(String(v)),
    formatter: (v) => Number(v),
    description: 'Integer',
    isDefault: true,
  });

  registerType('Float', {
    checker: (v) => validator.isFloat(String(v)),
    formatter: (v) => Number(v),
    description: 'Float',
    isDefault: true,
  });

  registerType('Object', {
    checker: (v) => v && typeof v === 'object',
    description: 'Object',
    isDefault: true,
  });

  registerType('Array', {
    checker: (v) => Array.isArray(v),
    description: 'Array',
    isDefault: true,
  });

  registerType('JSON', {
    checker: (v) => typeof v === 'string' && validator.isJSON(v),
    formatter: (v) => v.trim(),
    description: 'string is valid JSON',
    isDefault: true,
  });

  registerType('MongoId', {
    checker: (v) => validator.isMongoId(String(v)),
    description: 'string is a valid hex-encoded representation of a MongoDB ObjectId',
    isDefault: true,
  });

  registerType('Email', {
    checker: (v) => typeof v === 'string' && validator.isEmail(v),
    formatter: (v) => v.trim(),
    description: 'string is an email',
    isDefault: true,
  });

  registerType('Domain', {
    checker: (v) => typeof v === 'string' && validator.isFQDN(v),
    formatter: (v) => v.trim(),
    description: 'string is a fully qualified domain name (e.g. domain.com)',
    isDefault: true,
  });

  registerType('Alpha', {
    checker: (v) => typeof v === 'string' && validator.isAlpha(v),
    description: 'string contains only letters (a-zA-Z).',
    isDefault: true,
  });

  registerType('AlphaNumeric', {
    checker: (v) => typeof v === 'string' && validator.isAlphanumeric(v),
    description: 'string contains only letters and numbers',
    isDefault: true,
  });

  registerType('Ascii', {
    checker: (v) => typeof v === 'string' && validator.isAscii(v),
    description: 'string contains ASCII chars only',
    isDefault: true,
  });

  registerType('Base64', {
    checker: (v) => typeof v === 'string' && validator.isBase64(v),
    formatter: (v) => v.trim(),
    description: 'string is base64 encoded',
    isDefault: true,
  });

  registerType('URL', {
    checker: (v) => typeof v === 'string' && validator.isURL(v),
    formatter: (v) => v.trim(),
    description: 'string is an URL',
    isDefault: true,
  });

};
<commit_msg>增加默认类型 TrimString & Any<commit_after>'use strict';

/**
 * hojs
 *
 * @author Zongmin Lei <leizongmin@gmail.com>
 */

import validator from 'validator';

export default function (registerType) {

  registerType('Boolean', {
    checker: (v) => typeof v === 'boolean' || (typeof v === 'string' && validator.isBoolean(v)),
    formatter: (v) => String(v).toLowerCase() === 'true' ? true : false,
    description: 'boolean',
    isDefault: true,
  });

  registerType('Date', {
    checker: (v) => v instanceof Date || (typeof v === 'string' && validator.isDate(v)),
    formatter: (v) => new Date(v),
    description: 'date',
    isDefault: true,
  });

  registerType('String', {
    checker: (v) => typeof v === 'string',
    description: 'string',
    isDefault: true,
  });

  registerType('TrimString', {
    checker: (v) => typeof v === 'string',
    formatter: (v) => v.trim(),
    description: 'auto trim string',
  });

  registerType('Number', {
    checker: (v) => !isNaN(v),
    formatter: (v) => Number(v),
    description: 'number',
    isDefault: true,
  });

  registerType('Integer', {
    checker: (v) => validator.isInt(String(v)),
    formatter: (v) => Number(v),
    description: 'integer',
    isDefault: true,
  });

  registerType('Float', {
    checker: (v) => validator.isFloat(String(v)),
    formatter: (v) => Number(v),
    description: 'float',
    isDefault: true,
  });

  registerType('Object', {
    checker: (v) => v && typeof v === 'object',
    description: 'object',
    isDefault: true,
  });

  registerType('Array', {
    checker: (v) => Array.isArray(v),
    description: 'array',
    isDefault: true,
  });

  registerType('JSON', {
    checker: (v) => typeof v === 'string' && validator.isJSON(v),
    formatter: (v) => v.trim(),
    description: 'string is valid JSON',
    isDefault: true,
  });

  registerType('Any', {
    checker: (v) => true,
    description: 'can be any type',
    isDefault: true,
  });

  registerType('MongoId', {
    checker: (v) => validator.isMongoId(String(v)),
    description: 'string is a valid hex-encoded representation of a MongoDB ObjectId',
    isDefault: true,
  });

  registerType('Email', {
    checker: (v) => typeof v === 'string' && validator.isEmail(v),
    formatter: (v) => v.trim(),
    description: 'string is an email',
    isDefault: true,
  });

  registerType('Domain', {
    checker: (v) => typeof v === 'string' && validator.isFQDN(v),
    formatter: (v) => v.trim(),
    description: 'string is a fully qualified domain name (e.g. domain.com)',
    isDefault: true,
  });

  registerType('Alpha', {
    checker: (v) => typeof v === 'string' && validator.isAlpha(v),
    description: 'string contains only letters (a-zA-Z).',
    isDefault: true,
  });

  registerType('AlphaNumeric', {
    checker: (v) => typeof v === 'string' && validator.isAlphanumeric(v),
    description: 'string contains only letters and numbers',
    isDefault: true,
  });

  registerType('Ascii', {
    checker: (v) => typeof v === 'string' && validator.isAscii(v),
    description: 'string contains ASCII chars only',
    isDefault: true,
  });

  registerType('Base64', {
    checker: (v) => typeof v === 'string' && validator.isBase64(v),
    formatter: (v) => v.trim(),
    description: 'string is base64 encoded',
    isDefault: true,
  });

  registerType('URL', {
    checker: (v) => typeof v === 'string' && validator.isURL(v),
    formatter: (v) => v.trim(),
    description: 'string is an URL',
    isDefault: true,
  });

};
<|endoftext|>


<commit_before>(function(w) {
	var sw = document.body.clientWidth,
		sh = document.body.clientHeight,
		breakpoint = 650,
		speed = 800,
		mobile = true;

	$(document).ready(function() {
		checkMobile();
		setNav();
		setImg();
	});

$(w).resize(function(){ //Update dimensions on resize
	sw = document.body.clientWidth;
	sh = document.body.clientHeight;
	checkMobile();
});

//Check if Mobile
function checkMobile() {
  mobile = (sw > breakpoint) ? false : true;

    if (!mobile) { //If Not Mobile
        loadAux();
	$('.aux header a').addClass('disabled').addClass('open');
	$('[role="tabpanel"],#nav,#search').show(); //Show full navigation and search
     } else { //Hide
              if(!$('#nav-anchors a').hasClass('active')) {
                    $('#nav,#search').hide(); //Hide full navigation and search
               }
     }
}
//Toggle navigation for small screens
function setNav() {
	var $anchorLinks = $('#nav-anchors').find('a');
	$anchorLinks.click(function(e){
		e.preventDefault();
		var $this = $(this),
				thisHref = $this.attr('href');
		$('.reveal').hide();
		if($this.hasClass('active')) {
			$this.removeClass('active');
			$(thisHref).hide();
		} else {
			$anchorLinks.removeClass('active');
			$this.addClass('active');
			$(thisHref).show();
		}
	});

}

function setImg() {
	var container = $('#img-container'),
		nav = $('#product-img').find('nav'),
		imgList = Object,
		current = 0,
		swipeEnabled = false;

function buildGallery() {
	container.html('

');
	imgList = $('#img-list');
	nav.find('li:first').addClass('active');

	var arr = '';

	//For Each Navigation Link
	nav.find('a').each(function() {
		 var $this = $(this),
	        	 href = $this.attr('href');

		  //Prepare list item with image source in data attribute
		  arr += '

';
	 });

	 //Append to #img-list
	 imgList.find('ul').append(arr);

	 //Nav Thumbnail Click
	 nav.on('click, 'a', function(e) {
		var pos = $(this).parent().index();
		e.preventDefault();
		loadImg(pos);
		if(swipeEnabled) {
			mySwipe.slide(pos, 300);
		}
		updateNav(pos);
	});

	Modernizr.load({
		test:Modernizr.touch && Modernizr.csstransitions,
		yep:'js/swipe.js',
		complete: function() {
			if(w.Swipe) {
				swipeEnabled = true;
				buildSwipe();
			}
		}
	});
	loadImg(0); //Load initial image
}
function buildSwipe() {
	//Initialize Swipe.js
	w.mySwipe = new Swipe (document.getElementbyId('img-list'), {
		callback: function(event, index, elem) {
			updateNav(index);
			loadImg(index+1);
		}
	});
	imgList.addEventListener('touchstart', function(event) {
	    			loadImg(w.mySwipe.getPos()+1);
							}, false);
}

//Dynamically Load Images
function loadImg(index) {
	var lis = imgList.find('li'),
		li = lis.eq(index),
		imgSrc = li.attr('data-imgsrc');
	if(!swipeEnabled) {
		lis.hide();
		li.show();
	}
	if(li.html() === "") { //If li is empty
		var img = new Image();
		imgList.addClass('loading');
		$(img).load(function () { //Load image
			$(this).hide();
			li.removeClass('loading');
			$(this).fadeIn();
		}).error(function () {
			//notify the user that the image could not be loaded
		}).attr('src', imgSrc);
		$(''>.attr('src', imgSrc).appendTo(li);
	}
}

function updateNav(pos) {
	nav.find('li').removeClass('active');
	nav.find('li:eq('+pos+')').addClass('active');
}

build Gallery();

}

//Set up Auxiliary content
$('.aux header a').addClass('disabled');

function loadAux() {
	var $aux = $('.aux');
	$aux.each(function(index) {
		var $this = $(this),
			auxLink = $this.find('a'),
			auxFragment = auxLink.attr('href'),
			auxContent = $this.find('[role=tabpanel]');
		if(auxContent.size()===0 && $this.hasClass('loaded')===false){
			loadContent(auxFragment,$this);
		}
	});
}
function loadContent(src,container) { //Load Tab Content
	container.addClass('loaded');
	$('
').load(src +' #content > div',function() {
		$(this).appendTo(container);
	});
}

$('.aux header a').click(function() {
	var $this = $(this),
		thisHref = $this.attr('href'),
		tabParent = $(this).parents('section'),
		tabPanel = tabParent.find('[role=tabpanel]');
	if(mobile) { //if Mobile
		if(tabPanel.size()===0) { //Load content if not present
			loadContent(thisHref,tabParent);
			$this.addClass('open');
		} else { //Toggle
			tabPanel.toggle();
			$this.toggleClass('open');
		}
	}
	return false;
});

//Geolocation
$('.find-nearby').click(function(){
	if (navigator.geolocation) {
		navigator.geolocation.getCurrentPosition(geoSuccess, geoError);
	}
});

	function geoSuccess(position) {
		var la = position.coords.latitude,
			lon = position.coords.longitude;
			alert('Your latitude is '+la+' and your longitude is '+lon); //Return latitude and longitude. Obviously in a live environment we would redirect to a store results page using window.location
	}
	function geoError() {
		alert('There was a problem determining your location.');
}

})(this);
<commit_msg>Added imgList variable in buildGallery<commit_after>(function(w) {
	var sw = document.body.clientWidth,
		sh = document.body.clientHeight,
		breakpoint = 650,
		speed = 800,
		mobile = true;

	$(document).ready(function() {
		checkMobile();
		setNav();
		setImg();
	});

$(w).resize(function(){ //Update dimensions on resize
	sw = document.body.clientWidth;
	sh = document.body.clientHeight;
	checkMobile();
});

//Check if Mobile
function checkMobile() {
  mobile = (sw > breakpoint) ? false : true;

    if (!mobile) { //If Not Mobile
        loadAux();
	$('.aux header a').addClass('disabled').addClass('open');
	$('[role="tabpanel"],#nav,#search').show(); //Show full navigation and search
     } else { //Hide
              if(!$('#nav-anchors a').hasClass('active')) {
                    $('#nav,#search').hide(); //Hide full navigation and search
               }
     }
}
//Toggle navigation for small screens
function setNav() {
	var $anchorLinks = $('#nav-anchors').find('a');
	$anchorLinks.click(function(e){
		e.preventDefault();
		var $this = $(this),
				thisHref = $this.attr('href');
		$('.reveal').hide();
		if($this.hasClass('active')) {
			$this.removeClass('active');
			$(thisHref).hide();
		} else {
			$anchorLinks.removeClass('active');
			$this.addClass('active');
			$(thisHref).show();
		}
	});

}

function setImg() {
	var container = $('#img-container'),
		nav = $('#product-img').find('nav'),
		imgList = Object,
		current = 0,
		swipeEnabled = false;

function buildGallery() {
	container.html('

');
	imgList = $('#img-list');
	nav.find('li:first').addClass('active');

	var arr = '';

	//For Each Navigation Link
	nav.find('a').each(function() {
		 var $this = $(this),
	        	 href = $this.attr('href');

		  //Prepare list item with image source in data attribute
		  arr += '

';
	 });

	 //Append to #img-list
	 imgList.find('ul').append(arr);

	 //Nav Thumbnail Click
	 nav.on('click, 'a', function(e) {
		var pos = $(this).parent().index();
		e.preventDefault();
		loadImg(pos);
		if(swipeEnabled) {
			mySwipe.slide(pos, 300);
		}
		updateNav(pos);
	});

	Modernizr.load({
		test:Modernizr.touch && Modernizr.csstransitions,
		yep:'js/swipe.js',
		complete: function() {
			if(w.Swipe) {
				swipeEnabled = true;
				buildSwipe();
			}
		}
	});
	loadImg(0); //Load initial image
}
function buildSwipe() {
	//Initialize Swipe.js
	var imgList = document.getElementById('img-list');
	w.mySwipe = new Swipe (imgList, {
		callback: function(event, index, elem) {
			updateNav(index);
			loadImg(index+1);
		}
	});
	imgList.addEventListener('touchstart', function(event) {
	    			loadImg(w.mySwipe.getPos()+1);
							}, false);
}

//Dynamically Load Images
function loadImg(index) {
	var lis = imgList.find('li'),
		li = lis.eq(index),
		imgSrc = li.attr('data-imgsrc');
	if(!swipeEnabled) {
		lis.hide();
		li.show();
	}
	if(li.html() === "") { //If li is empty
		var img = new Image();
		imgList.addClass('loading');
		$(img).load(function () { //Load image
			$(this).hide();
			li.removeClass('loading');
			$(this).fadeIn();
		}).error(function () {
			//notify the user that the image could not be loaded
		}).attr('src', imgSrc);
		$(''>.attr('src', imgSrc).appendTo(li);
	}
}

function updateNav(pos) {
	nav.find('li').removeClass('active');
	nav.find('li:eq('+pos+')').addClass('active');
}

build Gallery();

}

//Set up Auxiliary content
$('.aux header a').addClass('disabled');

function loadAux() {
	var $aux = $('.aux');
	$aux.each(function(index) {
		var $this = $(this),
			auxLink = $this.find('a'),
			auxFragment = auxLink.attr('href'),
			auxContent = $this.find('[role=tabpanel]');
		if(auxContent.size()===0 && $this.hasClass('loaded')===false){
			loadContent(auxFragment,$this);
		}
	});
}
function loadContent(src,container) { //Load Tab Content
	container.addClass('loaded');
	$('
').load(src +' #content > div',function() {
		$(this).appendTo(container);
	});
}

$('.aux header a').click(function() {
	var $this = $(this),
		thisHref = $this.attr('href'),
		tabParent = $(this).parents('section'),
		tabPanel = tabParent.find('[role=tabpanel]');
	if(mobile) { //if Mobile
		if(tabPanel.size()===0) { //Load content if not present
			loadContent(thisHref,tabParent);
			$this.addClass('open');
		} else { //Toggle
			tabPanel.toggle();
			$this.toggleClass('open');
		}
	}
	return false;
});

//Geolocation
$('.find-nearby').click(function(){
	if (navigator.geolocation) {
		navigator.geolocation.getCurrentPosition(geoSuccess, geoError);
	}
});

	function geoSuccess(position) {
		var la = position.coords.latitude,
			lon = position.coords.longitude;
			alert('Your latitude is '+la+' and your longitude is '+lon); //Return latitude and longitude. Obviously in a live environment we would redirect to a store results page using window.location
	}
	function geoError() {
		alert('There was a problem determining your location.');
}

})(this);
<|endoftext|>


<commit_before>/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */

/*!
 * Next JS
 * Copyright (c)2011 Xenophy.CO.,LTD All rights Reserved.
 * http://www.xenophy.com
 */

// {{{ requires

require('should');
var assert = require('assert');

require('NX/core/class/ClassManager');
var T_Class = require('NX/core/class/Class');

// }}}
// {{{ callOverridden

module.exports = {

    // {{{ test callOverridden#pattern1

    'test callOverridden#pattern1': function() {

        T_ClassManager.create('NXTest.Base.callOverridden.p1cls', {
            hoge: function() {
                return 'org';
            }
        });

        T_ClassManager.create('NXTest.Base.callOverridden.p1cls2', {
            extend: 'NXTest.Base.callOverridden.p1cls',
            hoge: function() {
                this.callOverridden().should.equal('org');
            }
        });

        try{
            var cls = new NXTest.Base.callOverridden.p1cls2();
            cls.hoge();
        } catch(e) {
            e.message.should.equal("[NXTest.Base.callOverridden.p1cls2] this.callOverridden was called in 'hoge' but this method has never been overridden");
        }

    },

    // }}}
    // {{{ test callOverridden#pattern2

    'test callOverridden#pattern2': function() {

        T_ClassManager.create('NXTest.Base.callOverridden.p2cls', {
            hoge: function() {
                return 'org';
            }
        });

        NXTest.Base.callOverridden.p2cls.override('hoge', function() {
            this.callOverridden().should.equal('org');
        });

        var cls = new NXTest.Base.callOverridden.p2cls();
        cls.hoge();

    },

    // }}}

};

// }}}

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * c-hanging-comment-ender-p: nil
 * End:
 */
<commit_msg>読み込みモジュール追加<commit_after>/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */

/*!
 * Next JS
 * Copyright (c)2011 Xenophy.CO.,LTD All rights Reserved.
 * http://www.xenophy.com
 */

// {{{ requires

require('should');
var assert = require('assert');

require('NX/core');
require('NX/core/class/ClassManager');
var T_Class = require('NX/core/class/Class');

// }}}
// {{{ callOverridden

module.exports = {

    // {{{ test callOverridden#pattern1

    'test callOverridden#pattern1': function() {

        T_ClassManager.create('NXTest.Base.callOverridden.p1cls', {
            hoge: function() {
                return 'org';
            }
        });

        T_ClassManager.create('NXTest.Base.callOverridden.p1cls2', {
            extend: 'NXTest.Base.callOverridden.p1cls',
            hoge: function() {
                this.callOverridden().should.equal('org');
            }
        });

        try{
            var cls = new NXTest.Base.callOverridden.p1cls2();
            cls.hoge();
        } catch(e) {
            e.message.should.equal("[NXTest.Base.callOverridden.p1cls2] this.callOverridden was called in 'hoge' but this method has never been overridden");
        }

    },

    // }}}
    // {{{ test callOverridden#pattern2

    'test callOverridden#pattern2': function() {

        T_ClassManager.create('NXTest.Base.callOverridden.p2cls', {
            hoge: function() {
                return 'org';
            }
        });

        NXTest.Base.callOverridden.p2cls.override('hoge', function() {
            this.callOverridden().should.equal('org');
        });

        var cls = new NXTest.Base.callOverridden.p2cls();
        cls.hoge();

    },

    // }}}

};

// }}}

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * c-hanging-comment-ender-p: nil
 * End:
 */
<|endoftext|>