- // ==UserScript==
- // @name hwm_build_manager
- // @author Chie (http://www.heroeswm.ru/pl_info.php?id=645888)
- // @icon https://s.gravatar.com/avatar/5fd0059ad34d082dfbd50cfdeb9aab6a
- // @description Менеджер билдов для HWM
- // @namespace https://github.com/betula/hwm_build_manager
- // @homepageURL https://github.com/betula/hwm_build_manager
- // @include http://*heroeswm.ru/*
- // @include http://178.248.235.15/*
- // @include http://*lordswm.com/*
- // @version 1.0.2
- // @grant none
- // ==/UserScript==
-
-
- // Build Manager 1.0.2
-
- class ServiceContainer {
-
- constructor() {
- this.instances = {};
- }
-
- _service(ctor) {
- let { name } = ctor;
- if (!this.instances[name]) {
- this.instances[name] = new ctor(this);
- }
- return this.instances[name];
- }
-
- get manager() { return this._service(ManagerService) }
- get fraction() { return this._service(FractionService) }
- get inventory() { return this._service(InventoryService) }
- get attribute() { return this._service(AttributeService) }
- get army() { return this._service(ArmyService) }
- get skill() { return this._service(SkillService) }
- get current() { return this._service(CurrentService) }
- get change() { return this._service(ChangeService) }
- get import() { return this._service(ImportService) }
-
- }
-
- class ManagerService {
-
- constructor(services) {
- this.services = services;
- this._storage = new LocalStorageArrayDriver('BM_MANAGER');
- this.items = [];
-
- this._restore();
- }
-
- createNew() {
- let nextNumber = 1;
- for (let item of this.items) {
- let match = item.name.match(/^Новый билд (\d+)$/);
- if (match) {
- nextNumber = Math.max(nextNumber, (parseInt(match[1]) || 0) + 1);
- }
- }
-
- let item = {
- id: uniqid(),
- name: `Новый билд ${nextNumber}`,
- fraction: this.services.fraction.default.id,
- inventory: this.services.inventory.default.id,
- attribute: this.services.attribute.default,
- army: this.services.army.default,
- skill: this.services.skill.default
- }
-
- this.items.push(item);
- this._store();
-
- return item;
- }
-
- remove(item) {
- let { founded, index } = this._searchByItem(item);
- if (!founded) return null;
-
- let items = this.items;
- items = items.slice(0, index).concat( items.slice(index + 1) );
- this.items = items;
- this._store();
-
- if (index === items.length) {
- return items[index - 1]
- }
- return items[index];
- }
-
- duplicate(item) {
- let { founded } = this._searchByItem(item);
- if (!founded) return null;
-
- let duplicate = deepCopy(item);
- duplicate.id = uniqid();
- duplicate.name += ' копия';
-
- this.items.push(duplicate);
- this._store()
-
- return duplicate;
- }
-
- update(updatedItem) {
- let { founded, index } = this._searchById(updatedItem.id);
- if (!founded) return null;
-
- this.items[index] = updatedItem;
- this._store();
-
- this.services.current.mayBeOnlyNameUpdated(updatedItem);
-
- return updatedItem;
- }
-
- searchEquals(item) {
- let { founded, index } = this._searchById(item.id);
- if (founded) {
- if (deepEquals(item, this.items[index])) {
- return {
- founded,
- index
- }
- }
- }
- return {
- founded: false
- }
- }
-
- serialize() {
- return JSON.stringify(this.items);
- }
-
-
- unserialize(value) {
- const INVALID = 'invalid';
-
- const Checker = {
- string(value) {
- if (typeof value !== 'string' || value.length === 0) throw INVALID;
- },
- number(value) {
- if (typeof value !== 'number') throw INVALID;
- },
- array(value) {
- if (!Array.isArray(value)) throw INVALID;
- },
- object(value) {
- if (!value || typeof value !== 'object') throw INVALID;
- },
- keys(value, keys) {
- if (!keys.every({}.hasOwnProperty.bind(value))) throw INVALID;
- for (let key of Object.keys(value)) {
- Checker.enum(key, keys);
- }
- },
- enum(value, values) {
- if (Array.isArray(value)) {
- for (let once of value) {
- Checker.enum(once, values);
- }
- } else {
- if (Array.isArray(values)) {
- if (values.indexOf(value) === -1) throw INVALID;
- } else {
- if (!values.hasOwnProperty(value)) throw INVALID;
- }
- }
- },
- length(value, len) {
- if (value.length !== len) throw INVALID;
- }
-
- };
-
- let items = [];
-
- try {
- items = JSON.parse(value);
- Checker.array(items);
-
- for (let item of items) {
- Checker.object(item);
- Checker.keys(item, [ 'id', 'name', 'fraction', 'inventory', 'attribute', 'army', 'skill' ]);
-
- let { id, name, fraction, inventory, attribute, army, skill } = item;
-
- Checker.string(id);
- Checker.string(name);
- Checker.enum(fraction, this.services.fraction.map);
- Checker.enum(inventory, this.services.inventory.map);
-
- Checker.object(attribute);
- Checker.keys(attribute, this.services.attribute.list);
- Object.values(attribute).forEach(Checker.number);
-
- Checker.array(army);
- Checker.length(army, 7);
- army.forEach(Checker.number);
-
- Checker.array(skill);
- Checker.enum(skill, this.services.skill.map);
- }
-
- } catch(e) {
- return false;
- }
-
- this.items = items;
- this._store();
- return true;
- }
-
- _searchById(id) {
- const items = this.items;
- let founded = false;
- let index;
- for (index = 0; index < items.length; index++) {
- if (items[index].id === id) {
- founded = true;
- break;
- }
- }
- return founded ? { founded, index } : { founded: false };
- }
-
- _searchByItem(item) {
- let index = this.items.indexOf(item);
- return index != -1
- ? { founded: true, index }
- : { founded: false };
- }
-
- _restore() {
- this.items = this._storage.fetch();
- }
-
- _store() {
- this._storage.put(this.items);
- }
-
- }
-
- class CurrentService {
-
- constructor(services) {
- this.services = services;
- this._storage = new LocalStorageDriver('BM_CURRENT');
- this._restore();
- }
-
- get item() {
- return this._item;
- }
-
- mayBeOnlyNameUpdated(updatedItem) {
- let current = this._item;
-
- if (!current) return;
- if (current.id !== updatedItem.id) return;
-
- let clone = deepCopy(current);
- clone.name = updatedItem.name;
- if (!deepEquals(clone, updatedItem)) return;
-
- current.name = updatedItem.name;
- this._store();
- }
-
- isExpired() {
- if (!this._item) return false;
- return !this.services.manager.searchEquals(this._item).founded;
- }
-
- change(item, force) {
- item = deepCopy(item);
-
- const change = () => {
- if (!item) return item;
- if (force || !this._item) {
- return this.services.change.force(item);
- }
- return this.services.change.diff(this._item, item);
- };
-
- return this.changeQueue = (this.changeQueue || Promise.resolve())
- .then(change, change)
- .then((item) => {
- this._update(item);
- return item;
- }, (e) => {
- this._update();
- return Promise.reject(e);
- });
- }
-
- equals(item) {
- return deepEquals(this._item, item);
- }
-
- _update(item = null) {
- this._item = item;
- this._store();
- }
-
- _restore() {
- this._item = this._storage.fetch();
- }
-
- _store() {
- this._storage.put(this._item);
- }
-
- }
-
- class ChangeService {
-
- constructor(services) {
- this.services = services;
- this.cache = {};
- }
-
- force(to) {
- const promise = Promise.resolve()
- .then(() => this._fraction(to.fraction))
- .then(() => this._skill(to.skill))
- .then(() => this._army(to.army))
- .then(() => this._inventory(to.inventory))
- .then(() => this._reset())
- .then(() => this._attribute(to.attribute))
- .then(() => to);
-
- return PromiseMDecorator(promise);
- }
-
- diff(from, to) {
- const fractionChanged = from.fraction !== to.fraction;
- const skillChanged = fractionChanged || !deepEquals(from.skill, to.skill);
- const armyChanged = fractionChanged || !deepEquals(from.army, to.army);
- const inventoryChanged = from.inventory !== to.inventory;
- const attributeChanged = !deepEquals(from.attribute, to.attribute);
-
- let serial = Promise.resolve();
- if (fractionChanged) {
- serial = serial.then(() => this._fraction(to.fraction, from.fraction))
- }
- if (skillChanged) {
- serial = serial.then(() => this._skill(to.skill))
- }
- if (armyChanged) {
- serial = serial.then(() => this._army(to.army))
- }
- if (inventoryChanged) {
- serial = serial.then(() => this._inventory(to.inventory))
- }
- if (attributeChanged) {
- serial = serial
- .then(() => this._reset())
- .then(() => this._attribute(to.attribute))
- }
- serial = serial.then(() => to);
-
- return PromiseMDecorator(serial);
- }
-
- _fraction(to, from) {
- to = this.services.fraction.map[to];
-
- let prepare = Promise.resolve();
-
- if (from) {
- from = this.services.fraction.map[from];
- } else {
- prepare = this.services.import.getFraction().then((id) => {
- from = this.services.fraction.map[id];
- })
- }
-
- const change = (data) => {
- return httpPlainRequest('FORM', '/castle.php', data)
- }
-
- return prepare.then(() => {
-
- if (from.fract !== to.fract) {
- let promise = change({ fract: to.fract });
- if (to.classid !== '0') {
- return promise.then(() => {
- return change({ classid: to.classid })
- });
- }
- return promise
- }
-
- if (from.classid !== to.classid) {
- return change({ classid: to.classid })
- }
-
- })
- }
-
- _skill(list) {
- let data = {
- rand: Math.random(),
- setstats: 1,
- }
-
- for (let i = 0; i < list.length; i++) {
- data[`param${i}`] = list[i];
- }
-
- return httpPlainRequest('FORM', '/skillwheel.php', data);
- }
-
- _army(list) {
- let data = {
- rand: Math.random(),
- }
-
- for (let i = 0; i < list.length; i++) {
- data[`countv${i+1}`] = list[i];
- }
-
- return httpPlainRequest('FORM', '/army_apply.php', data);
- }
-
- _inventory(id) {
- let struct = this.services.inventory.map[id];
- let data = {
- r: Date.now() + String(Math.random()).slice(2)
- };
- data[struct.type] = struct.value;
- return httpPlainRequest('GET', '/inventory.php', data);
- }
-
- _reset() {
- let resetLinkPromise = Promise.resolve(this.cache.resetLink);
-
- if (!this.cache.resetLink) {
- resetLinkPromise = httpPlainRequest('GET', '/home.php').then((html) => {
- let m = html.match(/shop\.php\?b=reset_tube&reset=2&sign=[0-9a-f]+/);
- if (!m) return null;
- return this.cache.resetLink = '/' + m[0];
- })
- }
-
- return resetLinkPromise.then((url) => (url ? httpPlainRequest('GET', url) : null));
- }
-
- _attribute(obj) {
- const getTotal = () => {
- return httpPlainRequest('GET', '/home.php').then((html) => {
- let m = html.match(/href="home\.php\?increase_all=knowledge"(?:.|\n)*?(\d+)\<\/td/);
- if (!m) return null;
- return parseInt(m[1]) || null;
- });
- }
-
- const increase = (name, count) => {
- let serial = Promise.resolve();
- for (let i = 0; i < count; i++) {
- serial = serial.then(() => httpPlainRequest('GET', `/home.php?increase=${name}`));
- }
- return serial;
- }
-
- const increaseAll = (name) => {
- return httpPlainRequest('GET', `/home.php?increase_all=${name}`);
- }
-
- const distribute = (total) => {
- total = total || 0;
-
- let list = [];
- for (let name of Object.keys(obj)) {
- list.push({ name, value: obj[name] })
- }
- list.sort((a, b) => a.value - b.value);
-
- let serial = Promise.resolve();
-
- let used = 0;
- list.slice(0, -1).forEach(({ name, value }) => {
- if (used >= total) return;
- if (value === 0) return;
-
- let v = Math.min(total - used, value);
- used += value;
- serial = serial.then(() => increase(name, v));
- });
-
- if (total > used) {
- let { name, value } = list[ list.length - 1 ];
- if (value > 0) {
- if (value < total - used) {
- serial = serial.then(() => increase(name, value));
- } else {
- serial = serial.then(() => increaseAll(name));
- }
- }
- }
-
- return serial;
- }
-
- return getTotal().then(distribute);
- }
-
- }
-
- class ImportService {
-
- constructor(services) {
- this.services = services;
- }
-
- getInventoryNamesIfAvailable() {
- if (location.pathname.match(/^\/inventory\.php/)) {
- let list = [];
- let nodes = document.querySelectorAll('a[href*="inventory.php?all_on"]');
- for (let node of nodes) {
- let [ _, type, value ] = node.getAttribute('href').match(/(all_on)=(\d)/);
- let name = node.innerText;
- list.push({
- type,
- value,
- name
- });
- }
- return list;
- }
- }
-
- getArmy() {
- return httpPlainRequest('GET', '/army.php').then((html) => {
- let m = html.match(/\<param name="FlashVars" value="param=\d+\|M([^"]+)/);
- if (!m) return null;
-
- let chunks = m[1].split(';M');
- let items = [];
-
- for (let chunk of chunks) {
- items.push( parseInt(chunk.split(':')[1].substr(57,3)) || 0 );
- }
-
- for (let i = items.length; i < this.services.army.iterator.length; i++) {
- items.push(0);
- }
-
- return items;
- });
- }
-
- getFraction() {
- return httpPlainRequest('GET', '/castle.php').then((html) => {
- let dict = {};
- for (let { fract, classid } of this.services.fraction.list) {
- if (!dict[fract]) {
- dict[fract] = {};
- }
- dict[fract][classid] = true;
- }
-
- const extractFract = () => {
- let m = html.match(/\<select name='fract'((?:.|[\r\n])+?)\<\/select/);
- if (!m) return null;
-
- let available = {};
- m[1].replace(/value=(\d)/g, (_, id) => {
- available[id] = true;
- });
-
- for (let id of Object.keys(dict)) {
- if (!available[id]) return id;
- }
- }
-
- const extractClassid = (fract) => {
- let m = html.match(/\<select name='classid'((?:.|[\r\n])+?)\<\/select/);
- if (!m) return null;
-
- let available = {};
- m[1].replace(/value=(\d)/g, (_, id) => {
- available[id] = true;
- });
-
- for (let id of Object.keys(dict[fract])) {
- if (!available[id]) return id;
- }
- }
-
- let fract = extractFract();
- if (!fract) return null;
-
- let classidList = Object.keys(dict[fract]);
- let classid;
-
- if (classidList.length === 1) {
- classid = classidList[0];
-
- } else {
- classid = extractClassid(fract);
- if (!classid) return null;
- }
-
- return `${fract}${classid}`
- })
- }
-
- getSkill() {
- return httpPlainRequest('GET', '/skillwheel.php').then((html) => {
- let m = html.match(/\<param name="FlashVars" value='param=.+?;builds=([^']+)/);
- if (!m) return null;
-
- let rows = m[1].split('$');
- let items = [];
-
- for (let r of rows) {
- let row = r.split('|');
- if (row.length != 10) continue;
-
- let id = row[0];
- let has = row[8];
-
- if (has === '1') {
- items.push(id);
- }
- }
-
- return items;
- })
- }
-
- }
-
- class FractionService {
-
- constructor() {
- this.list = [
- { fract: '1', classid: '0', name: 'Рыцарь' },
- { fract: '1', classid: '1', name: 'Рыцарь света' },
- { fract: '2', classid: '0', name: 'Некромант' },
- { fract: '2', classid: '1', name: 'Некромант - повелитель смерти' },
- { fract: '3', classid: '0', name: 'Маг' },
- { fract: '3', classid: '1', name: 'Маг-разрушитель' },
- { fract: '4', classid: '0', name: 'Эльф' },
- { fract: '4', classid: '1', name: 'Эльф-заклинатель' },
- { fract: '5', classid: '0', name: 'Варвар' },
- { fract: '5', classid: '1', name: 'Варвар крови' },
- { fract: '5', classid: '2', name: 'Варвар-шаман' },
- { fract: '6', classid: '0', name: 'Темный эльф' },
- { fract: '6', classid: '1', name: 'Темный эльф-укротитель' },
- { fract: '7', classid: '0', name: 'Демон' },
- { fract: '7', classid: '1', name: 'Демон тьмы' },
- { fract: '8', classid: '0', name: 'Гном' },
- { fract: '9', classid: '0', name: 'Степной варвар' }
- ];
-
- this.map = {};
-
- for (let item of this.list) {
- item.id = item.fract + item.classid;
- this.map[item.id] = item;
- }
- }
-
- get default() {
- return this.list[0];
- }
-
- }
-
- class InventoryService {
-
- constructor(services) {
- this.services = services;
- this._storage = new LocalStorageArrayDriver('BM_INVENTORY');
- this.loaded = false;
-
- this.list = [
- { type: 'all_off', value: '100', name: 'Снять все' },
- { type: 'all_on', value: '1', name: 'Набор 1' },
- { type: 'all_on', value: '2', name: 'Набор 2' },
- { type: 'all_on', value: '3', name: 'Набор 3' },
- { type: 'all_on', value: '4', name: 'Набор 4' },
- { type: 'all_on', value: '5', name: 'Набор 5' }
- ]
-
- this.map = {};
-
- for (let item of this.list) {
- item.id = item.type + item.value;
- this.map[item.id] = item;
- }
-
- this._restore();
- }
-
- _restore() {
- let list = this._storage.fetch();
-
- for (let item of list) {
- let id = item.type + item.value;
- if (this.map[id]) {
- this.map[id].name = item.name;
- }
- }
- }
-
- syncNamesIfAvailable() {
- let list = this.services.import.getInventoryNamesIfAvailable();
- if (list) {
- for (let { type, value, name } of list) {
- let id = type + value;
- if (this.map[id]) {
- this.map[id].name = name;
- }
- }
- this._storage.put(list);
- }
- }
-
- get default() {
- return this.list[0];
- }
-
- }
-
- class AttributeService {
-
- get list() {
- return Object.keys(this.default);
- }
-
- get default() {
- return {
- attack: 0,
- defence: 0,
- power: 0,
- knowledge: 0
- }
- }
-
- }
-
- class ArmyService {
-
- get iterator() {
- return this.default;
- }
-
- get default() {
- return [ 0, 0, 0, 0, 0, 0, 0 ]
- }
-
- }
-
-
-
- class SkillService {
-
- constructor() {
- this.table = [
- { id: "attack", name: "Нападение", list: [
- { id: "attack1", name: "Основы нападения", main: true },
- { id: "attack2", name: "Развитое нападение", main: true },
- { id: "attack3", name: "Искусное нападение", main: true },
- { id: "battle_frenzy", name: "Боевое безумие" },
- { id: "retribution", name: "Воздаяние" },
- { id: "nature_wrath", name: "Лесная ярость" },
- { id: "power_of_speed", name: "Мастерство скорости" },
- { id: "excruciating_strike", name: "Мощный удар" },
- { id: "archery", name: "Стрельба" },
- { id: "tactics", name: "Тактика" },
- { id: "cold_steel", name: "Холодная сталь" },
- ]}, { id: "defense", name: "Защита", list: [
- { id: "defense1", name: "Основы защиты", main: true },
- { id: "defense2", name: "Развитая защита", main: true },
- { id: "defense3", name: "Искусная защита", main: true },
- { id: "last_stand", name: "Битва до последнего" },
- { id: "stand_your_ground", name: "Глухая оборона" },
- { id: "preparation", name: "Готовность" },
- { id: "power_of_endurance", name: "Сила камня" },
- { id: "resistance", name: "Сопротивление" },
- { id: "protection", name: "Сопротивление магии" },
- { id: "vitality", name: "Стойкость" },
- { id: "evasion", name: "Уклонение" },
- ]}, { id: "luck", name: "Удача", list: [
- { id: "luck1", name: "Призрачная удача", main: true },
- { id: "luck2", name: "Большая удача", main: true },
- { id: "luck3", name: "Постоянная удача", main: true },
- { id: "magic_resistance", name: "Магическое сопротивление" },
- { id: "piercing_luck", name: "Пронзающая удача" },
- { id: "soldier_luck", name: "Солдатская удача" },
- { id: "warlock_luck", name: "Удачливый чародей" },
- { id: "swarming_gate", name: "Широкие врата ада" },
- { id: "elven_luck", name: "Эльфийская удача" },
- ]}, { id: "leadership", name: "Лидерство", list: [
- { id: "leadership1", name: "Основы лидерства", main: true },
- { id: "leadership2", name: "Развитое лидерство", main: true },
- { id: "leadership3", name: "Искусное лидерство", main: true },
- { id: "aura_of_swiftness", name: "Аура скорости" },
- { id: "divine_guidance", name: "Воодушевление" },
- { id: "battle_commander", name: "Лесной лидер" },
- { id: "recruitment", name: "Сбор войск" },
- { id: "empathy", name: "Сопереживание" },
- ]}, { id: "enlightenment", name: "Образование", list: [
- { id: "enlightenment1", name: "Начальное образование", main: true },
- { id: "enlightenment2", name: "Среднее образование", main: true },
- { id: "enlightenment3", name: "Высшее образование", main: true },
- { id: "graduate", name: "Выпускник" },
- { id: "wizard_reward", name: "Колдовская награда" },
- { id: "know_your_enemy", name: "Лесное коварство" },
- { id: "lord_of_the_undead", name: "Повелитель мёртвых" },
- { id: "intelligence", name: "Притяжение маны" },
- { id: "dark_revelation", name: "Тёмное откровение" },
- { id: "arcane_exaltation", name: "Хранитель тайного" },
- ]}, { id: "dark", name: "Магия Тьмы", list: [
- { id: "dark1", name: "Основы магии Тьмы", main: true },
- { id: "dark2", name: "Сильная магия Тьмы", main: true },
- { id: "dark3", name: "Искусная магия Тьмы", main: true },
- { id: "weakening_strike", name: "Ослабляющий удар" },
- { id: "fallen_knight", name: "Падший рыцарь" },
- { id: "master_of_pain", name: "Повелитель боли" },
- { id: "master_of_curses", name: "Повелитель проклятий" },
- { id: "master_of_mind", name: "Повелитель разума" },
- ]}, { id: "destructive", name: "Магия Хаоса", list: [
- { id: "destructive1", name: "Основы магии Хаоса", main: true },
- { id: "destructive2", name: "Сильная магия Хаоса", main: true },
- { id: "destructive3", name: "Искусная магия Хаоса", main: true },
- { id: "searing_fires", name: "Иссушающее пламя" },
- { id: "sap_magic", name: "Истощение магии" },
- { id: "fiery_wrath", name: "Огненная ярость" },
- { id: "master_of_storms", name: "Повелитель бурь" },
- { id: "master_of_fire", name: "Повелитель огня" },
- { id: "master_of_ice", name: "Повелитель холода" },
- { id: "secrets_of_destruction", name: "Тайны хаоса" },
- ]}, { id: "light", name: "Магия Света", list: [
- { id: "light1", name: "Основы магии Света", main: true },
- { id: "light2", name: "Сильная магия Света", main: true },
- { id: "light3", name: "Искусная магия Света", main: true },
- { id: "master_of_blessings", name: "Дарующий благословение" },
- { id: "master_of_abjuration", name: "Дарующий защиту" },
- { id: "fire_resistance", name: "Защита от огня" },
- { id: "master_of_wrath", name: "Повелитель ярости" },
- { id: "twilight", name: "Сумерки" },
- { id: "refined_mana", name: "Тайны света" },
- ]}, { id: "summon", name: "Магия Природы", list: [
- { id: "summon1", name: "Основы магии Природы", main: true },
- { id: "summon2", name: "Сильная магия Природы", main: true },
- { id: "summon3", name: "Искусная магия Природы", main: true },
- { id: "master_of_conjuration", name: "Повелитель волшебства" },
- { id: "master_of_life", name: "Повелитель жизни" },
- { id: "master_of_obstacles", name: "Повелитель препятствий" },
- ]}, { id: "sorcery", name: "Чародейство", list: [
- { id: "sorcery1", name: "Основы чародейства", main: true },
- { id: "sorcery2", name: "Развитое чародейство", main: true },
- { id: "sorcery3", name: "Искусное чародейство", main: true },
- { id: "mana_regeneration", name: "Восполнение маны" },
- { id: "boneward", name: "Защита от магии хаоса" },
- { id: "erratic_mana", name: "Изменчивая мана" },
- { id: "magic_insight", name: "Мудрость" },
- { id: "arcane_brillance", name: "Тайное откровение" },
- { id: "arcane_excellence", name: "Тайное преимущество" },
- { id: "arcane_training", name: "Тайные знания" },
- ]}, { id: "special", name: "Фракция", list: [
- { id: "hellfire", name: "Адское пламя" },
- { id: "magic_mirror", name: "Волшебное зеркало" },
- { id: "runeadv", name: "Дополнительные руны" },
- { id: "necr_soul", name: "Духовная связь" },
- { id: "zakarrow", name: "Заколдованная стрела" },
- { id: "nomagicdamage", name: "Контроль магии" },
- { id: "elf_shot", name: "Ливень из стрел" },
- { id: "benediction", name: "Молитва" },
- { id: "knight_mark", name: "Надзор" },
- { id: "memoryblood", name: "Память нашей Крови" },
- { id: "cre_master", name: "Повелитель существ" },
- { id: "consumecorpse", name: "Поглощение трупов" },
- { id: "barb_skill", name: "Пробивающая мощь" },
- { id: "powerraise", name: "Совершенное Поднятие мертвецов" },
- { id: "dark_blood", name: "Тёмная кровь" },
- { id: "dark_power", name: "Тёмная сила" },
- { id: "save_rage", name: "Упорство ярости" },
- ]}
- ];
-
- this.map = {};
- for (let section of this.table) {
- for (let item of section.list) {
- this.map[item.id] = item;
- }
- }
- }
-
- get default() {
- return [];
- }
-
- }
-
-
- styles(`
- .mb-editor-name__box {
- margin: 5px 0 0 0;
- }
- .mb-editor-name__block-label {
- display: inline-block;
- width: 110px;
- }
- .mb-editor-name__block-input {
- width: 526px;
- }
- `);
- class EditorNameComponent {
-
- view({ attrs: { value, onchange } }) {
-
- return m('.mb-editor-name__box', [
- m('.mb-editor-name__block', [
- m('.mb-editor-name__block-label', 'Название:'),
- m('input.mb-editor-name__block-input', { oninput: m.withAttr('value', onchange), value })
- ])
- ])
- }
- }
-
-
- styles(`
- .mb-editor-fraction__box {
- margin: 5px 0;
- }
- .mb-editor-fraction__block-label {
- display: inline-block;
- width: 110px;
- }
- .mb-editor-fraction__import-button {
- display: inline-block;
- margin-left: 4px;
- cursor: pointer;
- }
- .mb-editor-fraction__import-button:hover {
- text-decoration: underline;
- }
- .mb-editor-fraction__import-button--importing {
- animation: mb-fraction-import-animation 1s infinite linear;
- cursor: wait;
- }
- .mb-editor-fraction__import-button--importing:hover {
- text-decoration: none;
- }
- @keyframes mb-fraction-import-animation {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(359deg); }
- }
- `);
- class EditorFractionComponent {
-
- constructor({ attrs: { services }}) {
- this.services = services;
- }
-
- view({ attrs: { value, onchange } }) {
-
- const importAction = () => {
- if (this.importing) return;
-
- this.importing = true;
-
- const finish = () => { this.importing = false };
-
- this.services.import.getFraction()
- .then((val) => {
- if (val) {
- onchange(val);
- }
- })
- .then(finish, finish);
- };
-
- const importButton = () => {
- return m('.mb-editor-fraction__import-button', { onclick: importAction, class: this.importing ? 'mb-editor-fraction__import-button--importing' : '' }, '<')
- };
-
- return m('.mb-editor-fraction__box', [
- m('.mb-editor-fraction__block', [
- m('.mb-editor-fraction__block-label', 'Фракция:'),
- m('select',
- { oninput: m.withAttr('value', onchange), value: value },
- this.services.fraction.list.map(({ id, name }) => {
- return m('option', { key: id, value: id }, name);
- })),
- importButton()
- ])
- ])
- }
- }
-
- styles(`
- .mb-editor-inventory__box {
- margin: 5px 0;
- }
- .mb-editor-inventory__block-label {
- display: inline-block;
- width: 110px;
- }
- `);
- class EditorInventoryComponent {
-
- constructor({ attrs: { services }}) {
- this.services = services;
- }
-
- view({ attrs: { value, onchange } }) {
-
- return m('.mb-editor-inventory__box', [
- m('.mb-editor-inventory__block', [
- m('.mb-editor-inventory__block-label', 'Набор оружия:'),
- m('select',
- { oninput: m.withAttr('value', onchange), value: value },
- this.services.inventory.list.map(({ id, name }) => {
- return m('option', { key: id, value: id }, name);
- }))
- ])
- ])
- }
- }
-
- styles(`
- .mb-editor-attribute__box {
- margin: 5px 0;
- }
- .mb-editor-attribute__block-label {
- display: inline-block;
- width: 110px;
- }
- .mb-editor-attribute__block-input {
- width: 20px;
- display: inline-block;
- }
- `);
- class EditorAttributeComponent {
-
- constructor({ attrs: { services }}) {
- this.services = services;
- }
-
- view({ attrs: { value, onchange } }) {
-
- let changeAction = (name, val) => {
- onchange(Object.assign({}, value, { [name]: parseInt(val) || 0 }));
- }
-
- return m('.mb-editor-attribute__box', [
- m('.mb-editor-attribute__block', [
- m('.mb-editor-attribute__block-label', 'Аттрибуты:'),
- this.services.attribute.list.map((name) => {
- return m('input.mb-editor-attribute__block-input',
- { key: name, oninput: m.withAttr('value', (value) => { changeAction(name, value) }), value: value[name] || 0 });
- })
- ])
- ])
- }
- }
-
- styles(`
- .mb-editor-army__box {
- margin: 5px 0;
- }
- .mb-editor-army__block-label {
- display: inline-block;
- width: 110px;
- }
- .mb-editor-army__block-controls {
- display: inline-block;
- }
- .mb-editor-army__block-input {
- width: 24px;
- display: inline-block;
- }
- .mb-editor-army__block-input:nth-child(1),
- .mb-editor-army__block-input:nth-child(2),
- .mb-editor-army__block-input:nth-child(3),
- .mb-editor-army__block-input:nth-child(4){
- width: 30px;
- }
- .mb-editor-army__block-import-button {
- margin-left: 4px;
- display: inline-block;
- cursor: pointer;
- }
- .mb-editor-army__block-import-button:hover {
- text-decoration: underline;
- }
- .mb-editor-army__block-import-button--importing {
- animation: mb-army-import-animation 1s infinite linear;
- cursor: wait;
- }
- .mb-editor-army__block-import-button--importing:hover {
- text-decoration: none;
- }
- @keyframes mb-army-import-animation {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(359deg); }
- }
- `);
- class EditorArmyComponent {
-
- constructor({ attrs: { services }}) {
- this.services = services;
- }
-
- view({ attrs: { value, onchange } }) {
-
- const changeAction = (index, val) => {
- let data = value.slice();
- data[index] = parseInt(val) || 0;
- onchange(data);
- };
-
- const importAction = () => {
- if (this.importing) return;
-
- this.importing = true;
-
- const finish = () => { this.importing = false };
-
- this.services.import.getArmy()
- .then((val) => {
- if (val) {
- onchange(val);
- }
- })
- .then(finish, finish);
- };
-
- const importButton = () => {
- return m('.mb-editor-army__block-import-button', { onclick: importAction, class: this.importing ? 'mb-editor-army__block-import-button--importing' : '' }, '<')
- };
-
- return m('.mb-editor-army__box', [
- m('.mb-editor-army__block', [
- m('.mb-editor-army__block-label', 'Армия:'),
- m('.mb-editor-army__block-controls',
- this.services.army.iterator.map((_, index) => {
- return m('input.mb-editor-army__block-input',
- { key: index, oninput: m.withAttr('value', (value) => { changeAction(index, value) }), value: value[index] || 0 })
- })
- ),
- importButton()
- ])
- ])
- }
- }
-
- styles(`
- .mb-editor-skill__box {
- margin: 5px 0;
- }
- .mb-editor-skill__select {
- display: inline-block;
- }
- .mb-editor-skill__option--main {
- font-weight: bold;
- }
- .mb-editor-skill__list-item-name {
- display: inline-block;
- margin-right: 4px;
- }
- .mb-editor-skill__list-item-button {
- display: inline-block;
- cursor: pointer;
- }
- .mb-editor-skill__list-item-button:hover {
- text-decoration: underline;
- }
- .mb-editor-skill__import-button {
- display: inline-block;
- margin-left: 4px;
- cursor: pointer;
- }
- .mb-editor-skill__import-button:hover {
- text-decoration: underline;
- }
- .mb-editor-skill__import-button--importing {
- animation: mb-skill-import-animation 1s infinite linear;
- cursor: wait;
- }
- .mb-editor-skill__import-button--importing:hover {
- text-decoration: none;
- }
- @keyframes mb-skill-import-animation {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(359deg); }
- }
- `);
- class EditorSkillComponent {
-
- constructor({ attrs: { services }}) {
- this.services = services;
- }
-
- view({ attrs: { value, onchange } }) {
-
- const removeAction = (id) => {
- let p = value.indexOf(id);
- onchange(value.slice(0, p).concat( value.slice(p + 1) ));
- };
-
- const importAction = () => {
- if (this.importing) return;
-
- this.importing = true;
-
- const finish = () => { this.importing = false };
-
- this.services.import.getSkill()
- .then((val) => {
- if (val) {
- onchange(val);
- }
- })
- .then(finish, finish);
- };
-
- const importButton = () => {
- return m('.mb-editor-skill__import-button', { onclick: importAction, class: this.importing ? 'mb-editor-skill__import-button--importing' : '' }, '<')
- };
-
- const list = () => {
- return m('.mb-editor-skill__list', value.map((id) => {
- return m('.mb-editor-skill__list-item', [
- m('.mb-editor-skill__list-item-name', this.services.skill.map[id].name),
- m('.mb-editor-skill__list-item-button', { onclick: () => { removeAction(id) } }, '[х]')
- ])
- }))
- }
-
- const select = () => {
- return m('select.mb-editor-skill__select',
- { oninput: m.withAttr('value', (id) => { onchange(value.concat(id)) }) }, [
- m('option', 'Навыки:'),
- this.services.skill.table.map(({ id, name, list }) => {
- return m('optgroup', { key: id, label: name }, list.map(({ id, name, main }) => {
- if (value.indexOf(id) !== -1) return null;
- return m('option', { key: id, value: id, class: main ? 'mb-editor-skill__option--main': '' }, name)
- }))
- })
- ])
- };
-
- return m('.mb-editor-skill__box', [
- m('.mb-editor-skill__select-block', [
- select(),
- importButton()
- ]),
- list()
- ])
- }
- }
-
-
- styles(`
- .mb-editor__section {
- padding: 5px 6px;
- display: table;
- }
- .mb-editor__buttons {
- padding: 3px 5px 4px 5px;
- border-top: 1px #5D413A solid;
- background: #F5F3EA;
- height: 16px;
- }
- .mb-editor__save-button {
- font-weight: bold;
- cursor: pointer;
- display: inline-block;
- margin-right: 8px;
- }
- .mb-editor__cancel-button {
- cursor: pointer;
- display: inline-block;
- }
- .mb-editor__close-button {
- cursor: pointer;
- display: inline-block;
- }
- .mb-editor__save-button:hover,
- .mb-editor__cancel-button:hover,
- .mb-editor__close-button:hover {
- text-decoration: underline;
- }
- .mb-editor__section-column {
- float: left;
- margin-right: 30px;
- }
- .mb-editor__section-column:last-child {
- margin-right: 0;
- }
- `);
- class EditorComponent {
-
- constructor({ attrs: { services }}) {
- this.services = services;
- }
-
- _updateOriginItem(item) {
- if (this.originItem !== item) {
- this.originItem = item;
- this.item = deepCopy(item);
- }
- }
-
- cancel() {
- this.item = deepCopy(this.originItem);
- }
-
- view({ attrs: { item: originItem, onchange, onclose } }) {
- this._updateOriginItem(originItem);
-
- let item = this.item;
- let services = this.services;
-
- const closeAction = () => {
- onclose();
- }
-
- const buttons = () => {
- let controls;
- if (deepEquals(this.item, originItem)) {
- controls = m('.mb-editor__close-button', { onclick: closeAction }, 'Закрыть');
-
- } else {
- controls = [
- m('.mb-editor__save-button', { onclick: () => { onchange(item) }}, 'Сохранить'),
- m('.mb-editor__cancel-button', { onclick: this.cancel.bind(this) }, 'Отменить')
- ];
- }
- return m('.mb-editor__buttons', controls);
- };
-
-
- return m('.mb-editor__box', [
- m('.mb-editor__section', [
- m(EditorNameComponent, { value: item.name, onchange: (value) => { item.name = value } }),
- m('.mb-editor__section-column', [
- m(EditorFractionComponent, { services, value: item.fraction, onchange: (value) => { item.fraction = value } }),
- m(EditorInventoryComponent, { services, value: item.inventory, onchange: (value) => { item.inventory = value } }),
- m(EditorAttributeComponent, { services, value: item.attribute, onchange: (value) => { item.attribute = value } }),
- m(EditorArmyComponent, { services, value: item.army, onchange: (value) => { item.army = value } }),
- ]),
- m('.mb-editor__section-column', [
- m(EditorSkillComponent, { services, value: item.skill, onchange: (value) => { item.skill = value } }),
- ])
- ]),
- buttons()
- ])
- }
-
- }
-
-
-
-
- styles(`
- .mb-export-popup__box {
- position: absolute;
- top: 2px;
- left: 2px;
- border: 1px #5D413A solid;
- }
- .mb-export-popup__header {
- background: #F5F3EA;
- border-bottom: 1px #5D413A solid;
- text-align: right;
- }
- .mb-export-popup__close-button {
- display: inline-block;
- cursor: pointer;
- color: rgb(89, 44, 8);
- padding: 4px 6px;
- }
- .mb-export-popup__close-button:hover {
- text-decoration: underline;
- }
- .mb-export-popup__body {
- background: #fff;
- }
- .mb-export-popup__body textarea {
- resize: none;
- box-sizing: border-box;
- width: 580px;
- height: 300px;
- font-size: 11px;
- padding: 3px 5px;
- margin: 0;
- border: none;
- }
- .mb-export-popup__footer {
- padding: 3px 5px 4px 5px;
- border-top: 1px #5D413A solid;
- background: #F5F3EA;
- height: 16px;
- }
- `);
- class ExportPopup {
-
- constructor({ attrs: { services }}) {
- this.services = services;
- }
-
- oncreate({ dom, attrs: { onclose } }) {
- this.releaseClickOutEventListener = nextTickAddClickOutEventListener(dom, onclose);
- }
-
- onbeforeremove() {
- this.releaseClickOutEventListener();
- }
-
- view({ attrs: { onclose }}) {
- return m('.mb-export-popup__box', [
- m('.mb-export-popup__header', [
- m('.mb-export-popup__close-button', { onclick: onclose }, 'Закрыть')
- ]),
- m('.mb-export-popup__body', [
- m('textarea', { readonly: true, value: this.services.manager.serialize() })
- ]),
- m('.mb-export-popup__footer')
- ])
- }
-
- };
-
- styles(`
- .mb-import-popup__box {
- position: absolute;
- top: 2px;
- left: 2px;
- border: 1px #5D413A solid;
- }
- .mb-import-popup__header {
- background: #F5F3EA;
- border-bottom: 1px #5D413A solid;
- text-align: right;
- }
- .mb-import-popup__close-button,
- .mb-import-popup__import-button {
- display: inline-block;
- cursor: pointer;
- color: rgb(89, 44, 8);
- padding: 4px 6px;
- }
- .mb-import-popup__close-button:hover,
- .mb-import-popup__import-button:hover {
- text-decoration: underline;
- }
- .mb-import-popup__import-button {
- font-weight: bold;
- }
- .mb-import-popup__body {
- background: #fff;
- }
- .mb-import-popup__body textarea {
- resize: none;
- box-sizing: border-box;
- width: 580px;
- height: 300px;
- font-size: 11px;
- padding: 3px 5px;
- margin: 0;
- border: none;
- }
- .mb-import-popup__footer {
- border-top: 1px #5D413A solid;
- background: #F5F3EA;
- }
- .mb-import-popup__import-error-message {
- color: red;
- margin-left: 10px;
- display: inline-block;
- padding: 4px 6px;
- }
- `);
- class ImportPopup {
-
- constructor({ attrs: { services }}) {
- this.services = services;
- this.invalid = false;
- }
-
- oncreate({ dom, attrs: { onclose } }) {
- this.releaseClickOutEventListener = nextTickAddClickOutEventListener(dom, onclose);
- }
-
- onbeforeremove() {
- this.releaseClickOutEventListener();
- }
-
- view({ attrs: { onclose, onimport }}) {
-
- const onchange = (value) => {
- this.data = value;
- this.invalid = false;
- }
-
- const importAction = () => {
- if (this.services.manager.unserialize(this.data)) {
- this.data = null;
- onimport();
- } else {
- this.invalid = true;
- }
- }
-
- return m('.mb-import-popup__box', [
- m('.mb-import-popup__header', [
- m('.mb-import-popup__close-button', { onclick: onclose }, 'Закрыть')
- ]),
- m('.mb-import-popup__body', [
- m('textarea', { value: this.data, oninput: m.withAttr('value', onchange) })
- ]),
- m('.mb-import-popup__footer', [
- m('.mb-import-popup__import-button', { onclick: importAction }, 'Импорт'),
- this.invalid
- ? m('.mb-import-popup__import-error-message', 'Некорректный формат данных')
- : null
- ])
- ])
- }
-
- };
-
- styles(`
- .mb-manager__box {
- width: 650px;
- border: 1px #5D413A solid;
- background: #fff;
- position: absolute;
- left: 3px;
- top: 3px;
- z-index: 3;
- box-sizing: border-box;
- }
- .mb-manager__header {
- background: #F5F3EA;
- border-bottom: 1px #5D413A solid;
- position: relative;
- display: flex;
- align-items: center;
- justify-content: space-between;
- }
- .mb-manager__header-button {
- display: inline-block;
- cursor: pointer;
- color: rgb(89, 44, 8);
- padding: 4px 0 4px 6px;
- }
- .mb-manager__header-button:last-child {
- padding-right: 6px;
- }
- .mb-manager__header-button:hover {
- text-decoration: underline;
- }
- .mb-manager__header-space {
- width: 20px;
- display: inline-block;
- }
- .mb-manager__list {
- max-height: 72px;
- overflow: auto;
- border-bottom: 1px #5D413A solid;
- margin-bottom: -1px;
- white-space: nowrap;
- }
- .mb-manager__list-item {
- padding: 0 6px;
- cursor: pointer;
- margin: 4px 0;
- display: table;
- }
- .mb-manager__list-item:hover {
- text-decoration: underline;
- }
- .mb-manager__list-item--selected {
- color: rgb(255, 0, 0);
- text-decoration: underline;
- }
- .mb-manager__list-empty {
- text-align: center;
- border-bottom: 1px #5D413A solid;
- padding: 15px 0;
- margin-bottom: -1px;
- }
- .mb-manager__confirm-remove {
- height: 72px;
- display: flex;
- align-items: center;
- justify-content: center;
- flex-direction: column;
- }
- .mb-manager__confirm-remove-buttons {
- margin-top: 7px;
- }
- .mb-manager__confirm-remove-button {
- display: inline-block;
- margin: 4px 4px;
- cursor: pointer;
- }
- .mb-manager__confirm-remove-button:hover {
- text-decoration: underline;
- }
- .mb-manager__confirm-remove-button--no {
- font-weight: bold;
- }
- .mb-manager__confirm-remove-button:hover:not(.mb-manager__confirm-remove-button--no) {
- color: red;
- }
- .mg-manager__body {
- margin-top: 1px;
- }
- `);
- class ManagerComponent {
-
- constructor({ attrs: { services }}) {
- this.services = services;
-
- this._initSelected();
- this.exportPopup = false;
- this.importPopup = false;
- }
-
- _initSelected() {
- let current = this.services.current.item;
- if (current) {
- let { founded, index } = this.services.manager.searchEquals(current);
- if (founded) {
- this.selected = this.services.manager.items[index];
- return;
- }
- }
- this.selected = this.services.manager.items[0];
- }
-
- createNew() {
- this.selected = this.services.manager.createNew();
- }
-
- selectItem(item) {
- this.selected = item;
- }
-
- removeSelected() {
- this.confirmRemove = true;
- }
-
- confirmRemoveOk() {
- this.selected = this.services.manager.remove(this.selected);
- this.confirmRemove = false;
- }
-
- confirmRemoveCancel() {
- this.confirmRemove = false;
- }
-
- duplicateSelected() {
- this.selected = this.services.manager.duplicate(this.selected);
- }
-
- updateItem(item) {
- this.selected = this.services.manager.update(item);
- }
-
- view({ attrs: { onclose } }) {
-
- const closeAction = () => {
- onclose();
- };
-
- const exportCloseAction = () => {
- this.exportPopup = false;
- };
-
- const importCloseAction = () => {
- this.importPopup = false;
- };
-
- const importAction = () => {
- this.importPopup = false;
- this.selected = null;
- };
-
- const headerLeft = () => {
- let controls = [];
-
- if (!this.confirmRemove) {
- controls.push(
- m('.mb-manager__header-button', { onclick: this.createNew.bind(this) }, 'Новый')
- );
-
- if (this.selected) {
- controls.push(
- m('.mb-manager__header-button', { onclick: this.duplicateSelected.bind(this) }, 'Копия'),
- m('.mb-manager__header-button', { onclick: this.removeSelected.bind(this) }, 'Удалить')
- )
- }
- }
-
- return m('.mb-manager__header-left', controls);
- };
-
- const headerRight = () => {
- let controls = [];
- if (!this.confirmRemove) {
- if (this.services.manager.items.length > 0) {
- controls.push(
- m('.mb-manager__header-button', { onclick: () => { this.exportPopup = true } }, 'Экспорт')
- )
- }
- controls.push(
- m('.mb-manager__header-button', { onclick: () => { this.importPopup = true } }, 'Импорт'),
- m('.mb-manager__header-space')
- )
- }
- controls.push(
- m('.mb-manager__header-button', { onclick: closeAction }, 'Закрыть')
- )
-
- return m('.mb-manager__header-right', controls);
- };
-
- const confirmRemove = () => {
- if (!this.confirmRemove) return null;
- return m('.mb-manager__confirm-remove', [
- m('.mb-manager__confirm-remove-message', [
- `Удалить "${this.selected.name}"?`
- ]),
- m('.mb-manager__confirm-remove-buttons', [
- m('.mb-manager__confirm-remove-button.mb-manager__confirm-remove-button--no', { onclick: this.confirmRemoveCancel.bind(this) }, 'Нет'),
- m('.mb-manager__confirm-remove-button', { onclick: this.confirmRemoveOk.bind(this) }, 'Да')
- ]),
- ])
- };
-
- const list = () => {
- if (this.confirmRemove) return null;
- let items = this.services.manager.items;
-
- if (items.length === 0) {
- return m('.mb-manager__list-empty', 'Список пуст')
- }
- return m('.mb-manager__list', items.map((item) => {
- return m('.mb-manager__list-item', {
- key: item.id,
- class: (this.selected || {}).id === item.id ? 'mb-manager__list-item--selected' : '',
- onclick: () => { this.selectItem(item) }
- }, item.name)
- }))
- };
-
- const body = () => {
- if (this.confirmRemove) return null;
- if (!this.selected) return null;
-
- return m('.mb-manager__body', [
- m(EditorComponent, { services: this.services, item: this.selected, onchange: this.updateItem.bind(this), onclose: closeAction })
- ]);
- };
-
- const popups = () => {
- if (this.confirmRemove) return null;
-
- return [
- this.exportPopup
- ? m(ExportPopup, { services: this.services, onclose: exportCloseAction })
- : null,
- this.importPopup
- ? m(ImportPopup, { services: this.services, onclose: importCloseAction, onimport: importAction })
- : null
- ]
- }
-
- return m('.mb-manager__box', [
- m('.mb-manager__header', [
- headerLeft(),
- headerRight()
- ]),
- confirmRemove(),
- list(),
- body(),
- popups(),
- ])
- }
- }
-
- styles(`
- .mb-selector__handler {
- display: flex;
- cursor: pointer;
- }
- .mb-selector__handler--changing {
- cursor: wait;
- }
- .mb-selector__info {
- padding: 2px 6px 4px 5px;
- background: #6b6b69;
- color: #f5c137;
- white-space: nowrap;
- border: 1px solid #f5c137;
- border-left: none;
- }
- .mb-selector__info-error {
- color: red;
- }
- .mb-selector__triangle-box {
- background: #6b6b69;
- color: #f5c137;
- border: 1px solid #f5c137;
- border-left: none;
- padding: 2px 8px 4px 5px;
- box-sizing: border-box;
- position: relative;
- }
- .mb-selector__triangle-box:before {
- content: "\\00a0";
- }
- .mb-selector__triangle {
- width: 0;
- height: 0;
- border-left: 5px solid transparent;
- border-right: 5px solid transparent;
- border-top: 5px solid #f5c137;
- position: absolute;
- left: 3px;
- top: 8px;
- }
- .mb-selector__triangle--up {
- transform: rotate(180deg);
- }
- .mb-selector__list-handler {
- z-index: 3;
- position: relative;
- }
- .mb-selector__list-box {
- position: absolute;
- top: 0;
- left: 0;
- border: 1px #5D413A solid;
- background: #fff;
- }
- .mb-selector__list-item {
- padding: 0 6px;
- cursor: pointer;
- margin: 4px 0;
- display: table;
- white-space: nowrap;
- }
- .mb-selector__list-item:hover .mb-selector__list-item-name {
- text-decoration: underline;
- }
- .mb-selector__list-item-name--current {
- color: rgb(255, 0, 0);
- text-decoration: underline;
- cursor: default;
- }
- .mb-selector__list-item-name {
- display: inline-block;
- }
- .mb-selector__list-item-force {
- display: inline-block;
- margin-left: 5px;
- }
- .mb-selector__list-item-force:hover {
- text-decoration: underline;
- }
- .mb-selector__list-footer {
- display: block;
- border-top: 1px #5D413A solid;
- padding: 4px 6px;
- margin: 0;
- background: #F5F3EA;
- }
- .mb-selector__list-button-cancel {
- cursor: pointer;
- display: inline-block;
- }
- .mb-selector__list-button-cancel:hover {
- text-decoration: underline;
- }
- `);
- class SelectorComponent {
-
- constructor({ attrs: { services }}) {
- this.services = services;
- this.dropped = false;
- this.changing = false;
- this.error = false;
-
- }
-
- oncreate({ dom }) {
- this.releaseClickOutEventListener = addClickOutEventListener(dom, () => {
- this.dropped = false;
- });
- }
-
- onbeforeremove() {
- this.releaseClickOutEventListener();
- }
-
- drop() {
- if (this.changing) return;
- this.dropped = !this.dropped;
- }
-
- view() {
- let items = this.services.manager.items;
- if (!items.length) return null;
-
- let current = this.services.current.item;
-
- const selectAction = (item, force) => {
- if (item === current && !force) return;
-
- this.dropped = false;
- this.changing = true;
-
- this.services.current.change(item, force)
- .then(() => {
- this.changing = false;
- this.error = false;
- }, (e) => {
- console.error(e);
- this.changing = false;
- this.error = true;
- });
- };
-
- const list = () => {
- if (!this.dropped) return null;
-
- const box = m('.mb-selector__list-box', [
- m('.mb-selector__list',
- items.map((item) => {
- return m('.mb-selector__list-item', [
- m('.mb-selector__list-item-name',
- this.services.current.equals(item)
- ? { class: 'mb-selector__list-item-name--current' }
- : { onclick: () => { selectAction(item) } },
- item.name),
- m('.mb-selector__list-item-force', { onclick: () => { selectAction(item, true) }}, '[*]')
- ])
- })),
- current
- ? m('.mb-selector__list-footer',
- m('.mb-selector__list-button-cancel', { onclick: () => { selectAction(null); } }, 'Сбросить'))
- : null,
- ]);
-
- return m('.mb-selector__list-handler', box);
- };
-
- const info = () => {
- if (!this.changing && !current && !this.error) return null;
-
- const text = () => {
- if (this.changing) {
- return 'Смена билда...'
- } else if (this.error) {
- return m('.mb-selector__info-error', 'Ошибка смены билда!')
- } else {
- return [
- this.services.current.isExpired() ? '*' : '',
- current.name
- ]
- }
- };
-
- return m('.mb-selector__info', text());
- };
-
- return m('.mb-selector__box', [
- m('.mb-selector__handler', { onclick: this.drop.bind(this), class: this.changing ? 'mb-selector__handler--changing' : '' }, [
- info(),
- m('.mb-selector__triangle-box',
- m('.mb-selector__triangle', { class: this.dropped ? 'mb-selector__triangle--up' : '' }))
- ]),
- list()
- ])
- }
-
- }
-
-
- styles(`
- .mb-app__handler {
- display: flex;
- }
- .mb-app__handler-editor-button {
- background: #6b6b69;
- color: #f5c137;
- border: 1px solid #f5c137;
- padding: 2px 6px 4px 6px;
- cursor: pointer;
- }
- `);
- class AppComponent {
-
- constructor() {
- this.manager = false;
- this.services = new ServiceContainer();
-
- this.services.inventory.syncNamesIfAvailable();
- }
-
- view() {
- return m('.mb-app__box', [
- m('.mb-app__handler', [
- m('.mb-app__handler-editor-button',
- { onclick: () => { this.manager = true } },
- '+'),
- m(SelectorComponent, { services: this.services })
- ]),
- this.manager
- ? m(ManagerComponent, { services: this.services, onclose: () => { this.manager = false } })
- : null
- ]);
- }
- }
-
-
- function mount() {
- let container = document.querySelector('body table table td');
- if (!container) return
-
- let checkAllowedPage = document.querySelector('a[href*="home.php"]');
- if (!checkAllowedPage) return;
-
- let root = document.createElement('div');
- root.style.position = 'absolute';
- root.style.top = '0';
- root.style.left = '0';
-
- container.style.position = 'relative';
- container.appendChild(root);
- m.mount(root, AppComponent);
- }
-
- function styles(content = null, flush = false) {
- let task = styles.task || {};
-
- if (content) {
- if (task.scheduled) {
- task.content += content;
- }
- else {
- let task = styles.task = {
- content,
- scheduled: true
- }
- task.timer = setTimeout(finish, 0, task)
- }
- }
-
- if (flush && task.scheduled) {
- clearInterval(task.timer);
- finish(task);
- }
-
- function finish(task) {
- let head = document.querySelector('head');
- head.insertAdjacentHTML('beforeEnd',
- `<style type="text/css">${task.content}</style>`);
- task.scheduled = false;
- }
- }
-
- function uniqid() {
- return Date.now().toString(36) + Math.random().toString(36).slice(1);
- }
-
- function deepCopy(value) {
- if (!value) return value;
- if (value instanceof Array) {
- return value.map(deepCopy);
- }
- if (typeof value === 'object') {
- let obj = {};
- for (let key of Object.keys(value)) {
- obj[key] = deepCopy(value[key])
- }
- return obj;
- }
- return value;
- }
-
- function deepEquals(a, b) {
- if (a === b) return true;
- if (a instanceof Array && b instanceof Array) {
- if (a.length !== b.length) return false;
- for (let i = 0; i < a.length; i++) {
- if (!deepEquals(a[i], b[i])) return false;
- }
- return true;
- }
- if (!a || !b) return false;
- if (typeof a === 'object' && typeof b === 'object') {
- let keys = Object.keys(a);
- if (keys.length !== Object.keys(b).length) return false;
- for (let key of keys) {
- if (!b.hasOwnProperty(key)) return false;
- if (!deepEquals(a[key], b[key])) return false;
- }
- return true;
- }
- return false;
- }
-
- function addClickOutEventListener(dom, fn) {
- const listener = (event) => {
- let node = event.target;
- while(node && node.parentNode) {
- if (node === dom) {
- return;
- }
- node = node.parentNode;
- }
-
- fn();
- m.redraw();
- };
-
- const body = document.body;
- body.addEventListener('click', listener);
- return () => {
- body.removeEventListener('click', listener);
- }
-
- }
-
- function nextTickAddClickOutEventListener(dom, fn) {
-
- let releaseEventListener = null;
- let timeout = setTimeout(() => {
- timeout = null;
- releaseEventListener = addClickOutEventListener(dom, fn);
- });
-
- return () => {
- if (timeout) clearTimeout(timeout);
- if (releaseEventListener) releaseEventListener();
- }
- }
-
- class LocalStorageDriver {
-
- constructor(key) {
- this.key = key;
- }
-
- fetch() {
- let text = localStorage.getItem(this.key);
- let data;
- try {
- data = JSON.parse(text);
- }
- catch(e) {
- data = null;
- }
- return data;
- }
-
- put(data) {
- localStorage.setItem(this.key, JSON.stringify(data));
- }
-
- }
-
- class LocalStorageArrayDriver extends LocalStorageDriver {
-
- fetch() {
- let data = super.fetch();
- if (!Array.isArray(data)) {
- data = [];
- }
- return data;
- }
-
- }
-
- function PromiseMDecorator(promise) {
- const proxyWithRedraw = (data) => {
- setTimeout(m.redraw.bind(m));
- return data;
- }
- return promise.then(
- proxyWithRedraw,
- (data) => proxyWithRedraw(Promise.reject(data))
- );
- }
-
- function httpPlainRequest(method, url, data) {
- if (method === 'FORM') {
- let form = new FormData();
- for (let key of Object.keys(data)) {
- form.append(key, data[key]);
- }
- data = form;
- method = 'POST';
- }
-
- return m.request({ method, url, data,
- extract: ({ responseText }) => responseText
- });
- }
-
- function main() {
- try {
- styles(null, true);
- mount();
- }
- catch(e) {
- console.error(e);
- }
- }
-
- setTimeout(main);
-
-
-
- // Mithrill 1.1.1
-
- ;(function() {
- "use strict"
- function Vnode(tag, key, attrs0, children, text, dom) {
- return {tag: tag, key: key, attrs: attrs0, children: children, text: text, dom: dom, domSize: undefined, state: undefined, _state: undefined, events: undefined, instance: undefined, skip: false}
- }
- Vnode.normalize = function(node) {
- if (Array.isArray(node)) return Vnode("[", undefined, undefined, Vnode.normalizeChildren(node), undefined, undefined)
- if (node != null && typeof node !== "object") return Vnode("#", undefined, undefined, node === false ? "" : node, undefined, undefined)
- return node
- }
- Vnode.normalizeChildren = function normalizeChildren(children) {
- for (var i = 0; i < children.length; i++) {
- children[i] = Vnode.normalize(children[i])
- }
- return children
- }
- var selectorParser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g
- var selectorCache = {}
- var hasOwn = {}.hasOwnProperty
- function compileSelector(selector) {
- var match, tag = "div", classes = [], attrs = {}
- while (match = selectorParser.exec(selector)) {
- var type = match[1], value = match[2]
- if (type === "" && value !== "") tag = value
- else if (type === "#") attrs.id = value
- else if (type === ".") classes.push(value)
- else if (match[3][0] === "[") {
- var attrValue = match[6]
- if (attrValue) attrValue = attrValue.replace(/\\(["'])/g, "$1").replace(/\\\\/g, "\\")
- if (match[4] === "class") classes.push(attrValue)
- else attrs[match[4]] = attrValue === "" ? attrValue : attrValue || true
- }
- }
- if (classes.length > 0) attrs.className = classes.join(" ")
- return selectorCache[selector] = {tag: tag, attrs: attrs}
- }
- function execSelector(state, attrs, children) {
- var hasAttrs = false, childList, text
- var className = attrs.className || attrs.class
- for (var key in state.attrs) {
- if (hasOwn.call(state.attrs, key)) {
- attrs[key] = state.attrs[key]
- }
- }
- if (className !== undefined) {
- if (attrs.class !== undefined) {
- attrs.class = undefined
- attrs.className = className
- }
- if (state.attrs.className != null) {
- attrs.className = state.attrs.className + " " + className
- }
- }
- for (var key in attrs) {
- if (hasOwn.call(attrs, key) && key !== "key") {
- hasAttrs = true
- break
- }
- }
- if (Array.isArray(children) && children.length === 1 && children[0] != null && children[0].tag === "#") {
- text = children[0].children
- } else {
- childList = children
- }
- return Vnode(state.tag, attrs.key, hasAttrs ? attrs : undefined, childList, text)
- }
- function hyperscript(selector) {
- // Because sloppy mode sucks
- var attrs = arguments[1], start = 2, children
- if (selector == null || typeof selector !== "string" && typeof selector !== "function" && typeof selector.view !== "function") {
- throw Error("The selector must be either a string or a component.");
- }
- if (typeof selector === "string") {
- var cached = selectorCache[selector] || compileSelector(selector)
- }
- if (attrs == null) {
- attrs = {}
- } else if (typeof attrs !== "object" || attrs.tag != null || Array.isArray(attrs)) {
- attrs = {}
- start = 1
- }
- if (arguments.length === start + 1) {
- children = arguments[start]
- if (!Array.isArray(children)) children = [children]
- } else {
- children = []
- while (start < arguments.length) children.push(arguments[start++])
- }
- var normalized = Vnode.normalizeChildren(children)
- if (typeof selector === "string") {
- return execSelector(cached, attrs, normalized)
- } else {
- return Vnode(selector, attrs.key, attrs, normalized)
- }
- }
- hyperscript.trust = function(html) {
- if (html == null) html = ""
- return Vnode("<", undefined, undefined, html, undefined, undefined)
- }
- hyperscript.fragment = function(attrs1, children) {
- return Vnode("[", attrs1.key, attrs1, Vnode.normalizeChildren(children), undefined, undefined)
- }
- var m = hyperscript
- /** @constructor */
- var PromisePolyfill = function(executor) {
- if (!(this instanceof PromisePolyfill)) throw new Error("Promise must be called with `new`")
- if (typeof executor !== "function") throw new TypeError("executor must be a function")
- var self = this, resolvers = [], rejectors = [], resolveCurrent = handler(resolvers, true), rejectCurrent = handler(rejectors, false)
- var instance = self._instance = {resolvers: resolvers, rejectors: rejectors}
- var callAsync = typeof setImmediate === "function" ? setImmediate : setTimeout
- function handler(list, shouldAbsorb) {
- return function execute(value) {
- var then
- try {
- if (shouldAbsorb && value != null && (typeof value === "object" || typeof value === "function") && typeof (then = value.then) === "function") {
- if (value === self) throw new TypeError("Promise can't be resolved w/ itself")
- executeOnce(then.bind(value))
- }
- else {
- callAsync(function() {
- if (!shouldAbsorb && list.length === 0) console.error("Possible unhandled promise rejection:", value)
- for (var i = 0; i < list.length; i++) list[i](value)
- resolvers.length = 0, rejectors.length = 0
- instance.state = shouldAbsorb
- instance.retry = function() {execute(value)}
- })
- }
- }
- catch (e) {
- rejectCurrent(e)
- }
- }
- }
- function executeOnce(then) {
- var runs = 0
- function run(fn) {
- return function(value) {
- if (runs++ > 0) return
- fn(value)
- }
- }
- var onerror = run(rejectCurrent)
- try {then(run(resolveCurrent), onerror)} catch (e) {onerror(e)}
- }
- executeOnce(executor)
- }
- PromisePolyfill.prototype.then = function(onFulfilled, onRejection) {
- var self = this, instance = self._instance
- function handle(callback, list, next, state) {
- list.push(function(value) {
- if (typeof callback !== "function") next(value)
- else try {resolveNext(callback(value))} catch (e) {if (rejectNext) rejectNext(e)}
- })
- if (typeof instance.retry === "function" && state === instance.state) instance.retry()
- }
- var resolveNext, rejectNext
- var promise = new PromisePolyfill(function(resolve, reject) {resolveNext = resolve, rejectNext = reject})
- handle(onFulfilled, instance.resolvers, resolveNext, true), handle(onRejection, instance.rejectors, rejectNext, false)
- return promise
- }
- PromisePolyfill.prototype.catch = function(onRejection) {
- return this.then(null, onRejection)
- }
- PromisePolyfill.resolve = function(value) {
- if (value instanceof PromisePolyfill) return value
- return new PromisePolyfill(function(resolve) {resolve(value)})
- }
- PromisePolyfill.reject = function(value) {
- return new PromisePolyfill(function(resolve, reject) {reject(value)})
- }
- PromisePolyfill.all = function(list) {
- return new PromisePolyfill(function(resolve, reject) {
- var total = list.length, count = 0, values = []
- if (list.length === 0) resolve([])
- else for (var i = 0; i < list.length; i++) {
- (function(i) {
- function consume(value) {
- count++
- values[i] = value
- if (count === total) resolve(values)
- }
- if (list[i] != null && (typeof list[i] === "object" || typeof list[i] === "function") && typeof list[i].then === "function") {
- list[i].then(consume, reject)
- }
- else consume(list[i])
- })(i)
- }
- })
- }
- PromisePolyfill.race = function(list) {
- return new PromisePolyfill(function(resolve, reject) {
- for (var i = 0; i < list.length; i++) {
- list[i].then(resolve, reject)
- }
- })
- }
- if (typeof window !== "undefined") {
- if (typeof window.Promise === "undefined") window.Promise = PromisePolyfill
- var PromisePolyfill = window.Promise
- } else if (typeof global !== "undefined") {
- if (typeof global.Promise === "undefined") global.Promise = PromisePolyfill
- var PromisePolyfill = global.Promise
- } else {
- }
- var buildQueryString = function(object) {
- if (Object.prototype.toString.call(object) !== "[object Object]") return ""
- var args = []
- for (var key0 in object) {
- destructure(key0, object[key0])
- }
- return args.join("&")
- function destructure(key0, value) {
- if (Array.isArray(value)) {
- for (var i = 0; i < value.length; i++) {
- destructure(key0 + "[" + i + "]", value[i])
- }
- }
- else if (Object.prototype.toString.call(value) === "[object Object]") {
- for (var i in value) {
- destructure(key0 + "[" + i + "]", value[i])
- }
- }
- else args.push(encodeURIComponent(key0) + (value != null && value !== "" ? "=" + encodeURIComponent(value) : ""))
- }
- }
- var FILE_PROTOCOL_REGEX = new RegExp("^file://", "i")
- var _8 = function($window, Promise) {
- var callbackCount = 0
- var oncompletion
- function setCompletionCallback(callback) {oncompletion = callback}
- function finalizer() {
- var count = 0
- function complete() {if (--count === 0 && typeof oncompletion === "function") oncompletion()}
- return function finalize(promise0) {
- var then0 = promise0.then
- promise0.then = function() {
- count++
- var next = then0.apply(promise0, arguments)
- next.then(complete, function(e) {
- complete()
- if (count === 0) throw e
- })
- return finalize(next)
- }
- return promise0
- }
- }
- function normalize(args, extra) {
- if (typeof args === "string") {
- var url = args
- args = extra || {}
- if (args.url == null) args.url = url
- }
- return args
- }
- function request(args, extra) {
- var finalize = finalizer()
- args = normalize(args, extra)
- var promise0 = new Promise(function(resolve, reject) {
- if (args.method == null) args.method = "GET"
- args.method = args.method.toUpperCase()
- var useBody = (args.method === "GET" || args.method === "TRACE") ? false : (typeof args.useBody === "boolean" ? args.useBody : true)
- if (typeof args.serialize !== "function") args.serialize = typeof FormData !== "undefined" && args.data instanceof FormData ? function(value) {return value} : JSON.stringify
- if (typeof args.deserialize !== "function") args.deserialize = deserialize
- if (typeof args.extract !== "function") args.extract = extract
- args.url = interpolate(args.url, args.data)
- if (useBody) args.data = args.serialize(args.data)
- else args.url = assemble(args.url, args.data)
- var xhr = new $window.XMLHttpRequest(),
- aborted = false,
- _abort = xhr.abort
- xhr.abort = function abort() {
- aborted = true
- _abort.call(xhr)
- }
- xhr.open(args.method, args.url, typeof args.async === "boolean" ? args.async : true, typeof args.user === "string" ? args.user : undefined, typeof args.password === "string" ? args.password : undefined)
- if (args.serialize === JSON.stringify && useBody) {
- xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8")
- }
- if (args.deserialize === deserialize) {
- xhr.setRequestHeader("Accept", "application/json, text/*")
- }
- if (args.withCredentials) xhr.withCredentials = args.withCredentials
- for (var key in args.headers) if ({}.hasOwnProperty.call(args.headers, key)) {
- xhr.setRequestHeader(key, args.headers[key])
- }
- if (typeof args.config === "function") xhr = args.config(xhr, args) || xhr
- xhr.onreadystatechange = function() {
- // Don't throw errors on xhr.abort().
- if(aborted) return
- if (xhr.readyState === 4) {
- try {
- var response = (args.extract !== extract) ? args.extract(xhr, args) : args.deserialize(args.extract(xhr, args))
- if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304 || FILE_PROTOCOL_REGEX.test(args.url)) {
- resolve(cast(args.type, response))
- }
- else {
- var error = new Error(xhr.responseText)
- for (var key in response) error[key] = response[key]
- reject(error)
- }
- }
- catch (e) {
- reject(e)
- }
- }
- }
- if (useBody && (args.data != null)) xhr.send(args.data)
- else xhr.send()
- })
- return args.background === true ? promise0 : finalize(promise0)
- }
- function jsonp(args, extra) {
- var finalize = finalizer()
- args = normalize(args, extra)
- var promise0 = new Promise(function(resolve, reject) {
- var callbackName = args.callbackName || "_mithril_" + Math.round(Math.random() * 1e16) + "_" + callbackCount++
- var script = $window.document.createElement("script")
- $window[callbackName] = function(data) {
- script.parentNode.removeChild(script)
- resolve(cast(args.type, data))
- delete $window[callbackName]
- }
- script.onerror = function() {
- script.parentNode.removeChild(script)
- reject(new Error("JSONP request failed"))
- delete $window[callbackName]
- }
- if (args.data == null) args.data = {}
- args.url = interpolate(args.url, args.data)
- args.data[args.callbackKey || "callback"] = callbackName
- script.src = assemble(args.url, args.data)
- $window.document.documentElement.appendChild(script)
- })
- return args.background === true? promise0 : finalize(promise0)
- }
- function interpolate(url, data) {
- if (data == null) return url
- var tokens = url.match(/:[^\/]+/gi) || []
- for (var i = 0; i < tokens.length; i++) {
- var key = tokens[i].slice(1)
- if (data[key] != null) {
- url = url.replace(tokens[i], data[key])
- }
- }
- return url
- }
- function assemble(url, data) {
- var querystring = buildQueryString(data)
- if (querystring !== "") {
- var prefix = url.indexOf("?") < 0 ? "?" : "&"
- url += prefix + querystring
- }
- return url
- }
- function deserialize(data) {
- try {return data !== "" ? JSON.parse(data) : null}
- catch (e) {throw new Error(data)}
- }
- function extract(xhr) {return xhr.responseText}
- function cast(type0, data) {
- if (typeof type0 === "function") {
- if (Array.isArray(data)) {
- for (var i = 0; i < data.length; i++) {
- data[i] = new type0(data[i])
- }
- }
- else return new type0(data)
- }
- return data
- }
- return {request: request, jsonp: jsonp, setCompletionCallback: setCompletionCallback}
- }
- var requestService = _8(window, PromisePolyfill)
- var coreRenderer = function($window) {
- var $doc = $window.document
- var $emptyFragment = $doc.createDocumentFragment()
- var nameSpace = {
- svg: "http://www.w3.org/2000/svg",
- math: "http://www.w3.org/1998/Math/MathML"
- }
- var onevent
- function setEventCallback(callback) {return onevent = callback}
- function getNameSpace(vnode) {
- return vnode.attrs && vnode.attrs.xmlns || nameSpace[vnode.tag]
- }
- //create
- function createNodes(parent, vnodes, start, end, hooks, nextSibling, ns) {
- for (var i = start; i < end; i++) {
- var vnode = vnodes[i]
- if (vnode != null) {
- createNode(parent, vnode, hooks, ns, nextSibling)
- }
- }
- }
- function createNode(parent, vnode, hooks, ns, nextSibling) {
- var tag = vnode.tag
- if (typeof tag === "string") {
- vnode.state = {}
- if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
- switch (tag) {
- case "#": return createText(parent, vnode, nextSibling)
- case "<": return createHTML(parent, vnode, nextSibling)
- case "[": return createFragment(parent, vnode, hooks, ns, nextSibling)
- default: return createElement(parent, vnode, hooks, ns, nextSibling)
- }
- }
- else return createComponent(parent, vnode, hooks, ns, nextSibling)
- }
- function createText(parent, vnode, nextSibling) {
- vnode.dom = $doc.createTextNode(vnode.children)
- insertNode(parent, vnode.dom, nextSibling)
- return vnode.dom
- }
- function createHTML(parent, vnode, nextSibling) {
- var match1 = vnode.children.match(/^\s*?<(\w+)/im) || []
- var parent1 = {caption: "table", thead: "table", tbody: "table", tfoot: "table", tr: "tbody", th: "tr", td: "tr", colgroup: "table", col: "colgroup"}[match1[1]] || "div"
- var temp = $doc.createElement(parent1)
- temp.innerHTML = vnode.children
- vnode.dom = temp.firstChild
- vnode.domSize = temp.childNodes.length
- var fragment = $doc.createDocumentFragment()
- var child
- while (child = temp.firstChild) {
- fragment.appendChild(child)
- }
- insertNode(parent, fragment, nextSibling)
- return fragment
- }
- function createFragment(parent, vnode, hooks, ns, nextSibling) {
- var fragment = $doc.createDocumentFragment()
- if (vnode.children != null) {
- var children = vnode.children
- createNodes(fragment, children, 0, children.length, hooks, null, ns)
- }
- vnode.dom = fragment.firstChild
- vnode.domSize = fragment.childNodes.length
- insertNode(parent, fragment, nextSibling)
- return fragment
- }
- function createElement(parent, vnode, hooks, ns, nextSibling) {
- var tag = vnode.tag
- var attrs2 = vnode.attrs
- var is = attrs2 && attrs2.is
- ns = getNameSpace(vnode) || ns
- var element = ns ?
- is ? $doc.createElementNS(ns, tag, {is: is}) : $doc.createElementNS(ns, tag) :
- is ? $doc.createElement(tag, {is: is}) : $doc.createElement(tag)
- vnode.dom = element
- if (attrs2 != null) {
- setAttrs(vnode, attrs2, ns)
- }
- insertNode(parent, element, nextSibling)
- if (vnode.attrs != null && vnode.attrs.contenteditable != null) {
- setContentEditable(vnode)
- }
- else {
- if (vnode.text != null) {
- if (vnode.text !== "") element.textContent = vnode.text
- else vnode.children = [Vnode("#", undefined, undefined, vnode.text, undefined, undefined)]
- }
- if (vnode.children != null) {
- var children = vnode.children
- createNodes(element, children, 0, children.length, hooks, null, ns)
- setLateAttrs(vnode)
- }
- }
- return element
- }
- function initComponent(vnode, hooks) {
- var sentinel
- if (typeof vnode.tag.view === "function") {
- vnode.state = Object.create(vnode.tag)
- sentinel = vnode.state.view
- if (sentinel.$$reentrantLock$$ != null) return $emptyFragment
- sentinel.$$reentrantLock$$ = true
- } else {
- vnode.state = void 0
- sentinel = vnode.tag
- if (sentinel.$$reentrantLock$$ != null) return $emptyFragment
- sentinel.$$reentrantLock$$ = true
- vnode.state = (vnode.tag.prototype != null && typeof vnode.tag.prototype.view === "function") ? new vnode.tag(vnode) : vnode.tag(vnode)
- }
- vnode._state = vnode.state
- if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
- initLifecycle(vnode._state, vnode, hooks)
- vnode.instance = Vnode.normalize(vnode._state.view.call(vnode.state, vnode))
- if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as argument")
- sentinel.$$reentrantLock$$ = null
- }
- function createComponent(parent, vnode, hooks, ns, nextSibling) {
- initComponent(vnode, hooks)
- if (vnode.instance != null) {
- var element = createNode(parent, vnode.instance, hooks, ns, nextSibling)
- vnode.dom = vnode.instance.dom
- vnode.domSize = vnode.dom != null ? vnode.instance.domSize : 0
- insertNode(parent, element, nextSibling)
- return element
- }
- else {
- vnode.domSize = 0
- return $emptyFragment
- }
- }
- //update
- function updateNodes(parent, old, vnodes, recycling, hooks, nextSibling, ns) {
- if (old === vnodes || old == null && vnodes == null) return
- else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns)
- else if (vnodes == null) removeNodes(old, 0, old.length, vnodes)
- else {
- if (old.length === vnodes.length) {
- var isUnkeyed = false
- for (var i = 0; i < vnodes.length; i++) {
- if (vnodes[i] != null && old[i] != null) {
- isUnkeyed = vnodes[i].key == null && old[i].key == null
- break
- }
- }
- if (isUnkeyed) {
- for (var i = 0; i < old.length; i++) {
- if (old[i] === vnodes[i]) continue
- else if (old[i] == null && vnodes[i] != null) createNode(parent, vnodes[i], hooks, ns, getNextSibling(old, i + 1, nextSibling))
- else if (vnodes[i] == null) removeNodes(old, i, i + 1, vnodes)
- else updateNode(parent, old[i], vnodes[i], hooks, getNextSibling(old, i + 1, nextSibling), recycling, ns)
- }
- return
- }
- }
- recycling = recycling || isRecyclable(old, vnodes)
- if (recycling) {
- var pool = old.pool
- old = old.concat(old.pool)
- }
- var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map
- while (oldEnd >= oldStart && end >= start) {
- var o = old[oldStart], v = vnodes[start]
- if (o === v && !recycling) oldStart++, start++
- else if (o == null) oldStart++
- else if (v == null) start++
- else if (o.key === v.key) {
- var shouldRecycle = (pool != null && oldStart >= old.length - pool.length) || ((pool == null) && recycling)
- oldStart++, start++
- updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), shouldRecycle, ns)
- if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling)
- }
- else {
- var o = old[oldEnd]
- if (o === v && !recycling) oldEnd--, start++
- else if (o == null) oldEnd--
- else if (v == null) start++
- else if (o.key === v.key) {
- var shouldRecycle = (pool != null && oldEnd >= old.length - pool.length) || ((pool == null) && recycling)
- updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), shouldRecycle, ns)
- if (recycling || start < end) insertNode(parent, toFragment(o), getNextSibling(old, oldStart, nextSibling))
- oldEnd--, start++
- }
- else break
- }
- }
- while (oldEnd >= oldStart && end >= start) {
- var o = old[oldEnd], v = vnodes[end]
- if (o === v && !recycling) oldEnd--, end--
- else if (o == null) oldEnd--
- else if (v == null) end--
- else if (o.key === v.key) {
- var shouldRecycle = (pool != null && oldEnd >= old.length - pool.length) || ((pool == null) && recycling)
- updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), shouldRecycle, ns)
- if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling)
- if (o.dom != null) nextSibling = o.dom
- oldEnd--, end--
- }
- else {
- if (!map) map = getKeyMap(old, oldEnd)
- if (v != null) {
- var oldIndex = map[v.key]
- if (oldIndex != null) {
- var movable = old[oldIndex]
- var shouldRecycle = (pool != null && oldIndex >= old.length - pool.length) || ((pool == null) && recycling)
- updateNode(parent, movable, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
- insertNode(parent, toFragment(movable), nextSibling)
- old[oldIndex].skip = true
- if (movable.dom != null) nextSibling = movable.dom
- }
- else {
- var dom = createNode(parent, v, hooks, ns, nextSibling)
- nextSibling = dom
- }
- }
- end--
- }
- if (end < start) break
- }
- createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns)
- removeNodes(old, oldStart, oldEnd + 1, vnodes)
- }
- }
- function updateNode(parent, old, vnode, hooks, nextSibling, recycling, ns) {
- var oldTag = old.tag, tag = vnode.tag
- if (oldTag === tag) {
- vnode.state = old.state
- vnode._state = old._state
- vnode.events = old.events
- if (!recycling && shouldNotUpdate(vnode, old)) return
- if (typeof oldTag === "string") {
- if (vnode.attrs != null) {
- if (recycling) {
- vnode.state = {}
- initLifecycle(vnode.attrs, vnode, hooks)
- }
- else updateLifecycle(vnode.attrs, vnode, hooks)
- }
- switch (oldTag) {
- case "#": updateText(old, vnode); break
- case "<": updateHTML(parent, old, vnode, nextSibling); break
- case "[": updateFragment(parent, old, vnode, recycling, hooks, nextSibling, ns); break
- default: updateElement(old, vnode, recycling, hooks, ns)
- }
- }
- else updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns)
- }
- else {
- removeNode(old, null)
- createNode(parent, vnode, hooks, ns, nextSibling)
- }
- }
- function updateText(old, vnode) {
- if (old.children.toString() !== vnode.children.toString()) {
- old.dom.nodeValue = vnode.children
- }
- vnode.dom = old.dom
- }
- function updateHTML(parent, old, vnode, nextSibling) {
- if (old.children !== vnode.children) {
- toFragment(old)
- createHTML(parent, vnode, nextSibling)
- }
- else vnode.dom = old.dom, vnode.domSize = old.domSize
- }
- function updateFragment(parent, old, vnode, recycling, hooks, nextSibling, ns) {
- updateNodes(parent, old.children, vnode.children, recycling, hooks, nextSibling, ns)
- var domSize = 0, children = vnode.children
- vnode.dom = null
- if (children != null) {
- for (var i = 0; i < children.length; i++) {
- var child = children[i]
- if (child != null && child.dom != null) {
- if (vnode.dom == null) vnode.dom = child.dom
- domSize += child.domSize || 1
- }
- }
- if (domSize !== 1) vnode.domSize = domSize
- }
- }
- function updateElement(old, vnode, recycling, hooks, ns) {
- var element = vnode.dom = old.dom
- ns = getNameSpace(vnode) || ns
- if (vnode.tag === "textarea") {
- if (vnode.attrs == null) vnode.attrs = {}
- if (vnode.text != null) {
- vnode.attrs.value = vnode.text //FIXME handle0 multiple children
- vnode.text = undefined
- }
- }
- updateAttrs(vnode, old.attrs, vnode.attrs, ns)
- if (vnode.attrs != null && vnode.attrs.contenteditable != null) {
- setContentEditable(vnode)
- }
- else if (old.text != null && vnode.text != null && vnode.text !== "") {
- if (old.text.toString() !== vnode.text.toString()) old.dom.firstChild.nodeValue = vnode.text
- }
- else {
- if (old.text != null) old.children = [Vnode("#", undefined, undefined, old.text, undefined, old.dom.firstChild)]
- if (vnode.text != null) vnode.children = [Vnode("#", undefined, undefined, vnode.text, undefined, undefined)]
- updateNodes(element, old.children, vnode.children, recycling, hooks, null, ns)
- }
- }
- function updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) {
- if (recycling) {
- initComponent(vnode, hooks)
- } else {
- vnode.instance = Vnode.normalize(vnode._state.view.call(vnode.state, vnode))
- if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as argument")
- if (vnode.attrs != null) updateLifecycle(vnode.attrs, vnode, hooks)
- updateLifecycle(vnode._state, vnode, hooks)
- }
- if (vnode.instance != null) {
- if (old.instance == null) createNode(parent, vnode.instance, hooks, ns, nextSibling)
- else updateNode(parent, old.instance, vnode.instance, hooks, nextSibling, recycling, ns)
- vnode.dom = vnode.instance.dom
- vnode.domSize = vnode.instance.domSize
- }
- else if (old.instance != null) {
- removeNode(old.instance, null)
- vnode.dom = undefined
- vnode.domSize = 0
- }
- else {
- vnode.dom = old.dom
- vnode.domSize = old.domSize
- }
- }
- function isRecyclable(old, vnodes) {
- if (old.pool != null && Math.abs(old.pool.length - vnodes.length) <= Math.abs(old.length - vnodes.length)) {
- var oldChildrenLength = old[0] && old[0].children && old[0].children.length || 0
- var poolChildrenLength = old.pool[0] && old.pool[0].children && old.pool[0].children.length || 0
- var vnodesChildrenLength = vnodes[0] && vnodes[0].children && vnodes[0].children.length || 0
- if (Math.abs(poolChildrenLength - vnodesChildrenLength) <= Math.abs(oldChildrenLength - vnodesChildrenLength)) {
- return true
- }
- }
- return false
- }
- function getKeyMap(vnodes, end) {
- var map = {}, i = 0
- for (var i = 0; i < end; i++) {
- var vnode = vnodes[i]
- if (vnode != null) {
- var key2 = vnode.key
- if (key2 != null) map[key2] = i
- }
- }
- return map
- }
- function toFragment(vnode) {
- var count0 = vnode.domSize
- if (count0 != null || vnode.dom == null) {
- var fragment = $doc.createDocumentFragment()
- if (count0 > 0) {
- var dom = vnode.dom
- while (--count0) fragment.appendChild(dom.nextSibling)
- fragment.insertBefore(dom, fragment.firstChild)
- }
- return fragment
- }
- else return vnode.dom
- }
- function getNextSibling(vnodes, i, nextSibling) {
- for (; i < vnodes.length; i++) {
- if (vnodes[i] != null && vnodes[i].dom != null) return vnodes[i].dom
- }
- return nextSibling
- }
- function insertNode(parent, dom, nextSibling) {
- if (nextSibling && nextSibling.parentNode) parent.insertBefore(dom, nextSibling)
- else parent.appendChild(dom)
- }
- function setContentEditable(vnode) {
- var children = vnode.children
- if (children != null && children.length === 1 && children[0].tag === "<") {
- var content = children[0].children
- if (vnode.dom.innerHTML !== content) vnode.dom.innerHTML = content
- }
- else if (vnode.text != null || children != null && children.length !== 0) throw new Error("Child node of a contenteditable must be trusted")
- }
- //remove
- function removeNodes(vnodes, start, end, context) {
- for (var i = start; i < end; i++) {
- var vnode = vnodes[i]
- if (vnode != null) {
- if (vnode.skip) vnode.skip = false
- else removeNode(vnode, context)
- }
- }
- }
- function removeNode(vnode, context) {
- var expected = 1, called = 0
- if (vnode.attrs && typeof vnode.attrs.onbeforeremove === "function") {
- var result = vnode.attrs.onbeforeremove.call(vnode.state, vnode)
- if (result != null && typeof result.then === "function") {
- expected++
- result.then(continuation, continuation)
- }
- }
- if (typeof vnode.tag !== "string" && typeof vnode._state.onbeforeremove === "function") {
- var result = vnode._state.onbeforeremove.call(vnode.state, vnode)
- if (result != null && typeof result.then === "function") {
- expected++
- result.then(continuation, continuation)
- }
- }
- continuation()
- function continuation() {
- if (++called === expected) {
- onremove(vnode)
- if (vnode.dom) {
- var count0 = vnode.domSize || 1
- if (count0 > 1) {
- var dom = vnode.dom
- while (--count0) {
- removeNodeFromDOM(dom.nextSibling)
- }
- }
- removeNodeFromDOM(vnode.dom)
- if (context != null && vnode.domSize == null && !hasIntegrationMethods(vnode.attrs) && typeof vnode.tag === "string") { //TODO test custom elements
- if (!context.pool) context.pool = [vnode]
- else context.pool.push(vnode)
- }
- }
- }
- }
- }
- function removeNodeFromDOM(node) {
- var parent = node.parentNode
- if (parent != null) parent.removeChild(node)
- }
- function onremove(vnode) {
- if (vnode.attrs && typeof vnode.attrs.onremove === "function") vnode.attrs.onremove.call(vnode.state, vnode)
- if (typeof vnode.tag !== "string" && typeof vnode._state.onremove === "function") vnode._state.onremove.call(vnode.state, vnode)
- if (vnode.instance != null) onremove(vnode.instance)
- else {
- var children = vnode.children
- if (Array.isArray(children)) {
- for (var i = 0; i < children.length; i++) {
- var child = children[i]
- if (child != null) onremove(child)
- }
- }
- }
- }
- //attrs2
- function setAttrs(vnode, attrs2, ns) {
- for (var key2 in attrs2) {
- setAttr(vnode, key2, null, attrs2[key2], ns)
- }
- }
- function setAttr(vnode, key2, old, value, ns) {
- var element = vnode.dom
- if (key2 === "key" || key2 === "is" || (old === value && !isFormAttribute(vnode, key2)) && typeof value !== "object" || typeof value === "undefined" || isLifecycleMethod(key2)) return
- var nsLastIndex = key2.indexOf(":")
- if (nsLastIndex > -1 && key2.substr(0, nsLastIndex) === "xlink") {
- element.setAttributeNS("http://www.w3.org/1999/xlink", key2.slice(nsLastIndex + 1), value)
- }
- else if (key2[0] === "o" && key2[1] === "n" && typeof value === "function") updateEvent(vnode, key2, value)
- else if (key2 === "style") updateStyle(element, old, value)
- else if (key2 in element && !isAttribute(key2) && ns === undefined && !isCustomElement(vnode)) {
- if (key2 === "value") {
- var normalized0 = "" + value // eslint-disable-line no-implicit-coercion
- //setting input[value] to same value by typing on focused element moves cursor to end in Chrome
- if ((vnode.tag === "input" || vnode.tag === "textarea") && vnode.dom.value === normalized0 && vnode.dom === $doc.activeElement) return
- //setting select[value] to same value while having select open blinks select dropdown in Chrome
- if (vnode.tag === "select") {
- if (value === null) {
- if (vnode.dom.selectedIndex === -1 && vnode.dom === $doc.activeElement) return
- } else {
- if (old !== null && vnode.dom.value === normalized0 && vnode.dom === $doc.activeElement) return
- }
- }
- //setting option[value] to same value while having select open blinks select dropdown in Chrome
- if (vnode.tag === "option" && old != null && vnode.dom.value === normalized0) return
- }
- // If you assign an input type1 that is not supported by IE 11 with an assignment expression, an error0 will occur.
- if (vnode.tag === "input" && key2 === "type") {
- element.setAttribute(key2, value)
- return
- }
- element[key2] = value
- }
- else {
- if (typeof value === "boolean") {
- if (value) element.setAttribute(key2, "")
- else element.removeAttribute(key2)
- }
- else element.setAttribute(key2 === "className" ? "class" : key2, value)
- }
- }
- function setLateAttrs(vnode) {
- var attrs2 = vnode.attrs
- if (vnode.tag === "select" && attrs2 != null) {
- if ("value" in attrs2) setAttr(vnode, "value", null, attrs2.value, undefined)
- if ("selectedIndex" in attrs2) setAttr(vnode, "selectedIndex", null, attrs2.selectedIndex, undefined)
- }
- }
- function updateAttrs(vnode, old, attrs2, ns) {
- if (attrs2 != null) {
- for (var key2 in attrs2) {
- setAttr(vnode, key2, old && old[key2], attrs2[key2], ns)
- }
- }
- if (old != null) {
- for (var key2 in old) {
- if (attrs2 == null || !(key2 in attrs2)) {
- if (key2 === "className") key2 = "class"
- if (key2[0] === "o" && key2[1] === "n" && !isLifecycleMethod(key2)) updateEvent(vnode, key2, undefined)
- else if (key2 !== "key") vnode.dom.removeAttribute(key2)
- }
- }
- }
- }
- function isFormAttribute(vnode, attr) {
- return attr === "value" || attr === "checked" || attr === "selectedIndex" || attr === "selected" && vnode.dom === $doc.activeElement
- }
- function isLifecycleMethod(attr) {
- return attr === "oninit" || attr === "oncreate" || attr === "onupdate" || attr === "onremove" || attr === "onbeforeremove" || attr === "onbeforeupdate"
- }
- function isAttribute(attr) {
- return attr === "href" || attr === "list" || attr === "form" || attr === "width" || attr === "height"// || attr === "type"
- }
- function isCustomElement(vnode){
- return vnode.attrs.is || vnode.tag.indexOf("-") > -1
- }
- function hasIntegrationMethods(source) {
- return source != null && (source.oncreate || source.onupdate || source.onbeforeremove || source.onremove)
- }
- //style
- function updateStyle(element, old, style) {
- if (old === style) element.style.cssText = "", old = null
- if (style == null) element.style.cssText = ""
- else if (typeof style === "string") element.style.cssText = style
- else {
- if (typeof old === "string") element.style.cssText = ""
- for (var key2 in style) {
- element.style[key2] = style[key2]
- }
- if (old != null && typeof old !== "string") {
- for (var key2 in old) {
- if (!(key2 in style)) element.style[key2] = ""
- }
- }
- }
- }
- //event
- function updateEvent(vnode, key2, value) {
- var element = vnode.dom
- var callback = typeof onevent !== "function" ? value : function(e) {
- var result = value.call(element, e)
- onevent.call(element, e)
- return result
- }
- if (key2 in element) element[key2] = typeof value === "function" ? callback : null
- else {
- var eventName = key2.slice(2)
- if (vnode.events === undefined) vnode.events = {}
- if (vnode.events[key2] === callback) return
- if (vnode.events[key2] != null) element.removeEventListener(eventName, vnode.events[key2], false)
- if (typeof value === "function") {
- vnode.events[key2] = callback
- element.addEventListener(eventName, vnode.events[key2], false)
- }
- }
- }
- //lifecycle
- function initLifecycle(source, vnode, hooks) {
- if (typeof source.oninit === "function") source.oninit.call(vnode.state, vnode)
- if (typeof source.oncreate === "function") hooks.push(source.oncreate.bind(vnode.state, vnode))
- }
- function updateLifecycle(source, vnode, hooks) {
- if (typeof source.onupdate === "function") hooks.push(source.onupdate.bind(vnode.state, vnode))
- }
- function shouldNotUpdate(vnode, old) {
- var forceVnodeUpdate, forceComponentUpdate
- if (vnode.attrs != null && typeof vnode.attrs.onbeforeupdate === "function") forceVnodeUpdate = vnode.attrs.onbeforeupdate.call(vnode.state, vnode, old)
- if (typeof vnode.tag !== "string" && typeof vnode._state.onbeforeupdate === "function") forceComponentUpdate = vnode._state.onbeforeupdate.call(vnode.state, vnode, old)
- if (!(forceVnodeUpdate === undefined && forceComponentUpdate === undefined) && !forceVnodeUpdate && !forceComponentUpdate) {
- vnode.dom = old.dom
- vnode.domSize = old.domSize
- vnode.instance = old.instance
- return true
- }
- return false
- }
- function render(dom, vnodes) {
- if (!dom) throw new Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.")
- var hooks = []
- var active = $doc.activeElement
- var namespace = dom.namespaceURI
- // First time0 rendering into a node clears it out
- if (dom.vnodes == null) dom.textContent = ""
- if (!Array.isArray(vnodes)) vnodes = [vnodes]
- updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), false, hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace)
- dom.vnodes = vnodes
- for (var i = 0; i < hooks.length; i++) hooks[i]()
- if ($doc.activeElement !== active) active.focus()
- }
- return {render: render, setEventCallback: setEventCallback}
- }
- function throttle(callback) {
- //60fps translates to 16.6ms, round it down since setTimeout requires int
- var time = 16
- var last = 0, pending = null
- var timeout = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout
- return function() {
- var now = Date.now()
- if (last === 0 || now - last >= time) {
- last = now
- callback()
- }
- else if (pending === null) {
- pending = timeout(function() {
- pending = null
- callback()
- last = Date.now()
- }, time - (now - last))
- }
- }
- }
- var _11 = function($window) {
- var renderService = coreRenderer($window)
- renderService.setEventCallback(function(e) {
- if (e.redraw !== false) redraw()
- })
- var callbacks = []
- function subscribe(key1, callback) {
- unsubscribe(key1)
- callbacks.push(key1, throttle(callback))
- }
- function unsubscribe(key1) {
- var index = callbacks.indexOf(key1)
- if (index > -1) callbacks.splice(index, 2)
- }
- function redraw() {
- for (var i = 1; i < callbacks.length; i += 2) {
- callbacks[i]()
- }
- }
- return {subscribe: subscribe, unsubscribe: unsubscribe, redraw: redraw, render: renderService.render}
- }
- var redrawService = _11(window)
- requestService.setCompletionCallback(redrawService.redraw)
- var _16 = function(redrawService0) {
- return function(root, component) {
- if (component === null) {
- redrawService0.render(root, [])
- redrawService0.unsubscribe(root)
- return
- }
-
- if (component.view == null && typeof component !== "function") throw new Error("m.mount(element, component) expects a component, not a vnode")
-
- var run0 = function() {
- redrawService0.render(root, Vnode(component))
- }
- redrawService0.subscribe(root, run0)
- redrawService0.redraw()
- }
- }
- m.mount = _16(redrawService)
- var Promise = PromisePolyfill
- var parseQueryString = function(string) {
- if (string === "" || string == null) return {}
- if (string.charAt(0) === "?") string = string.slice(1)
- var entries = string.split("&"), data0 = {}, counters = {}
- for (var i = 0; i < entries.length; i++) {
- var entry = entries[i].split("=")
- var key5 = decodeURIComponent(entry[0])
- var value = entry.length === 2 ? decodeURIComponent(entry[1]) : ""
- if (value === "true") value = true
- else if (value === "false") value = false
- var levels = key5.split(/\]\[?|\[/)
- var cursor = data0
- if (key5.indexOf("[") > -1) levels.pop()
- for (var j = 0; j < levels.length; j++) {
- var level = levels[j], nextLevel = levels[j + 1]
- var isNumber = nextLevel == "" || !isNaN(parseInt(nextLevel, 10))
- var isValue = j === levels.length - 1
- if (level === "") {
- var key5 = levels.slice(0, j).join()
- if (counters[key5] == null) counters[key5] = 0
- level = counters[key5]++
- }
- if (cursor[level] == null) {
- cursor[level] = isValue ? value : isNumber ? [] : {}
- }
- cursor = cursor[level]
- }
- }
- return data0
- }
- var coreRouter = function($window) {
- var supportsPushState = typeof $window.history.pushState === "function"
- var callAsync0 = typeof setImmediate === "function" ? setImmediate : setTimeout
- function normalize1(fragment0) {
- var data = $window.location[fragment0].replace(/(?:%[a-f89][a-f0-9])+/gim, decodeURIComponent)
- if (fragment0 === "pathname" && data[0] !== "/") data = "/" + data
- return data
- }
- var asyncId
- function debounceAsync(callback0) {
- return function() {
- if (asyncId != null) return
- asyncId = callAsync0(function() {
- asyncId = null
- callback0()
- })
- }
- }
- function parsePath(path, queryData, hashData) {
- var queryIndex = path.indexOf("?")
- var hashIndex = path.indexOf("#")
- var pathEnd = queryIndex > -1 ? queryIndex : hashIndex > -1 ? hashIndex : path.length
- if (queryIndex > -1) {
- var queryEnd = hashIndex > -1 ? hashIndex : path.length
- var queryParams = parseQueryString(path.slice(queryIndex + 1, queryEnd))
- for (var key4 in queryParams) queryData[key4] = queryParams[key4]
- }
- if (hashIndex > -1) {
- var hashParams = parseQueryString(path.slice(hashIndex + 1))
- for (var key4 in hashParams) hashData[key4] = hashParams[key4]
- }
- return path.slice(0, pathEnd)
- }
- var router = {prefix: "#!"}
- router.getPath = function() {
- var type2 = router.prefix.charAt(0)
- switch (type2) {
- case "#": return normalize1("hash").slice(router.prefix.length)
- case "?": return normalize1("search").slice(router.prefix.length) + normalize1("hash")
- default: return normalize1("pathname").slice(router.prefix.length) + normalize1("search") + normalize1("hash")
- }
- }
- router.setPath = function(path, data, options) {
- var queryData = {}, hashData = {}
- path = parsePath(path, queryData, hashData)
- if (data != null) {
- for (var key4 in data) queryData[key4] = data[key4]
- path = path.replace(/:([^\/]+)/g, function(match2, token) {
- delete queryData[token]
- return data[token]
- })
- }
- var query = buildQueryString(queryData)
- if (query) path += "?" + query
- var hash = buildQueryString(hashData)
- if (hash) path += "#" + hash
- if (supportsPushState) {
- var state = options ? options.state : null
- var title = options ? options.title : null
- $window.onpopstate()
- if (options && options.replace) $window.history.replaceState(state, title, router.prefix + path)
- else $window.history.pushState(state, title, router.prefix + path)
- }
- else $window.location.href = router.prefix + path
- }
- router.defineRoutes = function(routes, resolve, reject) {
- function resolveRoute() {
- var path = router.getPath()
- var params = {}
- var pathname = parsePath(path, params, params)
- var state = $window.history.state
- if (state != null) {
- for (var k in state) params[k] = state[k]
- }
- for (var route0 in routes) {
- var matcher = new RegExp("^" + route0.replace(/:[^\/]+?\.{3}/g, "(.*?)").replace(/:[^\/]+/g, "([^\\/]+)") + "\/?$")
- if (matcher.test(pathname)) {
- pathname.replace(matcher, function() {
- var keys = route0.match(/:[^\/]+/g) || []
- var values = [].slice.call(arguments, 1, -2)
- for (var i = 0; i < keys.length; i++) {
- params[keys[i].replace(/:|\./g, "")] = decodeURIComponent(values[i])
- }
- resolve(routes[route0], params, path, route0)
- })
- return
- }
- }
- reject(path, params)
- }
- if (supportsPushState) $window.onpopstate = debounceAsync(resolveRoute)
- else if (router.prefix.charAt(0) === "#") $window.onhashchange = resolveRoute
- resolveRoute()
- }
- return router
- }
- var _20 = function($window, redrawService0) {
- var routeService = coreRouter($window)
- var identity = function(v) {return v}
- var render1, component, attrs3, currentPath, lastUpdate
- var route = function(root, defaultRoute, routes) {
- if (root == null) throw new Error("Ensure the DOM element that was passed to `m.route` is not undefined")
- var run1 = function() {
- if (render1 != null) redrawService0.render(root, render1(Vnode(component, attrs3.key, attrs3)))
- }
- var bail = function(path) {
- if (path !== defaultRoute) routeService.setPath(defaultRoute, null, {replace: true})
- else throw new Error("Could not resolve default route " + defaultRoute)
- }
- routeService.defineRoutes(routes, function(payload, params, path) {
- var update = lastUpdate = function(routeResolver, comp) {
- if (update !== lastUpdate) return
- component = comp != null && (typeof comp.view === "function" || typeof comp === "function")? comp : "div"
- attrs3 = params, currentPath = path, lastUpdate = null
- render1 = (routeResolver.render || identity).bind(routeResolver)
- run1()
- }
- if (payload.view || typeof payload === "function") update({}, payload)
- else {
- if (payload.onmatch) {
- Promise.resolve(payload.onmatch(params, path)).then(function(resolved) {
- update(payload, resolved)
- }, bail)
- }
- else update(payload, "div")
- }
- }, bail)
- redrawService0.subscribe(root, run1)
- }
- route.set = function(path, data, options) {
- if (lastUpdate != null) options = {replace: true}
- lastUpdate = null
- routeService.setPath(path, data, options)
- }
- route.get = function() {return currentPath}
- route.prefix = function(prefix0) {routeService.prefix = prefix0}
- route.link = function(vnode1) {
- vnode1.dom.setAttribute("href", routeService.prefix + vnode1.attrs.href)
- vnode1.dom.onclick = function(e) {
- if (e.ctrlKey || e.metaKey || e.shiftKey || e.which === 2) return
- e.preventDefault()
- e.redraw = false
- var href = this.getAttribute("href")
- if (href.indexOf(routeService.prefix) === 0) href = href.slice(routeService.prefix.length)
- route.set(href, undefined, undefined)
- }
- }
- route.param = function(key3) {
- if(typeof attrs3 !== "undefined" && typeof key3 !== "undefined") return attrs3[key3]
- return attrs3
- }
- return route
- }
- m.route = _20(window, redrawService)
- m.withAttr = function(attrName, callback1, context) {
- return function(e) {
- callback1.call(context || this, attrName in e.currentTarget ? e.currentTarget[attrName] : e.currentTarget.getAttribute(attrName))
- }
- }
- var _28 = coreRenderer(window)
- m.render = _28.render
- m.redraw = redrawService.redraw
- m.request = requestService.request
- m.jsonp = requestService.jsonp
- m.parseQueryString = parseQueryString
- m.buildQueryString = buildQueryString
- m.version = "1.1.1"
- m.vnode = Vnode
- if (typeof module !== "undefined") module["exports"] = m
- else window.m = m
- }());