<commit_before>Meteor.startup(() => {
  $('html').attr('lang', 'en');
});

Template.main.onRendered(() => {
  $('.ui.menu .ui.dropdown').dropdown({
      on: 'hover'
    });
});

Template.markScheme.onRendered(() => {
  $('.ui.checkbox').checkbox();
});

Template.insertScheme.onRendered(() => {
  $('.ui.checkbox').checkbox();
  $.getScript('dragula.min.js', function () {
    var lastItem;
    drake = dragula({
      isContainer: function (el) {
        return el.classList.contains('dragula-container');
      }
    });
    drake.on('drop', function(item, tar, source, sibling) {
      $('.rubric-table input:first').trigger('change');
      let rObj = Session.get('rubricObject');
      Session.set('rubricObject', []);
      Meteor.setTimeout( function () {
        Session.set('rubricObject', rObj);
      }, 80);
    });
  });
});

Session.setDefault('adjustmentAllowed', false);
Session.setDefault('rubricObject', [{
  uuid: UI._globalHelpers.generateUUID(),
  rows: [{uuid: UI._globalHelpers.generateUUID()}],
}]);
Session.setDefault('comments', [{
  uuid: UI._globalHelpers.generateUUID()
}]);
Session.setDefault('rubricHistory', []);
Session.setDefault('unitName', UI._globalHelpers.generateFunName());
Session.setDefault('editingName', false);
Session.setDefault('commentHistory', []);
// Keep track of if rubric or comment field should be undone.
Session.setDefault('actionHistory', []);

var totalMarksFunction = function () {
  let rObjs = Session.get('rubricObject'),
      totalMarks = 0;
  rObjs.forEach((rubric) => {
    let max = 0;
    rubric.rows.forEach((r) => {
      if (r.criteriaValue !== undefined && r.criteriaValue > max) {
        max = r.criteriaValue;
      }
    });
    totalMarks += max;
  });
  return totalMarks;
}

Template.insertScheme.helpers({
  'totalMarks': totalMarksFunction
  ,
  'unitName': function () {
    return Session.get('unitName');
  },
  'editingName': function () {
    return Session.get('editingName');
  }
});

Template.insertScheme.events({
  'click .submit-scheme': function(evt) {
    let form = $('#marking-scheme-form')[0];
    if (form.checkValidity()) {
      evt.preventDefault();
      let schemaObject = {
        'name': $('input[name="scheme-name"]').val(),
        'description': $('textarea[name="scheme-desc"]').val(),
        'createdAt': new Date(),
        'aspects': Session.get('rubricObject'),
        'comments': Session.get('comments'),
        'adjustmentValuePositive': $('input[name="adjustment-positive"]').val(),
        'adjustmentValueNegative': $('input[name="adjustment-negative"]').val(),
        'maxMarks': totalMarksFunction()
      };
      Meteor.call('addScheme', schemaObject, (error, result) => {
        if (error) {
          console.log(error.message, error.details);
        } else {
          Session.set('adjustmentAllowed', false);
          Session.set('rubricObject', [{
            uuid: UI._globalHelpers.generateUUID(),
            rows: [{uuid: UI._globalHelpers.generateUUID()}],
          }]);
          Session.set('comments', [{
            uuid: UI._globalHelpers.generateUUID()
          }]);
          Session.set('rubricHistory', []);
          Session.set('unitName', UI._globalHelpers.generateFunName());
          Session.set('editingName', false);
          Session.set('commentHistory', []);
          Session.set('actionHistory', []);
          form.reset();
          Router.go('/viewSchemes');
        }
      });
    } else {
      // Semantic validation checks
    }
  },
  'click .name-field': function () {
    Session.set('editingName', true);
    setTimeout(function() { $('input[name="scheme-name"]').select(); }, 100);

  },
  'blur input[name="scheme-name"]': function () {
    Session.set('editingName', false);
    Session.set('unitName', $('input[name="scheme-name"]').val());
  },
  'keydown': function (evt) {
    // Meta key works for ctrl on windows and cmd on mac.
    if (evt.keyCode == 90 && evt.metaKey) alert("Ctrl+z");
    // TODO: UNDO THINGS!
  },
  'click .reset-scheme': function (evt) {
    evt.preventDefault();
    $('.ui.basic.reset-check.modal')
      .modal({
        closable  : false,
        onApprove : function() {
          document.getElementById("marking-scheme-form").reset();
          $('input[name="scheme-name"]').val(Session.get('unitName'));
        },
        detachable: false
      }).modal('show');
  }
});

Template.rubricBuilder.helpers({
  rubricObject: function () {
    return Session.get('rubricObject');
  },
  pickColour: function (index) {
    let colours = ['blue', 'orange', 'green', 'yellow',
                    'teal', 'violet', 'grey', 'pink'];
    return colours[index % colours.length];
  },
  canUndo: function() {
    return Session.get('rubricHistory').length > 0;
  }
});

Template.rubricBuilder.events({
  'click .add-criterion': function (evt) {
    evt.preventDefault();
    let rObjs = Session.get('rubricObject'),
        id = $(evt.currentTarget).closest('div .grid').attr('data-uuid');
    rObjs.forEach((rubric) => {
      if (rubric.uuid == id) {
        rubric['rows'].push({uuid: UI._globalHelpers.generateUUID()});
      }
    });
    Session.set('rubricObject', rObjs);
  },
  'click .add-aspect': function (evt) {
    evt.preventDefault();
    let rObj = Session.get('rubricObject');
    rObj.push({
      uuid: UI._globalHelpers.generateUUID(),
      rows: [{uuid: UI._globalHelpers.generateUUID()}]
    });
    Session.set('rubricObject', rObj);
  },
  'click .rubric-array-remove': function (evt) {
    evt.preventDefault();
    let rObjs = Session.get('rubricObject'),
        rowId = $(evt.currentTarget).closest('tr').attr('data-uuid'),
        tableId = $(evt.currentTarget).closest('table').attr('data-uuid');
    rObjs.forEach((rubric) => {
      if (rubric.uuid == tableId) {
        rubric.rows = rubric.rows.filter((row) => {
          return row.uuid != rowId;
        });
      }
    });
    Session.set('rubricObject', rObjs);
  },
  'click .remove-aspect': function (evt) {
    evt.preventDefault();
    let rObjs = Session.get('rubricObject'),
        id = $(evt.currentTarget).closest('div .grid').attr('data-uuid');
    rObjs = rObjs.filter((rubric) => {
      return rubric.uuid != id;
    });
    Session.set('rubricObject', rObjs);
  },
  'change input': function () {
    let rObjs = Session.get('rubricObject'),
        historyArray = Session.get('rubricHistory');
    historyArray.push(rObjs);

    rObjs.forEach((rubric) => {
      let $table = $('table[data-uuid="' + rubric.uuid + '"]'),
          $rows = $table.children('tbody').children('tr'),
          rows = [];
      rubric.aspect = $table.find('input[name="rubric-aspect"]').val();
      $rows.each((index, row) => {
        let rowObj = {};
        rowObj.uuid = $(row).attr('data-uuid');
        rowObj.criteria = $(row).find('input[name="criteria"]').val();
        // Parse if defined. Use base 10.
        if ($(row).find('input[name="criteria-value"]').val() !== undefined) {
          rowObj.criteriaValue = parseInt($(row).find('input[name="criteria-value"]').val(), 10);
        }
        rows.push(rowObj);
      })
      rubric.rows = rows;
    });

    let actionHistory = Session.get('actionHistory');
    actionHistory.push('rubric');
    Session.set('actionHistory', actionHistory);
    Session.set('rubricHistory', historyArray);
    Session.set('rubricObject', rObjs);

  },
  'keydown input[name="criteria-value"]': function (evt) {
    let id = $(evt.currentTarget).closest('table').attr('data-uuid'),
        $table = $('table[data-uuid="' + id + '"]');
        $lastRow = $table.find('tr:last');
        lastRowId = $lastRow.attr('data-uuid');
        eventId = $(evt.currentTarget).closest('tr').attr('data-uuid');
    if (eventId === lastRowId) {
      if (evt.keyCode === 9 && !evt.shiftKey && ($(evt.currentTarget).val() || $lastRow.find('input[name="criteria"]').val().length > 0)) {
        evt.preventDefault();
        console.log($table.closest('.add-criterion'));
        $('div[data-uuid="' + id +'"]').find('.add-criterion').trigger('click');
        Meteor.setTimeout(function() { $table.find('tr:last input[name="criteria"]').focus(); }, 100);
      }
    }
  },
  'keydown input': function (evt) {
    if (evt.keyCode === 13) {
      evt.preventDefault();
      // Translate that return into a tab...
      let e = jQuery.Event('keydown', { keyCode: 9 });
      $(evt.currentTarget).trigger(e);
    }
  },
  'click .duplicate-aspect': function (evt) {
    evt.preventDefault();
    let rObj = Session.get('rubricObject'),
        id = $(evt.currentTarget).closest('div .grid').attr('data-uuid'),
        historyArray = Session.get('rubricHistory');

    rObj.forEach((rubric) => {
      if (rubric.uuid == id) {
        let newRows = [];
        rubric.rows.forEach((row) => {
          newRows.push({
            uuid: UI._globalHelpers.generateUUID(),
            criteria: row.criteria,
            criteriaValue: row.criteriaValue
          });
        });
        rObj.push({
          aspect: rubric.aspect,
          uuid: UI._globalHelpers.generateUUID(),
          rows: newRows
        });
      }
    });
    historyArray.push(rObj);
    Session.set('rubricHistory', historyArray);
    Session.set('rubricObject', rObj);
  },
  'click .undo-rubric-action': function (evt) {
    evt.preventDefault();
    let historyArray = Session.get('rubricHistory');
    Session.set('rubricObject', historyArray.pop());
    Session.set('rubricHistory', historyArray);
  }
});

Template.commentBuilder.helpers({
  comments: function () {
    return Session.get('comments');
  },
  isLast: function(index) {
    if (index === Session.get('comments').length - 1) {
      return 'last-comment';
    } else {
      return '';
    }
  },
  canUndo: function() {
    return Session.get('commentHistory').length > 0;
  }
});

Template.commentBuilder.events({
  'click .comment-remove': function (evt) {
    evt.preventDefault();
    let comments = Session.get('comments'),
        id = $(evt.currentTarget).closest('.comment-item').attr('data-uuid');
    comments = comments.filter((com) => {
      return com.uuid != id;
    });
    Session.set('comments', comments);
  },
  'click .add-comment': function (evt) {
    evt.preventDefault();
    let comments = Session.get('comments');
    comments.push({uuid: UI._globalHelpers.generateUUID()});
    Session.set('comments', comments);
  },
  'change input': function () {
    let comments = Session.get('comments'),
        commentArray = Session.get('commentHistory');
    comments.forEach((com) => {
      com.comment = $('.comment-item[data-uuid="' + com.uuid + '"] input').val();
    });
    Session.set('comments', comments);
    commentArray.push(comments);
    Session.set('commentHistory', commentArray);

    let actionHistory = Session.get('actionHistory');
    actionHistory.push('comment');
    Session.set('actionHistory', actionHistory);
  },
  'keydown .last-comment': function (evt) {
    if (evt.keyCode === 9 && !evt.shiftKey && $(evt.currentTarget).find('input').val().length > 0) {
      evt.preventDefault();
      $('.add-comment').trigger('click');
      setTimeout(function() { $('.last-comment input').focus(); }, 100);
    }
  },
  'keydown input': function (evt) {
    if (evt.keyCode === 13) {
      evt.preventDefault();
      // Translate that return into a tab...
      var e = jQuery.Event('keydown', { keyCode: 9 });
      $(evt.currentTarget).trigger(e);
    }
  },
  'click .undo-comment-action': function (evt) {
    evt.preventDefault();
    let commentArray = Session.get('commentHistory');
    Session.set('comments', commentArray.pop());
    Session.set('commentHistory', commentArray);
  }
});

Template.viewSchemes.helpers({
});

Template.viewSchemesListItem.helpers({
  friendlyDate: function () {
    return moment(this.createdAt).fromNow();
  },
  recent: function () {
    console.log(moment(this.createdAt).isAfter(moment().startOf('day')));
    return moment(this.createdAt).isAfter(moment().startOf('day'));
  }
});

