Skip to content

Commit

Permalink
Merge pull request #396 from opentable/oclient-templates
Browse files Browse the repository at this point in the history
Make oc-client.js supporting more templates via an extendable API
  • Loading branch information
matteofigus authored Mar 19, 2017
2 parents a376df3 + 5704b5f commit 88989ce
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 39 deletions.
64 changes: 49 additions & 15 deletions src/components/oc-client/src/oc-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ var oc = oc || {};
// Constants
var CDNJS_BASEURL = 'https://cdnjs.cloudflare.com/ajax/libs/',
IE9_AJAX_POLYFILL_URL = CDNJS_BASEURL + 'jquery-ajaxtransport-xdomainrequest/1.0.3/jquery.xdomainrequest.min.js',
HANDLEBARS_URL = CDNJS_BASEURL + 'handlebars.js/4.0.5/handlebars.runtime.min.js',
JADE_URL = CDNJS_BASEURL + 'jade/1.11.0/runtime.min.js',
JQUERY_URL = CDNJS_BASEURL + 'jquery/1.11.2/jquery.min.js',
RETRY_INTERVAL = oc.conf.retryInterval || 5000,
RETRY_LIMIT = oc.conf.retryLimit || 30,
Expand Down Expand Up @@ -72,6 +70,20 @@ var oc = oc || {};
}
};

var coreTemplates = {
'handlebars': {
externals: [
{ global: 'Handlebars', url: 'https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.runtime.min.js' }
]
},
'jade': {
externals: [
{ global: 'jade', url: 'https://cdnjs.cloudflare.com/ajax/libs/jade/1.11.0/runtime.min.js' }
]
}
};
var registeredTemplates = oc.conf.templates ? oc.registerTemplates(oc.conf.templates) : coreTemplates;

