<commit_before>import rootRef from '../libs/firebase';
import { v4rootRef } from '../libs/firebase';
import _ from 'lodash';

const C = require('../constants').default;

const sessionsRef = rootRef.child('savedSessions');
const v4sessionsRef = v4rootRef.child('connectSessions');
let allQuestions = {};
let questionsInitialized = {};

export default {
  get(sessionID, cb) {
    // First attempt to get the new normalized session object for this ID
    v4sessionsRef.child(sessionID).once('value', (snapshot) => {
      if (snapshot.exists()) {
        const v4session = denormalizeSession(snapshot.val());
        handleSessionSnapshot(v4session, cb);
      } else {
        // If we can't find a new style session, look for an old one
        sessionsRef.child(sessionID).once('value', (snapshot) => {
          if (snapshot.exists()) {
            const v2session = snapshot.val();
            handleSessionSnapshot(v2session, cb);
          }
        });
      }
    });
  },

  update(sessionID, session) {
    const cleanSession = _.pickBy(session);
    const cleanedSession = JSON.parse(JSON.stringify(cleanSession));
    delete_null_properties(cleanedSession, true);

    // During our rollout, we want to limit the number of people this
    // could impact if things go wrong.  So we're only going to apply
    // this new process to a small percentage of sessions.  This does
    // mean that a single user could get a mix of session types in the
    // same day, but since sessions will be invisible if they work,
    // that shouldn't matter.

    // This is the whole number percentage of users who will be assigned
    // to the new session type.
    const percentAssigned = 10;
    if (sessionID && simpleHash(sessionID) % 100 < percentAssigned) {
      const normalizedSession = normalizeSession(cleanedSession)
      // Let's start including an updated time on our sessions
      normalizedSession.updatedAt = new Date().getTime();
      v4sessionsRef.child(sessionID).set(normalizedSession);
    } else {
      sessionsRef.child(sessionID).set(cleanedSession);
    }
  },

  delete(sessionID) {
    // During rollout, let's not delete old sessions so that we can roll back
    //sessionsRef.child(sessionID).remove();
    v4sessionsRef.child(sessionID).remove();
  },

  populateQuestions(questionType, questions, forceRefresh) {
    if (questionsInitialized[questionType] && !forceRefresh) return;

    Object.keys(questions).forEach((uid) => {
      allQuestions[uid] = {
        question: Object.assign(questions[uid], {key: uid}),
        type: questionType,
      }
    })
    questionsInitialized[questionType] = true;
  }

};

function simpleHash(str) {
  // NOTE: This entire function is lifted from the "string-hash" module
  // on NPM, but I didn't want to add a new dependency for temporary code
  // so I simply re-implemented it here.
  // Source: https://github.com/darkskyapp/string-hash/blob/master/index.js
  var hash = 5381,
      i    = str.length;

  while(i) {
    hash = (hash * 33) ^ str.charCodeAt(--i);
  }

  /* JavaScript does bitwise operations (like XOR, above) on 32-bit signed
   * integers. Since we want the results to be always positive, convert the
   * signed int to an unsigned by doing an unsigned bitshift. */
  return hash >>> 0;
}

function denormalizeSession(session) {
  // If someone has answered no questions, this key will be missing
  if (session.answeredQuestions) {
    session.answeredQuestions.forEach((value, index, answeredQuestions) => {
      answeredQuestions[index] = denormalizeQuestion(value);
    });
  }
  session.questionSet.forEach((value, index, questionSet) => {
    questionSet[index] = denormalizeQuestion(value);
  });
  // If all questions are answered, we won't have this key
  if (session.unansweredQuestions) {
    session.unansweredQuestions.forEach((value, index, unansweredQuestions) => {
      unansweredQuestions[index] = denormalizeQuestion(value);
    });
  }
  if (session.currentQuestion) {
    session.currentQuestion = denormalizeQuestion(session.currentQuestion);
  }
  return session
}

function denormalizeQuestion(question) {
  // Questions stored on the session object have a different shape
  // if they have any attempt data attached to them
  const questionUid = question.attempts ? question.question : question;
  // We need to make sure that the 'question' part of the
  // question object is a clean copy so that we can modify
  // it without changing the cached question object
  const denormalizedQuestion = JSON.parse(JSON.stringify(allQuestions[questionUid].question))
  const questionType = allQuestions[questionUid].type;
  if (question.attempts) {
    denormalizedQuestion.attempts = question.attempts;
  }
  return {
    question: denormalizedQuestion,
    type: questionType,
  }
}

function normalizeSession(session) {
  // Deep copy so that we return a clean object
  let sessionCopy = JSON.parse(JSON.stringify(session));
  sessionCopy.questionSet = sessionCopy.questionSet.map(normalizeQuestion);
  // If someone has answered all the questions, key will be missing
  if (sessionCopy.unansweredQuestions) {
    sessionCopy.unansweredQuestions = sessionCopy.unansweredQuestions.map(normalizeQuestion);
  }
  if (sessionCopy.currentQuestion) {
    sessionCopy.currentQuestion = normalizeQuestion(sessionCopy.currentQuestion);
  }
  // If someone has not answered any questions, this key will be missing
  if (sessionCopy.answeredQuestions) {
    sessionCopy.answeredQuestions = sessionCopy.answeredQuestions.map(normalizeQuestion);
  }
  return sessionCopy
}

function normalizeQuestion(question) {
  if (!question.question.attempts) return question.question.key;
  return {
    question: question.question.key,
    attempts: question.question.attempts,
  }
}

function handleSessionSnapshot(session, callback) {
  if (session.currentQuestion) {
    if (session.currentQuestion.question) {
      session.currentQuestion.question.attempts = session.currentQuestion.question.attempts || [];
    } else {
      session.currentQuestion.data.attempts = session.currentQuestion.data.attempts || [];
    }
  }
  session.unansweredQuestions ? true : session.unansweredQuestions = [];
  callback(session);
}

function delete_null_properties(test, recurse) {
  for (const i in test) {
    if (test[i] === null) {
      delete test[i];
    } else if (recurse && typeof test[i] === 'object') {
      delete_null_properties(test[i], recurse);
    }
  }
}

export {
  denormalizeSession,
  normalizeSession,
  allQuestions,
}
<commit_msg>Increase the percentage of sessions getting new style sessions<commit_after>import rootRef from '../libs/firebase';
import { v4rootRef } from '../libs/firebase';
import _ from 'lodash';

const C = require('../constants').default;

const sessionsRef = rootRef.child('savedSessions');
const v4sessionsRef = v4rootRef.child('connectSessions');
let allQuestions = {};
let questionsInitialized = {};

export default {
  get(sessionID, cb) {
    // First attempt to get the new normalized session object for this ID
    v4sessionsRef.child(sessionID).once('value', (snapshot) => {
      if (snapshot.exists()) {
        const v4session = denormalizeSession(snapshot.val());
        handleSessionSnapshot(v4session, cb);
      } else {
        // If we can't find a new style session, look for an old one
        sessionsRef.child(sessionID).once('value', (snapshot) => {
          if (snapshot.exists()) {
            const v2session = snapshot.val();
            handleSessionSnapshot(v2session, cb);
          }
        });
      }
    });
  },

  update(sessionID, session) {
    const cleanSession = _.pickBy(session);
    const cleanedSession = JSON.parse(JSON.stringify(cleanSession));
    delete_null_properties(cleanedSession, true);

    // During our rollout, we want to limit the number of people this
    // could impact if things go wrong.  So we're only going to apply
    // this new process to a small percentage of sessions.  This does
    // mean that a single user could get a mix of session types in the
    // same day, but since sessions will be invisible if they work,
    // that shouldn't matter.

    // This is the whole number percentage of users who will be assigned
    // to the new session type.
    const percentAssigned = 50;
    if (sessionID && simpleHash(sessionID) % 100 < percentAssigned) {
      const normalizedSession = normalizeSession(cleanedSession)
      // Let's start including an updated time on our sessions
      normalizedSession.updatedAt = new Date().getTime();
      v4sessionsRef.child(sessionID).set(normalizedSession);
    } else {
      sessionsRef.child(sessionID).set(cleanedSession);
    }
  },

  delete(sessionID) {
    // During rollout, let's not delete old sessions so that we can roll back
    //sessionsRef.child(sessionID).remove();
    v4sessionsRef.child(sessionID).remove();
  },

  populateQuestions(questionType, questions, forceRefresh) {
    if (questionsInitialized[questionType] && !forceRefresh) return;

    Object.keys(questions).forEach((uid) => {
      allQuestions[uid] = {
        question: Object.assign(questions[uid], {key: uid}),
        type: questionType,
      }
    })
    questionsInitialized[questionType] = true;
  }

};

function simpleHash(str) {
  // NOTE: This entire function is lifted from the "string-hash" module
  // on NPM, but I didn't want to add a new dependency for temporary code
  // so I simply re-implemented it here.
  // Source: https://github.com/darkskyapp/string-hash/blob/master/index.js
  var hash = 5381,
      i    = str.length;

  while(i) {
    hash = (hash * 33) ^ str.charCodeAt(--i);
  }

  /* JavaScript does bitwise operations (like XOR, above) on 32-bit signed
   * integers. Since we want the results to be always positive, convert the
   * signed int to an unsigned by doing an unsigned bitshift. */
  return hash >>> 0;
}

function denormalizeSession(session) {
  // If someone has answered no questions, this key will be missing
  if (session.answeredQuestions) {
    session.answeredQuestions.forEach((value, index, answeredQuestions) => {
      answeredQuestions[index] = denormalizeQuestion(value);
    });
  }
  session.questionSet.forEach((value, index, questionSet) => {
    questionSet[index] = denormalizeQuestion(value);
  });
  // If all questions are answered, we won't have this key
  if (session.unansweredQuestions) {
    session.unansweredQuestions.forEach((value, index, unansweredQuestions) => {
      unansweredQuestions[index] = denormalizeQuestion(value);
    });
  }
  if (session.currentQuestion) {
    session.currentQuestion = denormalizeQuestion(session.currentQuestion);
  }
  return session
}

function denormalizeQuestion(question) {
  // Questions stored on the session object have a different shape
  // if they have any attempt data attached to them
  const questionUid = question.attempts ? question.question : question;
  // We need to make sure that the 'question' part of the
  // question object is a clean copy so that we can modify
  // it without changing the cached question object
  const denormalizedQuestion = JSON.parse(JSON.stringify(allQuestions[questionUid].question))
  const questionType = allQuestions[questionUid].type;
  if (question.attempts) {
    denormalizedQuestion.attempts = question.attempts;
  }
  return {
    question: denormalizedQuestion,
    type: questionType,
  }
}

function normalizeSession(session) {
  // Deep copy so that we return a clean object
  let sessionCopy = JSON.parse(JSON.stringify(session));
  sessionCopy.questionSet = sessionCopy.questionSet.map(normalizeQuestion);
  // If someone has answered all the questions, key will be missing
  if (sessionCopy.unansweredQuestions) {
    sessionCopy.unansweredQuestions = sessionCopy.unansweredQuestions.map(normalizeQuestion);
  }
  if (sessionCopy.currentQuestion) {
    sessionCopy.currentQuestion = normalizeQuestion(sessionCopy.currentQuestion);
  }
  // If someone has not answered any questions, this key will be missing
  if (sessionCopy.answeredQuestions) {
    sessionCopy.answeredQuestions = sessionCopy.answeredQuestions.map(normalizeQuestion);
  }
  return sessionCopy
}

function normalizeQuestion(question) {
  if (!question.question.attempts) return question.question.key;
  return {
    question: question.question.key,
    attempts: question.question.attempts,
  }
}

function handleSessionSnapshot(session, callback) {
  if (session.currentQuestion) {
    if (session.currentQuestion.question) {
      session.currentQuestion.question.attempts = session.currentQuestion.question.attempts || [];
    } else {
      session.currentQuestion.data.attempts = session.currentQuestion.data.attempts || [];
    }
  }
  session.unansweredQuestions ? true : session.unansweredQuestions = [];
  callback(session);
}

