<commit_before>var util = require('util');
var sjcl = require('./utils').sjcl;
var stypes = require('./serializedtypes');
var hashprefixes = require('./hashprefixes');

var UInt256 = require('./uint256').UInt256;
var SerializedObject = require('./serializedobject').SerializedObject;

function SHAMap() {
  this.root = new SHAMapTreeNodeInner();
};

SHAMap.prototype.add_item = function (tag, node, type) {
  var node = new SHAMapTreeNodeLeaf(tag, node, type);
  this.root.add_item(tag, node);
};

SHAMap.prototype.hash = function () {
  return this.root.hash();
};

/**
 * Abstract class representing a node in a SHAMap tree.
 *
 * Can be either SHAMapTreeNodeInner or SHAMapTreeNodeLeaf.
 */
function SHAMapTreeNode() {

};

SHAMapTreeNode.TYPE_INNER = 1;
SHAMapTreeNode.TYPE_TRANSACTION_NM = 2;
SHAMapTreeNode.TYPE_TRANSACTION_MD = 3;
SHAMapTreeNode.TYPE_ACCOUNT_STATE = 4;

SHAMapTreeNode.prototype.add_item = function (tag_segment, node) {
  throw new Error("Called unimplemented virtual method SHAMapTreeNode#add_item.");
};

SHAMapTreeNode.prototype.hash = function () {
  throw new Error("Called unimplemented virtual method SHAMapTreeNode#hash.");
};

/**
 * Inner (non-leaf) node in a SHAMap tree.
 */
function SHAMapTreeNodeInner(depth) {
  SHAMapTreeNode.call(this);

  this.leaves = {};

  this.type = SHAMapTreeNode.INNER;

  // TODO
  this.depth == depth == null ? 0 : depth;

  this.empty = true;
}

util.inherits(SHAMapTreeNodeInner, SHAMapTreeNode);

SHAMapTreeNodeInner.prototype.add_item = function (tag_segment, node) {
  var current_node = this.get_node(tag_segment[0]);

  if (current_node) {
    // A node already exists in this slot

    if (current_node instanceof SHAMapTreeNodeInner) {
      // There is an inner node, so we need to go deeper
      current_node.add_item(tag_segment.slice(1), node);
    } else if (current_node.get_segment() === tag_segment) {
      // Collision
      throw new Error("Tried to add a node to a SHAMap that was already in there.");
    } else {
      // Turn it into an inner node
      var new_inner_node = new SHAMapTreeNodeInner();

      // Move the existing leaf node down one level
      current_node.set_segment(current_node.get_segment().slice(1));
      new_inner_node.set_node(current_node.get_segment()[0], current_node);

      // Add the new node next to it
      new_inner_node.add_item(tag_segment.slice(1), node);

      // And place the newly created inner node in the slot
      this.set_node(tag_segment[0], new_inner_node);
    }
  } else {
    // Neat, we have a nice open spot for the new node
    node.set_segment(tag_segment);
    this.set_node(tag_segment[0], node);
  }
};

/**
 * Overwrite the node that is currently in a given slot.
 */
SHAMapTreeNodeInner.prototype.set_node = function (slot, node) {
  this.leaves[slot] = node;
  this.empty = false;
};

SHAMapTreeNodeInner.prototype.get_node = function (slot) {
  return this.leaves[slot];
};

SHAMapTreeNodeInner.prototype.hash = function () {
  if (this.empty) {
    return UInt256.from_hex(UInt256.HEX_ZERO);
  }

  var hash_buffer = new SerializedObject();
  var buffer = [];
  for (var i = 0; i < 16; i++) {
    var leafHash = UInt256.from_hex(UInt256.HEX_ZERO);
    var slot = i.toString(16).toUpperCase();
    if ("object" === typeof this.leaves[slot]) {
      leafHash = this.leaves[slot].hash();
    }
    hash_buffer.append(leafHash.to_bytes());
  }

  var hash = hash_buffer.hash(hashprefixes.HASH_INNER_NODE);

  return UInt256.from_bits(hash);
};

/**
 * Leaf node in a SHAMap tree.
 */
function SHAMapTreeNodeLeaf(tag, node, type) {
  SHAMapTreeNode.call(this);

  if ("string" === typeof tag) {
    tag = UInt256.from_hex(tag);
  } else if (tag instanceof UInt256) {
    // Type is already the right one
  } else {
    throw new Error("Tag is unexpected type.");
  }

  this.tag = tag;
  this.tag_segment = null;

  this.type = type;

  this.node = node;
}
util.inherits(SHAMapTreeNodeLeaf, SHAMapTreeNode);

SHAMapTreeNodeLeaf.prototype.get_segment = function (segment) {
  return this.tag_segment;
};

SHAMapTreeNodeLeaf.prototype.set_segment = function (segment) {
  this.tag_segment = segment;
};

SHAMapTreeNodeLeaf.prototype.hash = function () {
  var buffer = new SerializedObject();
  switch (this.type) {
    case SHAMapTreeNode.TYPE_ACCOUNT_STATE:
      buffer.append(this.node);
      buffer.append(this.tag.to_bytes());
      return buffer.hash(hashprefixes.HASH_LEAF_NODE);
    case SHAMapTreeNode.TYPE_TRANSACTION_NM:
      return this.tag;
    case SHAMapTreeNode.TYPE_TRANSACTION_MD:
      buffer.append(this.node);
      buffer.append(this.tag.to_bytes());
      return buffer.hash(hashprefixes.HASH_TX_NODE);
    default:
      throw new Error("Tried to hash a SHAMap node of unknown type.");
  }
};

exports.SHAMap = SHAMap;
exports.SHAMapTreeNode = SHAMapTreeNode;
exports.SHAMapTreeNodeInner = SHAMapTreeNodeInner;
exports.SHAMapTreeNodeLeaf = SHAMapTreeNodeLeaf;
<commit_msg>Less slicing and dicing of tag_segment/indexes<commit_after>var util = require('util');
var sjcl = require('./utils').sjcl;
var stypes = require('./serializedtypes');
var hashprefixes = require('./hashprefixes');

var UInt256 = require('./uint256').UInt256;
var SerializedObject = require('./serializedobject').SerializedObject;

function SHAMap() {
  this.root = new SHAMapTreeNodeInner(0);
};

SHAMap.prototype.add_item = function (tag, node, type) {
  var node = new SHAMapTreeNodeLeaf(tag, node, type);
  this.root.add_item(tag, node);
};

SHAMap.prototype.hash = function () {
  return this.root.hash();
};

/**
 * Abstract class representing a node in a SHAMap tree.
 *
 * Can be either SHAMapTreeNodeInner or SHAMapTreeNodeLeaf.
 */
function SHAMapTreeNode() {

};

SHAMapTreeNode.TYPE_INNER = 1;
SHAMapTreeNode.TYPE_TRANSACTION_NM = 2;
SHAMapTreeNode.TYPE_TRANSACTION_MD = 3;
SHAMapTreeNode.TYPE_ACCOUNT_STATE = 4;

SHAMapTreeNode.prototype.add_item = function (tag_segment, node) {
  throw new Error("Called unimplemented virtual method SHAMapTreeNode#add_item.");
};

SHAMapTreeNode.prototype.hash = function () {
  throw new Error("Called unimplemented virtual method SHAMapTreeNode#hash.");
};

/**
 * Inner (non-leaf) node in a SHAMap tree.
 */
function SHAMapTreeNodeInner(depth) {
  SHAMapTreeNode.call(this);

  this.leaves = {};

  this.type = SHAMapTreeNode.INNER;
  this.depth = depth == null ? 0 : depth;

  this.empty = true;
}

util.inherits(SHAMapTreeNodeInner, SHAMapTreeNode);

/*
* @param tag_segment {String} (equates to a ledger entries `index`)
*/
SHAMapTreeNodeInner.prototype.add_item = function (tag_segment, node) {
  var depth = this.depth;
  var existing_node = this.get_node(tag_segment[depth]);

  if (existing_node) {
    // A node already exists in this slot
    if (existing_node instanceof SHAMapTreeNodeInner) {
      // There is an inner node, so we need to go deeper
      existing_node.add_item(tag_segment, node);
    } else if (existing_node.get_segment() === tag_segment) {
      // Collision
      throw new Error("Tried to add a node to a SHAMap that was already in there.");
    } else {
      // Turn it into an inner node
      var new_inner_node = new SHAMapTreeNodeInner(depth + 1);

      // Parent new and existing node
      new_inner_node.add_item(existing_node.get_segment(), existing_node);
      new_inner_node.add_item(tag_segment, node);

      // And place the newly created inner node in the slot
      this.set_node(tag_segment[depth], new_inner_node);
    }
  } else {
    // Neat, we have a nice open spot for the new node
    node.set_segment(tag_segment);
    this.set_node(tag_segment[depth], node);
  }
};

/**
 * Overwrite the node that is currently in a given slot.
 */
SHAMapTreeNodeInner.prototype.set_node = function (slot, node) {
  this.leaves[slot] = node;
  this.empty = false;
};

SHAMapTreeNodeInner.prototype.get_node = function (slot) {
  return this.leaves[slot];
};

SHAMapTreeNodeInner.prototype.hash = function () {
  if (this.empty) {
    return UInt256.from_hex(UInt256.HEX_ZERO);
  }

  var hash_buffer = new SerializedObject();
  var buffer = [];
  for (var i = 0; i < 16; i++) {
    var leafHash = UInt256.from_hex(UInt256.HEX_ZERO);
    var slot = i.toString(16).toUpperCase();
    if ("object" === typeof this.leaves[slot]) {
      leafHash = this.leaves[slot].hash();
    }
    hash_buffer.append(leafHash.to_bytes());
  }

  var hash = hash_buffer.hash(hashprefixes.HASH_INNER_NODE);

  return UInt256.from_bits(hash);
};

/**
 * Leaf node in a SHAMap tree.
 */
function SHAMapTreeNodeLeaf(tag, node, type) {
  SHAMapTreeNode.call(this);

  if ("string" === typeof tag) {
    tag = UInt256.from_hex(tag);
  } else if (tag instanceof UInt256) {
    // Type is already the right one
  } else {
    throw new Error("Tag is unexpected type.");
  }

  this.tag = tag;
  this.tag_segment = null;

  this.type = type;

  this.node = node;
}
util.inherits(SHAMapTreeNodeLeaf, SHAMapTreeNode);

SHAMapTreeNodeLeaf.prototype.get_segment = function (segment) {
  return this.tag_segment;
};

SHAMapTreeNodeLeaf.prototype.set_segment = function (segment) {
  this.tag_segment = segment;
};

SHAMapTreeNodeLeaf.prototype.hash = function () {
  var buffer = new SerializedObject();
  switch (this.type) {
    case SHAMapTreeNode.TYPE_ACCOUNT_STATE:
      buffer.append(this.node);
      buffer.append(this.tag.to_bytes());
      return buffer.hash(hashprefixes.HASH_LEAF_NODE);
    case SHAMapTreeNode.TYPE_TRANSACTION_NM:
      return this.tag;
    case SHAMapTreeNode.TYPE_TRANSACTION_MD:
      buffer.append(this.node);
      buffer.append(this.tag.to_bytes());
      return buffer.hash(hashprefixes.HASH_TX_NODE);
    default:
      throw new Error("Tried to hash a SHAMap node of unknown type.");
  }
};