Template.viewSchemesListItem.events({
  'click .delete-scheme': function (evt) {
    evt.preventDefault();
    console.log('deleting: ', this._id);
    Meteor.call('deleteScheme', this._id);
  },
  'click .edit-scheme': function (evt) {
    evt.preventDefault();
    window.alert('Coming soon!');
  }
});
<commit_msg>Remove some console messages.<commit_after>Meteor.startup(() => {
  $('html').attr('lang', 'en');
});

Template.main.onRendered(() => {
  $('.ui.menu .ui.dropdown').dropdown({
      on: 'hover'
    });
});

Template.markScheme.onRendered(() => {
  $('.ui.checkbox').checkbox();
});

Template.insertScheme.onRendered(() => {
  $('.ui.checkbox').checkbox();
  $.getScript('dragula.min.js', function () {
    var lastItem;
    drake = dragula({
      isContainer: function (el) {
        return el.classList.contains('dragula-container');
      }
    });
    drake.on('drop', function(item, tar, source, sibling) {
      $('.rubric-table input:first').trigger('change');
      let rObj = Session.get('rubricObject');
      Session.set('rubricObject', []);
      Meteor.setTimeout( function () {
        Session.set('rubricObject', rObj);
      }, 80);
    });
  });
});

Session.setDefault('adjustmentAllowed', false);
Session.setDefault('rubricObject', [{
  uuid: UI._globalHelpers.generateUUID(),
  rows: [{uuid: UI._globalHelpers.generateUUID()}],
}]);
Session.setDefault('comments', [{
  uuid: UI._globalHelpers.generateUUID()
}]);
Session.setDefault('rubricHistory', []);
Session.setDefault('unitName', UI._globalHelpers.generateFunName());
Session.setDefault('editingName', false);
Session.setDefault('commentHistory', []);
// Keep track of if rubric or comment field should be undone.
Session.setDefault('actionHistory', []);

var totalMarksFunction = function () {
  let rObjs = Session.get('rubricObject'),
      totalMarks = 0;
  rObjs.forEach((rubric) => {
    let max = 0;
    rubric.rows.forEach((r) => {
      if (r.criteriaValue !== undefined && r.criteriaValue > max) {
        max = r.criteriaValue;
      }
    });
    totalMarks += max;
  });
  return totalMarks;
}

Template.insertScheme.helpers({
  'totalMarks': totalMarksFunction
  ,
  'unitName': function () {
    return Session.get('unitName');
  },
  'editingName': function () {
    return Session.get('editingName');
  }
});

Template.insertScheme.events({
  'click .submit-scheme': function(evt) {
    let form = $('#marking-scheme-form')[0];
    if (form.checkValidity()) {
      evt.preventDefault();
      let schemaObject = {
        'name': $('input[name="scheme-name"]').val(),
        'description': $('textarea[name="scheme-desc"]').val(),
        'createdAt': new Date(),
        'aspects': Session.get('rubricObject'),
        'comments': Session.get('comments'),
        'adjustmentValuePositive': $('input[name="adjustment-positive"]').val(),
        'adjustmentValueNegative': $('input[name="adjustment-negative"]').val(),
        'maxMarks': totalMarksFunction()
      };
      Meteor.call('addScheme', schemaObject, (error, result) => {
        if (error) {
          console.log(error.message, error.details);
        } else {
          Session.set('adjustmentAllowed', false);
          Session.set('rubricObject', [{
            uuid: UI._globalHelpers.generateUUID(),
            rows: [{uuid: UI._globalHelpers.generateUUID()}],
          }]);
          Session.set('comments', [{
            uuid: UI._globalHelpers.generateUUID()
          }]);
          Session.set('rubricHistory', []);
          Session.set('unitName', UI._globalHelpers.generateFunName());
          Session.set('editingName', false);
          Session.set('commentHistory', []);
          Session.set('actionHistory', []);
          form.reset();
          Router.go('/viewSchemes');
        }
      });
    } else {
      // Semantic validation checks
    }
  },
  'click .name-field': function () {
    Session.set('editingName', true);
    setTimeout(function() { $('input[name="scheme-name"]').select(); }, 100);

  },
  'blur input[name="scheme-name"]': function () {
    Session.set('editingName', false);
    Session.set('unitName', $('input[name="scheme-name"]').val());
  },
  'keydown': function (evt) {
    // Meta key works for ctrl on windows and cmd on mac.
    if (evt.keyCode == 90 && evt.metaKey) alert("Ctrl+z");
    // TODO: UNDO THINGS!
  },
  'click .reset-scheme': function (evt) {
    evt.preventDefault();
    $('.ui.basic.reset-check.modal')
      .modal({
        closable  : false,
        onApprove : function() {
          document.getElementById("marking-scheme-form").reset();
          $('input[name="scheme-name"]').val(Session.get('unitName'));
        },
        detachable: false
      }).modal('show');
  }
});

Template.rubricBuilder.helpers({
  rubricObject: function () {
    return Session.get('rubricObject');
  },
  pickColour: function (index) {
    let colours = ['blue', 'orange', 'green', 'yellow',
                    'teal', 'violet', 'grey', 'pink'];
    return colours[index % colours.length];
  },
  canUndo: function() {
    return Session.get('rubricHistory').length > 0;
  }
});

Template.rubricBuilder.events({
  'click .add-criterion': function (evt) {
    evt.preventDefault();
    let rObjs = Session.get('rubricObject'),
        id = $(evt.currentTarget).closest('div .grid').attr('data-uuid');
    rObjs.forEach((rubric) => {
      if (rubric.uuid == id) {
        rubric['rows'].push({uuid: UI._globalHelpers.generateUUID()});
      }
    });
    Session.set('rubricObject', rObjs);
  },
  'click .add-aspect': function (evt) {
    evt.preventDefault();
    let rObj = Session.get('rubricObject');
    rObj.push({
      uuid: UI._globalHelpers.generateUUID(),
      rows: [{uuid: UI._globalHelpers.generateUUID()}]
    });
    Session.set('rubricObject', rObj);
  },
  'click .rubric-array-remove': function (evt) {
    evt.preventDefault();
    let rObjs = Session.get('rubricObject'),
        rowId = $(evt.currentTarget).closest('tr').attr('data-uuid'),
        tableId = $(evt.currentTarget).closest('table').attr('data-uuid');
    rObjs.forEach((rubric) => {
      if (rubric.uuid == tableId) {
        rubric.rows = rubric.rows.filter((row) => {
          return row.uuid != rowId;
        });
      }
    });
    Session.set('rubricObject', rObjs);
  },
  'click .remove-aspect': function (evt) {
    evt.preventDefault();
    let rObjs = Session.get('rubricObject'),
        id = $(evt.currentTarget).closest('div .grid').attr('data-uuid');
    rObjs = rObjs.filter((rubric) => {
      return rubric.uuid != id;
    });
    Session.set('rubricObject', rObjs);
  },
  'change input': function () {
    let rObjs = Session.get('rubricObject'),
        historyArray = Session.get('rubricHistory');
    historyArray.push(rObjs);

    rObjs.forEach((rubric) => {
      let $table = $('table[data-uuid="' + rubric.uuid + '"]'),
          $rows = $table.children('tbody').children('tr'),
          rows = [];
      rubric.aspect = $table.find('input[name="rubric-aspect"]').val();
      $rows.each((index, row) => {
        let rowObj = {};
        rowObj.uuid = $(row).attr('data-uuid');
        rowObj.criteria = $(row).find('input[name="criteria"]').val();
        // Parse if defined. Use base 10.
        if ($(row).find('input[name="criteria-value"]').val() !== undefined) {
          rowObj.criteriaValue = parseInt($(row).find('input[name="criteria-value"]').val(), 10);
        }
        rows.push(rowObj);
      })
      rubric.rows = rows;
    });

    let actionHistory = Session.get('actionHistory');
    actionHistory.push('rubric');
    Session.set('actionHistory', actionHistory);
    Session.set('rubricHistory', historyArray);
    Session.set('rubricObject', rObjs);

  },
  'keydown input[name="criteria-value"]': function (evt) {
    let id = $(evt.currentTarget).closest('table').attr('data-uuid'),
        $table = $('table[data-uuid="' + id + '"]');
        $lastRow = $table.find('tr:last');
        lastRowId = $lastRow.attr('data-uuid');
        eventId = $(evt.currentTarget).closest('tr').attr('data-uuid');
    if (eventId === lastRowId) {
      if (evt.keyCode === 9 && !evt.shiftKey && ($(evt.currentTarget).val() || $lastRow.find('input[name="criteria"]').val().length > 0)) {
        evt.preventDefault();
        $('div[data-uuid="' + id +'"]').find('.add-criterion').trigger('click');
        Meteor.setTimeout(function() { $table.find('tr:last input[name="criteria"]').focus(); }, 100);
      }
    }
  },
  'keydown input': function (evt) {
    if (evt.keyCode === 13) {
      evt.preventDefault();
      // Translate that return into a tab...
      let e = jQuery.Event('keydown', { keyCode: 9 });
      $(evt.currentTarget).trigger(e);
    }
  },
  'click .duplicate-aspect': function (evt) {
    evt.preventDefault();
    let rObj = Session.get('rubricObject'),
        id = $(evt.currentTarget).closest('div .grid').attr('data-uuid'),
        historyArray = Session.get('rubricHistory');

    rObj.forEach((rubric) => {
      if (rubric.uuid == id) {
        let newRows = [];
        rubric.rows.forEach((row) => {
          newRows.push({
            uuid: UI._globalHelpers.generateUUID(),
            criteria: row.criteria,
            criteriaValue: row.criteriaValue
          });
        });
        rObj.push({
          aspect: rubric.aspect,
          uuid: UI._globalHelpers.generateUUID(),
          rows: newRows
        });
      }
    });
    historyArray.push(rObj);
    Session.set('rubricHistory', historyArray);
    Session.set('rubricObject', rObj);
  },
  'click .undo-rubric-action': function (evt) {
    evt.preventDefault();
    let historyArray = Session.get('rubricHistory');
    Session.set('rubricObject', historyArray.pop());
    Session.set('rubricHistory', historyArray);
  }
});

Template.commentBuilder.helpers({
  comments: function () {
    return Session.get('comments');
  },
  isLast: function(index) {
    if (index === Session.get('comments').length - 1) {
      return 'last-comment';
    } else {
      return '';
    }
  },
  canUndo: function() {
    return Session.get('commentHistory').length > 0;
  }
});

Template.commentBuilder.events({
  'click .comment-remove': function (evt) {
    evt.preventDefault();
    let comments = Session.get('comments'),
        id = $(evt.currentTarget).closest('.comment-item').attr('data-uuid');
    comments = comments.filter((com) => {
      return com.uuid != id;
    });
    Session.set('comments', comments);
  },
  'click .add-comment': function (evt) {
    evt.preventDefault();
    let comments = Session.get('comments');
    comments.push({uuid: UI._globalHelpers.generateUUID()});
    Session.set('comments', comments);
  },
  'change input': function () {
    let comments = Session.get('comments'),
        commentArray = Session.get('commentHistory');
    comments.forEach((com) => {
      com.comment = $('.comment-item[data-uuid="' + com.uuid + '"] input').val();
    });
    Session.set('comments', comments);
    commentArray.push(comments);
    Session.set('commentHistory', commentArray);

    let actionHistory = Session.get('actionHistory');
    actionHistory.push('comment');
    Session.set('actionHistory', actionHistory);
  },
  'keydown .last-comment': function (evt) {
    if (evt.keyCode === 9 && !evt.shiftKey && $(evt.currentTarget).find('input').val().length > 0) {
      evt.preventDefault();
      $('.add-comment').trigger('click');
      setTimeout(function() { $('.last-comment input').focus(); }, 100);
    }
  },
  'keydown input': function (evt) {
    if (evt.keyCode === 13) {
      evt.preventDefault();
      // Translate that return into a tab...
      var e = jQuery.Event('keydown', { keyCode: 9 });
      $(evt.currentTarget).trigger(e);
    }
  },
  'click .undo-comment-action': function (evt) {
    evt.preventDefault();
    let commentArray = Session.get('commentHistory');
    Session.set('comments', commentArray.pop());
    Session.set('commentHistory', commentArray);
  }
});

Template.viewSchemes.helpers({
});

Template.viewSchemesListItem.helpers({
  friendlyDate: function () {
    return moment(this.createdAt).fromNow();
  },
  recent: function () {
    return moment(this.createdAt).isAfter(moment().startOf('day'));
  }
});

Template.viewSchemesListItem.events({
  'click .delete-scheme': function (evt) {
    evt.preventDefault();
    console.log('deleting: ', this._id);
    Meteor.call('deleteScheme', this._id);
  },
  'click .edit-scheme': function (evt) {
    evt.preventDefault();
    window.alert('Coming soon!');
  }
});
<|endoftext|>


<commit_before>define(['app',
    'lodash',
  ],
  function(app,_) {

    app.directive('toolTip', [function() {
      return {
        restrict: 'A',
        replace: false,
        transclude: false,

        link: function($scope, $element, $attr) {

          $element.tooltip({ placement: $attr.dataPlacement,
                 content: function() {
                   return $attr.dataOriginalTitle;
                 }
           });

           $element.on('mouseenter', function() {
                 $element.tooltip('show');
           });
           $element.on('mouseleave', function() {
                 $element.tooltip('hide');
           });

          } //link
      }; //return
    }]); //directive

  }); //define<commit_msg>timeout remove tooltip, some were getting stuck<commit_after>define(['app'],
  function(app) {

    app.directive('toolTip', ['$timeout',function($timeout) {
      return {
        restrict: 'A',
        replace: false,
        transclude: false,

        link: function($scope, $element, $attr) {

          $element.tooltip({ placement: $attr.dataPlacement,
                 content: function() {
                   return $attr.dataOriginalTitle;
                 }
           });

           $element.on('mouseenter', function() {
                 $element.tooltip('show');
                 $timeout(function(){
                    $element.tooltip('hide');
                 },5000);
           });
           $element.on('mouseleave', function() {
                 $element.tooltip('hide');
           });

          } //link
      }; //return
    }]); //directive

  }); //define<|endoftext|>


<commit_before>/* global angular */
'use strict';

angular.module('storm.controllers')

.controller('LocalRowListCtrl', ['$scope', '$state', '$stateParams', '$injector', 'Navigation', function($scope, $state, $stateParams, $injector, Navigation) {

	$scope.items = [];
	$scope.lastPage = true;

	var oldest = $stateParams.view === 'oldest' ? true : false;

	// Delete alert
	$scope.deleteAlert = $stateParams.view === 'delete' ? true : undefined;

	if (!$scope.deleteAlert) {
		// Get service dynamically from current state
		var service = $injector.get($state.current.service);

		service.getList(oldest).then(function(items) {
			$scope.items = items;
		});
	}

	$scope.$watch('deleteAlert', function(value, oldValue) {
		if (value === undefined) return;
		Navigation.setActiveElement(value ? 'confirm-delete' : 'menu-' + $state.current.service.toLowerCase());
	});

	$scope.delete = function() {
		service.clear().then(function() {
			$scope.items = [];
		});
		$scope.hideDeleteAlert();
	};

	$scope.hideDeleteAlert = function() {
		$scope.deleteAlert = false;
	};

}]);<commit_msg>Fix delete confirmation in queue and history<commit_after>/* global angular */
'use strict';

angular.module('storm.controllers')

.controller('LocalRowListCtrl', ['$scope', '$state', '$stateParams', '$injector', 'Navigation', function($scope, $state, $stateParams, $injector, Navigation) {

	$scope.items = [];
	$scope.lastPage = true;

	var oldest = $stateParams.view === 'oldest' ? true : false;

	// Delete alert
	$scope.deleteAlert = $stateParams.view === 'delete' ? true : undefined;

	// Get service dynamically from current state
	var service = $injector.get($state.current.service);

	if (!$scope.deleteAlert) {
		service.getList(oldest).then(function(items) {
			$scope.items = items;
		});
	}

	$scope.$watch('deleteAlert', function(value, oldValue) {
		if (value === undefined) return;
		Navigation.setActiveElement(value ? 'confirm-delete' : 'menu-' + $state.current.service.toLowerCase());
	});

	$scope.delete = function() {
		service.clear().then(function() {
			$scope.items = [];
		});
		$scope.hideDeleteAlert();
	};

	$scope.hideDeleteAlert = function() {
		$scope.deleteAlert = false;
	};

}]);<|endoftext|>


<commit_before>import redis from 'redis';

let client;

function getHistoricalCrawlData(startIndex, count) {
  return new Promise((resolve, reject) => {
    client.lrange('aggregated-info', startIndex, startIndex + count - 1, (err, response) => {
      if (err) {
        return reject(err);
      }
      response.forEach((json, index, arr) => {
        arr[index] = JSON.parse(json);
      });
      return resolve(response);
    });
  });
}

function getHistoricalURLData(url, count) {
  return new Promise((resolve, reject) => {
    const key = `historical-data:${url}`;
    client.lrange(key, 0, count - 1, (err, response) => {
      if (err) {
        return reject(err);
      }
      response.forEach((json, index, arr) => {
        arr[index] = JSON.parse(json);
      });
      return resolve(response);
    });
  });
}

function addPromise(promises) {
  let resolve;
  let reject;
  const p = new Promise((res, rej) => {
    resolve = res;
    reject = rej;
  });
  promises.push(p);

  return (err, response) => {
    if (err) {
      return reject(err);
    }
    return resolve(response);
  };
}

function updateWithCurrentCrawlResult(url, data) {
  const promises = [];

  client.lpush(`historical-data:${url}`, JSON.stringify(data), addPromise(promises));

  for (const i in data) {
    if (data.hasOwnProperty(i) && data[i] === true) {
      client.hincrby('current-crawl-aggregated-data', i, 1, addPromise(promises));
    }
  }
  client.hincrby('current-crawl-aggregated-data', 'totalRecords', 1, addPromise(promises));

  return Promise.all(promises);
}

function finishCurrentCrawl() {
  return new Promise((resolve, reject) => {
    client.hgetall('current-crawl-aggregated-data', (err, response) => {
      if (err) {
        return reject(err);
      }

      const promises = [];
      client.lpush('aggregated-info', JSON.stringify(response), addPromise(promises));
      client.del('current-crawl-aggregated-data', addPromise(promises));
      return Promise.all(promises).then(() => {
        return resolve();
      });
    });
  });
}

function configure(opts) {
  return new Promise((resolve, reject) => {
    if (!opts.url) {
      return reject(new Error('Redis URL must be specified'));
    }

    let createClientOpts = {};
    if (opts.createClientOpts) {
      createClientOpts = opts.createClientOpts;
    }

    try {
      client = redis.createClient(opts.url, createClientOpts);
    } catch (err) {
      return reject(err);
    }

    if (!opts.dbTestNumber) {
      return resolve();
    }

    client.select(opts.dbTestNumber, (err) => {
      if (err) {
        return reject(err);
      }
      return resolve();
    });
  });
}

export default {
  getHistoricalCrawlData,
  getHistoricalURLData,
  updateWithCurrentCrawlResult,
  finishCurrentCrawl,
  configure,
};
<commit_msg>Return new arr from dataStore.getHistoricalURLData<commit_after>import redis from 'redis';

let client;

function getHistoricalCrawlData(startIndex, count) {
  return new Promise((resolve, reject) => {
    client.lrange('aggregated-info', startIndex, startIndex + count - 1, (err, response) => {
      if (err) {
        return reject(err);
      }
      response.forEach((json, index, arr) => {
        arr[index] = JSON.parse(json);
      });
      return resolve(response);
    });
  });
}

function getHistoricalURLData(url, count) {
  return new Promise((resolve, reject) => {
    const key = `historical-data:${url}`;
    client.lrange(key, 0, count - 1, (err, response) => {
      if (err) {
        return reject(err);
      }
      const ret = response.map((json) => {
        return JSON.parse(json);
      });
      return resolve(ret);
    });
  });
}

function addPromise(promises) {
  let resolve;
  let reject;
  const p = new Promise((res, rej) => {
    resolve = res;
    reject = rej;
  });
  promises.push(p);

  return (err, response) => {
    if (err) {
      return reject(err);
    }
    return resolve(response);
  };
}

function updateWithCurrentCrawlResult(url, data) {
  const promises = [];

  client.lpush(`historical-data:${url}`, JSON.stringify(data), addPromise(promises));

  for (const i in data) {
    if (data.hasOwnProperty(i) && data[i] === true) {
      client.hincrby('current-crawl-aggregated-data', i, 1, addPromise(promises));
    }
  }
  client.hincrby('current-crawl-aggregated-data', 'totalRecords', 1, addPromise(promises));

  return Promise.all(promises);
}

function finishCurrentCrawl() {
  return new Promise((resolve, reject) => {
    client.hgetall('current-crawl-aggregated-data', (err, response) => {
      if (err) {
        return reject(err);
      }

      const promises = [];
      client.lpush('aggregated-info', JSON.stringify(response), addPromise(promises));
      client.del('current-crawl-aggregated-data', addPromise(promises));
      return Promise.all(promises).then(() => {
        return resolve();
      });
    });
  });
}

function configure(opts) {
  return new Promise((resolve, reject) => {
    if (!opts.url) {
      return reject(new Error('Redis URL must be specified'));
    }

    let createClientOpts = {};
    if (opts.createClientOpts) {
      createClientOpts = opts.createClientOpts;
    }

    try {
      client = redis.createClient(opts.url, createClientOpts);
    } catch (err) {
      return reject(err);
    }

    if (!opts.dbTestNumber) {
      return resolve();
    }

    client.select(opts.dbTestNumber, (err) => {
      if (err) {
        return reject(err);
      }
      return resolve();
    });
  });
}

export default {
  getHistoricalCrawlData,
  getHistoricalURLData,
  updateWithCurrentCrawlResult,
  finishCurrentCrawl,
  configure,
};
<|endoftext|>


<commit_before>import React from 'react'
import { render } from 'react-dom'
import Modal from 'react-modal'

import { errorTest } from '../shared/methods'
import Layout, { Basic as BasicLayout } from './pages/layout'
import App from './app'

import 'formdata-polyfill'
import './visual/global'

import Dashboard from './pages/dashboard'
import Control from './pages/control'
import Home from './pages/home'
import Login, { loggedInRedirect } from './pages/login'
import GetStarted from './pages/get-started'
import Campaign from './pages/campaign'
import CampaignSettings from './pages/campaign-settings'
import CampaignPlayers from './pages/campaign-players'
import NewCampaign from './pages/new-campaign'
import Verify from './pages/verify'
import Enrol from './pages/enrol'
import Card from './pages/card'
import EditCard from './pages/edit-card'

const root = document.createElement('div')
root.id = 'react-root'
document.body.appendChild(root)

Modal.setAppElement('#' + root.id)

render(
	<App
		routes={{
			'/:campaignId/dashboard'({ campaignId }) {
				return (
					<BasicLayout campaignId={campaignId}>
						<Dashboard />
					</BasicLayout>
				)
			},

			'/:campaignId/dashboard-control'({ campaignId }) {
				return (
					<Layout campaignId={campaignId}>
						<Control />
					</Layout>
				)
			},

			'/:campaignId/join/:secret'({ campaignId, secret }) {
				return (
					<Layout campaignId={campaignId} secret={secret}>
						<Enrol secret={secret} />
					</Layout>
				)
			},

			'/:campaignId/settings'({ campaignId }) {
				return (
					<Layout campaignId={campaignId}>
						<CampaignSettings />
					</Layout>
				)
			},

			'/:campaignId/players'({ campaignId }) {
				return (
					<Layout campaignId={campaignId}>
						<CampaignPlayers />
					</Layout>
				)
			},

			'/:campaignId/new'({ campaignId }) {
				return (
					<Layout campaignId={campaignId}>
						<EditCard />
					</Layout>
				)
			},

			'/:campaignId/:cardId'({ campaignId, cardId }) {
				if (!cardId) return false

				return (
					<Layout campaignId={campaignId}>
						<Card cardId={cardId} />
					</Layout>
				)
			},

			'/:campaignId/:cardId/edit'({ campaignId, cardId }) {
				if (!cardId) return false

				return (
					<Layout campaignId={campaignId}>
						<EditCard cardId={cardId} />
					</Layout>
				)
			},

			'/:campaignId'({ campaignId }) {
				if (!campaignId) return false

				return (
					<Layout campaignId={campaignId}>
						<Campaign />
					</Layout>
				)
			},

			'/new-campaign'() {
				return (
					<Layout>
						<NewCampaign />
					</Layout>
				)
			},

			'/get-started'(params, { title }) {
				return (
					loggedInRedirect() || (
						<Layout>
							<GetStarted title={title} />
						</Layout>
					)
				)
			},

			'/login'() {
				return (
					loggedInRedirect() || (
						<Layout>
							<Login />
						</Layout>
					)
				)
			},

			'/verify/:token'({ token }) {
				return (
					loggedInRedirect() || (
						<Layout>
							<Verify token={token} />
						</Layout>
					)
				)
			},

			'/debug'() {
				return (
					<Layout>
						<button type='button' onClick={() => errorTest()}>
							throw a meteor.call error
						</button>
					</Layout>
				)
			},

			'/'() {
				return (
					<Layout>
						<Home />
					</Layout>
				)
			},
		}}
	/>,
	root,
)
<commit_msg>full layout for dashboard<commit_after>import React from 'react'
import { render } from 'react-dom'
import Modal from 'react-modal'

import { errorTest } from '../shared/methods'
import Layout, { Basic as BasicLayout } from './pages/layout'
import App from './app'

import 'formdata-polyfill'
import './visual/global'

import Dashboard from './pages/dashboard'
import Control from './pages/control'
import Home from './pages/home'
import Login, { loggedInRedirect } from './pages/login'
import GetStarted from './pages/get-started'
import Campaign from './pages/campaign'
import CampaignSettings from './pages/campaign-settings'
import CampaignPlayers from './pages/campaign-players'
import NewCampaign from './pages/new-campaign'
import Verify from './pages/verify'
import Enrol from './pages/enrol'
import Card from './pages/card'
import EditCard from './pages/edit-card'

const root = document.createElement('div')
root.id = 'react-root'
document.body.appendChild(root)

Modal.setAppElement('#' + root.id)

render(
	<App
		routes={{
			'/:campaignId/dashboard'({ campaignId }) {
				return (
					<Layout campaignId={campaignId}>
						<Dashboard />
					</Layout>
				)
			},

			'/:campaignId/dashboard-control'({ campaignId }) {
				return (
					<Layout campaignId={campaignId}>
						<Control />
					</Layout>
				)
			},

			'/:campaignId/join/:secret'({ campaignId, secret }) {
				return (
					<Layout campaignId={campaignId} secret={secret}>
						<Enrol secret={secret} />
					</Layout>
				)
			},

			'/:campaignId/settings'({ campaignId }) {
				return (
					<Layout campaignId={campaignId}>
						<CampaignSettings />
					</Layout>
				)
			},

			'/:campaignId/players'({ campaignId }) {
				return (
					<Layout campaignId={campaignId}>
						<CampaignPlayers />
					</Layout>
				)
			},

			'/:campaignId/new'({ campaignId }) {
				return (
					<Layout campaignId={campaignId}>
						<EditCard />
					</Layout>
				)
			},

			'/:campaignId/:cardId'({ campaignId, cardId }) {
				if (!cardId) return false

				return (
					<Layout campaignId={campaignId}>
						<Card cardId={cardId} />
					</Layout>
				)
			},

			'/:campaignId/:cardId/edit'({ campaignId, cardId }) {
				if (!cardId) return false

				return (
					<Layout campaignId={campaignId}>
						<EditCard cardId={cardId} />
					</Layout>
				)
			},

			'/:campaignId'({ campaignId }) {
				if (!campaignId) return false

				return (
					<Layout campaignId={campaignId}>
						<Campaign />
					</Layout>
				)
			},

			'/new-campaign'() {
				return (
					<Layout>
						<NewCampaign />
					</Layout>
				)
			},

			'/get-started'(params, { title }) {
				return (
					loggedInRedirect() || (
						<Layout>
							<GetStarted title={title} />
						</Layout>
					)
				)
			},

			'/login'() {
				return (
					loggedInRedirect() || (
						<Layout>
							<Login />
						</Layout>
					)
				)
			},

			'/verify/:token'({ token }) {
				return (
					loggedInRedirect() || (
						<Layout>
							<Verify token={token} />
						</Layout>
					)
				)
			},

			'/debug'() {
				return (
					<Layout>
						<button type='button' onClick={() => errorTest()}>
							throw a meteor.call error
						</button>
					</Layout>
				)
			},

			'/'() {
				return (
					<Layout>
						<Home />
					</Layout>
				)
			},
		}}
	/>,
	root,
)
<|endoftext|>


<commit_before>'use strict';

/*
 * Defining the Package
 */
var Module = require('meanio').Module;

var Columby = new Module('columby');

/*
 * All MEAN packages require registration
 * Dependency injection is used to define required modules
 */
Columby.register(function(app, auth, database) {

  //We enable routing. By default the Package Object is passed to the routes
  Columby.routes(app, auth, database);

  Columby.aggregateAsset('css','fontello/fontello.css');
  Columby.aggregateAsset('css','fontello/animation.css');
  Columby.aggregateAsset('css','columby.css');
  Columby.aggregateAsset('css','editor-sidebar.css');

  if (process.env.NODE_ENV === 'development') {
    Columby.aggregateAsset('js', 'typekit.js');
  }

  return Columby;
});
<commit_msg>toaster instead of notification2<commit_after>'use strict';

/*
 * Defining the Package
 */
var Module = require('meanio').Module;

var Columby = new Module('columby');

/*
 * All MEAN packages require registration
 * Dependency injection is used to define required modules
 */
Columby.register(function(app, auth, database) {

  //We enable routing. By default the Package Object is passed to the routes
  Columby.routes(app, auth, database);

  Columby.aggregateAsset('css','fontello/fontello.css');
  Columby.aggregateAsset('css','fontello/animation.css');
  Columby.aggregateAsset('css','columby.css');
  Columby.aggregateAsset('css','editor-sidebar.css');

  /*
  if (process.env.NODE_ENV === 'development') {
    Columby.aggregateAsset('js', 'typekit.js');
  }
*/
  return Columby;
});
<|endoftext|>


<commit_before>/* This file is licensed under the MIT License. See LICENSE for details. */

var node = [];
var save = [];

for (let i = 0; i < 12; i += 1) {
  node[i] = document.createElement("div");
  document.querySelector("#grid").appendChild(node[i]);

  node[i].classList.add("node");
  node[i].code = document.createElement("textarea");

  node[i].code.spellcheck = false;
  node[i].code.addEventListener("input", function () {
    var text = this.value.split("\n");
    for (let i = 0; i < text.length; i += 1) {
      if (text[i].length > 18) text[i] = text[i].substring(0, 18);
      text[i] = text[i].toLowerCase();
    }
    this.value = text.slice(0, 15).join('\n');

    save[i] = this.value;
    window.name = JSON.stringify(save);
  });

  node[i].appendChild(node[i].code);

  for (let thing of ["acc", "bak", "last", "mode", "idle"]) {
    node[i][thing] = document.createElement("div");
    node[i][thing].classList.add("data", thing);
    node[i][thing].innerHTML = "
";
    node[i].appendChild(node[i][thing]);
  }

  node[i].acc.setAttribute("data-value", "0");
  node[i].bak.setAttribute("data-value", "(0)");
  node[i].last.setAttribute("data-value", "n/a");
  node[i].mode.setAttribute("data-value", "idle");
  node[i].idle.setAttribute("data-value", "0%");

  if (i > 3) {
    node[i].classList.add("margin-top");
    node[i].arrow = {};

    for (let dir of ["up", "down"]) {
      node[i].arrow[dir] = document.createElement("div");
      node[i].arrow[dir].classList.add("arrow", dir);
      node[i].appendChild(node[i].arrow[dir]);
    }
  }
  if (i % 4 !== 0) {
    node[i].classList.add("margin-left");
    if (!node[i].arrow) node[i].arrow = {};

    for (let dir of ["left", "right"]) {
      node[i].arrow[dir] = document.createElement("div");
      node[i].arrow[dir].classList.add("arrow", dir);
      node[i].appendChild(node[i].arrow[dir]);
    }
  }
}

if (window.name !== "") {
  save = JSON.parse(window.name);
  for (let i = 0; i < 12; i += 1) {
    node[i].code.value = save[i] || "";
  }
}

var TIS = {
  runCmd: function (cmd, node) {
    cmd = cmd.replace(/((\s)\s+)|,/g, "$2").split(" ");
    if ((!cmd[0][0]) || cmd[0][0] === "#") return;

    for (let i = 1; i < cmd.length; i += 1) {
      if (cmd[i][0] === "#") {
        cmd = cmd.slice(0, i);
        break;
      }
    }

    if (cmd[0] === "nop") {
      if (cmd[1]) throw new SyntaxError("too many operands");
      return;
    }

    if (cmd[0] === "mov") {
      if (cmd.length < 3) throw new SyntaxError("missing operand");
      if (cmd.length > 3) throw new SyntaxError("too many operands");
    }
  }
};
<commit_msg>Add MOV support to API<commit_after>/* This file is licensed under the MIT License. See LICENSE for details. */

var node = [];
var save = [];

for (let i = 0; i < 12; i += 1) {
  node[i] = document.createElement("div");
  document.querySelector("#grid").appendChild(node[i]);
  node[i].classList.add("node");

  node[i].outgate = {};
  node[i].ready = true;

  node[i].code = document.createElement("textarea");
  node[i].code.spellcheck = false;

  node[i].code.addEventListener("input", function () {
    var text = this.value.split("\n");
    for (let i = 0; i < text.length; i += 1) {
      if (text[i].length > 18) text[i] = text[i].substring(0, 18);
      text[i] = text[i].toLowerCase();
    }
    this.value = text.slice(0, 15).join('\n');

    save[i] = this.value;
    window.name = JSON.stringify(save);
  });

  node[i].appendChild(node[i].code);

  for (let thing of ["acc", "bak", "last", "mode", "idle"]) {
    node[i][thing] = document.createElement("div");
    node[i][thing].classList.add("data", thing);
    node[i][thing].innerHTML = "
";
    node[i].appendChild(node[i][thing]);
  }

  node[i].acc.setAttribute("data-value", "0");
  node[i].bak.setAttribute("data-value", "(0)");
  node[i].last.setAttribute("data-value", "n/a");
  node[i].mode.setAttribute("data-value", "idle");
  node[i].idle.setAttribute("data-value", "0%");

  if (i > 3) {
    node[i].classList.add("margin-top");
    node[i].arrow = {};

    for (let dir of ["up", "down"]) {
      node[i].arrow[dir] = document.createElement("div");
      node[i].arrow[dir].classList.add("arrow", dir);
      node[i].appendChild(node[i].arrow[dir]);
    }
  }
  if (i % 4 !== 0) {
    node[i].classList.add("margin-left");
    if (!node[i].arrow) node[i].arrow = {};

    for (let dir of ["left", "right"]) {
      node[i].arrow[dir] = document.createElement("div");
      node[i].arrow[dir].classList.add("arrow", dir);
      node[i].appendChild(node[i].arrow[dir]);
    }
  }
}

if (window.name !== "") {
  save = JSON.parse(window.name);
  for (let i = 0; i < 12; i += 1) {
    node[i].code.value = save[i] || "";
  }
}

var TIS = {
  eval: function (nodei, cmd) {
    cmd = cmd.replace(/((\s)\s+)|,/g, "$2").split(" ");
    if ((!cmd[0][0]) || cmd[0][0] === "#") return;

    for (let i = 1; i < cmd.length; i += 1) {
      if (cmd[i][0] === "#") {
        cmd = cmd.slice(0, i);
        break;
      }
    }

    if (cmd[0] === "nop") {
      if (cmd[1]) throw new SyntaxError("too many operands");
      return;
    }

    if (cmd[0] === "mov") {
      if (cmd.length < 3) throw new SyntaxError("missing operand");
      if (cmd.length > 3) throw new SyntaxError("too many operands");
      TIS.mov(nodei, cmd[1], cmd[2]);
    }
  },
  mov: function (nodei, src, dst) {
    if (src.match(/^[0-9]+$/)) {
      if (["up", "right", "down", "left"].indexOf(dst) !== -1) {
        if (node[nodei].outgate[dst] && node[nodei].outgate[dst].match(/a-z/)) {
          if (dst === "up")         var dstnode = nodei - 4;
          else if (dst === "right") var dstnode = nodei + 1;
          else if (dst === "down")  var dstnode = nodei + 4;
          else                      var dstnode = nodei - 1;
          TIS.mov(dstnode, src, node[nodei].outgate[dst]);
          node[dstnode].ready = true;
        } else {
          node[nodei].outgate[dst] = src;
          node[nodei].ready = false;
        }
      } else if (dst === "acc") {
        node[nodei].acc.setAttribute("data-value", src);
      } else {
        throw new ReferenceError('invalid register "' + dst + '"');
      }
    } else if (["up", "right", "down", "left"].indexOf(src) !== -1) {
      if (src === "up") {
        var rule = nodei > 3;
        var dstnode = nodei - 4;
        var dstdir = "down";
      } else if (src === "right") {
        var rule = nodei < 11;
        var dstnode = nodei + 1;
        var dstdir = "left";
      } else if (src === "down") {
        var rule = nodei < 8;
        var dstnode = nodei + 4;
        var dstdir = "up";
      } else {
        var rule = nodei > 0;
        var dstnode = nodei - 1;
        var dstdir = "right";
      }
      if (rule) {
        if (node[dstnode].outgate[dstdir]) {
          TIS.mov(nodei, node[dstnode].outgate[dstdir], dst);
          node[dstnode].ready = true;
        } else {
          node[dstnode].outgate[dstdir] = dst;
          node[nodei].ready = false;
        }
      }
    } else if (src === "acc") {
      TIS.mov(nodei, node[nodei].acc.getAttribute("data-value"), dst);
    } else {
      throw new SyntaxError('invalid expression "' + src + '"');
    }
  }
};
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015-2016 by Arena of Titans Contributors.
 *
 * This file is part of Arena of Titans.
 *
 * Arena of Titans is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Arena of Titans is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Arena of Titans. If not, see <http://www.gnu.org/licenses/>.
 */

import * as LogManager from "aurelia-logging";
import { inject } from "aurelia-framework";
import { EventAggregator } from "aurelia-event-aggregator";
import { I18N } from "aurelia-i18n";

@inject(I18N, EventAggregator)
export class Popup {
    constructor(i18n, ea) {
        this._i18n = i18n;
        this._ea = ea;

        this._logger = LogManager.getLogger("AoTPopup");
        this._popups = [];
        this._displayedPopupData = null;
        // We initialize the displayed popup deferred to a resolved deferred.
        this._displayedPopupDeferred = this._createDeferred();
        this._displayedPopupDeferred.resolve();

        this._popupReadyDeferred = this._createDeferred();
        this._ea.subscribe("aot:popup:ready", () => {
            this._popupReadyDeferred.resolve();
        });
        this._ea.subscribe("i18n:locale:changed", () => {
            this._translatePopup();
        });
    }

    _createDeferred() {
        const deferred = {};
        deferred.promise = new Promise((resolve, reject) => {
            deferred.resolve = () => {
                resolve();
                deferred.pending = false;
            };
            deferred.reject = () => {
                reject();
                deferred.pending = false;
            };
            deferred.pending = true;
        });
        return deferred;
    }

    display(type, data, { timeout = 0 } = {}) {
        if (type === "transition") {
            this._closeAllWithoutTimeout();
        }

        let popupDeferred = this._createDeferred();

        let startCounter = () => {
            if (type === "transition") {
                this._ea.publish("aot:game:counter_start");
            }
        };
        popupDeferred.promise.then(startCounter, startCounter);

        this._popups.push({
            type: type,
            data: data,
            deferred: popupDeferred,
            timeout: timeout,
        });
        // Since services are instantiated first, we need to wait for aot-popup to be attached
        // before trying to display a popup.
        this._popupReadyDeferred.promise.then(() => {
            return this._displayedPopupDeferred.promise.then(
                () => this._displayNext(),
                () => this._displayNext(),
            );
        });

        return popupDeferred.promise;
    }

    _closeAllWithoutTimeout() {
        this._logger.debug("Closing all popups that require user interaction");
        this._popups = this._popups.filter(popup => popup.timeout);
        if (this._displayedPopupData !== null && !this._displayedPopupData.meta.timeout) {
            this._displayedPopupDeferred.reject(new Error("Closed automatically"));
            this._displayedPopupData = null;
        }
    }

    _displayNext() {
        // We check that we have popup to display: if we are in the recursion, this._popups
        // may be an empty array.
        if (this._popups.length === 0 || this._displayedPopupDeferred.pending) {
            return;
        }

        let popup = this._popups.shift();
        this._displayedPopupData = popup.data;
        this._logger.debug("Displaying next popup", JSON.stringify(this._displayedPopupData));
        this._displayedPopupData.meta = {
            timeout: popup.timeout,
        };
        this._translatePopup();

        if (popup.timeout) {
            let closeTimeout = setTimeout(() => {
                this._logger.debug("Hit popup time out, closing", popup.timeout);
                popup.deferred.resolve();
            }, popup.timeout);
            let cancelCloseTimeout = () => {
                clearTimeout(closeTimeout);
            };
            popup.deferred.promise.then(cancelCloseTimeout, cancelCloseTimeout);
        }
        this._logger.debug("Displayed popup is now of type", popup.type);
        this._displayedPopupDeferred = popup.deferred;

        this._ea.publish("aot:popup:display", {
            type: popup.type,
            data: popup.data,
            deferred: popup.deferred,
        });

        // As soon as the current popup is closed, we display the next one.
        this._displayedPopupDeferred.promise.then(
            () => {
                this._displayedPopupData = null;
                this._displayNext();
            },
            () => {
                this._displayedPopupData = null;
                this._displayNext();
            },
        );
    }

    _translatePopup() {
        if (!this._canTranslatePopup()) {
            return;
        }

        let translateData = this._displayedPopupData.translate;
        let params = translateData.params || {};
        this._translateObj(params, translateData.paramsToTranslate);
        this._translateObj(this._displayedPopupData, translateData.messages, params);
        this._translateChoices();
    }

    _canTranslatePopup() {
        return (
            this._displayedPopupData !== null &&
            this._displayedPopupData.translate &&
            this._displayedPopupData.translate.messages
        );
    }

    _translateObj(dest, source, params = {}) {
        for (let key in source) {
            dest[key] = this._i18n.tr(source[key], params);
        }
    }

    _translateChoices() {
        if (!this._displayedPopupData.choices) {
            return;
        }

        this._displayedPopupData.choices = this._displayedPopupData.choices.map(choice => ({
            ...choice,
            name: this._i18n.tr(choice.name),
        }));

        this._translateObj(this._displayedPopupData, this._displayedPopupData.choices);
    }
}
<commit_msg>fix(popup): allow popups resolve method to take arguments<commit_after>/*
 * Copyright (C) 2015-2016 by Arena of Titans Contributors.
 *
 * This file is part of Arena of Titans.
 *
 * Arena of Titans is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Arena of Titans is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Arena of Titans. If not, see <http://www.gnu.org/licenses/>.
 */

import * as LogManager from "aurelia-logging";
import { inject } from "aurelia-framework";
import { EventAggregator } from "aurelia-event-aggregator";
import { I18N } from "aurelia-i18n";

@inject(I18N, EventAggregator)
export class Popup {
    constructor(i18n, ea) {
        this._i18n = i18n;
        this._ea = ea;

        this._logger = LogManager.getLogger("AoTPopup");
        this._popups = [];
        this._displayedPopupData = null;
        // We initialize the displayed popup deferred to a resolved deferred.
        this._displayedPopupDeferred = this._createDeferred();
        this._displayedPopupDeferred.resolve();

        this._popupReadyDeferred = this._createDeferred();
        this._ea.subscribe("aot:popup:ready", () => {
            this._popupReadyDeferred.resolve();
        });
        this._ea.subscribe("i18n:locale:changed", () => {
            this._translatePopup();
        });
    }

    _createDeferred() {
        const deferred = {};
        deferred.promise = new Promise((resolve, reject) => {
            deferred.resolve = (...args) => {
                resolve(...args);
                deferred.pending = false;
            };
            deferred.reject = (...args) => {
                reject(...args);
                deferred.pending = false;
            };
            deferred.pending = true;
        });
        return deferred;
    }

    display(type, data, { timeout = 0 } = {}) {
        if (type === "transition") {
            this._closeAllWithoutTimeout();
        }

        let popupDeferred = this._createDeferred();

        let startCounter = () => {
            if (type === "transition") {
                this._ea.publish("aot:game:counter_start");
            }
        };
        popupDeferred.promise.then(startCounter, startCounter);

        this._popups.push({
            type: type,
            data: data,
            deferred: popupDeferred,
            timeout: timeout,
        });
        // Since services are instantiated first, we need to wait for aot-popup to be attached
        // before trying to display a popup.
        this._popupReadyDeferred.promise.then(() => {
            return this._displayedPopupDeferred.promise.then(
                () => this._displayNext(),
                () => this._displayNext(),
            );
        });

        return popupDeferred.promise;
    }

    _closeAllWithoutTimeout() {
        this._logger.debug("Closing all popups that require user interaction");
        this._popups = this._popups.filter(popup => popup.timeout);
        if (this._displayedPopupData !== null && !this._displayedPopupData.meta.timeout) {
            this._displayedPopupDeferred.reject(new Error("Closed automatically"));
            this._displayedPopupData = null;
        }
    }

    _displayNext() {
        // We check that we have popup to display: if we are in the recursion, this._popups
        // may be an empty array.
        if (this._popups.length === 0 || this._displayedPopupDeferred.pending) {
            return;
        }

        let popup = this._popups.shift();
        this._displayedPopupData = popup.data;
        this._logger.debug("Displaying next popup", JSON.stringify(this._displayedPopupData));
        this._displayedPopupData.meta = {
            timeout: popup.timeout,
        };
        this._translatePopup();

        if (popup.timeout) {
            let closeTimeout = setTimeout(() => {
                this._logger.debug("Hit popup time out, closing", popup.timeout);
                popup.deferred.resolve();
            }, popup.timeout);
            let cancelCloseTimeout = () => {
                clearTimeout(closeTimeout);
            };
            popup.deferred.promise.then(cancelCloseTimeout, cancelCloseTimeout);
        }
        this._logger.debug("Displayed popup is now of type", popup.type);
        this._displayedPopupDeferred = popup.deferred;

        this._ea.publish("aot:popup:display", {
            type: popup.type,
            data: popup.data,
            deferred: popup.deferred,
        });

        // As soon as the current popup is closed, we display the next one.
        this._displayedPopupDeferred.promise.then(
            () => {
                this._displayedPopupData = null;
                this._displayNext();
            },
            () => {
                this._displayedPopupData = null;
                this._displayNext();
            },
        );
    }

    _translatePopup() {
        if (!this._canTranslatePopup()) {
            return;
        }

        let translateData = this._displayedPopupData.translate;
        let params = translateData.params || {};
        this._translateObj(params, translateData.paramsToTranslate);
        this._translateObj(this._displayedPopupData, translateData.messages, params);
        this._translateChoices();
    }

    _canTranslatePopup() {
        return (
            this._displayedPopupData !== null &&
            this._displayedPopupData.translate &&
            this._displayedPopupData.translate.messages
        );
    }

    _translateObj(dest, source, params = {}) {
        for (let key in source) {
            dest[key] = this._i18n.tr(source[key], params);
        }
    }

    _translateChoices() {
        if (!this._displayedPopupData.choices) {
            return;
        }

        this._displayedPopupData.choices = this._displayedPopupData.choices.map(choice => ({
            ...choice,
            name: this._i18n.tr(choice.name),
        }));

        this._translateObj(this._displayedPopupData, this._displayedPopupData.choices);
    }
}
<|endoftext|>


<commit_before>'use strict'
var oShare = require('ftc-share');
oShare.buildAll();

