Created
March 1, 2019 12:24
-
-
Save alksily/fac51425c3eefc903e6d478ab680c6d5 to your computer and use it in GitHub Desktop.
App bundle.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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