var retry = function(component, cb, failedRetryCb){
if(retries[component] === undefined){
retries[component] = RETRY_LIMIT;
Expand Down Expand Up @@ -100,6 +112,19 @@ var oc = oc || {};
return href;
};

oc.registerTemplates = function (templates) {
templates = Array.isArray(templates) ? templates : [templates];
templates.forEach(function(template){
if (!registeredTemplates[template.type]) {
registeredTemplates[template.type] = {
externals: template.externals
};
}
});
oc.ready(oc.renderUnloadedComponents);
return templates;
};

// A minimal require.js-ish that uses head.js
oc.require = function(nameSpace, url, callback){
if(typeof(url) === 'function'){
Expand Down Expand Up @@ -294,25 +319,34 @@ var oc = oc || {};

oc.render = function(compiledViewInfo, model, callback){
oc.ready(function(){
if(!!compiledViewInfo.type.match(/jade|handlebars/g)){
var template = registeredTemplates[compiledViewInfo.type];

if(!!template){
oc.require(['oc', 'components', compiledViewInfo.key], compiledViewInfo.src, function(compiledView){
if(!compiledView){
callback(MESSAGES_ERRORS_LOADING_COMPILED_VIEW.replace('{0}', compiledViewInfo.src));
} else {
if(compiledViewInfo.type === 'handlebars'){
oc.require('Handlebars', HANDLEBARS_URL, function(){
try {
var linked = $window.Handlebars.template(compiledView, []);
callback(null, linked(model));
} catch(e){
callback(e.toString());

var externals = template.externals;
var externalsRequired = 0;

externals.forEach(function(library, _index, externals){
oc.require(library.global, library.url, function(){
externalsRequired++;
if(externalsRequired === externals.length) {
if(compiledViewInfo.type === 'handlebars'){
try {
var linked = $window.Handlebars.template(compiledView, []);
callback(null, linked(model));
} catch(e){
callback(e.toString());
}
} else {
callback(null, compiledView(model));
}
}
});
} else if(compiledViewInfo.type === 'jade'){
oc.require('jade', JADE_URL, function(){
callback(null, compiledView(model));
});
}
});
}
});
} else {
Expand Down
95 changes: 71 additions & 24 deletions test/front-end/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

var handlebars3CompiledView = 'oc.components=oc.components||{},oc.components["46ee85c314b371cac60471cef5b2e2e6c443dccf"]={compiler:[6,">= 2.0.0-beta.1"],main:function(){return"Hello world!"},useData:!0};';
var handlebarsCompiledView = 'oc.components=oc.components||{},oc.components["46ee85c314b371cac60471cef5b2e2e6c443dccf"]={compiler:[7,">= 4.0.0"],main:function(){return"Hello world!"},useData:!0};';
var emojiCompiledView = 'oc.components=oc.components||{},oc.components["46ee85c314b371cac60471cef5b2e2e6c443dccc"]=function(){return "😎";};';
var jadeCompiledView = 'oc.components=oc.components||{},oc.components["09227309bca0b1ec1866c547ebb76c74921e85d2"]=function(n){var e,o=[],c=n||{};return function(n){o.push("<span>hello "+jade.escape(null==(e=n)?"":e)+"</span>")}.call(this,"name"in c?c.name:"undefined"!=typeof name?name:void 0),o.join("")};';

describe('oc-client : render', function(){
Expand All @@ -28,9 +29,9 @@ describe('oc-client : render', function(){
expect(callback.args[0][0]).toEqual('Error getting compiled view: https://my-cdn.com/components/a-component/1.2.123/template.js');
});
});

describe('when rendering handlebars component', function(){

describe('when handlebars runtime not loaded', function(){

var originalHandlebars, originalHeadLoad, callback, headSpy;
Expand All @@ -49,10 +50,10 @@ describe('oc-client : render', function(){

callback = sinon.spy();
eval(handlebarsCompiledView);

oc.render({
src: 'https://my-cdn.com/components/a-component/1.2.123/template.js',
type: 'handlebars',
src: 'https://my-cdn.com/components/a-component/1.2.123/template.js',
type: 'handlebars',
key: '46ee85c314b371cac60471cef5b2e2e6c443dccf'
}, {}, callback);
});
Expand All @@ -73,17 +74,17 @@ describe('oc-client : render', function(){
expect(callback.args[0][1]).toEqual('Hello world!');
});
});

describe('when handlebars runtime loaded', function(){

var callback, headSpy;
beforeEach(function(){
headSpy = sinon.spy(head, 'load');
callback = sinon.spy();
eval(handlebarsCompiledView);
eval(handlebarsCompiledView);
oc.render({
src: 'https://my-cdn.com/components/a-component/1.2.123/template.js',
type: 'handlebars',
src: 'https://my-cdn.com/components/a-component/1.2.123/template.js',
type: 'handlebars',
key: '46ee85c314b371cac60471cef5b2e2e6c443dccf'
}, {}, callback);
});
Expand Down Expand Up @@ -112,8 +113,8 @@ describe('oc-client : render', function(){
callback = sinon.spy();
eval(handlebars3CompiledView);
oc.render({
src: 'https://my-cdn.com/components/a-component/1.2.123/template.js',
type: 'handlebars',
src: 'https://my-cdn.com/components/a-component/1.2.123/template.js',
type: 'handlebars',
key: '46ee85c314b371cac60471cef5b2e2e6c443dccf'
}, {}, callback);
});
Expand All @@ -129,7 +130,7 @@ describe('oc-client : render', function(){
});

describe('when rendering jade component', function(){

describe('when jade runtime not loaded', function(){

var originalJade, originalHeadLoad, callback, headSpy;
Expand All @@ -147,10 +148,10 @@ describe('oc-client : render', function(){

callback = sinon.spy();
eval(jadeCompiledView);

oc.render({
src: 'https://my-cdn.com/components/a-component/1.2.456/template.js',
type: 'jade',
src: 'https://my-cdn.com/components/a-component/1.2.456/template.js',
type: 'jade',
key: '09227309bca0b1ec1866c547ebb76c74921e85d2'
}, { name: 'Michael' }, callback);
});
Expand All @@ -171,17 +172,17 @@ describe('oc-client : render', function(){
expect(callback.args[0][1]).toEqual('<span>hello Michael</span>');
});
});

describe('when jade runtime loaded', function(){

var callback, headSpy;
beforeEach(function(){
beforeEach(function(){
headSpy = sinon.spy(head, 'load');
callback = sinon.spy();
eval(jadeCompiledView);
eval(jadeCompiledView);
oc.render({
src: 'https://my-cdn.com/components/a-component/1.2.456/template.js',
type: 'jade',
src: 'https://my-cdn.com/components/a-component/1.2.456/template.js',
type: 'jade',
key: '09227309bca0b1ec1866c547ebb76c74921e85d2'
}, { name: 'James' }, callback);
});
Expand All @@ -201,17 +202,17 @@ describe('oc-client : render', function(){
});
});
});

describe('when rendering unsupported component', function(){

var callback, headSpy;
beforeEach(function(){
headSpy = sinon.spy(head, 'load');
callback = sinon.spy();
eval(jadeCompiledView);
eval(jadeCompiledView);
oc.render({
src: 'https://my-cdn.com/components/a-component/1.2.789/template.js',
type: 'hello!',
src: 'https://my-cdn.com/components/a-component/1.2.789/template.js',
type: 'hello!',
key: '123456789123456789123456789126456789'
}, { param: 'blabla' }, callback);
});
Expand All @@ -225,4 +226,50 @@ describe('oc-client : render', function(){
expect(callback.args[0][0]).toBe('Error loading component: view engine "hello!" not supported');
});
});

describe('when adding support to new template', function(){
describe('and the new template client-dependency is not loaded', function(){
var originalEmoji, jEmoji, originalHeadLoad, callback, headSpy;
beforeEach(function(){
originalHeadLoad = head.load;
headSpy = sinon.spy();

head.load = function(url, cb){
headSpy(url, cb);
cb();
};

callback = sinon.spy();
eval(emojiCompiledView);

oc.registerTemplates({
type:'emoji',
externals: [
{ global: 'jEmoji', url: 'http://cdn.staticfile.org/emoji/0.2.2/emoji.js' }
]
});

oc.render({
src: 'https://my-cdn.com/components/a-component/1.2.456/template.js',
type: 'emoji',
key: '46ee85c314b371cac60471cef5b2e2e6c443dccc'
}, {}, callback);
});

afterEach(function(){
head.load = originalHeadLoad;
});

it('should require and wait for it', function(){
expect(headSpy.called).toBe(true);
expect(headSpy.args[0][0]).toEqual('http://cdn.staticfile.org/emoji/0.2.2/emoji.js');
});

it('should render the component', function(){
expect(callback.called).toBe(true);
expect(callback.args[0][0]).toBe(null);
expect(callback.args[0][1]).toEqual('😎');
});
});
});
});

0 comments on commit 88989ce

Please sign in to comment.