$(function() {

/* variables*/
var $w = $(window);
var pageName = window.location.pathname;
var headerHeight = $('.header').height();
var viewportHeight = $(window).height() - headerHeight;
var $tocNav = $('.nav__toc').eq(0);

//Get the image source of `.story-cover` and put it as the background of `.story-header` so that the picture could flow with resizing while `wechat` could capture this image as thumbnail.
$('.story-cover').css('background-image', function() {
	return 'url(' + $('.cover-image').attr('src') + ')';
});

/* Show/Hide Navigation */
showHideNav($('.small-menu'), $('.nav__toc'));
setHeight($('.text-over-media'), viewportHeight);
backToTop($('.to-top'));

/* Generate navigation and deal with scrolled pagination */
var navLinks = generateNav($('.nav__toc'), $('.nav-target'));

var navTargetTops = getOffsetTop($('.nav-target')).toArray();

var wScrolledTop = $w.scrollTop();
var currentPage = onWhichPage(wScrolledTop, navTargetTops);
var previousPage = currentPage;
activeNavLink(currentPage, navLinks);
logPages(pageName, currentPage);

$w.on('scroll', function() {
	var wScrolledTop = $w.scrollTop();
	var currentPage = onWhichPage(wScrolledTop, navTargetTops);
	if (previousPage !== currentPage) {
		previousPage = currentPage;
		activeNavLink(currentPage, navLinks);
		logPages(pageName, currentPage);
	}
});

});

function activeNavLink(currentPage, navLinks) {
	var currentNavLink = navLinks[currentPage - 1];
	currentNavLink.addClass('active');
	currentNavLink.siblings().removeClass('active');
}

function onWhichPage(x, arr) {
//Initially you are on the page 1.
	var j = 1;
	for (var i = 0; i < arr.length; i++) {
// If x > arr[i], you are on the page i+1.
		if (x >= arr[i]) {
			j = i+1;
		}
	}
	return j;
}

function logPages(pageName, pageNumber) {
	try {
	  ga('send', 'pageview', pageName + '?page=' + pageNumber);
	  fa('send', 'pageview', pageName + '?page=' + pageNumber);
	  ftcLog();
	} catch (ignore) {

	}
}

function backToTop($elm) {
	$elm.on('click', function(e){
		e.preventDefault();
		$(window).scrollTo(0, 1000);
	});
}

function setHeight($elms, height) {
	$elms.each(function() {
		$(this).height(height);
	});
}

function getOffsetTop($elms) {
	return $elms.map(function() {
		return /*var offsetTop =*/ $(this).offset().top;
	});
}

function generateNav($navContainer, $navTargets) {
	var navLinks = [];
	$navTargets.each(function(i) {
		var targetId = $(this).attr('id');
		var link = $('<a/>', {
			'href': '#' + targetId,
			'click': function(e) {
				e.preventDefault();
				$(window).scrollTo(document.getElementById(targetId), 300);
				$(e.target).addClass('active');
				$(e.target).siblings().removeClass('active');
			}
		}).text(i+1);

		$navContainer.append(link);
		navLinks.push(link);
	});
	return navLinks;
}

function showHideNav($elm, $navContainer) {
	$('body').on('load click touch', function() {
		$navContainer.addClass('hide-on-small');
	});

	$elm.on('click touch', function(e) {
		$navContainer.toggleClass('hide-on-small');
		e.stopPropagation();
	});
}<commit_msg>change code order<commit_after>'use strict'
var oShare = require('ftc-share');

$(function() {

/* variables*/
var $w = $(window);
var pageName = window.location.pathname;
var headerHeight = $('.header').height();
var viewportHeight = $(window).height() - headerHeight;
var $tocNav = $('.nav__toc').eq(0);

setHeight($('.text-over-media'), viewportHeight);
//Get the image source of `.story-cover` and put it as the background of `.story-header` so that the picture could flow with resizing while `wechat` could capture this image as thumbnail.
$('.story-cover').css('background-image', function() {
	return 'url(' + $('.cover-image').attr('src') + ')';
});

/* Show/Hide Navigation */
showHideNav($('.small-menu'), $('.nav__toc'));

backToTop($('.to-top'));

/* Generate navigation and deal with scrolled pagination */
var navLinks = generateNav($('.nav__toc'), $('.nav-target'));

var navTargetTops = getOffsetTop($('.nav-target')).toArray();

var wScrolledTop = $w.scrollTop();
var currentPage = onWhichPage(wScrolledTop, navTargetTops);
var previousPage = currentPage;
activeNavLink(currentPage, navLinks);
logPages(pageName, currentPage);

$w.on('scroll', function() {
	var wScrolledTop = $w.scrollTop();
	var currentPage = onWhichPage(wScrolledTop, navTargetTops);
	if (previousPage !== currentPage) {
		previousPage = currentPage;
		activeNavLink(currentPage, navLinks);
		logPages(pageName, currentPage);
	}
});

});

function activeNavLink(currentPage, navLinks) {
	var currentNavLink = navLinks[currentPage - 1];
	currentNavLink.addClass('active');
	currentNavLink.siblings().removeClass('active');
}

function onWhichPage(x, arr) {
//Initially you are on the page 1.
	var j = 1;
	for (var i = 0; i < arr.length; i++) {
// If x > arr[i], you are on the page i+1.
		if (x >= arr[i]) {
			j = i+1;
		}
	}
	return j;
}

function logPages(pageName, pageNumber) {
	try {
	  ga('send', 'pageview', pageName + '?page=' + pageNumber);
	  fa('send', 'pageview', pageName + '?page=' + pageNumber);
	  ftcLog();
	} catch (ignore) {

	}
}

function backToTop($elm) {
	$elm.on('click', function(e){
		e.preventDefault();
		$(window).scrollTo(0, 1000);
	});
}

function setHeight($elms, height) {
	$elms.each(function() {
		$(this).height(height);
	});
}

function getOffsetTop($elms) {
	return $elms.map(function() {
		return /*var offsetTop =*/ $(this).offset().top;
	});
}

function generateNav($navContainer, $navTargets) {
	var navLinks = [];
	$navTargets.each(function(i) {
		var targetId = $(this).attr('id');
		var link = $('<a/>', {
			'href': '#' + targetId,
			'click': function(e) {
				e.preventDefault();
				$(window).scrollTo(document.getElementById(targetId), 300);
				$(e.target).addClass('active');
				$(e.target).siblings().removeClass('active');
			}
		}).text(i+1);

		$navContainer.append(link);
		navLinks.push(link);
	});
	return navLinks;
}

function showHideNav($elm, $navContainer) {
	$('body').on('load click touch', function() {
		$navContainer.addClass('hide-on-small');
	});

	$elm.on('click touch', function(e) {
		$navContainer.toggleClass('hide-on-small');
		e.stopPropagation();
	});
}

oShare.buildAll();<|endoftext|>


<commit_before>var $ = require("lib").$;
var Backbone = require("lib").Backbone;
var _ = require("lib")._;

var Utils = require("./app/base/js/utils");
var models = require("models");
var UserModel = models.UserModel;

var UserStatus = require("./app/user/js/user-status.jsx");
var ProgressBar = require("top-progress-bar");

var Quiz = require("./app/quiz/js/api");
var Concept = require("./app/concept/js/api");
var Course = require("./app/course/js/api");
var CodeQuiz = require("./app/code-quiz/js/api");

var SearchModel = require("./app/search/js/models").SearchModel;
var Search = require("./app/search/js/search.jsx");

require("csrf");

var Router = Backbone.Router.extend({

    initialize: function(options) {
        this.currentComponent = null;
        this.userModel = options.userModel;
        ProgressBar.init();

        Backbone.on("app:notFound", this.notFound, this);
    },

    routes: {
        "creator/concept(/)": "createConcept",
        "creator/concept/:id(/)": "editConcept",
        "creator/concept/concept/:id/change/": "editConcept",
        "creator/markdown-sections(/)": "viewMarkdownSections",
        "creator/course(/)": "createCourse",
        "creator/course/:id(/)": "editCourse",
        "creator/quiz(/)": "createQuiz",
        "creator/quiz/:id(/)": "editQuiz",
        "creator/code-quiz(/)": "createCodeQuiz",
        "creator/code-quiz/:id(/)": "editCodeQuiz",
        "creator/concepts(/)": "listCreatorConcepts",
        "concept/:id(/)": "previewConcept",
        "code-quiz/:id(/)": "attemptCodeQuiz",
        "course/:id(/)": "learnCourse",
        "course/:courseSlug/:conceptSlug(/)": "learnCourseConcept",
        "(/)": "home",
        "just-signed-up(/)": "routeToLastVisitedURL",
        "login(/)": "gotoLogin",
        "logged-out(/)": "showLoggedOut",
        "*path": "notFound"
    },

    previewConcept: function(id) {
        this.resetPage();
        Concept.Preview.render({id: id}, this.pageElement);
        this.currentComponent = Concept.Preview;
    },

    createConcept: function() {
        this.resetPage();
        Concept.Creator.render({id: null}, this.pageElement);
        this.currentComponent = Concept.Creator;
    },

    editConcept: function(id) {
        this.resetPage();
        Concept.Creator.render({id: id}, this.pageElement);
        this.currentComponent = Concept.Creator;
    },

    listCreatorConcepts: function() {
        this.resetPage();
        Concept.CreatorList.render({}, this.pageElement);
        this.currentComponent = Concept.CreatorList;
    },

    viewMarkdownSections: function() {
        this.resetPage();
        Concept.CreatorMarkdown.render({}, this.pageElement);
        this.currentComponent = Concept.CreatorMarkdown;
    },

    createCourse: function() {
        this._showCourse({});
    },

    editCourse: function(id) {
        this._showCourse({id: id});
    },

    _showCourse: function(options) {
        this.resetPage();
        Course.Creator.render(options, this.pageElement);
        this.currentComponent = Course.Creator;
    },

    learnCourse: function(id) {
        this.resetPage();
        Course.Student.render({id: id}, this.pageElement);
        this.currentComponent = Course.Student;
    },

    learnCourseConcept: function(courseSlug, conceptSlug) {
        this.resetPage();
        Course.CourseConcept.render({
            courseSlug: courseSlug,
            conceptSlug: conceptSlug
        }, this.pageElement);
        this.currentComponent = Course.CourseConcept;
    },

    createCodeQuiz: function() {
        this._showCodeQuiz({
            id: null
        });
    },

    editCodeQuiz: function(id) {
        this._showCodeQuiz({
            id: id
        });
    },

    _showCodeQuiz: function(options) {
        this.resetPage();
        CodeQuiz.Creator.render(options, this.pageElement);
        this.currentComponent = CodeQuiz.Creator;
    },

    attemptCodeQuiz: function(id) {
        this.resetPage();
        CodeQuiz.Student.render({
            id: id
        }, this.pageElement);
        this.currentComponent = CodeQuiz.Student;
    },

    authRequiredRoutes: ['creator'],

    gotoLogin: function() {
        window.location.href = "/admin";
    },

    showLoggedOut: function() {
        this.resetPage();
        var url = "https://youtu.be/uCg2BoKiuOM?t=84"
        var a = $("<a>").html("Have a nice day!").attr("href", url);
        var h5 = $("<h5>").html("You are logged out. ").append(a).css({
            "margin-top": "3%",
            "text-align": "center"
        });
        $(this.pageElement).append(h5);
        this.currentComponent = this;
    },

    routeToLastVisitedURL: function() {
        url = localStorage.getItem("lastVisitedURL");
        localStorage.removeItem("lastVisitedURL");
        Backbone.history.navigate(url, {trigger: true});
    },

    createQuiz: function() {
        this.resetPage();
        Quiz.render(this.pageElement, {quizId: null});
        this.currentComponent = Quiz;
    },

    editQuiz: function(id) {
        this.resetPage();
        Quiz.render(this.pageElement, {id: id});
        this.currentComponent = Quiz;
    },

    resetPage: function() {
        ProgressBar.reset();
        if(this.currentComponent !== null) {
            this.currentComponent.unmount(this.pageElement);
            this.pageElement.remove();
        }
        var page = document.createElement("div");
        page.setAttribute("id", "page-content");
        page.setAttribute("class", "container");
        //this.renderLoading(page);
        var pageFull = document.getElementById("page-full");
        pageFull.appendChild(page);
        this.pageElement = page;
    },

    renderLoading: function(page) {
        var progress = $("<div>").addClass("progress");
        var child = $("<div>").addClass("indeterminate");
        progress.append(child);
        $(page).append(progress);
    },

    home: function() {
        this.resetPage();
        this.currentComponent = null;
        Backbone.history.navigate("course/python-tutorial/", {trigger: true});
    },

    notFound: function() {
        this.resetPage();
        var h4 = $("<h4>").html("Oops. Page Not found.").css({
            "margin-top": "3%",
            "text-align": "center"
        });
        $(this.pageElement).append(h4);
        this.currentComponent = this;
    },

    unmount: function() {
        this.pageElement.remove();
    },

    execute: function(callback, args, name) {
        if(this.isAuthRequired() && !this.userModel.isAuthenticated()) {
            this.gotoLogin();
            return false;
            //Backbone.history.navigate("login", {trigger: true});
            //return false;
        }

        if(callback) {
            callback.apply(this, args);
            var frag = utils.addTrailingSlash(Backbone.history.getFragment());
            Backbone.history.navigate(frag, {trigger: false});
        }
    },

    isAuthRequired: function() {
        var frag = Backbone.history.getFragment();
        var matched = _.filter(this.authRequiredRoutes, function(r) {
            return frag.indexOf(r) !== -1;
        });
        return matched.length > 0;
    }

});

