dhxmvp
Version:
A complete boilerplate for building online, offline and syncable MVP Single Page Applications using DHTMLX.
1,032 lines (944 loc) • 44.4 kB
JavaScript
(function(namespace) {
'use strict';
})(window.$dhx = window.$dhx || {});
(function(namespace) {
'use strict';
})($dhx.ui = $dhx.ui || {});
(function(namespace) {
'use strict';
var root,
_application,
_router,
_main_view,
_child_view,
_child_views = [],
_child_presenters = [],
_registered_events = [],
_options = {},
_root_topic = '',
_presenter_topic = '',
_model_topic = '',
/**
* [application private application bootstrap constructor]
* @param {[Object]} stash [xxxxxxxxxxx]
* @return {[Object]} [returns an router object]
*/
application = function(stash) {
var appId;
if (typeof stash.appId === 'undefined') {
stash.appId = "" + Math.random() + "";
}
//application = namespace.copyTo(application, stash);
this.appId = stash.appId;
this.container = stash.container;
this.root = stash.root;
this.icons_path = stash.icons_path || stash.root + 'assets/icons/64/';
this.deps_path = stash.deps_path || stash.root + 'deps/';
this.lib_path = stash.lib_path || stash.root + 'lib/';
this.stash = stash;
root = stash.root;
//this.options = {};
_options = stash;
_options.from = 'super';
var isAllEventsReturninOk = namespace.triggerMethod('before:start', _options);
if (!isAllEventsReturninOk) {
throw ' application will not initialize due a onBeforeStart event returning false';
}
this.initialize(_options);
this.active_route = false;
this.last_active_route = false;
_application = this;
},
/**
* [router private router constructor]
* @param {[Object]} stash [xxxxxxxxxxx]
* @return {[Object]} [returns an router object]
*/
router = function(stash) {
var self = this;
_router = this;
},
/**
* [private view constructor]
* @param {[type]} stash [description]
* @return {[view]} view [description]
*/
main_view = function(factory) {
////console.log( _application );
//main_view = namespace.copyTo(main_view, _application);
main_view = namespace.copyTo(main_view, factory);
this.appId = _application.appId;
this.container = _application.container;
this.root = _application.root;
this.icons_path = _application.icons_path;
this.dispatch = function(id) {
_router.dispatch(id, true);
if (this.onDispatch) this.onDispatch(id);
};
_main_view = this;
},
/**
* [private view constructor]
* @param {[type]} stash [description]
* @return {[view]} view [description]
*/
child_view = function(factory) {
child_view = namespace.copyTo(child_view, factory);
this.appId = _application.appId;
this.container = _application.container;
this.root = _application.root;
this.icons_path = _application.icons_path;
};
/**
* [application.prototype MVP aplication bootstrap constructor class prototype chain]
* @type {Object}
*/
application.prototype = {
initialize: function(options) {
//console.log('method from application.prototype');
////console.log('app initialized from ' + options.from);
//namespace.triggerMethod('start', options);
},
start: function(c) {
var hash = window.location.hash,
deps = [],
core = [],
models = [],
model_engine = [],
model,
presenter,
view;
c = c || {};
// set mobile flag
if (window.screen.availWidth < 1024) {
namespace.ui.isMobile = true;
}
core.push(_application.lib_path + "presenter/" + ($dhx.environment != 'test' ? "min." : "") + "presenter.js");
core.push(_application.lib_path + "view/" + ($dhx.environment != 'test' ? "min." : "") + "view.js");
//deps.push("http://cdn.dhtmlx.com/edge/dhtmlx.css");
//deps.push("http://cdn.dhtmlx.com/edge/dhtmlx.js");
deps.push(_application.deps_path + "thirdparty/dhtmlx5.0/dhtmlx.css");
deps.push(_application.deps_path + "thirdparty/dhtmlx5.0/dhtmlx_.js");
deps.push(_application.deps_path + "thirdparty/signals.js");
deps.push(_application.deps_path + "thirdparty/hasher.js");
deps.push(_application.deps_path + "thirdparty/crossroads.js");
deps.push(_application.deps_path + "dhx/min.dhx.MQ.js");
deps.push(_application.deps_path + "dhx/dhx.ui.Mediator.js");
deps.push(_application.deps_path + "dhx/dhx.ui.router.js");
deps.push(_application.deps_path + "dhx/dhx.ui.session.js");
if (c.full) {
deps.push(_application.deps_path + "thirdparty/jquery.min.js");
deps.push("https://cdn.jsdelivr.net/pouchdb/5.4.5/pouchdb.min.js");
deps.push(_application.deps_path + "dhx/min.dhx.ui.i18n.js");
deps.push(_application.deps_path + "dhx/min.dhx.ui.i18n.en-us.js");
deps.push(_application.deps_path + "thirdparty/moment.min.js");
deps.push(_application.deps_path + "thirdparty/moment-timezone-with-data.min.js");
deps.push(_application.deps_path + "dhx/min.dhtmlx_grid_moment_type.js");
deps.push(_application.deps_path + "dhx/min.dhx.excells.js");
deps.push(_application.deps_path + "dhx/min.dhx.crypt.js");
//deps.push(_application.deps_path + "thirdparty/creditcard.min.js");
//deps.push(_application.deps_path + "thirdparty/min.progressbar.js");
//deps.push("https://js.stripe.com/v2/");
deps.push(_application.deps_path + "thirdparty/ie10-viewport-bug-workaround.js");
deps.push(_application.deps_path + "thirdparty/min.underscore.js");
deps.push(_application.deps_path + "thirdparty/backbone-min.js");
deps.push(_application.deps_path + "thirdparty/min.backbone-indexeddb.js");
deps.push(_application.deps_path + "dhx/min.dhx.component.js");
deps.push(_application.deps_path + "dhx/min.dhx.dhtmlx.js");
deps.push(_application.deps_path + "dhx/min.dhx.ui.form.js");
} else {
if (c.stripe) {
deps.push("https://js.stripe.com/v2/");
}
if (c.pouch) {
deps.push("https://cdn.jsdelivr.net/pouchdb/5.4.5/pouchdb.min.js");
}
if (c.backboneIDB) {
deps.push("http://cdn.pubnub.com/pubnub.min.js");
deps.push(_application.deps_path + "thirdparty/min.underscore.js");
deps.push(_application.deps_path + "thirdparty/backbone-min.js");
deps.push(_application.deps_path + "thirdparty/min.backbone-indexeddb.js");
}
if (c.$dhx_crypt) {
deps.push(_application.deps_path + "dhx/min.dhx.crypt.js");
}
if (c.$dhx_grid || c.$dhx_form) {
deps.push(_application.deps_path + "thirdparty/jquery.min.js");
deps.push(_application.deps_path + "dhx/min.dhx.ui.i18n.js");
deps.push(_application.deps_path + "dhx/min.dhx.ui.i18n.en-us.js");
deps.push(_application.deps_path + "thirdparty/moment.min.js");
deps.push(_application.deps_path + "thirdparty/moment-timezone-with-data.min.js");
deps.push(_application.deps_path + "dhx/min.dhtmlx_grid_moment_type.js");
deps.push(_application.deps_path + "dhx/min.dhx.component.js");
deps.push(_application.deps_path + "thirdparty/creditcard.min.js");
}
if (c.$dhx_grid) {
deps.push(_application.deps_path + "dhx/min.dhx.excells.js");
}
if (c.$dhx_form) {
deps.push(_application.deps_path + "dhx/min.dhx.dhtmlx.js");
deps.push(_application.deps_path + "dhx/min.dhx.ui.form.js");
}
}
if (_application.stash.model.models) {
_application.stash.model.models.forEach(function(file) {
models.push(_application.lib_path + "model/models/" + ($dhx.environment != 'test' ? "min." : "") + "" + file + ".js");
});
}
if (_application.stash.model.collections) {
_application.stash.model.collections.forEach(function(file) {
models.push(_application.lib_path + "model/collections/" + ($dhx.environment != 'test' ? "min." : "") + "" + file + ".js");
});
}
if (_application.stash.model.engine) {
model_engine = [
_application.lib_path + "model/engines/" + ($dhx.environment != 'test' ? "min." : "") + "" + _application.stash.model.engine + ".js"
];
} else {
_application.stash.model.engine = 'backboneIDB';
model_engine = [
_application.lib_path + "model/engines/" + ($dhx.environment != 'test' ? "min." : "") + "" + _application.stash.model.engine + ".js"
];
}
// load dep files
$dhx.onDemand.require(deps, function() {
// import models and collections files
$dhx.onDemand.require(models, function() {
// import models engine file
$dhx.onDemand.require(model_engine, function() {
$dhx.onDemand.require(core, function() {
namespace.start_all();
}); // end $dhx.onDemand.require(core, function()
}); // end $dhx.onDemand.require(model_engine, function()
}); // end $dhx.onDemand.require(models, function()
}); // end $dhx.onDemand.require(deps, function()
} // end application.start()
};
/**
* [router.prototype MVP router constructor class prototype chain]
* @type {Object}
*/
router.prototype = {
dispatch: function(route, addEntry) {
var router = this.router;
//console.info('Dispatching route: ', route);
namespace.destroy_active_route();
if( route != '#' )
{
$dhx.ui.router.routeTo(route);
$dhx.ui.router.router.resetState();
}
else
{
window.location.hash = '/';
_application.active_route = route;
}
},
route: function(stash) {
this.routes[stash.url] = stash;
}
};
main_view.prototype = {
initialize: function(options) {
//console.log(' initialize method from main_view.prototype');
////console.log('app initialized from ' + options.from);
//namespace.triggerMethod('start', options);
}
};
child_view.prototype = {
initialize: function(options) {
//console.log(' initialize method from child_view.prototype');
////console.log('app initialized from ' + options.from);
//namespace.triggerMethod('start', options);
}
};
/**
* [$dhx.ui.mvp.router Public access to MVP router features]
* @type {Object}
*/
namespace.router = {
/**
* [extend generate a new router constructor by inheriting the mvp router and append the methods from factory]
* @param {[Object]} factory [a collection of public properties and methods]
* @return {[constructor]} [MVP router constructor]
*/
extend: function(factory) {
var start = function() {
console.log('start from extend factory');
};
return namespace.extend({
base: router,
factory: factory,
onBeforeExtend: function(factory) {
/**
* [factory a collection of public properties and methods]
* @type {[Object}
*/
factory = factory || {};
// set a presenter class if it was not set when extending the router
factory.presenter = factory.presenter || {
start: start
};
// set a start method for the presenter if it was not set when extending the router
factory.presenter.start = factory.presenter.start || start;
// set a empty collection of application routes if it was not set when extending the router
//factory.appRoutes = factory.appRoutes || {};
//set a empty collection of routes created on the fly if it was not set when extending the router
factory.routes = factory.routes || {};
////console.log( '>>>>>XXX>>>>>> ', factory );
// map root route that will call the presenter.start();
if (!factory.routes.hasOwnProperty('#')) {
factory.routes['#'] = {
url: '#',
method: 'start'
};
}
}
});
}
};
/**
* [$dhx.ui.mvp.application public access to MVP application bootstrap]
* @type {Object}
*/
namespace.application = {
/**
* [extend generate a new application bootrap constructor by inheriting the mvp application schema and append the methods from factory]
* @param {[Object]} factory [a collection of public properties and methods]
* @return {[constructor]} [MVP router constructor]
*/
extend: function(factory) {
return namespace.extend({
base: application,
factory: factory,
onBeforeExtend: function() {}
});
}
};
namespace.main_view = {
/**
* [extend generate a new application bootrap constructor by inheriting the mvp application schema and append the methods from factory]
* @param {[Object]} factory [a collection of public properties and methods]
* @return {[constructor]} [MVP router constructor]
*/
extend: function(factory) {
return namespace.extend({
base: main_view,
factory: factory,
onBeforeExtend: function() {}
});
}
};
namespace.child_view = {
/**
* [extend generate a new application bootrap constructor by inheriting the mvp application schema and append the methods from factory]
* @param {[Object]} factory [a collection of public properties and methods]
* @return {[constructor]} [MVP router constructor]
*/
extend: function(factory) {
return namespace.extend({
base: child_view,
factory: factory,
onBeforeExtend: function() {}
});
}
};
namespace.start_all = function() {
//alert( window.screen.availWidth );
window.pubnub = PUBNUB.init({
publish_key: 'pub-c-d128f7d4-39ab-43e7-9547-4dc1bdea2300',
subscribe_key: 'sub-c-142379cc-668e-11e6-9eba-02ee2ddab7fe',
//uuid: 'Stephen',
error: function (error) {
console.log('Error:', error);
}
});
namespace.setup_routes();
namespace.setup_models();
namespace.setup_collections();
namespace.start_model();
};
namespace.setup_routes = function() {
var route_handler = function( o ) {
};
//console.log( _router.routes );
// declare routes
for (var route in _router.routes) {
if (route != '#') {
console.info('Route setup: ', route);
$dhx.ui.router.addRoute(route, route_handler);
}
}
};
namespace.start_model = function() {
var presenter = $dhx.ui.mvp.presenters.get('presenter'),
view = $dhx.ui.mvp.views.get('view'),
model = $dhx.ui.mvp.model.engine.get(_application.stash.model.engine);
model.start({
onSuccess: function() {
console.info('model started');
model.schema.start({
onSuccess: function() {
view.model = model;
view.rendered = false;
view.initialize();
presenter._view = view;
presenter.view = view;
//presenter._model = model;
presenter.model = model;
// make presenter to listen to Mediator
presenter._subscriber = presenter.subscriber || function(event, message) {
console.log('Presenter subescriber defined in $dhx.ui.mvp Received Message: ', message);
};
// make model listen to Mediator
presenter.model._subscriber = presenter.model.subscriber || function(event, message) {
console.log('Model subescriber defined in $dhx.ui.mvp Received Message: ', message);
};
presenter._subscriber_token = $dhx.ui.Mediator.listen('users,pets,questions:changeModel', presenter._subscriber);
presenter.model._subscriber_presenter_token = $dhx.ui.Mediator.listen('users,pets,questions:changeModel', presenter.model._subscriber);
_application.presenters = $dhx.ui.mvp.presenters;
_application.views = $dhx.ui.mvp.views;
////console.log( presenter );
_router.presenter = presenter;
view._router = _router;
view.presenter = presenter;
_application.main_presenter = presenter;
_application.main_view = view;
/**
* dispatch root '#' url
*/
if (!namespace.app_started) {
namespace.start_app();
}
}
}); // end model.schema.start
} // end onSuccess
}); // end model.start
};
namespace.setup_models = function() {
// for each model
_application.stash.model.models.forEach(function(modelName) {
// declare model
var model = {};
model[modelName] = (function(model) {
'strict';
return model;
}(window[modelName]));
$dhx.ui.mvp.model.declare(model);
window[modelName] = null;
});
};
namespace.setup_collections = function() {
// for each collection
_application.stash.model.collections.forEach(function(collectionName) {
// declare collection
var collection = {};
collection[collectionName] = (function(collection) {
'strict';
collection.defaults = $dhx.ui.mvp.model.get(collection.model);
collection.item = collection.model;
return collection;
}(window[collectionName]));
$dhx.ui.mvp.model.collection.declare(collection);
window[collectionName] = null;
});
};
namespace.queryString = function(name, url) {
if (!url) url = window.location.href;
//url = url.replace(/#/gi,'');
////console.log( url );
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
};
namespace.app_started = false;
namespace.start_app = function() {
var current_url = $dhx.ui.router.request_url || '';
if (current_url == '#/') {
current_url = '';
}
if (current_url !== '') {
current_url = current_url.toString().replace(/#/, '');
}
_router.dispatch('#');
$dhx.ui.mvp.presenters.get('presenter').start();
namespace.triggerMethod('start', _options);
// start all $dhx dependence
if ($dhx.ui.i18n) $dhx.ui.i18n.start();
if ($dhx.excells) $dhx.excells.init();
// when current url is not root, when starting with calling a sub view:
if (current_url !== '') {
_router.presenter._view.render({
onSuccess: function(c) {
namespace.triggerMethod('render', _options);
$dhx.ui.mvp.views.get('view').rendered = true;
$dhx.ui.mvp.views.get('view').dispatch(current_url);
if (c.onComplete) c.onComplete(current_url);
},
ok: function(c) {
namespace.triggerMethod('render', _options);
$dhx.ui.mvp.views.get('view').rendered = true;
$dhx.ui.mvp.views.get('view').dispatch(current_url);
if (c.onComplete) c.onComplete(current_url);
},
onFail: function() {},
});
} else {
_router.presenter._view.render({
onSuccess: function() {
namespace.triggerMethod('render', _options);
$dhx.ui.mvp.views.get('view').rendered = true;
},
ok: function() {
namespace.triggerMethod('render', _options);
$dhx.ui.mvp.views.get('view').rendered = true;
},
onFail: function() {},
});
}
$dhx.MQ.publish(_router.presenter.topic, {
action: 'start',
target: null
});
namespace.app_started = true;
};
/**
* [$dhx.ui.mvp.extend generate a new constructor by inheriting a base class and appending the methods from a factory]
* @param {[Object]} c [A JSON object containing the following properties and methods]
* @param {[Constructor]} c.base [a constructor function to be used as base class ]
* @param {[Object]} c.factory [a collection of public properties and methods to be appended to the new generated constructor]
* @return {[Constructor]} constructor [returns a new object constructor that inherits the base class and the factory]
*/
namespace.extend = function(c) {
var base = c.base,
factory = c.factory,
sub = null;
if (c.onBeforeExtend) {
c.onBeforeExtend(factory);
}
sub = function(stash) {
stash = stash || {};
base.call(this, stash);
};
sub.prototype = Object.create(base.prototype);
sub.prototype.constructor = sub;
sub = namespace.copyTo(sub, factory);
sub.on = function(pattern, fn) {
////console.log('instanceof base: ', (instanceof base) )
_registered_events.push({
pattern: pattern,
fn: fn,
base: base
});
};
sub.start = function(options) {
_options = options;
};
return sub;
};
namespace.copyTo = function(base, factory) {
for (var name in factory) {
if (factory.hasOwnProperty(name)) {
base.prototype[name] = factory[name];
}
}
return base;
};
namespace.triggerMethod = function() {
var event = arguments[0],
parameter = arguments[1] || false,
tests = [];
_registered_events.forEach(function(evtObject) {
if (evtObject.pattern === event) {
if (parameter) {
tests.push(evtObject.fn(parameter));
} else {
tests.push(evtObject.fn());
}
}
});
return tests.join('.').indexOf('false') > -1 ? false : true;
};
namespace.loadModule = function( dispatched_route, data ) {
var method_name = 'start',
router = _router,
routes = router.routes,
route = null,
route_matched = false,
ev = eval,
reg = ev(data.route._matchRegexp),
remove = [];
//console.log( dispatched_route );
//console.log( data );
//console.log( data.route._optionalParamsIds );
//console.log( data.route._paramsIds );
//console.log( data.route._pattern );
for( var r in router.routes )
{
if( reg.test(r) )
{
route_matched = true;
}
}
if( ! route_matched )
{
throw 'Undeclared ' + dispatched_route + ' route';
}
//remove = data.route._optionalParamsIds.map( function(){
//
//} );
route = data.route._pattern;
//console.log( 'dispatched_route: ', dispatched_route );
//console.log( 'internal matched route: ', route );
if (route in router.routes) {
if (router.routes[route].method) {
method_name = router.routes[route].method;
}
} else {
throw 'Undeclared ' + route + ' route';
}
// set global active_route value
_application.active_route = route;
// if active route is not first route(#)
if (route != '#') {
// If not explicity defined, then implicity set Presenter and View names by using route name
routes[route].presenter = routes[route].presenter || route;
routes[route].view = routes[route].view || route;
}
// this route has a predefined presenter
if (routes[route].presenter) {
var deps = [];
if (routes[route].view) {
deps.push(_application.lib_path + "view/" + ($dhx.environment != 'test' ? "min." : "") + routes[route].view + ".js");
}
deps.push(_application.lib_path + "presenter/" + ($dhx.environment != 'test' ? "min." : "") + routes[route].presenter + ".js");
// import auxiliar views
if (routes[route].append_views) {
routes[route].append_views.forEach(function(stash) {
deps.push(_application.lib_path + "view/" + ($dhx.environment != 'test' ? "min." : "") + stash[Object.keys(stash)[0]] + ".js");
});
}
$dhx.onDemand.load(deps, function() {
_child_presenters[route] = $dhx.ui.mvp.presenters.get(routes[route].presenter);
_child_views[route] = $dhx.ui.mvp.views.get(routes[route].view);
// import auxiliar views as new object into currently namespace scope
if (routes[route].append_views) {
routes[route].append_views.forEach(function(stash) {
_child_views[route][Object.keys(stash)[0]] = window[stash[Object.keys(stash)[0]]];
//window[stash[Object.keys(stash)[0]]] = null;
});
}
// create a reference to view on child presenter
_child_presenters[route].view = _child_views[route];
_child_presenters[route].view._wrapper = _main_view._wrapper;
_child_presenters[route].view.app = {
mainView: $dhx.ui.mvp.views.get('view'),
_child_presenters: _child_presenters,
_child_views: _child_views
};
//_child_presenters[route]._view.window_manager = _main_view.window_manager;
// create reference to modek on child presenter
_child_presenters[route].model = _router.presenter.model;
// set a subscriber if not defined on child presenter
_child_presenters[route]._subscriber = _child_presenters[route].subscriber || function(event, message) {
console.log('Child Presenter subescriber defined in $dhx.ui.mvp Received Message: ', message);
};
// subscribe presenter to events
_child_presenters[route]._subscriber_token = $dhx.ui.Mediator.listen('questions:changeModel', _child_presenters[route]._subscriber);
// create a reference to presenter on view
_child_views[route].presenter = _child_presenters[route];
// start presenter
_child_presenters[route].start();
//initialize view
_child_views[route].initialize();
// render view
_child_views[route].render(_router.presenter._model, _child_presenters[route]);
$dhx.MQ.publish(_child_presenters[route].topic, {
action: 'start',
target: null
});
});
} else {
// this route has not a predefined presenter
// like #
// $dhx.ui.mvp.presenters.get('presenter')
//if (router.presenter[method_name]) {
// router.presenter[method_name]();
//} else if (_router[method_name]) {
// _router[method_name]();
//}
}
};
namespace.destroy_active_route = function(){
_application.last_active_route = _application.active_route;
// destroy last active view if is there one
if (_child_presenters[_application.last_active_route]) {
// call child_presenter.destroy()
if (_child_presenters[_application.last_active_route].destroy) {
_child_presenters[_application.last_active_route].destroy();
}
// call child_view.destroy()
if (_child_views[_application.last_active_route].destroy) {
_child_views[_application.last_active_route].destroy();
}
// make child_presenter to unlistent to listener assigned to it
$dhx.ui.Mediator.unlisten(_child_presenters[_application.last_active_route]._subscriber_token);
_child_views[_application.last_active_route] = null;
_child_presenters[_application.last_active_route] = null;
delete _child_views[_application.last_active_route];
delete _child_presenters[_application.last_active_route];
}
};
namespace.views = {
views: [],
declare: function(c) {
var view_name = Object.keys(c)[0];
view_name = view_name.toString().replace(/\//g, '');
namespace.views.views[view_name] = c[view_name];
},
get: function(view_name) {
view_name = view_name.toString().replace(/\//g, '');
return namespace.views.views[view_name] || false;
}
};
namespace.presenters = {
presenters: [],
declare: function(c) {
var view_name = Object.keys(c)[0];
view_name = view_name.toString().replace(/\//g, '');
namespace.presenters.presenters[view_name] = c[view_name];
},
get: function(view_name) {
view_name = view_name.toString().replace(/\//g, '');
return namespace.presenters.presenters[view_name] || false;
}
};
namespace.models = {
models: [],
declare: function(c) {
var model_name = Object.keys(c)[0];
model_name = model_name.toString().replace(/\//g, '');
namespace.models.models[model_name] = c[model_name];
},
get: function(model_name) {
model_name = model_name.toString().replace(/\//g, '');
return namespace.models.models[model_name] || false;
}
};
namespace.ui = {
isMobile: false,
window_manager: null,
window_manager_is_ready: false,
_window_manager: function (skin) {
var self = namespace.ui;
if (!self.window_manager_is_ready) {
self.window_manager = new dhtmlXWindows({
//skin: self.skin
});
//self.window_manager.setSkin(self.skin);
self.window_manager_is_ready = true;
}
},
window: function (c) {
var self = namespace.ui;
if( ! self.window_manager_is_ready )
{
self._window_manager();
}
return self.window_manager.createWindow(c);
},
askNotificationPermission: function(c) {
Notification.requestPermission(function(permission) {
// Whatever the user answers, we make sure Chrome stores the information
if (!('permission' in Notification)) {
Notification.permission = permission;
}
if (c.onSuccess) c.onSuccess(permission);
//document.getElementById('dhx_npermission').value = permission;
// If the user is okay, let's create a notification
if (permission === "granted") {
var notification = new Notification('Notification test', {
body: 'it is working!',
icon: _application.root + 'assets/images/notification.png'
});
}
});
},
askLocationPermission: function(c) {
},
getQuota : function (onSuccess, onFail) {
var webkitStorageInfo = window.webkitStorageInfo || navigator.webkitTemporaryStorage || navigator.webkitPersistentStorage || false;
if (!webkitStorageInfo) {
var err = $dhx.Browser.name + " does not provide quota management.";
$dhx.notify('Quota information', err, _application.root + 'assets/images/notification.png');
if (onFail) onFail(err);
return;
}
webkitStorageInfo.queryUsageAndQuota(webkitStorageInfo.TEMPORARY, function (used, remaining) {
used = (used / 1024 / 1024 / 1024).toFixed(5);
remaining = (remaining / 1024 / 1024 / 1024).toFixed(2);
//$dhx.notify('Quota information', "Used quota: " + used + " GB, remaining quota: " + remaining+' GB.', _application.root + 'assets/images/notification.png');
if (onSuccess) onSuccess(used, remaining);
}, function (e) {
if (onFail) onFail(e);
console.log('Error', e);
});
}
};
namespace.model = {
_collections: {},
collection: {
declare: function(c) {
var collection_name = Object.keys(c)[0];
collection_name = collection_name.toString().replace(/\//g, '');
namespace.model._collections[collection_name] = c[collection_name];
},
get: function(collection_name) {
collection_name = collection_name || false;
if (collection_name) {
collection_name = collection_name.toString().replace(/\//g, '');
return namespace.model._collections[collection_name] || false;
} else {
return namespace.model._collections;
}
}
},
_engines: {},
engine: {
declare: function(c) {
var core_name = Object.keys(c)[0];
core_name = core_name.toString().replace(/\//g, '');
namespace.model._engines[core_name] = c[core_name];
},
get: function(core_name) {
core_name = core_name.toString().replace(/\//g, '');
return namespace.model._engines[core_name] || false;
}
},
_models: {},
declare: function(c) {
var model_name = Object.keys(c)[0];
model_name = model_name.toString().replace(/\//g, '');
namespace.model._models[model_name] = c[model_name];
},
get: function(model_name) {
if (model_name) {
model_name = model_name.toString().replace(/\//g, '');
return namespace.model._models[model_name] || false;
}
return namespace.model._models;
},
helpers: {
schema: {
record: function(c) {
var self = this,
attributes = {},
reject = ['_id', 'id', '__v'],
model_schema = namespace.model.get(c.model);
c.record = JSON.parse(JSON.stringify(c.record));
for (var record_field in c.record) {
if (!reject.contains(record_field)) {
// if field is declared in schema
if (record_field in model_schema) {
attributes[record_field] = c.record[record_field];
} else {
//console.warn('ignoring field ' + record_field);
}
}
}
for (var model_field_obj_key in model_schema) {
if (!reject.contains(model_field_obj_key)) {
// if attributes already have model_field_obj_key declared
if (typeof attributes[model_field_obj_key] !== 'undefined') {
// check it type if it matches the type declared on schema
if (typeof attributes[model_field_obj_key] !== model_schema[model_field_obj_key].type.toLowerCase()) {
console.warn('error creating record object');
throw 'Invalid type for ' + model_field_obj_key + '. It should be ' + model_schema[model_field_obj_key].type.toLowerCase() + ', but you passed ' + typeof attributes[model_field_obj_key];
}
// check it format if it matches the validate.rules declared on schema
if (model_schema[model_field_obj_key].validate.required || (model_schema[model_field_obj_key].validate.rules || "").indexOf('NotEmpty') > -1) {
//console.log( 'IS MANDATORY' );
//console.log( 'attributes[ model_field_obj_key ]: ', attributes[ model_field_obj_key ] );
if (attributes[model_field_obj_key] === "" || attributes[model_field_obj_key] === null) {
console.warn('error creating record object');
throw 'You need to provide a value for ' + model_field_obj_key + '. It should be ' + model_schema[model_field_obj_key].type.toLowerCase() + '.';
}
}
//console.log('------XXX-------');
} else {
console.info('setting default value (' + model_schema[model_field_obj_key].default+') for ' + model_field_obj_key);
// append field and use it default value
attributes[model_field_obj_key] = model_schema[model_field_obj_key].default;
}
}
}
//console.log(model_schema);
if (c.record.__v) {
attributes.__v = c.record.__v;
}
if (c.record.id) {
attributes.id = c.record.id;
}
else
{
attributes.id = $dhx.guid();
}
attributes._id = attributes.id;
for (var i in attributes) {
self[i] = attributes[i];
}
//console.warn( 'formated record: ', self );
},
defaults: {
__v: {
type: 'number',
default: 0,
unique: false,
validate: {
required: true,
mask_to_use: '',
rules: ''
},
ui: {
form: {
label: '__v',
type: 'hidden',
},
grid: {
header: '__v',
align: 'left',
coltype: 'ro',
width: '0'
}
}
},
_id: {
type: 'string',
default: 0,
unique: true,
validate: {
required: true,
mask_to_use: '',
rules: ''
},
ui: {
form: {
label: '_id',
type: 'hidden',
},
grid: {
header: '_id',
align: 'left',
coltype: 'ro',
width: '0'
}
}
}
}
}
}
};
})($dhx.ui.mvp = $dhx.ui.mvp || {});