routebar
Version:
A visual component for navigating between panel cells containing user content.
1,339 lines (1,240 loc) • 227 kB
JavaScript
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%'});
};
/**
* Уничтожить экзе