var triggerResize = function() {
    Backbone.trigger("window:resize");
};

triggerResize = _.debounce(triggerResize, 500);

var listenToResize = function() {
    //$(window).resize(triggerResize);
};

var init = function() {

    var userModel = new UserModel();
    userModel.fetch().then(function() {

        var searchModel = new SearchModel(userModel.toJSON().ALGOLIA);
        window.s = searchModel;
        Search.render(searchModel, {
            searchBar: document.getElementById("search-bar"),
            searchHits: document.getElementById("search-hits-container")
        });

        UserStatus.render(userModel, document.getElementById("user-status"));
        var router = new Router({userModel: userModel});
        Backbone.history.start({pushState: true});
        console.log(userModel.toJSON());

    });

    listenToResize();

};

// 3 -> 2 -> 1: 🔥
$(document).ready(init);
<commit_msg>Client Routing: Fix typo in 404 message.<commit_after>var $ = require("lib").$;
var Backbone = require("lib").Backbone;
var _ = require("lib")._;

var Utils = require("./app/base/js/utils");
var models = require("models");
var UserModel = models.UserModel;

var UserStatus = require("./app/user/js/user-status.jsx");
var ProgressBar = require("top-progress-bar");

var Quiz = require("./app/quiz/js/api");
var Concept = require("./app/concept/js/api");
var Course = require("./app/course/js/api");
var CodeQuiz = require("./app/code-quiz/js/api");

var SearchModel = require("./app/search/js/models").SearchModel;
var Search = require("./app/search/js/search.jsx");

require("csrf");

var Router = Backbone.Router.extend({

    initialize: function(options) {
        this.currentComponent = null;
        this.userModel = options.userModel;
        ProgressBar.init();

        Backbone.on("app:notFound", this.notFound, this);
    },

    routes: {
        "creator/concept(/)": "createConcept",
        "creator/concept/:id(/)": "editConcept",
        "creator/concept/concept/:id/change/": "editConcept",
        "creator/markdown-sections(/)": "viewMarkdownSections",
        "creator/course(/)": "createCourse",
        "creator/course/:id(/)": "editCourse",
        "creator/quiz(/)": "createQuiz",
        "creator/quiz/:id(/)": "editQuiz",
        "creator/code-quiz(/)": "createCodeQuiz",
        "creator/code-quiz/:id(/)": "editCodeQuiz",
        "creator/concepts(/)": "listCreatorConcepts",
        "concept/:id(/)": "previewConcept",
        "code-quiz/:id(/)": "attemptCodeQuiz",
        "course/:id(/)": "learnCourse",
        "course/:courseSlug/:conceptSlug(/)": "learnCourseConcept",
        "(/)": "home",
        "just-signed-up(/)": "routeToLastVisitedURL",
        "login(/)": "gotoLogin",
        "logged-out(/)": "showLoggedOut",
        "*path": "notFound"
    },

    previewConcept: function(id) {
        this.resetPage();
        Concept.Preview.render({id: id}, this.pageElement);
        this.currentComponent = Concept.Preview;
    },

    createConcept: function() {
        this.resetPage();
        Concept.Creator.render({id: null}, this.pageElement);
        this.currentComponent = Concept.Creator;
    },

    editConcept: function(id) {
        this.resetPage();
        Concept.Creator.render({id: id}, this.pageElement);
        this.currentComponent = Concept.Creator;
    },

    listCreatorConcepts: function() {
        this.resetPage();
        Concept.CreatorList.render({}, this.pageElement);
        this.currentComponent = Concept.CreatorList;
    },

    viewMarkdownSections: function() {
        this.resetPage();
        Concept.CreatorMarkdown.render({}, this.pageElement);
        this.currentComponent = Concept.CreatorMarkdown;
    },

    createCourse: function() {
        this._showCourse({});
    },

    editCourse: function(id) {
        this._showCourse({id: id});
    },

    _showCourse: function(options) {
        this.resetPage();
        Course.Creator.render(options, this.pageElement);
        this.currentComponent = Course.Creator;
    },

    learnCourse: function(id) {
        this.resetPage();
        Course.Student.render({id: id}, this.pageElement);
        this.currentComponent = Course.Student;
    },

    learnCourseConcept: function(courseSlug, conceptSlug) {
        this.resetPage();
        Course.CourseConcept.render({
            courseSlug: courseSlug,
            conceptSlug: conceptSlug
        }, this.pageElement);
        this.currentComponent = Course.CourseConcept;
    },

    createCodeQuiz: function() {
        this._showCodeQuiz({
            id: null
        });
    },

    editCodeQuiz: function(id) {
        this._showCodeQuiz({
            id: id
        });
    },

    _showCodeQuiz: function(options) {
        this.resetPage();
        CodeQuiz.Creator.render(options, this.pageElement);
        this.currentComponent = CodeQuiz.Creator;
    },

    attemptCodeQuiz: function(id) {
        this.resetPage();
        CodeQuiz.Student.render({
            id: id
        }, this.pageElement);
        this.currentComponent = CodeQuiz.Student;
    },

    authRequiredRoutes: ['creator'],

    gotoLogin: function() {
        window.location.href = "/admin";
    },

    showLoggedOut: function() {
        this.resetPage();
        var url = "https://youtu.be/uCg2BoKiuOM?t=84"
        var a = $("<a>").html("Have a nice day!").attr("href", url);
        var h5 = $("<h5>").html("You are logged out. ").append(a).css({
            "margin-top": "3%",
            "text-align": "center"
        });
        $(this.pageElement).append(h5);
        this.currentComponent = this;
    },

    routeToLastVisitedURL: function() {
        url = localStorage.getItem("lastVisitedURL");
        localStorage.removeItem("lastVisitedURL");
        Backbone.history.navigate(url, {trigger: true});
    },

    createQuiz: function() {
        this.resetPage();
        Quiz.render(this.pageElement, {quizId: null});
        this.currentComponent = Quiz;
    },

    editQuiz: function(id) {
        this.resetPage();
        Quiz.render(this.pageElement, {id: id});
        this.currentComponent = Quiz;
    },

    resetPage: function() {
        ProgressBar.reset();
        if(this.currentComponent !== null) {
            this.currentComponent.unmount(this.pageElement);
            this.pageElement.remove();
        }
        var page = document.createElement("div");
        page.setAttribute("id", "page-content");
        page.setAttribute("class", "container");
        //this.renderLoading(page);
        var pageFull = document.getElementById("page-full");
        pageFull.appendChild(page);
        this.pageElement = page;
    },

    renderLoading: function(page) {
        var progress = $("<div>").addClass("progress");
        var child = $("<div>").addClass("indeterminate");
        progress.append(child);
        $(page).append(progress);
    },

    home: function() {
        this.resetPage();
        this.currentComponent = null;
        Backbone.history.navigate("course/python-tutorial/", {trigger: true});
    },

    notFound: function() {
        this.resetPage();
        var h4 = $("<h4>").html("Oops... Page Not found.").css({
            "margin-top": "3%",
            "text-align": "center"
        });
        $(this.pageElement).append(h4);
        this.currentComponent = this;
    },

    unmount: function() {
        this.pageElement.remove();
    },

    execute: function(callback, args, name) {
        if(this.isAuthRequired() && !this.userModel.isAuthenticated()) {
            this.gotoLogin();
            return false;
            //Backbone.history.navigate("login", {trigger: true});
            //return false;
        }

        if(callback) {
            callback.apply(this, args);
            var frag = utils.addTrailingSlash(Backbone.history.getFragment());
            Backbone.history.navigate(frag, {trigger: false});
        }
    },

    isAuthRequired: function() {
        var frag = Backbone.history.getFragment();
        var matched = _.filter(this.authRequiredRoutes, function(r) {
            return frag.indexOf(r) !== -1;
        });
        return matched.length > 0;
    }

});

var triggerResize = function() {
    Backbone.trigger("window:resize");
};

triggerResize = _.debounce(triggerResize, 500);

var listenToResize = function() {
    $(window).resize(triggerResize);
};

var init = function() {

    var userModel = new UserModel();
    userModel.fetch().then(function() {

        var searchModel = new SearchModel(userModel.toJSON().ALGOLIA);
        window.s = searchModel;
        Search.render(searchModel, {
            searchBar: document.getElementById("search-bar"),
            searchHits: document.getElementById("search-hits-container")
        });

        UserStatus.render(userModel, document.getElementById("user-status"));
        var router = new Router({userModel: userModel});
        Backbone.history.start({pushState: true});
        console.log(userModel.toJSON());

    });

    listenToResize();

};

// 3 -> 2 -> 1: 🔥
$(document).ready(init);
<|endoftext|>


<commit_before>var isGithubDemo = isGithubDemo || false;

