json-tree-view
Version:
A JSON Tree View Component, for browsering or editing JSON object. Fork from json-view writing by Richard Livingston.
2,028 lines (1,709 loc) • 143 kB
JavaScript
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
/**
* Created by richard.livingston on 18/02/2017.
*/
'use strict';
var util = require('util'),
EE = require('events').EventEmitter;
module.exports = JSONTreeView;
util.inherits(JSONTreeView, EE);
function JSONTreeView(name_, value_, parent_, isRoot_){
var self = this;
if (typeof isRoot_ === 'undefined' && arguments.length < 4) {
isRoot_ = true;
}
EE.call(self);
if(arguments.length < 2){
value_ = name_;
name_ = undefined;
}
var name, value, type, oldType = null, filterText = '', hidden = false,
readonly = parent_ ? parent_.readonly : false,
readonlyWhenFiltering = parent_ ? parent_.readonlyWhenFiltering : false,
alwaysShowRoot = false,
showCount = parent_ ? parent_.showCountOfObjectOrArray : true,
includingRootName = true,
domEventListeners = [], children = [], expanded = false,
edittingName = false, edittingValue = false,
nameEditable = true, valueEditable = true;
var dom = {
container : document.createElement('div'),
collapseExpand : document.createElement('div'),
name : document.createElement('div'),
separator : document.createElement('div'),
value : document.createElement('div'),
spacing: document.createElement('div'),
delete : document.createElement('div'),
children : document.createElement('div'),
insert : document.createElement('div')
};
Object.defineProperties(self, {
dom : {
value : dom.container,
enumerable : true
},
isRoot: {
get : function(){
return isRoot_;
}
},
parent: {
get: function() {
return parent_;
}
},
children: {
get: function() {
var result = null;
if (type === 'array') {
result = children;
}
else if (type === 'object') {
result = {};
children.forEach(function(e) {
result[e.name] = e;
});
}
return result;
}
},
readonly: {
get: function() {
return !!(readonly & 1);
},
set: function(ro) {
readonly = setBit(readonly, 0, +ro);
!!(readonly & 1) ? dom.container.classList.add('readonly')
: dom.container.classList.remove('readonly');
for (var i in children) {
if (typeof children[i] === 'object') {
children[i].readonly = setBit(readonly, 0, +ro);
}
}
}
},
readonlyWhenFiltering: {
get: function() {
return readonlyWhenFiltering;
},
set: function(rowf) {
readonly = setBit(readonly, 1, +rowf);
readonlyWhenFiltering = rowf;
(readonly && this.filterText) || !!(readonly & 1)
? dom.container.classList.add('readonly')
: dom.container.classList.remove('readonly');
for (var i in children) {
if (typeof children[i] === 'object') {
children[i].readonly = setBit(readonly, 1, +rowf);
children[i].readonlyWhenFiltering = rowf;
}
}
}
},
hidden: {
get: function() {
return hidden;
},
set: function(h) {
hidden = h;
h ? dom.container.classList.add('hidden')
: dom.container.classList.remove('hidden');
if (!h) {
parent_ && (parent_.hidden = h);
}
}
},
showCountOfObjectOrArray: {
get: function() {
return showCount;
},
set: function(show) {
showCount = show;
for (var i in children) {
if (typeof children[i] === 'object') {
children[i].showCountOfObjectOrArray = show;
}
}
(this.type === 'object' || this.type === 'array') && this.updateCount();
}
},
filterText: {
get: function() {
return filterText;
},
set: function(text) {
filterText = text;
if (text) {
if (readonly > 0) {
dom.container.classList.add('readonly');
}
var key = this.name + '';
var value = this.value + '';
if (this.type === 'object' || this.type === 'array') {
value = '';
}
if (key.indexOf(text) > -1 || value.indexOf(text) > -1) {
this.hidden = false;
}
else {
if (!this.alwaysShowRoot || !isRoot_) {
this.hidden = true;
}
}
}
else {
!this.readonly && dom.container.classList.remove('readonly');
this.hidden = false;
}
for (var i in children) {
if (typeof children[i] === 'object') {
children[i].filterText = text;
}
}
}
},
alwaysShowRoot: {
get: function() {
return alwaysShowRoot;
},
set: function(value) {
if (isRoot_ && this.filterText) {
this.hidden = !value;
}
alwaysShowRoot = value;
for (var i in children) {
if (typeof children[i] === 'object') {
children[i].alwaysShowRoot = value;
}
}
}
},
withRootName: {
get: function() {
return includingRootName;
},
set: function(value) {
includingRootName = value;
}
},
name : {
get : function(){
return name;
},
set : setName,
enumerable : true
},
value : {
get : function(){
return value;
},
set : setValue,
enumerable : true
},
type : {
get : function(){
return type;
},
enumerable : true
},
oldType: {
get: function () {
return oldType;
},
enumerable: true
},
nameEditable : {
get : function(){
return nameEditable;
},
set : function(value){
nameEditable = !!value;
},
enumerable : true
},
valueEditable : {
get : function(){
return valueEditable;
},
set : function(value){
valueEditable = !!value;
},
enumerable : true
},
refresh : {
value : refresh,
enumerable : true
},
updateCount: {
value: updateObjectChildCount,
enumerable: true
},
collapse : {
value : collapse,
enumerable : true
},
expand : {
value : expand,
enumerable : true
},
destroy : {
value : destroy,
enumerable : true
},
editName : {
value : editField.bind(null, 'name'),
enumerable : true
},
editValue : {
value : editField.bind(null, 'value'),
enumerable : true
}
});
Object.keys(dom).forEach(function(k){
if (k === 'delete' && self.isRoot) {
return;
}
var element = dom[k];
if(k == 'container'){
return;
}
element.className = k;
if (['name', 'separator', 'value', 'spacing'].indexOf(k) > -1) {
element.className += ' item';
}
dom.container.appendChild(element);
});
dom.container.className = 'jsonView';
addDomEventListener(dom.collapseExpand, 'click', onCollapseExpandClick);
addDomEventListener(dom.value, 'click', expand.bind(null, false));
addDomEventListener(dom.name, 'click', expand.bind(null, false));
addDomEventListener(dom.name, 'dblclick', editField.bind(null, 'name'));
addDomEventListener(dom.name, 'click', itemClicked.bind(null, 'name'));
addDomEventListener(dom.name, 'blur', editFieldStop.bind(null, 'name'));
addDomEventListener(dom.name, 'keypress',
editFieldKeyPressed.bind(null, 'name'));
addDomEventListener(dom.name, 'keydown',
editFieldTabPressed.bind(null, 'name'));
addDomEventListener(dom.value, 'dblclick', editField.bind(null, 'value'));
addDomEventListener(dom.value, 'click', itemClicked.bind(null, 'value'));
addDomEventListener(dom.value, 'blur', editFieldStop.bind(null, 'value'));
addDomEventListener(dom.value, 'keypress',
editFieldKeyPressed.bind(null, 'value'));
addDomEventListener(dom.value, 'keydown',
editFieldTabPressed.bind(null, 'value'));
addDomEventListener(dom.value, 'keydown', numericValueKeyDown);
addDomEventListener(dom.insert, 'click', onInsertClick);
addDomEventListener(dom.delete, 'click', onDeleteClick);
setName(name_);
setValue(value_);
function setBit(n, i, b) {
var j = 0;
while ((n >> j << j)) {
j++;
}
return i >= j
? (n | +b << i )
: (n >> (i + 1) << (i + 1)) | (n % (n >> i << i)) | (+b << i);
}
function squarebracketify(exp) {
return typeof exp === 'string'
? exp.replace(/\.([0-9]+)/g, '[$1]') : exp + '';
}
function refresh(silent){
var expandable = type == 'object' || type == 'array';
children.forEach(function(child){
child.refresh(true);
});
dom.collapseExpand.style.display = expandable ? '' : 'none';
if(expanded && expandable){
expand(false, silent);
}
else{
collapse(false, silent);
}
if (!silent) {
self.emit('refresh', self, [self.name], self.value);
}
}
function collapse(recursive, silent){
if(recursive){
children.forEach(function(child){
child.collapse(true, true);
});
}
expanded = false;
dom.children.style.display = 'none';
dom.collapseExpand.className = 'expand';
dom.container.classList.add('collapsed');
dom.container.classList.remove('expanded');
if (!silent && (type == 'object' || type == 'array')) {
self.emit('collapse', self, [self.name], self.value);
}
}
function expand(recursive, silent){
var keys;
if(type == 'object'){
keys = Object.keys(value);
}
else if(type == 'array'){
keys = value.map(function(v, k){
return k;
});
}
else{
keys = [];
}
// Remove children that no longer exist
for(var i = children.length - 1; i >= 0; i --){
var child = children[i];
if (!child) {
break;
}
if(keys.indexOf(child.name) == -1){
children.splice(i, 1);
removeChild(child);
}
}
if(type != 'object' && type != 'array'){
return collapse();
}
keys.forEach(function(key){
addChild(key, value[key]);
});
if(recursive){
children.forEach(function(child){
child.expand(true, true);
});
}
expanded = true;
dom.children.style.display = '';
dom.collapseExpand.className = 'collapse';
dom.container.classList.add('expanded');
dom.container.classList.remove('collapsed');
if (!silent && (type == 'object' || type == 'array')) {
self.emit('expand', self, [self.name], self.value);
}
}
function destroy(){
var child, event;
while(event = domEventListeners.pop()){
event.element.removeEventListener(event.name, event.fn);
}
while(child = children.pop()){
removeChild(child);
}
}
function setName(newName){
var nameType = typeof newName,
oldName = name;
if(newName === name){
return;
}
if(nameType != 'string' && nameType != 'number'){
throw new Error('Name must be either string or number, ' + newName);
}
dom.name.innerText = newName;
name = newName;
self.emit('rename', self, [name], oldName, newName, true);
}
function setValue(newValue){
var oldValue = value,
str, len;
if (isRoot_ && !oldValue) {
oldValue = newValue;
}
type = getType(newValue);
oldType = oldValue ? getType(oldValue) : type;
switch(type){
case 'null':
str = 'null';
break;
case 'undefined':
str = 'undefined';
break;
case 'object':
len = Object.keys(newValue).length;
str = showCount ? 'Object[' + len + ']' : (len < 1 ? '{}' : '');
break;
case 'array':
len = newValue.length;
str = showCount ? 'Array[' + len + ']' : (len < 1 ? '[]' : '');
break;
default:
str = newValue;
break;
}
dom.value.innerText = str;
dom.value.className = 'value item ' + type;
if(newValue === value){
return;
}
value = newValue;
if(type == 'array' || type == 'object'){
// Cannot edit objects as string because the formatting is too messy
// Would have to either pass as JSON and force user to wrap properties in quotes
// Or first JSON stringify the input before passing, this could allow users to reference globals
// Instead the user can modify individual properties, or just delete the object and start again
valueEditable = false;
if(type == 'array'){
// Obviously cannot modify array keys
nameEditable = false;
}
}
self.emit('change', self, [name], oldValue, newValue);
refresh();
}
function updateObjectChildCount() {
var str = '', len;
if (type === 'object') {
len = Object.keys(value).length;
str = showCount ? 'Object[' + len + ']' : (len < 1 ? '{}' : '');
}
if (type === 'array') {
len = value.length;
str = showCount ? 'Array[' + len + ']' : (len < 1 ? '[]' : '');
}
dom.value.innerText = str;
}
function addChild(key, val){
var child;
for(var i = 0, len = children.length; i < len; i ++){
if(children[i].name == key){
child = children[i];
break;
}
}
if(child){
child.value = val;
}
else{
child = new JSONTreeView(key, val, self, false);
child.on('rename', onChildRename);
child.on('delete', onChildDelete);
child.on('change', onChildChange);
child.on('append', onChildAppend);
child.on('click', onChildClick);
child.on('expand', onChildExpand);
child.on('collapse', onChildCollapse);
child.on('refresh', onChildRefresh);
children.push(child);
child.emit('append', child, [key], 'value', val, true);
}
dom.children.appendChild(child.dom);
return child;
}
function removeChild(child){
if(child.dom.parentNode){
dom.children.removeChild(child.dom);
}
child.destroy();
child.emit('delete', child, [child.name], child.value,
child.parent.isRoot ? child.parent.oldType : child.parent.type, true);
child.removeAllListeners();
}
function editField(field){
if((readonly > 0 && filterText) || !!(readonly & 1)) {
return;
}
if(field === 'value' && (type === 'object' || type === 'array')){
return;
}
if(parent_ && parent_.type == 'array'){
// Obviously cannot modify array keys
nameEditable = false;
}
var editable = field == 'name' ? nameEditable : valueEditable,
element = dom[field];
if(!editable && (parent_ && parent_.type === 'array')){
if (!parent_.inserting) {
// throw new Error('Cannot edit an array index.');
return;
}
}
if(field == 'value' && type == 'string'){
element.innerText = '"' + value + '"';
}
if(field == 'name'){
edittingName = true;
}
if(field == 'value'){
edittingValue = true;
}
element.classList.add('edit');
element.setAttribute('contenteditable', true);
element.focus();
document.execCommand('selectAll', false, null);
}
function itemClicked(field) {
self.emit('click', self,
!self.withRootName && self.isRoot ? [''] : [self.name], self.value);
}
function editFieldStop(field){
var element = dom[field];
if(field == 'name'){
if(!edittingName){
return;
}
edittingName = false;
}
if(field == 'value'){
if(!edittingValue){
return;
}
edittingValue = false;
}
if(field == 'name'){
var p = self.parent;
var edittingNameText = element.innerText;
if (p && p.type === 'object' && edittingNameText in p.value) {
element.innerText = name;
element.classList.remove('edit');
element.removeAttribute('contenteditable');
// throw new Error('Name exist, ' + edittingNameText);
}
else {
setName.call(self, edittingNameText);
}
}
else{
var text = element.innerText;
try{
setValue(text === 'undefined' ? undefined : JSON.parse(text));
}
catch(err){
setValue(text);
}
}
element.classList.remove('edit');
element.removeAttribute('contenteditable');
}
function editFieldKeyPressed(field, e){
switch(e.key){
case 'Escape':
case 'Enter':
editFieldStop(field);
break;
}
}
function editFieldTabPressed(field, e){
if(e.key == 'Tab'){
editFieldStop(field);
if(field == 'name'){
e.preventDefault();
editField('value');
}
else{
editFieldStop(field);
}
}
}
function numericValueKeyDown(e){
var increment = 0, currentValue;
if(type != 'number'){
return;
}
switch(e.key){
case 'ArrowDown':
case 'Down':
increment = -1;
break;
case 'ArrowUp':
case 'Up':
increment = 1;
break;
}
if(e.shiftKey){
increment *= 10;
}
if(e.ctrlKey || e.metaKey){
increment /= 10;
}
if(increment){
currentValue = parseFloat(dom.value.innerText);
if(!isNaN(currentValue)){
setValue(Number((currentValue + increment).toFixed(10)));
}
}
}
function getType(value){
var type = typeof value;
if(type == 'object'){
if(value === null){
return 'null';
}
if(Array.isArray(value)){
return 'array';
}
}
if (type === 'undefined') {
return 'undefined';
}
return type;
}
function onCollapseExpandClick(){
if(expanded){
collapse();
}
else{
expand();
}
}
function onInsertClick(){
var newName = type == 'array' ? value.length : undefined,
child = addChild(newName, null);
if (child.parent) {
child.parent.inserting = true;
}
if(type == 'array'){
value.push(null);
child.editValue();
child.emit('append', self, [value.length - 1], 'value', null, true);
if (child.parent) {
child.parent.inserting = false;
}
}
else{
child.editName();
}
}
function onDeleteClick(){
self.emit('delete', self, [self.name], self.value,
self.parent.isRoot ? self.parent.oldType : self.parent.type, false);
}
function onChildRename(child, keyPath, oldName, newName, original){
var allow = newName && type != 'array' && !(newName in value) && original;
if(allow){
value[newName] = child.value;
delete value[oldName];
if (self.inserting) {
child.emit('append', child, [newName], 'name', newName, true);
self.inserting = false;
return;
}
}
else if(oldName === undefined){
// A new node inserted via the UI
original && removeChild(child);
}
else if (original){
// Cannot rename array keys, or duplicate object key names
child.name = oldName;
return;
}
// value[keyPath] = newName;
// child.once('rename', onChildRename);
if (self.withRootName || !self.isRoot) {
keyPath.unshift(name);
}
else if (self.withRootName && self.isRoot) {
keyPath.unshift(name);
}
if (oldName !== undefined) {
self.emit('rename', child, keyPath, oldName, newName, false);
}
}
function onChildAppend(child, keyPath, nameOrValue, newValue, sender){
if (self.withRootName || !self.isRoot) {
keyPath.unshift(name);
}
self.emit('append', child, keyPath, nameOrValue, newValue, false);
sender && updateObjectChildCount();
}
function onChildChange(child, keyPath, oldValue, newValue, recursed){
if(!recursed){
value[keyPath] = newValue;
}
if (self.withRootName || !self.isRoot) {
keyPath.unshift(name);
}
self.emit('change', child, keyPath, oldValue, newValue, true);
}
function onChildDelete(child, keyPath, deletedValue, parentType, passive){
var key = child.name;
if (passive) {
if (self.withRootName/* || !self.isRoot*/) {
keyPath.unshift(name);
}
self.emit('delete', child, keyPath, deletedValue, parentType, passive);
updateObjectChildCount();
}
else {
if (type == 'array') {
value.splice(key, 1);
}
else {
delete value[key];
}
refresh(true);
}
}
function onChildClick(child, keyPath, value) {
if (self.withRootName || !self.isRoot) {
keyPath.unshift(name);
}
self.emit('click', child, keyPath, value);
}
function onChildExpand(child, keyPath, value) {
if (self.withRootName || !self.isRoot) {
keyPath.unshift(name);
}
self.emit('expand', child, keyPath, value);
}
function onChildCollapse(child, keyPath, value) {
if (self.withRootName || !self.isRoot) {
keyPath.unshift(name);
}
self.emit('collapse', child, keyPath, value);
}
function onChildRefresh(child, keyPath, value) {
if (self.withRootName || !self.isRoot) {
keyPath.unshift(name);
}
self.emit('refresh', child, keyPath, value);
}
function addDomEventListener(element, name, fn){
element.addEventListener(name, fn);
domEventListeners.push({element : element, name : name, fn : fn});
}
}
},{"events":3,"util":7}],2:[function(require,module,exports){
/**
* Created by r1ch4 on 02/10/2016.
*/
var JSONTreeView = require('json-tree-view');
var view = new JSONTreeView('example', {
hello : 'world',
doubleClick : 'me to edit',
a : null,
b : true,
c : false,
d : 1,
e : {nested : 'object'},
f : [1,2,3]
}, null);
view.expand(true);
view.withRootName = true;
view.on('change', function(self, keyPath, oldValue, newValue){
console.log('change', keyPath, oldValue, '=>', newValue);
});
view.on('rename', function (self, keyPath, oldName, newName) {
console.log('rename', keyPath, oldName, '=>', newName);
});
view.on('delete', function (self, keyPath, value, parentType) {
console.log('delete', keyPath, '=>', value, parentType);
});
view.on('append', function (self, keyPath, nameOrValue, newValue) {
console.log('append', keyPath, nameOrValue, '=>', newValue);
});
view.on('click', function (self, keyPath, value) {
console.log('click', keyPath, '=>', value);
});
view.on('expand', function (self, keyPath, value) {
console.log('expand', keyPath, '=>', value);
});
view.on('collapse', function (self, keyPath, value) {
console.log('collapse', keyPath, '=>', value);
});
view.on('refresh', function (self, keyPath, value) {
console.log('refresh', keyPath, '=>', value);
});
document.body.appendChild(view.dom);
window.view = view;
view.value.f.pop()
view.value.f.push(9)
view.value.e.a = 'aaa';
view.value.e.d = 'ddd';
delete view.value.c;
view.refresh();
/*
view.alwaysShowRoot = true;
view.readonlyWhenFiltering = true;
view.filterText = 'a';
view.filterText = null;
view.readonly = true;
*/
document.getElementById('filter').addEventListener('input', function() {
view.filterText = this.value;
});
document.getElementById('root').addEventListener('change', function() {
view.alwaysShowRoot = !!this.checked;
});
document.getElementById('rowf').addEventListener('change', function() {
view.readonlyWhenFiltering = !!this.checked;
});
document.getElementById('ro').addEventListener('change', function() {
view.readonly = !!this.checked;
});
document.getElementById('sc').addEventListener('change', function () {
view.showCountOfObjectOrArray = !!this.checked;
});
document.getElementById('wr').addEventListener('change', function () {
view.withRootName = !!this.checked;
});
},{"json-tree-view":1}],3:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.
function EventEmitter() {
this._events = this._events || {};
this._maxListeners = this._maxListeners || undefined;
}
module.exports = EventEmitter;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter.defaultMaxListeners = 10;
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function(n) {
if (!isNumber(n) || n < 0 || isNaN(n))
throw TypeError('n must be a positive number');
this._maxListeners = n;
return this;
};
EventEmitter.prototype.emit = function(type) {
var er, handler, len, args, i, listeners;
if (!this._events)
this._events = {};
// If there is no 'error' event listener then throw.
if (type === 'error') {
if (!this._events.error ||
(isObject(this._events.error) && !this._events.error.length)) {
er = arguments[1];
if (er instanceof Error) {
throw er; // Unhandled 'error' event
} else {
// At least give some kind of context to the user
var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
err.context = er;
throw err;
}
}
}
handler = this._events[type];
if (isUndefined(handler))
return false;
if (isFunction(handler)) {
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
args = Array.prototype.slice.call(arguments, 1);
handler.apply(this, args);
}
} else if (isObject(handler)) {
args = Array.prototype.slice.call(arguments, 1);
listeners = handler.slice();
len = listeners.length;
for (i = 0; i < len; i++)
listeners[i].apply(this, args);
}
return true;
};
EventEmitter.prototype.addListener = function(type, listener) {
var m;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events)
this._events = {};
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (this._events.newListener)
this.emit('newListener', type,
isFunction(listener.listener) ?
listener.listener : listener);
if (!this._events[type])
// Optimize the case of one listener. Don't need the extra array object.
this._events[type] = listener;
else if (isObject(this._events[type]))
// If we've already got an array, just append.
this._events[type].push(listener);
else
// Adding the second element, need to change to array.
this._events[type] = [this._events[type], listener];
// Check for listener leak
if (isObject(this._events[type]) && !this._events[type].warned) {
if (!isUndefined(this._maxListeners)) {
m = this._maxListeners;
} else {
m = EventEmitter.defaultMaxListeners;
}
if (m && m > 0 && this._events[type].length > m) {
this._events[type].warned = true;
console.error('(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.',
this._events[type].length);
if (typeof console.trace === 'function') {
// not supported in IE 10
console.trace();
}
}
}
return this;
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.once = function(type, listener) {
if (!isFunction(listener))
throw TypeError('listener must be a function');
var fired = false;
function g() {
this.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(this, arguments);
}
}
g.listener = listener;
this.on(type, g);
return this;
};
// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener = function(type, listener) {
var list, position, length, i;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events || !this._events[type])
return this;
list = this._events[type];
length = list.length;
position = -1;
if (list === listener ||
(isFunction(list.listener) && list.listener === listener)) {
delete this._events[type];
if (this._events.removeListener)
this.emit('removeListener', type, listener);
} else if (isObject(list)) {
for (i = length; i-- > 0;) {
if (list[i] === listener ||
(list[i].listener && list[i].listener === listener)) {
position = i;
break;
}
}
if (position < 0)
return this;
if (list.length === 1) {
list.length = 0;
delete this._events[type];
} else {
list.splice(position, 1);
}
if (this._events.removeListener)
this.emit('removeListener', type, listener);
}
return this;
};
EventEmitter.prototype.removeAllListeners = function(type) {
var key, listeners;
if (!this._events)
return this;
// not listening for removeListener, no need to emit
if (!this._events.removeListener) {
if (arguments.length === 0)
this._events = {};
else if (this._events[type])
delete this._events[type];
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
for (key in this._events) {
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = {};
return this;
}
listeners = this._events[type];
if (isFunction(listeners)) {
this.removeListener(type, listeners);
} else if (listeners) {
// LIFO order
while (listeners.length)
this.removeListener(type, listeners[listeners.length - 1]);
}
delete this._events[type];
return this;
};
EventEmitter.prototype.listeners = function(type) {
var ret;
if (!this._events || !this._events[type])
ret = [];
else if (isFunction(this._events[type]))
ret = [this._events[type]];
else
ret = this._events[type].slice();
return ret;
};
EventEmitter.prototype.listenerCount = function(type) {
if (this._events) {
var evlistener = this._events[type];
if (isFunction(evlistener))
return 1;
else if (evlistener)
return evlistener.length;
}
return 0;
};
EventEmitter.listenerCount = function(emitter, type) {
return emitter.listenerCount(type);
};
function isFunction(arg) {
return typeof arg === 'function';
}
function isNumber(arg) {
return typeof arg === 'number';
}
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
function isUndefined(arg) {
return arg === void 0;
}
},{}],4:[function(require,module,exports){
// shim for using process in browser
var process = module.exports = {};
// cached from whatever global is present so that test runners that stub it
// don't break things. But we need to wrap it in a try catch in case it is
// wrapped in strict mode code which doesn't define any globals. It's inside a
// function because try/catches deoptimize in certain engines.
var cachedSetTimeout;
var cachedClearTimeout;
function defaultSetTimout() {
throw new Error('setTimeout has not been defined');
}
function defaultClearTimeout () {
throw new Error('clearTimeout has not been defined');
}
(function () {
try {
if (typeof setTimeout === 'function') {
cachedSetTimeout = setTimeout;
} else {
cachedSetTimeout = defaultSetTimout;
}
} catch (e) {
cachedSetTimeout = defaultSetTimout;
}
try {
if (typeof clearTimeout === 'function') {
cachedClearTimeout = clearTimeout;
} else {
cachedClearTimeout = defaultClearTimeout;
}
} catch (e) {
cachedClearTimeout = defaultClearTimeout;
}
} ())
function runTimeout(fun) {
if (cachedSetTimeout === setTimeout) {
//normal enviroments in sane situations
return setTimeout(fun, 0);
}
// if setTimeout wasn't available but was latter defined
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
cachedSetTimeout = setTimeout;
return setTimeout(fun, 0);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedSetTimeout(fun, 0);
} catch(e){
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedSetTimeout.call(null, fun, 0);
} catch(e){
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
return cachedSetTimeout.call(this, fun, 0);
}
}
}
function runClearTimeout(marker) {
if (cachedClearTimeout === clearTimeout) {
//normal enviroments in sane situations
return clearTimeout(marker);
}
// if clearTimeout wasn't available but was latter defined
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
cachedClearTimeout = clearTimeout;
return clearTimeout(marker);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedClearTimeout(marker);
} catch (e){
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedClearTimeout.call(null, marker);
} catch (e){
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
return cachedClearTimeout.call(this, marker);
}
}
}
var queue = [];
var draining = false;
var currentQueue;
var queueIndex = -1;
function cleanUpNextTick() {
if (!draining || !currentQueue) {
return;
}
draining = false;
if (currentQueue.length) {
queue = currentQueue.concat(queue);
} else {
queueIndex = -1;
}
if (queue.length) {
drainQueue();
}
}
function drainQueue() {
if (draining) {
return;
}
var timeout = runTimeout(cleanUpNextTick);
draining = true;
var len = queue.length;
while(len) {
currentQueue = queue;
queue = [];
while (++queueIndex < len) {
if (currentQueue) {
currentQueue[queueIndex].run();
}
}
queueIndex = -1;
len = queue.length;
}
currentQueue = null;
draining = false;
runClearTimeout(timeout);
}
process.nextTick = function (fun) {
var args = new Array(arguments.length - 1);
if (arguments.length > 1) {
for (var i = 1; i < arguments.length; i++) {
args[i - 1] = arguments[i];
}
}
queue.push(new Item(fun, args));
if (queue.length === 1 && !draining) {
runTimeout(drainQueue);
}
};
// v8 likes predictible objects
function Item(fun, array) {
this.fun = fun;
this.array = array;
}
Item.prototype.run = function () {
this.fun.apply(null, this.array);
};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
process.versions = {};
function noop() {}
process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;
process.prependListener = noop;
process.prependOnceListener = noop;
process.listeners = function (name) { return [] }
process.binding = function (name) {
throw new Error('process.binding is not supported');
};
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){
if (typeof Object.create === 'function') {
// implementation from standard node.js 'util' module
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
} else {
// old school shim for old browsers
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
var TempCtor = function () {}
TempCtor.prototype = superCtor.prototype
ctor.prototype = new TempCtor()
ctor.prototype.constructor = ctor
}
}
},{}],6:[function(require,module,exports){
module.exports = function isBuffer(arg) {
return arg && typeof arg === 'object'
&& typeof arg.copy === 'function'
&& typeof arg.fill === 'function'
&& typeof arg.readUInt8 === 'function';
}
},{}],7:[function(require,module,exports){
(function (process,global){
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.
var formatRegExp = /%[sdj%]/g;
exports.format = function(f) {
if (!isString(f)) {
var objects = [];
for (var i = 0; i < arguments.length; i++) {
objects.push(inspect(arguments[i]));
}
return objects.join(' ');
}
var i = 1;
var args = arguments;
var len = args.length;
var str = String(f).replace(formatRegExp, function(x) {
if (x === '%%') return '%';
if (i >= len) return x;
switch (x) {
case '%s': return String(args[i++]);
case '%d': return Number(args[i++]);
case '%j':
try {
return JSON.stringify(args[i++]);
} catch (_) {
return '[Circular]';
}
default:
return x;
}
});
for (var x = args[i]; i < len; x = args[++i]) {
if (isNull(x) || !isObject(x)) {
str += ' ' + x;
} else {
str += ' ' + inspect(x);
}
}
return str;
};
// Mark that a method should not be used.
// Returns a modified function which warns once by default.
// If --no-deprecation is set, then it is a no-op.
exports.deprecate = function(fn, msg) {
// Allow for deprecating things in the process of starting up.
if (isUndefined(global.process)) {
return function() {
return exports.deprecate(fn, msg).apply(this, arguments);
};
}
if (process.noDeprecation === true) {
return fn;
}
var warned = false;
function deprecated() {
if (!warned) {
if (process.throwDeprecation) {
throw new Error(msg);
} else if (process.traceDeprecation) {
console.trace(msg);
} else {
console.error(msg);
}
warned = true;
}
return fn.apply(this, arguments);
}
return deprecated;
};
var debugs = {};
var debugEnviron;
exports.debuglog = function(set) {
if (isUndefined(debugEnviron))
debugEnviron = process.env.NODE_DEBUG || '';
set = set.toUpperCase();
if (!debugs[set]) {
if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
var pid = process.pid;
debugs[set] = function() {
var msg = exports.format.apply(exports, arguments);
console.error('%s %d: %s', set, pid, msg);
};
} else {
debugs[set] = function() {};
}
}
return debugs[set];
};
/**
* Echos the value of a value. Trys to print the value out
* in the best way possible given the different types.
*
* @param {Object} obj The object to print out.
* @param {Object} opts Optional options object that alters the output.
*/
/* legacy: obj, showHidden, depth, colors*/
function inspect(obj, opts) {
// default options
var ctx = {
seen: [],
stylize: stylizeNoColor
};
// legacy...
if (arguments.length >= 3) ctx.depth = arguments[2];
if (arguments.length >= 4) ctx.colors = arguments[3];
if (isBoolean(opts)) {
// legacy...
ctx.showHidden = opts;
} else if (opts) {
// got an "options" object
exports._extend(ctx, opts);
}
// set default options
if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
if (isUndefined(ctx.depth)) ctx.depth = 2;
if (isUndefined(ctx.colors)) ctx.colors = false;
if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
if (ctx.colors) ctx.stylize = stylizeWithColor;
return formatValue(ctx, obj, ctx.depth);
}
exports.inspect = inspect;
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
inspect.colors = {
'bold' : [1, 22],
'italic' : [3, 23],
'underline' : [4, 24],
'inverse' : [7, 27],
'white' : [37, 39],
'grey' : [90, 39],
'black' : [30, 39],
'blue' : [34, 39],
'cyan' : [36, 39],
'green' : [32, 39],
'magenta' : [35, 39],
'red' : [31, 39],
'yellow' : [33, 39]
};
// Don't use 'blue' not visible on cmd.exe
inspect.styles = {
'special': 'cyan',
'number': 'yellow',
'boolean': 'yellow',
'undefined': 'grey',
'null': 'bold',
'string': 'green',
'date': 'magenta',
// "name": intentionally not styling
'regexp': 'red'
};
function stylizeWithColor(str, styleType) {
var style = inspect.styles[styleType];
if (style) {
return '\u001b[' + inspect.colors[style][0] + 'm' + str +
'\u001b[' + inspect.colors[style][1] + 'm';
} else {
return str;
}
}
function stylizeNoColor(str, styleType) {
return str;
}
function arrayToHash(array) {
var hash = {};
array.forEach(function(val, idx) {
hash[val] = true;
});
return hash;
}
function formatValue(ctx, value, recurseTimes) {
// Provide a hook for user-specified inspect functions.
// Check that value is an object with an inspect function on it
if (ctx.customInspect &&
value &&
isFunction(value.inspect) &&
// Filter out the util module, it's inspect function is special
value.inspect !== exports.inspect &&
// Also filter out any prototype objects using the circular check.
!(value.constructor && value.constructor.prototype === value)) {
var ret = value.inspect(recurseTimes, ctx);
if (!isString(ret)) {
ret = formatValue(ctx, ret, recurseTimes);
}
return ret;
}
// Primitive types cannot have properties
var primitive = formatPrimitive(ctx, value);
if (primitive) {
return primitive;
}
// Look up the keys of the object.
var keys = Object.keys(value);
var visibleKeys = arrayToHash(keys);
if (ctx.showHidden) {
keys = Object.getOwnPropertyNames(value);
}
// IE doesn't make error fields non-enumerable
// http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
if (isError(value)
&& (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
return formatError(value);
}
// Some type of object without properties can be shortcutted.
if (keys.length === 0) {
if (isFunction(value)) {
var name = value.name ? ': ' + value.name : '';
return ctx.stylize('[Function' + name + ']', 'special');
}
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
}
if (isDate(value)) {
return ctx.stylize(Date.prototype.toString.call(value), 'date');
}
if (isError(value)) {
return formatError(value);
}
}
var base = '', array = false, braces = ['{', '}'];
// Make Array say that they are Array
if (isArray(value)) {
array = true;
braces = ['[', ']'];
}
// Make functions say that they are functions
if (isFunction(value)) {
var n = value.name ? ': ' + value.name : '';
base = ' [Function' + n + ']';
}
// Make RegExps say that they are RegExps
if (isRegExp(value)) {
base = ' ' + RegExp.prototype.toString.call(value);
}
// Make dates with properties first say the date
if (isDate(value)) {
base = ' ' + Date.prototype.toUTCString.call(value);
}
// Make error with message first say the error
if (isError(value)) {
base = ' ' + formatError(value);
}
if (keys.length === 0 && (!array || value.length == 0)) {
return braces[0] + base + braces[1];
}
if (recurseTimes < 0) {
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
} else {
return ctx.stylize('[Object]', 'special');
}
}
ctx.seen.push(value);
var output;
if (array) {
output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
} else {
output = keys.map(function(key) {
return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
});
}
ctx.seen.pop();
return reduceToSingleString(output, base, braces);
}
function formatPrimitive(ctx, value) {
if (isUndefined(value))
return ctx.stylize('undefined', 'undefined');
if (isString(value)) {
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
.replace(/'/g, "\\'")
.replace(/\\"/g, '"') + '\'';
return ctx.stylize(simple, 'string');
}
if (isNumber(value))
return ctx.stylize('' + value, 'number');
if (isBoolean(value))
return ctx.stylize('' + value, 'boolean');
// For some reason typeof null is "object", so special case here.
if (isNull(value))
return ctx.stylize('null', 'null');
}
function formatError(value) {
return '[' + Error.prototype.toString.call(value) + ']';
}
function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
var output = [];
for (var i = 0, l = value.length; i < l; ++i) {
if (hasOwnProperty(value, String(i))) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
String(i), true));
} else {
output.push('');
}
}
keys.forEach(function(key) {
if (!key.match(/^\d+$/)) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
key, true));
}
});
return output;
}
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
var name, str, desc;
desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
if (desc.get) {
if (desc.set) {
str = ctx.stylize('[Getter/Setter]', 'special');
} else {
str = ctx.stylize('[Getter]', 'special');
}
} else {
if (desc.set) {
str = ctx.stylize('[Setter]', 'special');
}
}
if (!hasOwnProperty(visibleKeys, key)) {
name = '[' + key + ']';
}
if (!str) {
if (ctx.seen.indexOf(desc.value) < 0) {
if (isNull(recurseTimes)) {
str = formatValue(ctx, desc.value, null);
} else {
str = formatValue(ctx, desc.value, recurseTimes - 1);
}
if (str.indexOf('\n') > -1) {
if (array) {
str = str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n').substr(2);
} else {
str = '\n' + str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n');
}
}
} else {
str = ctx.stylize('[Circular]', 'special');
}
}
if (isUndefined(name)) {
if (array && key.match(/^\d+$/)) {
return str;
}
name = JSON.stringify('' + key);
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
name = name.substr(1, name.length - 2);
name = ctx.stylize(name, 'name');
} else {
name = name.replace(/'/g, "\\'")
.replace(/\\"/g, '"')
.replace(/(^"|"$)/g, "'");
name = ctx.stylize(name, 'string');
}
}
return name + ': ' + str;
}
function reduceToSingleString(output, base, braces) {
var numLinesEst = 0;
var length = output.reduce(function(prev, cur) {
numLinesEst++;
if (cur.indexOf('\n') >= 0) numLinesEst++;
return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
}, 0);
if (length > 60) {
return braces[0] +
(base === '' ? '' : base + '\n ') +
' ' +
output.join(',\n ') +
' ' +
braces[1];
}
return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
}
// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
function isArray(ar) {
return Array.isArray(ar);
}
exports.isArray = isArray;
function isBoolean(arg) {
return typeof arg === 'boolean';
}
exports.isBoolean = isBoolean;
function isNull(arg) {
return arg === null;
}
exports.isNull = isNull;
function isNullOrUndefined(arg) {
return arg == null;
}
exports.isNullOrUndefined = isNullOrUndefined;
function isNumber(arg) {
return typeof arg === 'number';
}
exports.isNumber = isNumber;
function isString(arg) {
return typeof arg === 'string';
}
exports.isString =