function delete_null_properties(test, recurse) {
  for (const i in test) {
    if (test[i] === null) {
      delete test[i];
    } else if (recurse && typeof test[i] === 'object') {
      delete_null_properties(test[i], recurse);
    }
  }
}

export {
  denormalizeSession,
  normalizeSession,
  allQuestions,
}
<|endoftext|>


<commit_before>'use strict'
var yo = require('yo-yo')
var BN = require('ethereumjs-util').BN

module.exports = {
  formatData: formatData,
  extractData: extractData
}

function formatData (key, data) {
  var style = fontColor(data)
  var keyStyle = data.isProperty ? 'color:#847979' : ''
  if (data.type === 'string') {
    data.self = JSON.stringify(data.self)
  }
  return yo`<label style=${keyStyle}>${key}: <label style=${style}>${data.self}</label><label style='font-style:italic'> ${data.isProperty ? '' : data.type}</label></label>`
}

function extractData (item, parent, key) {
  var ret = {}
  if (item.isProperty) {
    return item
  }
  if (item.type.lastIndexOf(']') === item.type.length - 1) {
    ret.children = (item.value || []).map(function (item, index) {
      return {key: index, value: item}
    })
    ret.children.unshift({
      key: 'length',
      value: {
        self: (new BN(item.length.replace('0x', ''), 16)).toString(10),
        type: 'uint',
        isProperty: true
      }
    })
    ret.isArray = true
    ret.self = parent.isArray ? 'Array' : item.type
  } else if (item.type.indexOf('struct') === 0) {
    ret.children = Object.keys((item.value || {})).map(function (key) {
      return {key: key, value: item.value[key]}
    })
    ret.self = item.type
    ret.isStruct = true
  } else {
    ret.children = []
    ret.self = item.value
    ret.type = item.type
  }
  return ret
}

function fontColor (data) {
  var color = '#124B46'
  if (data.isArray || data.isStruct) {
    color = '#847979'
  } else if (data.type.indexOf('uint') === 0 ||
              data.type.indexOf('int') === 0 ||
              data.type.indexOf('bool') === 0 ||
              data.type.indexOf('enum') === 0) {
    color = '#0F0CE9'
  } else if (data.type === 'string') {
    color = '#E91E0C'
  }
  return 'color:' + color
}

function isArray (type) {
  return type.lastIndexOf(']') === type.length - 1
}

<commit_msg>remove isArray<commit_after>'use strict'
var yo = require('yo-yo')
var BN = require('ethereumjs-util').BN

module.exports = {
  formatData: formatData,
  extractData: extractData
}

function formatData (key, data) {
  var style = fontColor(data)
  var keyStyle = data.isProperty ? 'color:#847979' : ''
  if (data.type === 'string') {
    data.self = JSON.stringify(data.self)
  }
  return yo`<label style=${keyStyle}>${key}: <label style=${style}>${data.self}</label><label style='font-style:italic'> ${data.isProperty ? '' : data.type}</label></label>`
}

function extractData (item, parent, key) {
  var ret = {}
  if (item.isProperty) {
    return item
  }
  if (item.type.lastIndexOf(']') === item.type.length - 1) {
    ret.children = (item.value || []).map(function (item, index) {
      return {key: index, value: item}
    })
    ret.children.unshift({
      key: 'length',
      value: {
        self: (new BN(item.length.replace('0x', ''), 16)).toString(10),
        type: 'uint',
        isProperty: true
      }
    })
    ret.isArray = true
    ret.self = parent.isArray ? 'Array' : item.type
  } else if (item.type.indexOf('struct') === 0) {
    ret.children = Object.keys((item.value || {})).map(function (key) {
      return {key: key, value: item.value[key]}
    })
    ret.self = item.type
    ret.isStruct = true
  } else {
    ret.children = []
    ret.self = item.value
    ret.type = item.type
  }
  return ret
}

function fontColor (data) {
  var color = '#124B46'
  if (data.isArray || data.isStruct) {
    color = '#847979'
  } else if (data.type.indexOf('uint') === 0 ||
              data.type.indexOf('int') === 0 ||
              data.type.indexOf('bool') === 0 ||
              data.type.indexOf('enum') === 0) {
    color = '#0F0CE9'
  } else if (data.type === 'string') {
    color = '#E91E0C'
  }
  return 'color:' + color
}

<|endoftext|>


<commit_before>/* Omega JS Canvas Controls UI Component
 *
 * Copyright (C) 2013 Mohammed Morsi <mo@morsi.org>
 * Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
 */

//= require "ui/canvas/controls_list"

Omega.UI.CanvasControls = function(parameters){
  this.locations_list   = new Omega.UI.CanvasControlsList({  div_id : '#locations_list' });
  this.entities_list    = new Omega.UI.CanvasControlsList({  div_id : '#entities_list'  });
  this.controls         = $('#canvas_controls');
  this.missions_button  = $('#missions_button');
  this.cam_reset        = $('#cam_reset');
  this.toggle_axis      = $('#toggle_axis input')

  /// need handle to canvas to
  /// - set scene
  /// - set camera target
  /// - reset camera
  /// - add/remove axis from canvas
  this.canvas = null;

  $.extend(this, parameters);

  /// TODO sort locations list
};

Omega.UI.CanvasControls.prototype = {
  wire_up : function(){
    var _this = this;

    this.locations_list.component().on('click', 'li',
      function(evnt){
        var item = $(evnt.currentTarget).data('item');
        _this.canvas.set_scene_root(item);
      })

    this.entities_list.component().on('click', 'li',
      function(evnt){
        var item = $(evnt.currentTarget).data('item');
        _this.canvas.set_scene_root(item.solar_system);
        _this.canvas.focus_on(item.location);
        _this.canvas._clicked_entity(item);
      })

    this.missions_button.on('click',
      function(evnt){
        _this._missions_button_click();
      });

    this.cam_reset.on('click',
      function(evnt){
        _this.canvas.reset_cam();
      });

    this.toggle_axis.on('click',
      function(evnt){
        if($(evnt.currentTarget).is(':checked'))
          _this.canvas.add(_this.canvas.axis);
        else
          _this.canvas.remove(_this.canvas.axis);
        _this.canvas.animate();
      });
    this.toggle_axis.attr('checked', false);

    this.locations_list.wire_up();
    this.entities_list.wire_up();
  },

  _missions_button_click : function(){
    var _this = this;
    var node  = this.canvas.page.node;
    Omega.Mission.all(node, function(missions){ _this.canvas.dialog.show_missions_dialog(missions); });
  }
}
<commit_msg>UI: Move camera to entity proximity when selecting via controls<commit_after>/* Omega JS Canvas Controls UI Component
 *
 * Copyright (C) 2013 Mohammed Morsi <mo@morsi.org>
 * Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
 */

//= require "ui/canvas/controls_list"

Omega.UI.CanvasControls = function(parameters){
  this.locations_list   = new Omega.UI.CanvasControlsList({  div_id : '#locations_list' });
  this.entities_list    = new Omega.UI.CanvasControlsList({  div_id : '#entities_list'  });
  this.controls         = $('#canvas_controls');
  this.missions_button  = $('#missions_button');
  this.cam_reset        = $('#cam_reset');
  this.toggle_axis      = $('#toggle_axis input')

  /// need handle to canvas to
  /// - set scene
  /// - set camera target
  /// - reset camera
  /// - add/remove axis from canvas
  this.canvas = null;

  $.extend(this, parameters);

  /// TODO sort locations list
};

Omega.UI.CanvasControls.prototype = {
  wire_up : function(){
    var _this = this;

    this.locations_list.component().on('click', 'li',
      function(evnt){
        var item = $(evnt.currentTarget).data('item');
        _this.canvas.set_scene_root(item);
      })

    this.entities_list.component().on('click', 'li',
      function(evnt){
        var item = $(evnt.currentTarget).data('item');
        _this.canvas.set_scene_root(item.solar_system);
        _this.canvas.cam.position.set(item.location.x + 500,
                                      item.location.y + 500,
                                      item.location.z + 500);
        _this.canvas.focus_on(item.location);
        _this.canvas._clicked_entity(item);
      })

    this.missions_button.on('click',
      function(evnt){
        _this._missions_button_click();
      });

    this.cam_reset.on('click',
      function(evnt){
        _this.canvas.reset_cam();
      });

    this.toggle_axis.on('click',
      function(evnt){
        if($(evnt.currentTarget).is(':checked'))
          _this.canvas.add(_this.canvas.axis);
        else
          _this.canvas.remove(_this.canvas.axis);
        _this.canvas.animate();
      });
    this.toggle_axis.attr('checked', false);

    this.locations_list.wire_up();
    this.entities_list.wire_up();
  },

  _missions_button_click : function(){
    var _this = this;
    var node  = this.canvas.page.node;
    Omega.Mission.all(node, function(missions){ _this.canvas.dialog.show_missions_dialog(missions); });
  }
}
<|endoftext|>


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

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, window, $ */

define(function (require, exports, module) {
    'use strict';

    var Commands                = require("command/Commands"),
        CommandManager          = require("command/CommandManager"),
        Strings                 = require("strings"),
        ProjectManager          = require("project/ProjectManager"),
        EditorManager           = require("editor/EditorManager");

    /**
     * @private
     * Increases or decreases the editor's font size.
     * @param {number} -1 to make the font smaller; 1 to make it bigger.
     */
    function _adjustFontSize(direction) {
        var styleId = "codemirror-dynamic-fonts";

        var fs = $(".CodeMirror-scroll").css("font-size");
        var lh = $(".CodeMirror-scroll").css("line-height");

        var validFont = /^[\d\.]+(px|em)$/;

        // Make sure the font size and line height are expressed in terms
        // we can handle (px or em). If not, simply bail.
        if (fs.search(validFont) === -1 || lh.search(validFont) === -1) {
            return;
        }

        // Guaranteed to work by the validation above.
        var fsUnits = fs.substring(fs.length - 2, fs.length);
        var lhUnits = lh.substring(lh.length - 2, lh.length);

        fs = fs.substring(0, fs.length - 2);
        lh = lh.substring(0, lh.length - 2);

        var fsDelta = (fsUnits === "px") ? 1 : 0.1;
        var lhDelta = (lhUnits === "px") ? 1 : 0.1;

        if (direction === -1) {
            fsDelta *= -1;
            lhDelta *= -1;
        }

        var fsStr = (parseFloat(fs) + fsDelta) + fsUnits;
        var lhStr = (parseFloat(lh) + lhDelta) + lhUnits;

        // Don't let the fonts get too small.
        if (direction === -1 && ((fsUnits === "px" && fs <= 1) || (fsUnits === "em" && fs <= 0.1))) {
            return;
        }

        // It's necessary to inject a new rule to address all editors.
        $("#" + styleId).remove();
        var style = $("<style type='text/css'></style>").attr("id", styleId);
        style.html(".CodeMirror-scroll {" +
                   "font-size: "   + fsStr + " !important;" +
                   "line-height: " + lhStr + " !important;}");
        $("head").append(style);

        EditorManager.getCurrentFullEditor().refreshAll();
    }

    function _handleIncreaseFontSize() {
        _adjustFontSize(1);
    }

    function _handleDecreaseFontSize() {
        _adjustFontSize(-1);
    }

    CommandManager.register(Strings.CMD_INCREASE_FONT_SIZE, Commands.VIEW_INCREASE_FONT_SIZE, _handleIncreaseFontSize);
    CommandManager.register(Strings.CMD_DECREASE_FONT_SIZE, Commands.VIEW_DECREASE_FONT_SIZE, _handleDecreaseFontSize);
});
<commit_msg>Added functionality to restore the font size to its original setting.<commit_after>/*
 * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, window, $ */

define(function (require, exports, module) {
    'use strict';

    var Commands                = require("command/Commands"),
        CommandManager          = require("command/CommandManager"),
        Strings                 = require("strings"),
        ProjectManager          = require("project/ProjectManager"),
        EditorManager           = require("editor/EditorManager");

    /**
     * @const
     * @type {string}
     */
    var DYNAMIC_FONT_STYLE_ID = "codemirror-dynamic-fonts";

    function _removeDynamicFontSize(refresh) {
        $("#" + DYNAMIC_FONT_STYLE_ID).remove();
        if (refresh) {
            EditorManager.getCurrentFullEditor().refreshAll();
        }
    }

    /**
     * @private
     * Increases or decreases the editor's font size.
     * @param {number} -1 to make the font smaller; 1 to make it bigger.
     */
    function _adjustFontSize(direction) {
        var fs = $(".CodeMirror-scroll").css("font-size");
        var lh = $(".CodeMirror-scroll").css("line-height");

        var validFont = /^[\d\.]+(px|em)$/;

        // Make sure the font size and line height are expressed in terms
        // we can handle (px or em). If not, simply bail.
        if (fs.search(validFont) === -1 || lh.search(validFont) === -1) {
            return;
        }

        // Guaranteed to work by the validation above.
        var fsUnits = fs.substring(fs.length - 2, fs.length);
        var lhUnits = lh.substring(lh.length - 2, lh.length);

        fs = fs.substring(0, fs.length - 2);
        lh = lh.substring(0, lh.length - 2);

        var fsDelta = (fsUnits === "px") ? 1 : 0.1;
        var lhDelta = (lhUnits === "px") ? 1 : 0.1;

        if (direction === -1) {
            fsDelta *= -1;
            lhDelta *= -1;
        }

        var fsStr = (parseFloat(fs) + fsDelta) + fsUnits;
        var lhStr = (parseFloat(lh) + lhDelta) + lhUnits;

        // Don't let the fonts get too small.
        if (direction === -1 && ((fsUnits === "px" && fs <= 1) || (fsUnits === "em" && fs <= 0.1))) {
            return;
        }

        // It's necessary to inject a new rule to address all editors.
        _removeDynamicFontSize(false);
        var style = $("<style type='text/css'></style>").attr("id", DYNAMIC_FONT_STYLE_ID);
        style.html(".CodeMirror-scroll {" +
                   "font-size: "   + fsStr + " !important;" +
                   "line-height: " + lhStr + " !important;}");
        $("head").append(style);

        EditorManager.getCurrentFullEditor().refreshAll();
    }

    function _handleIncreaseFontSize() {
        _adjustFontSize(1);
    }

    function _handleDecreaseFontSize() {
        _adjustFontSize(-1);
    }

    function _handleRestoreFontSize() {
        _removeDynamicFontSize(true);
    }

    CommandManager.register(Strings.CMD_INCREASE_FONT_SIZE, Commands.VIEW_INCREASE_FONT_SIZE, _handleIncreaseFontSize);
    CommandManager.register(Strings.CMD_DECREASE_FONT_SIZE, Commands.VIEW_DECREASE_FONT_SIZE, _handleDecreaseFontSize);
    CommandManager.register(Strings.CMD_RESTORE_FONT_SIZE,  Commands.VIEW_RESTORE_FONT_SIZE,  _handleRestoreFontSize);
});
<|endoftext|>


<commit_before>import {inject,LogManager} from 'aurelia-framework';
import {EventAggregator} from 'aurelia-event-aggregator';
import {Router, activationStrategy} from 'aurelia-router';
import {Countries} from '../../services/countries';
import {Albums} from '../../services/albums';
import {StampCollections} from '../../services/stampCollections';
import {Sellers} from '../../services/sellers';
import {Catalogues} from '../../services/catalogues';
import {Stamps} from '../../services/stamps';
import {EventNames} from '../../event-names';
import  _  from 'lodash';

import 'resources/styles/views/manage/manage.css!';

const logger = LogManager.getLogger('stamp-list');

@inject(EventAggregator, Countries, Albums, StampCollections, Sellers, Catalogues, Stamps)
export class ManageList {

	selectedEntity = undefined;
	entityModels = [];
	subscriptions = [];

	constructor(eventBus, countryService, albumService, stampCollectionService, sellerService, catalogueService, stampService) {
		this.eventBus = eventBus;
		this.stampService = stampService;
		this.entityModels = [
			{
				field: 'countryRef',
				collectionName: countryService.getResourceName(),
				label: 'Countries',
				editTitle: 'Edit Country',
				createTitle: 'Create Country',
				service: countryService,
				editor: 'views/countries/country-editor'
			},
			{
				field: 'albumRef',
				collectionName: albumService.getResourceName(),
				label: 'Albums',
				editTitle: 'Edit Album',
				createTitle: 'Create Album',
				service: albumService,
				editor: 'views/albums/album-editor'
			},
			{
				field: 'stampCollectionRef',
				collectionName: stampCollectionService.getResourceName(),
				label: 'Stamp Collections',
				editTitle: 'Edit Stamp Collection',
				createTitle: 'Create Stamp Collection',
				service: stampCollectionService,
				editor: 'views/stamp-collections/stamp-collection-editor'
			},
			{
				field: 'sellerRef',
				collectionName: sellerService.getResourceName(),
				label: 'Sellers',
				editTitle: 'Edit Seller',
				createTitle: 'Create Seller',
				service: sellerService
			},
			{
				field: 'catalogueRef',
				collectionName: catalogueService.getResourceName(),
				label: 'Catalogues',
				editTitle: 'Edit Catalogue',
				createTitle: 'Create Catalogue',
				service: catalogueService
			}
		];
		this.configureSubscriptions();
	}

	configureRouter(config, router) {
		this.router = router;
		config.title = 'Manage';
		config.mapUnknownRoutes(instruction => {
			if( instruction.fragment === '' ) {
				instruction.config.moduleId = './list';
				this._restoreState();
			} else {
				var index = _.findIndex(this.entityModels, {collectionName: instruction.fragment});
				if (index >= 0) {
					this._saveState(this.entityModels[index].field);
					instruction.config.moduleId = './list';
				}
			}
		});
	}

	_saveState(fieldDef) {
		var obj = {
			field: fieldDef
		};
		localStorage.setItem("manage-entities", JSON.stringify(obj));
	}

	_restoreState() {
		var entityCache = localStorage.getItem("manage-entities");
		if (entityCache) {
			var cacheVal = JSON.parse(entityCache);
			if (cacheVal.field) {
				var that = this;
				setTimeout(function() {
					that.setEntity(cacheVal.field);
				}, 250);

			}
		}
	}

	detached() {
		this.subscriptions.forEach(function(subscription) {
			subscription();
		})
		this.subscriptions = [];
	}

	configureSubscriptions() {
		this.subscriptions.push(this.eventBus.subscribe(EventNames.entityFilter, opts => {
			this.router.navigate("/stamp-list?$filter=" + encodeURI(opts.$filter));
			//this.router.navigate(this.router.generate('stamp-list', { $filter: opts.$filter }));
		}));
		this.subscriptions.push(this.eventBus.subscribe(EventNames.selectEntity, collectionName => {
			var fieldDef = _.findWhere(this.entityModels, { collectionName: collectionName });
			if( fieldDef ) {
				this.processField( fieldDef );
			}
		}));
		this.subscriptions.push(this.eventBus.subscribe(EventNames.save, model => {
			if( this.selectedEntity.service ) {
				this.selectedEntity.service.save(model).then(result => {
					this.eventBus.publish(EventNames.close);
				}).catch(err => {
					this.eventBus.publish(EventNames.actionError, err.message);
				});
			}
		}));
		this.subscriptions.push(this.eventBus.subscribe(EventNames.edit, config => {
			this.editingModel = config.model;
			this.editorTitle = config.field.editTitle;
			this.editorContent = config.field.editor;
		}));
		this.subscriptions.push(this.eventBus.subscribe(EventNames.entityDelete, config => {

		}));
	}

	determineActivationStrategy(){
		return activationStrategy.replace;
	}

	getSortCriteria(fieldDef) {
		var opts = {
			$orderby: 'name asc'
		};
		if (fieldDef.field === 'catalogueRef') {
			opts.$orderby = 'issue desc';
		}
		return opts;
	}

	processField( fieldDef ) {
		this.selectedEntity = fieldDef;
		fieldDef.service.find(this.getSortCriteria(fieldDef)).then(result => {
			var that = this;
			that.eventBus.publish(EventNames.manageEntity, {
				models : result.models,
				field: that.selectedEntity
			});
			Promise.all(result.models.map(function(model) {
				var opts = {
					$filter: '(' + fieldDef.field + ' eq ' + model.id + ')'
				};
				that.stampService.count(opts).then(count => {
					model.stampCount = +count;
					return model;
				}).catch(issue => {
					logger.error( issue );
				});
			})).catch( issue => {
				logger.error( issue );
			});
		});
	}

	setEntity(entityType) {
		var index = _.findIndex(this.entityModels, {field: entityType});
		if( index >= 0 ) {
			var collectionName = this.entityModels[index].collectionName;
			if( this.router.currentInstruction && this.router.currentInstruction.fragment !== collectionName ) {
				this.router.navigate( collectionName );
			}

		}
	}

	create(entity) {
		var that = this;
		setTimeout( function() {
			that.editingModel = { };
			that.editorTitle = entity.createTitle;
			that.editorContent = entity.editor;
		}, 50);

	}

}
<commit_msg>Router now handles $ in query keys<commit_after>import {inject,LogManager} from 'aurelia-framework';
import {EventAggregator} from 'aurelia-event-aggregator';
import {Router, activationStrategy} from 'aurelia-router';
import {Countries} from '../../services/countries';
import {Albums} from '../../services/albums';
import {StampCollections} from '../../services/stampCollections';
import {Sellers} from '../../services/sellers';
import {Catalogues} from '../../services/catalogues';
import {Stamps} from '../../services/stamps';
import {EventNames} from '../../event-names';
import  _  from 'lodash';

import 'resources/styles/views/manage/manage.css!';

const logger = LogManager.getLogger('stamp-list');

@inject(EventAggregator, Countries, Albums, StampCollections, Sellers, Catalogues, Stamps)
export class ManageList {

	selectedEntity = undefined;
	entityModels = [];
	subscriptions = [];

	constructor(eventBus, countryService, albumService, stampCollectionService, sellerService, catalogueService, stampService) {
		this.eventBus = eventBus;
		this.stampService = stampService;
		this.entityModels = [
			{
				field: 'countryRef',
				collectionName: countryService.getResourceName(),
				label: 'Countries',
				editTitle: 'Edit Country',
				createTitle: 'Create Country',
				service: countryService,
				editor: 'views/countries/country-editor'
			},
			{
				field: 'albumRef',
				collectionName: albumService.getResourceName(),
				label: 'Albums',
				editTitle: 'Edit Album',
				createTitle: 'Create Album',
				service: albumService,
				editor: 'views/albums/album-editor'
			},
			{
				field: 'stampCollectionRef',
				collectionName: stampCollectionService.getResourceName(),
				label: 'Stamp Collections',
				editTitle: 'Edit Stamp Collection',
				createTitle: 'Create Stamp Collection',
				service: stampCollectionService,
				editor: 'views/stamp-collections/stamp-collection-editor'
			},
			{
				field: 'sellerRef',
				collectionName: sellerService.getResourceName(),
				label: 'Sellers',
				editTitle: 'Edit Seller',
				createTitle: 'Create Seller',
				service: sellerService
			},
			{
				field: 'catalogueRef',
				collectionName: catalogueService.getResourceName(),
				label: 'Catalogues',
				editTitle: 'Edit Catalogue',
				createTitle: 'Create Catalogue',
				service: catalogueService
			}
		];
		this.configureSubscriptions();
	}

	configureRouter(config, router) {
		this.router = router;
		config.title = 'Manage';
		config.mapUnknownRoutes(instruction => {
			if( instruction.fragment === '' ) {
				instruction.config.moduleId = './list';
				this._restoreState();
			} else {
				var index = _.findIndex(this.entityModels, {collectionName: instruction.fragment});
				if (index >= 0) {
					this._saveState(this.entityModels[index].field);
					instruction.config.moduleId = './list';
				}
			}
		});
	}

	_saveState(fieldDef) {
		var obj = {
			field: fieldDef
		};
		localStorage.setItem("manage-entities", JSON.stringify(obj));
	}

	_restoreState() {
		var entityCache = localStorage.getItem("manage-entities");
		if (entityCache) {
			var cacheVal = JSON.parse(entityCache);
			if (cacheVal.field) {
				var that = this;
				setTimeout(function() {
					that.setEntity(cacheVal.field);
				}, 250);

			}
		}
	}

