Skip to content

Instantly share code, notes, and snippets.

@alksily
Created March 1, 2019 12:24
Show Gist options
  • Save alksily/fac51425c3eefc903e6d478ab680c6d5 to your computer and use it in GitHub Desktop.
Save alksily/fac51425c3eefc903e6d478ab680c6d5 to your computer and use it in GitHub Desktop.
App bundle.js
/**
* Copyright (c) 2017, AEngine Official
* MIT License
*
* Need: jQuery, Backbone & Lodash
*/
'use strict';
// App
let App = {};
App = _.extend(App, Backbone.Events, {
debug: true,
locale: 'ru',
_module: {},
_controller: {},
_initialize: [],
$window: null,
$document: null,
// список отложенных задач
deferredList: [],
// объект роутера
router: null,
location: 'main/index',
param: undefined,
controller: function(name, constructor) {
let controller = this._controller[name] = {};
if (typeof constructor == 'function') {
constructor(controller);
}
},
module: function(name, constructor) {
let module = window[name] = this._module[name] = {};
if (typeof constructor == 'function') {
constructor(module);
if (typeof module.initialize == 'function') {
this._initialize.push(module.initialize);
}
}
},
goTo: function(url, trigger, replace) {
trigger = trigger == undefined ? true : trigger;
replace = replace == undefined ? false : replace;
App.router.navigate(url, {
trigger: trigger,
replace: replace
});
return this;
},
refresh: function(url) {
url = url || window.location;
window.location = url;
},
info: function() {
if (this.debug) {
console.info.apply(console, arguments);
}
return this;
},
log: function() {
if (this.debug) {
console.log.apply(console, arguments);
}
return this;
},
warn: function() {
if (this.debug) {
console.warn.apply(console, arguments);
}
return this;
},
error: function() {
if (this.debug) {
console.error.apply(console, arguments);
}
return this;
},
/**
* Обёртка JQuery.XHR
*
* @param data
* @returns {XMLHttpRequest}
*/
xhr: function(data) {
let param = {
method: 'GET',
dataType: 'json',
url: '',
data: {},
done: null,
fail: null,
always: null,
before: null,
cache: false
};
data = _.extend(param, data);
return $.ajax({
method: data.method.toUpperCase(),
dataType: data.dataType,
url: data.url,
data: data.data,
success: data.done,
error: data.fail,
complete: data.always,
beforeSend: data.before,
cache: data.cache
});
},
run: function() {
this.$window = $(window);
this.$document = $(document);
let constructor;
while (constructor = this._initialize.shift()) {
constructor();
}
App.router = new App.Router();
// выполняем отложенные задачи
$.when.apply(this, App.deferredList)
.done(function() {
// приложение готово
App.trigger('ready');
App.info('App ready');
Backbone.history.start({
pushState: true
});
})
.fail(function() {
// приложение умерло ._.
App.warn('Fail to start');
});
}
});
// Router
App.Router = Backbone.Router.extend({
routes: {
'*notFound': ''
},
requestList: [],
initialize: function() {
App.info('Router init');
this.on('route', this.handlerRoute);
App.$document.on('click', 'a:not([data-bypass])', function(e) {
e.preventDefault();
let link = e.currentTarget,
href = link.href;
// требуется открыть ссылку в новом окне
if (link.target == '_blank' || e.which == 2) {
window.open(href);
} else {
if (href.replace(/[^#]/g, '') !== '#') {
let url = href.split('//')[1].split('/');
// проверяем ведёт ли ссылка на внешний ресурс
if (url[0] == location.host || url[0] === location.hostname) {
url.shift();
App.goTo('/' + url.join('/'));
} else {
// отправляем по назначению..
location.href = href;
}
} else {
// ссылка-якорь, меняем хеш
location.hash = href.split('#')[1];
}
}
});
},
handlerLeave: null,
handlerRoute: function() {
_.each(this.requestList, function(request) {
if (request.abort) {
request.abort();
}
});
this.requestList = [];
let url = Backbone.history.location.pathname.split('/'),
controller = 'Main',
action = 'index',
params = [],
param = false;
if (url.length > 1 && url[1]) {
controller = url[1].capitalize();
if (url.length > 2 && url[2]) {
action = url[2].toLowerCase();
if (url.length > 3 && url[3]) {
param = url[3];
params = url.slice(3);
}
}
}
if (typeof this.handlerLeave == 'function') {
this.handlerLeave();
}
App.location = controller + '/' + action;
App.param = param;
if (App._controller[controller]) {
if (App._controller[controller][action]) {
App.info('Route to ' + controller + '/' + action);
App._controller[controller][action].in(param, params);
if (App._controller[controller][action]['out']) {
this.handlerLeave = () => {
App.info('Leave from ' + controller + '/' + action);
return App._controller[controller][action]['out'](param, params);
};
} else {
this.handlerLeave = null;
}
} else {
App.trigger('router:404');
App.warn('Not found action "' + action + '" in controller "' + controller + '"');
}
} else {
App.trigger('router:404');
App.warn('Not found controller "' + controller + '"');
}
}
});
// Collection
App.Collection = Backbone.Collection.extend({});
// Model
App.Model = Backbone.Model.extend({});
// View
App.View = Backbone.View.extend({
templateName: '',
model: null,
collection: null,
/**
* Возвращает данные указанной формы
*
* @param form
* @returns {*}
*/
serialize: function(form) {
return this.$(form || 'form')
.serializeArray()
.reduce(function(obj, item) {
obj[item.name] = item.value;
return obj;
}, {});
},
/**
* Подсвечивает поля ввода красным цветом, если ошибка
*
* @param result
*/
formError: function(result) {
if (result) {
if (result.reason) {
this.$('[data-var="form:error"]').text(result.reason[App.locale]);
}
if (result.response) {
_(result.response).each((text, name) => {
let $el = this.$('[name="' + name + '"]');
$el
.addClass('error')
.one('change', function() {
$el.removeClass('error');
});
});
}
}
},
/**
* Возвращает кешированный шаблон
*
* @param name
* @returns {*}
*/
template: function(name) {
name = name || this.templateName;
let templateStorage = App.View.__template;
if (!templateStorage) {
templateStorage = App.View.__template = {};
}
if (!templateStorage[name]) {
templateStorage[name] = _.template($('script#tpl-' + name).html());
}
return templateStorage[name];
},
/**
* @returns {App.View}
*/
render: function() {
this.$el.html(this.template()(this.model ? {model: this.model} : (this.collection ? {collection: this.collection} : {data: arguments})));
return this;
},
/**
* @returns {App.View}
*/
detach: function() {
this.$el.detach();
return this;
},
/**
* @returns {App.View}
*/
delete: function() {
this.detach();
this.remove();
return this;
},
});
// Capitalize function
String.prototype.capitalize = function() {
return this.substr(0, 1).toUpperCase() + this.substr(1).toLowerCase();
};
// run
$(() => {
Backbone.emulateHTTP = true;
Backbone.emulateJSON = true;
App.run();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment