1
0
mirror of https://github.com/mgerb/mywebsite synced 2026-03-06 08:15:25 +00:00

Added files

This commit is contained in:
2015-06-25 16:28:41 -05:00
parent 656dca9289
commit eb27b55a54
5621 changed files with 1630154 additions and 0 deletions

605
mongoui/mongoui-master/node_modules/derby/lib/Dom.js generated vendored Normal file
View 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);
};
}

View 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;
}
}

View 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

File diff suppressed because it is too large Load Diff

View 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
View 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);
};
}

View 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;
}

View 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();
}
}
}

View 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;
}

View 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;
}

View 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
View 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);

View 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);
};

View 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
View 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
View 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
};

View 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);
}
}

View 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'});
});
}

View 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];
}