UNPKG

routebar

Version:

A visual component for navigating between panel cells containing user content.

1,339 lines (1,240 loc) 227 kB
var rb = /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // identity function for calling harmony imports with the correct context /******/ __webpack_require__.i = function(value) { return value; }; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 13); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/** * Модуль, содержащий всякие полезные переменные и функции * @module Errors */ !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function() { function CustomError(property) { this.name = this.name || "CustomError"; this.property = property; this.message = this.name + ": " + property; if (Error.captureStackTrace) { Error.captureStackTrace(this, CustomError); } else { this.stack = (new Error()).stack; } } /** * @class * Класс ошибки, означающий неправильно переданный в функцию аргумент * @param {string} argName - название аргумента * @param {Object} arg - значение аргумента * @constructor module:Errors~ArgumentError */ function ArgumentError(argName, arg) { if (typeof arg === 'function') { arg = 'function() {...}'; } else { arg = JSON.stringify(arg); } arg = 'wrong function argument "' + argName + '": ' + arg; this.name = 'ArgumentError'; CustomError.apply(this, [arg]); } ArgumentError.prototype = Object.create(CustomError.prototype); ArgumentError.prototype.constructor = ArgumentError; /** * @class * Класс ошибки, означающий, что путь от одной модели до другой модели не был найден * @param {ScreenModel} fromScreen - модель, из которой осуществлялся поиск * @param {ScreenModel} toScreen - модель, в которую осуществлялся поиск * @constructor module:Errors~PathNotFoundError */ function PathNotFoundError(fromScreen, toScreen) { this.name = 'PathNotFoundError'; var arg = 'path not found: from ' + fromScreen.toString() + ' to ' + toScreen.toString(); CustomError.apply(this, [arg]); } PathNotFoundError.prototype = Object.create(CustomError.prototype); PathNotFoundError.prototype.constructor = PathNotFoundError; /** * @class * Класс ошибки, означающий критическую ошибку логики * @param {string} property - подробности ошибки * @constructor module:Errors~FatalError */ function FatalError(property) { this.name = 'FatalError'; CustomError.apply(this, arguments); } FatalError.prototype = Object.create(CustomError.prototype); FatalError.prototype.constructor = FatalError; /** * @class * Класс ошибки, означающий, что функция интерфейса еще не реализована * @param {string} module - название интерфейса * @param {string} functionName - название функции * @constructor module:Errors~NotRealizedError */ function NotRealizedError(module, functionName) { this.name = 'NotRealizedError'; var arg = 'Not realized ' + module + ':' + functionName; CustomError.apply(this, [arg]); } NotRealizedError.prototype = Object.create(CustomError.prototype); NotRealizedError.prototype.constructor = NotRealizedError; return /** @alias module:Errors */ { /** * Класс ошибки, означающий неправильно переданный в функцию аргумент * @type {module:Errors~ArgumentError} */ ArgumentError: ArgumentError, /** * Класс ошибки, означающий, что путь от одной модели до другой модели не был найден * @type {module:Errors~PathNotFoundError} */ PathNotFoundError: PathNotFoundError, /** * Класс ошибки, означающий, что функция интерфейса еще не реализована * @type {module:Errors~NotRealizedError} */ NotRealizedError: NotRealizedError, /** * Класс ошибки, означающий критическую ошибку логики * @type {module:Errors~FatalError} */ FatalError: FatalError }; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/** * Модуль, содержащий всякие полезные переменные и функции * @module Utils */ !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0)], __WEBPACK_AMD_DEFINE_RESULT__ = function(Errors) { "use strict"; /** * Функция, возвращающая противоположную сторону к исходной * @param {string} side - исходная сторона * @returns {string} противоположная сторона * @memberOf module:Utils */ function oppositeSide(side) { if (side === 'left') return 'right'; if (side === 'right') return 'left'; if (side === 'top') return 'bottom'; if (side === 'bottom') return 'top'; if (side === 'center') return 'center'; throw new Errors.ArgumentError('side', side); } /** * Функция, возвращающая левую (верхнюю) сторону к исходной * @param {string} side - исходная сторона * @returns {string} левая (верхняя) сторона * @memberOf module:Utils */ function getStartSide(side) { if (side === 'left') return 'left'; if (side === 'right') return 'left'; if (side === 'top') return 'top'; if (side === 'bottom') return 'top'; if (side === 'center') return 'center'; throw new Errors.ArgumentError('side', side); } /** * Возвращает модуль числа index в конечной группе порядка length. * @param {number} index - исходное число * @param {number} length - порядок группы * @returns {number} модуль числа * @memberOf module:Utils */ function cycledNumber(index, length) { return (index % length + length) % length; } /** * Делает первую букву строки заглавной * @param {string} string - исходная строка * @returns {string} строка с первой заглавной буквой * @memberOf module:Utils */ function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } /** * Подмешать миксин к классу * @param {function} base - исходный класс * @param {Object} mixin - миксин * @memberOf module:Utils */ function mixin(base, mixin) { for(var key in mixin) { if (mixin.hasOwnProperty(key)) { base.prototype[key] = mixin[key]; } } } /** * Унаследовать класс от базового класса * @param {function} child - класс-наследник * @param {function} parent - базовый класс * @memberOf module:Utils */ function inherite(child, parent) { child.prototype = Object.create(parent.prototype); child.prototype.constructor = child; } /** * Пустая функция * @memberOf module:Utils */ function nop() {} // Mobile check /** * Возвращает флаг, является ли окружение мобильным устройством * @returns {boolean} флаг, является ли окружение мобильным устройством * @memberOf module:Utils */ function mobileCheck() { var check = false; (function(a){if(/(android|ipad|playbook|silk|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera); return check; } if (!Array.prototype.find) { Array.prototype.find = function(predicate) { if (this == null) { throw new TypeError('Array.prototype.find called on null or undefined'); } if (typeof predicate !== 'function') { throw new TypeError('predicate must be a function'); } var list = Object(this); var length = list.length >>> 0; var thisArg = arguments[1]; var value; for (var i = 0; i < length; i++) { value = list[i]; if (predicate.call(thisArg, value, i, list)) { return value; } } return undefined; }; } (function(e){ e.closest = e.closest || function(css){ var node = this; while (node) { if (node.matches(css)) return node; else node = node.parentElement; } return null; } })(Element.prototype); return /** @alias module:Utils */ { /** * Массив из возможных сторон */ sides: ['left', 'top', 'right', 'bottom'], /** * Массив из возможных сторон включая центральную */ sidesWithCenter: ['center', 'left', 'top', 'right', 'bottom'], /** * Является ли окружение мобильным устройством */ isMobile: mobileCheck(), nop: nop, cycledNumber: cycledNumber, oppositeSide: oppositeSide, getStartSide: getStartSide, capitalizeFirstLetter: capitalizeFirstLetter, mixin: mixin, inherite: inherite }; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); /***/ }), /* 2 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(1), __webpack_require__(0)], __WEBPACK_AMD_DEFINE_RESULT__ = function(Utils, Errors) { "use strict"; /** * @class * Интерфейс для плагина. Плагины, расширяющие функционал панели должны наследоваться от этого интерфейса. * @constructor IPlugin * @interface */ function IPlugin() { } /** * Применить конфигурацию. * @param {Moving~config} config - конфигурация * @memberOf IPlugin */ IPlugin.prototype.configure = function(config) { throw new Errors.NotRealizedError('IPlugin', 'configure'); }; /** * Уничтожить экземпляр интерфейса. * @memberOf IPlugin */ IPlugin.prototype.destroy = function() { throw new Errors.NotRealizedError('IPlugin', 'destroy'); }; return IPlugin; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); /***/ }), /* 3 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(1), __webpack_require__(2), __webpack_require__(0)], __WEBPACK_AMD_DEFINE_RESULT__ = function(Utils, IPlugin, Errors) { "use strict"; /** * @class * Интерфейс управления панелью. Позволяет переключаться в соседние ячейки панели. * @constructor IControl * @interface * @extends IPlugin */ function IControl() { } Utils.inherite(IControl, IPlugin); /** * Возвращает флаг, включено ли управление панелью. * @memberOf IControl */ IControl.prototype.isEnable = function() { throw new Errors.NotRealizedError('IControl', 'isEnable'); }; /** * включить управление панелью. * @memberOf IControl */ IControl.prototype.enable = function() { throw new Errors.NotRealizedError('IControl', 'enable'); }; /** * выключить управление панелью. * @memberOf IControl */ IControl.prototype.disable = function() { throw new Errors.NotRealizedError('IControl', 'disable'); }; return IControl; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); /***/ }), /* 4 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0)], __WEBPACK_AMD_DEFINE_RESULT__ = function(Errors) { "use strict"; /** * Конфигурация модели * @typedef {Object} ScreenModel~ScreenConfig * @property {ScreenModel[]} [children] - Потомки модели * @property {ScreenModel[]} [parents] - Предки модели * @property {boolean} [isPermanent] - Является ли модель постоянно хранимой, если да, то попав на страницу не будет оттуда удаляться. * @property {boolean} [isDirectedGraph] - Является ли строящийся граф моделей ориентированным. * @property {string} [html] - Контент модели * @property {number} [defaultChildIndex] - Индекс модели по умолчанию среди моделей-потомков * @property {number} [defaultParentIndex] - Индекс модели по умолчанию среди моделей-предков */ /** * Конфигурация моделей по умолчанию * @typedef {Object} ScreenModel~DefaultScreenConfig * @property {boolean} [isPermanent] - Является ли модель постоянно хранимой, если да, то попав на страницу не будет оттуда удаляться. * @property {boolean} [isDirectedGraph] - Является ли строящийся граф моделей ориентированным. * @property {number} [defaultChildIndex] - Индекс модели по умолчанию среди моделей-потомков * @property {number} [defaultParentIndex] - Индекс модели по умолчанию среди моделей-предков */ /** * @class * Модель контента, отображаемая в ячейке панели. * @param {String|ScreenModel~ScreenConfig} [html] - контент модели * @param {ScreenModel[]} [children] - потомки модели * @param {ScreenModel[]} [parents] - предки модели * @constructor ScreenModel */ function ScreenModel(html, children, parents) { if (!ScreenModel._mainScreenSetted) { ScreenModel._mainScreen = this; } this._children = []; this._parents = []; var isPermanent, isDirectedGraph, defaultChildIndex, defaultParentIndex; if (typeof html === 'object') { children = html.children; parents = html.parents; isPermanent = html.isPermanent; isDirectedGraph = html.isDirectedGraph; defaultChildIndex = html.defaultChildIndex; defaultParentIndex = html.defaultParentIndex; html = html.html; } else if (typeof html !== 'string') { html = ''; } if (isPermanent === undefined) { isPermanent = ScreenModel.isPermanent; } if (isDirectedGraph === undefined) { isDirectedGraph = ScreenModel.isDirectedGraph; } if (defaultChildIndex === undefined) { defaultChildIndex = ScreenModel.defaultChildIndex; } if (defaultParentIndex === undefined) { defaultParentIndex = ScreenModel.defaultParentIndex; } this._id = 'screen_' + ScreenModel._length++; this._html = html; this._temporary = !isPermanent; // Todo на изменение тут менять и там где используется this._isDirectedGraph = !!isDirectedGraph; // Todo на изменение тут менять и там где используется this._defaultChildIndex = defaultChildIndex; this._defaultParentIndex = defaultParentIndex; this.resetChildren(children); this.resetParents(parents); } /** * Возвращает идентификатор модели * @returns {string} идентификатор модели * @memberOf ScreenModel */ ScreenModel.prototype.toString = function() { return this._id; }; /** * Возвращает контент модели * @param {string} [html] - если аргумент задан, он будет установлен в качестве контента модели * @returns {string} контент модели * @memberOf ScreenModel */ ScreenModel.prototype.html = function (html) { if (typeof html === 'string') { this._html = html; // todo обновить все ячейки в которых лежит эта модель } return this._html; }; /** * Возвращает опцию "временная модель". Если модель временная, она не будет храниться на странице, если не отображается. * @returns {boolean} опция "временная модель" * @memberOf ScreenModel */ ScreenModel.prototype.isTemporary = function() { return this._temporary; }; /** * Возвращает опцию "ориентированный граф". Если true, модель является частью ориентированного графа. * @returns {boolean} опция "ориентированный граф" * @memberOf ScreenModel */ ScreenModel.prototype.isDirectedGraph = function() { return this._isDirectedGraph; }; /** * Возвращает индекс модели по умолчанию среди моделей-потомков * @param {number} [index] - если задан индекс, он будет установлен как значение по умолчанию * @returns {number} индекс модели по умолчанию среди моделей-потомков * @memberOf ScreenModel */ ScreenModel.prototype.defaultChildIndex = function(index) { if (typeof index === 'number') { this._defaultChildIndex = index; } return this._defaultChildIndex; }; /** * Возвращает индекс модели по умолчанию среди моделей-предков * @param {number} [index] - если задан индекс, он будет установлен как значение по умолчанию * @returns {number} индекс модели по умолчанию среди моделей-предков * @memberOf ScreenModel */ ScreenModel.prototype.defaultParentIndex = function(index) { if (typeof index === 'number') { this._defaultParentIndex = index; } return this._defaultParentIndex; }; ScreenModel.prototype._addScreen = function(screen, isChild) { if (isChild) { if (this.getChildIndex(screen) !== -1) { console.log('screenModel: "' + screen.toString() + '" child screen exists!'); } else { this._children.push(screen); //todo смотреть что оба скрина одного типа isDirectGraph screen._parents.push(this); } } else { if (this.getParentIndex(screen) !== -1) { console.log('screenModel: "' + screen.toString() + '" parent screen exists!'); } else { this._parents.push(screen); screen._children.push(this); } } if (!this._isDirectedGraph) { if (!screen._isAddingState) { this._isAddingState = true; screen._addScreen(this, isChild); this._isAddingState = false; } } return this; }; ScreenModel.prototype._getScreenIndex = function(screen, arr) { var index = -1; if (typeof screen === 'number') { if (isNaN(screen)) { throw new Errors.ArgumentError('screen', screen); } index = screen; } else if (typeof screen === 'string') { screen = arr.find(function(curScreen, curIndex) { if (curScreen.toString() === screen) { index = curIndex; return true; } }); } else if (screen instanceof ScreenModel) { index = arr.indexOf(screen); } else { throw new Errors.ArgumentError('screen', screen); } return index; }; ScreenModel.prototype._removeScreen = function(screen, isChild) { var arr = isChild ? this._children : this._parents, index = this._getScreenIndex(screen, arr); if (index !== -1) { var removed = arr.splice(index, 1)[0]; } else { return; } if (isChild) { removed.removeParent(this); } else { removed.removeChild(this); } if (!this._isDirectedGraph) { removed._removeScreen(this, isChild); } return this; }; /** * Сортирует набор потомков. Сортировка происходит по правилам сортировки массива. * @param {function} [compareFn] - Если задана функция сравнения, она будет использована при сортировке. * @returns {ScreenModel} текущая модель * @memberOf ScreenModel */ ScreenModel.prototype.sortChildren = function(compareFn) { this._children = this._children.sort(compareFn); ScreenModel._runUpdateFn(this); return this; }; /** * Возвращает количество потомков. * @returns {Number} количество потомков * @memberOf ScreenModel */ ScreenModel.prototype.childrenLength = function () { return this._children.length; }; /** * Находит индекс модели среди набора потомков * @param {ScreenModel|string|number} child - искомая модель, ее идентификатор или порядковый номер в наборе * @returns {number} искомый индекс модели * @memberOf ScreenModel */ ScreenModel.prototype.getChildIndex = function(child) { return this._getScreenIndex(child, this._children); }; /** * Находит модель среди набора потомков * @param {ScreenModel|string|number} child - искомая модель, ее идентификатор или порядковый номер в наборе * @returns {ScreenModel} искомая модель * @memberOf ScreenModel */ ScreenModel.prototype.getChild = function(child) { var index = this.getChildIndex(child); return this._children[index]; }; /** * Удаляет модель из набора потомков * @param {ScreenModel|string|number} child - удаляемая модель, ее идентификатор или порядковый номер в наборе * @returns {ScreenModel} текущая модель * @memberOf ScreenModel */ ScreenModel.prototype.removeChild = function(child) { this._removeScreen(child, true); ScreenModel._runUpdateFn(this); return this; }; /** * Добавить набор моделей в конец к набору потомков * @param {ScreenModel[]|ScreenModel} children - набор добавляемый моделей * @returns {ScreenModel} текущая модель * @memberOf ScreenModel */ ScreenModel.prototype.pushChildren = function(children) { if (Array.isArray(children)) { for (var i = 0; i < children.length; i++) { this._addScreen(children[i], true); } } else if (children instanceof ScreenModel) { this._addScreen(children, true); } else { ScreenModel._runUpdateFn(this); throw new Errors.ArgumentError('children', children); } ScreenModel._runUpdateFn(this); return this; }; /** * Переопределить набор моделей потомков, то есть удалить старые и установить новые * @param {ScreenModel[]} [children] - набор добавляемый моделей * @returns {ScreenModel} текущая модель * @memberOf ScreenModel */ ScreenModel.prototype.resetChildren = function(children) { this._clearChildren().pushChildren(children || []); return this; }; ScreenModel.prototype._clearChildren = function() { for (var i = this._children.length - 1; i >= 0; i--) { this._removeScreen(this._children[i], true); } return this; }; /** * Сортирует набор предков. Сортировка происходит по правилам сортировки массива. * @param {function} [compareFn] - Если задана функция сравнения, она будет использована при сортировке. * @returns {ScreenModel} текущая модель * @memberOf ScreenModel */ ScreenModel.prototype.sortParents = function(compareFn) { this._parents = this._parents.sort(compareFn); ScreenModel._runUpdateFn(this); return this; }; /** * Возвращает количество предков. * @returns {Number} количество предков * @memberOf ScreenModel */ ScreenModel.prototype.parentsLength = function () { return this._parents.length; }; /** * Находит индекс модели среди набора предков * @param {ScreenModel|string|number} parent - искомая модель, ее идентификатор или порядковый номер в наборе * @returns {number} искомый индекс модели * @memberOf ScreenModel */ ScreenModel.prototype.getParentIndex = function(parent) { return this._getScreenIndex(parent, this._parents); }; /** * Находит модель среди набора предков * @param {ScreenModel|string|number} parent - искомая модель, ее идентификатор или порядковый номер в наборе * @returns {ScreenModel} искомая модель * @memberOf ScreenModel */ ScreenModel.prototype.getParent = function(parent) { var index = this.getParentIndex(parent); return this._parents[index]; }; /** * Удаляет модель из набора предков * @param {ScreenModel|string|number} parent - удаляемая модель, ее идентификатор или порядковый номер в наборе * @returns {ScreenModel} текущая модель * @memberOf ScreenModel */ ScreenModel.prototype.removeParent = function(parent) { this._removeScreen(parent, false); ScreenModel._runUpdateFn(this); return this; }; /** * Добавить набор моделей в конец к набору предков * @param {ScreenModel[]|ScreenModel} parents - набор добавляемый моделей * @returns {ScreenModel} текущая модель * @memberOf ScreenModel */ ScreenModel.prototype.pushParents = function(parents) { if (Array.isArray(parents)) { for (var i = 0; i < parents.length; i++) { this._addScreen(parents[i], false); } } else if (parents instanceof ScreenModel) { this._addScreen(parents, false); } else { ScreenModel._runUpdateFn(this); throw new Errors.ArgumentError('parents', parents); } ScreenModel._runUpdateFn(this); return this; }; /** * Переопределить набор моделей предков, то есть удалить старые и установить новые * @param {ScreenModel[]} [parents] - набор добавляемый моделей * @returns {ScreenModel} текущая модель * @memberOf ScreenModel */ ScreenModel.prototype.resetParents = function(parents) { this._clearParents().pushParents(parents || []); return this; }; ScreenModel.prototype._clearParents = function() { for (var i = this._parents.length - 1; i >= 0; i--) { this._removeScreen(this._parents[i], false); } return this; }; /** * Устанавливает конфигурацию моделей по умолчанию. Изначальные значения по умоланию: <br> * isPermanent: false, <br> * isDirectedGraph: true, <br> * defaultChildIndex: 0, <br> * defaultParentIndex: 0 * @param {ScreenModel~DefaultScreenConfig} config - конфигурация * @memberOf ScreenModel */ ScreenModel.configure = function(config) { ScreenModel.isPermanent = config.isPermanent; ScreenModel.isDirectedGraph = config.isDirectedGraph; ScreenModel.defaultChildIndex = config.defaultChildIndex; ScreenModel.defaultParentIndex = config.defaultParentIndex; }; ScreenModel.configure({ isPermanent: false, isDirectedGraph: true, defaultChildIndex: 0, defaultParentIndex: 0 }); ScreenModel._length = 1; ScreenModel._relativeUpdateFn = []; /** * Установить модель по умолчанию, она будет использоваться в качестве стартовой для панелей, если при старте не заданы иные модели. * Если модель по умолчанию не установлена вручную, будет использован первый созданный экземпляр модели. * @param {ScreenModel} screen - модель по умолчанию * @memberOf ScreenModel * @see {@link module:RbManager.init} */ ScreenModel.setMainScreen = function(screen) { ScreenModel._mainScreen = screen; ScreenModel._mainScreenSetted = true; }; /** * Получить модель по умолчанию * @returns {ScreenModel} модель по умолчанию * @memberOf ScreenModel */ ScreenModel.getMainScreen = function() { return ScreenModel._mainScreen; }; /** * Зарегистрировать функцию для запуска, когда изменится структура графа * @param {function} fn - функция для запуска * @memberOf ScreenModel */ ScreenModel.registerUpdateFn = function(fn) { ScreenModel._relativeUpdateFn.push(fn); }; /** * Удалить функцию из списка функций для запуска, когда изменится структура графа * @param {function} fn - функция для запуска * @memberOf ScreenModel */ ScreenModel.unregisterUpdateFn = function(fn) { ScreenModel._relativeUpdateFn = ScreenModel._relativeUpdateFn.filter(function(value) { return value !== fn; }); }; /** * Очистить набор функций для запуска, когда изменится структура графа * @memberOf ScreenModel */ ScreenModel.clearUpdateFn = function() { ScreenModel._relativeUpdateFn = []; }; ScreenModel._runUpdateFn = function(screen) { ScreenModel._relativeUpdateFn.forEach(function(fn) { fn.call(undefined, screen); }); }; return ScreenModel; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); /***/ }), /* 5 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(14)], __WEBPACK_AMD_DEFINE_RESULT__ = function(Moving) { "use strict"; /** * callback-функция, которая будет выполнена после инициализации панелей * * @callback module:RbManager~initCallback * @param {Moving[]} Instances Набор панелей, действующих в данный момент на странице */ /** * Функция, инициализирующая расположенные в данный момент на странице панели. * Если startScreens не задан, первым аргументом может быть callback. * Оживляются элементы с классом rb-wrapper, находящиеся на странице, в качестве идентификатора берется значение * атрибута data-id или id, иначе идентификатор будет назначен самостоятельно. * Инициализация запускается асинхронно, сразу как только страница будет отрендерена. * @param {Object.<string, ScreenModel>} [startScreens] набор моделей контента, которые будут для панелей моделями по умолчанию. * @param {module:RbManager~initCallback} [callback] функция, которая будет выполнена после инициализации панелей * @memberOf module:RbManager */ function init(startScreens, callback) { if (typeof startScreens === 'function') { callback = startScreens; startScreens = undefined; } function waitJQuery() { $(function() { var $rbWrapper = $('.rb-wrapper'); var loadingPromises = []; for (var i = 0; i < $rbWrapper.length; i++) { var elemWrapper = $rbWrapper.eq(i), id = elemWrapper.data('id') || elemWrapper.attr('id') || 'instance_' + i; if (rb.Instances[id] === undefined) { elemWrapper.html('<div class="rb"><div tabindex="-1" class="rb__fake-element"></div></div>'); var $rb = elemWrapper.find('>.rb'), inst = new Moving($rb, startScreens && startScreens[id]); loadingPromises.push(inst._loadingPromise); Object.defineProperty(rb.Instances, id, { value: inst, configurable: true, enumerable: true }); } } Promise.all(loadingPromises).then(function() { callback && callback(rb.Instances); }); }); } function timeoutFunc() { if (typeof jQuery === 'undefined') { setTimeout(timeoutFunc, 0); } else { waitJQuery(); } } timeoutFunc(); } /** * Функция, удаляющая панель со страницы * @param {string} id Идентификатор модели контента * @memberOf module:RbManager * @see {@link ScreenModel#toString} */ function remove(id) { if (rb.Instances.hasOwnProperty(id)) { rb.Instances[id].destroy(); delete rb.Instances[id]; } } function batchAction(action, args) { var res = []; for (var id in rb.Instances) { if (rb.Instances.hasOwnProperty(id)) { var inst = rb.Instances[id]; res.push(inst[action].apply(inst, args)); } } return res; } /** * Применить конфигурацию к панелям * @param {Moving~config} config - конфигурация * @memberOf module:Batch * @see {@link Moving#configure} */ function configure(config) { batchAction('configure', arguments); } /** * Осуществить переход для всех панелей в указанную сторону. * @param {string} side - сторона, в которую осуществляется переход * @param {Boolean} [isSaveHistory] - сохранять ли осуществляемый переход в историю переходов * @returns {Promise} promise о завершении действия во всех панелях * @memberOf module:Batch * @see {@link Moving#move} */ function move(side, isSaveHistory) { return Promise.all(batchAction('move', arguments)); } /** * Осуществить откат последнего удачного хода, воспользовавшись историей переходов. * @returns {Promise} promise о завершении действия во всех панелях * @memberOf module:Batch * @see {@link Moving#moveBack} */ function moveBack() { return batchAction('moveBack', arguments); } /** * Анимировать запрещенное перемещение в одну из сторон. В панели в эту сторону перемещение может быть запрещено, * но будет анимировано, будто запрещено. Это полезно, например, если необходимо, чтобы либо все панели были перемещены * в одну из сторон, либо все анимировали запрещенный переход. * @param {string} side - сторона, в которую осуществляется переход * @returns {Promise} promise о завершении действия во всех панелях * @memberOf module:Batch * @see {@link Moving#animateWrongSide} */ function animateWrongSide(side) { return Promise.all(batchAction('animateWrongSide', arguments)); } /** * Установить модель контента в текущую ячейку панелей. * @param {ScreenModel} screen - Устанавливаемая модель контента * @param {Boolean} [isSaveHistory] - Сохранять ли устанавливаемую модель в историю переходов * @returns {Promise} promise о завершении установки модели во все панели * @memberOf module:Batch * @see {@link Moving#setScreen} */ function setScreen(screen, isSaveHistory) { return Promise.all(batchAction('setScreen', arguments)); } /** * Перезагрузить все панели на странице. Перезагрузка предполагает обновление верстки ячейки панели, * сброс состояния в верстке. Если в элементах верстки есть подписки, необходимо позаботиться об отписке и * последующей подписке к новым элементам верстки. * @prop {string} side - сторона, с которой будет перезагружаться ячейка панели относительно текущей ячейки. * @memberOf module:Batch * @see {@link Moving#reload} */ function reload(side) { batchAction('reload', arguments); } /** * Удалить все панели со страницы. * @memberOf module:Batch * @see {@link module:RbManager.remove} */ function removeAll() { for (var id in rb.Instances) { remove(id); } } /** * Пакетированные действия на панелях, то есть выполняемые для всех панелей разом. * @typedef {Object} Batch * @module Batch */ var Batch = { configure: configure, move: move, moveBack: moveBack, animateWrongSide: animateWrongSide, setScreen: setScreen, reload: reload, removeAll: removeAll }; /** * Module rbManager. * @module RbManager */ return { init: init, remove: remove, /** * @type module:Batch */ Batch: Batch }; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); /***/ }), /* 6 */ /***/ (function(module, exports) { // removed by extract-text-webpack-plugin /***/ }), /* 7 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(1), __webpack_require__(2), __webpack_require__(0), __webpack_require__(18)], __WEBPACK_AMD_DEFINE_RESULT__ = function(Utils, IPlugin, Errors) { "use strict"; /** * @class * Класс анимации переходов в панели * @param {JQuery} mainDiv - элемент, в котором располагается панель. Должен содержать класс rb-wrapper. * @param {ElementsPool} elementsPool - хранилище элементов ячеек панели * @constructor Animation * @extends IPlugin */ function Animation(mainDiv, elementsPool) { this._elementsPool = elementsPool; if (mainDiv instanceof $) { this._mainDiv = mainDiv; } else { throw new Errors.ArgumentError('mainDiv', mainDiv); } } Utils.inherite(Animation, IPlugin); /** * Применить конфигурацию. Учитывает опции wrongTime1, wrongTime2, correctTime, wrongEasing1, wrongEasing2, correctEasing, showAdjacentScreens. * @param {Moving~config} config - конфигурация * @memberOf Animation */ Animation.prototype.configure = function(config) { function fixTime(argName, time) { if (typeof time === 'number') { return time > 0 ? time : 1; } else { if (time === undefined) { return 500; } else { throw new Errors.ArgumentError(argName, time); } } } if (typeof config === 'object') { if (config.wrongTime1 !== undefined) { this._wrongTime1 = fixTime('wrongTime1', config.wrongTime1); } if (config.wrongTime2 !== undefined) { this._wrongTime2 = fixTime('wrongTime2', config.wrongTime2); } if (config.correctTime !== undefined) { this._correctTime = fixTime('correctTime', config.correctTime); } if (config.wrongEasing1 !== undefined) { this._wrongEasing1 = config.wrongEasing1; } if (config.wrongEasing2 !== undefined) { this._wrongEasing2 = config.wrongEasing2; } if (config.correctEasing !== undefined) { this._correctEasing = config.correctEasing; } if (config.showAdjacentScreens !== undefined) { this._showAdjacentScreens = config.showAdjacentScreens; } } }; Animation.prototype._animate = function(elem, side, value, easing, time, beforeFn, afterFn) { beforeFn && beforeFn(); var css = {}, opts; css[Utils.getStartSide(side)] = value + '%'; opts = { duration: time, easing: easing, queue: false, done: afterFn }; elem.animate(css, opts); }; Animation.prototype._updateState = function(res, elements) { if (this._isAnimate) { this._isAnimate = false; this._new && this._new.stop(); this._old && this._old.stop(false, true); this._cur && this._cur.stop(); this._prev && this._prev.stop(false, true); this._next && this._next.stop(false, true); this._res(false); } this._isAnimate = true; this._old = elements.oldElem; this._new = elements.newElem; this._cur = elements.curElem; this._prev = elements.prevElem; this._next = elements.nextElem; this._res = res; }; /** * Анимация неудачного перехода * @param {string} side - сторона перехода * @memberOf Animation */ Animation.prototype.goToWrongSide = function(side) { var self = this, width = 100, height = 100, elem = this._elementsPool.getElementBySide('center'), nextElem = this._elementsPool.getElementBySide(side), prevElem = this._elementsPool.getElementBySide(Utils.oppositeSide(side)); return new Promise(function(res, rej) { function wrongAnimate(elem, startLeft, startTop, beforeFn, afterFn) { self._animate(elem, side, '+=' + value, self._wrongEasing1, self._isAnimate ? self._wrongTime1 : 10, function() { startLeft -= 100; startTop -= 100; elem.css({'left': startLeft + '%', 'top': startTop + '%'}); beforeFn && beforeFn(); }, function() { self._animate(elem, side, '-=' + value, self._wrongEasing2, self._isAnimate ? self._wrongTime2 : 10, undefined, function() { afterFn && afterFn(); }); }); } self._updateState(res, { curElem: elem, prevElem: prevElem, nextElem: nextElem }); var dw = width/10, dh = height/10, value = 0, relValWidth = 0, relValHeight = 0; if (side === 'left') { relValWidth = -width; value = - dw; } else if (side === 'right') { relValWidth = width; value = dw; } else if (side === 'top') { relValHeight = -height; value = - dh; } else if (side === 'bottom') { relValHeight = height; value = dh; } if (self._showAdjacentScreens) { wrongAnimate(nextElem, width + relValWidth, height + relValHeight, function() { nextElem.toggleClass('rb__hiding-screen', true); }, function() { nextElem.toggleClass('rb__hiding-screen', false); }, true); wrongAnimate(prevElem, width - relValWidth, height - relValHeight, function() { prevElem.toggleClass('rb__hiding-screen', true); }, function() { prevElem.toggleClass('rb__hiding-screen', false); }, true); } wrongAnimate(elem, width, height, undefined, function() { self._isAnimate = false; self._res(true); }); }); }; /** * Анимация удачного перехода * @param {string} side - сторона перехода * @memberOf Animation */ Animation.prototype.goToCorrectSide = function(side) { var self = this, newElem = this._elementsPool.getElementBySide('center'), oldElem = this._elementsPool.getElementBySide(Utils.oppositeSide(side)), width = 100, height = 100; return new Promise(function(res, rej) { function correctAnimate(elem, startLeft, startTop, beforeFn, afterFn) { self._animate(elem, side, '-=' + value, self._correctEasing, self._correctTime, function() { startLeft -= 100; startTop -= 100; elem.css({'left': startLeft + '%', 'top': startTop + '%'}); beforeFn && beforeFn(); }, function() { afterFn && afterFn(); }); } self._updateState(res, { oldElem: oldElem, newElem: newElem }); var value = 0, relValWidth = 0, relValHeight = 0; if (side === 'left') { relValWidth = -width; value = - width; } else if (side === 'right') { relValWidth = width; value = width; } else if (side === 'top') { relValHeight = -height; value = - height; } else if (side === 'bottom') { relValHeight = height; value = height; } if (self._showAdjacentScreens) { correctAnimate(oldElem, width, height, function () { oldElem.toggleClass('rb__hiding-screen', true); }, function () { oldElem.toggleClass('rb__hiding-screen', false); }, true); } correctAnimate(newElem, width + relValWidth, height + relValHeight, undefined, function() { self._isAnimate = false; self._res(true); }); }); }; /** * Переход в центральную ячейку * @memberOf Animation */ Animation.prototype.goToCenter = function() { var elem = this._elementsPool.getElementBySide('center'); elem.css({'left': '0%', 'top': '0%'}); }; /** * Уничтожить экзе