xf/src/xf.view.js (157 lines of code) (raw):
define([
'./xf.core',
'underscore',
'backbone',
'./dom/dom',
'./xf.settings',
'./xf.storage',
'./xf.device'
], function(XF, _, BB, Dom) {
/**
Implements view workaround flow.
@class
@static
@augments XF.Events
*/
XF.View = BB.View.extend({
url: function() {
return XF.settings.property('templateUrlPrefix') + XF.device.type.templatePath + this.component.name + XF.settings.property('templateUrlPostfix');
},
/**
Flag that determines whether the Model update should be ignored by the View (in this case you may launch {@link XF.View#refresh} manualy)
@default false
@type Boolean
*/
_bindListeners: function() {
if (this.component.options.autorender) {
if (this.component.collection) {
this.listenTo(this.component.collection, 'fetched', this.refresh);
} else if (this.component.model) {
this.listenTo(this.component.model, 'fetched', this.refresh);
}
}
this.on('refresh', this.refresh, this);
},
_initProperties: function() {
var template = {
src: null,
compiled: null,
cache: true
};
this.template = this.template || {};
this.template = _.defaults(this.template, template);
this.status = {
loaded: false,
loading: false,
loadingFailed: false
};
this.component = null;
},
constructor: function(options) {
// Sorry, BB extend makes all properties static
this._initProperties();
this.setElement('[data-id=' + options.attributes['data-id'] + ']', false);
if (options.component) {
this.component = options.component;
}
_.omit(options, 'component');
this._bindListeners();
this.load();
BB.View.apply(this, arguments);
},
initialize: function() {
},
construct: function() {
},
load: function() {
if (this.template.src) {
this.status.loading = false;
this.status.loaded = true;
this.trigger('loaded');
return;
}
var url = (_.isFunction(this.url)) ? this.url() : this.url;
if (!url) {
this.status.loadingFailed = true;
this.trigger('loaded');
return;
}
// trying to get template from cache
console.log(111, XF.settings.noCache);
if (!XF.settings.noCache) {
console.log(this.template.cache, _.has(XF, 'storage'));
if (this.template.cache && _.has(XF, 'storage')) {
var cachedTemplate = XF.storage.get(url);
if (cachedTemplate) {
this.template.src = cachedTemplate;
this.status.loaded = true;
this.trigger('loaded');
return;
}
}
}
if (!this.status.loaded && !this.status.loading) {
this.status.loading = true;
var $this = this;
Dom.ajax({
url: url,
complete: function(jqXHR, textStatus) {
if (!$this.component) {
throw 'XF.View "component" linkage lost';
}
if (textStatus == 'success') {
var template = jqXHR.responseText;
// saving template into cache if the option is turned on
if (!XF.settings.noCache) {
if ($this.template.cache && _.has(XF, 'storage')) {
XF.storage.set(url, template);
}
}
$this.template.src = jqXHR.responseText;
$this.status.loading = false;
$this.status.loaded = true;
$this.afterLoadTemplate();
$this.trigger('loaded');
} else {
$this.template.src = null;
$this.status.loading = false;
$this.status.loaded = false;
$this.status.loadingFailed = true;
$this.afterLoadTemplateFailed();
$this.trigger('loaded');
}
}
});
}
},
/**
Compiles component template if necessary & executes it with current component instance model
@static
*/
getMarkup: function() {
var data = {};
if (!this.template.compiled) {
this.template.compiled = _.template(this.template.src);
}
if (this.component.collection) {
data = this.component.collection.toJSON();
} else if (this.component.model) {
data = this.component.model.toJSON();
}
return this.template.compiled({
data: data,
options: this.component.options
});
},
/**
HOOK: override to add logic before template load
*/
beforeLoadTemplate: function() {},
/**
HOOK: override to add logic after template load
*/
afterLoadTemplate: function() {},
/**
HOOK: override to add logic for the case when it's impossible to load template
*/
afterLoadTemplateFailed: function() {
XF.log('view: could not load template for "' + this.component.id + '"');
},
/**
Renders component into placeholder + calling all the necessary hooks & events
*/
refresh: function() {
if (this.status.loaded && this.template.src) {
if ((!this.component.collection && !this.component.model) || (this.component.collection && this.component.collection.status.loaded) || (this.component.model && this.component.model.status.loaded)) {
this.beforeRender();
this.render();
this.afterRender();
}
}
},
/**
HOOK: override to add logic before render
*/
beforeRender: function() {},
/**
Identifies current render vesion
@private
*/
renderVersion: 0,
/**
Renders component into placeholder
@private
*/
render: function() {
if (this.component) {
this.component._removeChildComponents();
}
this.$el.html(this.getMarkup());
XF.trigger('ui:enhance', this.$el);
this.renderVersion++;
this.trigger('rendered');
return this;
},
/**
HOOK: override to add logic after render
*/
afterRender: function() {}
});
return XF;
});