exports.SHAMap = SHAMap;
exports.SHAMapTreeNode = SHAMapTreeNode;
exports.SHAMapTreeNodeInner = SHAMapTreeNodeInner;
exports.SHAMapTreeNodeLeaf = SHAMapTreeNodeLeaf;
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 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.
 *
 */

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

    var Fluxxor = require("fluxxor"),
        Immutable = require("immutable"),
        _ = require("lodash");

    var events = require("../events"),
        collection = require("js/util/collection"),
        log = require("js/util/log");

    var DialogStore = Fluxxor.createStore({
        /**
         * The set of open Dialog IDs
         *
         * @private
         * @type {Immutable.Set.<string>}
         */
        _openDialogs: Immutable.Set(),

        /**
         * Information/state for all registered dialogs
         *
         * The value of the map represents the state of the given dialog.
         * It is a map with the following optional keys:
         *     policy: Immutable.Map.<string, boolean>,
         *     documentID: number,
         *     selectionType: string

         * @private
         * @type {Immutable.Map.<string, Immutable.Map<string, object>>}
         */
        _registeredDialogs: Immutable.Map(),

        initialize: function () {
            this.bindActions(
                events.dialog.REGISTER_DIALOG, this._handleRegister,
                events.dialog.DEREGISTER_DIALOG, this._handleDeregister,
                events.dialog.OPEN_DIALOG, this._handleOpen,
                events.dialog.CLOSE_DIALOG, this._handleClose,
                events.dialog.CLOSE_ALL_DIALOGS, this._handleCloseAll,
                events.document.SELECT_LAYERS_BY_ID, this._handleSelectionChange,
                events.document.SELECT_LAYERS_BY_INDEX, this._handleSelectionChange,
                events.document.GROUP_SELECTED, this._handleSelectionChange,
                events.document.CLOSE_DOCUMENT, this._handleDocumentChange,
                events.document.SELECT_DOCUMENT, this._handleDocumentChange
            );
        },

        getState: function () {
            return {
                openDialogs: this._openDialogs,
                appIsModal: this._openDialogs.contains("first-launch-dialog")
            };
        },

        /**
         * Fetch the current document ID, or null if there is no current document.
         *
         * @private
         * @return {?number}
         */
        _getCurrentDocumentID: function () {
            var applicationStore = this.flux.store("application");

            return applicationStore.getCurrentDocumentID();
        },

        /**
         * Fetch the type of the current layer selection, or none if there is no
         * consistent type.
         *
         * @private
         * @return {string}
         */
        _getCurrentSelectionType: function () {
            var applicationStore = this.flux.store("application"),
                currentDocument = applicationStore.getCurrentDocument();

            if (!currentDocument) {
                return null;
            }

            var kinds = collection.pluck(currentDocument.layers.selected, "kind");

            return collection.uniformValue(kinds);
        },

        /**
         * Handle a registerDialog event
         * (does not emit a change event)
         * merges state if this event has already been registered
         *
         * @private
         * @param {{id: string, dismissalPolicy: object}} payload
         */
        _handleRegister: function (payload) {
            var id = payload.id,
                state = {
                    policy: Immutable.Map(payload.dismissalPolicy)
                };

            this._registeredDialogs = this._registeredDialogs.update(id, Immutable.Map(), function (val) {
                return val.merge(state);
            });
        },

        /**
         * Handle a deregisterDialog event
         * emits a change event if this dialog was open
         *
         * @private
         * @param {{id: string, dismissalPolicy: object}} payload
         */
        _handleDeregister: function (payload) {
            var id = payload.id;
            this._registeredDialogs = this._registeredDialogs.delete(id);
            if (this._openDialogs.has(id)) {
                this._openDialogs = this._openDialogs.delete(id);
                this.emit("change");
            }
        },

        /**
         * Handle an open-dialog event.
         * If this dialog has not been pre-registered, it must contain a dismissal policy in the payload
         * Otherwise, the optional dismissal policy will overwrite the previous
         *
         * @private
         * @param {{id: string, dismissalPolicy: object=}} payload
         */
        _handleOpen: function (payload) {
            var id = payload.id,
                newState = Immutable.Map({
                    policy: Immutable.Map(payload.dismissalPolicy || {})
                });

            // register on the fly, but warn if a dismissal policy was not provided
            if (!this._registeredDialogs.has(id)) {
                if (_.isEmpty(payload.dismissalPolicy)) {
                    log.warn("Opening an un-registered dialog without providing a dismissalPolicy");
                }
            } else {
                // merge the new policy, if it was provided
                newState = this._registeredDialogs.get(id).merge(newState);
            }

            if (newState.getIn(["policy", "documentChange"])) {
                newState = newState.set("documentID", this._getCurrentDocumentID());
            }

            if (newState.getIn(["policy", "selectionTypeChange"])) {
                newState = newState.set("selectionType", this._getCurrentSelectionType());
            }

            // update the registry
            this._registeredDialogs = this._registeredDialogs.set(id, newState);

            // Close dialogs with the "openDialog" dismissal policy
            // and add this new one
            this._openDialogs = this._openDialogs
                .filterNot(function (dialogID) {
                    return this._registeredDialogs.getIn([dialogID, "policy", "dialogOpen"], false);
                }, this)
                .add(id);

            this.emit("change");
        },

        /**
         * Handle a close-dialog event.
         *
         * @private
         * @param {{id: number}} payload
         */
        _handleClose: function (payload) {
            this._openDialogs = this._openDialogs.delete(payload.id);
            this.emit("change");
        },

        /**
         * Handle a close-all-dialogs event.
         *
         * @private
         */
        _handleCloseAll: function () {
            this._openDialogs = this._openDialogs.clear();
            this.emit("change");
        },

        /**
         * Close all dialogs with a documentChange dismissal policy.
         *
         * @private
         */
        _handleDocumentChange: function () {
            this.waitFor(["document", "application"], function () {
                this._openDialogs = this._openDialogs.filterNot(function (dialogID) {
                    var state = this._registeredDialogs.get(dialogID);
                    return state.get("policy").get("documentChange") &&
                        state.get("documentID") !== this._getCurrentDocumentID();
                }, this);

                this.emit("change");
            });
        },

        /**
         * Close all dialogs with a selectionTypeChange dismissal policy.
         *
         * @private
         */
        _handleSelectionChange: function () {
            this.waitFor(["document"], function () {
                this._openDialogs = this._openDialogs.filterNot(function (dialogID) {
                    var state = this._registeredDialogs.get(dialogID);
                    return state.get("policy").get("selectionTypeChange") &&
                        state.get("selectionType") !== this._getCurrentSelectionType();
                }, this);

                this.emit("change");
            });
        }
    });

    module.exports = DialogStore;
});
<commit_msg>Added keyboard shortcut as a modal state<commit_after>/*
 * Copyright (c) 2014 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.
 *
 */

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

    var Fluxxor = require("fluxxor"),
        Immutable = require("immutable"),
        _ = require("lodash");

    var events = require("../events"),
        collection = require("js/util/collection"),
        log = require("js/util/log");

    var DialogStore = Fluxxor.createStore({
        /**
         * The set of open Dialog IDs
         *
         * @private
         * @type {Immutable.Set.<string>}
         */
        _openDialogs: Immutable.Set(),

        /**
         * Information/state for all registered dialogs
         *
         * The value of the map represents the state of the given dialog.
         * It is a map with the following optional keys:
         *     policy: Immutable.Map.<string, boolean>,
         *     documentID: number,
         *     selectionType: string

         * @private
         * @type {Immutable.Map.<string, Immutable.Map<string, object>>}
         */
        _registeredDialogs: Immutable.Map(),

        initialize: function () {
            this.bindActions(
                events.dialog.REGISTER_DIALOG, this._handleRegister,
                events.dialog.DEREGISTER_DIALOG, this._handleDeregister,
                events.dialog.OPEN_DIALOG, this._handleOpen,
                events.dialog.CLOSE_DIALOG, this._handleClose,
                events.dialog.CLOSE_ALL_DIALOGS, this._handleCloseAll,
                events.document.SELECT_LAYERS_BY_ID, this._handleSelectionChange,
                events.document.SELECT_LAYERS_BY_INDEX, this._handleSelectionChange,
                events.document.GROUP_SELECTED, this._handleSelectionChange,
                events.document.CLOSE_DOCUMENT, this._handleDocumentChange,
                events.document.SELECT_DOCUMENT, this._handleDocumentChange
            );
        },

        getState: function () {
            return {
                openDialogs: this._openDialogs,
                appIsModal: this._openDialogs.contains("first-launch-dialog") || this._openDialogs.contains("keyboard-shortcut-dialog")
            };
        },

        /**
         * Fetch the current document ID, or null if there is no current document.
         *
         * @private
         * @return {?number}
         */
        _getCurrentDocumentID: function () {
            var applicationStore = this.flux.store("application");

            return applicationStore.getCurrentDocumentID();
        },

        /**
         * Fetch the type of the current layer selection, or none if there is no
         * consistent type.
         *
         * @private
         * @return {string}
         */
        _getCurrentSelectionType: function () {
            var applicationStore = this.flux.store("application"),
                currentDocument = applicationStore.getCurrentDocument();

            if (!currentDocument) {
                return null;
            }

            var kinds = collection.pluck(currentDocument.layers.selected, "kind");

            return collection.uniformValue(kinds);
        },

        /**
         * Handle a registerDialog event
         * (does not emit a change event)
         * merges state if this event has already been registered
         *
         * @private
         * @param {{id: string, dismissalPolicy: object}} payload
         */
        _handleRegister: function (payload) {
            var id = payload.id,
                state = {
                    policy: Immutable.Map(payload.dismissalPolicy)
                };

            this._registeredDialogs = this._registeredDialogs.update(id, Immutable.Map(), function (val) {
                return val.merge(state);
            });
        },

        /**
         * Handle a deregisterDialog event
         * emits a change event if this dialog was open
         *
         * @private
         * @param {{id: string, dismissalPolicy: object}} payload
         */
        _handleDeregister: function (payload) {
            var id = payload.id;
            this._registeredDialogs = this._registeredDialogs.delete(id);
            if (this._openDialogs.has(id)) {
                this._openDialogs = this._openDialogs.delete(id);
                this.emit("change");
            }
        },

        /**
         * Handle an open-dialog event.
         * If this dialog has not been pre-registered, it must contain a dismissal policy in the payload
         * Otherwise, the optional dismissal policy will overwrite the previous
         *
         * @private
         * @param {{id: string, dismissalPolicy: object=}} payload
         */
        _handleOpen: function (payload) {
            var id = payload.id,
                newState = Immutable.Map({
                    policy: Immutable.Map(payload.dismissalPolicy || {})
                });

            // register on the fly, but warn if a dismissal policy was not provided
            if (!this._registeredDialogs.has(id)) {
                if (_.isEmpty(payload.dismissalPolicy)) {
                    log.warn("Opening an un-registered dialog without providing a dismissalPolicy");
                }
            } else {
                // merge the new policy, if it was provided
                newState = this._registeredDialogs.get(id).merge(newState);
            }

            if (newState.getIn(["policy", "documentChange"])) {
                newState = newState.set("documentID", this._getCurrentDocumentID());
            }

            if (newState.getIn(["policy", "selectionTypeChange"])) {
                newState = newState.set("selectionType", this._getCurrentSelectionType());
            }

            // update the registry
            this._registeredDialogs = this._registeredDialogs.set(id, newState);

            // Close dialogs with the "openDialog" dismissal policy
            // and add this new one
            this._openDialogs = this._openDialogs
                .filterNot(function (dialogID) {
                    return this._registeredDialogs.getIn([dialogID, "policy", "dialogOpen"], false);
                }, this)
                .add(id);

            this.emit("change");
        },

        /**
         * Handle a close-dialog event.
         *
         * @private
         * @param {{id: number}} payload
         */
        _handleClose: function (payload) {
            this._openDialogs = this._openDialogs.delete(payload.id);
            this.emit("change");
        },

        /**
         * Handle a close-all-dialogs event.
         *
         * @private
         */
        _handleCloseAll: function () {
            this._openDialogs = this._openDialogs.clear();
            this.emit("change");
        },

        /**
         * Close all dialogs with a documentChange dismissal policy.
         *
         * @private
         */
        _handleDocumentChange: function () {
            this.waitFor(["document", "application"], function () {
                this._openDialogs = this._openDialogs.filterNot(function (dialogID) {
                    var state = this._registeredDialogs.get(dialogID);
                    return state.get("policy").get("documentChange") &&
                        state.get("documentID") !== this._getCurrentDocumentID();
                }, this);

                this.emit("change");
            });
        },

        /**
         * Close all dialogs with a selectionTypeChange dismissal policy.
         *
         * @private
         */
        _handleSelectionChange: function () {
            this.waitFor(["document"], function () {
                this._openDialogs = this._openDialogs.filterNot(function (dialogID) {
                    var state = this._registeredDialogs.get(dialogID);
                    return state.get("policy").get("selectionTypeChange") &&
                        state.get("selectionType") !== this._getCurrentSelectionType();
                }, this);

                this.emit("change");
            });
        }
    });

    module.exports = DialogStore;
});
<|endoftext|>


