mirror of
https://github.com/sstent/node.git
synced 2026-01-27 15:41:43 +00:00
updated app
This commit is contained in:
322
first-project/node_modules/derby/lib/View.server.js
generated
vendored
Normal file
322
first-project/node_modules/derby/lib/View.server.js
generated
vendored
Normal file
@@ -0,0 +1,322 @@
|
||||
var EventDispatcher = require('./EventDispatcher')
|
||||
, racer = require('racer')
|
||||
, Promise = racer.util.Promise
|
||||
, isProduction = racer.util.isProduction
|
||||
, merge = racer.util.merge
|
||||
, finishAfter = racer.util.async.finishAfter
|
||||
, Model = racer["protected"].Model
|
||||
, uglify = require('racer/node_modules/uglify-js')
|
||||
, files = require('./files')
|
||||
, htmlUtil = require('html-util')
|
||||
, escapeHtml = htmlUtil.escapeHtml
|
||||
, trimLeading = htmlUtil.trimLeading
|
||||
, refresh = require('./refresh.server')
|
||||
, errorHtml = refresh.errorHtml
|
||||
, cssError = refresh.cssError
|
||||
, templateError = refresh.templateError
|
||||
, View = module.exports = require('./View')
|
||||
, 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, '<\\/');
|
||||
}
|
||||
|
||||
function loadTemplatesScript(requirePath, templates, instances, libraryData) {
|
||||
return '(function() {\n' +
|
||||
'var view = require("' + requirePath + '").view;\n' +
|
||||
'view._makeAll(\n' +
|
||||
JSON.stringify(templates, null, 2) + ', ' +
|
||||
JSON.stringify(instances, null, 2) + ');\n' +
|
||||
'view._makeComponents(\n' +
|
||||
JSON.stringify(libraryData, null, 2) + ');\n' +
|
||||
'})();';
|
||||
}
|
||||
|
||||
View.prototype.isServer = true;
|
||||
|
||||
View.prototype.inline = function(fn) {
|
||||
return this._inline += uglify("(" + fn + ")()") + ';';
|
||||
};
|
||||
|
||||
View.prototype._load = function(isStatic, callback) {
|
||||
var view = this
|
||||
, appFilename, clientName, count, errors, finish, js, options
|
||||
, promise, requirePath, root, libraries, fileInfo, loadTemplates;
|
||||
|
||||
if (isProduction) {
|
||||
this._watch = false;
|
||||
this._load = function(isStatic, callback) {
|
||||
callback();
|
||||
};
|
||||
} else {
|
||||
this._watch = true;
|
||||
}
|
||||
|
||||
// Use a promise to avoid simultaneously loading multiple times
|
||||
if (promise = this._loadPromise) {
|
||||
return promise.on(callback);
|
||||
}
|
||||
promise = this._loadPromise = (new Promise).on(callback);
|
||||
|
||||
// Once loading is complete, make the files reload from disk the next time
|
||||
promise.on(function() {
|
||||
delete view._loadPromise;
|
||||
});
|
||||
|
||||
errors = {};
|
||||
|
||||
if (isStatic) {
|
||||
root = this._root;
|
||||
clientName = this._clientName;
|
||||
count = 2;
|
||||
finish = function() {
|
||||
if (--count) return;
|
||||
promise.resolve();
|
||||
};
|
||||
|
||||
} else {
|
||||
appFilename = this._appFilename;
|
||||
options = this._derbyOptions || {};
|
||||
fileInfo = files.parseName(appFilename, options);
|
||||
this._root = root = fileInfo.root;
|
||||
this._requirePath = requirePath = fileInfo.require;
|
||||
this._clientName = clientName = fileInfo.clientName;
|
||||
if (!clientName) promise.resolve();
|
||||
|
||||
count = 3;
|
||||
finish = function() {
|
||||
if (--count) return;
|
||||
|
||||
// Templates are appended to the js bundle here so that it does
|
||||
// not have to be regenerated if only the template files are modified
|
||||
if (isProduction) loadTemplates = uglify(loadTemplates);
|
||||
js += ';' + loadTemplates;
|
||||
|
||||
view._errors = errorHtml(errors) || '';
|
||||
|
||||
files.writeJs(root, js, options, function(err, jsFile, appHash) {
|
||||
if (err) throw err;
|
||||
view._jsFile = jsFile;
|
||||
view._appHash = appHash;
|
||||
promise.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
if (this._js) {
|
||||
js = this._js;
|
||||
finish();
|
||||
|
||||
} else {
|
||||
files.js(appFilename, function(err, value, inline) {
|
||||
if (err) throw err;
|
||||
js = value;
|
||||
if (!isProduction) view._js = value;
|
||||
if (inline) view.inline("function(){" + inline + "}");
|
||||
finish();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this._loadCss(root, clientName, function(err, css) {
|
||||
if (err) {
|
||||
css = '<style id=$_css></style>';
|
||||
errors['CSS'] = cssError(err);
|
||||
} else {
|
||||
css = css ? '<style id=$_css>' + css + '</style>' : '';
|
||||
}
|
||||
view._css = css;
|
||||
finish();
|
||||
});
|
||||
|
||||
libraries = this._libraries;
|
||||
this._loadTemplates(root, clientName, function(err, templates, instances, libraryData) {
|
||||
if (err) errors['Template'] = templateError(err);
|
||||
loadTemplates = loadTemplatesScript(requirePath, templates, instances, libraryData);
|
||||
view._makeAll(templates, instances);
|
||||
view._makeComponents(libraryData);
|
||||
finish();
|
||||
});
|
||||
};
|
||||
|
||||
View.prototype._loadCss = function(root, clientName, callback) {
|
||||
files.css(root, clientName, isProduction, function(err, value) {
|
||||
value = isProduction ? trimLeading(value) : '\n' + value;
|
||||
callback(err, value);
|
||||
});
|
||||
};
|
||||
|
||||
View.prototype._loadTemplates = function(root, clientName, callback) {
|
||||
var count = 1
|
||||
, libraries = this._libraries
|
||||
, libraryData = {}
|
||||
, templates, instances, finish, libraryName, library
|
||||
|
||||
for (libraryName in libraries) count++;
|
||||
finish = finishAfter(count, 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);
|
||||
});
|
||||
|
||||
for (libraryName in libraries) {
|
||||
library = libraries[libraryName];
|
||||
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[libraryName] = {
|
||||
templates: libraryTemplates
|
||||
, instances: libraryInstances
|
||||
};
|
||||
finish();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
// Load templates, css, and scripts from files
|
||||
this._load(isStatic, function() {
|
||||
view._render(res, model, ns, ctx, isStatic);
|
||||
});
|
||||
};
|
||||
|
||||
View.prototype._init = function(model) {
|
||||
// Initialize view & model for rendering
|
||||
model.__events = emptyEventDispatcher;
|
||||
model.__blockPaths = {};
|
||||
model.__pathMap = emptyPathMap;
|
||||
this.model = model;
|
||||
this._idCount = 0;
|
||||
var libraries = this._libraries
|
||||
, name
|
||||
for (name in libraries) {
|
||||
libraries[name].view._init(model);
|
||||
}
|
||||
};
|
||||
|
||||
View.prototype._render = function(res, model, ns, ctx, isStatic) {
|
||||
this._init(model);
|
||||
|
||||
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 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)
|
||||
, view = this
|
||||
, body, scripts, tail;
|
||||
|
||||
// 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 + charset + "<title>" + title + "</title>" + head + this._css + header);
|
||||
|
||||
// Remaining HTML
|
||||
body = this.get('body', ns, ctx) + this.get('footer', ns, ctx);
|
||||
if (body.slice(0, 4) === '<!--') {
|
||||
body = '­' + body;
|
||||
}
|
||||
res.write(body);
|
||||
} catch (err) {
|
||||
var errText = templateError(err);
|
||||
if (!this._errors) this._errors = errorHtml({Template: errText});
|
||||
res.write('<!DOCTYPE html><meta charset=utf-8><title></title>' + this._css);
|
||||
}
|
||||
|
||||
tail = this.get('tail', ns, ctx);
|
||||
|
||||
// Wait for transactions to finish and package 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.
|
||||
model.bundle(function(bundle) {
|
||||
view._renderScripts(res, ns, ctx, isStatic, tail, bundle);
|
||||
});
|
||||
};
|
||||
|
||||
View.prototype._renderScripts = function(res, ns, ctx, isStatic, tail, bundle) {
|
||||
var clientName = this._clientName;
|
||||
|
||||
// Inline scripts and external scripts
|
||||
scripts = "<script>";
|
||||
if (!isStatic) {
|
||||
scripts += "function " + clientName + "(){" + clientName + "=1}";
|
||||
}
|
||||
scripts += escapeInlineScript(this._inline) + "</script>" + this.get('scripts', ns, ctx);
|
||||
if (!isStatic) {
|
||||
scripts += "<script defer async onload=" + clientName + "() src=" + this._jsFile + "></script>";
|
||||
}
|
||||
res.write(scripts);
|
||||
|
||||
// Initialization script and Tail
|
||||
if (isStatic) return res.end(tail);
|
||||
|
||||
res.end("<script>(function(){function f(){setTimeout(function(){" + clientName +
|
||||
"=require('" + this._requirePath + "')(" + escapeInlineScript(bundle) + ",'" +
|
||||
this._appHash + "'," + (+this._watch) + ",'" + (ns || '') + "'" +
|
||||
(ctx ? ',' + escapeInlineScript(JSON.stringify(ctx)) : '') + ")},0)}" +
|
||||
clientName + "===1?f():" + clientName + "=f})()</script>" + tail + this._errors);
|
||||
};
|
||||
Reference in New Issue
Block a user