	detached() {
		this.subscriptions.forEach(function(subscription) {
			subscription();
		})
		this.subscriptions = [];
	}

	configureSubscriptions() {
		this.subscriptions.push(this.eventBus.subscribe(EventNames.entityFilter, opts => {
			this.router.navigate(this.router.generate('stamp-list', { $filter: opts.$filter }));
		}));
		this.subscriptions.push(this.eventBus.subscribe(EventNames.selectEntity, collectionName => {
			var fieldDef = _.findWhere(this.entityModels, { collectionName: collectionName });
			if( fieldDef ) {
				this.processField( fieldDef );
			}
		}));
		this.subscriptions.push(this.eventBus.subscribe(EventNames.save, model => {
			if( this.selectedEntity.service ) {
				this.selectedEntity.service.save(model).then(result => {
					this.eventBus.publish(EventNames.close);
				}).catch(err => {
					this.eventBus.publish(EventNames.actionError, err.message);
				});
			}
		}));
		this.subscriptions.push(this.eventBus.subscribe(EventNames.edit, config => {
			this.editingModel = config.model;
			this.editorTitle = config.field.editTitle;
			this.editorContent = config.field.editor;
		}));
		this.subscriptions.push(this.eventBus.subscribe(EventNames.entityDelete, config => {

		}));
	}

	determineActivationStrategy(){
		return activationStrategy.replace;
	}

	getSortCriteria(fieldDef) {
		var opts = {
			$orderby: 'name asc'
		};
		if (fieldDef.field === 'catalogueRef') {
			opts.$orderby = 'issue desc';
		}
		return opts;
	}

	processField( fieldDef ) {
		this.selectedEntity = fieldDef;
		fieldDef.service.find(this.getSortCriteria(fieldDef)).then(result => {
			var that = this;
			that.eventBus.publish(EventNames.manageEntity, {
				models : result.models,
				field: that.selectedEntity
			});
			Promise.all(result.models.map(function(model) {
				var opts = {
					$filter: '(' + fieldDef.field + ' eq ' + model.id + ')'
				};
				that.stampService.count(opts).then(count => {
					model.stampCount = +count;
					return model;
				}).catch(issue => {
					logger.error( issue );
				});
			})).catch( issue => {
				logger.error( issue );
			});
		});
	}

	setEntity(entityType) {
		var index = _.findIndex(this.entityModels, {field: entityType});
		if( index >= 0 ) {
			var collectionName = this.entityModels[index].collectionName;
			if( this.router.currentInstruction && this.router.currentInstruction.fragment !== collectionName ) {
				this.router.navigate( collectionName );
			}

		}
	}

	create(entity) {
		var that = this;
		setTimeout( function() {
			that.editingModel = { };
			that.editorTitle = entity.createTitle;
			that.editorContent = entity.editor;
		}, 50);

	}

}
<|endoftext|>


<commit_before>/**
	_moon.SimplePicker_ is a control that solicits a choice from the user by
	cycling through a list of options. The picker's child components, typically
	simple enyo.Control objects with text content,
	become the options for the picker.

		{kind:"moon.SimplePicker", onChange:"changed", selectedIndex:1, components: [
			{content:"San Francisco"},
			{content:"Boston"},
			{content:"Tokyo"}
		]}

	The picker may be changed programmatically by calling _previous()_ or
	_next()_, or by modifying the _selectedIndex_ published property by calling
	_set("selectedIndex", <value>)_.

	The _onChange_ event is fired when the selected item changes, and contains the
	following	properties:

		{
			selected: [object Object],	// Reference to selected item
			content: "San Francisco",	// Content of selected item
			index: 1					// Index of selected item
		}

	The picker options may be modified programmatically in the standard manner, by
	calling	_createComponent().render()_ or _destroy()_.  Note that _reflow()_
	must be called after components are added or removed:

		// Add new items to picker
		this.$.picker.createComponent({"New York"}).render();
		this.$.picker.createComponent({"London"}).render();
		this.$.picker.reflow();

		// Remove currently selected item from picker
		this.$.picker.getSelected().destroy();
		this.$.picker.reflow();
*/
enyo.kind({
	name: "moon.SimplePicker",
	classes: "moon-simple-picker",
	events: {
		/**
			Fires when the currently selected item changes.

			_inEvent.selected_ contains a reference to the currently selected item.

			_inEvent.content_ contains the content of the currently selected item.

			_inEvent.index_ contains the index of the currently selected item.
		*/
		onChange:""
	},
	published: {
		//* Reference to currently selected item, if any
		selected:"",
		//* Index of currently selected item, if any
		selectedIndex:null,
		//* When true, picker transitions animate left/right
		animate:true,
		//* When true, button is shown as disabled and does not generate tap events
		disabled: false
	},
	//* @protected
	components: [
		{kind:"enyo.Button", classes:"moon-simple-picker-button", content:"<", ontap:"previous", spotlight:true, defaultSpotlightRight: 'buttonRight', name:"buttonLeft"},
		{kind:"enyo.Panels", classes:"moon-simple-picker-client", controlClasses:"moon-simple-picker-item", draggable:false, arrangerKind: "CarouselArranger", name:"client", onTransitionFinish:"transitionFinished"},
		{kind:"enyo.Button", classes:"moon-simple-picker-button", content:">", ontap:"next", spotlight:true, defaultSpotlightLeft: 'buttonLeft', name:"buttonRight"}
	],
	create: function() {
		this.inherited(arguments);
		this.animateChanged();
		this.selectedIndexChanged();
		this.disabledChanged();
	},
	rendered: function() {
		this.inherited(arguments);
		this._rendered = true;
	},
	createComponents: function(inC, inOpts) {
		var inherited = this.createComponents._inherited;
		if (this.$.client) {
			inOpts = inOpts || {};
			inOpts.container = this.$.client;
		}
		return inherited.call(this, inC, inOpts);
	},
	createComponent: function(inC, inOpts) {
		var inherited = this.createComponent._inherited;
		if (this.$.client) {
			inOpts = inOpts || {};
			inOpts.container = this.$.client;
		}
		return inherited.call(this, inC, inOpts);
	},
	reflow: function() {
		this.inherited(arguments);

		// Find max width of all children
		var width = 0;
		for (var c$=this.$.client.getPanels(), i=0; i<c$.length; i++) {
			width = Math.max(width, c$[i].getBounds().width);
		}
		this.$.client.setBounds({width:width});
		for (c$=this.$.client.getPanels(), i=0; i<c$.length; i++) {
			c$[i].setBounds({width:width});
		}
		this.$.client.reflow();
		this.$.client.setBounds({height: this.$.buttonLeft.getBounds().height});

		// Make sure selected item is in sync after Panels reflow, which may have
		// followed an item being added/removed
		if (this.selected != this.$.client.getActive()) {
			this.setSelected(this.$.client.getActive());
			this.setSelectedIndex(this.$.client.getIndex());
			this.fireChangedEvent();
		}
	},
	transitionFinished: function(inSender, inEvent) {
		var fp = (this.getSelected() === this.$.client.getActive()); // false positive
		this.setSelected(this.$.client.getActive());
		this.setSelectedIndex(this.$.client.getIndex());
		if (!fp) {
			this.fireChangedEvent();
		}
		return true;
	},
	fireChangedEvent: function() {
		if (this._rendered) {
			this.doChange({
				selected: this.selected,
				content: this.selected && this.selected.content,
				index: this.selected && this.selectedIndex
			});
		}
	},
	disabledChanged: function() {
		this.addRemoveClass("disabled", this.disabled);
		this.$.buttonLeft.setDisabled(this.disabled);
		this.$.buttonRight.setDisabled(this.disabled);
	},
	animateChanged: function() {
		this.$.client.setAnimate(this.animate);
	},
	selectedChanged: function(inOld) {
		if (this.selected != this.$.client.getActive()) {
			this.$.client.setIndex(this.selected.indexInContainer());
		}
	},
	selectedIndexChanged: function(inOld) {
		if ((this.selectedIndex !== null) && (this.selectedIndex != this.$.client.getIndex())) {
			this.$.client.setIndex(this.selectedIndex);
		}
	},
	//* @public
	//* Cycles the selected item to the one before the currently selected item.
	previous: function() {
		this.$.client.previous();
	},
	//* @public
	//* Cycles the selected item to the one after the currently selected item.
	next: function() {
		this.$.client.next();
	}
});<commit_msg>Fix picker to not set widths to zero if picker isn't visible when rendered into DOM<commit_after>/**
	_moon.SimplePicker_ is a control that solicits a choice from the user by
	cycling through a list of options. The picker's child components, typically
	simple enyo.Control objects with text content,
	become the options for the picker.

		{kind:"moon.SimplePicker", onChange:"changed", selectedIndex:1, components: [
			{content:"San Francisco"},
			{content:"Boston"},
			{content:"Tokyo"}
		]}

	The picker may be changed programmatically by calling _previous()_ or
	_next()_, or by modifying the _selectedIndex_ published property by calling
	_set("selectedIndex", <value>)_.

	The _onChange_ event is fired when the selected item changes, and contains the
	following	properties:

		{
			selected: [object Object],	// Reference to selected item
			content: "San Francisco",	// Content of selected item
			index: 1					// Index of selected item
		}

	The picker options may be modified programmatically in the standard manner, by
	calling	_createComponent().render()_ or _destroy()_.  Note that _reflow()_
	must be called after components are added or removed:

		// Add new items to picker
		this.$.picker.createComponent({"New York"}).render();
		this.$.picker.createComponent({"London"}).render();
		this.$.picker.reflow();

		// Remove currently selected item from picker
		this.$.picker.getSelected().destroy();
		this.$.picker.reflow();
*/
enyo.kind({
	name: "moon.SimplePicker",
	classes: "moon-simple-picker",
	events: {
		/**
			Fires when the currently selected item changes.

			_inEvent.selected_ contains a reference to the currently selected item.

			_inEvent.content_ contains the content of the currently selected item.

			_inEvent.index_ contains the index of the currently selected item.
		*/
		onChange:""
	},
	published: {
		//* Reference to currently selected item, if any
		selected:"",
		//* Index of currently selected item, if any
		selectedIndex:null,
		//* When true, picker transitions animate left/right
		animate:true,
		//* When true, button is shown as disabled and does not generate tap events
		disabled: false
	},
	//* @protected
	components: [
		{kind:"enyo.Button", classes:"moon-simple-picker-button", content:"<", ontap:"previous", spotlight:true, defaultSpotlightRight: 'buttonRight', name:"buttonLeft"},
		{kind:"enyo.Panels", classes:"moon-simple-picker-client", controlClasses:"moon-simple-picker-item", draggable:false, arrangerKind: "CarouselArranger", name:"client", onTransitionFinish:"transitionFinished"},
		{kind:"enyo.Button", classes:"moon-simple-picker-button", content:">", ontap:"next", spotlight:true, defaultSpotlightLeft: 'buttonLeft', name:"buttonRight"}
	],
	create: function() {
		this.inherited(arguments);
		this.animateChanged();
		this.selectedIndexChanged();
		this.disabledChanged();
	},
	rendered: function() {
		this.inherited(arguments);
		this._rendered = true;
	},
	createComponents: function(inC, inOpts) {
		var inherited = this.createComponents._inherited;
		if (this.$.client) {
			inOpts = inOpts || {};
			inOpts.container = this.$.client;
		}
		return inherited.call(this, inC, inOpts);
	},
	createComponent: function(inC, inOpts) {
		var inherited = this.createComponent._inherited;
		if (this.$.client) {
			inOpts = inOpts || {};
			inOpts.container = this.$.client;
		}
		return inherited.call(this, inC, inOpts);
	},
	reflow: function() {
		this.inherited(arguments);

		// Find max width of all children
		var width = 0;
		for (var c$=this.$.client.getPanels(), i=0; i<c$.length; i++) {
			width = Math.max(width, c$[i].getBounds().width);
		}
		if(0 === width) {
			return;
		}
		this.$.client.setBounds({width:width});
		for (c$=this.$.client.getPanels(), i=0; i<c$.length; i++) {
			c$[i].setBounds({width:width});
		}
		this.$.client.reflow();
		this.$.client.setBounds({height: this.$.buttonLeft.getBounds().height});

		// Make sure selected item is in sync after Panels reflow, which may have
		// followed an item being added/removed
		if (this.selected != this.$.client.getActive()) {
			this.setSelected(this.$.client.getActive());
			this.setSelectedIndex(this.$.client.getIndex());
			this.fireChangedEvent();
		}
	},
	transitionFinished: function(inSender, inEvent) {
		var fp = (this.getSelected() === this.$.client.getActive()); // false positive
		this.setSelected(this.$.client.getActive());
		this.setSelectedIndex(this.$.client.getIndex());
		if (!fp) {
			this.fireChangedEvent();
		}
		return true;
	},
	fireChangedEvent: function() {
		if (this._rendered) {
			this.doChange({
				selected: this.selected,
				content: this.selected && this.selected.content,
				index: this.selected && this.selectedIndex
			});
		}
	},
	disabledChanged: function() {
		this.addRemoveClass("disabled", this.disabled);
		this.$.buttonLeft.setDisabled(this.disabled);
		this.$.buttonRight.setDisabled(this.disabled);
	},
	animateChanged: function() {
		this.$.client.setAnimate(this.animate);
	},
	selectedChanged: function(inOld) {
		if (this.selected != this.$.client.getActive()) {
			this.$.client.setIndex(this.selected.indexInContainer());
		}
	},
	selectedIndexChanged: function(inOld) {
		if ((this.selectedIndex !== null) && (this.selectedIndex != this.$.client.getIndex())) {
			this.$.client.setIndex(this.selectedIndex);
		}
	},
	//* @public
	//* Cycles the selected item to the one before the currently selected item.
	previous: function() {
		this.$.client.previous();
	},
	//* @public
	//* Cycles the selected item to the one after the currently selected item.
	next: function() {
		this.$.client.next();
	}
});
<|endoftext|>


