react-tree-menu
Version:
A tree menu component for React
1,559 lines (1,295 loc) • 1.33 MB
JavaScript
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var React = require('react'),
TreeMenu = require('../index'),
TreeNode = require('../index').TreeNode,
TreeMenuUtils = require('../index').Utils,
Immutable = require('immutable'),
_ = require('lodash');
var CSSTransitionGroup = require('react-addons-css-transition-group');
var App = React.createClass({displayName: "App",
getInitialState: function() {
return {
lastAction1: null,
lastAction2: null,
lastAction3: null,
staticTreeData: {
"option_2.a" : {
checked: false
},
"option_2.b" : {
checked: false
}
},
dynamicTreeData: [
{
label : "Option 1"
},
{
label : "Option 2",
children : [
{
checkbox: true,
label: "Sub Option A",
children: [
{
label: "Third Level Option 1",
checkbox : true
},
{
label: "Third Level Option 2",
checkbox : true
}
]
},
{
checkbox: true,
label: "Sub Option B"
}
]
}
],
dynamicTreeDataMap: {
"Option 1" : {
checked: true,
checkbox: true,
children: {
"Sub Option 1" : {
checked: false
},
"Sub Option 2" : {
checked: false,
checkbox: true,
children: {
"Sub-Sub Option 1" : {
checked: false,
checkbox: true
},
"Sub-Sub Option 2" : {
checked: false,
checkbox: true
}
}
}
}
},
"Option 2" : {
checked: false,
checkbox: true
}
},
dynamicTreeDataMap2: {
"Option 1" : {
checkbox: false,
children: {
"Sub Option 1" : {
checkbox: false
},
"Sub Option 2" : {
checkbox: false,
children: {
"Sub-Sub Option 1" : {
selected: true,
checkbox: false
},
"Sub-Sub Option 2" : {
checkbox: false
}
}
}
}
},
"Option 2" : {
checkbox: false
}
}
};
},
render: function() {
var dynamicExample1 = this._getExamplePanel("Dynamic", this._getDynamicTreeExample()),
declarativeExample = this._getExamplePanel("Declarative", this._getDeclarativeTreeExample()),
unboundExample = this._getExamplePanel("Unbound", this._getUnboundTreeExample()),
statefulExample = this._getExamplePanel("Stateful", this._getStatefulTreeExample()),
dynamicExample2 = this._getExamplePanel("Dynamic (Object)", this._getDynamicTreeExample2()),
dynamicExample3 = this._getExamplePanel("Selection w/o Checkboxes", this._getDynamicTreeExample3()),
labelFilterExample = this._getExamplePanel("Label Filter", this._getLabelFilterExample()),
rendererExample = this._getExamplePanel("Label/Checkbox Renderers", this._getRendererExample());
return React.createElement("div", {className: "container"},
React.createElement("div", {className: "row"},
React.createElement("div", {className: "col-lg-12 hero"},
React.createElement("h1", null, React.createElement("code", null, "<TreeMenu/>"))
)
),
React.createElement("div", {className: "row"},
React.createElement("div", {className: "col-lg-12 hero"},
React.createElement("h3", null, "Check out the code for this demo ", React.createElement("a", {href: "https://github.com/MandarinConLaBarba/react-tree-menu/blob/master/example/App.jsx"}, "here"), ".")
)
),
React.createElement("div", {className: "row"},
React.createElement("div", {className: "col-lg-3"},
React.createElement("h2", null, "Dynamic (Array)"),
React.createElement("ul", null,
React.createElement("li", null, "This menu is built dynamically using the data prop (array)"),
React.createElement("li", null, "It is collapsible (the default), so expand/collapse icons show"),
React.createElement("li", null, "It has no identifier prop for the TreeMenu, so it uses the array index when emitting events")
)
),
React.createElement("div", {className: "col-lg-3"},
React.createElement("h2", null, "Declarative"),
React.createElement("ul", null,
React.createElement("li", null, "This menu is built w/ nested TreeNode components"),
React.createElement("li", null, "It has collapsible=false, so no expand/collapse icons show"),
React.createElement("li", null, "It has identifier=\"id\", so it uses the 'id' prop when emitting events")
)
),
React.createElement("div", {className: "col-lg-3"},
React.createElement("h2", null, "Unbound: Won't Update UI State"),
React.createElement("ul", null,
React.createElement("li", null, "This menu doesn't have any handlers applied that update UI state, so it's static.")
)
),
React.createElement("div", {className: "col-lg-3"},
React.createElement("h2", null, "Stateful, manages its own UI state"),
React.createElement("ul", null,
React.createElement("li", null, "This menu has stateful=true, so it manages its own state w/o help from the Controller-View.")
)
)
),
React.createElement("div", {className: "row"},
React.createElement("div", {className: "col-lg-3"},
dynamicExample1
),
React.createElement("div", {className: "col-lg-3"},
declarativeExample
),
React.createElement("div", {className: "col-lg-3"},
unboundExample
),
React.createElement("div", {className: "col-lg-3"},
statefulExample
)
),
React.createElement("div", {className: "row"},
React.createElement("div", {className: "col-lg-3"},
React.createElement(CSSTransitionGroup, {
transitionEnterTimeout: 500,
transitionName: "last-action", transitionLeave: false},
this._getLastActionNode("1")
)
),
React.createElement("div", {className: "col-lg-3"},
React.createElement(CSSTransitionGroup, {transitionEnterTimeout: 500, transitionName: "last-action", transitionLeave: false},
this._getLastActionNode("2")
)
),
React.createElement("div", {className: "col-lg-3"},
React.createElement(CSSTransitionGroup, {transitionEnterTimeout: 500, transitionName: "last-action", transitionLeave: false},
this._getLastActionNode("3")
)
),
React.createElement("div", {className: "col-lg-3"},
React.createElement(CSSTransitionGroup, {transitionEnterTimeout: 500, transitionName: "last-action", transitionLeave: false},
this._getLastActionNode("4")
)
)
),
React.createElement("div", {className: "row"},
React.createElement("div", {className: "col-lg-3"},
React.createElement("h2", null, "Dynamic (Object)"),
React.createElement("ul", null,
React.createElement("li", null, "This menu is built dynamically using the data prop (object)"),
React.createElement("li", null, "It is collapsible (the default), so expand/collapse icons show"),
React.createElement("li", null, "It has no identifier prop for the TreeMenu, so it uses the object key when emitting events")
)
),
React.createElement("div", {className: "col-lg-3"},
React.createElement("h2", null, "Dynamic - No Checkboxes"),
React.createElement("ul", null,
React.createElement("li", null, "This menu is built dynamically using the data prop (object)"),
React.createElement("li", null, "It doesn't have checkboxes, but does have selection state")
)
),
React.createElement("div", {className: "col-lg-3"},
React.createElement("h2", null, "Label Filter"),
React.createElement("ul", null,
React.createElement("li", null, "This menu has a labelFilter prop that truncates the displayed label")
)
),
React.createElement("div", {className: "col-lg-3"},
React.createElement("h2", null, "Renderers"),
React.createElement("ul", null,
React.createElement("li", null, "Using renderer (node factory) methods as arguments")
)
)
),
React.createElement("div", {className: "row"},
React.createElement("div", {className: "col-lg-3"},
dynamicExample2
),
React.createElement("div", {className: "col-lg-3"},
dynamicExample3
),
React.createElement("div", {className: "col-lg-3"},
labelFilterExample
),
React.createElement("div", {className: "col-lg-3"},
rendererExample
)
),
React.createElement("div", {className: "row"},
React.createElement("div", {className: "col-lg-3"},
React.createElement(CSSTransitionGroup, {transitionEnterTimeout: 500, transitionName: "last-action", transitionLeave: false},
this._getLastActionNode("5")
)
),
React.createElement("div", {className: "col-lg-3"},
React.createElement(CSSTransitionGroup, {transitionEnterTimeout: 500, transitionName: "last-action", transitionLeave: false},
this._getLastActionNode("6")
)
)
)
);
},
_getLastActionNode: function (col) {
var lastActionNode = React.createElement("div", {className: "text-center alert alert-success tree-event-alert"}, "Waiting for interaction"),
key = "lastAction" + col;
var action = this.state[key];
if (action) {
lastActionNode = (
React.createElement("div", {className: "text-center alert alert-success tree-event-alert", key: "lastAction_" + col + "_" + action.time},
React.createElement("h3", null, "Event Received:"),
React.createElement("div", null, React.createElement("strong", null, action.event)),
React.createElement("h3", null, React.createElement("code", null, "<TreeNode/>"), " Affected: "),
React.createElement("div", null, React.createElement("strong", null, action.node))
));
} else {
}
return lastActionNode;
},
_getStatefulTreeExample: function () {
return (
React.createElement(TreeMenu, {
identifier: "id",
stateful: true,
onTreeNodeClick: this._setLastActionState.bind(this, "clicked", "4"),
onTreeNodeCollapseChange: this._setLastActionState.bind(this, "collapsed", "4"),
onTreeNodeCheckChange: this._setLastActionState.bind(this, "checked", "4"),
expandIconClass: "fa fa-chevron-right",
collapseIconClass: "fa fa-chevron-down"},
React.createElement(TreeNode, {label: "Option 1", checkbox: true, id: "option_1"}),
React.createElement(TreeNode, {label: "Option 2", checkbox: true, id: "option_2"},
React.createElement(TreeNode, {label: "Option A", checkbox: true, id: "option_2.a"}),
React.createElement(TreeNode, {label: "Option B", checkbox: true, id: "option_2.b"},
React.createElement(TreeNode, {label: "Option B.x", checkbox: true, id: "option_2.b.x"}),
React.createElement(TreeNode, {label: "Option B.y", checkbox: true, id: "option_2.b.y"})
)
)
)
);
},
_getUnboundTreeExample: function () {
return (
React.createElement(TreeMenu, {
identifier: "id",
onTreeNodeClick: this._setLastActionState.bind(this, "clicked", "3"),
onTreeNodeCollapseChange: this._setLastActionState.bind(this, "collapsed", "3"),
onTreeNodeCheckChange: this._setLastActionState.bind(this, "checked", "3"),
expandIconClass: "fa fa-chevron-right",
collapseIconClass: "fa fa-chevron-down"},
React.createElement(TreeNode, {label: "Option 1", checkbox: true, id: "option_1"}),
React.createElement(TreeNode, {label: "Option 2", checkbox: true, id: "option_2"},
React.createElement(TreeNode, {label: "Option A", checkbox: true, checked: true, id: "option_2.a"}),
React.createElement(TreeNode, {label: "Option B", checkbox: true, id: "option_2.b"})
),
React.createElement(TreeNode, {label: "Option 3", checkbox: true, id: "option_3"}),
React.createElement(TreeNode, {label: "Option 3", checkbox: true, id: "option_3"})
)
);
},
_getDeclarativeTreeExample: function () {
return (
React.createElement(TreeMenu, {
sort: true,
identifier: "id",
onTreeNodeClick: this._setLastActionState.bind(this, "clicked", "2"),
onTreeNodeCollapseChange: this._handleDeclarativeTreeNodePropChange.bind(this, "collapsed"),
onTreeNodeCheckChange: this._handleDeclarativeTreeNodePropChange.bind(this, "checked"),
collapsible: false,
expandIconClass: "fa fa-chevron-right",
collapseIconClass: "fa fa-chevron-down"},
React.createElement(TreeNode, {label: "Option 1", id: "option_1"}),
React.createElement(TreeNode, {label: "Option 2", id: "option_2"},
React.createElement(TreeNode, {label: "Option B", checkbox: true, checked: this.state.staticTreeData["option_2.b"].checked, id: "option_2.b"}),
React.createElement(TreeNode, {label: "Option A", checkbox: true, checked: this.state.staticTreeData["option_2.a"].checked, id: "option_2.a"})
),
React.createElement(TreeNode, {label: "Option 3", id: "option_3"}),
React.createElement(TreeNode, {label: "Option 4", id: "option_4"})
)
);
},
_getLabelFilterExample: function () {
return (
React.createElement(TreeMenu, {
identifier: "id",
onTreeNodeClick: function() {},
onTreeNodeCollapseChange: function() {},
onTreeNodeCheckChange: function() {},
collapsible: false,
labelFilter: function(label) {
var max = 10;
if (label.length <= max) return label;
return label.substring(label, max).concat("...");
},
expandIconClass: "fa fa-chevron-right",
collapseIconClass: "fa fa-chevron-down"},
React.createElement(TreeNode, {label: "Option 1 with a long name", id: "option_1"}),
React.createElement(TreeNode, {label: "Option 2 also has a long name", id: "option_2"},
React.createElement(TreeNode, {label: "Option A with a long name", checkbox: true, id: "option_2.a"}),
React.createElement(TreeNode, {label: "Option B with a long name", checkbox: true, id: "option_2.b"})
),
React.createElement(TreeNode, {label: "Option 3 with a long name", id: "option_3"}),
React.createElement(TreeNode, {label: "Option 4 with a long name", id: "option_4"})
)
);
},
_getRendererExample: function () {
return (
React.createElement(TreeMenu, {
identifier: "id",
onTreeNodeClick: function() {},
onTreeNodeCollapseChange: function() {},
onTreeNodeCheckChange: function() {},
collapsible: false,
labelFilter: function(label) {
var max = 10;
if (label.length <= max) return label;
return label.substring(label, max).concat("...");
},
labelFactory: function(labelClassName, displayLabel) {
return React.createElement("span", {className: labelClassName}, displayLabel, " ", "<span/>");
},
checkboxFactory: function(checkboxClassName, isChecked) {
return React.createElement("span", {className: checkboxClassName + " fa " + (isChecked ? "fa-check-circle" : "fa-circle-o")});
},
expandIconClass: "fa fa-chevron-right",
collapseIconClass: "fa fa-chevron-down"},
React.createElement(TreeNode, {label: "Option 1 with a long name", id: "option_1"}),
React.createElement(TreeNode, {label: "Option 2 also has a long name", id: "option_2", checkbox: true, checked: false},
React.createElement(TreeNode, {label: "Option A with a long name", checkbox: true, id: "option_2.a"}),
React.createElement(TreeNode, {label: "Option B with a long name", checkbox: true, checked: true, id: "option_2.b"})
),
React.createElement(TreeNode, {label: "Option 3 with a long name", id: "option_3"}),
React.createElement(TreeNode, {label: "Option 4 with a long name", id: "option_4"})
)
);
},
_getDynamicTreeExample: function () {
return (
React.createElement(TreeMenu, {
expandIconClass: "fa fa-chevron-right",
collapseIconClass: "fa fa-chevron-down",
onTreeNodeClick: this._setLastActionState.bind(this, "clicked", "1"),
onTreeNodeCollapseChange: this._handleDynamicTreeNodePropChange.bind(this, "collapsed"),
onTreeNodeCheckChange: this._handleDynamicTreeNodePropChange.bind(this, "checked"),
data: this.state.dynamicTreeData})
);
},
_getDynamicTreeExample2: function () {
return (
React.createElement(TreeMenu, {
expandIconClass: "fa fa-chevron-right",
collapseIconClass: "fa fa-chevron-down",
onTreeNodeClick: this._setLastActionState.bind(this, "clicked", "5"),
onTreeNodeCollapseChange: this._handleDynamicObjectTreeNodePropChange.bind(this, 5, "dynamicTreeDataMap","collapsed"),
onTreeNodeCheckChange: this._handleDynamicObjectTreeNodePropChange.bind(this, 5, "dynamicTreeDataMap","checked"),
data: this.state.dynamicTreeDataMap})
);
},
_getDynamicTreeExample3: function () {
return (
React.createElement(TreeMenu, {
expandIconClass: "fa fa-chevron-right",
collapseIconClass: "fa fa-chevron-down",
onTreeNodeCollapseChange: this._handleDynamicObjectTreeNodePropChange.bind(this, 6, "dynamicTreeDataMap2", "collapsed"),
onTreeNodeCheckChange: this._handleDynamicObjectTreeNodePropChange.bind(this, 6, "dynamicTreeDataMap2","checked"),
onTreeNodeSelectChange: this._handleDynamicObjectTreeNodePropChange.bind(this, 6, "dynamicTreeDataMap2","selected"),
data: this.state.dynamicTreeDataMap2})
);
},
_getExamplePanel: function (title, treeMenuNode) {
return React.createElement("div", null,
React.createElement("div", {className: "panel panel-default"},
React.createElement("div", {className: "panel-heading"}, title + " Menu"),
React.createElement("div", {className: "panel-body"},
treeMenuNode
)
)
);
},
_handleDeclarativeTreeNodePropChange: function (propName, lineage) {
this._setLastActionState(propName, "2", lineage);
var nodeId = lineage.pop();
var treeState = this.state.staticTreeData;
treeState[nodeId][propName] = !treeState[nodeId][propName];
this.setState({
staticTreeData : treeState
});
},
_handleDynamicTreeNodePropChange: function (propName, lineage) {
this._setLastActionState(propName, "1", lineage);
this.setState(TreeMenuUtils.getNewTreeState(lineage, this.state.dynamicTreeData, propName));
},
_handleDynamicObjectTreeNodePropChange: function (messageWindowKey, stateKey, propName, lineage) {
this._setLastActionState(propName, messageWindowKey, lineage);
//Get a node path that includes children, given a key
function getNodePath(nodeKey) {
if (nodeKey.length === 1) return nodeKey;
return _(nodeKey).zip(nodeKey.map(function () {
return "children";
})).flatten().initial().value();
}
var oldState = Immutable.fromJS(this.state[stateKey]);
var nodePath = getNodePath(lineage),
keyPaths = [nodePath.concat([propName])];
//Build a list of key paths for all children
function addChildKeys(state, parentPath) {
var childrenPath = parentPath.concat('children'),
children = state.getIn(childrenPath);
if (!children || children.size === 0) return;
children.map(function (value, key) {
keyPaths.push(childrenPath.concat([key, propName]))
addChildKeys(state, childrenPath.concat([key]));
});
}
addChildKeys(oldState, nodePath);
//Get the new prop state
var newPropState = !oldState.getIn(keyPaths[0]);
//Now create a new map w/ all the changes
var newState = oldState.withMutations(function(state) {
keyPaths.forEach(function (keyPath) {
state.setIn(keyPath, newPropState);
})
});
var mutation = {};
mutation[stateKey] = newState.toJS();
this.setState(mutation);
},
_setLastActionState: function (action, col, node) {
var toggleEvents = ["collapsed", "checked", "selected"];
if (toggleEvents.indexOf(action) >= 0) {
action += "Changed";
}
console.log("Controller View received tree menu " + action + " action: " + node.join(" > "));
var key = "lastAction" + col;
var mutation = {};
mutation[key] = {
event: action,
node: node.join(" > "),
time: new Date().getTime()
};
this.setState(mutation)
}
});
module.exports = App;
},{"../index":3,"immutable":5,"lodash":9,"react":240,"react-addons-css-transition-group":78}],2:[function(require,module,exports){
var React = require('react');
var ReactDOM = require('react-dom');
var App = require('./App.jsx');
ReactDOM.render(React.createElement(App, null), document.getElementById('appContainer'));
},{"./App.jsx":1,"react":240,"react-dom":79}],3:[function(require,module,exports){
var api = require('./src/TreeMenu.jsx');
api.TreeMenu = require('./src/TreeMenu.jsx');
api.TreeNode = require('./src/TreeNode.jsx');
api.Utils = require('./src/TreeMenuUtils');
module.exports = api;
},{"./src/TreeMenu.jsx":241,"./src/TreeMenuUtils":242,"./src/TreeNode.jsx":243}],4:[function(require,module,exports){
// shim for using process in browser
var process = module.exports = {};
var queue = [];
var draining = false;
function drainQueue() {
if (draining) {
return;
}
draining = true;
var currentQueue;
var len = queue.length;
while(len) {
currentQueue = queue;
queue = [];
var i = -1;
while (++i < len) {
currentQueue[i]();
}
len = queue.length;
}
draining = false;
}
process.nextTick = function (fun) {
queue.push(fun);
if (!draining) {
setTimeout(drainQueue, 0);
}
};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
function noop() {}
process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;
process.binding = function (name) {
throw new Error('process.binding is not supported');
};
// TODO(shtylman)
process.cwd = function () { return '/' };
process.chdir = function (dir) {
throw new Error('process.chdir is not supported');
};
process.umask = function() { return 0; };
},{}],5:[function(require,module,exports){
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
global.Immutable = factory()
}(this, function () { 'use strict';var SLICE$0 = Array.prototype.slice;
function createClass(ctor, superClass) {
if (superClass) {
ctor.prototype = Object.create(superClass.prototype);
}
ctor.prototype.constructor = ctor;
}
// Used for setting prototype methods that IE8 chokes on.
var DELETE = 'delete';
// Constants describing the size of trie nodes.
var SHIFT = 5; // Resulted in best performance after ______?
var SIZE = 1 << SHIFT;
var MASK = SIZE - 1;
// A consistent shared value representing "not set" which equals nothing other
// than itself, and nothing that could be provided externally.
var NOT_SET = {};
// Boolean references, Rough equivalent of `bool &`.
var CHANGE_LENGTH = { value: false };
var DID_ALTER = { value: false };
function MakeRef(ref) {
ref.value = false;
return ref;
}
function SetRef(ref) {
ref && (ref.value = true);
}
// A function which returns a value representing an "owner" for transient writes
// to tries. The return value will only ever equal itself, and will not equal
// the return of any subsequent call of this function.
function OwnerID() {}
// http://jsperf.com/copy-array-inline
function arrCopy(arr, offset) {
offset = offset || 0;
var len = Math.max(0, arr.length - offset);
var newArr = new Array(len);
for (var ii = 0; ii < len; ii++) {
newArr[ii] = arr[ii + offset];
}
return newArr;
}
function ensureSize(iter) {
if (iter.size === undefined) {
iter.size = iter.__iterate(returnTrue);
}
return iter.size;
}
function wrapIndex(iter, index) {
return index >= 0 ? (+index) : ensureSize(iter) + (+index);
}
function returnTrue() {
return true;
}
function wholeSlice(begin, end, size) {
return (begin === 0 || (size !== undefined && begin <= -size)) &&
(end === undefined || (size !== undefined && end >= size));
}
function resolveBegin(begin, size) {
return resolveIndex(begin, size, 0);
}
function resolveEnd(end, size) {
return resolveIndex(end, size, size);
}
function resolveIndex(index, size, defaultIndex) {
return index === undefined ?
defaultIndex :
index < 0 ?
Math.max(0, size + index) :
size === undefined ?
index :
Math.min(size, index);
}
function Iterable(value) {
return isIterable(value) ? value : Seq(value);
}
createClass(KeyedIterable, Iterable);
function KeyedIterable(value) {
return isKeyed(value) ? value : KeyedSeq(value);
}
createClass(IndexedIterable, Iterable);
function IndexedIterable(value) {
return isIndexed(value) ? value : IndexedSeq(value);
}
createClass(SetIterable, Iterable);
function SetIterable(value) {
return isIterable(value) && !isAssociative(value) ? value : SetSeq(value);
}
function isIterable(maybeIterable) {
return !!(maybeIterable && maybeIterable[IS_ITERABLE_SENTINEL]);
}
function isKeyed(maybeKeyed) {
return !!(maybeKeyed && maybeKeyed[IS_KEYED_SENTINEL]);
}
function isIndexed(maybeIndexed) {
return !!(maybeIndexed && maybeIndexed[IS_INDEXED_SENTINEL]);
}
function isAssociative(maybeAssociative) {
return isKeyed(maybeAssociative) || isIndexed(maybeAssociative);
}
function isOrdered(maybeOrdered) {
return !!(maybeOrdered && maybeOrdered[IS_ORDERED_SENTINEL]);
}
Iterable.isIterable = isIterable;
Iterable.isKeyed = isKeyed;
Iterable.isIndexed = isIndexed;
Iterable.isAssociative = isAssociative;
Iterable.isOrdered = isOrdered;
Iterable.Keyed = KeyedIterable;
Iterable.Indexed = IndexedIterable;
Iterable.Set = SetIterable;
var IS_ITERABLE_SENTINEL = '@@__IMMUTABLE_ITERABLE__@@';
var IS_KEYED_SENTINEL = '@@__IMMUTABLE_KEYED__@@';
var IS_INDEXED_SENTINEL = '@@__IMMUTABLE_INDEXED__@@';
var IS_ORDERED_SENTINEL = '@@__IMMUTABLE_ORDERED__@@';
/* global Symbol */
var ITERATE_KEYS = 0;
var ITERATE_VALUES = 1;
var ITERATE_ENTRIES = 2;
var REAL_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
var FAUX_ITERATOR_SYMBOL = '@@iterator';
var ITERATOR_SYMBOL = REAL_ITERATOR_SYMBOL || FAUX_ITERATOR_SYMBOL;
function Iterator(next) {
this.next = next;
}
Iterator.prototype.toString = function() {
return '[Iterator]';
};
Iterator.KEYS = ITERATE_KEYS;
Iterator.VALUES = ITERATE_VALUES;
Iterator.ENTRIES = ITERATE_ENTRIES;
Iterator.prototype.inspect =
Iterator.prototype.toSource = function () { return this.toString(); }
Iterator.prototype[ITERATOR_SYMBOL] = function () {
return this;
};
function iteratorValue(type, k, v, iteratorResult) {
var value = type === 0 ? k : type === 1 ? v : [k, v];
iteratorResult ? (iteratorResult.value = value) : (iteratorResult = {
value: value, done: false
});
return iteratorResult;
}
function iteratorDone() {
return { value: undefined, done: true };
}
function hasIterator(maybeIterable) {
return !!getIteratorFn(maybeIterable);
}
function isIterator(maybeIterator) {
return maybeIterator && typeof maybeIterator.next === 'function';
}
function getIterator(iterable) {
var iteratorFn = getIteratorFn(iterable);
return iteratorFn && iteratorFn.call(iterable);
}
function getIteratorFn(iterable) {
var iteratorFn = iterable && (
(REAL_ITERATOR_SYMBOL && iterable[REAL_ITERATOR_SYMBOL]) ||
iterable[FAUX_ITERATOR_SYMBOL]
);
if (typeof iteratorFn === 'function') {
return iteratorFn;
}
}
function isArrayLike(value) {
return value && typeof value.length === 'number';
}
createClass(Seq, Iterable);
function Seq(value) {
return value === null || value === undefined ? emptySequence() :
isIterable(value) ? value.toSeq() : seqFromValue(value);
}
Seq.of = function(/*...values*/) {
return Seq(arguments);
};
Seq.prototype.toSeq = function() {
return this;
};
Seq.prototype.toString = function() {
return this.__toString('Seq {', '}');
};
Seq.prototype.cacheResult = function() {
if (!this._cache && this.__iterateUncached) {
this._cache = this.entrySeq().toArray();
this.size = this._cache.length;
}
return this;
};
// abstract __iterateUncached(fn, reverse)
Seq.prototype.__iterate = function(fn, reverse) {
return seqIterate(this, fn, reverse, true);
};
// abstract __iteratorUncached(type, reverse)
Seq.prototype.__iterator = function(type, reverse) {
return seqIterator(this, type, reverse, true);
};
createClass(KeyedSeq, Seq);
function KeyedSeq(value) {
return value === null || value === undefined ?
emptySequence().toKeyedSeq() :
isIterable(value) ?
(isKeyed(value) ? value.toSeq() : value.fromEntrySeq()) :
keyedSeqFromValue(value);
}
KeyedSeq.of = function(/*...values*/) {
return KeyedSeq(arguments);
};
KeyedSeq.prototype.toKeyedSeq = function() {
return this;
};
KeyedSeq.prototype.toSeq = function() {
return this;
};
createClass(IndexedSeq, Seq);
function IndexedSeq(value) {
return value === null || value === undefined ? emptySequence() :
!isIterable(value) ? indexedSeqFromValue(value) :
isKeyed(value) ? value.entrySeq() : value.toIndexedSeq();
}
IndexedSeq.of = function(/*...values*/) {
return IndexedSeq(arguments);
};
IndexedSeq.prototype.toIndexedSeq = function() {
return this;
};
IndexedSeq.prototype.toString = function() {
return this.__toString('Seq [', ']');
};
IndexedSeq.prototype.__iterate = function(fn, reverse) {
return seqIterate(this, fn, reverse, false);
};
IndexedSeq.prototype.__iterator = function(type, reverse) {
return seqIterator(this, type, reverse, false);
};
createClass(SetSeq, Seq);
function SetSeq(value) {
return (
value === null || value === undefined ? emptySequence() :
!isIterable(value) ? indexedSeqFromValue(value) :
isKeyed(value) ? value.entrySeq() : value
).toSetSeq();
}
SetSeq.of = function(/*...values*/) {
return SetSeq(arguments);
};
SetSeq.prototype.toSetSeq = function() {
return this;
};
Seq.isSeq = isSeq;
Seq.Keyed = KeyedSeq;
Seq.Set = SetSeq;
Seq.Indexed = IndexedSeq;
var IS_SEQ_SENTINEL = '@@__IMMUTABLE_SEQ__@@';
Seq.prototype[IS_SEQ_SENTINEL] = true;
// #pragma Root Sequences
createClass(ArraySeq, IndexedSeq);
function ArraySeq(array) {
this._array = array;
this.size = array.length;
}
ArraySeq.prototype.get = function(index, notSetValue) {
return this.has(index) ? this._array[wrapIndex(this, index)] : notSetValue;
};
ArraySeq.prototype.__iterate = function(fn, reverse) {
var array = this._array;
var maxIndex = array.length - 1;
for (var ii = 0; ii <= maxIndex; ii++) {
if (fn(array[reverse ? maxIndex - ii : ii], ii, this) === false) {
return ii + 1;
}
}
return ii;
};
ArraySeq.prototype.__iterator = function(type, reverse) {
var array = this._array;
var maxIndex = array.length - 1;
var ii = 0;
return new Iterator(function()
{return ii > maxIndex ?
iteratorDone() :
iteratorValue(type, ii, array[reverse ? maxIndex - ii++ : ii++])}
);
};
createClass(ObjectSeq, KeyedSeq);
function ObjectSeq(object) {
var keys = Object.keys(object);
this._object = object;
this._keys = keys;
this.size = keys.length;
}
ObjectSeq.prototype.get = function(key, notSetValue) {
if (notSetValue !== undefined && !this.has(key)) {
return notSetValue;
}
return this._object[key];
};
ObjectSeq.prototype.has = function(key) {
return this._object.hasOwnProperty(key);
};
ObjectSeq.prototype.__iterate = function(fn, reverse) {
var object = this._object;
var keys = this._keys;
var maxIndex = keys.length - 1;
for (var ii = 0; ii <= maxIndex; ii++) {
var key = keys[reverse ? maxIndex - ii : ii];
if (fn(object[key], key, this) === false) {
return ii + 1;
}
}
return ii;
};
ObjectSeq.prototype.__iterator = function(type, reverse) {
var object = this._object;
var keys = this._keys;
var maxIndex = keys.length - 1;
var ii = 0;
return new Iterator(function() {
var key = keys[reverse ? maxIndex - ii : ii];
return ii++ > maxIndex ?
iteratorDone() :
iteratorValue(type, key, object[key]);
});
};
ObjectSeq.prototype[IS_ORDERED_SENTINEL] = true;
createClass(IterableSeq, IndexedSeq);
function IterableSeq(iterable) {
this._iterable = iterable;
this.size = iterable.length || iterable.size;
}
IterableSeq.prototype.__iterateUncached = function(fn, reverse) {
if (reverse) {
return this.cacheResult().__iterate(fn, reverse);
}
var iterable = this._iterable;
var iterator = getIterator(iterable);
var iterations = 0;
if (isIterator(iterator)) {
var step;
while (!(step = iterator.next()).done) {
if (fn(step.value, iterations++, this) === false) {
break;
}
}
}
return iterations;
};
IterableSeq.prototype.__iteratorUncached = function(type, reverse) {
if (reverse) {
return this.cacheResult().__iterator(type, reverse);
}
var iterable = this._iterable;
var iterator = getIterator(iterable);
if (!isIterator(iterator)) {
return new Iterator(iteratorDone);
}
var iterations = 0;
return new Iterator(function() {
var step = iterator.next();
return step.done ? step : iteratorValue(type, iterations++, step.value);
});
};
createClass(IteratorSeq, IndexedSeq);
function IteratorSeq(iterator) {
this._iterator = iterator;
this._iteratorCache = [];
}
IteratorSeq.prototype.__iterateUncached = function(fn, reverse) {
if (reverse) {
return this.cacheResult().__iterate(fn, reverse);
}
var iterator = this._iterator;
var cache = this._iteratorCache;
var iterations = 0;
while (iterations < cache.length) {
if (fn(cache[iterations], iterations++, this) === false) {
return iterations;
}
}
var step;
while (!(step = iterator.next()).done) {
var val = step.value;
cache[iterations] = val;
if (fn(val, iterations++, this) === false) {
break;
}
}
return iterations;
};
IteratorSeq.prototype.__iteratorUncached = function(type, reverse) {
if (reverse) {
return this.cacheResult().__iterator(type, reverse);
}
var iterator = this._iterator;
var cache = this._iteratorCache;
var iterations = 0;
return new Iterator(function() {
if (iterations >= cache.length) {
var step = iterator.next();
if (step.done) {
return step;
}
cache[iterations] = step.value;
}
return iteratorValue(type, iterations, cache[iterations++]);
});
};
// # pragma Helper functions
function isSeq(maybeSeq) {
return !!(maybeSeq && maybeSeq[IS_SEQ_SENTINEL]);
}
var EMPTY_SEQ;
function emptySequence() {
return EMPTY_SEQ || (EMPTY_SEQ = new ArraySeq([]));
}
function keyedSeqFromValue(value) {
var seq =
Array.isArray(value) ? new ArraySeq(value).fromEntrySeq() :
isIterator(value) ? new IteratorSeq(value).fromEntrySeq() :
hasIterator(value) ? new IterableSeq(value).fromEntrySeq() :
typeof value === 'object' ? new ObjectSeq(value) :
undefined;
if (!seq) {
throw new TypeError(
'Expected Array or iterable object of [k, v] entries, '+
'or keyed object: ' + value
);
}
return seq;
}
function indexedSeqFromValue(value) {
var seq = maybeIndexedSeqFromValue(value);
if (!seq) {
throw new TypeError(
'Expected Array or iterable object of values: ' + value
);
}
return seq;
}
function seqFromValue(value) {
var seq = maybeIndexedSeqFromValue(value) ||
(typeof value === 'object' && new ObjectSeq(value));
if (!seq) {
throw new TypeError(
'Expected Array or iterable object of values, or keyed object: ' + value
);
}
return seq;
}
function maybeIndexedSeqFromValue(value) {
return (
isArrayLike(value) ? new ArraySeq(value) :
isIterator(value) ? new IteratorSeq(value) :
hasIterator(value) ? new IterableSeq(value) :
undefined
);
}
function seqIterate(seq, fn, reverse, useKeys) {
var cache = seq._cache;
if (cache) {
var maxIndex = cache.length - 1;
for (var ii = 0; ii <= maxIndex; ii++) {
var entry = cache[reverse ? maxIndex - ii : ii];
if (fn(entry[1], useKeys ? entry[0] : ii, seq) === false) {
return ii + 1;
}
}
return ii;
}
return seq.__iterateUncached(fn, reverse);
}
function seqIterator(seq, type, reverse, useKeys) {
var cache = seq._cache;
if (cache) {
var maxIndex = cache.length - 1;
var ii = 0;
return new Iterator(function() {
var entry = cache[reverse ? maxIndex - ii : ii];
return ii++ > maxIndex ?
iteratorDone() :
iteratorValue(type, useKeys ? entry[0] : ii - 1, entry[1]);
});
}
return seq.__iteratorUncached(type, reverse);
}
createClass(Collection, Iterable);
function Collection() {
throw TypeError('Abstract');
}
createClass(KeyedCollection, Collection);function KeyedCollection() {}
createClass(IndexedCollection, Collection);function IndexedCollection() {}
createClass(SetCollection, Collection);function SetCollection() {}
Collection.Keyed = KeyedCollection;
Collection.Indexed = IndexedCollection;
Collection.Set = SetCollection;
/**
* An extension of the "same-value" algorithm as [described for use by ES6 Map
* and Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Key_equality)
*
* NaN is considered the same as NaN, however -0 and 0 are considered the same
* value, which is different from the algorithm described by
* [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is).
*
* This is extended further to allow Objects to describe the values they
* represent, by way of `valueOf` or `equals` (and `hashCode`).
*
* Note: because of this extension, the key equality of Immutable.Map and the
* value equality of Immutable.Set will differ from ES6 Map and Set.
*
* ### Defining custom values
*
* The easiest way to describe the value an object represents is by implementing
* `valueOf`. For example, `Date` represents a value by returning a unix
* timestamp for `valueOf`:
*
* var date1 = new Date(1234567890000); // Fri Feb 13 2009 ...
* var date2 = new Date(1234567890000);
* date1.valueOf(); // 1234567890000
* assert( date1 !== date2 );
* assert( Immutable.is( date1, date2 ) );
*
* Note: overriding `valueOf` may have other implications if you use this object
* where JavaScript expects a primitive, such as implicit string coercion.
*
* For more complex types, especially collections, implementing `valueOf` may
* not be performant. An alternative is to implement `equals` and `hashCode`.
*
* `equals` takes another object, presumably of similar type, and returns true
* if the it is equal. Equality is symmetrical, so the same result should be
* returned if this and the argument are flipped.
*
* assert( a.equals(b) === b.equals(a) );
*
* `hashCode` returns a 32bit integer number representing the object which will
* be used to determine how to store the value object in a Map or Set. You must
* provide both or neither methods, one must not exist without the other.
*
* Also, an important relationship between these methods must be upheld: if two
* values are equal, they *must* return the same hashCode. If the values are not
* equal, they might have the same hashCode; this is called a hash collision,
* and while undesirable for performance reasons, it is acceptable.
*
* if (a.equals(b)) {
* assert( a.hashCode() === b.hashCode() );
* }
*
* All Immutable collections implement `equals` and `hashCode`.
*
*/
function is(valueA, valueB) {
if (valueA === valueB || (valueA !== valueA && valueB !== valueB)) {
return true;
}
if (!valueA || !valueB) {
return false;
}
if (typeof valueA.valueOf === 'function' &&
typeof valueB.valueOf === 'function') {
valueA = valueA.valueOf();
valueB = valueB.valueOf();
}
return typeof valueA.equals === 'function' &&
typeof valueB.equals === 'function' ?
valueA.equals(valueB) :
valueA === valueB || (valueA !== valueA && valueB !== valueB);
}
function fromJS(json, converter) {
return converter ?
fromJSWith(converter, json, '', {'': json}) :
fromJSDefault(json);
}
function fromJSWith(converter, json, key, parentJSON) {
if (Array.isArray(json)) {
return converter.call(parentJSON, key, IndexedSeq(json).map(function(v, k) {return fromJSWith(converter, v, k, json)}));
}
if (isPlainObj(json)) {
return converter.call(parentJSON, key, KeyedSeq(json).map(function(v, k) {return fromJSWith(converter, v, k, json)}));
}
return json;
}
function fromJSDefault(json) {
if (Array.isArray(json)) {
return IndexedSeq(json).map(fromJSDefault).toList();
}
if (isPlainObj(json)) {
return KeyedSeq(json).map(fromJSDefault).toMap();
}
return json;
}
function isPlainObj(value) {
return value && value.constructor === Object;
}
var Math__imul =
typeof Math.imul === 'function' && Math.imul(0xffffffff, 2) === -2 ?
Math.imul :
function Math__imul(a, b) {
a = a | 0; // int
b = b | 0; // int
var c = a & 0xffff;
var d = b & 0xffff;
// Shift by 0 fixes the sign on the high part.
return (c * d) + ((((a >>> 16) * d + c * (b >>> 16)) << 16) >>> 0) | 0; // int
};
// v8 has an optimization for storing 31-bit signed numbers.
// Values which have either 00 or 11 as the high order bits qualify.
// This function drops the highest order bit in a signed number, maintaining
// the sign bit.
function smi(i32) {
return ((i32 >>> 1) & 0x40000000) | (i32 & 0xBFFFFFFF);
}
function hash(o) {
if (o === false || o === null || o === undefined) {
return 0;
}
if (typeof o.valueOf === 'function') {
o = o.valueOf();
if (o === false || o === null || o === undefined) {
return 0;
}
}
if (o === true) {
return 1;
}
var type = typeof o;
if (type === 'number') {
var h = o | 0;
if (h !== o) {
h ^= o * 0xFFFFFFFF;
}
while (o > 0xFFFFFFFF) {
o /= 0xFFFFFFFF;
h ^= o;
}
return smi(h);
}
if (type === 'string') {
return o.length > STRING_HASH_CACHE_MIN_STRLEN ? cachedHashString(o) : hashString(o);
}
if (typeof o.hashCode === 'function') {
return o.hashCode();
}
return hashJSObj(o);
}
function cachedHashString(string) {
var hash = stringHashCache[string];
if (hash === undefined) {
hash = hashString(string);
if (STRING_HASH_CACHE_SIZE === STRING_HASH_CACHE_MAX_SIZE) {
STRING_HASH_CACHE_SIZE = 0;
stringHashCache = {};
}
STRING_HASH_CACHE_SIZE++;
stringHashCache[string] = hash;
}
return hash;
}
// http://jsperf.com/hashing-strings
function hashString(string) {
// This is the hash from JVM
// The hash code for a string is computed as
// s[0] * 31 ^ (n - 1) + s[1] * 31 ^ (n - 2) + ... + s[n - 1],
// where s[i] is the ith character of the string and n is the length of
// the string. We "mod" the result to make it between 0 (inclusive) and 2^31
// (exclusive) by dropping high bits.
var hash = 0;
for (var ii = 0; ii < string.length; ii++) {
hash = 31 * hash + string.charCodeAt(ii) | 0;
}
return smi(hash);
}
function hashJSObj(obj) {
var hash = weakMap && weakMap.get(obj);
if (hash) return hash;
hash = obj[UID_HASH_KEY];
if (hash) return hash;
if (!canDefineProperty) {
hash = obj.propertyIsEnumerable && obj.propertyIsEnumerable[UID_HASH_KEY];
if (hash) return hash;
hash = getIENodeHash(obj);
if (hash) return hash;
}
if (Object.isExtensible && !Object.isExtensible(obj)) {
throw new Error('Non-extensible objects are not allowed as keys.');
}
hash = ++objHashUID;
if (objHashUID & 0x40000000) {
objHashUID = 0;
}
if (weakMap) {
weakMap.set(obj, hash);
} else if (canDefineProperty) {
Object.defineProperty(obj, UID_HASH_KEY, {
'enumerable': false,
'configurable': false,
'writable': false,
'value': hash
});
} else if (obj.propertyIsEnumerable &&
obj.propertyIsEnumerable === obj.constructor.prototype.propertyIsEnumerable) {
// Since we can't define a non-enumerable property on the object
// we'll hijack one of the less-used non-enumerable properties to
// save our hash on it. Since this is a function it will not show up in
// `JSON.stringify` which is what we want.
obj.propertyIsEnumerable = function() {
return this.constructor.prototype.propertyIsEnumerable.apply(this, arguments);
};
obj.propertyIsEnumerable[UID_HASH_KEY] = hash;
} else if (obj.nodeType) {
// At this point we couldn't get the IE `uniqueID` to use as a hash
// and we couldn't use a non-enumerable property to exploit the
// dontEnum bug so we simply add the `UID_HASH_KEY` on the node
// itself.
obj[UID_HASH_KEY] = hash;
} else {
throw new Error('Unable to set a non-enumerable property on object.');
}
return hash;
}
// True if Object.defineProperty works as expected. IE8 fails this test.
var canDefineProperty = (function() {
try {
Object.defineProperty({}, 'x', {});
return true;
} catch (e) {
return false;
}
}());
// IE has a `uniqueID` property on DOM nodes. We can construct the hash from it
// and avoid memory leaks from the IE cloneNode bug.
function getIENode