<commit_before>/* globals define, forge */
define(function(require, exports, module) {
    var Modifier = require("famous/core/Modifier");
    var Transform = require("famous/core/Transform");
    var View = require("famous/core/View");
    var ContainerSurface = require("famous/surfaces/ContainerSurface");

    var Templates = require("Templates");
    var NativeView = require("views/NativeView");
    var ListView = require("views/ListView");
    var SettingsView = require("views/SettingsView");

    /**
     * view constructor
     */
    function AppView() {
        View.apply(this, arguments);

        _createNativeView.call(this);
        _createSettingsView.call(this);
        _createListView.call(this);

        _createEvents.call(this);

        this.trigger("clickRefresh");
    }
    AppView.prototype = Object.create(View.prototype);
    AppView.prototype.constructor = AppView;

    /**
     * view state variables
     */
    AppView.DEFAULT_OPTIONS = {
        currentTag: "Popular",
        transition: {
            duration: 400,
            curve: "easeInOut"
        }
    };

    /**
     * creates a view that manages native UI elements
     */
    function _createNativeView() {
        this.nativeView = new NativeView();
        this.subscribe(this.nativeView);
    }

    /**
     * creates a view that manages the slide-out Settings menu
     */
    function _createSettingsView() {
        this.settingsContainer = new ContainerSurface({
            properties: {
                overflow: "hidden",
                backgroundColor: "white"
            }
        });
        this.settingsView = new SettingsView();
        this.subscribe(this.settingsView);
        this.settingsContainer.add(this.settingsView);
        this.add(this.settingsContainer);
    }

    /**
     * creates a view that manages the image timeline
     */
    function _createListView() {
        this.listContainer = new ContainerSurface({
            properties: {
                backgroundColor: "#f4f4f4",
                boxShadow: "0 0 20px rgba(0, 0, 0, 0.5)"
            }
        });
        this.listContainer.context.setPerspective(2000);
        this.listModifier = new Modifier({
            transform: Transform.translate(0, 0, 0.1)
        });
        this.listView = new ListView();
        this.listContainer.add(this.listView);
        this.add(this.listModifier).add(this.listContainer);
    }

    /**
     * configure view event handling
     */
    function _createEvents() {
        this._eventInput.on("clickBurger", function () {
            _openBurgerMenu.call(this);
        }.bind(this));
        this._eventInput.on("clickDone", function () {
            _closeBurgerMenu.call(this);
        }.bind(this));
        this._eventInput.on("clickRefresh", function () {
            _refreshListView.call(this);
        }.bind(this));
        this._eventInput.on("clickCamera", function () {
            _takePhotograph.call(this);
        }.bind(this));
        this._eventInput.on("clickTag", function (tag) {
            this.options.currentTag = tag;
            _refreshListView.call(this);
            this.nativeView.trigger("clickDone", tag);
        }.bind(this));
    }

    /**
     * toggles the sliding menu
     */
    /*function _toggleMainView() {
        if (this._toggle) {
            this.listModifier.setTransform(Transform.translate(0, 0, 1.0),
                                           this.options.transition);
        } else {
            this.listModifier.setTransform(Transform.translate(this.options.openPosition, 0, 1.0),
                                           this.options.transition);
        }
        this._toggle = !this._toggle;
        return this._toggle;
    }*/

    /**
     * opens the sliding menu
     */
    function _openBurgerMenu() {
        this.listModifier.setTransform(Transform.translate(276, 0, 1.0), {
            duration: 400,
            curve: "easeInOut"
        });
    }

    /**
     * closes the sliding menu
     */
    function _closeBurgerMenu() {
        this.listModifier.setTransform(Transform.translate(0, 0, 1.0), {
            duration: 400,
            curve: "easeInOut"
        });
    }

    /**
     * refresh the image timeline with new items from the remote API
     */
    function _refreshListView() {
        var client_id = "e8f3e3e90a0d466484df7fac556c51da";
        var tag = this.options.currentTag.toLowerCase();
        var url;
        if (tag === "popular") {
            url = "https://api.instagram.com/v1/media/popular";
        } else {
            url = "https://api.instagram.com/v1/tags/" + tag + "/media/recent";
        }
        forge.request.ajax({
            url: url + "?client_id=" + client_id,
            dataType: "json"
        }, function (response) {
            response.data.forEach(function (item) {
                this.listView.addItem(Templates.front(item),
                                      Templates.rear(item));
            }.bind(this));
        }.bind(this), function (error) {
            console.error("Request failed: " + JSON.stringify(error));
        });
    }

    /**
     * take a photograph with the device camera
     */
    function _takePhotograph() {
        forge.file.getImage({
            width: 290,
            source: "camera",
            saveLocation: "file"
        }, function (file) {
            forge.file.URL(file, function (url) {
                var item = {
                    user:    { profile_picture: "img/forge-logo.png",
                               full_name: "Forge" },
                    images:  { low_resolution: { url: url } },
                    caption: { text: "Made with @befamous and @triggercorp" },
                    comments: { data: [
                        { from: { full_name: "antoinevg"  }, text: "feeling excited about #hybrid apps yet?" }
                    ] }
                };
                this.listView.addItem(Templates.front(item),
                                      Templates.rear(item));
            }.bind(this));
        }.bind(this));
    }

    module.exports = AppView;
});
<commit_msg>Fix getImage() size<commit_after>/* globals define, forge */
define(function(require, exports, module) {
    var Modifier = require("famous/core/Modifier");
    var Transform = require("famous/core/Transform");
    var View = require("famous/core/View");
    var ContainerSurface = require("famous/surfaces/ContainerSurface");

    var Templates = require("Templates");
    var NativeView = require("views/NativeView");
    var ListView = require("views/ListView");
    var SettingsView = require("views/SettingsView");

    /**
     * view constructor
     */
    function AppView() {
        View.apply(this, arguments);

        _createNativeView.call(this);
        _createSettingsView.call(this);
        _createListView.call(this);

        _createEvents.call(this);

        this.trigger("clickRefresh");
    }
    AppView.prototype = Object.create(View.prototype);
    AppView.prototype.constructor = AppView;

    /**
     * view state variables
     */
    AppView.DEFAULT_OPTIONS = {
        currentTag: "Popular",
        transition: {
            duration: 400,
            curve: "easeInOut"
        }
    };

    /**
     * creates a view that manages native UI elements
     */
    function _createNativeView() {
        this.nativeView = new NativeView();
        this.subscribe(this.nativeView);
    }

    /**
     * creates a view that manages the slide-out Settings menu
     */
    function _createSettingsView() {
        this.settingsContainer = new ContainerSurface({
            properties: {
                overflow: "hidden",
                backgroundColor: "white"
            }
        });
        this.settingsView = new SettingsView();
        this.subscribe(this.settingsView);
        this.settingsContainer.add(this.settingsView);
        this.add(this.settingsContainer);
    }

    /**
     * creates a view that manages the image timeline
     */
    function _createListView() {
        this.listContainer = new ContainerSurface({
            properties: {
                backgroundColor: "#f4f4f4",
                boxShadow: "0 0 20px rgba(0, 0, 0, 0.5)"
            }
        });
        this.listContainer.context.setPerspective(2000);
        this.listModifier = new Modifier({
            transform: Transform.translate(0, 0, 0.1)
        });
        this.listView = new ListView();
        this.listContainer.add(this.listView);
        this.add(this.listModifier).add(this.listContainer);
    }

    /**
     * configure view event handling
     */
    function _createEvents() {
        this._eventInput.on("clickBurger", function () {
            _openBurgerMenu.call(this);
        }.bind(this));
        this._eventInput.on("clickDone", function () {
            _closeBurgerMenu.call(this);
        }.bind(this));
        this._eventInput.on("clickRefresh", function () {
            _refreshListView.call(this);
        }.bind(this));
        this._eventInput.on("clickCamera", function () {
            _takePhotograph.call(this);
        }.bind(this));
        this._eventInput.on("clickTag", function (tag) {
            this.options.currentTag = tag;
            _refreshListView.call(this);
            this.nativeView.trigger("clickDone", tag);
        }.bind(this));
    }

    /**
     * opens the sliding menu
     */
    function _openBurgerMenu() {
        this.listModifier.setTransform(Transform.translate(276, 0, 1.0), {
            duration: 400,
            curve: "easeInOut"
        });
    }

    /**
     * closes the sliding menu
     */
    function _closeBurgerMenu() {
        this.listModifier.setTransform(Transform.translate(0, 0, 1.0), {
            duration: 400,
            curve: "easeInOut"
        });
    }

    /**
     * refresh the image timeline with new items from the remote API
     */
    function _refreshListView() {
        var client_id = "e8f3e3e90a0d466484df7fac556c51da";
        var tag = this.options.currentTag.toLowerCase();
        var url;
        if (tag === "popular") {
            url = "https://api.instagram.com/v1/media/popular";
        } else {
            url = "https://api.instagram.com/v1/tags/" + tag + "/media/recent";
        }
        forge.request.ajax({
            url: url + "?client_id=" + client_id,
            dataType: "json"
        }, function (response) {
            response.data.forEach(function (item) {
                this.listView.addItem(Templates.front(item),
                                      Templates.rear(item));
            }.bind(this));
        }.bind(this), function (error) {
            console.error("Request failed: " + JSON.stringify(error));
        });
    }

    /**
     * take a photograph with the device camera
     */
    function _takePhotograph() {
        forge.file.getImage({
            width: 300,
            source: "camera",
            saveLocation: "file"
        }, function (file) {
            forge.file.URL(file, function (url) {
                var item = {
                    user:    { profile_picture: "img/forge-logo.png",
                               full_name: "Forge" },
                    images:  { low_resolution: { url: url } },
                    caption: { text: "Made with @befamous and @triggercorp" },
                    comments: { data: [
                        { from: { full_name: "antoinevg"  }, text: "feeling excited about #hybrid apps yet?" }
                    ] }
                };
                this.listView.addItem(Templates.front(item),
                                      Templates.rear(item));
            }.bind(this));
        }.bind(this));
    }

    module.exports = AppView;
});
<|endoftext|>


<commit_before>"use strict";

var App = App || {};

let MapView = function(div) {
  let self = {
    map: null,
    serviceLayer: null,
    currentLocationMarker: null,
    icons: {},

    iconColorNames: ["blue", "red", "green", "orange", "yellow", "violet", "grey", "black"],
    iconColors: {
      "blue": "#2e84cb",
      "red": "#cb2d40",
      "green": "#28ad25",
      "orange": "#cc852a",
      "yellow": "#cac428",
      "violet": "#9c2bcb",
      "grey": "#7b7b7b",
      "black": "#3e3e3e"
    },

    rectLayer: null,
    rects: {},
    rectColors: d3.schemeCategory10.slice(0),
    totalRects: 0,

    choroplethLayer: null,
    choropleth: null
  };

  init();

  function init() {
    initIcons(); // create icon references for map use
    createMap();
  }

  function createMap() {
    console.log(d3.select("#" + div).node().clientWidth);

    self.map = L.map(div);
    console.log(self.map.getSize());
    // create the map layer using data from openstreetmap

    var osmUrl = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; // normal
    // var osmUrl = 'http://a.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png'; // dark
    // var osmUrl = 'https://a.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png'; // light

    var osmAttrib = 'Map data © OpenStreetMap contributors';

    var osm = new L.TileLayer(osmUrl, {
      minZoom: 11,
      maxZoom: 18,
      zoomSnap: 0.25,
      zoomDelta: 0.25,
      attribution: osmAttrib
    });

    self.map.addLayer(osm);
    self.map.setView([41.779786, -87.644778], 15);

    self.choroplethLayer = L.layerGroup([]).addTo(self.map);
    self.rectLayer = L.layerGroup([]).addTo(self.map);
    self.serviceGroup = L.layerGroup([]).addTo(self.map);
    self.map.zoomControl.setPosition('bottomright');

    // causes map to recalculate size... (I shouldn't need to do this)
    // setTimeout(function() {
    //   self.map.invalidateSize();
    // }, 0);
  }

  // initialize the different icon options by color
  function initIcons() {
    for (let color of self.iconColorNames) {
      self.icons[color] = new L.Icon({
        iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-' + color + '.png',
        shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
        iconSize: [25, 41],
        iconAnchor: [12, 41],
        popupAnchor: [1, -34],
        shadowSize: [41, 41]
      });
    }
  }

  function plotServices(englewoodLocations) {
    self.serviceGroup.clearLayers();

    // iterate through the social services location file
    for (let loc of englewoodLocations) {
      // convert the X and Y values to lat and lng for clarity
      let lat = loc.Y,
        lng = loc.X;

      loc.visible = true;

      // create a marker for each social services location
      L.marker(
          L.latLng(lat, lng), {
            icon: self.icons[self.iconColorNames[0]],
            riseOnHover: true, // moves the marker to the front on mouseover
            // bind data to marker inside options
            data: loc
          }
        ).bindPopup(function(layer) { // allow for the popup on click with the name of the location
          let phoneRegex = /(\d{3})\D*(\d{3})\D*(\d{4})(x\d+)?/g;
          let match = phoneRegex.exec(loc["Contact Phone Number"]);
          let matches = [];

          while (match != null) {
              matches.push(match.slice(1, 5));
              match = phoneRegex.exec(loc["Contact Phone Number"]);
          }

          matches = matches.map((num) => {
            let phone = num.slice(0, 3).join("-");
            if (num[3]) {
              return [phone, num[3]].join(" ");
            }

            return phone;
          });

          return "" + loc["Organization Name"] + "
" +
            loc["Description of Services Provided in Englewood"] + "

" +
            "" +
            " " + loc["Address"] + "
" +
            (matches.length ?
              (" " + matches.join(" or ") + "
") : "") +
            (loc["Website"] ?
              ("" +
                " " + loc["Website"] + "
") : "");
        }).addTo(self.serviceGroup)
        .on("click", function(e) {
          if (this.options.data.visible && App.controllers.listToMapLink) {
            App.controllers.listToMapLink.mapMarkerSelected(this.options.data);
          } else {

          }
        });
    }
  }

  function updateServicesWithFilter(filteredData, serviceFilters) {
    // if (Object.keys(serviceFilters).length === 0) {
    //   // if there are no filters, show all locations
    //   self.serviceGroup.eachLayer(function(layer) {
    //     layer.setOpacity(1);
    //   });
    // } else {
    // otherwise only show locations that match at least one of the selected properties
    self.serviceGroup.eachLayer(function(layer) {
      let loc = layer.options.data;
      // let show = false;
      //
      // for (let property of Object.keys(serviceFilters)) {
      //   if (loc[property] == 1) {
      //     show = true;
      //     break;
      //   }
      // }

      let show = _.includes(filteredData, loc);
      layer.options.data.visible = show;

      if (show) {
        layer.setOpacity(1);
        layer.setZIndexOffset(100);
        layer.setIcon(self.icons["blue"]);
      } else {
        layer.setOpacity(0.2);
        layer.setZIndexOffset(0);
        layer.setIcon(self.icons["grey"]);
      }

    });
    // }
  }

  function setSelectedService(service) {
    self.serviceGroup.eachLayer(function(layer) {
      if (service && service["Organization Name"] === layer.options.data["Organization Name"]) {
        layer.setIcon(self.icons["orange"]);

        // open popup forcefully
        if (!layer._popup._latlng) {
          layer._popup.setLatLng(new L.latLng(layer.options.data.Y, layer.options.data.X));
        }

        layer._popup.openOn(self.map);
      } else {
        layer.options.data.visible ? layer.setIcon(self.icons["blue"]) : layer.setIcon(self.icons["grey"]);
        // layer.setIcon(self.icons["blue"]);
      }
    });

    if (service) {
      let lat = Number(service.Y) + (L.Browser.mobile ? 0.003 : 0);
      let lng = Number(service.X) - (!L.Browser.mobile && +d3.select("#serviceListWrapper").style("opacity") ? 0.005 : 0);
      self.map.setView([lat, lng], 16);
    }
  }

  function drawLocationMarker(position) {
    self.currentLocationMarker = L.marker(position, {
      icon: self.icons[self.iconColorNames[1]],
      zIndexOffset: 200
    });

    self.map.addLayer(self.currentLocationMarker);
  }

  function drawRect(bound1, bound2) {
    let llBound1 = self.map.containerPointToLatLng(bound1);
    let llBound2 = self.map.containerPointToLatLng(bound2);

    let color = self.rectColors.shift();

    let rect = L.rectangle([llBound1, llBound2], {
        color,
        data: self.totalRects
      })
      .bindPopup(function(layer) { // allow for the popup on click with the name of the location
        return `<button class='btn btn-xs btn-danger' onclick='App.controllers.rectSelector.removeRect(${layer.options.data})'>
       Remove</button>`;
      })
      // .setZIndex(200)
      .addTo(self.rectLayer);

    self.rects[self.totalRects] = rect;

    return {
      id: self.totalRects++,
      color,
      bounds: [llBound1, llBound2]
    };
  }

  function removeRect(rect) {
    self.map.removeLayer(self.rects[rect]);
    self.rectColors.push(self.rects[rect].options.color);

    delete self.rects[rect];
  }

  function centerAroundRect(rect) {
    self.map.fitBounds(rect.bounds);
  }

  function drawChoropleth(data) {
    // remove old choropleth
    if (self.choropleth) {
      self.choroplethLayer.removeLayer(self.choropleth);
    }

    // if data specified, add new choropleth
    if (data) {
      let colorScale = d3.scaleLinear()
        .domain(d3.extent(data.features, f => f.properties.data))
        .range(['#9ebcda', '#6e016b']);

      console.log(colorScale.domain(), colorScale.range());

      // TODO: draw color scale for map

      self.choropleth = L.geoJSON(data, {
          style: function(feature) {
            return {
              color: feature.properties.data === 0 ? "#444" : colorScale(feature.properties.data),
              opacity: 0.1,
              fillOpacity: 0.75,
              className: "geoJSON-gridSpace"
            }
          }
        })
        .on("mouseover", function(geojson) {
          // console.log(layer);
          geojson.layer.bringToFront();
        })
        .on("mouseout", function(geojson) {
          // console.log(layer);
          geojson.layer.bringToBack();
        })
        .bindPopup(function(layer) {
          console.log(layer.feature.properties.data);
          return JSON.stringify(layer.feature.properties.description) + "
" + layer.feature.properties.data.toFixed(2);
        }).addTo(self.choroplethLayer);

      self.rectLayer.eachLayer(rect => rect.bringToFront());
    }
  }

  function jumpToLocation(position) {
    //remove previous circle marker
    if (self.currentLocationMarker != undefined)
      self.map.removeLayer(self.currentLocationMarker);

    //move map to new poisition
    self.map.setView([position.lat, position.lng], 16);

    //draw a circle marker at new position
    drawLocationMarker(position);
  }

  return {
    createMap,
    plotServices,
    updateServicesWithFilter,
    setSelectedService,

    drawRect,
    removeRect,
    centerAroundRect,

    drawChoropleth,

    jumpToLocation
  };
};
<commit_msg>push change of leaflet mobile check -> screen width check<commit_after>"use strict";

var App = App || {};

let MapView = function(div) {
  let self = {
    map: null,
    serviceLayer: null,
    currentLocationMarker: null,
    icons: {},

    iconColorNames: ["blue", "red", "green", "orange", "yellow", "violet", "grey", "black"],
    iconColors: {
      "blue": "#2e84cb",
      "red": "#cb2d40",
      "green": "#28ad25",
      "orange": "#cc852a",
      "yellow": "#cac428",
      "violet": "#9c2bcb",
      "grey": "#7b7b7b",
      "black": "#3e3e3e"
    },

    rectLayer: null,
    rects: {},
    rectColors: d3.schemeCategory10.slice(0),
    totalRects: 0,

    choroplethLayer: null,
    choropleth: null
  };

  init();

  function init() {
    initIcons(); // create icon references for map use
    createMap();
  }

  function createMap() {
    console.log(d3.select("#" + div).node().clientWidth);

    self.map = L.map(div);
    console.log(self.map.getSize());
    // create the map layer using data from openstreetmap

    var osmUrl = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; // normal
    // var osmUrl = 'http://a.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png'; // dark
    // var osmUrl = 'https://a.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png'; // light

    var osmAttrib = 'Map data © OpenStreetMap contributors';

    var osm = new L.TileLayer(osmUrl, {
      minZoom: 11,
      maxZoom: 18,
      zoomSnap: 0.25,
      zoomDelta: 0.25,
      attribution: osmAttrib
    });

    self.map.addLayer(osm);
    self.map.setView([41.779786, -87.644778], 15);

    self.choroplethLayer = L.layerGroup([]).addTo(self.map);
    self.rectLayer = L.layerGroup([]).addTo(self.map);
    self.serviceGroup = L.layerGroup([]).addTo(self.map);
    self.map.zoomControl.setPosition('bottomright');

    // causes map to recalculate size... (I shouldn't need to do this)
    // setTimeout(function() {
    //   self.map.invalidateSize();
    // }, 0);
  }

  // initialize the different icon options by color
  function initIcons() {
    for (let color of self.iconColorNames) {
      self.icons[color] = new L.Icon({
        iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-' + color + '.png',
        shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
        iconSize: [25, 41],
        iconAnchor: [12, 41],
        popupAnchor: [1, -34],
        shadowSize: [41, 41]
      });
    }
  }

  function plotServices(englewoodLocations) {
    self.serviceGroup.clearLayers();

    // iterate through the social services location file
    for (let loc of englewoodLocations) {
      // convert the X and Y values to lat and lng for clarity
      let lat = loc.Y,
        lng = loc.X;

      loc.visible = true;

      // create a marker for each social services location
      L.marker(
          L.latLng(lat, lng), {
            icon: self.icons[self.iconColorNames[0]],
            riseOnHover: true, // moves the marker to the front on mouseover
            // bind data to marker inside options
            data: loc
          }
        ).bindPopup(function(layer) { // allow for the popup on click with the name of the location
          let phoneRegex = /(\d{3})\D*(\d{3})\D*(\d{4})(x\d+)?/g;
          let match = phoneRegex.exec(loc["Contact Phone Number"]);
          let matches = [];

          while (match != null) {
              matches.push(match.slice(1, 5));
              match = phoneRegex.exec(loc["Contact Phone Number"]);
          }

          matches = matches.map((num) => {
            let phone = num.slice(0, 3).join("-");
            if (num[3]) {
              return [phone, num[3]].join(" ");
            }

            return phone;
          });

          return "" + loc["Organization Name"] + "
" +
            loc["Description of Services Provided in Englewood"] + "

" +
            "" +
            " " + loc["Address"] + "
" +
            (matches.length ?
              (" " + matches.join(" or ") + "
") : "") +
            (loc["Website"] ?
              ("" +
                " " + loc["Website"] + "
") : "");
        }).addTo(self.serviceGroup)
        .on("click", function(e) {
          if (this.options.data.visible && App.controllers.listToMapLink) {
            App.controllers.listToMapLink.mapMarkerSelected(this.options.data);
          } else {

          }
        });
    }
  }

  function updateServicesWithFilter(filteredData, serviceFilters) {
    // if (Object.keys(serviceFilters).length === 0) {
    //   // if there are no filters, show all locations
    //   self.serviceGroup.eachLayer(function(layer) {
    //     layer.setOpacity(1);
    //   });
    // } else {
    // otherwise only show locations that match at least one of the selected properties
    self.serviceGroup.eachLayer(function(layer) {
      let loc = layer.options.data;
      // let show = false;
      //
      // for (let property of Object.keys(serviceFilters)) {
      //   if (loc[property] == 1) {
      //     show = true;
      //     break;
      //   }
      // }

      let show = _.includes(filteredData, loc);
      layer.options.data.visible = show;

      if (show) {
        layer.setOpacity(1);
        layer.setZIndexOffset(100);
        layer.setIcon(self.icons["blue"]);
      } else {
        layer.setOpacity(0.2);
        layer.setZIndexOffset(0);
        layer.setIcon(self.icons["grey"]);
      }

    });
    // }
  }

  function setSelectedService(service) {
    self.serviceGroup.eachLayer(function(layer) {
      if (service && service["Organization Name"] === layer.options.data["Organization Name"]) {
        layer.setIcon(self.icons["orange"]);

        // open popup forcefully
        if (!layer._popup._latlng) {
          layer._popup.setLatLng(new L.latLng(layer.options.data.Y, layer.options.data.X));
        }

        layer._popup.openOn(self.map);
      } else {
        layer.options.data.visible ? layer.setIcon(self.icons["blue"]) : layer.setIcon(self.icons["grey"]);
        // layer.setIcon(self.icons["blue"]);
      }
    });

    if (service) {
      let lat = Number(service.Y) + (L.Browser.mobile ? 0.003 : 0);
      let lng = Number(service.X) - ((window.innerWidth > 768) && +d3.select("#serviceListWrapper").style("opacity") ? 0.005 : 0);
      self.map.setView([lat, lng], 16);
    }
  }

  function drawLocationMarker(position) {
    self.currentLocationMarker = L.marker(position, {
      icon: self.icons[self.iconColorNames[1]],
      zIndexOffset: 200
    });

    self.map.addLayer(self.currentLocationMarker);
  }

  function drawRect(bound1, bound2) {
    let llBound1 = self.map.containerPointToLatLng(bound1);
    let llBound2 = self.map.containerPointToLatLng(bound2);

    let color = self.rectColors.shift();

    let rect = L.rectangle([llBound1, llBound2], {
        color,
        data: self.totalRects
      })
      .bindPopup(function(layer) { // allow for the popup on click with the name of the location
        return `<button class='btn btn-xs btn-danger' onclick='App.controllers.rectSelector.removeRect(${layer.options.data})'>
       Remove</button>`;
      })
      // .setZIndex(200)
      .addTo(self.rectLayer);

    self.rects[self.totalRects] = rect;

    return {
      id: self.totalRects++,
      color,
      bounds: [llBound1, llBound2]
    };
  }

  function removeRect(rect) {
    self.map.removeLayer(self.rects[rect]);
    self.rectColors.push(self.rects[rect].options.color);

    delete self.rects[rect];
  }

  function centerAroundRect(rect) {
    self.map.fitBounds(rect.bounds);
  }

  function drawChoropleth(data) {
    // remove old choropleth
    if (self.choropleth) {
      self.choroplethLayer.removeLayer(self.choropleth);
    }

    // if data specified, add new choropleth
    if (data) {
      let colorScale = d3.scaleLinear()
        .domain(d3.extent(data.features, f => f.properties.data))
        .range(['#9ebcda', '#6e016b']);

      console.log(colorScale.domain(), colorScale.range());

      // TODO: draw color scale for map

      self.choropleth = L.geoJSON(data, {
          style: function(feature) {
            return {
              color: feature.properties.data === 0 ? "#444" : colorScale(feature.properties.data),
              opacity: 0.1,
              fillOpacity: 0.75,
              className: "geoJSON-gridSpace"
            }
          }
        })
        .on("mouseover", function(geojson) {
          // console.log(layer);
          geojson.layer.bringToFront();
        })
        .on("mouseout", function(geojson) {
          // console.log(layer);
          geojson.layer.bringToBack();
        })
        .bindPopup(function(layer) {
          console.log(layer.feature.properties.data);
          return JSON.stringify(layer.feature.properties.description) + "
" + layer.feature.properties.data.toFixed(2);
        }).addTo(self.choroplethLayer);

      self.rectLayer.eachLayer(rect => rect.bringToFront());
    }
  }

  function jumpToLocation(position) {
    //remove previous circle marker
    if (self.currentLocationMarker != undefined)
      self.map.removeLayer(self.currentLocationMarker);

    //move map to new poisition
    self.map.setView([position.lat, position.lng], 16);

    //draw a circle marker at new position
    drawLocationMarker(position);
  }

  return {
    createMap,
    plotServices,
    updateServicesWithFilter,
    setSelectedService,

    drawRect,
    removeRect,
    centerAroundRect,

    drawChoropleth,

    jumpToLocation
  };
};
<|endoftext|>


<commit_before>/*global
 define, require
 */
/*jslint
 browser: true,
 white: true
 */
define([
    'promise',
    'kb_common_utils',
    'kb_widgetAdapters_objectWidget',
    'kb_widgetAdapters_kbWidget'
],
    function (Promise, Utils, widgetAdapter, KBWidgetAdapter) {
        'use strict';

        function factory(config) {
            // Variables
            // The widget registry is a db (map) of widget definitions.
            // Note that we do NOT YET store widget instance references ...
            var widgets = {},
                runtime = config.runtime;

            // Functions

            // API Functions

            function addWidget(widgetDef) {
                if (widgets[widgetDef.id]) {
                    throw new Error('Widget ' + widgetDef.id + ' is already registered');
                }
                /* TODO:  validate the widget ...*/
                widgets[widgetDef.id] = widgetDef;
            }
            function getWidget(widgetId) {
                return widgets[widgetId];
            }

            function makeFactoryWidget(widget, config) {
                return new Promise(function (resolve, reject) {
                    require([widget.module], function (factory) {
                        if (factory.make === undefined) {
                            reject('Factory widget does not have a "make" method: ' + widget.id + ', ' + widget.module);
                        }
                        try {
                            resolve(factory.make(config));
                        } catch (ex) {
                            reject(ex);
                        }
                    });
                });
            }

            function makeObjectWidget(widget, config) {
                return Promise.try(function () {
                    return widgetAdapter.make({
                        widgetDef: widget,
                        initConfig: config,
                        adapterConfig: {
                            runtime: runtime
                        }
                    });
                });
            }

            function makeKbWidget(widget, config) {
                return Promise.try(function () {
                    var adapterConfig = {
                        runtime: runtime,
                        widget: {
                            module: widget.module,
                            jquery_object: config.jqueryName,
                            panel: config.panel,
                            title: widget.title
                        }
                    };
                    return KBWidgetAdapter.make(adapterConfig);
                });
            }

            function makeWidget(widgetId, config) {
                var widgetDef = widgets[widgetId];
                if (!widgetDef) {
                    throw new Error('Widget ' + widgetId + ' not found');
                }

                config = config || {};
                config.runtime = runtime;

                // How we create a widget depends on what type it is.
                switch (widgetDef.type) {
                    case 'factory':
                        return makeFactoryWidget(widgetDef, config);
                    case 'object':
                        return makeObjectWidget(widgetDef, config);
                    case 'kbwidget':
                        return makeKbWidget(widgetDef, config);
                    default:
                        throw new Error('Unsupported widget type ' + widgetDef.type);
                }

            }

            // API
            return {
                addWidget: addWidget,
                getWidget: getWidget,
                makeWidget: makeWidget
            };
        }

        return {
            make: function (config) {
                return factory(config);
            }
        };
    });<commit_msg>widget id becomes widget name, to be more consistent with the usage elsewhere<commit_after>/*global
 define, require
 */
/*jslint
 browser: true,
 white: true
 */
define([
    'promise',
    'kb_widgetAdapters_objectWidget',
    'kb_widgetAdapters_kbWidget'
],
    function (Promise, widgetAdapter, KBWidgetAdapter) {
        'use strict';

        function factory(config) {
            // Variables
            // The widget registry is a db (map) of widget definitions.
            // Note that we do NOT YET store widget instance references ...
            var widgets = {},
                runtime = config.runtime;

            // Functions

            // API Functions

            function addWidget(widgetDef) {
                if (widgetDef.id) {
                    widgetDef.name = widgetDef.id;
                }
                if (widgets[widgetDef.name]) {
                    throw new Error('Widget ' + widgetDef.name + ' is already registered');
                }
                /* TODO:  validate the widget ...*/
                widgets[widgetDef.name] = widgetDef;
            }
            function getWidget(widgetId) {
                return widgets[widgetId];
            }

            function makeFactoryWidget(widget, config) {
                return new Promise(function (resolve, reject) {
                    require([widget.module], function (factory) {
                        if (factory.make === undefined) {
                            reject('Factory widget does not have a "make" method: ' + widget.name + ', ' + widget.module);
                        }
                        try {
                            resolve(factory.make(config));
                        } catch (ex) {
                            reject(ex);
                        }
                    });
                });
            }

            function makeObjectWidget(widget, config) {
                return Promise.try(function () {
                    return widgetAdapter.make({
                        widgetDef: widget,
                        initConfig: config,
                        adapterConfig: {
                            runtime: runtime
                        }
                    });
                });
            }

            function makeKbWidget(widget, config) {
                return Promise.try(function () {
                    var adapterConfig = {
                        runtime: runtime,
                        widget: {
                            module: widget.module,
                            jquery_object: config.jqueryName,
                            panel: config.panel,
                            title: widget.title
                        }
                    };
                    return KBWidgetAdapter.make(adapterConfig);
                });
            }

            function makeWidget(widgetName, config) {
                var widgetDef = widgets[widgetName];
                if (!widgetDef) {
                    throw new Error('Widget ' + widgetName + ' not found');
                }

                config = config || {};
                config.runtime = runtime;

                // How we create a widget depends on what type it is.
                switch (widgetDef.type) {
                    case 'factory':
                        return makeFactoryWidget(widgetDef, config);
                    case 'object':
                        return makeObjectWidget(widgetDef, config);
                    case 'kbwidget':
                        return makeKbWidget(widgetDef, config);
                    default:
                        throw new Error('Unsupported widget type ' + widgetDef.type);
                }

            }

            // API
            return {
                addWidget: addWidget,
                getWidget: getWidget,
                makeWidget: makeWidget
            };
        }

        return {
            make: function (config) {
                return factory(config);
            }
        };
    });<|endoftext|>


<commit_before>/*global console, window, document, jQuery, Kinetic*/
var MAPJS = MAPJS || {};
MAPJS.KineticMediator = function (mapModel, stage) {
	'use strict';
	var layer = new Kinetic.Layer(),
		nodeByIdeaId = {},
		connectorByFromIdeaId_ToIdeaId = {},
		connectorKey = function (fromIdeaId, toIdeaId) {
			return fromIdeaId + '_' + toIdeaId;
		};
	stage.add(layer);
	mapModel.addEventListener('nodeCreated', function (n) {
		var node = new Kinetic.Idea({
			level: n.level,
			x: n.x,
			y: n.y,
			text: n.title,
			mmStyle: n.style,
			opacity: 0
		});
		/* in kinetic 4.3 cannot use click because click if fired on dragend */
		node.on('click tap', mapModel.selectNode.bind(mapModel, n.id));
		node.on('dragstart', function () {
			node.moveToTop();
			node.attrs.shadow.offset = {
				x: 8,
				y: 8
			};
		});
		node.on('dragmove', function () {
			mapModel.nodeDragMove(
				n.id,
				node.attrs.x,
				node.attrs.y
			);
		});
		node.on('dragend', function () {
			node.attrs.shadow.offset = {
				x: 4,
				y: 4
			};
			mapModel.nodeDragEnd(
				n.id,
				node.attrs.x,
				node.attrs.y
			);
		});
		node.on(':textChanged', function (event) {
			mapModel.updateTitle(n.id, event.text);
			mapModel.dispatchEvent('inputEnabledChanged', true);
		});
		node.on(':editing', function(event){
			mapModel.dispatchEvent('inputEnabledChanged', false);
		});
		node.on(':nodeEditRequested', mapModel.editNode.bind(mapModel, 'mouse', false));

		mapModel.addEventListener('nodeEditRequested:' + n.id, node.editNode);
		nodeByIdeaId[n.id] = node;
		layer.add(node);
		node.transitionToAndDontStopCurrentTransitions({
			opacity: 1,
			duration: 0.4
		});
	});
	mapModel.addEventListener('nodeSelectionChanged', function (ideaId, isSelected) {
		var node = nodeByIdeaId[ideaId],
			scale = stage.getScale().x || 1,
			offset = 100,
			move = { x: 0, y: 0 };
		node.setIsSelected(isSelected);
		if (!isSelected) {
			return;
		}
		if (node.getAbsolutePosition().x + node.getWidth() * scale + offset > stage.getWidth()) {
			move.x = stage.getWidth() - (node.getAbsolutePosition().x + node.getWidth() * scale + offset);
		} else if (node.getAbsolutePosition().x < offset) {
			move.x  = offset - node.getAbsolutePosition().x;
		}
		if (node.getAbsolutePosition().y + node.getHeight() * scale + offset > stage.getHeight()) {
			move.y = stage.getHeight() - (node.getAbsolutePosition().y + node.getHeight() * scale + offset);
		} else if (node.getAbsolutePosition().y < offset) {
			move.y = offset - node.getAbsolutePosition().y;
		}
		stage.transitionTo({
			x: stage.attrs.x + move.x,
			y: stage.attrs.y + move.y,
			duration: 0.4,
			easing: 'ease-in-out'
		});
	});
	mapModel.addEventListener('nodeStyleChanged', function (n) {
		var node = nodeByIdeaId[n.id];
		node.setMMStyle(n.style);
	});
	mapModel.addEventListener('nodeDroppableChanged', function (ideaId, isDroppable) {
		var node = nodeByIdeaId[ideaId];
		node.setIsDroppable(isDroppable);
	});
	mapModel.addEventListener('nodeRemoved', function (n) {
		var node = nodeByIdeaId[n.id];
		delete nodeByIdeaId[n.id];
		node.transitionTo({
			opacity: 0.25,
			duration: 0.4,
			callback: node.remove.bind(node)
		});
		node.off('click dblclick tap dragstart dragmove dragend mouseover mouseout :textChanged :nodeEditRequested');
		mapModel.removeEventListener('nodeEditRequested:' + n.id, node.editNode);
	});
	mapModel.addEventListener('nodeMoved', function (n, reason) {
		var node = nodeByIdeaId[n.id];
		node.transitionTo({
			x: n.x,
			y: n.y,
			duration: 0.4,
			easing: reason === 'failed' ? 'bounce-ease-out' : 'ease-in-out'
		});
	});
	mapModel.addEventListener('nodeTitleChanged', function (n) {
		var node = nodeByIdeaId[n.id];
		node.setText(n.title);
		layer.draw();
	});
	mapModel.addEventListener('connectorCreated', function (n) {
		var connector = new Kinetic.Connector({
			shapeFrom: nodeByIdeaId[n.from],
			shapeTo: nodeByIdeaId[n.to],
			stroke: '#888',
			strokeWidth: 1,
			opacity: 0
		});
		connector.opacity = 0;
		connectorByFromIdeaId_ToIdeaId[connectorKey(n.from, n.to)] = connector;
		layer.add(connector);
		connector.moveToBottom();
		connector.transitionTo({
			opacity: 1,
			duration: 0.4
		});
	});
	mapModel.addEventListener('connectorRemoved', function (n) {
		var key = connectorKey(n.from, n.to),
			connector = connectorByFromIdeaId_ToIdeaId[key];
		delete connectorByFromIdeaId_ToIdeaId[key];
		connector.transitionTo({
			opacity: 0,
			duration: 0.1,
			callback: connector.remove.bind(connector)
		});
	});
	mapModel.addEventListener('mapScaleChanged', function (isScaleUp) {
		var scale = (stage.getScale().x || 1) * (isScaleUp ? 1.25 : 0.8);
		stage.transitionTo({
			scale: {
				x: scale,
				y: scale
			},
			duration: 0.1
		});
	});
	(function () {
		var keyboardEventHandlers = {
			13: mapModel.addSiblingIdea.bind(mapModel, 'keyboard'),
			8: mapModel.removeSubIdea.bind(mapModel, 'keyboard'),
			9: mapModel.addSubIdea.bind(mapModel, 'keyboard'),
			37: mapModel.selectNodeLeft.bind(mapModel, 'keyboard'),
			38: mapModel.selectNodeUp.bind(mapModel, 'keyboard'),
			39: mapModel.selectNodeRight.bind(mapModel, 'keyboard'),
			40: mapModel.selectNodeDown.bind(mapModel, 'keyboard'),
			46: mapModel.removeSubIdea.bind(mapModel, 'keyboard'),
			32: mapModel.editNode.bind(mapModel, 'keyboard'),
			191: mapModel.toggleCollapse.bind(mapModel, 'keyboard')
		}, shiftKeyboardEventHandlers = {
			9: mapModel.insertIntermediate.bind(mapModel, 'keyboard'),
			38: mapModel.toggleCollapse.bind(mapModel, 'keyboard')
		}, metaKeyboardEventHandlers = {
			90: mapModel.undo.bind(mapModel, 'keyboard'),
			89: mapModel.redo.bind(mapModel, 'keyboard')
		},
			onKeydown = function (evt) {
				var eventHandler = ((evt.metaKey || evt.ctrlKey) ? metaKeyboardEventHandlers :
						(evt.shiftKey ? shiftKeyboardEventHandlers : keyboardEventHandlers))[evt.which];
				if (eventHandler) {
					eventHandler();
					evt.preventDefault();
				}
			},
			onScroll = function (event, delta, deltaX, deltaY) {
				if (stage) {
					if (deltaY !== 0) { stage.attrs.y += (deltaY < 0 ? -5 : 5); }
					if (deltaX !== 0) { stage.attrs.x += (deltaX < 0 ? 5 : -5); }
					stage.draw();
				}
				if (deltaX < 0) { /* stop the back button */
					event.preventDefault();
				}
				if (deltaY < 0) { /*stop scrolling down */
					event.preventDefault();
				}
			};
		jQuery(document).keydown(onKeydown);
		jQuery(window).mousewheel(onScroll);
		mapModel.addEventListener('inputEnabledChanged', function (isInputEnabled) {
			jQuery(document)[isInputEnabled ? 'bind' : 'unbind']('keydown', onKeydown);
			jQuery(window)[isInputEnabled ? 'mousewheel' : 'unmousewheel'](onScroll);
		});

	}());
};
MAPJS.KineticMediator.dimensionProvider = _.memoize(function (title) {
	'use strict';
	console.log('here');
	var text = new Kinetic.Idea({
		text: title
	});
	return {
		width: text.getWidth(),
		height: text.getHeight()
	};
});
MAPJS.KineticMediator.layoutCalculator = function (idea) {
	'use strict';
	return MAPJS.calculateLayout(idea, MAPJS.KineticMediator.dimensionProvider);
};
<commit_msg>removed console.log<commit_after>/*global console, window, document, jQuery, Kinetic*/
var MAPJS = MAPJS || {};
MAPJS.KineticMediator = function (mapModel, stage) {
	'use strict';
	var layer = new Kinetic.Layer(),
		nodeByIdeaId = {},
		connectorByFromIdeaId_ToIdeaId = {},
		connectorKey = function (fromIdeaId, toIdeaId) {
			return fromIdeaId + '_' + toIdeaId;
		};
	stage.add(layer);
	mapModel.addEventListener('nodeCreated', function (n) {
		var node = new Kinetic.Idea({
			level: n.level,
			x: n.x,
			y: n.y,
			text: n.title,
			mmStyle: n.style,
			opacity: 0
		});
		/* in kinetic 4.3 cannot use click because click if fired on dragend */
		node.on('click tap', mapModel.selectNode.bind(mapModel, n.id));
		node.on('dragstart', function () {
			node.moveToTop();
			node.attrs.shadow.offset = {
				x: 8,
				y: 8
			};
		});
		node.on('dragmove', function () {
			mapModel.nodeDragMove(
				n.id,
				node.attrs.x,
				node.attrs.y
			);
		});
		node.on('dragend', function () {
			node.attrs.shadow.offset = {
				x: 4,
				y: 4
			};
			mapModel.nodeDragEnd(
				n.id,
				node.attrs.x,
				node.attrs.y
			);
		});
		node.on(':textChanged', function (event) {
			mapModel.updateTitle(n.id, event.text);
			mapModel.dispatchEvent('inputEnabledChanged', true);
		});
		node.on(':editing', function(event){
			mapModel.dispatchEvent('inputEnabledChanged', false);
		});
		node.on(':nodeEditRequested', mapModel.editNode.bind(mapModel, 'mouse', false));

		mapModel.addEventListener('nodeEditRequested:' + n.id, node.editNode);
		nodeByIdeaId[n.id] = node;
		layer.add(node);
		node.transitionToAndDontStopCurrentTransitions({
			opacity: 1,
			duration: 0.4
		});
	});
	mapModel.addEventListener('nodeSelectionChanged', function (ideaId, isSelected) {
		var node = nodeByIdeaId[ideaId],
			scale = stage.getScale().x || 1,
			offset = 100,
			move = { x: 0, y: 0 };
		node.setIsSelected(isSelected);
		if (!isSelected) {
			return;
		}
		if (node.getAbsolutePosition().x + node.getWidth() * scale + offset > stage.getWidth()) {
			move.x = stage.getWidth() - (node.getAbsolutePosition().x + node.getWidth() * scale + offset);
		} else if (node.getAbsolutePosition().x < offset) {
			move.x  = offset - node.getAbsolutePosition().x;
		}
		if (node.getAbsolutePosition().y + node.getHeight() * scale + offset > stage.getHeight()) {
			move.y = stage.getHeight() - (node.getAbsolutePosition().y + node.getHeight() * scale + offset);
		} else if (node.getAbsolutePosition().y < offset) {
			move.y = offset - node.getAbsolutePosition().y;
		}
		stage.transitionTo({
			x: stage.attrs.x + move.x,
			y: stage.attrs.y + move.y,
			duration: 0.4,
			easing: 'ease-in-out'
		});
	});
	mapModel.addEventListener('nodeStyleChanged', function (n) {
		var node = nodeByIdeaId[n.id];
		node.setMMStyle(n.style);
	});
	mapModel.addEventListener('nodeDroppableChanged', function (ideaId, isDroppable) {
		var node = nodeByIdeaId[ideaId];
		node.setIsDroppable(isDroppable);
	});
	mapModel.addEventListener('nodeRemoved', function (n) {
		var node = nodeByIdeaId[n.id];
		delete nodeByIdeaId[n.id];
		node.transitionTo({
			opacity: 0.25,
			duration: 0.4,
			callback: node.remove.bind(node)
		});
		node.off('click dblclick tap dragstart dragmove dragend mouseover mouseout :textChanged :nodeEditRequested');
		mapModel.removeEventListener('nodeEditRequested:' + n.id, node.editNode);
	});
	mapModel.addEventListener('nodeMoved', function (n, reason) {
		var node = nodeByIdeaId[n.id];
		node.transitionTo({
			x: n.x,
			y: n.y,
			duration: 0.4,
			easing: reason === 'failed' ? 'bounce-ease-out' : 'ease-in-out'
		});
	});
	mapModel.addEventListener('nodeTitleChanged', function (n) {
		var node = nodeByIdeaId[n.id];
		node.setText(n.title);
		layer.draw();
	});
	mapModel.addEventListener('connectorCreated', function (n) {
		var connector = new Kinetic.Connector({
			shapeFrom: nodeByIdeaId[n.from],
			shapeTo: nodeByIdeaId[n.to],
			stroke: '#888',
			strokeWidth: 1,
			opacity: 0
		});
		connector.opacity = 0;
		connectorByFromIdeaId_ToIdeaId[connectorKey(n.from, n.to)] = connector;
		layer.add(connector);
		connector.moveToBottom();
		connector.transitionTo({
			opacity: 1,
			duration: 0.4
		});
	});
	mapModel.addEventListener('connectorRemoved', function (n) {
		var key = connectorKey(n.from, n.to),
			connector = connectorByFromIdeaId_ToIdeaId[key];
		delete connectorByFromIdeaId_ToIdeaId[key];
		connector.transitionTo({
			opacity: 0,
			duration: 0.1,
			callback: connector.remove.bind(connector)
		});
	});
	mapModel.addEventListener('mapScaleChanged', function (isScaleUp) {
		var scale = (stage.getScale().x || 1) * (isScaleUp ? 1.25 : 0.8);
		stage.transitionTo({
			scale: {
				x: scale,
				y: scale
			},
			duration: 0.1
		});
	});
	(function () {
		var keyboardEventHandlers = {
			13: mapModel.addSiblingIdea.bind(mapModel, 'keyboard'),
			8: mapModel.removeSubIdea.bind(mapModel, 'keyboard'),
			9: mapModel.addSubIdea.bind(mapModel, 'keyboard'),
			37: mapModel.selectNodeLeft.bind(mapModel, 'keyboard'),
			38: mapModel.selectNodeUp.bind(mapModel, 'keyboard'),
			39: mapModel.selectNodeRight.bind(mapModel, 'keyboard'),
			40: mapModel.selectNodeDown.bind(mapModel, 'keyboard'),
			46: mapModel.removeSubIdea.bind(mapModel, 'keyboard'),
			32: mapModel.editNode.bind(mapModel, 'keyboard'),
			191: mapModel.toggleCollapse.bind(mapModel, 'keyboard')
		}, shiftKeyboardEventHandlers = {
			9: mapModel.insertIntermediate.bind(mapModel, 'keyboard'),
			38: mapModel.toggleCollapse.bind(mapModel, 'keyboard')
		}, metaKeyboardEventHandlers = {
			90: mapModel.undo.bind(mapModel, 'keyboard'),
			89: mapModel.redo.bind(mapModel, 'keyboard')
		},
			onKeydown = function (evt) {
				var eventHandler = ((evt.metaKey || evt.ctrlKey) ? metaKeyboardEventHandlers :
						(evt.shiftKey ? shiftKeyboardEventHandlers : keyboardEventHandlers))[evt.which];
				if (eventHandler) {
					eventHandler();
					evt.preventDefault();
				}
			},
			onScroll = function (event, delta, deltaX, deltaY) {
				if (stage) {
					if (deltaY !== 0) { stage.attrs.y += (deltaY < 0 ? -5 : 5); }
					if (deltaX !== 0) { stage.attrs.x += (deltaX < 0 ? 5 : -5); }
					stage.draw();
				}
				if (deltaX < 0) { /* stop the back button */
					event.preventDefault();
				}
				if (deltaY < 0) { /*stop scrolling down */
					event.preventDefault();
				}
			};
		jQuery(document).keydown(onKeydown);
		jQuery(window).mousewheel(onScroll);
		mapModel.addEventListener('inputEnabledChanged', function (isInputEnabled) {
			jQuery(document)[isInputEnabled ? 'bind' : 'unbind']('keydown', onKeydown);
			jQuery(window)[isInputEnabled ? 'mousewheel' : 'unmousewheel'](onScroll);
		});

	}());
};
MAPJS.KineticMediator.dimensionProvider = _.memoize(function (title) {
	'use strict';
	var text = new Kinetic.Idea({
		text: title
	});
	return {
		width: text.getWidth(),
		height: text.getHeight()
	};
});
MAPJS.KineticMediator.layoutCalculator = function (idea) {
	'use strict';
	return MAPJS.calculateLayout(idea, MAPJS.KineticMediator.dimensionProvider);
};
<|endoftext|>


<commit_before>/*
Language: AVR Assembler
Author: Vladimir Ermakov <vooon341@gmail.com>
*/

function(hljs) {
  return {
    case_insensitive: true,
    keywords: {
      keyword:
        /* mnemonic */
        'adc add adiw and andi asr bclr bld brbc brbs brcc brcs break breq brge brhc brhs ' +
        'brid brie brlo brlt brmi brne brpl brsh brtc brts brvc brvs bset bst call cbi cbr ' +
        'clc clh cli cln clr cls clt clv clz com cp cpc cpi cpse dec eicall eijmp elpm eor ' +
        'fmul fmuls fmulsu icall ijmp in inc jmp ld ldd ldi lds lpm lsl lsr mov movw mul ' +
        'muls mulsu neg nop or ori out pop push rcall ret reti rjmp rol ror sbc sbr sbrc sbrs ' +
        'sec seh sbi sbci sbic sbis sbiw sei sen ser ses set sev sez sleep spm st std sts sub ' +
        'subi swap tst wdr',
      built_in:
        /* general purpose registers */
        'r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 ' +
        'r23 r24 r25 r26 r27 r28 r29 r30 r31 x|0 xh xl y|0 yh yl z|0 zh zl ' +
        /* IO Registers (ATMega128) */
        'ucsr1c udr1 ucsr1a ucsr1b ubrr1l ubrr1h ucsr0c ubrr0h tccr3c tccr3a tccr3b tcnt3h ' +
        'tcnt3l ocr3ah ocr3al ocr3bh ocr3bl ocr3ch ocr3cl icr3h icr3l etimsk etifr tccr1c ' +
        'ocr1ch ocr1cl twcr twdr twar twsr twbr osccal xmcra xmcrb eicra spmcsr spmcr portg ' +
        'ddrg ping portf ddrf sreg sph spl xdiv rampz eicrb eimsk gimsk gicr eifr gifr timsk ' +
        'tifr mcucr mcucsr tccr0 tcnt0 ocr0 assr tccr1a tccr1b tcnt1h tcnt1l ocr1ah ocr1al ' +
        'ocr1bh ocr1bl icr1h icr1l tccr2 tcnt2 ocr2 ocdr wdtcr sfior eearh eearl eedr eecr ' +
        'porta ddra pina portb ddrb pinb portc ddrc pinc portd ddrd pind spdr spsr spcr udr0 ' +
        'ucsr0a ucsr0b ubrr0l acsr admux adcsr adch adcl porte ddre pine pinf'
    },
    contains: [
      hljs.C_BLOCK_COMMENT_MODE,
      {className: 'comment', begin: ';',  end: '$', relevance: 0},
      hljs.C_NUMBER_MODE, // 0x..., decimal, float
      hljs.BINARY_NUMBER_MODE, // 0b...
      {
        className: 'number',
        begin: '\\b(\\$[a-zA-Z0-9]+|0o[0-7]+)' // $..., 0o...
      },
      hljs.QUOTE_STRING_MODE,
      {
        className: 'string',
        begin: '\'', end: '[^\\\\]\'',
        illegal: '[^\\\\][^\']'
      },
      {className: 'label',  begin: '^[A-Za-z0-9_.$]+:'},
      {className: 'preprocessor', begin: '#', end: '$'},
      {  // директивы «.include» «.macro» и т.д.
        className: 'preprocessor',
        begin: '\\.[a-zA-Z]+'
      },
      {  // подстановка в «.macro»
        className: 'localvars',
        begin: '@[0-9]+'
      }
    ]
  };
}
<commit_msg>Redefined AVR asm directives as keywords.<commit_after>/*
Language: AVR Assembler
Author: Vladimir Ermakov <vooon341@gmail.com>
*/

function(hljs) {
  return {
    case_insensitive: true,
    lexemes: '\\.?' + hljs.IDENT_RE,
    keywords: {
      keyword:
        /* mnemonic */
        'adc add adiw and andi asr bclr bld brbc brbs brcc brcs break breq brge brhc brhs ' +
        'brid brie brlo brlt brmi brne brpl brsh brtc brts brvc brvs bset bst call cbi cbr ' +
        'clc clh cli cln clr cls clt clv clz com cp cpc cpi cpse dec eicall eijmp elpm eor ' +
        'fmul fmuls fmulsu icall ijmp in inc jmp ld ldd ldi lds lpm lsl lsr mov movw mul ' +
        'muls mulsu neg nop or ori out pop push rcall ret reti rjmp rol ror sbc sbr sbrc sbrs ' +
        'sec seh sbi sbci sbic sbis sbiw sei sen ser ses set sev sez sleep spm st std sts sub ' +
        'subi swap tst wdr',
      built_in:
        /* general purpose registers */
        'r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 ' +
        'r23 r24 r25 r26 r27 r28 r29 r30 r31 x|0 xh xl y|0 yh yl z|0 zh zl ' +
        /* IO Registers (ATMega128) */
        'ucsr1c udr1 ucsr1a ucsr1b ubrr1l ubrr1h ucsr0c ubrr0h tccr3c tccr3a tccr3b tcnt3h ' +
        'tcnt3l ocr3ah ocr3al ocr3bh ocr3bl ocr3ch ocr3cl icr3h icr3l etimsk etifr tccr1c ' +
        'ocr1ch ocr1cl twcr twdr twar twsr twbr osccal xmcra xmcrb eicra spmcsr spmcr portg ' +
        'ddrg ping portf ddrf sreg sph spl xdiv rampz eicrb eimsk gimsk gicr eifr gifr timsk ' +
        'tifr mcucr mcucsr tccr0 tcnt0 ocr0 assr tccr1a tccr1b tcnt1h tcnt1l ocr1ah ocr1al ' +
        'ocr1bh ocr1bl icr1h icr1l tccr2 tcnt2 ocr2 ocdr wdtcr sfior eearh eearl eedr eecr ' +
        'porta ddra pina portb ddrb pinb portc ddrc pinc portd ddrd pind spdr spsr spcr udr0 ' +
        'ucsr0a ucsr0b ubrr0l acsr admux adcsr adch adcl porte ddre pine pinf',
      preprocessor:
        '.byte .cseg .db .def .device .dseg .dw .endmacro .equ .eseg .exit .include .list ' +
        '.listmac .macro .nolist .org .set'
    },
    contains: [
      hljs.C_BLOCK_COMMENT_MODE,
      {className: 'comment', begin: ';',  end: '$', relevance: 0},
      hljs.C_NUMBER_MODE, // 0x..., decimal, float
      hljs.BINARY_NUMBER_MODE, // 0b...
      {
        className: 'number',
        begin: '\\b(\\$[a-zA-Z0-9]+|0o[0-7]+)' // $..., 0o...
      },
      hljs.QUOTE_STRING_MODE,
      {
        className: 'string',
        begin: '\'', end: '[^\\\\]\'',
        illegal: '[^\\\\][^\']'
      },
      {className: 'label',  begin: '^[A-Za-z0-9_.$]+:'},
      {className: 'preprocessor', begin: '#', end: '$'},
      {  // подстановка в «.macro»
        className: 'localvars',
        begin: '@[0-9]+'
      }
    ]
  };
}
<|endoftext|>


<commit_before>/*
Language: Python
*/

function(hljs) {
  var PROMPT = {
    className: 'prompt',  begin: '^(>>>|\\.\\.\\.) '
  }
  var STRINGS = [
    {
      className: 'string',
      begin: '(u|b)?r?\'\'\'', end: '\'\'\'',
      contains: [PROMPT],
      relevance: 10
    },
    {
      className: 'string',
      begin: '(u|b)?r?"""', end: '"""',
      contains: [PROMPT],
      relevance: 10
    },
    {
      className: 'string',
      begin: '(u|r|ur)\'', end: '\'',
      contains: [hljs.BACKSLASH_ESCAPE],
      relevance: 10
    },
    {
      className: 'string',
      begin: '(u|r|ur)"', end: '"',
      contains: [hljs.BACKSLASH_ESCAPE],
      relevance: 10
    },
    {
      className: 'string',
      begin: '(b|br)\'', end: '\'',
      contains: [hljs.BACKSLASH_ESCAPE]
    },
    {
      className: 'string',
      begin: '(b|br)"', end: '"',
      contains: [hljs.BACKSLASH_ESCAPE]
    }
  ].concat([
    hljs.APOS_STRING_MODE,
    hljs.QUOTE_STRING_MODE
  ]);
  var TITLE = {
    className: 'title', begin: hljs.UNDERSCORE_IDENT_RE
  };
  var PARAMS = {
    className: 'params',
    begin: '\\(', end: '\\)',
    contains: ['self', hljs.C_NUMBER_MODE, PROMPT].concat(STRINGS)
  };
  var FUNC_CLASS_PROTO = {
    beginWithKeyword: true, end: ':',
    illegal: '[${=;\\n]',
    contains: [TITLE, PARAMS],
    relevance: 10
  };

  return {
    keywords: {
      keyword:
        'and elif is global as in if from raise for except finally print import pass return ' +
        'exec else break not with class assert yield try while continue del or def lambda ' +
        'nonlocal|10',
      built_in:
        'None True False Ellipsis NotImplemented'
    },
    illegal: '(</|->|\\?)',
    contains: STRINGS.concat([
      PROMPT,
      hljs.HASH_COMMENT_MODE,
      hljs.inherit(FUNC_CLASS_PROTO, {className: 'function', keywords: 'def'}),
      hljs.inherit(FUNC_CLASS_PROTO, {className: 'class', keywords: 'class'}),
      hljs.C_NUMBER_MODE,
      {
        className: 'decorator',
        begin: '@', end: '$'
      },
      {
        begin: '\\b(print|exec)\\(' // don’t highlight keywords-turned-functions in Python 3
      }
    ])
  };
}
<commit_msg>Literal regexps in Python definition.<commit_after>/*
Language: Python
*/

function(hljs) {
  var PROMPT = {
    className: 'prompt',  begin: /^(>>>|\.\.\.) /
  }
  var STRINGS = [
    {
      className: 'string',
      begin: /(u|b)?r?'''/, end: /'''/,
      contains: [PROMPT],
      relevance: 10
    },
    {
      className: 'string',
      begin: /(u|b)?r?"""/, end: /"""/,
      contains: [PROMPT],
      relevance: 10
    },
    {
      className: 'string',
      begin: /(u|r|ur)'/, end: /'/,
      contains: [hljs.BACKSLASH_ESCAPE],
      relevance: 10
    },
    {
      className: 'string',
      begin: /(u|r|ur)"/, end: /"/,
      contains: [hljs.BACKSLASH_ESCAPE],
      relevance: 10
    },
    {
      className: 'string',
      begin: /(b|br)'/, end: /'/,
      contains: [hljs.BACKSLASH_ESCAPE]
    },
    {
      className: 'string',
      begin: /(b|br)"/, end: /"/,
      contains: [hljs.BACKSLASH_ESCAPE]
    }
  ].concat([
    hljs.APOS_STRING_MODE,
    hljs.QUOTE_STRING_MODE
  ]);
  var TITLE = {
    className: 'title', begin: hljs.UNDERSCORE_IDENT_RE
  };
  var PARAMS = {
    className: 'params',
    begin: /\(/, end: /\)/,
    contains: ['self', hljs.C_NUMBER_MODE, PROMPT].concat(STRINGS)
  };
  var FUNC_CLASS_PROTO = {
    beginWithKeyword: true, end: /:/,
    illegal: /[${=;\n]/,
    contains: [TITLE, PARAMS],
    relevance: 10
  };

  return {
    keywords: {
      keyword:
        'and elif is global as in if from raise for except finally print import pass return ' +
        'exec else break not with class assert yield try while continue del or def lambda ' +
        'nonlocal|10',
      built_in:
        'None True False Ellipsis NotImplemented'
    },
    illegal: /(<\/|->|\?)/,
    contains: STRINGS.concat([
      PROMPT,
      hljs.HASH_COMMENT_MODE,
      hljs.inherit(FUNC_CLASS_PROTO, {className: 'function', keywords: 'def'}),
      hljs.inherit(FUNC_CLASS_PROTO, {className: 'class', keywords: 'class'}),
      hljs.C_NUMBER_MODE,
      {
        className: 'decorator',
        begin: /@/, end: /$/
      },
      {
        begin: /\b(print|exec)\(/ // don’t highlight keywords-turned-functions in Python 3
      }
    ])
  };
}
<|endoftext|>


<commit_before><commit_msg>GL 修改打包文件<commit_after><|endoftext|>