Skip to content

Instantly share code, notes, and snippets.

@unkillbob
Created September 5, 2013 06:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save unkillbob/6446581 to your computer and use it in GitHub Desktop.
Save unkillbob/6446581 to your computer and use it in GitHub Desktop.
Spike on dynamically loaded nested Y.Apps using the YUI App Framework: http://yuilibrary.com/yui/docs/app/.
YUI.add('inner-app1', function (Y, NAME) {
"use strict";
var CLASS_NAMES = {
pjax: 'spike-pjax'
},
InnerApp1,
_renderLinks,
_renderContent;
_renderLinks = Y.Handlebars.compile(
'<ul class="separated spike-pjax">' +
'{{#each names}}' +
'<li><a href="{{{../baseUrl}}}{{.}}">Greet {{.}}</a></li>' +
'<li><a href="{{{../baseUrl}}}{{.}}/foo">Greet {{.}} and then some</a></li>' +
'{{/each}}' +
'</ul>');
_renderContent = Y.Handlebars.compile(
'<h2>Inner App 1</h2>' +
'<p>' +
'{{#if name}}' +
'Hello {{name}}!' +
'{{else}}' +
'Hi!' +
'{{/if}}' +
'</p>');
InnerApp1 = Y.Base.create('inner-app1', Y.App, [], {
views: {
},
initializer: function() {
},
render: function() {
InnerApp1.superclass.render.apply(this, arguments);
var links = _renderLinks({
baseUrl: this._normalizePath(this.get('root') + '/'),
names: ['James', 'Spock']
});
this.get('container').insertBefore(links, this.get('viewContainer'));
return this;
},
_renderInnerAppContent: function() {
this.get('viewContainer').setHTML(_renderContent({
name: this._activeName
}));
},
_handleInnerAppRoute: function(req) {
this._activeName = req.params.name;
this._renderInnerAppContent();
}
}, {
ATTRS: {
routes: {
value: [{
path: '/',
callbacks: '_handleInnerAppRoute'
}, {
path: '/:name',
callbacks: '_handleInnerAppRoute'
}, {
path: '/:name/*',
callbacks: '_handleInnerAppRoute'
}]
},
linkSelector: {
value: 'a.' + CLASS_NAMES.pjax +', .' + CLASS_NAMES.pjax + ' a'
}
}
});
Y.namespace('SPIKE').InnerApp1 = InnerApp1;
}, '@VERSION@', {"requires": ["app-base", "base", "handlebars"]});
YUI.add('inner-app2', function (Y, NAME) {
"use strict";
var CLASS_NAMES = {
pjax: 'spike-pjax'
},
InnerApp2,
_renderLinks,
_renderContent;
_renderLinks = Y.Handlebars.compile(
'<ul class="separated spike-pjax">' +
'{{#each names}}' +
'<li><a href="{{{../baseUrl}}}{{.}}">Greet {{.}}</a></li>' +
'<li><a href="{{{../baseUrl}}}{{.}}/foo">Greet {{.}} and then some</a></li>' +
'{{/each}}' +
'</ul>');
_renderContent = Y.Handlebars.compile(
'<h2>Inner App 2</h2>' +
'<p>' +
'{{#if name}}' +
'Hello {{name}}!' +
'{{else}}' +
'Hi!' +
'{{/if}}' +
'</p>');
InnerApp2 = Y.Base.create('inner-app2', Y.App, [], {
views: {
},
initializer: function() {
},
render: function() {
InnerApp2.superclass.render.apply(this, arguments);
var links = _renderLinks({
baseUrl: this._normalizePath(this.get('root') + '/'),
names: ['James', 'Spock']
});
this.get('container').insertBefore(links, this.get('viewContainer'));
return this;
},
_renderInnerAppContent: function() {
this.get('viewContainer').setHTML(_renderContent({
name: this._activeName
}));
},
_handleInnerAppRoute: function(req) {
this._activeName = req.params.name;
this._renderInnerAppContent();
}
}, {
ATTRS: {
routes: {
value: [{
path: '/',
callbacks: '_handleInnerAppRoute'
}, {
path: '/:name',
callbacks: '_handleInnerAppRoute'
}, {
path: '/:name/*',
callbacks: '_handleInnerAppRoute'
}]
},
linkSelector: {
value: 'a.' + CLASS_NAMES.pjax +', .' + CLASS_NAMES.pjax + ' a'
}
}
});
Y.namespace('SPIKE').InnerApp2 = InnerApp2;
}, '@VERSION@', {"requires": ["app-base", "base", "handlebars"]});
YUI.add('top-app', function (Y, NAME) {
"use strict";
/*global alert, console*/
var CLASS_NAMES = {
pjax: 'spike-pjax'
},
MOCK_CONFIG = [{
// /app1 => Y.use('inner-app1') => new Y.SPIKE.InnerApp1(...)
contextPath: 'app1',
moduleName: 'inner-app1',
namespace: 'SPIKE',
className: 'InnerApp1'
}, {
// /app2 => use('inner-app2') => new Y.SPIKE.InnerApp2(...)
contextPath: 'app2',
moduleName: 'inner-app2',
namespace: 'SPIKE',
className: 'InnerApp2'
}],
THROBBER_HTML = '<div class="throbber-large"></div>',
TopApp,
_renderMenu;
_renderMenu = Y.Handlebars.compile(
'<ul class="separated spike-pjax">' +
'{{#each menuItems}}' +
'<li><a href="{{{../baseUrl}}}{{path}}">{{label}}</a></li>' +
'<li><a href="{{{../baseUrl}}}{{path}}/Spock">{{label}}: Greet Spock</a></li>' +
'{{/each}}' +
'</ul>');
TopApp = Y.Base.create('top-app', Y.App, [], {
views: {
},
initializer: function() {
var modules,
appConfigByPath = {};
modules = Y.Array.map(MOCK_CONFIG, function(appConfig) {
appConfigByPath[appConfig.contextPath] = appConfig;
return appConfig.moduleName;
});
// Trigger a prefetch the modules for all the sub-apps
Y.use(modules);
this._appConfigByPath = appConfigByPath;
this._menuItems = [{
label: 'App 1',
path: 'app1'
}, {
label: 'App 2',
path: 'app2'
}];
},
render: function() {
var menuHtml;
TopApp.superclass.render.apply(this, arguments);
menuHtml = _renderMenu({
menuItems: this._menuItems,
baseUrl: this._normalizePath(this.get('root') + '/')
});
this.get('container').insertBefore(menuHtml, this.get('viewContainer'));
this._renderWelcomeScreen();
return this;
},
_showNestedApp: function(req) {
var appPath = req.params.appPath;
if (appPath) {
if (this._activeAppPath === appPath) {
console.log('App with path "' + appPath + '" already active, doing nothing.');
return;
}
if (!this._appConfigByPath[appPath]) {
alert('404! No registered application with path "' + appPath + '".');
return;
}
}
if (this._activeApp) {
this._activeApp.destroy();
delete this._activeAppPath;
}
if (appPath) {
this._loadAndRenderApp(appPath);
} else {
this._renderWelcomeScreen();
}
},
_renderWelcomeScreen: function() {
this.get('viewContainer').set('text', 'Welcome to the nested Y.Apps spike!');
},
_loadAndRenderApp: function(appPath) {
this.get('viewContainer').setHTML(THROBBER_HTML);
Y.use(this._appConfigByPath[appPath].moduleName, Y.bind(this._renderApp, this, appPath));
},
_renderApp: function(appPath) {
var cfg = this._appConfigByPath[appPath],
ns = Y.namespace(cfg.namespace),
AppFn = ns && ns[cfg.className],
viewContainer,
appConfig,
app;
if (!AppFn) {
alert('500! Failed to load application with path "' + appPath + '".');
return;
}
viewContainer = this.get('viewContainer');
viewContainer.empty();
appConfig = {
container: viewContainer,
root: this._joinURL(appPath),
linkSelector: null,
// Important on IE 9 and below
serverRouting: true
};
if (!this.get('html5')) {
appConfig.root = this.removeRoot(appConfig.root);
}
console.log('Loading app with path "' + appPath + '" and root URL: "' + appConfig.root + '"');
app = new AppFn(appConfig);
this._activeApp = app;
this._activeAppPath = appPath;
app.render().dispatch();
}
}, {
ATTRS: {
routes: {
value: [{
path: '/:appPath',
callbacks: '_showNestedApp'
}, {
path: '/:appPath/*',
callbacks: '_showNestedApp'
}]
},
linkSelector: {
value: 'a.' + CLASS_NAMES.pjax +', .' + CLASS_NAMES.pjax + ' a'
}
}
});
Y.namespace('SPIKE').TopApp = TopApp;
}, '@VERSION@', {"requires": ["app-base", "array-extras", "base", "handlebars"]});
@unkillbob
Copy link
Author

Note this has been superseded by a more thorough spike here: https://github.com/orionhealth/nested-y-apps-spike

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment