/* * * Внешний вид * */ function задатьВнешнийВид() { var вид = document.createElement("style"); document.head.appendChild(вид); вид.innerHTML = ` .муром-кнопка { padding: 0.5em 2em 0.5em 2em; margin-right: 0.5em; float: right; color: #222; font-family: sans-serif; border: 1px solid #ddd; background-color: transparent; cursor: pointer; text-transform: uppercase; -webkit-transition-duration: 0.2s; /* Safari */ transition-duration: 0.2s; } .муром-кнопка:hover { border: 1px solid #222; } .муром-отступ-по-сторонам { margin-left: 0.5em; margin-right: 0.5em; } `; } /* * * Список модулей * */ function СписокМодулей() { var я = this; this.создатьИнтерфейс(); this.задатьВид(); this.выбрали = new Уведомитель(); this.выбрали.подписать(function(){ я.отобразитьВыбор(); }); } СписокМодулей.prototype.создатьИнтерфейс = function() { // Помещаем таблицу в div для реализации промотки. this.иф = document.createElement("div"); this.таблица = document.createElement("table"); this.иф.appendChild(this.таблица); }; СписокМодулей.prototype.задатьВид = function() { this.иф.style.cssText = ` overflow: auto; height: 18.5em; border: 1px solid #ddd; /* padding: 0.5em; margin: 0.5em; */ `; this.таблица.style.cssText = ` color: #666666; font-family: sans-serif; cursor: default; border-collapse: collapse; `; }; СписокМодулей.prototype.очистить = function() { while (this.таблица.rows.length) { this.таблица.deleteRow(0); }; }; СписокМодулей.prototype.добавитьЭлемент = function(статус, имя) { var статусHTML = ""; if (статус) { статусHTML = "checked"; } var ряд = this.таблица.insertRow(); var ячейка = 0; var номер = ряд.insertCell(ячейка++); номер.innerHTML = this.таблица.rows.length - 1; номер.style.cssText = "padding: 0.5em;"; var вкл = ряд.insertCell(ячейка++); вкл.innerHTML = ``; var название = ряд.insertCell(ячейка++); название.innerHTML = имя; название.style.cssText = "padding: 0.5em; width: 100%;"; }; СписокМодулей.prototype.отобразитьСписок = function(список) { this.очистить(); for (var номер in список) { var элемент = список[номер]; var статус = элемент[0]; var имя = элемент[1]; this.добавитьЭлемент(статус, имя); } }; СписокМодулей.prototype.улавливатьВыборЭлемента = function(номер) { var я = this; var ряд = this.таблица.rows[номер] ряд.onclick = function() { я.выборРанее = я.выбор; я.выбор = номер; я.выбрали.уведомить(); }; }; СписокМодулей.prototype.улавливатьВыбор = function() { this.выборРанее = null; this.выбор = null; for (var номер = 0; номер < this.таблица.rows.length; ++номер) { this.улавливатьВыборЭлемента(номер); } }; СписокМодулей.prototype.отобразитьВыбор = function() { if (this.выборРанее != null) { var ряд = this.таблица.rows[this.выборРанее]; ряд.style.backgroundColor = null; } var ряд = this.таблица.rows[this.выбор]; ряд.style.backgroundColor = "#eee"; }; СписокМодулей.prototype.задатьСписок = function(список) { this.отобразитьСписок(список); this.улавливатьВыбор(); }; СписокМодулей.prototype.выбрать = function(номер) { var ряд = this.таблица.rows[номер]; ряд.scrollIntoView(); ряд.onclick(); }; СписокМодулей.prototype.обновитьЭлемент = function(номер, статус, имя) { var ряд = this.таблица.rows[номер]; ряд.cells[1].childNodes[0].checked = статус; ряд.cells[2].innerHTML = имя; }; СписокМодулей.prototype.удалитьЭлемент = function(номер) { var ряд = this.таблица.rows[номер]; ряд.parentNode.removeChild(ряд); } /* * * Тест списка модулей * */ function ТестСпискаМодулей() { this.создатьИнтерфейс(); } ТестСпискаМодулей.prototype.создатьИнтерфейс = function() { var я = this; this.иф = document.createElement("div"); this.список = new СписокМодулей(); this.иф.appendChild(this.список.иф); var модули = [ [true, "муром.загрузка_1.0.0"], [true, "муром.uuid_1.0.0"], [true, "Уведомитель_1.0.0"], [false, "uikit_3.2.0.css"], [false, "uikit_3.2.0.js"], [false, "ПанельУправления.UIKit"], [false, "ПанельУправления_1.0.0"], ]; this.список.задатьСписок(модули); this.список.выбрать(0); this.создатьКнопку("Выбрать последний", function(){ console.log("выбрать"); я.список.выбрать(модули.length - 1); }); this.создатьКнопку("Обновить последний", function(){ я.список.обновитьЭлемент(модули.length - 1, true, "Новое имя"); }); this.создатьКнопку("Удалить последний", function(){ я.список.удалитьЭлемент(модули.length - 1); }); this.создатьКнопку("Добавить", function(){ я.список.добавитьЭлемент(true, "Новый-599"); var номер = я.список.таблица.rows.length - 1; я.список.улавливатьВыборЭлемента(номер); я.список.выбрать(номер); }); }; ТестСпискаМодулей.prototype.создатьКнопку = function(имя, реакция) { var кнопка = document.createElement("button"); кнопка.innerHTML = имя; this.иф.appendChild(кнопка); кнопка.onclick = реакция; }; /* * * Свойства модуля * */ function СвойстваМодуля() { this.создатьИнтерфейс(); this.изменилиНомер = new Уведомитель(); this.настроитьНомер(); this.изменилиИмя = new Уведомитель(); this.настроитьИмя(); this.изменилиСтатус = new Уведомитель(); this.настроитьСтатус(); this.удалить = new Уведомитель(); this.настроитьУдаление(); } СвойстваМодуля.prototype.создатьИнтерфейс = function() { this.иф = document.createElement("div"); this.иф.style.cssText = ` border: 1px solid #ddd; /* padding: 0.5em; margin: 0.5em; */ color: #666666; font-family: sans-serif; `; this.таблица = document.createElement("table"); this.иф.appendChild(this.таблица); }; Object.defineProperty(СвойстваМодуля.prototype, "номер", { get: function() { return Number(this.полеНомер.value); }, set: function(значение) { this.полеНомер.value = значение; } }); СвойстваМодуля.prototype.настроитьНомер = function() { var я = this; var ряд = this.таблица.insertRow(); var ячейка = 0; var ключ = ряд.insertCell(ячейка++); ключ.innerHTML = "Номер:"; ключ.style.cssText = "padding: 0.5em;"; var значение = ряд.insertCell(ячейка++); this.полеНомер = document.createElement("input"); this.полеНомер.type = "number"; this.полеНомер.min = 0; значение.style.cssText = "width: 100%; padding: 0.5em;"; this.полеНомер.style.cssText = "width: 100%;"; значение.appendChild(this.полеНомер); this.полеНомер.oninput = function() { я.изменилиНомер.уведомить(); }; }; Object.defineProperty(СвойстваМодуля.prototype, "имя", { get: function() { return this.полеИмя.value; }, set: function(значение) { this.полеИмя.value = значение; } }); СвойстваМодуля.prototype.настроитьИмя = function() { var я = this; var ряд = this.таблица.insertRow(); var ячейка = 0; var ключ = ряд.insertCell(ячейка++); ключ.innerHTML = "Имя:"; ключ.style.cssText = "padding: 0.5em;"; var значение = ряд.insertCell(ячейка++); this.полеИмя = document.createElement("input"); значение.style.cssText = "width: 100%; padding: 0.5em;"; this.полеИмя.style.cssText = "width: 100%;"; значение.appendChild(this.полеИмя); this.полеИмя.oninput = function() { я.изменилиИмя.уведомить(); }; }; Object.defineProperty(СвойстваМодуля.prototype, "статус", { get: function() { return this.переключатель.checked; }, set: function(значение) { this.переключатель.checked = значение; } }); СвойстваМодуля.prototype.настроитьСтатус = function() { var я = this; var ряд = this.таблица.insertRow(); var ячейка = 0; var ключ = ряд.insertCell(ячейка++); ключ.innerHTML = "Исполнять:"; ключ.style.cssText = "padding: 0.5em;"; var значение = ряд.insertCell(ячейка++); this.переключатель = document.createElement("input"); this.переключатель.type = "checkbox"; this.переключатель.style.cssText = "padding: 0.5em;"; значение.appendChild(this.переключатель); this.переключатель.onchange = function() { я.изменилиСтатус.уведомить(); }; ключ.onclick = function() { я.переключатель.checked = !я.переключатель.checked; я.изменилиСтатус.уведомить(); }; }; СвойстваМодуля.prototype.настроитьУдаление = function() { var я = this; var ряд = this.таблица.insertRow(); var ячейка = 0; ряд.insertCell(ячейка++); var значение = ряд.insertCell(ячейка++); this.кнопкаУдалить = document.createElement("button"); this.кнопкаУдалить.innerHTML = "Удалить"; this.кнопкаУдалить.classList.add("муром-кнопка"); значение.appendChild(this.кнопкаУдалить); this.кнопкаУдалить.onclick = function() { я.удалить.уведомить(); }; }; /* * * Тест свойства модуля * */ function ТестСвойстваМодуля() { this.создатьИнтерфейс(); } ТестСвойстваМодуля.prototype.создатьИнтерфейс = function() { var я = this; this.иф = document.createElement("div"); this.свойства = new СвойстваМодуля(); this.иф.appendChild(this.свойства.иф); this.свойства.изменилиНомер.подписать(function(){ console.log("номер: '" + я.свойства.номер + "'"); }); this.свойства.изменилиИмя.подписать(function(){ console.log("имя: '" + я.свойства.имя + "'"); }); this.свойства.изменилиСтатус.подписать(function(){ console.log("статус: '" + я.свойства.статус + "'"); }); this.свойства.удалить.подписать(function(){ console.log("удалить модуль '" + я.свойства.имя + "'"); }); }; /* * * Модули * */ function Модули() { } Модули.prototype.свойства = function(номер) { return murom.moduleProperties(номер); }; Модули.prototype.задатьСвойства = function(номер, свойства) { var м = муром.модули[номер]; м[2] = свойства; }; Модули.prototype.статус = function(номер) { return murom.moduleStatus(номер); }; Модули.prototype.задатьСтатус = function(номер, статус) { var св = this.свойства(номер); св["status"] = статус; this.задатьСвойства(номер, св); }; Модули.prototype.задатьИмя = function(номер, имя) { var м = муром.модули[номер]; м[0] = имя; }; Модули.prototype.задатьНомер = function(старый, новый) { //console.log("задать номер. '" + старый + "' -> '" + новый + "'"); var модуль = муром.модули[старый]; // Удаляем старую запись. муром.модули.splice(старый, 1); // Добавляем модуль в новую позицию. муром.модули.splice(новый, 0, модуль); }; /* * * Панель управления * */ function ПанельУправления() { this.модули = new Модули(); this.создатьОснову(); this.создатьСохранениеСкачиваниеДобавление(); this.создатьСписокМодулей(); this.создатьСвойстваМодуля(); } ПанельУправления.prototype.создатьОбёрткуЯчейку = function() { var обёртка = document.createElement("table"); обёртка.style.cssText = "width: 100%;"; var ряд = обёртка.insertRow(); var ячейка = ряд.insertCell(); return [обёртка, ячейка]; }; ПанельУправления.prototype.создатьОснову = function() { this.иф = document.createElement("table"); this.иф.style.cssText = "width: 100%;"; var ряд = this.иф.insertRow(); this.лево = ряд.insertCell(); this.лево.style.cssText = "width: 100%;"; var право = ряд.insertCell(); право.style.cssText = "height: 100%;"; this.кнопки = document.createElement("table"); this.кнопки.style.cssText = "height: 100%;"; право.appendChild(this.кнопки); ряд = this.иф.insertRow(); this.низ = ряд.insertCell(); this.низ.colSpan = 2; }; ПанельУправления.prototype.создатьСписокМодулей = function() { this.список = new СписокМодулей(); this.список.задатьСписок(this.списокМодулей()); var оя = this.создатьОбёрткуЯчейку(); this.лево.appendChild(оя[0]); оя[1].appendChild(this.список.иф); }; ПанельУправления.prototype.создатьСвойстваМодуля = function() { this.свойства = new СвойстваМодуля(); оя = this.создатьОбёрткуЯчейку(); this.низ.appendChild(оя[0]); оя[1].appendChild(this.свойства.иф); }; ПанельУправления.prototype.списокМодулей = function() { var список = []; for (var номер in муром.модули) { var м = муром.модули[номер]; var статус = this.модули.статус(номер); var имя = м[0]; var элемент = [статус, имя]; список.push(элемент); } return список; }; ПанельУправления.prototype.создатьКнопку = function(имя, уведомитель) { var кнопка = document.createElement("button"); кнопка.innerHTML = имя; кнопка.style.cssText = "width: 100%;"; кнопка.classList.add("муром-кнопка"); кнопка.onclick = function() { уведомитель.уведомить(); }; return кнопка; }; ПанельУправления.prototype.создатьСохранениеСкачиваниеДобавление = function() { var я = this; var ряд = this.кнопки.insertRow(); var ячейка = ряд.insertCell(); this.сохранить = new Уведомитель(); this.кнопкаСохранить = this.создатьКнопку("Сохранить", this.сохранить); ячейка.appendChild(this.кнопкаСохранить); ряд = this.кнопки.insertRow(); ячейка = ряд.insertCell(); this.скачать = new Уведомитель(); this.кнопкаСкачать = this.создатьКнопку("Скачать", this.скачать); ячейка.appendChild(this.кнопкаСкачать); // Пробел. ряд = this.кнопки.insertRow(); ячейка = ряд.insertCell(); ячейка.style.cssText = "height: 100%;"; ряд = this.кнопки.insertRow(); ячейка = ряд.insertCell(); this.добавить = new Уведомитель(); this.кнопкаДобавить = this.создатьКнопку("Добавить", this.добавить); ячейка.appendChild(this.кнопкаДобавить); }; ПанельУправления.prototype.имяФайла = function() { var путь = window.location.pathname; var имя = путь.split("/").pop(); return decodeURI(имя); }; function запуститьПУ() { var пу = new ПанельУправления(); муром.пу = пу; var области = муром.создатьЛевуюПравуюОбласти(); var по = области[1]; по.appendChild(пу.иф); муром.создатьРедакторВЛевойОбласти(); var список = пу.список; var свойства = пу.свойства; var модули = пу.модули; function отобразитьКодВыбранногоМодуля() { var модуль = муром.модули[список.выбор]; var код = муром.atob(модуль[1]); муром.редактор.session.setValue(код); } function отобразитьСвойстваВыбранногоМодуля() { var модуль = муром.модули[список.выбор]; свойства.номер = список.выбор; свойства.имя = модуль[0]; свойства.статус = пу.модули.статус(список.выбор); } список.выбрали.подписатьМного([ отобразитьКодВыбранногоМодуля, отобразитьСвойстваВыбранногоМодуля, ]); function обновитьСтатусМодуля() { var номер = список.выбор; var имя = свойства.имя; var статус = свойства.статус; модули.задатьСтатус(номер, статус); список.обновитьЭлемент(номер, статус, имя); } свойства.изменилиСтатус.подписать(обновитьСтатусМодуля); function обновитьИмяМодуля() { var номер = список.выбор; var имя = свойства.имя; var статус = свойства.статус; модули.задатьИмя(номер, имя); список.обновитьЭлемент(номер, статус, имя); } свойства.изменилиИмя.подписать(обновитьИмяМодуля); function обновитьНомерМодуля() { var старый = список.выбор; var новый = свойства.номер; if (старый == новый) { return; } if (новый > муром.модули.length - 1) { новый = муром.модули.length - 1; } модули.задатьНомер(старый, новый); список.задатьСписок(пу.списокМодулей()); список.выбрать(новый); } свойства.изменилиНомер.подписать(обновитьНомерМодуля); function добавитьМодуль() { var число = Math.floor(Math.random() * Math.floor(1000)); var имя = "новый-" + число; var код = `console.log("НАДО Добавить код в модуль '` + имя + `'");`; var модуль = [имя, муром.btoa(код)]; муром.модули.push(модуль); var модули = пу.списокМодулей(); список.задатьСписок(модули); список.выбрать(модули.length - 1); } пу.добавить.подписать(добавитьМодуль); function удалитьМодуль() { var номер = список.выбор; var статус = пу.модули.статус(номер); if (статус) { alert("ОШИБКА Удалить можно лишь неисполняемый модуль"); return; } // Удалить выбранный модуль. муром.модули.splice(номер, 1); --номер; if (номер < 0) { номер = 0; } var модули = пу.списокМодулей(); список.задатьСписок(модули); список.выбрать(номер); } свойства.удалить.подписать(удалитьМодуль); function сохранитьВыбранныйМодуль() { var модуль = муром.модули[список.выбор]; var код = муром.редактор.session.getValue(); модуль[1] = муром.btoa(код); } function сохранить() { пу.кнопкаСохранить.disabled = true; localforage.setItem("modules", муром.модули, function(ошибка, значение){ пу.кнопкаСохранить.disabled = false; if (ошибка) { console.error("Не удалось сохранить модули: '" + ошибка + "'"); } }); } пу.сохранить.подписатьМного([ сохранитьВыбранныйМодуль, сохранить, ]); // How to create a file in memory for user to download, but not through server? // https://stackoverflow.com/a/18197341 function скачать() { var содержимое = муром.файл.начало; for (var номер in муром.модули) { var модуль = муром.модули[номер]; var имя = модуль[0]; var код64 = модуль[1]; var свойства = модули.свойства(номер); содержимое += ` [ "` + имя + `", "` + код64 + `", ` + JSON.stringify(свойства) + ` ], ` ; } содержимое += муром.файл.конец; содержимое = муром.btoa(содержимое); var ссыль = document.createElement("a"); ссыль.setAttribute("href", "data:text/html;charset=utf-8;base64," + содержимое); var имя = пу.имяФайла(); ссыль.setAttribute("download", имя); ссыль.style.display = "none"; document.body.appendChild(ссыль); ссыль.click(); document.body.removeChild(ссыль); } пу.скачать.подписать(скачать); // При запуске. список.выбрать(0); } /* * * Пуск * */ if (window.location.search == "?0") { console.debug("Запуск панели управления"); задатьВнешнийВид(); запуститьПУ(); console.debug("Панель управления запущена") }