UNPKG

mojito

Version:

Mojito provides an architecture, components and tools for developers to build complex web applications faster.

208 lines (178 loc) 6.34 kB
/* * Copyright (c) 2011-2013, Yahoo! Inc. All rights reserved. * Copyrights licensed under the New BSD License. * See the accompanying LICENSE file for terms. */ /*jslint anon:true, nomen:true, browser:true, plusplus:true*/ /*global YUI*/ YUI.add('mojito-output-handler', function(Y, NAME) { 'use strict'; var attachAssets, complete, loaded = { js: {}, css: {} }; // Attach assets found in the "assets" to the page attachAssets = function(assets, cb) { var toLoad = { css: [], js: [] }, done = {}, blobNode, doneChecker, executeInlinedScripts; // Any scripts contain in assets.blob must be created using document.createElment('script'), // and then replaced, otherwise the scripts never get executed. executeInlinedScripts = function (node) { var i, child, script; if (node.tagName === 'SCRIPT') { script = document.createElement('script'); script.text = node.text; for (i = 0; i < node.attributes.length; i++) { if (node.attributes[i].specified) { script[node.attributes[i].name] = node.attributes[i].value; } } node.parentNode.replaceChild(script, node); return; } for (i = 0; i < node.children.length; i++) { child = node.children[i]; executeInlinedScripts(child); } }; Y.Object.each(assets, function(types, location) { Y.Object.each(types, function(list, type) { var i; if (type === 'blob') { for (i = 0; i < list.length; i += 1) { blobNode = Y.Node.create(list[i]); if (blobNode) { Y.one('head').append(blobNode); // Ensure that inlined script get executed. executeInlinedScripts(blobNode._node); } } } else { for (i = 0; i < list.length; i += 1) { if (!loaded[type][list[i]]) { toLoad[type].push(list[i]); } loaded[type][list[i]] = true; } } }); }); doneChecker = function(type) { if (type) { done[type] = true; } if (done.css && done.js) { cb(); } }; if (toLoad.css.length > 0) { // TODO: better error detection/handling. Y.Get.css(toLoad.css, { onEnd: function() { doneChecker('css'); } }); } else { done.css = true; } if (toLoad.js.length > 0) { // TODO: better error detection/handling. Y.Get.script(toLoad.js, { onEnd: function() { doneChecker('js'); } }); } else { done.js = true; } // in case we have neither (or either Y.Get calls return really fast) doneChecker(); }; /* * Handles final processing for done(). * @method complete * @param {string} data The data to pass to the callback. Usually markup or * JSON. * @param {Object} meta The meta object from the dispatch() call. * @param {MojitoClient} client The client instance. * @param {string} viewId An optional view ID for the mojit. * @param {Function} callback The callback function to invoke. */ complete = function(data, meta, client, viewId, callback) { // If we get some JSON decode it if (meta && meta.http && meta.http.headers['content-type'] && meta.http.headers['content-type'][0].indexOf( 'application/json' ) === 0) { data = Y.JSON.parse(data); } callback(null, data, meta); if (meta && meta.binders) { // DOM needs to render and return to main event loop before // attaching. window.setTimeout(function() { client.attachBinders(meta.binders, viewId, meta.view.id); }); } }; /* * This is an object used as the single pathway for data to leave a mojit * action execution. It is used as a component of the ActionContext object, * which uses it to call <em>done</em> and <em>flush</em> in order to * complete. * * There are two versions of this object, one for the client, and one for * the server. This is the client version, which is much simpler than the * server version. * * @class OutputHandler * @constructor * @param {String} viewId The view id of the current mojit binder * responsible for this action execution * @param {Function} cb * @param {Object} mojitoClient */ function OutputHandler(viewId, cb, mojitoClient) { this.viewId = viewId; this.callback = cb; this.buffer = ''; this.mojitoClient = mojitoClient; this.page = mojitoClient.page; } OutputHandler.prototype = { flush: function(data, meta) { this.done(data, meta); }, done: function(data, meta) { var client = this.mojitoClient, viewId = this.viewId, callback = this.callback; // Add meta to the page before going on if (meta && meta.assets) { attachAssets(meta.assets, function() { complete(data, meta, client, viewId, callback); }); } else { complete(data, meta, client, viewId, callback); } }, error: function(err) { this.callback(err); } }; Y.namespace('mojito').OutputHandler = OutputHandler; }, '0.1.0', {requires: [ 'mojito', 'json-parse', 'node' ]});