UNPKG

jquery-toad

Version:

jQuery TOAD - O velho e querido jQuery

305 lines (232 loc) 9.83 kB
$namespace(3, '@', function (exports) { var utils = $require('utils'); var NAME_FIELD = 'name', CONSTRUCTOR_FIELD = 'ctor', EXPORT_NAME_FIELD = '$name', CONTROLLER_VIEW_FIELD_PRIVATE = '__view__', CONTROLLER_VIEW_FIELD = '$view', CONTROLLER_MODEL_FIELD_PRIVATE = '__model__', CONTROLLER_MODEL_FIELD = '$model', CONTROLLER_TRIGGER_FIELD_PRIVATE = '__triggers__', CONTROLLER_TRIGGER_FIELD = '$onUpdateModel'; var lazyTriggers = []; var controllers = []; var internals = exports.__internals__ = exports.__internals__ || {}; internals.getController = _getController; internals.callLazyTriggers = _callLazyTriggers; // Registra constantes públicas internals.setConstant('VIEW_BY_ID', 1); /** * Registra um controlador * * @param {string} name - Nome do controlador * @param {function} ctor - Função construtora do controlador */ exports.registerController = function (name, ctor) { var options = ensureOptions({ name: name, ctor: ctor }); var controllerName = options[NAME_FIELD]; if (controllers[controllerName]) { throw new Error('Controller ' + controllerName + ' already registered!'); } var fnCtrl = options[CONSTRUCTOR_FIELD]; fnCtrl[EXPORT_NAME_FIELD] = options[NAME_FIELD]; controllers[controllerName] = fnCtrl; fnCtrl.prototype[CONTROLLER_VIEW_FIELD] = _getViewElement; fnCtrl.prototype[CONTROLLER_MODEL_FIELD] = _manageModel; fnCtrl.prototype[CONTROLLER_TRIGGER_FIELD] = _manageTriggers; return fnCtrl; } function ensureOptions(options) { options = options || {}; if (typeof options[NAME_FIELD] != 'string') throw invalidOptionMessage(NAME_FIELD, 'string'); if (typeof options[CONSTRUCTOR_FIELD] != 'function') throw invalidOptionMessage(CONSTRUCTOR_FIELD, 'function'); return options; } function invalidOptionMessage(fieldName, fieldType) { return 'Invalid @controller.{name}. Must be a {type}.' .replace('{name}', fieldName) .replace('{type}', fieldType); } function _getController(controllerName) { if (typeof controllerName !== 'string' || controllerName == '') { throw new Error('Parameter controllerName is required.'); } if (!controllers[controllerName]) { throw new Error('Controller ' + controllerName + ' not registered!'); } return controllers[controllerName]; } /** * Retorna uma coleção de elementos dentro do escopo da controller * * @param {DOM} elType - Elemento DOM * @param {string} selector - jQuery selector */ function _getViewElement(elType, selector) { var view = this[CONTROLLER_VIEW_FIELD_PRIVATE], VIEW_BY_ID = $require('@').constants.VIEW_BY_ID; if (!(view instanceof $)) return; if (typeof elType === 'string' && arguments.length === 1) selector = elType; else if (typeof selector !== 'string') throw new Error('Invalid view selector.'); else switch (elType) { case VIEW_BY_ID: selector = '[data-id="{id}"]'.replace('{id}', selector); break; default: throw new Error('Invalid view type "' + elType + '".'); } return $(selector, view); } /** * Gerencia o modelo */ function _manageModel() { var clonerCurrent = new internals.PlainObjectCloner(this[CONTROLLER_MODEL_FIELD_PRIVATE]); // this.$model(): Get a full model if (!arguments.length) { return clonerCurrent.cloneObject(); } // this.$model({ object }): Set a full model if (arguments.length === 1 && utils.isObject(arguments[0])) { var clonerNew = new internals.PlainObjectCloner(arguments[0]), newState = clonerNew.cloneObject(); this[CONTROLLER_MODEL_FIELD_PRIVATE] = newState; _callTriggers(clonerCurrent.cloneObject(), newState, null, this); return; } // this.$model('string'): Get path of model if (arguments.length === 1 && utils.isString(arguments[0])) { var path = $.trim(arguments[0]), stateFull = clonerCurrent.cloneObject(); if (path.length === 0) return stateFull; return utils.getObjectItemByPath(stateFull, path) } // this.$model('string', { object }): Get path of model if (arguments.length === 2 && utils.isString(arguments[0]) && utils.isObject(arguments[1])) { var path = arguments[0], stateFull = clonerCurrent.cloneObject(), clonerNew = new internals.PlainObjectCloner(arguments[1]), newState = clonerNew.cloneObject(); utils.setObjectItemByPath(stateFull, path, newState); this[CONTROLLER_MODEL_FIELD_PRIVATE] = stateFull; _callTriggers(clonerCurrent.cloneObject(), stateFull, path, this); return; } throw new Error('Call with invalid parameters for ' + CONTROLLER_MODEL_FIELD + '!'); } function _attachTrigger(ctrl, path, trigger) { if (!utils.isArray(ctrl[CONTROLLER_TRIGGER_FIELD_PRIVATE])) ctrl[CONTROLLER_TRIGGER_FIELD_PRIVATE] = []; var triggers = ctrl[CONTROLLER_TRIGGER_FIELD_PRIVATE]; for (var t in triggers) { var trg = triggers[t]; if (trg.path === path && trg.trigger === trigger) return; } triggers.push({ path: path, trigger: trigger }); } function _manageTriggers() { if (arguments.length === 1 && utils.isFunction(arguments[0])) { return _attachTrigger(this, null, arguments[0]); } if (arguments.length === 2 && utils.isString(arguments[0]) && utils.isFunction(arguments[1])) { return _attachTrigger(this, arguments[0], arguments[1]); } throw new Error('Call with invalid parameters for ' + CONTROLLER_TRIGGER_FIELD + '!'); } function _callTriggers(oldState, newState, modelPath, controller) { if (!controller[CONTROLLER_VIEW_FIELD_PRIVATE]) { _setLazyTriggers(oldState, newState, modelPath, controller); return; } var eligibleTriggers = [], path = (modelPath || ''), pathParts = path === '' ? [] : path.split('.'); for (var idx = pathParts.length - 1; idx >= 0; idx--) { var pathPartsBegin = pathParts.splice(0, idx + 1); pathParts = pathPartsBegin.concat(pathParts); eligibleTriggers.push(pathPartsBegin.join('.')); } eligibleTriggers.push(''); var triggers = controller[CONTROLLER_TRIGGER_FIELD_PRIVATE] || [], triggerFilter = function (prefix) { return $.grep(triggers, function (item) { return (item.path || '') === prefix; }); }; $.each(eligibleTriggers, function (_, itemPath) { $.each(triggerFilter(itemPath), function (_, tgr) { if (!utils.isFunction(tgr.trigger)) return; var _oldState = oldState, _newState = newState; if (tgr.path) { _oldState = utils.getObjectItemByPath(_oldState, tgr.path); _newState = utils.getObjectItemByPath(_newState, tgr.path); } // function(oldState, newState, modelPath, controller) { } tgr.trigger.call( null, /* this -> null */ _oldState, _newState, modelPath, controller); }); }); } function _setLazyTriggers(oldState, newState, modelPath, controller) { var triggerIdx = -1, triggerRecord = { controller: controller, trigger: { oldState: oldState, newState: newState, modelPath: modelPath } }; $.each(lazyTriggers, function (idx, item) { if (item.controller === controller) triggerIdx = idx; }); if (triggerIdx >= 0) lazyTriggers[triggerIdx] = triggerRecord; else lazyTriggers.push(triggerRecord); } function _callLazyTriggers(controller) { var triggerIdx = -1, triggerRecord; $.each(lazyTriggers, function (idx, record) { if (record.controller === controller) { triggerIdx = idx; triggerRecord = record; } }); if (triggerRecord) { try { _callTriggers( triggerRecord.trigger.oldState, triggerRecord.trigger.newState, triggerRecord.trigger.modelPath, triggerRecord.controller ); } catch (_) { } } if (triggerIdx >= 0) { lazyTriggers.splice(triggerIdx, 1); } } })