mirror of
https://github.com/mgerb/mywebsite
synced 2026-03-06 08:15:25 +00:00
Added files
This commit is contained in:
605
mongoui/mongoui-master/node_modules/derby/lib/Dom.js
generated
vendored
Normal file
605
mongoui/mongoui-master/node_modules/derby/lib/Dom.js
generated
vendored
Normal file
@@ -0,0 +1,605 @@
|
||||
var racer = require('racer')
|
||||
, domShim = require('dom-shim')
|
||||
, EventDispatcher = require('./EventDispatcher')
|
||||
, viewPath = require('./viewPath')
|
||||
, escapeHtml = require('html-util').escapeHtml
|
||||
, merge = racer.util.merge
|
||||
, win = window
|
||||
, doc = win.document
|
||||
, markers = {}
|
||||
, elements = {
|
||||
$_win: win
|
||||
, $_doc: doc
|
||||
}
|
||||
, addListener, removeListener;
|
||||
|
||||
module.exports = Dom;
|
||||
|
||||
function Dom(model) {
|
||||
var dom = this
|
||||
, fns = this.fns
|
||||
|
||||
// Map dom event name -> true
|
||||
, listenerAdded = {}
|
||||
, captureListenerAdded = {};
|
||||
|
||||
// DOM listener capturing allows blur and focus to be delegated
|
||||
// http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
|
||||
var captureEvents = this._captureEvents = new EventDispatcher({
|
||||
onTrigger: onCaptureTrigger
|
||||
, onBind: onCaptureBind
|
||||
});
|
||||
function onCaptureTrigger(name, listener, e) {
|
||||
var id = listener.id
|
||||
, el = doc.getElementById(id);
|
||||
|
||||
// Remove listener if element isn't found
|
||||
if (!el) return false;
|
||||
|
||||
if (el.tagName === 'HTML' || el.contains(e.target)) {
|
||||
onDomTrigger(name, listener, id, e, el);
|
||||
}
|
||||
}
|
||||
function onCaptureBind(name, listener) {
|
||||
if (captureListenerAdded[name]) return;
|
||||
addListener(doc, name, captureTrigger, true);
|
||||
captureListenerAdded[name] = true;
|
||||
}
|
||||
|
||||
var events = this._events = new EventDispatcher({
|
||||
onTrigger: onDomTrigger
|
||||
, onBind: onDomBind
|
||||
});
|
||||
function onDomTrigger(name, listener, id, e, el, next) {
|
||||
var delay = listener.delay
|
||||
, finish = listener.fn;
|
||||
|
||||
e.path = function(name) {
|
||||
var path = model.__pathMap.paths[listener.pathId];
|
||||
if (!name) return path;
|
||||
viewPath.patchCtx(listener.ctx, path)
|
||||
return viewPath.ctxPath(listener.view, listener.ctx, name);
|
||||
};
|
||||
e.get = function(name) {
|
||||
var path = e.path(name);
|
||||
return viewPath.dataValue(listener.view, listener.ctx, model, path);
|
||||
};
|
||||
e.at = function(name) {
|
||||
return model.at(e.path(name));
|
||||
};
|
||||
|
||||
if (!finish) {
|
||||
// Update the model when the element's value changes
|
||||
finish = function() {
|
||||
var value = dom.getMethods[listener.method](el, listener.property)
|
||||
, setValue = listener.setValue;
|
||||
|
||||
// Allow the listener to override the setting function
|
||||
if (setValue) {
|
||||
setValue(model, value);
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove this listener if its path id is no longer registered
|
||||
var path = model.__pathMap.paths[listener.pathId];
|
||||
if (!path) return false;
|
||||
|
||||
// Set the value if changed
|
||||
if (model.get(path) === value) return;
|
||||
model.pass(e).set(path, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (delay != null) {
|
||||
setTimeout(finish, delay, e, el, next, dom);
|
||||
} else {
|
||||
finish(e, el, next, dom);
|
||||
}
|
||||
}
|
||||
function onDomBind(name, listener, eventName) {
|
||||
if (listenerAdded[eventName]) return;
|
||||
addListener(doc, eventName, triggerDom, true);
|
||||
listenerAdded[eventName] = true;
|
||||
}
|
||||
|
||||
function triggerDom(e, el, noBubble, continued) {
|
||||
if (!el) el = e.target;
|
||||
var prefix = e.type + ':'
|
||||
, id;
|
||||
|
||||
// Next can be called from a listener to continue bubbling
|
||||
function next() {
|
||||
triggerDom(e, el.parentNode, false, true);
|
||||
}
|
||||
next.firstTrigger = !continued;
|
||||
if (noBubble && (id = el.id)) {
|
||||
return events.trigger(prefix + id, id, e, el, next);
|
||||
}
|
||||
while (true) {
|
||||
while (!(id = el.id)) {
|
||||
if (!(el = el.parentNode)) return;
|
||||
}
|
||||
// Stop bubbling once the event is handled
|
||||
if (events.trigger(prefix + id, id, e, el, next)) return;
|
||||
if (!(el = el.parentNode)) return;
|
||||
}
|
||||
}
|
||||
|
||||
function captureTrigger(e) {
|
||||
captureEvents.trigger(e.type, e);
|
||||
}
|
||||
|
||||
this.trigger = triggerDom;
|
||||
this.captureTrigger = captureTrigger;
|
||||
|
||||
this._listeners = [];
|
||||
this._components = [];
|
||||
this._pendingUpdates = [];
|
||||
|
||||
function componentCleanup() {
|
||||
var components = dom._components
|
||||
, map = getMarkers()
|
||||
, i, component
|
||||
for (i = components.length; i--;) {
|
||||
component = components[i];
|
||||
if (component && !getMarker(map, component.scope)) {
|
||||
component.emit('destroy');
|
||||
}
|
||||
}
|
||||
}
|
||||
// This cleanup listeners is placed at the beginning so that component
|
||||
// scopes are cleared before any ref cleanups are checked
|
||||
model.listeners('cleanup').unshift(componentCleanup);
|
||||
}
|
||||
|
||||
Dom.prototype = {
|
||||
clear: domClear
|
||||
, bind: domBind
|
||||
, item: domItem
|
||||
, marker: domMarker
|
||||
, update: domUpdate
|
||||
, nextUpdate: nextUpdate
|
||||
, _emitUpdate: emitUpdate
|
||||
, addListener: domAddListener
|
||||
, removeListener: domRemoveListener
|
||||
, addComponent: addComponent
|
||||
|
||||
, getMethods: {
|
||||
attr: getAttr
|
||||
, prop: getProp
|
||||
, propPolite: getProp
|
||||
, html: getHtml
|
||||
// These methods return NaN, because it never equals anything else. Thus,
|
||||
// when compared against the new value, the new value will always be set
|
||||
, append: getNaN
|
||||
, insert: getNaN
|
||||
, remove: getNaN
|
||||
, move: getNaN
|
||||
}
|
||||
|
||||
, setMethods: {
|
||||
attr: setAttr
|
||||
, prop: setProp
|
||||
, propPolite: setProp
|
||||
, html: setHtml
|
||||
, append: setAppend
|
||||
, insert: setInsert
|
||||
, remove: setRemove
|
||||
, move: setMove
|
||||
}
|
||||
|
||||
, fns: {
|
||||
$forChildren: forChildren
|
||||
, $forName: forName
|
||||
}
|
||||
}
|
||||
|
||||
function domClear() {
|
||||
this._events.clear();
|
||||
this._captureEvents.clear();
|
||||
var components = this._components
|
||||
, listeners = this._listeners
|
||||
, i, component
|
||||
for (i = listeners.length; i--;) {
|
||||
removeListener.apply(null, listeners[i]);
|
||||
}
|
||||
this._listeners = [];
|
||||
for (i = components.length; i--;) {
|
||||
component = components[i];
|
||||
component && component.emit('destroy');
|
||||
}
|
||||
this._components = [];
|
||||
markers = {};
|
||||
}
|
||||
|
||||
function domListenerHash() {
|
||||
var out = {}
|
||||
, key
|
||||
for (key in this) {
|
||||
if (key === 'view' || key === 'ctx' || key === 'pathId') continue;
|
||||
out[key] = this[key];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function domBind(eventName, id, listener) {
|
||||
listener.toJSON = domListenerHash;
|
||||
if (listener.capture) {
|
||||
listener.id = id;
|
||||
this._captureEvents.bind(eventName, listener);
|
||||
} else {
|
||||
this._events.bind("" + eventName + ":" + id, listener, eventName);
|
||||
}
|
||||
}
|
||||
|
||||
function domItem(id) {
|
||||
return doc.getElementById(id) || elements[id] || getRange(id);
|
||||
}
|
||||
|
||||
function domUpdate(el, method, ignore, value, property, index) {
|
||||
// Set to true during rendering
|
||||
if (this._preventUpdates) return;
|
||||
|
||||
// Wrapped in a try / catch so that errors thrown on DOM updates don't
|
||||
// stop subsequent code from running
|
||||
try {
|
||||
// Don't do anything if the element is already up to date
|
||||
if (value === this.getMethods[method](el, property)) return;
|
||||
this.setMethods[method](el, ignore, value, property, index);
|
||||
this._emitUpdate();
|
||||
} catch (err) {
|
||||
setTimeout(function() {
|
||||
throw err;
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
function nextUpdate(callback) {
|
||||
this._pendingUpdates.push(callback);
|
||||
}
|
||||
function emitUpdate() {
|
||||
var fns = this._pendingUpdates
|
||||
, len = fns.length
|
||||
, i;
|
||||
if (!len) return;
|
||||
this._pendingUpdates = [];
|
||||
// Give the browser a chance to render the page before initializing
|
||||
// components and other delayed updates
|
||||
setTimeout(function() {
|
||||
for (i = 0; i < len; i++) {
|
||||
fns[i]();
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function domAddListener(el, name, callback, captures) {
|
||||
this._listeners.push([el, name, callback, captures]);
|
||||
addListener(el, name, callback, captures);
|
||||
}
|
||||
function domRemoveListener(el, name, callback, captures) {
|
||||
removeListener(el, name, callback, captures);
|
||||
}
|
||||
|
||||
function addComponent(ctx, component) {
|
||||
var components = this._components
|
||||
, dom = component.dom = Object.create(this);
|
||||
|
||||
components.push(component);
|
||||
component.on('destroy', function() {
|
||||
var index = components.indexOf(component);
|
||||
if (index === -1) return;
|
||||
// The components array gets replaced on a dom.clear, so we allow
|
||||
// it to get sparse as individual components are destroyed
|
||||
delete components[index];
|
||||
});
|
||||
|
||||
dom.addListener = function(el, name, callback, captures) {
|
||||
component.on('destroy', function() {
|
||||
removeListener(el, name, callback, captures);
|
||||
});
|
||||
addListener(el, name, callback, captures);
|
||||
};
|
||||
|
||||
dom.element = function(name) {
|
||||
var id = ctx.$elements[name];
|
||||
return document.getElementById(id);
|
||||
};
|
||||
|
||||
return dom;
|
||||
}
|
||||
|
||||
|
||||
function getAttr(el, attr) {
|
||||
return el.getAttribute(attr);
|
||||
}
|
||||
function getProp(el, prop) {
|
||||
return el[prop];
|
||||
}
|
||||
function getHtml(el) {
|
||||
return el.innerHTML;
|
||||
}
|
||||
function getNaN() {
|
||||
return NaN;
|
||||
}
|
||||
|
||||
function setAttr(el, ignore, value, attr) {
|
||||
if (ignore && el.id === ignore) return;
|
||||
el.setAttribute(attr, value);
|
||||
}
|
||||
function setProp(el, ignore, value, prop) {
|
||||
if (ignore && el.id === ignore) return;
|
||||
el[prop] = value;
|
||||
}
|
||||
function propPolite(el, ignore, value, prop) {
|
||||
if (ignore && el.id === ignore) return;
|
||||
if (el !== doc.activeElement || !doc.hasFocus()) {
|
||||
el[prop] = value;
|
||||
}
|
||||
}
|
||||
|
||||
function makeSVGFragment(fragment, svgElement) {
|
||||
// TODO: Allow optional namespace declarations
|
||||
var pre = '<svg xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink>'
|
||||
, post = '</svg>'
|
||||
, range = document.createRange()
|
||||
range.selectNode(svgElement);
|
||||
return range.createContextualFragment(pre + fragment + post);
|
||||
}
|
||||
function appendSVG(element, fragment, svgElement) {
|
||||
var frag = makeSVGFragment(fragment, svgElement)
|
||||
, children = frag.childNodes[0].childNodes
|
||||
, i
|
||||
for (i = children.length; i--;) {
|
||||
element.appendChild(children[0]);
|
||||
}
|
||||
}
|
||||
function insertBeforeSVG(element, fragment, svgElement) {
|
||||
var frag = makeSVGFragment(fragment, svgElement)
|
||||
, children = frag.childNodes[0].childNodes
|
||||
, parent = element.parentNode
|
||||
, i
|
||||
for (i = children.length; i--;) {
|
||||
parent.insertBefore(children[0], element);
|
||||
}
|
||||
}
|
||||
function removeChildren(element) {
|
||||
var children = element.childNodes
|
||||
, i
|
||||
for (i = children.length; i--;) {
|
||||
element.removeChild(children[0]);
|
||||
}
|
||||
}
|
||||
|
||||
function isSVG(obj) {
|
||||
return !!obj.ownerSVGElement || obj.tagName === "svg";
|
||||
}
|
||||
function svgRoot(obj) {
|
||||
return obj.ownerSVGElement || obj;
|
||||
}
|
||||
function isRange(obj) {
|
||||
return !!obj.cloneRange;
|
||||
}
|
||||
|
||||
function setHtml(obj, ignore, value, escape) {
|
||||
if (escape) value = escapeHtml(value);
|
||||
if(isRange(obj)) {
|
||||
if(isSVG(obj.startContainer)) {
|
||||
// SVG Element
|
||||
obj.deleteContents();
|
||||
var svgElement = svgRoot(obj.startContainer);
|
||||
obj.insertNode(makeSVGFragment(value, svgElement));
|
||||
return;
|
||||
} else {
|
||||
// Range
|
||||
obj.deleteContents();
|
||||
obj.insertNode(obj.createContextualFragment(value));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (isSVG(obj)) {
|
||||
// SVG Element
|
||||
var svgElement = svgRoot(obj);
|
||||
removeChildren(obj);
|
||||
appendSVG(obj, value, svgElement);
|
||||
return;
|
||||
}
|
||||
// HTML Element
|
||||
if (ignore && obj.id === ignore) return;
|
||||
obj.innerHTML = value;
|
||||
}
|
||||
function setAppend(obj, ignore, value, escape) {
|
||||
if (escape) value = escapeHtml(value);
|
||||
if (isSVG(obj)) {
|
||||
// SVG Element
|
||||
var svgElement = obj.ownerSVGElement || obj;
|
||||
appendSVG(obj, value, svgElement);
|
||||
return;
|
||||
}
|
||||
if (obj.nodeType) {
|
||||
// HTML Element
|
||||
obj.insertAdjacentHTML('beforeend', value);
|
||||
} else {
|
||||
// Range
|
||||
if(isSVG(obj.startContainer)) {
|
||||
var el = obj.endContainer
|
||||
, ref = el.childNodes[obj.endOffset];
|
||||
var svgElement = svgRoot(ref);
|
||||
el.insertBefore(makeSVGFragment(value, svgElement), ref)
|
||||
} else {
|
||||
var el = obj.endContainer
|
||||
, ref = el.childNodes[obj.endOffset];
|
||||
el.insertBefore(obj.createContextualFragment(value), ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
function setInsert(obj, ignore, value, escape, index) {
|
||||
if (escape) value = escapeHtml(value);
|
||||
if (obj.nodeType) {
|
||||
// Element
|
||||
if (ref = obj.childNodes[index]) {
|
||||
if (isSVG(obj)) {
|
||||
var svgElement = obj.ownerSVGElement || obj;
|
||||
insertBeforeSVG(ref, value, svgElement);
|
||||
return;
|
||||
}
|
||||
ref.insertAdjacentHTML('beforebegin', value);
|
||||
} else {
|
||||
if (isSVG(obj)) {
|
||||
var svgElement = obj.ownerSVGElement || obj;
|
||||
appendSVG(obj, value, svgElement);
|
||||
return;
|
||||
}
|
||||
obj.insertAdjacentHTML('beforeend', value);
|
||||
}
|
||||
} else {
|
||||
// Range
|
||||
if(isSVG(obj.startContainer)) {
|
||||
var el = obj.startContainer
|
||||
, ref = el.childNodes[obj.startOffset + index];
|
||||
var svgElement = svgRoot(ref);
|
||||
el.insertBefore(makeSVGFragment(value, svgElement), ref)
|
||||
} else {
|
||||
var el = obj.startContainer
|
||||
, ref = el.childNodes[obj.startOffset + index];
|
||||
el.insertBefore(obj.createContextualFragment(value), ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
function setRemove(el, ignore, index) {
|
||||
if (!el.nodeType) {
|
||||
// Range
|
||||
index += el.startOffset;
|
||||
el = el.startContainer;
|
||||
}
|
||||
var child = el.childNodes[index];
|
||||
if (child) el.removeChild(child);
|
||||
}
|
||||
function setMove(el, ignore, from, to, howMany) {
|
||||
var child, fragment, nextChild, offset, ref, toEl;
|
||||
if (!el.nodeType) {
|
||||
offset = el.startOffset;
|
||||
from += offset;
|
||||
to += offset;
|
||||
el = el.startContainer;
|
||||
}
|
||||
child = el.childNodes[from];
|
||||
|
||||
// Don't move if the item at the destination is passed as the ignore
|
||||
// option, since this indicates the intended item was already moved
|
||||
// Also don't move if the child to move matches the ignore option
|
||||
if (!child || ignore && (toEl = el.childNodes[to]) &&
|
||||
toEl.id === ignore || child.id === ignore) return;
|
||||
|
||||
ref = el.childNodes[to > from ? to + howMany : to];
|
||||
if (howMany > 1) {
|
||||
fragment = document.createDocumentFragment();
|
||||
while (howMany--) {
|
||||
nextChild = child.nextSibling;
|
||||
fragment.appendChild(child);
|
||||
if (!(child = nextChild)) break;
|
||||
}
|
||||
el.insertBefore(fragment, ref);
|
||||
return;
|
||||
}
|
||||
el.insertBefore(child, ref);
|
||||
}
|
||||
|
||||
function forChildren(e, el, next, dom) {
|
||||
// Prevent infinte emission
|
||||
if (!next.firstTrigger) return;
|
||||
|
||||
// Re-trigger the event on all child elements
|
||||
var children = el.childNodes;
|
||||
for (var i = 0, len = children.length, child; i < len; i++) {
|
||||
child = children[i];
|
||||
if (child.nodeType !== 1) continue; // Node.ELEMENT_NODE
|
||||
dom.trigger(e, child, true, true);
|
||||
forChildren(e, child, next, dom);
|
||||
}
|
||||
}
|
||||
|
||||
function forName(e, el, next, dom) {
|
||||
// Prevent infinte emission
|
||||
if (!next.firstTrigger) return;
|
||||
|
||||
var name = el.getAttribute('name');
|
||||
if (!name) return;
|
||||
|
||||
// Re-trigger the event on all other elements with
|
||||
// the same 'name' attribute
|
||||
var elements = doc.getElementsByName(name)
|
||||
, len = elements.length;
|
||||
if (!(len > 1)) return;
|
||||
for (var i = 0, element; i < len; i++) {
|
||||
element = elements[i];
|
||||
if (element === el) continue;
|
||||
dom.trigger(e, element, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
function getMarkers() {
|
||||
var map = {}
|
||||
// NodeFilter.SHOW_COMMENT == 128
|
||||
, commentIterator = doc.createTreeWalker(doc, 128, null, false)
|
||||
, comment
|
||||
while (comment = commentIterator.nextNode()) {
|
||||
map[comment.data] = comment;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
function getMarker(map, name) {
|
||||
var marker = map[name];
|
||||
if (!marker) return;
|
||||
|
||||
// Comment nodes may continue to exist even if they have been removed from
|
||||
// the page. Thus, make sure they are still somewhere in the page body
|
||||
if (!doc.contains(marker)) {
|
||||
delete map[name];
|
||||
return;
|
||||
}
|
||||
return marker;
|
||||
}
|
||||
|
||||
function domMarker(name) {
|
||||
var marker = getMarker(markers, name);
|
||||
if (!marker) {
|
||||
markers = getMarkers();
|
||||
marker = getMarker(markers, name);
|
||||
if (!marker) return;
|
||||
}
|
||||
return marker;
|
||||
}
|
||||
|
||||
function getRange(name) {
|
||||
var start = domMarker(name);
|
||||
if (!start) return;
|
||||
var end = domMarker('$' + name);
|
||||
if (!end) return;
|
||||
|
||||
var range = doc.createRange();
|
||||
range.setStartAfter(start);
|
||||
range.setEndBefore(end);
|
||||
return range;
|
||||
}
|
||||
|
||||
if (doc.addEventListener) {
|
||||
addListener = function(el, name, callback, captures) {
|
||||
el.addEventListener(name, callback, captures || false);
|
||||
};
|
||||
removeListener = function(el, name, callback, captures) {
|
||||
el.removeEventListener(name, callback, captures || false);
|
||||
};
|
||||
|
||||
} else if (doc.attachEvent) {
|
||||
addListener = function(el, name, callback) {
|
||||
function listener() {
|
||||
if (!event.target) event.target = event.srcElement;
|
||||
callback(event);
|
||||
}
|
||||
callback.$derbyListener = listener;
|
||||
el.attachEvent('on' + name, listener);
|
||||
};
|
||||
removeListener = function(el, name, callback) {
|
||||
el.detachEvent('on' + name, callback.$derbyListener);
|
||||
};
|
||||
}
|
||||
43
mongoui/mongoui-master/node_modules/derby/lib/EventDispatcher.js
generated
vendored
Normal file
43
mongoui/mongoui-master/node_modules/derby/lib/EventDispatcher.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
function empty() {}
|
||||
|
||||
module.exports = EventDispatcher;
|
||||
|
||||
function EventDispatcher(options) {
|
||||
if (options == null) options = {};
|
||||
this._onTrigger = options.onTrigger || empty;
|
||||
this._onBind = options.onBind || empty;
|
||||
this.clear();
|
||||
}
|
||||
|
||||
EventDispatcher.prototype = {
|
||||
clear: function() {
|
||||
this.names = {};
|
||||
}
|
||||
|
||||
, bind: function(name, listener, arg0) {
|
||||
this._onBind(name, listener, arg0);
|
||||
var names = this.names
|
||||
, obj = names[name] || {};
|
||||
obj[JSON.stringify(listener)] = listener;
|
||||
return names[name] = obj;
|
||||
}
|
||||
|
||||
, trigger: function(name, value, arg0, arg1, arg2, arg3, arg4, arg5) {
|
||||
var names = this.names
|
||||
, listeners = names[name]
|
||||
, onTrigger = this._onTrigger
|
||||
, count = 0
|
||||
, key, listener;
|
||||
for (key in listeners) {
|
||||
listener = listeners[key];
|
||||
count++;
|
||||
if (false !== onTrigger(name, listener, value, arg0, arg1, arg2, arg3, arg4, arg5)) {
|
||||
continue;
|
||||
}
|
||||
delete listeners[key];
|
||||
count--;
|
||||
}
|
||||
if (!count) delete names[name];
|
||||
return count;
|
||||
}
|
||||
}
|
||||
153
mongoui/mongoui-master/node_modules/derby/lib/PathMap.js
generated
vendored
Normal file
153
mongoui/mongoui-master/node_modules/derby/lib/PathMap.js
generated
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
module.exports = PathMap
|
||||
|
||||
function PathMap() {
|
||||
this.clear();
|
||||
}
|
||||
PathMap.prototype = {
|
||||
clear: function() {
|
||||
this.count = 0;
|
||||
this.ids = {};
|
||||
this.paths = {};
|
||||
this.arrays = {};
|
||||
}
|
||||
|
||||
, id: function(path) {
|
||||
var id;
|
||||
// Return the path for an id, or create a new id and index it
|
||||
return this.ids[path] || (
|
||||
id = ++this.count
|
||||
, this.paths[id] = path
|
||||
, this._indexArray(path, id)
|
||||
, this.ids[path] = id
|
||||
);
|
||||
}
|
||||
|
||||
, _indexArray: function(path, id) {
|
||||
var arr, index, match, nested, remainder, set, setArrays;
|
||||
while (match = /^(.+)\.(\d+)(\*?(?:\..+|$))/.exec(path)) {
|
||||
path = match[1];
|
||||
index = +match[2];
|
||||
remainder = match[3];
|
||||
arr = this.arrays[path] || (this.arrays[path] = []);
|
||||
set = arr[index] || (arr[index] = {});
|
||||
if (nested) {
|
||||
setArrays = set.arrays || (set.arrays = {});
|
||||
setArrays[remainder] = true;
|
||||
} else {
|
||||
set[id] = remainder;
|
||||
}
|
||||
nested = true;
|
||||
}
|
||||
}
|
||||
|
||||
, _incrItems: function(path, map, start, end, byNum, oldArrays, oldPath) {
|
||||
var arrayMap, arrayPath, arrayPathTo, i, id, ids, itemPath, remainder;
|
||||
if (oldArrays == null) oldArrays = {};
|
||||
|
||||
for (i = start; i < end; i++) {
|
||||
ids = map[i];
|
||||
if (!ids) continue;
|
||||
|
||||
for (id in ids) {
|
||||
remainder = ids[id];
|
||||
if (id === 'arrays') {
|
||||
for (remainder in ids[id]) {
|
||||
arrayPath = (oldPath || path) + '.' + i + remainder;
|
||||
arrayMap = oldArrays[arrayPath] || this.arrays[arrayPath];
|
||||
if (arrayMap) {
|
||||
arrayPathTo = path + '.' + (i + byNum) + remainder;
|
||||
this.arrays[arrayPathTo] = arrayMap;
|
||||
this._incrItems(arrayPathTo, arrayMap, 0, arrayMap.length, 0, oldArrays, arrayPath);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
itemPath = path + '.' + (i + byNum) + remainder;
|
||||
this.paths[id] = itemPath;
|
||||
this.ids[itemPath] = +id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
, _delItems: function(path, map, start, end, len, oldArrays) {
|
||||
var arrayLen, arrayMap, arrayPath, i, id, ids, itemPath, remainder;
|
||||
if (oldArrays == null) oldArrays = {};
|
||||
|
||||
for (i = start; i < len; i++) {
|
||||
ids = map[i];
|
||||
if (!ids) continue;
|
||||
|
||||
for (id in ids) {
|
||||
if (id === 'arrays') {
|
||||
for (remainder in ids[id]) {
|
||||
arrayPath = path + '.' + i + remainder;
|
||||
if (arrayMap = this.arrays[arrayPath]) {
|
||||
arrayLen = arrayMap.length;
|
||||
this._delItems(arrayPath, arrayMap, 0, arrayLen, arrayLen, oldArrays);
|
||||
oldArrays[arrayPath] = arrayMap;
|
||||
delete this.arrays[arrayPath];
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
itemPath = this.paths[id];
|
||||
delete this.ids[itemPath];
|
||||
if (i > end) continue;
|
||||
delete this.paths[id];
|
||||
}
|
||||
}
|
||||
|
||||
return oldArrays;
|
||||
}
|
||||
|
||||
, onRemove: function(path, start, howMany) {
|
||||
var map = this.arrays[path]
|
||||
, end, len, oldArrays;
|
||||
if (!map) return;
|
||||
end = start + howMany;
|
||||
len = map.length;
|
||||
// Delete indicies for removed items
|
||||
oldArrays = this._delItems(path, map, start, end + 1, len);
|
||||
// Decrement indicies of later items
|
||||
this._incrItems(path, map, end, len, -howMany, oldArrays);
|
||||
map.splice(start, howMany);
|
||||
}
|
||||
|
||||
, onInsert: function(path, start, howMany) {
|
||||
var map = this.arrays[path]
|
||||
, end, len, oldArrays;
|
||||
if (!map) return;
|
||||
end = start + howMany;
|
||||
len = map.length;
|
||||
// Delete indicies for items in inserted positions
|
||||
oldArrays = this._delItems(path, map, start, end + 1, len);
|
||||
// Increment indicies of later items
|
||||
this._incrItems(path, map, start, len, howMany, oldArrays);
|
||||
while (howMany--) {
|
||||
map.splice(start, 0, {});
|
||||
}
|
||||
}
|
||||
|
||||
, onMove: function(path, from, to, howMany) {
|
||||
var map = this.arrays[path]
|
||||
, afterFrom, afterTo, items, oldArrays;
|
||||
if (!map) return;
|
||||
afterFrom = from + howMany;
|
||||
afterTo = to + howMany;
|
||||
// Adjust paths for items between from and to
|
||||
if (from > to) {
|
||||
oldArrays = this._delItems(path, map, to, afterFrom, afterFrom);
|
||||
this._incrItems(path, map, to, from, howMany, oldArrays);
|
||||
} else {
|
||||
oldArrays = this._delItems(path, map, from, afterTo, afterTo);
|
||||
this._incrItems(path, map, afterFrom, afterTo, -howMany, oldArrays);
|
||||
}
|
||||
// Adjust paths for the moved item(s)
|
||||
this._incrItems(path, map, from, afterFrom, to - from, oldArrays);
|
||||
// Fix the array index
|
||||
items = map.splice(from, howMany);
|
||||
map.splice.apply(map, [to, 0].concat(items));
|
||||
}
|
||||
}
|
||||
1429
mongoui/mongoui-master/node_modules/derby/lib/View.js
generated
vendored
Normal file
1429
mongoui/mongoui-master/node_modules/derby/lib/View.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
411
mongoui/mongoui-master/node_modules/derby/lib/View.server.js
generated
vendored
Normal file
411
mongoui/mongoui-master/node_modules/derby/lib/View.server.js
generated
vendored
Normal file
@@ -0,0 +1,411 @@
|
||||
var path = require('path')
|
||||
, EventDispatcher = require('./EventDispatcher')
|
||||
, md5 = require('MD5')
|
||||
, racer = require('racer')
|
||||
, Promise = racer.util.Promise
|
||||
, merge = racer.util.merge
|
||||
, deepCopy = racer.util.deepCopy
|
||||
, finishAfter = racer.util.async.finishAfter
|
||||
, isProduction = racer.util.isProduction
|
||||
, files = require('./files')
|
||||
, htmlUtil = require('html-util')
|
||||
, escapeHtml = htmlUtil.escapeHtml
|
||||
, trimLeading = htmlUtil.trimLeading
|
||||
, refresh = require('./refresh.server')
|
||||
, View = module.exports = require('./View')
|
||||
, Model = racer['protected'].Model
|
||||
, emptyModel = new Model
|
||||
, emptyRes = {
|
||||
getHeader: empty
|
||||
, setHeader: empty
|
||||
, write: empty
|
||||
, end: empty
|
||||
}
|
||||
, emptyPathMap = {
|
||||
id: empty
|
||||
}
|
||||
, emptyEventDispatcher = {
|
||||
bind: empty
|
||||
}
|
||||
|
||||
emptyModel._commit = empty;
|
||||
emptyModel.bundle = empty;
|
||||
|
||||
function empty() {}
|
||||
|
||||
function escapeInlineScript(s) {
|
||||
return s.replace(/<\//g, '<\\/');
|
||||
}
|
||||
|
||||
View.prototype.isServer = true;
|
||||
|
||||
View.prototype.inline = function(fn) {
|
||||
var script = "(" + fn + ")()";
|
||||
if (racer.get('minify')) {
|
||||
script = racer.get('minifyJs')(script);
|
||||
}
|
||||
this._inline += script + ';';
|
||||
};
|
||||
|
||||
View.prototype.render = function(res) {
|
||||
var view = this
|
||||
, i, arg, ctx, isStatic, model, ns;
|
||||
if (res == null) res = emptyRes;
|
||||
for (i = 1; i <= 5; i++) {
|
||||
arg = arguments[i];
|
||||
if (arg instanceof Model) {
|
||||
model = arg;
|
||||
} else if (typeof arg === 'object') {
|
||||
ctx = arg;
|
||||
} else if (typeof arg === 'string') {
|
||||
ns = arg;
|
||||
} else if (typeof arg === 'number') {
|
||||
res.statusCode = arg;
|
||||
} else if (typeof arg === 'boolean') {
|
||||
isStatic = arg;
|
||||
}
|
||||
}
|
||||
if (model == null) model = emptyModel;
|
||||
ctx = this._beforeRender(model, ns, ctx);
|
||||
|
||||
this._load(isStatic, function(err, errors, css, jsFile, appHash) {
|
||||
if (err) throw err;
|
||||
view._init(model);
|
||||
ctx.$appHash = appHash;
|
||||
ctx.$collections = res._derbyCollections;
|
||||
view._render(res, model, ns, ctx, isStatic, errors, css, jsFile);
|
||||
});
|
||||
};
|
||||
|
||||
View.prototype._init = function(model) {
|
||||
// Initialize model and view for rendering
|
||||
if (model == null) model = emptyModel;
|
||||
model.__events = emptyEventDispatcher;
|
||||
model.__blockPaths = {};
|
||||
model.__pathMap = emptyPathMap;
|
||||
this._resetForRender(model);
|
||||
};
|
||||
|
||||
View.prototype._render = function(res, model, ns, ctx, isStatic, errors, css, jsFile) {
|
||||
errors || (errors = {});
|
||||
|
||||
if (!res.getHeader('content-type')) {
|
||||
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
||||
}
|
||||
|
||||
try {
|
||||
// The view.get function renders and sets event listeners
|
||||
|
||||
var view = this
|
||||
, doctype = this.get('doctype', ns, ctx)
|
||||
, root = this.get('root', ns, ctx)
|
||||
, charset = this.get('charset', ns, ctx)
|
||||
, title = escapeHtml(this.get('title$s', ns, ctx))
|
||||
, head = this.get('head', ns, ctx)
|
||||
, header = this.get('header', ns, ctx)
|
||||
, body, footer, tail;
|
||||
|
||||
css = '<style id=$_css>' + (css || '') + '</style>';
|
||||
|
||||
// The first chunk includes everything through header. Head should contain
|
||||
// any meta tags and script tags, since it is included before CSS.
|
||||
// If there is a small amount of header HTML that will display well by itself,
|
||||
// it is a good idea to add this to the Header view so that it renders ASAP.
|
||||
res.write(
|
||||
doctype + root +
|
||||
'<head>' + charset + "<title>" + title + "</title>" + head + css + '</head>' +
|
||||
'<!--$_page-->' + header
|
||||
);
|
||||
|
||||
// Remaining HTML
|
||||
body = this.get('body', ns, ctx);
|
||||
footer = this.get('footer', ns, ctx);
|
||||
tail = this.get('tail', ns, ctx);
|
||||
res.write(body + footer + '<!--$$_page-->');
|
||||
|
||||
if (!isProduction) ctx.$renderHash = md5(header + body + footer);
|
||||
|
||||
} catch (err) {
|
||||
errors['Template'] = refresh.templateError(err);
|
||||
res.write('<!DOCTYPE html><meta charset=utf-8><title></title>' + css);
|
||||
}
|
||||
|
||||
// Display server-side rendering error stack trace in development
|
||||
if (!isProduction) tail += refresh.errorHtml(errors) || '';
|
||||
|
||||
// Wait for transactions to finish and bundle up the racer model data
|
||||
|
||||
// TODO: There is a potential race condition with rendering based on the
|
||||
// model before it is bundled. However, components may want to run init
|
||||
// code that performs model mutations, so we can't bundle until after that.
|
||||
// Figure out some solution to make sure that the client will have exactly
|
||||
// the same model data when rendering to set up browser events, etc.
|
||||
if (isStatic) {
|
||||
view._renderScripts(res, ns, ctx, isStatic, jsFile, tail);
|
||||
return;
|
||||
}
|
||||
model.del('_$components');
|
||||
model.bundle(function(bundle) {
|
||||
view._renderScripts(res, ns, ctx, isStatic, jsFile, tail, bundle);
|
||||
});
|
||||
};
|
||||
|
||||
View.prototype._renderScripts = function(res, ns, ctx, isStatic, jsFile, tail, bundle) {
|
||||
// Inline scripts and external scripts
|
||||
var scripts = this._inline ? '<script>' + escapeInlineScript(this._inline) + '</script>' : '';
|
||||
scripts += this.get('scripts', ns, ctx);
|
||||
if (!isStatic) {
|
||||
scripts += '<script id=$_js defer async onload="this.loaded=true" src=' + jsFile + '></script>';
|
||||
}
|
||||
res.write(scripts);
|
||||
|
||||
// Initialization script and Tail
|
||||
if (isStatic) return res.end(tail);
|
||||
|
||||
res.end("<script>setTimeout(function(){" +
|
||||
"var el = document.getElementById('$_js');" +
|
||||
"el.loaded ? init() : el.onload = init;" +
|
||||
"function init(){" +
|
||||
"DERBY.init(" + escapeInlineScript(bundle) + "," +
|
||||
escapeInlineScript(JSON.stringify(deepCopy(ctx))) + ")" +
|
||||
"}" +
|
||||
"},0)</script>" + tail);
|
||||
};
|
||||
|
||||
View.prototype._load = function(isStatic, callback) {
|
||||
// Wait for loading to complete if already loading
|
||||
if (this._loadCallbacks) {
|
||||
this._loadCallbacks.push(callback);
|
||||
return;
|
||||
}
|
||||
|
||||
this._loadCallbacks = [callback];
|
||||
var view = this;
|
||||
|
||||
function resolve(err, errors, css, jsFile, appHash) {
|
||||
var cb;
|
||||
while (cb = view._loadCallbacks.shift()) {
|
||||
cb(err, errors, css, jsFile, appHash);
|
||||
}
|
||||
// Once loading is complete, make the files reload from disk the next time
|
||||
delete view._loadCallbacks;
|
||||
}
|
||||
|
||||
loadAll(this, isStatic, function(err, errors, css, jsFile, appHash) {
|
||||
view._appHash = appHash;
|
||||
if (err) return resolve(err);
|
||||
// Only load from disk once in production
|
||||
if (isProduction) {
|
||||
view._load = function(isStatic, callback) {
|
||||
callback(null, errors, css, jsFile, appHash);
|
||||
};
|
||||
}
|
||||
resolve(null, errors, css, jsFile, appHash);
|
||||
});
|
||||
};
|
||||
|
||||
View.prototype.pack = function(callback) {
|
||||
var view = this
|
||||
, appFilename = view._appFilename
|
||||
, fileInfo = files.parseName(appFilename)
|
||||
, root = fileInfo.root
|
||||
, clientName = fileInfo.clientName
|
||||
|
||||
function finish(err) {
|
||||
callback(err, clientName);
|
||||
}
|
||||
racer.set('minify', true);
|
||||
|
||||
view._loadStyles(root, clientName, function(err, css) {
|
||||
if (err) return finish(err);
|
||||
|
||||
view._loadTemplates(root, clientName, function(err, templates, instances, libraryData) {
|
||||
if (err) return finish(err);
|
||||
var templatesScript = loadTemplatesScript(templates, instances, libraryData);
|
||||
templatesScript = racer.get('minifyJs')(templatesScript);
|
||||
|
||||
files.js(appFilename, {minify: true, debug: false}, function(err, js, inline) {
|
||||
files.writeJs(root, js + '\n;' + templatesScript, true, function(err, jsFile, appHash) {
|
||||
if (err) return finish(err);
|
||||
|
||||
var filename = clientName + '.json'
|
||||
, file = JSON.stringify({
|
||||
css: css
|
||||
, templates: templates
|
||||
, instances: instances
|
||||
, libraryData: libraryData
|
||||
, inline: inline
|
||||
, jsFile: jsFile
|
||||
, appHash: appHash
|
||||
})
|
||||
files.writeGen(root, filename, file, true, finish);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function loadAll(view, isStatic, callback) {
|
||||
var errors = {}
|
||||
, appFilename, fileInfo, root, clientName, dataFile, data
|
||||
|
||||
if (isStatic) {
|
||||
root = view._root;
|
||||
clientName = view._clientName;
|
||||
} else {
|
||||
appFilename = view._appFilename;
|
||||
fileInfo = files.parseName(appFilename);
|
||||
root = fileInfo.root;
|
||||
clientName = fileInfo.clientName;
|
||||
}
|
||||
|
||||
if (isProduction) {
|
||||
try {
|
||||
dataFile = files.genInfo(root, clientName + '.json', true).filePath;
|
||||
data = require(dataFile);
|
||||
view._makeAll(data.templates, data.instances);
|
||||
view._makeComponents(data.libraryData);
|
||||
return callback(null, null, data.css, data.jsFile, data.appHash);
|
||||
} catch (err) {
|
||||
// Don't do anything if the file isn't found or there is another error
|
||||
}
|
||||
}
|
||||
|
||||
view._loadStyles(root, clientName, function(err, css) {
|
||||
if (err) errors['CSS'] = refresh.cssError(err);
|
||||
|
||||
view._loadTemplates(root, clientName, function(err, templates, instances, libraryData) {
|
||||
if (err) errors['Template'] = refresh.templateError(err);
|
||||
view._makeAll(templates, instances);
|
||||
view._makeComponents(libraryData);
|
||||
var templatesScript = loadTemplatesScript(templates, instances, libraryData);
|
||||
if (racer.get('minify')) {
|
||||
templatesScript = racer.get('minifyJs')(templatesScript);
|
||||
}
|
||||
|
||||
// Don't include JS for static pages
|
||||
if (isStatic) return callback(null, errors, css);
|
||||
|
||||
// JS files are only loaded once per process start
|
||||
if (view._js) return finish(view._js);
|
||||
|
||||
files.js(appFilename, function(err, js, inline) {
|
||||
if (err) return callback(err);
|
||||
if (inline) view.inline("function(){" + inline + "}");
|
||||
view._js = js;
|
||||
finish(js);
|
||||
});
|
||||
|
||||
function finish(js) {
|
||||
files.writeJs(root, js + '\n;' + templatesScript, false, function(err, jsFile, appHash) {
|
||||
if (err) return callback(err);
|
||||
callback(err, errors, css, jsFile, appHash);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: We are sending all libraries to all apps whether or not they
|
||||
// are used. We should only be sending the libraries that each app needs
|
||||
function loadTemplatesScript(templates, instances, libraryData) {
|
||||
return '(function() {\n' +
|
||||
'var view = DERBY.app.view;\n' +
|
||||
'view._makeAll(' +
|
||||
sortedJson(templates, 2) + ', ' +
|
||||
sortedJson(instances, 2) + ');\n' +
|
||||
'view._makeComponents(' +
|
||||
sortedJson(libraryData, 2) + ');\n' +
|
||||
'})();';
|
||||
}
|
||||
|
||||
function sortedJson(obj, space) {
|
||||
if (typeof obj !== 'object' || Array.isArray(obj)) {
|
||||
return JSON.stringify(obj, null, space);
|
||||
}
|
||||
var out = []
|
||||
, key;
|
||||
for (key in obj) {
|
||||
out.push('"' + key + '": ' + sortedJson(obj[key], space));
|
||||
}
|
||||
return out.length ? '{\n ' + out.sort().join(',\n ') + '\n}' : '{}';
|
||||
}
|
||||
|
||||
View.prototype._loadStyles = function(root, clientName, callback) {
|
||||
var styleFiles = []
|
||||
, out = []
|
||||
, libraries = this._libraries
|
||||
, minify = racer.get('minify')
|
||||
, len, i, library, styles, finish
|
||||
|
||||
function add(styles) {
|
||||
var file = path.resolve(library.root, styles);
|
||||
styleFiles.push(file);
|
||||
}
|
||||
|
||||
for (i = 0, len = libraries.length; i < len; i++) {
|
||||
library = libraries[i];
|
||||
styles = library.styles;
|
||||
if (!styles) continue;
|
||||
if (Array.isArray(styles)) {
|
||||
styles.forEach(add);
|
||||
} else {
|
||||
add(styles);
|
||||
}
|
||||
}
|
||||
|
||||
styleFiles.push(clientName);
|
||||
|
||||
finish = finishAfter(styleFiles.length, function(err) {
|
||||
if (err) return callback(err);
|
||||
callback(null, out.join(''));
|
||||
});
|
||||
|
||||
styleFiles.forEach(function(file, i) {
|
||||
files.css(root, file, minify, function(err, value) {
|
||||
out[i] = minify ? trimLeading(value) : '\n' + value;
|
||||
finish(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
View.prototype._loadTemplates = function(root, clientName, callback) {
|
||||
var libraries = this._libraries
|
||||
, libraryData = {}
|
||||
, templates, instances, finish
|
||||
|
||||
finish = finishAfter(libraries.length + 1, function(err) {
|
||||
callback(err, templates, instances, libraryData);
|
||||
});
|
||||
|
||||
files.templates(root, clientName, function(err, _templates, _instances) {
|
||||
if (err) {
|
||||
templates = {};
|
||||
instances = {};
|
||||
} else {
|
||||
templates = _templates;
|
||||
instances = _instances;
|
||||
}
|
||||
finish(err);
|
||||
});
|
||||
|
||||
libraries.forEach(function(library) {
|
||||
files.library(library.root, function(err, components) {
|
||||
if (err) return finish(err);
|
||||
var libraryTemplates = {}
|
||||
, libraryInstances = {}
|
||||
, componentName, component;
|
||||
for (componentName in components) {
|
||||
component = components[componentName];
|
||||
// TODO: Namespace component partials of each component
|
||||
merge(libraryTemplates, component.templates);
|
||||
merge(libraryInstances, component.instances);
|
||||
}
|
||||
libraryData[library.ns] = {
|
||||
templates: libraryTemplates
|
||||
, instances: libraryInstances
|
||||
};
|
||||
finish();
|
||||
});
|
||||
});
|
||||
};
|
||||
76
mongoui/mongoui-master/node_modules/derby/lib/app.js
generated
vendored
Normal file
76
mongoui/mongoui-master/node_modules/derby/lib/app.js
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
var EventEmitter = require('events').EventEmitter
|
||||
, racer = require('racer')
|
||||
, View = require('./View')
|
||||
, collection = require('./collection')
|
||||
, isServer = racer.util.isServer
|
||||
|
||||
exports.create = createApp;
|
||||
exports.treeMerge = treeMerge;
|
||||
|
||||
function createApp(derby, appModule) {
|
||||
var app = racer.util.merge(appModule.exports, EventEmitter.prototype)
|
||||
|
||||
app.view = new View(derby._libraries, app, appModule.filename);
|
||||
app.fn = appFn;
|
||||
|
||||
function appFn(value, fn) {
|
||||
if (typeof value === 'string') {
|
||||
pathMerge(app, value, fn, app);
|
||||
} else {
|
||||
treeMerge(app, value, app);
|
||||
}
|
||||
return app;
|
||||
}
|
||||
|
||||
app._Collections = {};
|
||||
app.Collection = collection.construct.bind(app);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
function traverseNode(node, segments) {
|
||||
var i, len, segment
|
||||
for (i = 0, len = segments.length; i < len; i++) {
|
||||
segment = segments[i];
|
||||
node = node[segment] || (node[segment] = {});
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
// Recursively set nested objects based on a path
|
||||
function pathMerge(node, path, value, app) {
|
||||
var segments = path.split('.')
|
||||
, last, i, len, segment
|
||||
if (typeof value === 'object') {
|
||||
node = traverseNode(node, segments);
|
||||
treeMerge(node, value, app);
|
||||
return;
|
||||
}
|
||||
last = segments.pop();
|
||||
node = traverseNode(node, segments);
|
||||
node[last] = bindPage(value, app);
|
||||
}
|
||||
|
||||
// Recursively set objects such that the non-objects are
|
||||
// merged with the corresponding structure of the base node
|
||||
function treeMerge(node, tree, app) {
|
||||
var key, child, value
|
||||
for (key in tree) {
|
||||
value = tree[key];
|
||||
if (typeof value === 'object') {
|
||||
child = node[key] || (node[key] = {});
|
||||
treeMerge(child, value, app);
|
||||
continue;
|
||||
}
|
||||
node[key] = bindPage(value, app);
|
||||
}
|
||||
}
|
||||
|
||||
function bindPage(fn, app) {
|
||||
// Don't bind the function on the server, since each
|
||||
// render gets passed a new model as part of the app
|
||||
if (isServer) return fn;
|
||||
return function() {
|
||||
return fn.apply(app.page, arguments);
|
||||
};
|
||||
}
|
||||
47
mongoui/mongoui-master/node_modules/derby/lib/cluster.js
generated
vendored
Normal file
47
mongoui/mongoui-master/node_modules/derby/lib/cluster.js
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
var cluster = require('cluster')
|
||||
, http = require('http')
|
||||
|
||||
module.exports = {
|
||||
run: run
|
||||
};
|
||||
|
||||
function run(filename, port) {
|
||||
if (cluster.isMaster) {
|
||||
console.log('Master pid', process.pid);
|
||||
startWorker();
|
||||
} else {
|
||||
var server = requireServer(filename);
|
||||
server.listen(port, function() {
|
||||
console.log('%d listening. Go to: http://localhost:%d/', process.pid, port);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function startWorker() {
|
||||
var worker = cluster.fork();
|
||||
worker.once('disconnect', function () {
|
||||
worker.process.kill();
|
||||
});
|
||||
worker.on('message', function(message) {
|
||||
if (message.type === 'reload') {
|
||||
if (worker.disconnecting) return;
|
||||
console.log('Killing %d', worker.process.pid);
|
||||
worker.process.kill();
|
||||
worker.disconnecting = true;
|
||||
startWorker();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function requireServer(filename) {
|
||||
try {
|
||||
var server = require(filename);
|
||||
} catch (e) {
|
||||
console.error('Error requiring server module from `%s`', filename);
|
||||
throw e;
|
||||
}
|
||||
if (!(server instanceof http.Server)) {
|
||||
throw new Error('`' + filename + '` does not export a valid `http.Server`');
|
||||
}
|
||||
return server;
|
||||
}
|
||||
63
mongoui/mongoui-master/node_modules/derby/lib/collection.js
generated
vendored
Normal file
63
mongoui/mongoui-master/node_modules/derby/lib/collection.js
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
module.exports = {
|
||||
construct: construct
|
||||
, pageInit: pageInit
|
||||
};
|
||||
|
||||
function construct(name, proto) {
|
||||
function Collection(page) {
|
||||
return createCollection(page, name, proto);
|
||||
}
|
||||
// Keep a map of defined collections so that they can
|
||||
// be reinitialized from their name on the client
|
||||
this._Collections[name] = Collection;
|
||||
// This makes it possible to subscribe to the entire collection
|
||||
// by making it look like a scoped model
|
||||
Collection._at = name;
|
||||
// TODO: Query builder on the collection
|
||||
return Collection;
|
||||
}
|
||||
|
||||
function createCollection(page, name, proto) {
|
||||
// Collections are actually just scoped models for now
|
||||
var _super = page.model.at(name)
|
||||
, collection = Object.create(_super)
|
||||
|
||||
// Mixin collection specific methods
|
||||
collection._super = _super;
|
||||
collection.page = page;
|
||||
for (key in proto) {
|
||||
collection[key] = proto[key];
|
||||
}
|
||||
|
||||
// Make collection available on the page for use in
|
||||
// event callbacks and other functions
|
||||
page[name] = collection;
|
||||
|
||||
// Keep track of collections that were created so that
|
||||
// they can be recreated on the client if first rendered
|
||||
// on the server
|
||||
page._collections.push(name);
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
function pageInit() {
|
||||
var i = 0
|
||||
, len = arguments.length
|
||||
, items = []
|
||||
, item
|
||||
// All collections are created first before any of their
|
||||
// init methods are called. That way collections created
|
||||
// together can rely on each other being available for use
|
||||
for (i = 0; i < len; i++) {
|
||||
item = arguments[i](this);
|
||||
items.push(item);
|
||||
}
|
||||
// Call the init method of each collection if defined
|
||||
for (i = 0; i < len; i++) {
|
||||
item = items[i];
|
||||
if (item.hasOwnProperty('init')) {
|
||||
item.init();
|
||||
}
|
||||
}
|
||||
}
|
||||
117
mongoui/mongoui-master/node_modules/derby/lib/component.js
generated
vendored
Normal file
117
mongoui/mongoui-master/node_modules/derby/lib/component.js
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
var EventEmitter = require('events').EventEmitter
|
||||
, path = require('path')
|
||||
, merge = require('racer').util.merge
|
||||
, View = require('./View')
|
||||
, arraySlice = Array.prototype.slice
|
||||
|
||||
module.exports = componentPlugin;
|
||||
|
||||
function componentPlugin(derby) {
|
||||
derby._libraries = [];
|
||||
derby._libraries.map = {};
|
||||
derby.createLibrary = createLibrary;
|
||||
}
|
||||
componentPlugin.decorate = 'derby';
|
||||
|
||||
|
||||
var componentProto = Object.create(EventEmitter.prototype);
|
||||
|
||||
componentProto.emitCancellable = function() {
|
||||
var cancelled = false
|
||||
, args = arraySlice.call(arguments)
|
||||
|
||||
function cancel() {
|
||||
cancelled = true;
|
||||
}
|
||||
|
||||
args.push(cancel);
|
||||
this.emit.apply(this, args);
|
||||
return cancelled;
|
||||
};
|
||||
|
||||
componentProto.emitDelayable = function() {
|
||||
var delayed = false
|
||||
, args = arraySlice.call(arguments, 0, -1)
|
||||
, callback = arguments[arguments.length - 1]
|
||||
|
||||
function delay() {
|
||||
delayed = true;
|
||||
}
|
||||
|
||||
args.push(delay, callback);
|
||||
this.emit.apply(this, args);
|
||||
if (!delayed) callback();
|
||||
return delayed;
|
||||
};
|
||||
|
||||
// Hack needed for model bundling
|
||||
componentProto.toJSON = function() {}
|
||||
|
||||
function type(view) {
|
||||
return view === this.view ? 'lib:' + this.id : this.ns + ':' + this.id;
|
||||
}
|
||||
|
||||
function createLibrary(config, options) {
|
||||
if (!config || !config.filename) {
|
||||
throw new Error ('Configuration argument with a filename is required');
|
||||
}
|
||||
if (!options) options = {};
|
||||
var root = path.dirname(config.filename)
|
||||
, ns = options.ns || config.ns || path.basename(root)
|
||||
, scripts = config.scripts || {}
|
||||
, view = new View
|
||||
, constructors = {}
|
||||
, library = {
|
||||
ns: ns
|
||||
, root: root
|
||||
, view: view
|
||||
, constructors: constructors
|
||||
, styles: config.styles
|
||||
}
|
||||
, Component, proto, id, script;
|
||||
|
||||
view._selfNs = 'lib';
|
||||
view._selfLibrary = library;
|
||||
|
||||
for (id in scripts) {
|
||||
script = scripts[id];
|
||||
script.setup && script.setup(library);
|
||||
|
||||
Component = function(model, scope) {
|
||||
this.view = view;
|
||||
this.model = model;
|
||||
this.scope = scope;
|
||||
this.history = null;
|
||||
this.dom = null;
|
||||
|
||||
// Don't limit the number of listeners
|
||||
this.setMaxListeners(0);
|
||||
|
||||
var component = this;
|
||||
model.__on = model._on;
|
||||
model._on = function(name, listener) {
|
||||
component.on('destroy', function() {
|
||||
model.removeListener(name, listener);
|
||||
})
|
||||
return model.__on(name, listener);
|
||||
};
|
||||
component.on('destroy', function() {
|
||||
model.silent().del();
|
||||
});
|
||||
}
|
||||
proto = Component.prototype = Object.create(componentProto);
|
||||
merge(proto, script);
|
||||
|
||||
Component.view = view;
|
||||
Component.ns = ns;
|
||||
Component.id = id;
|
||||
Component.type = type;
|
||||
|
||||
// Note that component names are all lowercased
|
||||
constructors[id.toLowerCase()] = Component;
|
||||
}
|
||||
|
||||
this._libraries.push(library);
|
||||
this._libraries.map[ns] = library;
|
||||
return library;
|
||||
}
|
||||
288
mongoui/mongoui-master/node_modules/derby/lib/derby.Model.js
generated
vendored
Normal file
288
mongoui/mongoui-master/node_modules/derby/lib/derby.Model.js
generated
vendored
Normal file
@@ -0,0 +1,288 @@
|
||||
var EventDispatcher = require('./EventDispatcher')
|
||||
, PathMap = require('./PathMap')
|
||||
, racer = require('racer')
|
||||
, Model = racer["protected"].Model
|
||||
, valueBinding = require('./View').valueBinding
|
||||
, arraySlice = [].slice;
|
||||
|
||||
exports.init = init;
|
||||
|
||||
// Add support for creating a model alias from a DOM node or jQuery object
|
||||
Model.prototype.__at = Model.prototype.at;
|
||||
Model.prototype.at = function(node, absolute) {
|
||||
var isNode = node && (node.parentNode || node.jquery && (node = node[0]));
|
||||
if (!isNode) return this.__at(node, absolute);
|
||||
|
||||
updateMarkers();
|
||||
|
||||
var blockPaths = this.__blockPaths
|
||||
, pathMap = this.__pathMap
|
||||
, root = this._root
|
||||
, child, i, id, last, path, blockPath, children, len;
|
||||
while (node) {
|
||||
if (node.$derbyMarkerParent && last) {
|
||||
node = last;
|
||||
while (node = node.previousSibling) {
|
||||
if (!(id = node.$derbyMarkerId)) continue;
|
||||
blockPath = blockPaths[id];
|
||||
if (node.$derbyMarkerEnd || !blockPath) break;
|
||||
|
||||
path = pathMap.paths[blockPath.id];
|
||||
if ((blockPath.type === 'each') && last) {
|
||||
i = 0;
|
||||
while (node = node.nextSibling) {
|
||||
if (node === last) {
|
||||
path = path + '.' + i;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return this.__at(path, true);
|
||||
}
|
||||
last = last.parentNode;
|
||||
node = last.parentNode;
|
||||
continue;
|
||||
}
|
||||
if ((id = node.id) && (blockPath = blockPaths[id])) {
|
||||
path = pathMap.paths[blockPath.id];
|
||||
if ((blockPath.type === 'each') && last) {
|
||||
children = node.childNodes;
|
||||
for (i = 0, len = children.length; i < len; i++) {
|
||||
child = children[i];
|
||||
if (child === last) {
|
||||
path = path + '.' + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.__at(path, true);
|
||||
}
|
||||
last = node;
|
||||
node = node.parentNode;
|
||||
}
|
||||
|
||||
// Just return the root scope if a path can't be found
|
||||
return root;
|
||||
}
|
||||
|
||||
function updateMarkers() {
|
||||
// NodeFilter.SHOW_COMMENT == 128
|
||||
var commentIterator = document.createTreeWalker(document.body, 128, null, false)
|
||||
, comment, id;
|
||||
while (comment = commentIterator.nextNode()) {
|
||||
if (comment.$derbyChecked) continue;
|
||||
comment.$derbyChecked = true;
|
||||
id = comment.data;
|
||||
if (id.charAt(0) !== '$') continue;
|
||||
if (id.charAt(1) === '$') {
|
||||
comment.$derbyMarkerEnd = true;
|
||||
id = id.slice(1);
|
||||
}
|
||||
comment.$derbyMarkerId = id;
|
||||
comment.parentNode.$derbyMarkerParent = true;
|
||||
}
|
||||
}
|
||||
|
||||
function init(derby, app) {
|
||||
var model = app.model
|
||||
, dom = app.dom
|
||||
, pathMap = model.__pathMap = new PathMap
|
||||
, events = model.__events = new EventDispatcher({onTrigger: derbyModelTrigger})
|
||||
|
||||
function derbyModelTrigger(pathId, listener, type, local, options, value, index, arg) {
|
||||
var id = listener[0]
|
||||
, el = dom.item(id);
|
||||
|
||||
// Fail and remove the listener if the element can't be found
|
||||
if (!el) return false;
|
||||
|
||||
var method = listener[1]
|
||||
, property = listener[2]
|
||||
, partial = listener.partial
|
||||
, path = pathMap.paths[pathId]
|
||||
, triggerId;
|
||||
if (method === 'propPolite' && local) method = 'prop';
|
||||
if (partial) {
|
||||
triggerId = id;
|
||||
if (method === 'html' && type) {
|
||||
if (partial.type === 'each' && !derby.get('disableArrayBindings')) {
|
||||
// Handle array updates
|
||||
method = type;
|
||||
if (type === 'append') {
|
||||
path += '.' + (index = model.get(path).length - 1);
|
||||
triggerId = null;
|
||||
} else if (type === 'insert') {
|
||||
path += '.' + index;
|
||||
triggerId = null;
|
||||
} else if (type === 'remove') {
|
||||
partial = null;
|
||||
} else if (type === 'move') {
|
||||
partial = null;
|
||||
property = arg;
|
||||
}
|
||||
} else {
|
||||
value = model.get(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (listener.getValue) {
|
||||
value = listener.getValue(model, path);
|
||||
}
|
||||
if (partial) {
|
||||
value = partial(listener.ctx, model, path, triggerId, value, index, listener);
|
||||
}
|
||||
value = valueBinding(value);
|
||||
dom.update(el, method, options && options.ignore, value, property, index);
|
||||
}
|
||||
|
||||
// Derby's mutator listeners are added via unshift instead of model.on, because
|
||||
// it needs to handle events in the same order that racer applies mutations.
|
||||
// If there is a listener to an event that applies a mutation, event listeners
|
||||
// later in the listeners queues could receive events in a different order
|
||||
|
||||
model.listeners('set').unshift(function listenerDerbySet(args, out, local, pass) {
|
||||
var arrayPath, i, index, path, value;
|
||||
model.emit('pre:set', args, out, local, pass);
|
||||
path = args[0], value = args[1];
|
||||
|
||||
// For set operations on array items, also emit a remove and insert in case the
|
||||
// array is bound
|
||||
if (/\.\d+$/.test(path)) {
|
||||
i = path.lastIndexOf('.');
|
||||
arrayPath = path.slice(0, i);
|
||||
index = path.slice(i + 1);
|
||||
triggerEach(arrayPath, 'remove', local, pass, index);
|
||||
triggerEach(arrayPath, 'insert', local, pass, value, index);
|
||||
}
|
||||
return triggerEach(path, 'html', local, pass, value);
|
||||
});
|
||||
|
||||
model.listeners('del').unshift(function listenerDerbyDel(args, out, local, pass) {
|
||||
model.emit('pre:del', args, out, local, pass);
|
||||
var path = args[0];
|
||||
return triggerEach(path, 'html', local, pass);
|
||||
});
|
||||
|
||||
model.listeners('push').unshift(function listenerDerbyPush(args, out, local, pass) {
|
||||
model.emit('pre:push', args, out, local, pass);
|
||||
var path = args[0]
|
||||
, values = arraySlice.call(args, 1);
|
||||
for (var i = 0, len = values.length, value; i < len; i++) {
|
||||
value = values[i];
|
||||
triggerEach(path, 'append', local, pass, value);
|
||||
}
|
||||
});
|
||||
|
||||
model.listeners('move').unshift(function listenerDerbyMove(args, out, local, pass) {
|
||||
model.emit('pre:move', args, out, local, pass);
|
||||
var path = args[0]
|
||||
, from = args[1]
|
||||
, to = args[2]
|
||||
, howMany = args[3]
|
||||
, len = model.get(path).length;
|
||||
from = refIndex(from);
|
||||
to = refIndex(to);
|
||||
if (from < 0) from += len;
|
||||
if (to < 0) to += len;
|
||||
if (from === to) return;
|
||||
// Update indicies in pathMap
|
||||
pathMap.onMove(path, from, to, howMany);
|
||||
triggerEach(path, 'move', local, pass, from, howMany, to);
|
||||
});
|
||||
|
||||
model.listeners('unshift').unshift(function listenerDerbyUnshift(args, out, local, pass) {
|
||||
model.emit('pre:unshift', args, out, local, pass);
|
||||
var path = args[0]
|
||||
, values = arraySlice.call(args, 1);
|
||||
insert(path, 0, values, local, pass);
|
||||
});
|
||||
|
||||
model.listeners('insert').unshift(function listenerDerbyInsert(args, out, local, pass) {
|
||||
model.emit('pre:insert', args, out, local, pass);
|
||||
var path = args[0]
|
||||
, index = args[1]
|
||||
, values = arraySlice.call(args, 2);
|
||||
insert(path, index, values, local, pass);
|
||||
});
|
||||
|
||||
model.listeners('remove').unshift(function listenerDerbyRemove(args, out, local, pass) {
|
||||
model.emit('pre:remove', args, out, local, pass);
|
||||
var path = args[0]
|
||||
, start = args[1]
|
||||
, howMany = args[2];
|
||||
remove(path, start, howMany, local, pass);
|
||||
});
|
||||
|
||||
model.listeners('pop').unshift(function listenerDerbyPop(args, out, local, pass) {
|
||||
model.emit('pre:pop', args, out, local, pass);
|
||||
var path = args[0];
|
||||
remove(path, model.get(path).length, 1, local, pass);
|
||||
});
|
||||
|
||||
model.listeners('shift').unshift(function listenerDerbyShift(args, out, local, pass) {
|
||||
model.emit('pre:shift', args, out, local, pass);
|
||||
var path = args[0];
|
||||
remove(path, 0, 1, local, pass);
|
||||
});
|
||||
|
||||
['connected', 'canConnect'].forEach(function(event) {
|
||||
model.listeners(event).unshift(function(value) {
|
||||
triggerEach(event, null, true, null, value);
|
||||
});
|
||||
});
|
||||
|
||||
model.on('reInit', function() {
|
||||
app.history.refresh();
|
||||
});
|
||||
|
||||
function triggerEach(path, arg0, arg1, arg2, arg3, arg4, arg5) {
|
||||
// While rendering the entire page, don't update any bindings
|
||||
if (dom._preventUpdates) return;
|
||||
|
||||
var id = pathMap.ids[path]
|
||||
, segments = path.split('.')
|
||||
, i, pattern;
|
||||
|
||||
// Trigger an event on the path if it has a pathMap ID
|
||||
if (id) events.trigger(id, arg0, arg1, arg2, arg3, arg4, arg5);
|
||||
|
||||
// Also trigger a pattern event for the path and each of its parent paths
|
||||
// This is used by view helper functions to match updates on a path
|
||||
// or any of its child segments
|
||||
i = segments.length + 1;
|
||||
while (--i) {
|
||||
pattern = segments.slice(0, i).join('.') + '*';
|
||||
if (id = pathMap.ids[pattern]) {
|
||||
events.trigger(id, arg0, arg1, arg2, arg3, arg4, arg5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get index if event was from refList id object
|
||||
function refIndex(obj) {
|
||||
return typeof obj === 'object' ? obj.index : +obj;
|
||||
}
|
||||
|
||||
function insert(path, start, values, local, pass) {
|
||||
start = refIndex(start);
|
||||
// Update indicies in pathMap
|
||||
pathMap.onInsert(path, start, values.length);
|
||||
for (var i = 0, len = values.length, value; i < len; i++) {
|
||||
value = values[i];
|
||||
triggerEach(path, 'insert', local, pass, value, start + i);
|
||||
}
|
||||
}
|
||||
|
||||
function remove(path, start, howMany, local, pass) {
|
||||
start = refIndex(start);
|
||||
var end = start + howMany;
|
||||
// Update indicies in pathMap
|
||||
pathMap.onRemove(path, start, howMany);
|
||||
for (var i = start; i < end; i++) {
|
||||
triggerEach(path, 'remove', local, pass, start);
|
||||
}
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
189
mongoui/mongoui-master/node_modules/derby/lib/derby.browser.js
generated
vendored
Normal file
189
mongoui/mongoui-master/node_modules/derby/lib/derby.browser.js
generated
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
var racer = require('racer')
|
||||
, tracks = require('tracks')
|
||||
, sharedCreateApp = require('./app').create
|
||||
, derbyModel = require('./derby.Model')
|
||||
, Dom = require('./Dom')
|
||||
, collection = require('./collection')
|
||||
, autoRefresh = require('./refresh').autoRefresh
|
||||
|
||||
module.exports = derbyBrowser;
|
||||
|
||||
function derbyBrowser(derby) {
|
||||
// This assumes that only a single instance of this module can run at a time,
|
||||
// which is reasonable in the browser. This is written like this so that
|
||||
// the DERBY global can be used to initialize templates and data.
|
||||
global.DERBY = derby;
|
||||
derby.createApp = createApp;
|
||||
derby.init = init;
|
||||
}
|
||||
derbyBrowser.decorate = 'derby';
|
||||
derbyBrowser.useWith = {server: false, browser: true};
|
||||
|
||||
function createApp(appModule) {
|
||||
if (derbyBrowser.created) {
|
||||
throw new Error('derby.createApp() called multiple times in the browser');
|
||||
} else {
|
||||
derbyBrowser.created = true;
|
||||
}
|
||||
|
||||
var app = sharedCreateApp(this, appModule)
|
||||
global.DERBY.app = app;
|
||||
|
||||
// Adds get, post, put, del, enter, and exit methods
|
||||
// as well as history to app
|
||||
tracks.setup(app, createPage, onRoute);
|
||||
|
||||
onRenderError = function(err, url) {
|
||||
setTimeout(function() {
|
||||
window.location = url;
|
||||
}, 0);
|
||||
throw err;
|
||||
}
|
||||
|
||||
function Page(app) {
|
||||
this.app = app;
|
||||
this.model = app.model;
|
||||
this.dom = app.dom;
|
||||
this.history = app.history;
|
||||
this._collections = [];
|
||||
this._routing = false;
|
||||
}
|
||||
Page.prototype.render = function(ns, ctx) {
|
||||
try {
|
||||
app.view.render(this.model, ns, ctx);
|
||||
this._routing = false;
|
||||
tracks.render(this, {
|
||||
url: this.params.url
|
||||
, previous: this.params.previous
|
||||
, method: 'enter'
|
||||
, noNavigate: true
|
||||
});
|
||||
} catch (err) {
|
||||
onRenderError(err, this.params.url);
|
||||
}
|
||||
};
|
||||
Page.prototype.init = collection.pageInit;
|
||||
|
||||
function createPage() {
|
||||
return new Page(app);
|
||||
}
|
||||
function onRoute(callback, page, params, next, isTransitional) {
|
||||
try {
|
||||
if (isTransitional) {
|
||||
callback(page.model, params, next);
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.method === 'enter' || params.method === 'exit') {
|
||||
callback.call(app, page.model, params);
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!page._routing) {
|
||||
app.view._beforeRoute();
|
||||
tracks.render(page, {
|
||||
url: page.params.previous
|
||||
, method: 'exit'
|
||||
, noNavigate: true
|
||||
});
|
||||
}
|
||||
page._routing = true;
|
||||
callback(page, page.model, params, next);
|
||||
} catch (err) {
|
||||
onRenderError(err, page.params.url);
|
||||
}
|
||||
}
|
||||
|
||||
app.ready = function(fn) {
|
||||
racer.on('ready', function(model) {
|
||||
fn.call(app, model);
|
||||
});
|
||||
};
|
||||
return app;
|
||||
}
|
||||
|
||||
function init(modelBundle, ctx) {
|
||||
var app = global.DERBY.app
|
||||
, ns = ctx.$ns
|
||||
, appHash = ctx.$appHash
|
||||
, renderHash = ctx.$renderHash
|
||||
, derby = this
|
||||
|
||||
// The init event is fired after the model data is initialized but
|
||||
// before the socket object is set
|
||||
racer.on('init', function(model) {
|
||||
var dom = new Dom(model);
|
||||
|
||||
app.model = model;
|
||||
app.dom = dom;
|
||||
|
||||
// Calling history.page() creates the initial page, which is only
|
||||
// created one time on the client
|
||||
// TODO: This is a rather obtuse mechanism
|
||||
var page = app.history.page();
|
||||
app.page = page;
|
||||
|
||||
// Reinitialize any collections which were already initialized
|
||||
// during rendering on the server
|
||||
if (ctx.$collections) {
|
||||
var Collections = ctx.$collections.map(function(name) {
|
||||
return app._Collections[name];
|
||||
});
|
||||
page.init.apply(page, Collections);
|
||||
}
|
||||
|
||||
// Update events should wait until after first render is done
|
||||
dom._preventUpdates = true;
|
||||
|
||||
derbyModel.init(derby, app);
|
||||
// Catch errors thrown when rendering and then throw from a setTimeout.
|
||||
// This way, the remaining init code can run and the app still connects
|
||||
try {
|
||||
// Render immediately upon initialization so that the page is in
|
||||
// EXACTLY the same state it was when rendered on the server
|
||||
app.view.render(model, ns, ctx, renderHash);
|
||||
} catch (err) {
|
||||
setTimeout(function() {
|
||||
throw err;
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
// The ready event is fired after the model data is initialized and
|
||||
// the socket object is set
|
||||
racer.on('ready', function(model) {
|
||||
model.socket.on('connect', function() {
|
||||
model.socket.emit('derbyClient', appHash, function(reload) {
|
||||
if (reload) {
|
||||
var retries = 0
|
||||
, reloadOnEmpty = function() {
|
||||
// TODO: Don't hack the Racer internal API so much
|
||||
if (model._txnQueue.length && retries++ < 20) {
|
||||
// Clear out private path transactions that could get stuck
|
||||
model._specModel();
|
||||
return setTimeout(reloadOnEmpty, 100);
|
||||
}
|
||||
window.location.reload(true);
|
||||
}
|
||||
reloadOnEmpty();
|
||||
}
|
||||
});
|
||||
});
|
||||
var debug = !model.flags.isProduction;
|
||||
if (debug) autoRefresh(app.view, model);
|
||||
|
||||
tracks.render(app.history.page(), {
|
||||
url: window.location.pathname + window.location.search
|
||||
, method: 'enter'
|
||||
, noNavigate: true
|
||||
});
|
||||
|
||||
// Delaying here to make sure that all ready callbacks are called before
|
||||
// the create functions run on various components
|
||||
setTimeout(function() {
|
||||
app.view._afterRender(ns, ctx);
|
||||
}, 0);
|
||||
});
|
||||
racer.init(modelBundle);
|
||||
}
|
||||
14
mongoui/mongoui-master/node_modules/derby/lib/derby.js
generated
vendored
Normal file
14
mongoui/mongoui-master/node_modules/derby/lib/derby.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
var racer = require('racer')
|
||||
, component = require('./component')
|
||||
, derby = module.exports = Object.create(racer)
|
||||
, derbyPlugin = racer.util.isServer ?
|
||||
__dirname + '/derby.server' : require('./derby.browser');
|
||||
|
||||
// Allow derby object to be targeted via plugin.decorate
|
||||
racer._makePlugable('derby', derby);
|
||||
|
||||
derby
|
||||
// Shared methods
|
||||
.use(component)
|
||||
// Server-side or browser-side methods
|
||||
.use(derbyPlugin);
|
||||
105
mongoui/mongoui-master/node_modules/derby/lib/derby.server.js
generated
vendored
Normal file
105
mongoui/mongoui-master/node_modules/derby/lib/derby.server.js
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
var fs = require('fs')
|
||||
, path = require('path')
|
||||
, http = require('http')
|
||||
, racer = require('racer')
|
||||
, tracks = require('tracks')
|
||||
, View = require('./View.server')
|
||||
, sharedCreateApp = require('./app').create
|
||||
, autoRefresh = require('./refresh.server').autoRefresh
|
||||
, derbyCluster = require('./cluster')
|
||||
, collection = require('./collection')
|
||||
, util = racer.util
|
||||
, merge = util.merge
|
||||
, isProduction = util.isProduction
|
||||
, proto
|
||||
|
||||
module.exports = derbyServer;
|
||||
|
||||
function derbyServer(derby) {
|
||||
derby.run = run;
|
||||
derby.createApp = createApp;
|
||||
derby.createStatic = createStatic;
|
||||
|
||||
Object.defineProperty(derby, 'version', {
|
||||
get: function() {
|
||||
return require('../package.json').version;
|
||||
}
|
||||
});
|
||||
}
|
||||
derbyServer.decorate = 'derby';
|
||||
derbyServer.useWith = {server: true, browser: false};
|
||||
|
||||
function run(filename, port) {
|
||||
// Resolve relative filenames
|
||||
filename = path.resolve(filename);
|
||||
if (port == null) port = process.env.PORT || (isProduction ? 80 : 3000);
|
||||
derbyCluster.run(filename, port)
|
||||
}
|
||||
|
||||
function createApp(appModule) {
|
||||
var app = sharedCreateApp(this, appModule)
|
||||
, view = app.view
|
||||
|
||||
racer.on('createStore', function(store) {
|
||||
autoRefresh(store, view, isProduction);
|
||||
});
|
||||
|
||||
// Expose methods on the application module
|
||||
|
||||
function Page(model, res) {
|
||||
this.model = model;
|
||||
this.view = view;
|
||||
this._res = res;
|
||||
this._collections = [];
|
||||
}
|
||||
Page.prototype.render = function(ns, ctx, status) {
|
||||
this._res._derbyCollections = this._collections;
|
||||
view.render(this._res, this.model, ns, ctx, status);
|
||||
};
|
||||
Page.prototype.init = collection.pageInit;
|
||||
|
||||
function createPage(req, res) {
|
||||
var model = req.getModel();
|
||||
return new Page(model, res);
|
||||
}
|
||||
function onRoute(callback, page, params, next, isTransitional) {
|
||||
if (isTransitional) {
|
||||
callback(page.model, params, next);
|
||||
} else {
|
||||
callback(page, page.model, params, next);
|
||||
}
|
||||
}
|
||||
app.routes = tracks.setup(app, createPage, onRoute);
|
||||
|
||||
app.ready = function() {};
|
||||
app.render = function(res, model, ns, ctx, status) {
|
||||
return view.render(res, model, ns, ctx, status);
|
||||
};
|
||||
|
||||
// Render immediately upon creating the app so that files
|
||||
// will be cached for the first render and the appHash gets
|
||||
// computed for reconnecting windows
|
||||
process.nextTick(function() {
|
||||
view.render();
|
||||
});
|
||||
return app;
|
||||
}
|
||||
|
||||
function createStatic(root) {
|
||||
return new Static(root, this._libraries);
|
||||
}
|
||||
|
||||
function Static(root, libraries) {
|
||||
this.root = root;
|
||||
this.libraries = libraries;
|
||||
this.views = {};
|
||||
}
|
||||
Static.prototype.render = function(name, res, model, ns, ctx, status) {
|
||||
var view = this.views[name];
|
||||
if (!view) {
|
||||
view = this.views[name] = new View(this.libraries);
|
||||
view._root = this.root;
|
||||
view._clientName = name;
|
||||
}
|
||||
view.render(res, model, ns, ctx, status, true);
|
||||
};
|
||||
185
mongoui/mongoui-master/node_modules/derby/lib/eventBinding.js
generated
vendored
Normal file
185
mongoui/mongoui-master/node_modules/derby/lib/eventBinding.js
generated
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
var util = require('racer').util
|
||||
, lookup = require('racer/lib/path').lookup
|
||||
, merge = util.merge
|
||||
, viewPath = require('./viewPath')
|
||||
, extractPlaceholder = viewPath.extractPlaceholder
|
||||
, dataValue = viewPath.dataValue
|
||||
, ctxPath = viewPath.ctxPath
|
||||
, pathFnArgs = viewPath.pathFnArgs
|
||||
, setBoundFn = viewPath.setBoundFn
|
||||
, arraySlice = [].slice
|
||||
|
||||
exports.splitEvents = splitEvents;
|
||||
exports.fnListener = fnListener;
|
||||
exports.containsEvent = containsEvent;
|
||||
exports.addDomEvent = util.isServer ? empty : addDomEvent;
|
||||
|
||||
function splitEvents(eventNames) {
|
||||
var pairs = eventNames.split(',')
|
||||
, eventList = []
|
||||
, i, j, pair, segments, name, eventName, delay, fns, fn;
|
||||
for (i = pairs.length; i--;) {
|
||||
pair = pairs[i];
|
||||
segments = pair.split(':');
|
||||
name = segments[0].split('/');
|
||||
eventName = name[0].trim();
|
||||
delay = name[1];
|
||||
fns = (segments[1] || '').trim().split(/\s+/);
|
||||
for (j = fns.length; j--;) {
|
||||
fn = fns[j];
|
||||
fns[j] = extractPlaceholder(fn) || fn;
|
||||
}
|
||||
eventList.push([eventName, delay, fns]);
|
||||
}
|
||||
return eventList;
|
||||
}
|
||||
|
||||
function containsEvent(eventNames, expected) {
|
||||
if (!Array.isArray(expected)) expected = [expected];
|
||||
var eventList = splitEvents(eventNames)
|
||||
, i, j, eventName
|
||||
for (i = eventList.length; i--;) {
|
||||
eventName = eventList[i][0];
|
||||
for (j = expected.length; j--;) {
|
||||
if (eventName === expected[j]) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function addDomEvent(events, attrs, eventNames, match, options) {
|
||||
var eventList = splitEvents(eventNames)
|
||||
, args, name;
|
||||
|
||||
if (match) {
|
||||
name = match.name;
|
||||
|
||||
if (~name.indexOf('(')) {
|
||||
args = pathFnArgs(name);
|
||||
if (!args.length) return;
|
||||
|
||||
events.push(function(ctx, modelEvents, dom, pathMap, view) {
|
||||
var id = attrs._id || attrs.id
|
||||
, paths = []
|
||||
, arg, path, pathId, event, eventName, eventOptions, i, j;
|
||||
options.setValue = function(model, value) {
|
||||
return setBoundFn(view, ctx, model, name, value);
|
||||
}
|
||||
for (i = args.length; i--;) {
|
||||
arg = args[i];
|
||||
path = ctxPath(view, ctx, arg);
|
||||
paths.push(path);
|
||||
pathId = pathMap.id(path);
|
||||
for (j = eventList.length; j--;) {
|
||||
event = eventList[j];
|
||||
eventName = event[0];
|
||||
eventOptions = merge({view: view, ctx: ctx, pathId: pathId, delay: event[1]}, options);
|
||||
dom.bind(eventName, id, eventOptions);
|
||||
}
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
events.push(function(ctx, modelEvents, dom, pathMap, view) {
|
||||
var id = attrs._id || attrs.id
|
||||
, pathId = pathMap.id(ctxPath(view, ctx, name))
|
||||
, event, eventName, eventOptions, i;
|
||||
for (i = eventList.length; i--;) {
|
||||
event = eventList[i];
|
||||
eventName = event[0];
|
||||
eventOptions = merge({view: view, ctx: ctx, pathId: pathId, delay: event[1]}, options);
|
||||
dom.bind(eventName, id, eventOptions);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
events.push(function(ctx, modelEvents, dom, pathMap, view) {
|
||||
var id = attrs._id || attrs.id
|
||||
, pathId = pathMap.id(ctxPath(view, ctx, '.'))
|
||||
, event, eventName, eventOptions, i;
|
||||
for (i = eventList.length; i--;) {
|
||||
event = eventList[i];
|
||||
eventName = event[0];
|
||||
eventOptions = fnListener(view, ctx, event[2], dom);
|
||||
eventOptions.delay = event[1];
|
||||
merge(eventOptions, options);
|
||||
merge(eventOptions, {view: view, ctx: ctx, pathId: pathId});
|
||||
dom.bind(eventName, id, eventOptions);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function eachFnListener(view, ctx, fnObj, dom) {
|
||||
var fnName, fn, fnCtxs, i, fnCtx;
|
||||
|
||||
fnName = typeof fnObj === 'object'
|
||||
? dataValue(view, ctx, view.model, fnObj.name)
|
||||
: fnName = fnObj;
|
||||
|
||||
// If a placeholder for an event name does not have a value, do nothing
|
||||
if (!fnName) return empty;
|
||||
|
||||
// See if it is a built-in function
|
||||
fn = dom && dom.fns[fnName];
|
||||
|
||||
// Lookup the function name on the component script or app
|
||||
|
||||
// TODO: This simply looks in the local scope for the function
|
||||
// and then goes up the scope if a function name is not found.
|
||||
// Better would be to actually figure out the scope of where the
|
||||
// function name is specfied, since there could easily be namespace
|
||||
// conflicts between functions in a component and functions in an
|
||||
// app using that component. How to implement this correctly is not
|
||||
// obvious at the moment.
|
||||
if (!fn) {
|
||||
fnCtxs = ctx.$fnCtx;
|
||||
for (i = fnCtxs.length; i--;) {
|
||||
fnCtx = fnCtxs[i];
|
||||
fn = fnCtx[fnName] || lookup(fnName, fnCtx);
|
||||
if (fn) break;
|
||||
}
|
||||
}
|
||||
if (!fn) throw new Error('Bound function not found: ' + fnName);
|
||||
|
||||
// Bind the listener to the app or component object on which it
|
||||
// was defined so that the `this` context will be the instance
|
||||
return fn.bind(fnCtx);
|
||||
}
|
||||
|
||||
function fnListener(view, ctx, fnNames, dom) {
|
||||
var listener = {
|
||||
fn: function() {
|
||||
var len = fnNames.length
|
||||
, args = arraySlice.call(arguments)
|
||||
, i, fn, boundFns
|
||||
|
||||
if (len === 0) {
|
||||
// Don't do anything if no handler functions were specified
|
||||
return listener.fn = empty;
|
||||
|
||||
} else if (len === 1) {
|
||||
fn = eachFnListener(view, ctx, fnNames[0], dom);
|
||||
|
||||
} else {
|
||||
boundFns = [];
|
||||
for (i = len; i--;) {
|
||||
boundFns.push(eachFnListener(view, ctx, fnNames[i], dom));
|
||||
}
|
||||
fn = function() {
|
||||
var args = arraySlice.call(arguments)
|
||||
for (var i = boundFns.length; i--;) {
|
||||
boundFns[i].apply(null, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
listener.fn = fn;
|
||||
fn.apply(null, args);
|
||||
}
|
||||
};
|
||||
return listener;
|
||||
}
|
||||
|
||||
function empty() {}
|
||||
537
mongoui/mongoui-master/node_modules/derby/lib/files.js
generated
vendored
Normal file
537
mongoui/mongoui-master/node_modules/derby/lib/files.js
generated
vendored
Normal file
@@ -0,0 +1,537 @@
|
||||
var pathUtil = require('path')
|
||||
, fs = require('fs')
|
||||
, dirname = pathUtil.dirname
|
||||
, basename = pathUtil.basename
|
||||
, join = pathUtil.join
|
||||
, exists = fs.exists || pathUtil.exists
|
||||
, relative = pathUtil.relative
|
||||
, resolve = pathUtil.resolve
|
||||
, crypto = require('crypto')
|
||||
, chokidar = require('chokidar')
|
||||
, stylus = require('stylus')
|
||||
, nib = require('nib')
|
||||
, less = require('less')
|
||||
, racer = require('racer')
|
||||
, Promise = racer.util.Promise
|
||||
, hasKeys = racer.util.hasKeys
|
||||
, finishAfter = racer.util.async.finishAfter
|
||||
, asyncForEach = racer.util.async.forEach
|
||||
, htmlUtil = require('html-util')
|
||||
, parseHtml = htmlUtil.parse
|
||||
, minifyHtml = htmlUtil.minify
|
||||
, styleCompilers = {
|
||||
stylus: stylusCompiler
|
||||
, less: lessCompiler
|
||||
}
|
||||
, derby = require('./derby')
|
||||
, isWindows = process.platform === 'win32'
|
||||
|
||||
exports.css = css;
|
||||
exports.templates = templates;
|
||||
exports.js = js;
|
||||
exports.library = library;
|
||||
exports.parseName = parseName;
|
||||
exports.hashFile = hashFile;
|
||||
exports.genInfo = genInfo;
|
||||
exports.writeGen = writeGen;
|
||||
exports.writeJs = writeJs;
|
||||
exports.watch = watch;
|
||||
|
||||
function css(root, clientName, compress, callback) {
|
||||
// TODO: Set default configuration options in a single place
|
||||
var styles = derby.get('styles') || ['less', 'stylus']
|
||||
, compiled = []
|
||||
, finish;
|
||||
|
||||
root += '/styles';
|
||||
|
||||
if (!Array.isArray(styles)) styles = [styles];
|
||||
|
||||
finish = finishAfter(styles.length, function(err) {
|
||||
callback(err, compiled.join(''));
|
||||
});
|
||||
|
||||
styles.forEach(function(style, i) {
|
||||
var compiler = styleCompilers[style];
|
||||
if (!compiler) finish(new Error('Unable to find compiler for: ' + style));
|
||||
|
||||
compiler(root, clientName, compress, function(err, value) {
|
||||
compiled[i] = value || '';
|
||||
finish(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function stylusCompiler(root, clientName, compress, callback) {
|
||||
findPath(root, clientName, '.styl', function(path) {
|
||||
if (!path) return callback('');
|
||||
fs.readFile(path, 'utf8', function(err, styl) {
|
||||
if (err) return callback(err);
|
||||
stylus(styl)
|
||||
.use(nib())
|
||||
.set('filename', path)
|
||||
.set('compress', compress)
|
||||
.set('include css', true)
|
||||
.render(callback);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function lessCompiler(root, clientName, compress, callback) {
|
||||
var dir = clientName.charAt(0) === '/' ? dirname(clientName) : root;
|
||||
findPath(root, clientName, '.less', function(path) {
|
||||
if (!path) return callback('');
|
||||
|
||||
fs.readFile(path, 'utf8', function(err, lessFile) {
|
||||
if (err) return callback(err);
|
||||
var parser = new less.Parser({
|
||||
paths: [dirname(path)]
|
||||
, filename: path
|
||||
});
|
||||
parser.parse(lessFile, function(err, tree) {
|
||||
var compiled;
|
||||
if (err) return callback(err);
|
||||
try {
|
||||
compiled = tree.toCSS({compress: compress});
|
||||
} catch (err) {
|
||||
return callback(err);
|
||||
}
|
||||
callback(null, compiled);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function templates(root, clientName, callback) {
|
||||
loadTemplates(root + '/views', clientName, callback);
|
||||
}
|
||||
|
||||
function js(parentFilename, options, callback) {
|
||||
var finish, inline, inlineFile, js;
|
||||
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
// Needed for tests
|
||||
if (!parentFilename) return callback();
|
||||
|
||||
// TODO: Move this to Tracks:
|
||||
// Express will try to include mime or connect, which won't work in the
|
||||
// browser. It doesn't actually need this for routing, so just ignore it
|
||||
options.ignore || (options.ignore = ['connect', 'mime']);
|
||||
options.entry || (options.entry = parentFilename);
|
||||
|
||||
inlineFile = join(dirname(parentFilename), 'inline.js');
|
||||
finish = finishAfter(2, function(err) {
|
||||
callback(err, js, inline);
|
||||
});
|
||||
racer.js(options, function(err, value) {
|
||||
js = value;
|
||||
finish(err);
|
||||
});
|
||||
fs.readFile(inlineFile, 'utf8', function(err, value) {
|
||||
inline = value;
|
||||
// Ignore file not found error
|
||||
if (err && err.code === 'ENOENT') err = null;
|
||||
finish(err);
|
||||
});
|
||||
}
|
||||
|
||||
function library(root, callback) {
|
||||
var components = {};
|
||||
|
||||
fs.readdir(root, function(err, files) {
|
||||
if (err) return callback(err);
|
||||
asyncForEach(files, libraryFile, function(err) {
|
||||
if (err) return callback(err);
|
||||
callback(null, components);
|
||||
});
|
||||
});
|
||||
|
||||
function libraryFile(file, callback) {
|
||||
var path = root + '/' + file
|
||||
fs.stat(path, function(err, stats) {
|
||||
if (err) return callback(err);
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
return addComponent(root, file, callback);
|
||||
}
|
||||
if (extensions['html'].test(file)) {
|
||||
file = file.replace(extensions['html'], '');
|
||||
return addComponent(root, file, callback);
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function addComponent(root, name, callback) {
|
||||
loadTemplates(root, name, function(err, templates, instances) {
|
||||
components[name] = {
|
||||
templates: templates
|
||||
, instances: instances
|
||||
};
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function unixRelative(from, to) {
|
||||
var path = relative(from, to);
|
||||
return isWindows ? path.replace(/\\/g, '/') : path;
|
||||
}
|
||||
|
||||
function parseName(parentFilename) {
|
||||
var parentDir = dirname(parentFilename)
|
||||
, root = parentDir
|
||||
, base = basename(parentFilename).replace(/\.(?:js|coffee)$/, '');
|
||||
if (base === 'index') {
|
||||
base = basename(parentDir);
|
||||
root = dirname(dirname(parentDir));
|
||||
} else if (basename(parentDir) === 'lib') {
|
||||
root = dirname(parentDir);
|
||||
}
|
||||
return {
|
||||
root: root
|
||||
, clientName: base
|
||||
};
|
||||
}
|
||||
|
||||
function hashFile(file) {
|
||||
var hash = crypto.createHash('md5').update(file).digest('base64');
|
||||
// Base64 uses characters reserved in URLs and adds extra padding charcters.
|
||||
// Replace "/" and "+" with the unreserved "-" and "_" and remove "=" padding
|
||||
return hash.replace(/[\/\+=]/g, function(match) {
|
||||
switch (match) {
|
||||
case '/': return '-';
|
||||
case '+': return '_';
|
||||
case '=': return '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function genInfo(root, filename, isPackage) {
|
||||
var staticRoot = derby.get('staticRoot') || join(root, 'public')
|
||||
, staticMount = derby.get('staticMount') || ''
|
||||
, staticDir = isPackage
|
||||
? derby.get('staticPackageDir') || '/genpack'
|
||||
: derby.get('staticDir') || '/gen'
|
||||
, staticPath = join(staticRoot, staticDir)
|
||||
, filePath = join(staticPath, filename)
|
||||
, relativePath = join(staticMount, staticDir, filename)
|
||||
return {
|
||||
staticPath: staticPath
|
||||
, staticRoot: staticRoot
|
||||
, filePath: filePath
|
||||
, relativePath: relativePath
|
||||
}
|
||||
}
|
||||
|
||||
function writeGen(root, filename, file, isPackage, callback) {
|
||||
var info = genInfo(root, filename, isPackage)
|
||||
function finish(err) {
|
||||
if (err) return callback(err);
|
||||
fs.writeFile(info.filePath, file, function(err) {
|
||||
callback(err, info.relativePath);
|
||||
});
|
||||
}
|
||||
exists(info.staticPath, function(value) {
|
||||
if (value) return finish();
|
||||
|
||||
fs.mkdir(info.staticRoot, '0777', function(err) {
|
||||
// Not a problem if the directory already exists
|
||||
if (err && err.code !== 'EEXIST') return finish(err);
|
||||
fs.mkdir(info.staticPath, '0777', function(err) {
|
||||
// Not a problem if the directory already exists
|
||||
if (err && err.code !== 'EEXIST') return finish(err);
|
||||
finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function writeJs(root, file, isPackage, callback) {
|
||||
var hash = hashFile(file)
|
||||
, filename = hash + '.js'
|
||||
writeGen(root, filename, file, isPackage, function(err, relativePath) {
|
||||
callback(err, relativePath, hash);
|
||||
});
|
||||
}
|
||||
|
||||
function watch(dir, type, onChange) {
|
||||
var extension = extensions[type]
|
||||
, hashes = {}
|
||||
, watcher = chokidar.watch([])
|
||||
|
||||
watcher
|
||||
.on('add', checkModified)
|
||||
.on('change', checkModified)
|
||||
.on('unlink', checkModified)
|
||||
.on('error', function(err) {
|
||||
console.error('Watch error\n', err);
|
||||
})
|
||||
|
||||
files(dir, extension).forEach(function(path) {
|
||||
fs.readFile(path, 'utf8', function(err, file) {
|
||||
if (err) return console.error('Watch error\n', err);
|
||||
hashes[path] = hashFile(file);
|
||||
watcher.add(path);
|
||||
});
|
||||
});
|
||||
|
||||
function checkModified(path) {
|
||||
fs.readFile(path, 'utf8', function(err, file) {
|
||||
if (err) return console.error('Watch error\n', err);
|
||||
var hash = hashFile(file);
|
||||
if (hash === hashes[path]) return;
|
||||
hashes[path] = hash;
|
||||
onChange(path);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function absolutePath(path) {
|
||||
return path === resolve('/', path);
|
||||
}
|
||||
|
||||
function findPath(root, name, extension, callback) {
|
||||
if (!absolutePath(name)) {
|
||||
name = join(root, name);
|
||||
}
|
||||
var path = name + extension;
|
||||
exists(path, function(value) {
|
||||
if (value) return callback(path);
|
||||
path = join(name, 'index' + extension);
|
||||
exists(path, function(value) {
|
||||
callback(value ? path : null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function loadTemplates(root, fileName, callback) {
|
||||
var count = 0
|
||||
, calls = {incr: incr, finish: finish};
|
||||
function incr() {
|
||||
count++;
|
||||
}
|
||||
function finish(err, templates, instances) {
|
||||
if (err) {
|
||||
calls.finish = function() {};
|
||||
return callback(err);
|
||||
}
|
||||
if (--count) return;
|
||||
if (hasKeys(instances)) {
|
||||
callback(null, templates, instances);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
forTemplate(root, fileName, 'import', calls);
|
||||
}
|
||||
|
||||
function forTemplate(root, fileName, get, calls, files, templates, instances, alias, currentNs) {
|
||||
if (currentNs == null) currentNs = '';
|
||||
calls.incr();
|
||||
findPath(root, fileName, '.html', function(path) {
|
||||
var getCount, got, matchesGet, promise;
|
||||
if (path === null) {
|
||||
if (!files) {
|
||||
// Return without doing anything if the path isn't found, and this is the
|
||||
// initial automatic lookup based on the clientName
|
||||
return calls.finish(null, {}, {});
|
||||
} else {
|
||||
return calls.finish(new Error(
|
||||
"Can't find file " + fileName
|
||||
));
|
||||
}
|
||||
}
|
||||
files || (files = {});
|
||||
templates || (templates = {});
|
||||
instances || (instances = {});
|
||||
|
||||
got = false;
|
||||
if (get === 'import') {
|
||||
matchesGet = function() {
|
||||
return got = true;
|
||||
}
|
||||
} else if (Array.isArray(get)) {
|
||||
getCount = get.length;
|
||||
matchesGet = function(name) {
|
||||
--getCount || (got = true);
|
||||
return ~get.indexOf(name);
|
||||
}
|
||||
} else {
|
||||
matchesGet = function(name) {
|
||||
got = true;
|
||||
return get === name;
|
||||
}
|
||||
}
|
||||
|
||||
promise = files[path];
|
||||
if (!promise) {
|
||||
promise = files[path] = new Promise;
|
||||
fs.readFile(path, 'utf8', function(err, file) {
|
||||
promise.resolve(err, file);
|
||||
});
|
||||
}
|
||||
promise.on(function(err, file) {
|
||||
if (err) return calls.finish(err);
|
||||
try {
|
||||
parseTemplateFile(root, dirname(path), path, calls, files, templates, instances, alias, currentNs, matchesGet, file);
|
||||
} catch (err) {
|
||||
if (err.message) {
|
||||
err.message = 'In file ' + path + '\n\n' + err.message;
|
||||
}
|
||||
return calls.finish(err);
|
||||
}
|
||||
if (!got && get !== 'import') {
|
||||
return calls.finish(new Error(
|
||||
"Can't find template '" + get + "' in " + path
|
||||
));
|
||||
}
|
||||
calls.finish(null, templates, instances);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function parseTemplateFile(root, dir, path, calls, files, templates, instances, alias, currentNs, matchesGet, file) {
|
||||
var relativePath = unixRelative(root, path);
|
||||
|
||||
parseHtml(file + '\n', {
|
||||
// Force template tags to be treated as raw tags,
|
||||
// meaning their contents are not parsed as HTML
|
||||
rawTags: /^(?:[^\s=\/!>]+:|style|script)$/i
|
||||
, matchEnd: matchEnd
|
||||
, start: onStart
|
||||
, text: onText
|
||||
});
|
||||
|
||||
function matchEnd(tagName) {
|
||||
if (tagName.slice(-1) === ':') {
|
||||
return /<\/?[^\s=\/!>]+:[\s>]/i;
|
||||
}
|
||||
return new RegExp('</' + tagName, 'i');
|
||||
}
|
||||
|
||||
// These variables pass state from attributes in the start tag to the
|
||||
// following template text
|
||||
var name, attrs;
|
||||
|
||||
function onStart(tag, tagName, _attrs) {
|
||||
var i = tagName.length - 1
|
||||
name = (tagName.charAt(i) === ':' ? tagName.slice(0, i) : '').toLowerCase();
|
||||
attrs = _attrs;
|
||||
for (var key in attrs) {
|
||||
if (attrs[key] === null) attrs[key] = true;
|
||||
}
|
||||
|
||||
if (name === 'import') {
|
||||
parseImport(root, dir, path, calls, files, templates, instances, currentNs, attrs)
|
||||
}
|
||||
}
|
||||
|
||||
function onText(text, isRawText) {
|
||||
if (!matchesGet(name)) return;
|
||||
if (name === 'import') {
|
||||
if (onlyWhitespace(text)) return;
|
||||
return calls.finish(new Error(
|
||||
"Content not allowed after <import:> in" + path + " : " + text
|
||||
));
|
||||
}
|
||||
var templateName = relativePath + ':' + name
|
||||
, instanceName = alias || name
|
||||
if (currentNs) {
|
||||
instanceName = currentNs + ':' + instanceName;
|
||||
}
|
||||
instances[instanceName] = [templateName, attrs];
|
||||
if (templates[templateName]) return;
|
||||
if (!(name && isRawText)) {
|
||||
if (onlyWhitespace(text)) return;
|
||||
return calls.finish(new Error(
|
||||
"Can't read template in " + path + " near the text: " + text
|
||||
));
|
||||
}
|
||||
templates[templateName] = attrs.literal ? text : minifyHtml(text);
|
||||
}
|
||||
}
|
||||
|
||||
function parseImport(root, dir, path, calls, files, templates, instances, currentNs, attrs) {
|
||||
var src = attrs.src
|
||||
, ns = attrs.ns
|
||||
, as = attrs.as
|
||||
, template = attrs.template
|
||||
, toGet = 'import'
|
||||
, srcNs
|
||||
if (!src) {
|
||||
return calls.finish(new Error(
|
||||
"Template import in " + path + " must have a 'src' attribute"
|
||||
));
|
||||
}
|
||||
if (template) {
|
||||
toGet = template.toLowerCase().split(' ');
|
||||
if (toGet.length > 1 && (as != null)) {
|
||||
return calls.finish(new Error(
|
||||
"Template import of '" + src + "' in " + path +
|
||||
" can't specify multiple 'template' values with 'as'"
|
||||
));
|
||||
}
|
||||
}
|
||||
if ('ns' in attrs) {
|
||||
if (as) {
|
||||
return calls.finish(new Error(
|
||||
"Template import of '" + src + "' in " + path +
|
||||
" can't specifiy both 'ns' and 'as' attributes"
|
||||
));
|
||||
}
|
||||
// Import into the namespace specified via 'ns' underneath
|
||||
// the current namespace
|
||||
ns = ns
|
||||
? currentNs ? currentNs + ':' + ns : ns
|
||||
: currentNs;
|
||||
} else if (as) {
|
||||
// If 'as' is specified, import into the current namespace
|
||||
ns = currentNs;
|
||||
} else {
|
||||
// If no namespace is specified, use the src file name
|
||||
// as the default namespace
|
||||
i = src.lastIndexOf('/');
|
||||
srcNs = i ? src.slice(i + 1) : src;
|
||||
ns = currentNs ? currentNs + ':' + srcNs : srcNs;
|
||||
}
|
||||
ns = ns.toLowerCase();
|
||||
|
||||
forTemplate(root, join(dir, src), toGet, calls, files, templates, instances, as, ns);
|
||||
}
|
||||
|
||||
function onlyWhitespace(text) {
|
||||
// Minify removes HTML comments & linebreaks
|
||||
return /^\s*$/.test(minifyHtml(text))
|
||||
}
|
||||
|
||||
// TODO: These should be set as configuration options
|
||||
var extensions = {
|
||||
html: /\.html$/i
|
||||
, css: /\.styl$|\.css|\.less$/i
|
||||
, js: /\.js$/i
|
||||
};
|
||||
|
||||
var ignoreDirectories = ['node_modules', '.git', 'gen'];
|
||||
|
||||
function ignored(path) {
|
||||
return ignoreDirectories.indexOf(path) === -1;
|
||||
}
|
||||
|
||||
function files(dir, extension, out) {
|
||||
if (out == null) out = [];
|
||||
fs.readdirSync(dir).filter(ignored).forEach(function(p) {
|
||||
p = join(dir, p);
|
||||
if (fs.statSync(p).isDirectory()) {
|
||||
files(p, extension, out);
|
||||
} else if (extension.test(p)) {
|
||||
out.push(p);
|
||||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
178
mongoui/mongoui-master/node_modules/derby/lib/markup.js
generated
vendored
Normal file
178
mongoui/mongoui-master/node_modules/derby/lib/markup.js
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
var eventBinding = require('./eventBinding')
|
||||
, splitEvents = eventBinding.splitEvents
|
||||
, containsEvent = eventBinding.containsEvent
|
||||
, addDomEvent = eventBinding.addDomEvent
|
||||
, TEXT_EVENTS = 'keyup,keydown,paste/0,dragover/0,blur'
|
||||
, AUTOCOMPLETE_OFF = {
|
||||
checkbox: true
|
||||
, radio: true
|
||||
}
|
||||
, onBindA, onBindForm;
|
||||
|
||||
module.exports = {
|
||||
bound: {
|
||||
'value': {
|
||||
'input': function(events, attrs, match) {
|
||||
var type = attrs.type
|
||||
, eventNames, method;
|
||||
if (type === 'radio' || type === 'checkbox') return;
|
||||
if (type === 'range' || 'x-blur' in attrs) {
|
||||
// Only update after the element loses focus
|
||||
delete attrs['x-blur'];
|
||||
eventNames = 'change,blur';
|
||||
} else {
|
||||
// By default, update as the user types
|
||||
eventNames = TEXT_EVENTS;
|
||||
}
|
||||
if ('x-ignore-focus' in attrs) {
|
||||
// Update value regardless of focus
|
||||
delete attrs['x-ignore-focus'];
|
||||
method = 'prop';
|
||||
} else {
|
||||
// Update value unless window and element are focused
|
||||
method = 'propPolite';
|
||||
}
|
||||
addDomEvent(events, attrs, eventNames, match, {
|
||||
method: 'prop'
|
||||
, property: 'value'
|
||||
});
|
||||
return {method: method};
|
||||
}
|
||||
}
|
||||
|
||||
, 'checked': {
|
||||
'*': function(events, attrs, match) {
|
||||
addDomEvent(events, attrs, 'change', match, {
|
||||
method: 'prop'
|
||||
, property: 'checked'
|
||||
});
|
||||
return {method: 'prop'};
|
||||
}
|
||||
}
|
||||
|
||||
, 'selected': {
|
||||
'*': function(events, attrs, match) {
|
||||
addDomEvent(events, attrs, 'change', match, {
|
||||
method: 'prop'
|
||||
, property: 'selected'
|
||||
});
|
||||
return {method: 'prop'};
|
||||
}
|
||||
}
|
||||
|
||||
, 'disabled': {
|
||||
'*': function() {
|
||||
return {method: 'prop'};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
, boundParent: {
|
||||
'contenteditable': {
|
||||
'*': function(events, attrs, match) {
|
||||
addDomEvent(events, attrs, TEXT_EVENTS, match, {
|
||||
method: 'html'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
, '*': {
|
||||
'textarea': function(events, attrs, match) {
|
||||
addDomEvent(events, attrs, TEXT_EVENTS, match, {
|
||||
method: 'prop'
|
||||
, property: 'value'
|
||||
});
|
||||
return {method: 'prop', property: 'value'};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
, element: {
|
||||
'select': function(events, attrs) {
|
||||
// Distribute change event to child nodes of select elements
|
||||
addDomEvent(events, attrs, 'change:$forChildren');
|
||||
return {addId: true};
|
||||
}
|
||||
|
||||
, 'input': function(events, attrs) {
|
||||
if (AUTOCOMPLETE_OFF[attrs.type] && !('autocomplete' in attrs)) {
|
||||
attrs.autocomplete = 'off';
|
||||
}
|
||||
if (attrs.type === 'radio') {
|
||||
// Distribute change events to other elements with the same name
|
||||
addDomEvent(events, attrs, 'change:$forName');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
, attr: {
|
||||
'x-bind': {
|
||||
'*': function(events, attrs, eventNames) {
|
||||
addDomEvent(events, attrs, eventNames);
|
||||
return {addId: true, del: true};
|
||||
}
|
||||
|
||||
, 'a': onBindA = function(events, attrs, eventNames) {
|
||||
if (containsEvent(eventNames, ['click', 'focus']) && !('href' in attrs)) {
|
||||
attrs.href = '#';
|
||||
if (!('onclick' in attrs)) {
|
||||
attrs.onclick = 'return false';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
, 'form': onBindForm = function(events, attrs, eventNames) {
|
||||
if (containsEvent(eventNames, 'submit')) {
|
||||
if (!('onsubmit' in attrs)) {
|
||||
attrs.onsubmit = 'return false';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
, 'x-capture': {
|
||||
'*': function(events, attrs, eventNames) {
|
||||
addDomEvent(events, attrs, eventNames, null, {capture: true});
|
||||
return {addId: true, del: true};
|
||||
}
|
||||
, 'a': onBindA
|
||||
, 'form': onBindForm
|
||||
}
|
||||
|
||||
, 'x-as': {
|
||||
'*': function(events, attrs, name) {
|
||||
events.push(function(ctx) {
|
||||
ctx.$elements[name] = attrs._id || attrs.id;
|
||||
});
|
||||
return {addId: true, del: true}
|
||||
}
|
||||
}
|
||||
|
||||
, 'checked': {
|
||||
'*': function() {
|
||||
return {bool: true};
|
||||
}
|
||||
}
|
||||
|
||||
, 'selected': {
|
||||
'*': function() {
|
||||
return {bool: true};
|
||||
}
|
||||
}
|
||||
|
||||
, 'disabled': {
|
||||
'*': function() {
|
||||
return {bool: true};
|
||||
}
|
||||
}
|
||||
|
||||
, 'autofocus': {
|
||||
'*': function() {
|
||||
return {bool: true};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
, TEXT_EVENTS: TEXT_EVENTS
|
||||
, AUTOCOMPLETE_OFF: AUTOCOMPLETE_OFF
|
||||
};
|
||||
63
mongoui/mongoui-master/node_modules/derby/lib/refresh.js
generated
vendored
Normal file
63
mongoui/mongoui-master/node_modules/derby/lib/refresh.js
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
var escapeHtml = require('html-util').escapeHtml
|
||||
, errors = {};
|
||||
|
||||
exports.errorHtml = errorHtml;
|
||||
exports.autoRefresh = autoRefresh;
|
||||
|
||||
function errorHtml(errors) {
|
||||
var text = ''
|
||||
, type, err;
|
||||
for (type in errors) {
|
||||
err = errors[type];
|
||||
text += '<h3>' + escapeHtml(type) + ' Error</h3><pre>' + escapeHtml(err) + '</pre>';
|
||||
}
|
||||
if (!text) return;
|
||||
return '<div id=$_derbyError style="position:absolute;background:rgba(0,0,0,.7);top:0;left:0;right:0;bottom:0;text-align:center">' +
|
||||
'<div style="background:#fff;padding:20px 40px;margin:60px;display:inline-block;text-align:left">' +
|
||||
text + '</div></div>';
|
||||
}
|
||||
|
||||
function autoRefresh(view, model) {
|
||||
var socket = model.socket;
|
||||
|
||||
socket.on('refreshCss', function(err, css) {
|
||||
var el = document.getElementById('$_css');
|
||||
if (el) el.innerHTML = css;
|
||||
updateError('CSS', err);
|
||||
});
|
||||
|
||||
socket.on('refreshHtml', function(err, templates, instances, libraryData) {
|
||||
view._makeAll(templates, instances);
|
||||
view._makeComponents(libraryData);
|
||||
try {
|
||||
view.app.dom._preventUpdates = true;
|
||||
view.app.history.refresh();
|
||||
} catch (_err) {
|
||||
err || (err = _err.stack);
|
||||
}
|
||||
updateError('Template', err);
|
||||
});
|
||||
}
|
||||
|
||||
function updateError(type, err) {
|
||||
if (err) {
|
||||
errors[type] = err;
|
||||
} else {
|
||||
delete errors[type];
|
||||
}
|
||||
var el = document.getElementById('$_derbyError')
|
||||
, html = errorHtml(errors)
|
||||
, fragment, range;
|
||||
if (html) {
|
||||
if (el) {
|
||||
el.outerHTML = html;
|
||||
} else {
|
||||
range = document.createRange();
|
||||
range.selectNode(document.body);
|
||||
fragment = range.createContextualFragment(html);
|
||||
document.body.appendChild(fragment);
|
||||
}
|
||||
} else {
|
||||
if (el) el.parentNode.removeChild(el);
|
||||
}
|
||||
}
|
||||
106
mongoui/mongoui-master/node_modules/derby/lib/refresh.server.js
generated
vendored
Normal file
106
mongoui/mongoui-master/node_modules/derby/lib/refresh.server.js
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
var files = require('./files')
|
||||
, refresh = module.exports = require('./refresh');
|
||||
|
||||
refresh.cssError = cssError;
|
||||
refresh.templateError = templateError;
|
||||
refresh.autoRefresh = autoRefresh;
|
||||
|
||||
function cssError(err) {
|
||||
if (err.stack) {
|
||||
console.error('\nCSS PARSE ERROR\n' + err.stack);
|
||||
return err.stack;
|
||||
} else {
|
||||
console.error('\nCSS PARSE ERROR\n' + err.message + '\n' + err.filename);
|
||||
return err.message + '\n' + err.filename;
|
||||
}
|
||||
}
|
||||
|
||||
function templateError(err) {
|
||||
console.error('\nTEMPLATE ERROR\n' + err.stack);
|
||||
return err.stack;
|
||||
}
|
||||
|
||||
function autoRefresh(store, view, isProduction) {
|
||||
if (!store.sockets) {
|
||||
store.once('setSockets', function() {
|
||||
autoRefresh(store, view, isProduction);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var views = store._derbyRefreshViews || (store._derbyRefreshViews = [])
|
||||
if (views.indexOf(view) !== -1) return;
|
||||
views.push(view);
|
||||
|
||||
setupStore(store, views, isProduction);
|
||||
}
|
||||
|
||||
function setupStore(store, views, isProduction) {
|
||||
if (store._derbyRefreshIsSetup) return;
|
||||
store._derbyRefreshIsSetup = true;
|
||||
|
||||
var listeners = {};
|
||||
|
||||
store.sockets.on('connection', function(socket) {
|
||||
socket.on('derbyClient', function(appHash, callback) {
|
||||
var reload = true
|
||||
, view, i, appFilename, sockets;
|
||||
for (i = views.length; i--;) {
|
||||
view = views[i];
|
||||
if (view._appHash === appHash) {
|
||||
reload = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
callback(reload);
|
||||
if (isProduction || reload || !process.send) return;
|
||||
|
||||
appFilename = view._appFilename;
|
||||
if (listeners[appFilename]) {
|
||||
return listeners[appFilename].push(socket);
|
||||
}
|
||||
|
||||
sockets = listeners[appFilename] = [socket];
|
||||
var parsed = files.parseName(appFilename)
|
||||
, root = parsed.root
|
||||
, rootLen = root.length
|
||||
, clientName = parsed.clientName;
|
||||
addWatches(root, root, clientName, sockets, view);
|
||||
view._libraries.forEach(function(library) {
|
||||
var watchRoot = library.root
|
||||
, pre = watchRoot.slice(0, rootLen)
|
||||
, post = watchRoot.slice(rootLen)
|
||||
// If the compoent is within the root directory and not under a
|
||||
// node_modules directory, it's files will be watched already
|
||||
if (pre === root && post.indexOf('/node_modules/') === -1) return;
|
||||
addWatches(library.root, root, clientName, sockets, view);
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addWatches(watchRoot, root, clientName, sockets, view) {
|
||||
files.watch(watchRoot, 'css', function() {
|
||||
view._loadStyles(root, clientName, function(err, css) {
|
||||
var errText;
|
||||
if (err) errText = cssError(err);
|
||||
for (var i = sockets.length; i--;) {
|
||||
sockets[i].emit('refreshCss', errText, css);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
files.watch(watchRoot, 'html', function() {
|
||||
view._loadTemplates(root, clientName, function(err, templates, instances, libraryData) {
|
||||
var errText;
|
||||
if (err) errText = templateError(err);
|
||||
for (var i = sockets.length; i--;) {
|
||||
sockets[i].emit('refreshHtml', errText, templates, instances, libraryData);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
files.watch(watchRoot, 'js', function() {
|
||||
process.send({type: 'reload'});
|
||||
});
|
||||
}
|
||||
378
mongoui/mongoui-master/node_modules/derby/lib/viewPath.js
generated
vendored
Normal file
378
mongoui/mongoui-master/node_modules/derby/lib/viewPath.js
generated
vendored
Normal file
@@ -0,0 +1,378 @@
|
||||
var lookup = require('racer/lib/path').lookup
|
||||
, trimLeading = require('html-util').trimLeading;
|
||||
|
||||
exports.wrapRemainder = wrapRemainder;
|
||||
exports.extractPlaceholder = extractPlaceholder;
|
||||
exports.pathFnArgs = pathFnArgs;
|
||||
exports.ctxPath = ctxPath;
|
||||
exports.getValue = getValue;
|
||||
exports.dataValue = dataValue;
|
||||
exports.setBoundFn = setBoundFn;
|
||||
exports.patchCtx = patchCtx;
|
||||
|
||||
function wrapRemainder(tagName, remainder) {
|
||||
if (!remainder) return false;
|
||||
return !(new RegExp('^<\/' + tagName, 'i')).test(remainder);
|
||||
}
|
||||
|
||||
var openPlaceholder = /^([\s\S]*?)(\{{1,3})\s*([\s\S]*)/
|
||||
, aliasContent = /^([\s\S]*)\s+as\s+:(\S+)\s*$/
|
||||
, blockContent = /^([\#\/]?)(else\sif|if|else|unless|each|with|unescaped)?\s*([\s\S]*?)\s*$/
|
||||
, closeMap = { 1: '}', 2: '}}' }
|
||||
function extractPlaceholder(text) {
|
||||
var match = openPlaceholder.exec(text);
|
||||
if (!match) return;
|
||||
var pre = match[1]
|
||||
, open = match[2]
|
||||
, remainder = match[3]
|
||||
, openLen = open.length
|
||||
, bound = openLen === 1
|
||||
, end = matchBraces(remainder, openLen, 0, '{', '}')
|
||||
, endInner = end - openLen
|
||||
, inner = remainder.slice(0, endInner)
|
||||
, post = remainder.slice(end)
|
||||
, alias, hash, type, name, escaped;
|
||||
|
||||
if (/["{[]/.test(inner)) {
|
||||
// Make sure that we didn't accidentally match a JSON literal
|
||||
try {
|
||||
JSON.parse(open + inner + closeMap[openLen]);
|
||||
return;
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
match = aliasContent.exec(inner);
|
||||
if (match) {
|
||||
inner = match[1];
|
||||
alias = match[2];
|
||||
}
|
||||
|
||||
match = blockContent.exec(inner)
|
||||
if (!match) return;
|
||||
hash = match[1];
|
||||
type = match[2];
|
||||
name = match[3];
|
||||
|
||||
escaped = true;
|
||||
if (type === 'unescaped') {
|
||||
escaped = false;
|
||||
type = '';
|
||||
}
|
||||
if (bound) name = name.replace(/\bthis\b/, '.');
|
||||
return {
|
||||
pre: pre
|
||||
, post: post
|
||||
, bound: bound
|
||||
, alias: alias
|
||||
, hash: hash
|
||||
, type: type
|
||||
, name: name
|
||||
, escaped: escaped
|
||||
, source: text
|
||||
};
|
||||
}
|
||||
|
||||
function matchBraces(text, num, i, openChar, closeChar) {
|
||||
var close, hasClose, hasOpen, open;
|
||||
i++;
|
||||
while (num) {
|
||||
close = text.indexOf(closeChar, i);
|
||||
open = text.indexOf(openChar, i);
|
||||
hasClose = ~close;
|
||||
hasOpen = ~open;
|
||||
if (hasClose && (!hasOpen || (close < open))) {
|
||||
i = close + 1;
|
||||
num--;
|
||||
continue;
|
||||
} else if (hasOpen) {
|
||||
i = open + 1;
|
||||
num++;
|
||||
continue;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
var fnCall = /^([^(]+)\s*\(\s*([\s\S]*?)\s*\)\s*$/
|
||||
, argSeparator = /\s*([,(])\s*/g
|
||||
, notSeparator = /[^,\s]/g
|
||||
, notPathArg = /(?:^['"\d\-[{])|(?:^null$)|(?:^true$)|(?:^false$)/;
|
||||
|
||||
function fnArgs(inner) {
|
||||
var args = []
|
||||
, lastIndex = 0
|
||||
, match, end, last;
|
||||
while (match = argSeparator.exec(inner)) {
|
||||
if (match[1] === '(') {
|
||||
end = matchBraces(inner, 1, argSeparator.lastIndex, '(', ')');
|
||||
args.push(inner.slice(lastIndex, end));
|
||||
notSeparator.lastIndex = end;
|
||||
lastIndex = argSeparator.lastIndex =
|
||||
notSeparator.test(inner) ? notSeparator.lastIndex - 1 : end;
|
||||
continue;
|
||||
}
|
||||
args.push(inner.slice(lastIndex, match.index));
|
||||
lastIndex = argSeparator.lastIndex;
|
||||
}
|
||||
last = inner.slice(lastIndex);
|
||||
if (last) args.push(last);
|
||||
return args;
|
||||
}
|
||||
|
||||
function fnCallError(name) {
|
||||
throw new Error('malformed view function call: ' + name);
|
||||
}
|
||||
|
||||
function fnArgValue(view, ctx, model, name, arg) {
|
||||
var literal = literalValue(arg)
|
||||
, argIds, path, pathId;
|
||||
if (literal === undefined) {
|
||||
argIds = ctx.hasOwnProperty('$fnArgIds') ?
|
||||
ctx.$fnArgIds : (ctx.$fnArgIds = {});
|
||||
if (pathId = argIds[arg]) {
|
||||
path = model.__pathMap.paths[pathId];
|
||||
} else {
|
||||
path = ctxPath(view, ctx, arg);
|
||||
argIds[arg] = model.__pathMap.id(path);
|
||||
}
|
||||
return dataValue(view, ctx, model, path);
|
||||
}
|
||||
return literal;
|
||||
}
|
||||
|
||||
function fnValue(view, ctx, model, name) {
|
||||
var match = fnCall.exec(name) || fnCallError(name)
|
||||
, fnName = match[1]
|
||||
, args = fnArgs(match[2])
|
||||
, fn, fnName, i;
|
||||
for (i = args.length; i--;) {
|
||||
args[i] = fnArgValue(view, ctx, model, name, args[i]);
|
||||
}
|
||||
if (!(fn = view.getFns[fnName])) {
|
||||
throw new Error('view function "' + fnName + '" not found for call: ' + name);
|
||||
}
|
||||
return fn.apply({view: view, ctx: ctx, model: model}, args);
|
||||
}
|
||||
|
||||
function pathFnArgs(name, paths) {
|
||||
var match = fnCall.exec(name) || fnCallError(name)
|
||||
, args = fnArgs(match[2])
|
||||
, i, arg;
|
||||
if (paths == null) paths = [];
|
||||
for (i = args.length; i--;) {
|
||||
arg = args[i];
|
||||
if (notPathArg.test(arg)) continue;
|
||||
if (~arg.indexOf('(')) {
|
||||
pathFnArgs(arg, paths);
|
||||
continue;
|
||||
}
|
||||
paths.push(arg);
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
var indexPlaceholder = /\$#/g;
|
||||
|
||||
function relativePath(ctx, i, remainder, noReplace) {
|
||||
var meta = ctx.$paths[i - 1] || []
|
||||
, base = meta[0]
|
||||
, name = base + remainder
|
||||
, offset, indices, index, placeholders
|
||||
|
||||
// Replace `$#` segments in a path with the proper indicies
|
||||
if (!noReplace && (placeholders = name.match(indexPlaceholder))) {
|
||||
indices = ctx.$indices;
|
||||
index = placeholders.length + indices.length - meta[1] - 1;
|
||||
name = name.replace(indexPlaceholder, function() {
|
||||
return indices[--index];
|
||||
});
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
function macroName(view, ctx, name) {
|
||||
if (name.charAt(0) !== '@') return;
|
||||
|
||||
var macroCtx = ctx.$macroCtx
|
||||
, segments = name.slice(1).split('.')
|
||||
, base = segments.shift().toLowerCase()
|
||||
, remainder = segments.join('.')
|
||||
, value = lookup(base, macroCtx)
|
||||
, matchName = value && value.$matchName
|
||||
if (matchName) {
|
||||
if (!remainder) return value;
|
||||
return {$matchName: matchName + '.' + remainder};
|
||||
}
|
||||
return remainder ? base + '.' + remainder : base;
|
||||
}
|
||||
|
||||
function ctxPath(view, ctx, name, noReplace) {
|
||||
var macroPath = macroName(view, ctx, name);
|
||||
if (macroPath && macroPath.$matchName) name = macroPath.$matchName;
|
||||
|
||||
var firstChar = name.charAt(0)
|
||||
, i, aliasName, remainder
|
||||
|
||||
// Resolve path aliases
|
||||
if (firstChar === ':') {
|
||||
if (~(i = name.search(/[.[]/))) {
|
||||
aliasName = name.slice(1, i);
|
||||
remainder = name.slice(i);
|
||||
} else {
|
||||
aliasName = name.slice(1);
|
||||
remainder = '';
|
||||
}
|
||||
i = ctx.$paths.length - ctx.$aliases[aliasName];
|
||||
if (i !== i) throw new Error('Cannot find alias for ' + aliasName);
|
||||
|
||||
name = relativePath(ctx, i, remainder, noReplace);
|
||||
|
||||
// Resolve relative paths
|
||||
} else if (firstChar === '.') {
|
||||
i = 0;
|
||||
while (name.charAt(i) === '.') {
|
||||
i++;
|
||||
}
|
||||
remainder = i === name.length ? '' : name.slice(i - 1);
|
||||
|
||||
name = relativePath(ctx, i, remainder, noReplace);
|
||||
}
|
||||
|
||||
// Perform path interpolation
|
||||
// TODO: This should nest properly and currently is only one level deep
|
||||
// TODO: This should also set up bindings
|
||||
return name.replace(/\[([^\]]+)\]/g, function(match, property, offset) {
|
||||
var segment = getValue(view, ctx, view.model, property);
|
||||
if (offset === 0 || name.charAt(offset - 1) === '.') return segment;
|
||||
return '.' + segment;
|
||||
});
|
||||
}
|
||||
|
||||
function escapeValue(value, escape) {
|
||||
return escape ? escape(value) : value;
|
||||
}
|
||||
|
||||
function literalValue(value) {
|
||||
if (value === 'null') return null;
|
||||
if (value === 'true') return true;
|
||||
if (value === 'false') return false;
|
||||
var firstChar = value.charAt(0)
|
||||
, match;
|
||||
if (firstChar === "'") {
|
||||
match = /^'(.*)'$/.exec(value) || fnCallError(value);
|
||||
return match[1];
|
||||
}
|
||||
if (firstChar === '"') {
|
||||
match = /^"(.*)"$/.exec(value) || fnCallError(value);
|
||||
return match[1];
|
||||
}
|
||||
if (/^[\d\-]/.test(firstChar) && !isNaN(value)) {
|
||||
return +value;
|
||||
}
|
||||
if (firstChar === '[' || firstChar === '{') {
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch (e) {}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getValue(view, ctx, model, name, escape, forceEscape) {
|
||||
var literal = literalValue(name)
|
||||
if (literal === undefined) {
|
||||
return dataValue(view, ctx, model, name, escape, forceEscape);
|
||||
}
|
||||
return literal;
|
||||
}
|
||||
|
||||
function dataValue(view, ctx, model, name, escape, forceEscape) {
|
||||
var macroPath, path, value;
|
||||
if (~name.indexOf('(')) {
|
||||
value = fnValue(view, ctx, model, name);
|
||||
return escapeValue(value, escape);
|
||||
}
|
||||
path = ctxPath(view, ctx, name);
|
||||
macroPath = macroName(view, ctx, path);
|
||||
if (macroPath) {
|
||||
if (macroPath.$matchName) {
|
||||
path = macroPath.$matchName;
|
||||
} else {
|
||||
value = lookup(macroPath, ctx.$macroCtx);
|
||||
if (typeof value === 'function') {
|
||||
if (value.unescaped && !forceEscape) return value(ctx, model);
|
||||
value = value(ctx, model);
|
||||
}
|
||||
return escapeValue(value, escape);
|
||||
}
|
||||
}
|
||||
value = lookup(path, ctx);
|
||||
if (value !== void 0) return escapeValue(value, escape);
|
||||
value = model.get(path);
|
||||
value = value !== void 0 ? value : model[path];
|
||||
return escapeValue(value, escape);
|
||||
}
|
||||
|
||||
function setBoundFn(view, ctx, model, name, value) {
|
||||
var match = fnCall.exec(name) || fnCallError(name)
|
||||
, fnName = match[1]
|
||||
, args = fnArgs(match[2])
|
||||
, get = view.getFns[fnName]
|
||||
, set = view.setFns[fnName]
|
||||
, numInputs = set && set.length - 1
|
||||
, arg, i, inputs, out, key, path, len;
|
||||
|
||||
if (!(get && set)) {
|
||||
throw new Error('view function "' + fnName + '" setter not found for binding to: ' + name);
|
||||
}
|
||||
|
||||
if (numInputs) {
|
||||
inputs = [value];
|
||||
i = 0;
|
||||
while (i < numInputs) {
|
||||
inputs.push(fnArgValue(view, ctx, model, name, args[i++]));
|
||||
}
|
||||
out = set.apply(null, inputs);
|
||||
} else {
|
||||
out = set(value);
|
||||
}
|
||||
if (!out) return;
|
||||
|
||||
for (key in out) {
|
||||
value = out[key];
|
||||
arg = args[key];
|
||||
if (~arg.indexOf('(')) {
|
||||
setBoundFn(view, ctx, model, arg, value);
|
||||
continue;
|
||||
}
|
||||
if (value === void 0 || notPathArg.test(arg)) continue;
|
||||
path = ctxPath(view, ctx, arg);
|
||||
if (model.get(path) === value) continue;
|
||||
model.set(path, value);
|
||||
}
|
||||
}
|
||||
|
||||
function patchCtx(ctx, triggerPath) {
|
||||
var meta, path;
|
||||
if (!(triggerPath && (meta = ctx.$paths[0]) && (path = meta[0]))) return;
|
||||
|
||||
var segments = path.split('.')
|
||||
, triggerSegments = triggerPath.replace(/\*$/, '').split('.')
|
||||
, indices = ctx.$indices.slice()
|
||||
, index = indices.length
|
||||
, i, len, segment, triggerSegment, n;
|
||||
for (i = 0, len = segments.length; i < len; i++) {
|
||||
segment = segments[i];
|
||||
triggerSegment = triggerSegments[i];
|
||||
// `(n = +triggerSegment) === n` will be false only if segment is NaN
|
||||
if (segment === '$#' && (n = +triggerSegment) === n) {
|
||||
indices[--index] = n;
|
||||
} else if (segment !== triggerSegment) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ctx.$indices = indices;
|
||||
ctx.$index = indices[0];
|
||||
}
|
||||
Reference in New Issue
Block a user