1
0
mirror of https://github.com/mgerb/mywebsite synced 2026-01-12 18:52:50 +00:00
Files
mywebsite/mongoui/mongoui-master/node_modules/derby/lib/derby.browser.js
2015-06-25 16:28:41 -05:00

190 lines
5.3 KiB
JavaScript

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