void function(window, document, undefined) {

  // ES5 strict mode
  "user strict";

  var MIN_COLUMN_COUNT = 3; // minimal column count
  var COLUMN_WIDTH = 220;   // cell width: 190, padding: 14 * 2, border: 1 * 2
  var GAP_HEIGHT = 15;      // vertical gap between cells
  var GAP_WIDTH = 15;       // horizontal gap between cells

  var columnHeights;        // array of every column's height
  var columnCount;          // number of columns
  var delayer;              // resize throttle timer
  var noticer;              // popup notice timer
  var loading = false;      // flag for loading state

  var noticeTag = document.getElementById('notice');
  var cellsContainer = document.getElementById('container');
  var cellTemplate = document.getElementById('template').innerHTML;

  // Cross-browser compatible event handler.
  var addEvent = function(element, type, handler) {
    if(element.addEventListener) {
      addEvent = function(element, type, handler) {
        element.addEventListener(type, handler, false);
      };
    } else if(element.attachEvent) {
      addEvent = function(element, type, handler) {
        element.attachEvent('on' + type, handler);
      };
    } else {
      addEvent = function(element, type, handler) {
        element['on' + type] = handler;
      };
    }
    addEvent(element, type, handler);
  };

  // Get the minimal value within an array of numbers.
  var getMinVal = function(arr) {
    return Math.min.apply(Math, arr);
  };

  // Get the maximal value within an array of numbers.
  var getMaxVal = function(arr) {
    return Math.max.apply(Math, arr);
  };

  // Get index of the minimal value within an array of numbers.
  var getMinKey = function(arr) {
    var key = 0;
    var min = arr[0];
    for(var i = 1, len = arr.length; i < len; i++) {
      if(arr[i] < min) {
        key = i;
        min = arr[i];
      }
    }
    return key;
  };

  // Get index of the maximal value within an array of numbers.
  var getMaxKey = function(arr) {
    var key = 0;
    var max = arr[0];
    for(var i = 1, len = arr.length; i < len; i++) {
      if(arr[i] > max) {
        key = i;
        max = arr[i];
      }
    }
    return key;
  };

  // Calculate column count from current page width.
  var getColumnCount = function() {
    return Math.max(MIN_COLUMN_COUNT, Math.floor((document.body.offsetWidth + GAP_WIDTH) / (COLUMN_WIDTH + GAP_WIDTH)));
  };

  // Pop notice tag after user liked or marked an item.
  var updateNotice = function(event) {
    clearTimeout(noticer);
    var e = event || window.event;
    var target = e.target || e.srcElement;
    if(target.tagName == 'SPAN') {
      var targetTitle = target.parentNode.dataset.title;
      noticeTag.innerHTML = (target.className == 'like' ? 'Liked ' : 'Marked ') + '' + targetTitle + '';
      noticeTag.className = 'on';
      noticer = setTimeout(function() {
        noticeTag.className = 'off';
      }, 2000);
    }
  };

  // Position the newly appended cells and update array of column heights.
  var adjustCells = function(cells) {
    var columnIndex;
    var columnHeight;
    for(var j = 0, k = cells.length; j < k; j++) {
      // Append the cell to column with the minimal height.
      columnIndex = getMinKey(columnHeights);
      columnHeight = columnHeights[columnIndex];
      cells[j].style.left = columnIndex * (COLUMN_WIDTH + GAP_WIDTH) + 'px';
      cells[j].style.top = columnHeight + 'px';
      columnHeights[columnIndex] = columnHeight + GAP_HEIGHT + cells[j].offsetHeight;
      cells[j].className = 'cell ready';
    }
    cellsContainer.style.height = getMaxVal(columnHeights) + 'px';
    loadCells();
  };

  // Fetch JSON string via Ajax, parse to HTML and append to the container.
  var appendCells = function(num) {
    if(loading) {
      return;
    }
    var xhrRequest = new XMLHttpRequest();
    var fragment = document.createDocumentFragment();
    var cells = [];
    var images;
    xhrRequest.open('GET', 'json.php?n=' + num, true);
    xhrRequest.onreadystatechange = function() {
      if(xhrRequest.readyState == 4 && xhrRequest.status == 200) {
        images = JSON.parse(xhrRequest.responseText);
        for(var j = 0, k = images.length; j < k; j++) {
          var cell = document.createElement('div');
          cell.className = 'cell';
          cell.dataset = {};  // stupid IE
          cell.dataset.title = images[j][s];
          cells.push(cell);
          front(cellTemplate, images[j], cell);
          fragment.appendChild(cell);
        }
        cellsContainer.appendChild(fragment);
        loading = false;
        adjustCells(cells);
      }
    };
    loading = true;
    xhrRequest.send(null);
  };

  // Fake mode, only for GH demo
  var appendCellsDemo = function(num) {
    var fragment = document.createDocumentFragment();
    var cells = [];
    var images = [286, 143, 270, 143, 190, 285, 152, 275, 285, 285, 128, 281, 242, 339, 236, 157, 286, 259, 267, 137, 253, 127, 190, 190, 225, 269, 264, 272, 126, 265, 287, 269, 125, 285, 190, 314, 141, 119, 274, 274, 285, 126, 279, 143, 266, 279, 600, 276, 285, 182, 143, 287, 126, 190, 285, 143, 241, 166, 240, 190];
    for(var j = 0; j < num; j++) {
      var key = Math.floor(Math.random() * 60) + 1;
      var cell = document.createElement('div');
      cell.className = 'cell';
      cell.dataset = {};  // stupid IE
      cell.dataset.title = key;
      cells.push(cell);
      front(cellTemplate, { s: key, h: images[key], w: 190 }, cell);
      fragment.appendChild(cell);
    }
    cellsContainer.appendChild(fragment);
    adjustCells(cells);
  };

  // Calculate new column data if it's necessary after resize.
  var reflowCells = function() {
    // Calculate new column count after resize.
    columnCount = getColumnCount();
    if(columnHeights.length != columnCount) {
      columnHeights = [];
      cellsContainer.style.width = (columnCount * (COLUMN_WIDTH + GAP_WIDTH) - GAP_WIDTH) + 'px';
      for(var i = 0; i < columnCount; i++) {
        columnHeights.push(GAP_HEIGHT);
      }
      adjustCells(cellsContainer.children);
    } else {
      loadCells();
    }
  };

  // Load and append new cells if container is scrolled to the bottom.
  var loadCells = function() {
    var verticalOffset = (window.innerHeight || document.documentElement.clientHeight) + (document.body.scrollTop || document.documentElement.scrollTop);
    if(verticalOffset > getMinVal(columnHeights)) {
      if(isGithubDemo) {
        appendCellsDemo(columnCount);
      } else {
        appendCells(columnCount);
      }
    }
  };

  // Add 500ms throttle to window resize.
  var delayedReflow = function() {
    clearTimeout(delayer);
    delayer = setTimeout(reflowCells, 500);
  };

  // Initialize the layout.
  var init = function() {
    columnHeights = [];
    columnCount = getColumnCount();
    cellsContainer.style.width = (columnCount * (COLUMN_WIDTH + GAP_WIDTH) - GAP_WIDTH) + 'px';
    for(var i = 0; i < columnCount; i++) {
      columnHeights.push(GAP_HEIGHT);
    }
    loadCells();
  };

  addEvent(cellsContainer, 'click', updateNotice);
  addEvent(window, 'scroll', loadCells);
  addEvent(window, 'resize', delayedReflow);
  addEvent(window, 'load', init);

}(window, document);<commit_msg>fix fake data<commit_after>var isGithubDemo = isGithubDemo || false;

void function(window, document, undefined) {

  // ES5 strict mode
  "user strict";

  var MIN_COLUMN_COUNT = 3; // minimal column count
  var COLUMN_WIDTH = 220;   // cell width: 190, padding: 14 * 2, border: 1 * 2
  var GAP_HEIGHT = 15;      // vertical gap between cells
  var GAP_WIDTH = 15;       // horizontal gap between cells

  var columnHeights;        // array of every column's height
  var columnCount;          // number of columns
  var delayer;              // resize throttle timer
  var noticer;              // popup notice timer
  var loading = false;      // flag for loading state

  var noticeTag = document.getElementById('notice');
  var cellsContainer = document.getElementById('container');
  var cellTemplate = document.getElementById('template').innerHTML;

  // Cross-browser compatible event handler.
  var addEvent = function(element, type, handler) {
    if(element.addEventListener) {
      addEvent = function(element, type, handler) {
        element.addEventListener(type, handler, false);
      };
    } else if(element.attachEvent) {
      addEvent = function(element, type, handler) {
        element.attachEvent('on' + type, handler);
      };
    } else {
      addEvent = function(element, type, handler) {
        element['on' + type] = handler;
      };
    }
    addEvent(element, type, handler);
  };

  // Get the minimal value within an array of numbers.
  var getMinVal = function(arr) {
    return Math.min.apply(Math, arr);
  };

  // Get the maximal value within an array of numbers.
  var getMaxVal = function(arr) {
    return Math.max.apply(Math, arr);
  };

  // Get index of the minimal value within an array of numbers.
  var getMinKey = function(arr) {
    var key = 0;
    var min = arr[0];
    for(var i = 1, len = arr.length; i < len; i++) {
      if(arr[i] < min) {
        key = i;
        min = arr[i];
      }
    }
    return key;
  };

  // Get index of the maximal value within an array of numbers.
  var getMaxKey = function(arr) {
    var key = 0;
    var max = arr[0];
    for(var i = 1, len = arr.length; i < len; i++) {
      if(arr[i] > max) {
        key = i;
        max = arr[i];
      }
    }
    return key;
  };

  // Calculate column count from current page width.
  var getColumnCount = function() {
    return Math.max(MIN_COLUMN_COUNT, Math.floor((document.body.offsetWidth + GAP_WIDTH) / (COLUMN_WIDTH + GAP_WIDTH)));
  };

  // Pop notice tag after user liked or marked an item.
  var updateNotice = function(event) {
    clearTimeout(noticer);
    var e = event || window.event;
    var target = e.target || e.srcElement;
    if(target.tagName == 'SPAN') {
      var targetTitle = target.parentNode.dataset.title;
      noticeTag.innerHTML = (target.className == 'like' ? 'Liked ' : 'Marked ') + '' + targetTitle + '';
      noticeTag.className = 'on';
      noticer = setTimeout(function() {
        noticeTag.className = 'off';
      }, 2000);
    }
  };

  // Position the newly appended cells and update array of column heights.
  var adjustCells = function(cells) {
    var columnIndex;
    var columnHeight;
    for(var j = 0, k = cells.length; j < k; j++) {
      // Append the cell to column with the minimal height.
      columnIndex = getMinKey(columnHeights);
      columnHeight = columnHeights[columnIndex];
      cells[j].style.left = columnIndex * (COLUMN_WIDTH + GAP_WIDTH) + 'px';
      cells[j].style.top = columnHeight + 'px';
      columnHeights[columnIndex] = columnHeight + GAP_HEIGHT + cells[j].offsetHeight;
      cells[j].className = 'cell ready';
    }
    cellsContainer.style.height = getMaxVal(columnHeights) + 'px';
    loadCells();
  };

  // Fetch JSON string via Ajax, parse to HTML and append to the container.
  var appendCells = function(num) {
    if(loading) {
      return;
    }
    var xhrRequest = new XMLHttpRequest();
    var fragment = document.createDocumentFragment();
    var cells = [];
    var images;
    xhrRequest.open('GET', 'json.php?n=' + num, true);
    xhrRequest.onreadystatechange = function() {
      if(xhrRequest.readyState == 4 && xhrRequest.status == 200) {
        images = JSON.parse(xhrRequest.responseText);
        for(var j = 0, k = images.length; j < k; j++) {
          var cell = document.createElement('div');
          cell.className = 'cell';
          cell.dataset = {};  // stupid IE
          cell.dataset.title = images[j][s];
          cells.push(cell);
          front(cellTemplate, images[j], cell);
          fragment.appendChild(cell);
        }
        cellsContainer.appendChild(fragment);
        loading = false;
        adjustCells(cells);
      }
    };
    loading = true;
    xhrRequest.send(null);
  };

  // Fake mode, only for GH demo
  var appendCellsDemo = function(num) {
    var fragment = document.createDocumentFragment();
    var cells = [];
    var images = [0, 286, 143, 270, 143, 190, 285, 152, 275, 285, 285, 128, 281, 242, 339, 236, 157, 286, 259, 267, 137, 253, 127, 190, 190, 225, 269, 264, 272, 126, 265, 287, 269, 125, 285, 190, 314, 141, 119, 274, 274, 285, 126, 279, 143, 266, 279, 600, 276, 285, 182, 143, 287, 126, 190, 285, 143, 241, 166, 240, 190];
    for(var j = 0; j < num; j++) {
      var key = Math.floor(Math.random() * 60) + 1;
      var cell = document.createElement('div');
      cell.className = 'cell';
      cell.dataset = {};  // stupid IE
      cell.dataset.title = key;
      cells.push(cell);
      front(cellTemplate, { s: key, h: images[key], w: 190 }, cell);
      fragment.appendChild(cell);
    }
    cellsContainer.appendChild(fragment);
    adjustCells(cells);
  };

  // Calculate new column data if it's necessary after resize.
  var reflowCells = function() {
    // Calculate new column count after resize.
    columnCount = getColumnCount();
    if(columnHeights.length != columnCount) {
      columnHeights = [];
      cellsContainer.style.width = (columnCount * (COLUMN_WIDTH + GAP_WIDTH) - GAP_WIDTH) + 'px';
      for(var i = 0; i < columnCount; i++) {
        columnHeights.push(GAP_HEIGHT);
      }
      adjustCells(cellsContainer.children);
    } else {
      loadCells();
    }
  };

  // Load and append new cells if container is scrolled to the bottom.
  var loadCells = function() {
    var verticalOffset = (window.innerHeight || document.documentElement.clientHeight) + (document.body.scrollTop || document.documentElement.scrollTop);
    if(verticalOffset > getMinVal(columnHeights)) {
      if(isGithubDemo) {
        appendCellsDemo(columnCount);
      } else {
        appendCells(columnCount);
      }
    }
  };

  // Add 500ms throttle to window resize.
  var delayedReflow = function() {
    clearTimeout(delayer);
    delayer = setTimeout(reflowCells, 500);
  };

  // Initialize the layout.
  var init = function() {
    columnHeights = [];
    columnCount = getColumnCount();
    cellsContainer.style.width = (columnCount * (COLUMN_WIDTH + GAP_WIDTH) - GAP_WIDTH) + 'px';
    for(var i = 0; i < columnCount; i++) {
      columnHeights.push(GAP_HEIGHT);
    }
    loadCells();
  };

  addEvent(cellsContainer, 'click', updateNotice);
  addEvent(window, 'scroll', loadCells);
  addEvent(window, 'resize', delayedReflow);
  addEvent(window, 'load', init);

}(window, document);<|endoftext|>