<commit_before>const pdelay = ms => new Promise(resolve => setTimeout(resolve, ms));
const fixSrc = (src) => {
  const s = src;
  if (s.match(/\/fr\/|_a\.jpg|1080x/)) {
    return s;
  }
  return s.replace(/c\d+\.\d+\.\d+\.\d+\//, '')
    .replace(/\w\d{3,4}x\d{3,4}\//g, s.match(/\/e\d{2}\//) ? '' : 'e15/');
};
const storeTypes = ['GraphImage', 'GraphSidecar', 'GraphVideo'];

class Fetcher {
  constructor(options) {
    this.base = 'https://www.instagram.com/';
    this.syncEach = options.syncEach;
    this.token = null;
    this.lastCursor = null;
    this.query_id = '17866917712078875';
    this.query_hash = 'bcbc6b4219dbbdf7af876bf561d7a283';
    this.rhxGis = '';
  }

  getJSON(url) {
    let variables = '';
    if (url.indexOf('variables') > 0) {
      variables = url.slice(url.indexOf('variables') + 10);
    } else {
      variables = `/${url.slice(0, url.indexOf('?'))}`;
    }
    const options = {
      method: 'GET',
      headers: {
        'X-Requested-With': 'XMLHttpRequest',
        'X-Instagram-GIS': md5(`${this.rhxGis}:${variables}`),
      },
      credentials: 'include',
    };
    return fetch(this.base + url, options)
      .then(res => res.json());
  }

  post(url, data) {
    const options = {
      method: 'POST',
      headers: {
        Accept: 'application/json, text/javascript, */*; q=0.01',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'X-CSRFToken': this.token,
        'X-Instagram-Ajax': 1,
        'X-Requested-With': 'XMLHttpRequest',
      },
      credentials: 'include',
    };
    if (data) {
      options.body = data;
    }
    return fetch(this.base + url, options)
      .then(res => res.json());
  }

  getDOM(html) {
    let doc;
    if (document.implementation) {
      doc = document.implementation.createHTMLDocument('');
      doc.documentElement.innerHTML = html;
    } else if (DOMParser) {
      doc = (new DOMParser()).parseFromString(html, 'text/html');
    } else {
      doc = document.createElement('div');
      doc.innerHTML = html;
    }
    return doc;
  }

  storeItem(items) {
    const temp = {};
    for (let i = 0; i < items.length; i += 1) {
      let item = items[i];
      if (item.node) {
        item = item.node;
        if (storeTypes.indexOf(item.__typename) === -1) {
          continue;
        }
        item.date = item.taken_at_timestamp;
        const caption = item.edge_media_to_caption.edges;
        item.caption = caption.length ? caption[0].node.text : '';
        item.likes = {
          count: item.edge_media_preview_like.count,
        };
        item.comments = {
          count: item.edge_media_to_comment.count,
        };
        item.code = item.shortcode;
        item.display_src = fixSrc(item.display_url);
        const usertags = { nodes: [] };
        if (item.edge_media_to_tagged_user.edges.length) {
          item.edge_media_to_tagged_user.edges.forEach((e) => {
            usertags.nodes.push(e.node);
          });
        }
        item.usertags = usertags;

        item.owner = {
          full_name: item.owner.full_name,
          id: item.owner.id,
          profile_pic_url: item.owner.profile_pic_url,
          username: item.owner.username,
        };
      }
      if (item.__typename === 'GraphSidecar') {
        const display_urls = []; // eslint-disable-line camelcase
        item.edge_sidecar_to_children.edges.forEach((e) => {
          const n = e.node;
          display_urls.push((n.is_video ? (`${n.video_url}|`) : '') +
            fixSrc(n.display_url));
        });
        item.display_urls = display_urls; // eslint-disable-line camelcase
      }
      const fields = ['caption', 'code', 'comments', 'date', 'display_src',
        'display_urls', 'video_url', 'id', 'likes', 'location', 'owner',
        'usertags', 'viewer_has_liked'];
      Object.keys(item).forEach((key) => {
        if (fields.indexOf(key) === -1) {
          delete item[key];
        }
      });
      const key = moment(item.date * 1000).startOf('day') / 100000;
      if (key) {
        if (temp[key] === undefined) {
          temp[key] = [];
        }
        temp[key].push(item);
      }
    }
    const newItems = Object.keys(temp).map(key => (DB.push(key, temp[key])));
    return Promise.all(newItems);
  }

  home() {
    return fetch(this.base, { credentials: 'include' })
      .then(res => res.text())
      .then((body) => {
        if (!body) {
          return Promise.reject();
        }
        const doc = this.getDOM(body);
        let s = doc.querySelectorAll('script');
        for (let i = 0; i < s.length; i += 1) {
          if (!s[i].src && s[i].textContent.indexOf('_sharedData') > 0) {
            s = s[i].textContent;
            break;
          }
        }
        const data = JSON.parse(s.match(/({".*})/)[1]);
        let feed = data.entry_data.FeedPage;
        this.rhxGis = data.rhx_gis;
        if (!feed) {
          return Promise.reject();
        }
        try {
          feed = feed[0].graphql.user.edge_web_feed_timeline;
          this.storeItem(feed.edges);
          this.lastCursor = feed.page_info.end_cursor;
        } catch (e) {
          this.lastCursor = null;
        }
        this.token = data.config.csrf_token;

        let common = doc.querySelector('script[src*="Commons.js"]');
        common = this.base + common.getAttribute('src').slice(1);
        return fetch(common, { credentials: 'include' });
      })
      .then(res => res.text())
      .then((rawBody) => {
        let body = rawBody;
        try {
          let hash = body.slice(0, body.indexOf('edge_web_feed_timeline'))
            .match(/\w="\w{32}",\w="\w{32}",\w="\w{32}"/g);
          this.query_hash = hash[hash.length - 1].slice(3, 35);
        } catch (e) {
          this.query_hash = null;
        }
        return true;
      });
  }

  feed(oldCount, total) {
    let url = null;
    if (this.query_hash) {
      const data = JSON.stringify({
        fetch_media_item_count: this.syncEach,
        fetch_media_item_cursor: this.lastCursor,
        fetch_comment_count: 4,
        fetch_like: 10,
        has_stories: false,
      });
      url = `hash=${this.query_hash}&variables=${encodeURIComponent(data)}`;
    } else {
      url = `id=${this.query_id}&` +
        `fetch_media_item_count=${this.syncEach}&` +
        `fetch_media_item_cursor=${this.lastCursor}&` +
        'fetch_comment_count=4&fetch_like=10';
    }
    return this.getJSON(`graphql/query/?query_${url}`).then((body) => {
      const feed = body.data.user.edge_web_feed_timeline;
      this.lastCursor = feed.page_info.end_cursor;
      this.storeItem(feed.edges);
      const count = oldCount - 1;
      console.log(`Synced ${total - count}/${total} feed.`);
      chrome.browserAction.setBadgeText({ text: `${total - count}/${total}` });
      if (count > 0 && feed.page_info.has_next_page) {
        return pdelay(2000).then(() => {
          this.feed(count, total);
        });
      }
      return chrome.browserAction.setBadgeText({ text: '' });
    });
  }

  auto(count = 10) {
    return this.home().then((res) => {
      if (res) {
        return this.feed(count, count);
      }
      return res;
    });
  }
}

window.Fetcher = Fetcher;
<commit_msg>Update feed hash & handle ajax token<commit_after>const pdelay = ms => new Promise(resolve => setTimeout(resolve, ms));
const fixSrc = (src) => {
  const s = src;
  if (s.match(/\/fr\/|_a\.jpg|1080x/)) {
    return s;
  }
  return s.replace(/c\d+\.\d+\.\d+\.\d+\//, '')
    .replace(/\w\d{3,4}x\d{3,4}\//g, s.match(/\/e\d{2}\//) ? '' : 'e15/');
};
const storeTypes = ['GraphImage', 'GraphSidecar', 'GraphVideo'];

class Fetcher {
  constructor(options) {
    this.base = 'https://www.instagram.com/';
    this.syncEach = options.syncEach;
    this.ajaxToken = null;
    this.token = null;
    this.lastCursor = null;
    this.query_id = '17866917712078875';
    this.query_hash = 'bcbc6b4219dbbdf7af876bf561d7a283';
    this.rhxGis = '';
  }

  getJSON(url) {
    let variables = '';
    if (url.indexOf('variables') > 0) {
      variables = url.slice(url.indexOf('variables') + 10);
    } else {
      variables = `/${url.slice(0, url.indexOf('?'))}`;
    }
    const options = {
      method: 'GET',
      headers: {
        'X-Requested-With': 'XMLHttpRequest',
        'X-Instagram-GIS': md5(`${this.rhxGis}:${variables}`),
      },
      credentials: 'include',
    };
    return fetch(this.base + url, options)
      .then(res => res.json());
  }

  post(url, data) {
    const options = {
      method: 'POST',
      headers: {
        Accept: 'application/json, text/javascript, */*; q=0.01',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'X-CSRFToken': this.token,
        'X-Instagram-Ajax': this.ajaxToken,
        'X-Requested-With': 'XMLHttpRequest',
      },
      credentials: 'include',
    };
    if (data) {
      options.body = data;
    }
    return fetch(this.base + url, options)
      .then(res => res.json());
  }

  getDOM(html) {
    let doc;
    if (document.implementation) {
      doc = document.implementation.createHTMLDocument('');
      doc.documentElement.innerHTML = html;
    } else if (DOMParser) {
      doc = (new DOMParser()).parseFromString(html, 'text/html');
    } else {
      doc = document.createElement('div');
      doc.innerHTML = html;
    }
    return doc;
  }

  storeItem(items) {
    const temp = {};
    for (let i = 0; i < items.length; i += 1) {
      let item = items[i];
      if (item.node) {
        item = item.node;
        if (storeTypes.indexOf(item.__typename) === -1) {
          continue;
        }
        item.date = item.taken_at_timestamp;
        const caption = item.edge_media_to_caption.edges;
        item.caption = caption.length ? caption[0].node.text : '';
        item.likes = {
          count: item.edge_media_preview_like.count,
        };
        item.comments = {
          count: (item.edge_media_preview_comment || item.edge_media_to_comment).count,
        };
        item.code = item.shortcode;
        item.display_src = fixSrc(item.display_url);
        const usertags = { nodes: [] };
        if (item.edge_media_to_tagged_user.edges.length) {
          item.edge_media_to_tagged_user.edges.forEach((e) => {
            usertags.nodes.push(e.node);
          });
        }
        item.usertags = usertags;

        item.owner = {
          full_name: item.owner.full_name,
          id: item.owner.id,
          profile_pic_url: item.owner.profile_pic_url,
          username: item.owner.username,
        };
      }
      if (item.__typename === 'GraphSidecar') {
        const display_urls = []; // eslint-disable-line camelcase
        item.edge_sidecar_to_children.edges.forEach((e) => {
          const n = e.node;
          display_urls.push((n.is_video ? (`${n.video_url}|`) : '') +
            fixSrc(n.display_url));
        });
        item.display_urls = display_urls; // eslint-disable-line camelcase
      }
      const fields = ['caption', 'code', 'comments', 'date', 'display_src',
        'display_urls', 'video_url', 'id', 'likes', 'location', 'owner',
        'usertags', 'viewer_has_liked'];
      Object.keys(item).forEach((key) => {
        if (fields.indexOf(key) === -1) {
          delete item[key];
        }
      });
      const key = moment(item.date * 1000).startOf('day') / 100000;
      if (key) {
        if (temp[key] === undefined) {
          temp[key] = [];
        }
        temp[key].push(item);
      }
    }
    const newItems = Object.keys(temp).map(key => (DB.push(key, temp[key])));
    return Promise.all(newItems);
  }

  home() {
    return fetch(this.base, { credentials: 'include' })
      .then(res => res.text())
      .then((body) => {
        if (!body) {
          return Promise.reject();
        }
        const doc = this.getDOM(body);
        let s = doc.querySelectorAll('script');
        for (let i = 0; i < s.length; i += 1) {
          if (!s[i].src && s[i].textContent.indexOf('_sharedData') > 0) {
            s = s[i].textContent;
            break;
          }
        }
        const data = JSON.parse(s.match(/({".*})/)[1]);
        let feed = data.entry_data.FeedPage;
        this.rhxGis = data.rhx_gis;
        if (!feed) {
          return Promise.reject();
        }
        try {
          feed = feed[0].graphql.user.edge_web_feed_timeline;
          this.storeItem(feed.edges);
          this.lastCursor = feed.page_info.end_cursor;
        } catch (e) {
          this.lastCursor = null;
        }
        this.token = data.config.csrf_token;
        this.ajaxToken = data.rollout_hash;

        let common = doc.querySelector('script[src*="Commons.js"]');
        common = this.base + common.getAttribute('src').slice(1);
        return fetch(common, { credentials: 'include' });
      })
      .then(res => res.text())
      .then((rawBody) => {
        let body = rawBody;
        try {
          let hash = body.slice(body.indexOf('FEED_QUERY_ID')).match(/"(\w{32})"/);
          this.query_hash = hash[1];
        } catch (e) {
          this.query_hash = null;
        }
        return true;
      });
  }

  feed(oldCount, total) {
    let url = null;
    if (this.query_hash) {
      const data = JSON.stringify({
        fetch_media_item_count: this.syncEach,
        fetch_media_item_cursor: this.lastCursor,
        fetch_comment_count: 4,
        fetch_like: 3,
        has_stories: false,
        has_threaded_comments: false,
      });
      url = `hash=${this.query_hash}&variables=${encodeURIComponent(data)}`;
    } else {
      url = `id=${this.query_id}&` +
        `fetch_media_item_count=${this.syncEach}&` +
        `fetch_media_item_cursor=${this.lastCursor}&` +
        'fetch_comment_count=4&fetch_like=3';
    }
    return this.getJSON(`graphql/query/?query_${url}`).then((body) => {
      const feed = body.data.user.edge_web_feed_timeline;
      this.lastCursor = feed.page_info.end_cursor;
      this.storeItem(feed.edges);
      const count = oldCount - 1;
      console.log(`Synced ${total - count}/${total} feed.`);
      chrome.browserAction.setBadgeText({ text: `${total - count}/${total}` });
      if (count > 0 && feed.page_info.has_next_page) {
        return pdelay(2000).then(() => {
          this.feed(count, total);
        });
      }
      return chrome.browserAction.setBadgeText({ text: '' });
    });
  }

  auto(count = 10) {
    return this.home().then((res) => {
      if (res) {
        return this.feed(count, count);
      }
      return res;
    });
  }
}

window.Fetcher = Fetcher;
<|endoftext|>


<commit_before>'use strict';
/* jshint -W098*/
function switchInputFactory(id, states, options){
	if(states === undefined || states.length < 1){
		states = ['on','off'];
	}
	function setDefault(option, defaultValue){
		if(option===undefined){
			option = defaultValue;
		}
		return option;
	}

	if(!states){ states = ['on','off']; }
	if(!options){ options = {}; }

	var switchInput = {
		states:states,
		id:id,
		defaultState:states[0],
		lookup:{},
		disabledStates:[],
		activeClass:'active-switch-state',
		inactiveClass:'inactive-switch-state',
		disabledClass:'disabled-switch-state'
	};

	for(var o in options){
		switchInput[o] = options[o];
	}

	$('#'+switchInput.id).addClass('input-switch');
	switchInput.disableState = function(state){
		$('#'+getStateID(state))
			.removeClass(switchInput.activeClass)
			.removeClass(switchInput.inactiveClass)
			.addClass(switchInput.disabledClass);

		switchInput.disabledStates[state] = true;

		//if the current state is being disabled move to the next enabled state
		if(switchInput.state === state){
			var currentIndex = switchInput.states.indexOf(state);
			var newStateSet = false;
			for (var i = currentIndex; (!newStateSet) && (i < switchInput.states.length); i = (i+1)%(switchInput.states.length)){
				if( !switchInput.disabledStates[switchInput.states[i]] ){
					changeState(switchInput.states[i]);
					break;
				}
			}
		}
	};

	switchInput.enableState = function(state){
		switchInput.disabledStates[state] = false;
		if(switchInput.state === undefined){
			switchInput.state = state;
		}
		toggleSwitch(getStateID(switchInput.state));
	};

	function getStateID(state){
		var s = switchInput.id+'-'+state.replace(/[\W\s]/g,'_');
		return s;//switchInput.id+'-'+state;
	}

	function toggleSwitch(activeID){
		$('.' + switchInput.id + '-state')
			.removeClass(switchInput.activeClass)
			.addClass(switchInput.inactiveClass);
		$('#'+activeID)
			.removeClass(switchInput.inactiveClass)
			.addClass(switchInput.activeClass);
		for(var state in switchInput.disabledStates){
			if(switchInput.disabledStates[state]){
				$('#'+getStateID(state))
					.removeClass(switchInput.inactiveClass)
					.removeClass(switchInput.activeClass)
					.addClass(switchInput.disabledClass);
			}
		}
	}

	$.each(switchInput.states, function(i){
		var newID = getStateID(switchInput.states[i]);
		$('#'+switchInput.id)
			.append('
' + switchInput.states[i] + '
');
	});

	$('.' + switchInput.id + '-state').on('click', function(ev){
		var stateName = ev.target.id.split(switchInput.id + '-')[1];
		if(!switchInput.disabledStates[stateName]){
			changeState(stateName);
		}
	});

	function changeState(stateName){
		switchInput.state = stateName;
		toggleSwitch(getStateID(stateName));
		$(switchInput).trigger('state-change');
	}

	changeState(switchInput.defaultState);
	return switchInput;
}<commit_msg>publicly exposing the setState method<commit_after>'use strict';
/* jshint -W098*/
function switchInputFactory(id, states, options){
	if(states === undefined || states.length < 1){
		states = ['on','off'];
	}
	function setDefault(option, defaultValue){
		if(option===undefined){
			option = defaultValue;
		}
		return option;
	}

	if(!states){ states = ['on','off']; }
	if(!options){ options = {}; }

	var switchInput = {
		states:states,
		id:id,
		defaultState:states[0],
		lookup:{},
		disabledStates:[],
		activeClass:'active-switch-state',
		inactiveClass:'inactive-switch-state',
		disabledClass:'disabled-switch-state'
	};

	for(var o in options){
		switchInput[o] = options[o];
	}

	$('#'+switchInput.id).addClass('input-switch');

	switchInput.changeState = function(stateName){
		switchInput.state = stateName;
		toggleSwitch(getStateID(stateName));
		$(switchInput).trigger('state-change');
	}

	switchInput.disableState = function(state){
		$('#'+getStateID(state))
			.removeClass(switchInput.activeClass)
			.removeClass(switchInput.inactiveClass)
			.addClass(switchInput.disabledClass);

		switchInput.disabledStates[state] = true;

		//if the current state is being disabled move to the next enabled state
		if(switchInput.state === state){
			var currentIndex = switchInput.states.indexOf(state);
			var newStateSet = false;
			for (var i = currentIndex; (!newStateSet) && (i < switchInput.states.length); i = (i+1)%(switchInput.states.length)){
				if( !switchInput.disabledStates[switchInput.states[i]] ){
					switchInput.changeState(switchInput.states[i]);
					break;
				}
			}
		}
	};

	switchInput.enableState = function(state){
		switchInput.disabledStates[state] = false;
		if(switchInput.state === undefined){
			switchInput.state = state;
		}
		toggleSwitch(getStateID(switchInput.state));
	};

	function getStateID(state){
		var s = switchInput.id+'-'+state.replace(/[\W\s]/g,'_');
		return s;//switchInput.id+'-'+state;
	}

	function toggleSwitch(activeID){
		$('.' + switchInput.id + '-state')
			.removeClass(switchInput.activeClass)
			.addClass(switchInput.inactiveClass);
		$('#'+activeID)
			.removeClass(switchInput.inactiveClass)
			.addClass(switchInput.activeClass);
		for(var state in switchInput.disabledStates){
			if(switchInput.disabledStates[state]){
				$('#'+getStateID(state))
					.removeClass(switchInput.inactiveClass)
					.removeClass(switchInput.activeClass)
					.addClass(switchInput.disabledClass);
			}
		}
	}

	$.each(switchInput.states, function(i){
		var newID = getStateID(switchInput.states[i]);
		$('#'+switchInput.id)
			.append('
' + switchInput.states[i] + '
');
	});

	$('.' + switchInput.id + '-state').on('click', function(ev){
		var stateName = ev.target.id.split(switchInput.id + '-')[1];
		if(!switchInput.disabledStates[stateName]){
			switchInput.changeState(stateName);
		}
	});

	switchInput.changeState(switchInput.defaultState);

	return switchInput;
}<|endoftext|>


<commit_before>'use strict';

var React = require('react');

var Calendar = React.createClass({
  daysInMonth: function(year, month, day) {
    return new Date(year, month, 0).getDate();
  },
  dayOfDate: function(year,month,day) {
    return new Date(year, month, day).getDay();
  },
  render: function() {
    console.log(this.props.headers)
    var headers = !this.props.headers
               || this.props.headers.map((each) => { return ({each}	) })

    var day = this.dayOfDate(+this.props.year, +this.props.month, 1)
    var daysInMonth = this.daysInMonth(+this.props.year, +this.props.month, 1)

    var days = _.range(day+1).map((each) => {
        return (	)
      }).concat(
        _.range(1, (daysInMonth+1))
         .map((each) => { return ({each}	) })
      ).concat(
        _.range(0, (7-((day+daysInMonth)%7)-1))
         .map((each) => { return (	) })
      )

    var rows = _.chain(days)
      .groupBy((element, index) => { return Math.floor(index/7); })
      .map((eachWeek) => { return
{eachWeek}
})

    return (

                {headers}
                {rows}

    );
  }
});

module.exports = Calendar
<commit_msg>TCV-22 Added previousMonth and nextMonth days<commit_after>'use strict';

var React = require('react');

var Calendar = React.createClass({
  daysInMonth: function(year, month, day) {
    return new Date(year, month, 0).getDate();
  },
  daysInPreviousMonth: function(year, month) {
    var date = new Date(year, month, 0)
    date.setMonth(date.getMonth()-1)
    return this.daysInMonth(date.getYear(), date.getMonth())
  },
  dayOfDate: function(year,month,day) {
    return new Date(year, month, day).getDay();
  },
  render: function() {
    var headers = !this.props.headers
               || this.props.headers.map((each) => { return ({each}	) })

    var day = this.dayOfDate(+this.props.year, +this.props.month, 1)
    var daysInMonth = this.daysInMonth(+this.props.year, +this.props.month)
    var daysInPreviousMonth = this.daysInPreviousMonth(+this.props.year, +this.props.month)

    console.log("day: " + day)
    console.log("daysInMonth: " + daysInMonth)
    console.log("range: " + (7-((day+daysInMonth)%7)))
    console.log("day+daysInMonth: " + (day+daysInMonth))
    console.log("(day+daysInMonth)%7: " + (day+daysInMonth)%7)

    var days = [].concat(
        _.range(daysInPreviousMonth-day+1, daysInPreviousMonth+1)
         .map((each) => { return ({each}	) })
      ).concat(
        _.range(1, daysInMonth+1)
         .map((each) => { return ({each}	) })
      ).concat(
        _.range(1, (7-((day+daysInMonth)%7))%7+1)
         .map((each) => { return ({each}	) })
      )

    var rows = _.chain(days)
      .groupBy((element, index) => { return Math.floor(index/7); })
      .map((eachWeek) => { return
{eachWeek}
})

    return (

                {headers}
                {rows}

    );
  }
});

module.exports = Calendar
<|endoftext|>


<commit_before>/**
* Each Enyo-provided library will annotate this structure with its own
* version info. Why? In general, Enyo and its libraries are versioned
* and released together, but libraries may be versioned separately in
* the future. Also, since libraries are checked out and updated
* individually, a project may be using "mismatched" libraries at any
* given time (e.g., the last stable release of Enyo core, but an
* unreleased checkout from the master branch of `layout`).
*
* Enyo uses semantic versioning. Official releases have version
* numbers	of the form `'X.y.z'`. Prereleases are indicated by a suffix
* of the form `'-pre.N'`, where `N` is incremented for each prerelease.
* Between releases, version numbers include an additional `'-dev'`
* suffix.
*
* @name enyo.version
* @type {Object}
* @property {String} enyo - The current release version string.
* @public
*/
enyo.version = {
	enyo: '2.6.0-pre.1'
};
<commit_msg>Update version string to 2.6.0-pre.1.dev<commit_after>/**
* Each Enyo-provided library will annotate this structure with its own
* version info. Why? In general, Enyo and its libraries are versioned
* and released together, but libraries may be versioned separately in
* the future. Also, since libraries are checked out and updated
* individually, a project may be using "mismatched" libraries at any
* given time (e.g., the last stable release of Enyo core, but an
* unreleased checkout from the master branch of `layout`).
*
* Enyo uses semantic versioning. Official releases have version
* numbers	of the form `'X.y.z'`. Prereleases are indicated by a suffix
* of the form `'-pre.N'`, where `N` is incremented for each prerelease.
* Between releases, version numbers include an additional `'-dev'`
* suffix.
*
* @name enyo.version
* @type {Object}
* @property {String} enyo - The current release version string.
* @public
*/
enyo.version = {
	enyo: '2.6.0-pre.1.dev'
};
<|endoftext|>


<commit_before>// notify.js uses the 'Bootstrap Growl Alerts' for Bootstrap Alert elements, recommended
// by http://styleguide.peaklibrary.com/ (according UX Specs).
// For now, is just implemented the 'success' version of this alerts, and auto-hide (5000ms).
// Info, docs & config: http://bootstrap-growl.remabledesigns.com/

define(['jquery'], function($) {
    return {
        showSuccess: function(obj) {
            $.notify({
                icon: 'fa fa-smile-o',
                message: '' + obj.messageTitle + '
' + obj.message
            },{ element: 'body', type: "success",
                placement: { align: 'center' },
                animate:{
                    enter: "animated-fx fadeIn",
                    exit: "animated-fx fadeOut"
                }
            });
        }
    };
});<commit_msg>Delete notify.js<commit_after><|endoftext|>


<commit_before>
//Takes two categories and collects data from the api.
//It then turns the data turns it into a two dimensional array.
//Any optional analysis (stripping records/colouring/graphing) can then be applied.
//Details for this analysis are given in the options object.
//Finally the table is drawn.
function createCrossPlot( catx, caty, options ){

	//These variable will hold all the JSON data from the api, when the AJAX requests are complete.
	var queryData, catxData, catyData;

	//Assemble the main query url according to the given options.
	var main_query_url = api_root + '/query_category/' + caty + '/' + catx;

	if( options.start_date && options.end_date ){
		main_query_url += '/' + options.start_date + '/' + options.end_date;
	}

	main_query_url += '?use_ids=1';

	if( options.location ){
		main_query_url += '&only_loc=' + options.location;
	}

	//Create the deffered objects to be executed simultaneously.
	var deferreds = [
		$.getJSON( main_query_url, function(data) {
			queryData = data;
		}),
		$.getJSON( api_root + "/variables/" + catx, function(data) {
			catxData = data;
		}),
		$.getJSON( api_root + "/variables/" + caty, function(data) {
			catyData = data;
		})
	];

	//Run the AJAX reuqests asynchronously and act when they have all completed.
	$.when.apply( $, deferreds ).then(function() {

		//Sort out the data for the table
		if( $.isEmptyObject(queryData) ){

			console.log("Empty object");
			$('#cross-wrapper').html(
				"Unfortunately we can't plot that table.  Please try another combination of categories."
			);

		}else{

			//Store the variable id's for each category.
			var yKeys = Object.keys(queryData);
			var xKeys = Object.keys(queryData[yKeys[0]]);

			var columns = [
				{
					"field": "state",
					"checkbox": true
				},{
					"field": "cases",
					"title": "#Cases",
					"align": "left",
					"class": "header"
				},

			];

			var data = [];

			//For each key in the y category, form the row from x category data.
			for( var y in yKeys.sort() ){
				var datum ={
					"cases": timelineLink(yKeys[y],catyData[yKeys[y]].name,"y")
				};
				var total = 0;
				for( var x in xKeys ){
					datum[xKeys[x]] = queryData[yKeys[y]][xKeys[x]];
					total +=queryData[yKeys[y]][xKeys[x]];
				}
				datum.total = total;
				data.push( datum );
			}

			//Now that we have the data in a form javascript can understand, we can do fancy stuff with it.
			colour = false;
			if( options ){
				if( options.strip ){
					var r = strip(columns, data, options.strip );
					columns = r[0];
					data = r[1];
				}
				if( options.colour == "true" ){
					maxMin = max_min( data );
					colour = true;
				}
			}

			// Add the rest of the columns when we know if we are colouring in the cells
			for( var k in xKeys.sort() ){
				var column ={
					"field": xKeys[k],
					"title": timelineLink(xKeys[k],catxData[xKeys[k]].name,"x"),
					"sortable": true

				};
				if(colour){
					column.cellStyle= createColourCell(maxMin);
				}
				columns.push(column);
			}
			columns.push(
				{
					"field": "total",
					"title": "Total",
					sortable: true
				}
			);

			//Draw the table
            var framework = "
" +
                            "
" +
                            "

";

            $("#cross-wrapper").html( framework );
			$("#cross-table").bootstrapTable({
				columns: columns,
				data: data,
				clickToSelect: true
			});

			console.log(columns);
			console.log(data);
		}
	});
}

function createColourCell(maxMin){
	// Returns a function that colours in the cells according to their value
	function cc(value, row, index){
		var perc = (value-maxMin[0])/(maxMin[1]-maxMin[0]);
		return {css: {"background-color": "rgba(217, 105, 42, " + perc +")"}};
	}
	return cc;
}

function max_min(data){
	// Returns max and min of all numbers in table
	var list = [];
	for( var r=1; r<data.length; r++ ){
		var row = data[r];
		for(var x in row){
			if( x!= "cases" && x!= "total"){
				list.push(Number(row[x]));
			}
		}
	}
	var maximum = Math.max.apply( Math, list );
	var minimum = Math.min.apply( Math, list );
	return [minimum,maximum];
}

function timelineLink(id, name, axis){
	//helper function to create links to activate the timeline
	return '' + name + "";
}

function createTimeline(id, cat, options){

	console.log( "Drawing timeline" );

	//These variable will hold all the JSON data from the api, when the AJAX requests are complete.
	var queryData, category, variable;

	//Assemble the main query url according to the given options.
	var main_query_url = api_root + '/query_variable/' + id + '/' + cat;
	if( options.start_date && options.end_date ){
		main_query_url += '/' + options.start_date + '/' + options.end_date;
	}
	main_query_url += '?use_ids=1';
	if( options.location ){
		main_query_url += '&only_loc=' + options.location;
	}

	//Execute multiple json requests simultaneously.
	var deferreds = [
		$.getJSON( main_query_url, function(data) {
			queryData = data;
		}),
		$.getJSON( api_root + "/variables/" + cat,  function(data) {
			category = data;
		}),
		$.getJSON( api_root + "/variable/" + id, function(data) {
			variable = data;
		})
	];

	//Run the AJAX reuqests asynchronously and act when they have all completed.
	$.when.apply( $, deferreds ).then(function() {

		var yKeys = Object.keys(queryData);
		var xKeys = Object.keys(queryData[yKeys[0]].weeks);
		var columns = [
			{
				"field": "cases",
				"title": "#Cases with "+ variable.name,
				"align": "left",
				"class": "header"
			}
		];
		var data = [];

		//For each key in the y category, form the row from x category data.
		for( var y in yKeys.sort() ){
            console.log( yKeys[y] );
			var datum ={
				"cases": category[yKeys[y]].name
			};
			var total = 0;
			for( var x in xKeys ){
				datum["week_" + xKeys[x]] = queryData[yKeys[y]].weeks[xKeys[x]];
				total += queryData[yKeys[y]].weeks[xKeys[x]];
			}
			datum.total = total;
			data.push( datum );
		}
		// Sort out options
		colour = false;
		if( options ){
			if( options.strip ){
				var r = strip(columns, data, options.strip );
				columns = r[0];
				data = r[1];
			}
			if( options.colour == "true" ){
				maxMin = max_min( data );
				colour = true;
			}
		}
		// Add remaining columns
		for( var k in xKeys.sort(function(a, b){return a-b;}) ){
			var column ={
				"field": "week_"+ xKeys[k],
				"title": "Week " + xKeys[k],
				"sortable": true
			};
			if(colour){
				column.cellStyle= createColourCell(maxMin);
			}
			columns.push(column);
		}
		columns.push(
			{
				"field": "total",
				"title": "Total",
				sortable: true
			}
		);
		//Draw!
        var framework = "
" +
                        "
" +
                        "

";
        $("#timeline-wrapper").html( framework );
		$("#timeline-table").bootstrapTable({
			columns: columns,
			data: data
		});

	});
}

function transpose( jsTable ){
	var newTable = jsTable[0].map(function(col, i) {
		return jsTable.map(function(row) {
			return row[i];
		});
	});
	return newTable;
}

function strip( columns, data, axis ){

	function stripRows(data){
		console.log("StripRows");
		//Store a list of rows to be removed.
		var remove = [];
		//For each row iterate through it's elements to seeif all are empty.
		for( var y=0; y<data.length; y++ ){
			var row = data[y];
			var empty = true;
			for( var x in row ){
				if( x != "cases" && Number(row[x]) !== 0 ) empty = false;
			}
			if( empty ) {
				remove.push(y);
			}
		}
		for( var i = remove.length-1; i>=0; i-- ) data.splice( remove[i], 1 );
		console.log(data.length);
		//Remove all empty rows (starting from the last to avoid screwing up indexes).
		return data;
	}

	// if( axis.indexOf('y') != -1 || axis.indexOf('Y') != -1 ){
	// 	table = stripRows( table );
	// }

	// if( axis.indexOf('x') != -1 || axis.indexOf('X') != -1 ){
	// 	table = transpose( stripRows( transpose( table ) ) );
	// }
	data = stripRows(data);
	return [columns, data];

}

<commit_msg>Added totals for columns<commit_after>
//Takes two categories and collects data from the api.
//It then turns the data turns it into a two dimensional array.
//Any optional analysis (stripping records/colouring/graphing) can then be applied.
//Details for this analysis are given in the options object.
//Finally the table is drawn.
function createCrossPlot( catx, caty, options ){

	//These variable will hold all the JSON data from the api, when the AJAX requests are complete.
	var queryData, catxData, catyData;

	//Assemble the main query url according to the given options.
	var main_query_url = api_root + '/query_category/' + caty + '/' + catx;

	if( options.start_date && options.end_date ){
		main_query_url += '/' + options.start_date + '/' + options.end_date;
	}

	main_query_url += '?use_ids=1';

	if( options.location ){
		main_query_url += '&only_loc=' + options.location;
	}

	//Create the deffered objects to be executed simultaneously.
	var deferreds = [
		$.getJSON( main_query_url, function(data) {
			queryData = data;
		}),
		$.getJSON( api_root + "/variables/" + catx, function(data) {
			catxData = data;
		}),
		$.getJSON( api_root + "/variables/" + caty, function(data) {
			catyData = data;
		})
	];

	//Run the AJAX reuqests asynchronously and act when they have all completed.
	$.when.apply( $, deferreds ).then(function() {

		//Sort out the data for the table
		if( $.isEmptyObject(queryData) ){

			console.log("Empty object");
			$('#cross-wrapper').html(
				"Unfortunately we can't plot that table.  Please try another combination of categories."
			);

		}else{

			//Store the variable id's for each category.
			var yKeys = Object.keys(queryData);
			var xKeys = Object.keys(queryData[yKeys[0]]);

			var columns = [
				{
					"field": "state",
					"checkbox": true
				},{
					"field": "cases",
					"title": "#Cases",
					"align": "left",
					"class": "header"
				},

			];

			var data = [];
            var colTotal = [];
            for( var i in xKeys ) colTotal.push( 0 );

			//For each key in the y category, form the row from x category data.
			for( var y in yKeys.sort() ){
				var row ={
					"cases": timelineLink(yKeys[y],catyData[yKeys[y]].name,"y")
				};
				var rowTotal = 0;

				for( var x in xKeys ){

                    //The data point to be added...
                    datum = queryData[yKeys[y]][xKeys[x]];

                    colTotal[ x ] += datum;
					rowTotal += datum;
                    row[xKeys[x]] = datum;
				}

				row.total = rowTotal;
				data.push( row );
			}

            totalRow = { "cases":"Total" };
            for( var col in xKeys ){
                totalRow[xKeys[col]] = colTotal[col];
            }
            data.push( totalRow );

			//Now that we have the data in a form javascript can understand, we can do fancy stuff with it.
			colour = false;
			if( options ){
				if( options.strip ){
					var r = strip(columns, data, options.strip );
					columns = r[0];
					data = r[1];
				}
				if( options.colour == "true" ){
					maxMin = max_min( data );
					colour = true;
				}
			}

			// Add the rest of the columns when we know if we are colouring in the cells
			for( var k in xKeys.sort() ){
				var column ={
					"field": xKeys[k],
					"title": timelineLink(xKeys[k],catxData[xKeys[k]].name,"x"),
					"sortable": true

				};
				if(colour){
					column.cellStyle= createColourCell(maxMin);
				}
				columns.push(column);
			}
			columns.push(
				{
					"field": "total",
					"title": "Total",
                    "class": "total-col",
					sortable: true
				}
			);

			//Draw the table
            var framework = "
" +
                            "
" +
                            "

";

            $("#cross-wrapper").html( framework );
			$("#cross-table").bootstrapTable({
				columns: columns,
				data: data,
				clickToSelect: true
			});

			console.log(columns);
			console.log(data);
		}
	});
}

function createColourCell(maxMin){
	// Returns a function that colours in the cells according to their value
	function cc(value, row, index){
        if(row.cases != "Total"){
		    var perc = (value-maxMin[0])/(maxMin[1]-maxMin[0]);
		    return {css: {"background-color": "rgba(217, 105, 42, " + perc +")"}};
        }
        return {classes: "total-row"};
	}
	return cc;
}

function max_min(data){
	// Returns max and min of all numbers in table
	var list = [];
	for( var r=1; r<data.length; r++ ){
		var row = data[r];
		for(var x in row){
			if( x != "cases" && x != "total" && row.cases != "Total"){
				list.push(Number(row[x]));
			}
		}
	}
	var maximum = Math.max.apply( Math, list );
	var minimum = Math.min.apply( Math, list );
	return [minimum,maximum];
}

function timelineLink(id, name, axis){
	//helper function to create links to activate the timeline
	return '' + name + "";
}

function createTimeline(id, cat, options){

	console.log( "Drawing timeline" );

	//These variable will hold all the JSON data from the api, when the AJAX requests are complete.
	var queryData, category, variable;

	//Assemble the main query url according to the given options.
	var main_query_url = api_root + '/query_variable/' + id + '/' + cat;
	if( options.start_date && options.end_date ){
		main_query_url += '/' + options.start_date + '/' + options.end_date;
	}
	main_query_url += '?use_ids=1';
	if( options.location ){
		main_query_url += '&only_loc=' + options.location;
	}

	//Execute multiple json requests simultaneously.
	var deferreds = [
		$.getJSON( main_query_url, function(data) {
			queryData = data;
		}),
		$.getJSON( api_root + "/variables/" + cat,  function(data) {
			category = data;
		}),
		$.getJSON( api_root + "/variable/" + id, function(data) {
			variable = data;
		})
	];

	//Run the AJAX reuqests asynchronously and act when they have all completed.
	$.when.apply( $, deferreds ).then(function() {

		var yKeys = Object.keys(queryData);
		var xKeys = Object.keys(queryData[yKeys[0]].weeks);
		var columns = [
			{
				"field": "cases",
				"title": "#Cases with "+ variable.name,
				"align": "left",
				"class": "header"
			}
		];
		var data = [];

		//For each key in the y category, form the row from x category data.
		for( var y in yKeys.sort() ){
            console.log( yKeys[y] );
			var datum ={
				"cases": category[yKeys[y]].name
			};
			var total = 0;
			for( var x in xKeys ){
				datum["week_" + xKeys[x]] = queryData[yKeys[y]].weeks[xKeys[x]];
				total += queryData[yKeys[y]].weeks[xKeys[x]];
			}
			datum.total = total;
			data.push( datum );
		}
		// Sort out options
		colour = false;
		if( options ){
			if( options.strip ){
				var r = strip(columns, data, options.strip );
				columns = r[0];
				data = r[1];
			}
			if( options.colour == "true" ){
				maxMin = max_min( data );
				colour = true;
			}
		}
		// Add remaining columns
		for( var k in xKeys.sort(function(a, b){return a-b;}) ){
			var column ={
				"field": "week_"+ xKeys[k],
				"title": "Week " + xKeys[k],
				"sortable": true
			};
			if(colour){
				column.cellStyle= createColourCell(maxMin);
			}
			columns.push(column);
		}
		columns.push(
			{
				"field": "total",
				"title": "Total",
				sortable: true
			}
		);
		//Draw!
        var framework = "
" +
                        "
" +
                        "

";
        $("#timeline-wrapper").html( framework );
		$("#timeline-table").bootstrapTable({
			columns: columns,
			data: data
		});

	});
}

function transpose( jsTable ){
	var newTable = jsTable[0].map(function(col, i) {
		return jsTable.map(function(row) {
			return row[i];
		});
	});
	return newTable;
}

function strip( columns, data, axis ){

	function stripRows(data){
		console.log("StripRows");
		//Store a list of rows to be removed.
		var remove = [];
		//For each row iterate through it's elements to seeif all are empty.
		for( var y=0; y<data.length; y++ ){
			var row = data[y];
			var empty = true;
			for( var x in row ){
				if( x != "cases" && Number(row[x]) !== 0 ) empty = false;
			}
			if( empty ) {
				remove.push(y);
			}
		}
		for( var i = remove.length-1; i>=0; i-- ) data.splice( remove[i], 1 );
		console.log(data.length);
		//Remove all empty rows (starting from the last to avoid screwing up indexes).
		return data;
	}

	// if( axis.indexOf('y') != -1 || axis.indexOf('Y') != -1 ){
	// 	table = stripRows( table );
	// }

	// if( axis.indexOf('x') != -1 || axis.indexOf('X') != -1 ){
	// 	table = transpose( stripRows( transpose( table ) ) );
	// }
	data = stripRows(data);
	return [columns, data];

}

<|endoftext|>


<commit_before>import Service from '@ember/service';
import { isPresent } from '@ember/utils';
import { A } from '@ember/array';
import getCompactVersion from 'ember-api-docs/utils/get-compact-version';

export default Service.extend({

  availableProjectVersions: {
    'ember': A(),
    'ember-data':A()
  },

  projectRevMap: {},

  addToProjectRevMap(projectVersionKey, projectRevDoc) {
    let projectRevMap = this.get('projectRevMap');
    if (!isPresent(projectRevMap[projectVersionKey])) {
      projectRevMap[projectVersionKey] =  projectRevDoc;
      this.set('projectRevMap', projectRevMap);
    }
  },

  getRevId(project, version, type, id) {
    let encodedId = encodeURIComponent(id);
    return this.get('projectRevMap')[`${project}-${version}`][type][encodedId];
  },

  getEncodedModulesFromProjectRev(id) {
    return Object.keys(this.get('projectRevMap')[id].module).sort();
  },

  initializeStore(availableProjectVersions, projectRevMap) {
    this.setProperties({
      availableProjectVersions: {
        'ember': A(availableProjectVersions['ember']),
        'ember-data': A(availableProjectVersions['ember-data'])
      },
      projectRevMap: projectRevMap
    })
  },

  getFullVersion(projectName, compactProjVersion) {
    const availProjVersions = this.get(`availableProjectVersions.${projectName}`);
    let filtered = availProjVersions.filter(function(v, index) {
      // shorten versions to 2 digits and compare them. 2.15.0 becomes 2.15
      let vTrimmed = getCompactVersion(v);
      let compactProjTrimmed = getCompactVersion(compactProjVersion);
      return vTrimmed === compactProjTrimmed
    })
    // since there can be multiple full versions that match the compact version,
    // use the most recent one.
    return filtered.reduce((accumulator, current) => accumulator.split('.')[2] < current.split('.')[2] ? current : accumulator);
  }
});
<commit_msg>simplify filter command in getFullVersion<commit_after>import Service from '@ember/service';
import { isPresent } from '@ember/utils';
import { A } from '@ember/array';
import getCompactVersion from 'ember-api-docs/utils/get-compact-version';

export default Service.extend({

  availableProjectVersions: {
    'ember': A(),
    'ember-data':A()
  },

  projectRevMap: {},

  addToProjectRevMap(projectVersionKey, projectRevDoc) {
    let projectRevMap = this.get('projectRevMap');
    if (!isPresent(projectRevMap[projectVersionKey])) {
      projectRevMap[projectVersionKey] =  projectRevDoc;
      this.set('projectRevMap', projectRevMap);
    }
  },

  getRevId(project, version, type, id) {
    let encodedId = encodeURIComponent(id);
    return this.get('projectRevMap')[`${project}-${version}`][type][encodedId];
  },

  getEncodedModulesFromProjectRev(id) {
    return Object.keys(this.get('projectRevMap')[id].module).sort();
  },

  initializeStore(availableProjectVersions, projectRevMap) {
    this.setProperties({
      availableProjectVersions: {
        'ember': A(availableProjectVersions['ember']),
        'ember-data': A(availableProjectVersions['ember-data'])
      },
      projectRevMap: projectRevMap
    })
  },

  getFullVersion(projectName, compactProjVersion) {
    const availProjVersions = this.get(`availableProjectVersions.${projectName}`);
    let filtered = availProjVersions.filter((v, index) => getCompactVersion(v) === getCompactVersion(compactProjVersion));
    // since there can be multiple full versions that match the compact version, use the most recent one.
    return filtered.reduce((accumulator, current) => accumulator.split('.')[2] < current.split('.')[2] ? current : accumulator);
  }
});
<|endoftext|>