diff --git a/404.shtml b/404.shtml new file mode 100755 index 0000000..d5b3791 --- /dev/null +++ b/404.shtml @@ -0,0 +1,13 @@ + + + + + Страница не найдена + + +

Страница не найдена

+ Запрошенный URL не найден на сервере 404. +
+ + + \ No newline at end of file diff --git a/405.shtml b/405.shtml new file mode 100755 index 0000000..afe0249 --- /dev/null +++ b/405.shtml @@ -0,0 +1,13 @@ + + + + + Страница не найдена + + +

Страница не найдена

+ Запрошенный URL не найден на сервере 405. +
+ + + \ No newline at end of file diff --git a/config/config_site.php b/config/config_site.php new file mode 100755 index 0000000..df4071b --- /dev/null +++ b/config/config_site.php @@ -0,0 +1,13 @@ + + + + + ../../img/favicon.ico + Движок для сайтов + Идеален для сайтов-визиток + + utf-8 + data/users.php + data/request_on_users.php + + \ No newline at end of file diff --git a/content/405.shtml b/content/405.shtml new file mode 100755 index 0000000..afe0249 --- /dev/null +++ b/content/405.shtml @@ -0,0 +1,13 @@ + + + + + Страница не найдена + + +

Страница не найдена

+ Запрошенный URL не найден на сервере 405. +
+ + + \ No newline at end of file diff --git a/content/access.page.php b/content/access.page.php new file mode 100755 index 0000000..d6106d0 --- /dev/null +++ b/content/access.page.php @@ -0,0 +1,106 @@ + + + + + + Суперлёгкий движок + + + + + + + + + + + + + + + + +текст текст текст текст текст текст текст текст текст текст текст тексритчрсотат текст текст текст текст текствяепивыериепчаивекапверыреверыверывеыве +
+ текст текст текст текст текыККПАФЦКАКПАМст текст текст текст текст текст текст текст текст текст урпкцуептекст текст текст +
+
+ текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текстфыкепыуверыер
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+]]>
+ Uz šo brīdi šeit ne kā nav

+ ]]>
+ ??????

+ ]]>
+
+
diff --git a/content/index.page.php b/content/index.page.php new file mode 100755 index 0000000..d5301b6 --- /dev/null +++ b/content/index.page.php @@ -0,0 +1,36 @@ + + + + + + Суперлёгкий движок + + + + + + + + + + + + + + + + +text +]]> + + + + diff --git a/content/rpi/index.page.php b/content/rpi/index.page.php new file mode 100755 index 0000000..0fa9800 --- /dev/null +++ b/content/rpi/index.page.php @@ -0,0 +1,107 @@ + + + + + + Суперлёгкий движок + + + + + + + + + + + + + + + + +текст текст текст текст текст текст текст текст текст текст текст тексритчрсотат текст текст текст текст  +
+ текст текст текст текст текыККПАФЦКАКПАМст текст текст текст текст текст текст текст урпкцуептекст текст текст +
+
+ текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст текст +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+]]>
+   cb bbvcdjyfdyhyhdывепиwstdg

+]]>
+ dfgesgfuyjчнлаг

+]]>
+
+
diff --git a/content/template.page.php b/content/template.page.php new file mode 100755 index 0000000..6a028bd --- /dev/null +++ b/content/template.page.php @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + пппппацфакц

+]]>
+ + Uz šo brīdi šeit ne kā nav

+ ]]> +
+ + ??????

+ ]]> +
+ +
+
diff --git a/data/Basic_functions.js b/data/Basic_functions.js new file mode 100755 index 0000000..6aeb32f --- /dev/null +++ b/data/Basic_functions.js @@ -0,0 +1,1510 @@ +/** + * @file Basic_functions.js + * @brief Основной JavaScript-файл проекта, содержит базовые функции, переменные и настройки +*/ + +/** @brief Действие менеджера */ +window.managerDataAction = ""; +/** @brief Текущий путь */ +window.currentPath = ''; +/** @brief История путей в менеджере */ +window.managerHistoryPaths = [window.currentPath]; +/** @brief Индекс текущего пути в истории */ +window.managerHistoryIndex = 0; +/** @brief Путь к файлу для таблицы менеджера */ +window.managerTableDivFilePath = ""; +/** @brief Имя файла для таблицы менеджера */ +window.managerTableDivFileName = ""; +/** @brief Последнее сохранённое имя страницы */ +window.saveHowNameLast = "index.page.php"; +/** @brief Путь для кнопки открытия страницы */ +window.openPageButPath = "no/Select"; +/** @brief Флаг, определяющий, запущено ли на телефоне */ +window.isPhone = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); +/** @brief Координаты касания по X (для мобильных устройств) */ +window.touchX = 0; +/** @brief Координаты касания по Y (для мобильных устройств) */ +window.touchY = 0; + +/** + * @brief Подключает плагин на страницу + * @param String plugin Имя подключаемого плагина + * @return Promise Разрешается после загрузки всех скриптов плагина +*/ +function includePlugin(plugin) { + return jsonrpcRequest("includePlugin", { plugin }) + .then(html => { + const div = document.createElement('div'); + div.innerHTML = html; + + const scripts = []; + Array.from(div.childNodes).forEach(node => { + if (node.nodeType === 1) node.setAttribute('plugin', plugin); + if (node.tagName === 'SCRIPT') { + const s = document.createElement('script'); + if (node.src) { + s.src = node.src; + s.async = false; + scripts.push(new Promise(res => s.onload = res)); + } else { + s.textContent = node.textContent; + } + document.body.appendChild(s); + } else { + document.body.appendChild(node); + } + }); + + return Promise.all(scripts); + }) + .then(() => { + const event = new Event("Load" + plugin + "Js"); + document.dispatchEvent(event); + window.dispatchEvent(event); + }); +} +window.includePlugin = includePlugin; + +/** + * @brief Удаляет DOM-элементы и скрипты плагина + * @param String plugin Имя удаляемого плагина + * @return Promise Разрешается после удаления всех файлов и элементов плагина +*/ +function removePluginDom(plugin) { + return jsonrpcRequest("removePluginDom", { plugin }) + .then(files => { + files.forEach(f => { + if (f.startsWith('#')) { + const el = document.getElementById(f.slice(1)); + if (el) el.remove(); + } else if (f.endsWith('.css')) { + document.querySelectorAll(`link[href="${f}"]`).forEach(el => el.remove()); + } else if (/\.js(\.php)?(\?.*)?$/.test(f)) { + const nameJs = plugin + "Js"; + delete window[nameJs]; + + const event = new Event('Load' + nameJs); + console.log(document.dispatchEvent(event)); + document.querySelectorAll('script').forEach(el => { + if (el.getAttribute('plugin') === plugin || (el.src && el.src.includes(f))) { + el.remove(); + } + }); + } + }); + + document.querySelectorAll(`[plugin="${plugin}"]`).forEach(el => el.remove()); + }); +} +window.removePluginDom = removePluginDom; + +document.addEventListener('DOMContentLoaded', () => { + const newsPlaceholder = document.getElementById('news-placeholder'); + const centerFloat = document.querySelector('.center-float'); + if (newsPlaceholder && centerFloat) { + centerFloat.appendChild(newsPlaceholder); + } else if (newsPlaceholder && !centerFloat) { + newsPlaceholder.remove(); + } +}); + +(function(){ + const hbody = document.getElementById('hbody') + const menuBtn = document.querySelector('.menu-btn.open') + const sideMenu = document.querySelector('.side-menu') + const smenu = document.getElementById('smenu') + const overlay = document.getElementById('overlay') + let rafId + + function update() { + const elems = [ + document.querySelector('.menu-btn.open'), + document.getElementById('shome'), + document.getElementById('smenu'), + document.getElementById('slng'), + document.getElementById('authorizationButton') + ].filter(Boolean) + + const originalDisplay = new Map() + elems.forEach(el => { + originalDisplay.set(el, el.style.display) + el.style.display = '' + }) + + const totalW = elems.reduce((sum, el) => { + const style = getComputedStyle(el) + return sum + + el.offsetWidth + + parseFloat(style.marginLeft) + + parseFloat(style.marginRight) + }, 0) + + const baseTop = elems[0].offsetTop + const wrapped = elems.some(el => el.offsetTop > baseTop) + + elems.forEach(el => { + el.style.display = originalDisplay.get(el) + }) + + if (totalW > hbody.clientWidth || wrapped) { + menuBtn.style.display = '' + sideMenu.style.display = '' + overlay.style.display = '' + smenu.style.display = 'none' + } else { + menuBtn.style.display = 'none' + sideMenu.style.display = 'none' + overlay.style.display = 'none' + smenu.style.display = '' + } + } + + function onResize() { + cancelAnimationFrame(rafId) + rafId = requestAnimationFrame(update) + } + + window.addEventListener('resize', onResize) + window.addEventListener('load', onResize); +})() +;(function(){ + const menuBtnOpen = document.querySelector('.menu-btn.open'); + const menuBtnClose = document.querySelector('.menu-btn.close'); + const checkbox = document.getElementById('menu-toggle'); + const overlay = document.getElementById('overlay'); + const sideMenu = document.querySelector('.side-menu'); + + menuBtnOpen.addEventListener('click', e => { + e.stopPropagation(); + e.preventDefault(); + checkbox.checked = true; + overlay.classList.add('active') + }); + + menuBtnClose.addEventListener('click', e => { + e.stopPropagation(); + e.preventDefault(); + checkbox.checked = false; + overlay.classList.remove('active') + }); + + checkbox.addEventListener('click', e => { + e.stopPropagation(); + }); + + document.addEventListener('click', e => { + if (!sideMenu.contains(e.target) && !menuBtnOpen.contains(e.target)) { + checkbox.checked = false; + overlay.classList.remove('active') + } + }); +})(); + +/** + * @brief Получает значение cookie по имени + * @param String name Имя cookie + * @return String|null Значение cookie или null, если не найдено +*/ +function getCookie(name) { + const cookies = document.cookie.split(';'); + for (let c of cookies) { + let [key, ...val] = c.trim().split('='); + if (key === name) return val.join('='); + } + return null; +} + +/** + * @brief Обновляет позицию фона и размер элементов редактирования +*/ +function updateEditElements() { + const scale = window.innerWidth <= 549 ? 1.15 : 1; + document.querySelectorAll('.editib, .editimc, .sym').forEach(el => { + if (!el.dataset.origBgX) { + const [origX, origY] = getComputedStyle(el) + .backgroundPosition + .split(' ') + .map(v => parseFloat(v)); + el.dataset.origBgX = origX; + el.dataset.origBgY = origY; + } + + const origX = parseFloat(el.dataset.origBgX); + const origY = parseFloat(el.dataset.origBgY); + + const newX = (origX * scale).toFixed(2) + 'px'; + const newY = (origY * scale).toFixed(2) + 'px'; + el.style.backgroundPosition = `${newX} ${newY}`; + + if (scale > 1) { + el.style.width = '30px'; + el.style.height = '30px'; + el.style.backgroundSize = 'calc(1122px* 1.15)'; + } else { + el.style.width = ''; + el.style.height = ''; + el.style.backgroundSize = ''; + } + }); +} + +window.addEventListener('load', updateEditElements); +window.addEventListener('resize', updateEditElements); + +/** + * @brief Настраивает обработчик движения меню по элементу + * @param String id Идентификатор основного элемента меню + * @param String extraId (опционально) Идентификатор дополнительного элемента для обработки +*/ +function movementMenu(id, extraId = "") { + const el = document.getElementById(id); + const extraEl = extraId ? document.getElementById(extraId) : document.getElementById(id); + if (!el) return; + extraEl.addEventListener("pointerdown", e => { + if (!isPhone) { + coor(e, id); + } + }); +} +window.movementMenu = movementMenu; + +window.addEventListener('load', function(){ + const container=document.querySelector('.toolbar-container') + const panel=document.getElementById('panel') + const arrowLeft=document.getElementById('arrow-left') + if(!container||!panel||!arrowLeft||!('ontouchstart' in window))return + let startX=0 + let currentTranslate=0 + container.addEventListener('touchstart',onTouchStart,{passive:false}) + container.addEventListener('touchmove',onTouchMove,{passive:false}) + container.addEventListener('touchend',onTouchEnd) + function getBounds(){ + const cw=container.scrollWidth + const pw=panel.clientWidth + const aw=arrowLeft.clientWidth + const extra=aw + const maxOffset=24 + const minOffset=pw-cw-extra + return{maxOffset,minOffset} + } + function getCurrentTranslate(){ + const m=window.getComputedStyle(container).transform + return m&&m!=='none'?parseFloat(m.split(',')[4]):0 + } + function onTouchStart(e){ + currentTranslate=getCurrentTranslate() + startX=e.touches[0].clientX + container.style.transition='none' + } + function onTouchMove(e){ + e.preventDefault() + const deltaX=e.touches[0].clientX-startX + const{maxOffset,minOffset}=getBounds() + let nextTranslate=currentTranslate+deltaX + nextTranslate=Math.min(maxOffset,nextTranslate) + nextTranslate=Math.max(minOffset,nextTranslate) + container.style.transform=`translateX(${nextTranslate}px)` + } + function onTouchEnd(){ + currentTranslate=getCurrentTranslate() + } +}) + +addEventListener("pointerup", stco); +addEventListener("touchend", stco); +/** @brief Вертикальное смещение при перемещении элемента */ +let dvV = 0; +/** @brief Горизонтальное смещение при перемещении элемента */ +let dvH = 0; +/** @brief Таймер для удержания перед началом перемещения */ +let holdTimer = null; +/** @brief ID элемента, который в данный момент перемещается */ +let targetId = ""; + +/** + * @brief Запускает процесс захвата координат элемента для перемещения + * @param Event event Событие указателя или касания + * @param String id Идентификатор элемента для перемещения +*/ +function coor(event, id) { + if (event.type === "pointerdown" && event.button !== 0) return; + if (event.target.closest('[contenteditable], input, textarea, select, option, ul, ol')) return; + + const el = document.getElementById(id); + if (!el) return; + + el.style.touchAction = 'none'; + el.style.overscrollBehavior = 'contain'; + + const rect = el.getBoundingClientRect(); + el.style.top = rect.top + "px"; + el.style.left = rect.left + "px"; + removeTranslateOnly(el); + + const clientY = event.touches ? event.touches[0].clientY : event.clientY; + const clientX = event.touches ? event.touches[0].clientX : event.clientX; + dvV = clientY - rect.top; + dvH = clientX - rect.left; + + targetId = id; + clearTimeout(holdTimer); + holdTimer = setTimeout(function() { + if (targetId) { + addEventListener("pointermove", neco, { passive: false }); + addEventListener("touchmove", neco, { passive: false }); + } + }, 100); +} + +/** + * @brief Обновляет позицию перемещаемого элемента при движении указателя или касания + * @param Event event Событие указателя или касания +*/ +function neco(event) { + if (!targetId) return; + event.preventDefault(); + const el = document.getElementById(targetId); + const clientY = event.touches ? event.touches[0].clientY : event.clientY; + const clientX = event.touches ? event.touches[0].clientX : event.clientX; + const fvV = clientY - dvV; + const fvH = clientX - dvH; + el.style.top = fvV + "px"; + el.style.left = fvH + "px"; + if (targetId === "basis3" && fvH < 0) { + el.style.left = "0px"; + } +} + +/** + * @brief Завершает перемещение элемента и убирает обработчики событий +*/ +function stco() { + clearTimeout(holdTimer); + removeEventListener("pointermove", neco, { passive: false }); + removeEventListener("touchmove", neco, { passive: false }); + targetId = ""; +} + +/** + * @brief Удаляет из transform только translate-преобразования + * @param HTMLElement el Элемент, у которого нужно очистить трансформацию +*/ +function removeTranslateOnly(el) { + const tf = el.style.transform.trim(); + if (!tf || tf === 'none') return; + const parts = tf + .split(/\)\s*/) + .map(p => p.trim()) + .filter(p => p && !p.startsWith('translate(') && !p.startsWith('translateX(') && !p.startsWith('translateY(')) + .map(p => p + ')'); + el.style.transform = parts.length > 0 ? parts.join(' ') : ''; +} + +/** + * @brief Создает AJAX-запрос с помощью jQuery + * @param Object data Данные для отправки + * @param Function successCallback Колбэк при успешном ответе +*/ +function createAjaxRequest(data, successCallback) { + $.ajax({ + url: window.location.href, + type: "POST", + data: data, + dataType: "json", + success: successCallback, + error: function(xhr, status, error) { + console.error('Ошибка:', status, error); + messageFunction("{{error}}"); + } + }); + /* console.log(data + " " + successCallback); */ +} +window.createAjaxRequest = createAjaxRequest; + +/** + * @brief Создает объект XMLHttpRequest с преднастроенным POST-запросом + * @param Function callback Функция, вызываемая при завершении запроса + * @return XMLHttpRequest Объект XHR +*/ +function createXHR(callback) { + let xhr = new XMLHttpRequest(); + xhr.open("POST", window.location.href, true); + xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + xhr.onload = callback; + return xhr; +} +window.createXHR = createXHR; + +/** @brief Счетчик идентификаторов для JSON-RPC */ +let rpcId = 0; +/** @brief Флаг блокировки генерации идентификатора */ +let idLock = false; + +/** + * @brief Генерирует следующий уникальный идентификатор для RPC-запроса + * @return Number Уникальный идентификатор +*/ +async function getNextId() { + while (idLock) await new Promise(r => setTimeout(r, 1)) + idLock = true + const id = ++rpcId + idLock = false + return id +} + +/** + * @brief Отправляет JSON-RPC запрос на сервер + * @param String method Имя удаленного метода + * @param Object params Параметры вызова метода + * @return Promise Результат выполнения RPC +*/ +async function jsonrpcRequest(method, params) { + const id = await getNextId() + const payload = { jsonrpc: "2.0", method, params, id } + return fetch(window.location.href, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(payload) + }) + .then(res => { + if (!res.ok) { + messageFunction("HTTP error: " + res.status) + throw new Error(`HTTP ${res.status}`) + } + return res.json() + }) + .then(r => { + if (r.error) { + messageFunction("Error: " + r.error.message) + throw new Error(`RPC function ${method} (id ${r.id}): ${r.error.code} ${r.error.message}`) + } + if (r.id !== id) { + messageFunction("Error: mismatched function id") + throw new Error(`Mismatched id: expected ${id}, got ${r.id}`) + } + return r.result + }) +} + +/** + * @brief Долгое нажатие на телефоне + * @param HTMLElement el Элемент, на который вешается обработчик + * @param Function fn Функция, вызываемая при удержании +*/ +function touchLong(el, fn) { + let timer + el.addEventListener('touchstart', function(e) { + timer = setTimeout(function() { + fn(e) + }, 500) + }, { passive: false }) + el.addEventListener('touchend', function() { + clearTimeout(timer) + }, { passive: true }) + el.addEventListener('touchmove', function() { + clearTimeout(timer) + }, { passive: true }) +} + +document.addEventListener('pointerdown', function(e){ + window.touchX = e.clientX + window.touchY = e.clientY +}, false) + +document.addEventListener('touchstart', function(e){ + window.touchX = e.touches[0].clientX + window.touchY = e.touches[0].clientY +}, { passive: true }) + +/* двойный клик для телефонов */ +if(isPhone){ + document.querySelectorAll('td[ondblclick]').forEach(td=>{ + let lastTap=0 + td.addEventListener('touchend',function(e){ + const now=Date.now() + if(now-lastTap<300){ + const js=td.getAttribute('ondblclick').replace(/;$/,'') + new Function('event',js)(e) + } + lastTap=now + },{passive:true}) + }) +} + +/** @brief Флаг, указывающий, были ли изменения в контенте */ +window.contentIsEdit = false; +if (document.getElementById("content")) { + document.getElementById("content").addEventListener("input", function() { + window.contentIsEdit = true; + }); + const observer = new MutationObserver(() => window.contentIsEdit = true); + observer.observe(document.getElementById("content"), { childList: true, subtree: true }); +} + +/** @brief Очередь сообщений для отображения */ +let messageQueue = []; +window.messageQueue = messageQueue; +/** @brief Флаг, указывающий, создается ли в данный момент сообщение */ +let messageIsCreating = false; + +/** + * @brief Добавляет сообщение в очередь и инициирует его показ + * @param String message Текст сообщения +*/ +function messageFunction(message) { + messageQueue.push(message); + if (!messageIsCreating) { + messageCreate(); + } +} +window.messageFunction = messageFunction; + +/** + * @brief Создает и отображает сообщение пользователю +*/ +function messageCreate() { + if (messageQueue.length === 0) return; + messageIsCreating = true; + + const messageBlock = document.createElement("div"); + messageBlock.classList.add('messageBlock', 'borderStyle'); + document.body.appendChild(messageBlock); + + requestAnimationFrame(() => { + messageBlock.classList.add('show'); + }); + + const messageBasicText = document.createElement('div'); + messageBasicText.classList.add('messageBasicText', 'borderStyle'); + messageBasicText.textContent = "{{message}}"; + + const messageText = document.createElement('div'); + messageText.classList.add('messageText'); + messageText.textContent = messageQueue.shift(); + + const messageButton = document.createElement('div'); + messageButton.classList.add('messageButton', 'borderStyle'); + messageButton.textContent = "{{ok}}"; + messageButton.onclick = messageRemove; + + messageBlock.appendChild(messageBasicText); + messageBlock.appendChild(messageText); + messageBlock.appendChild(messageButton); + + setTimeout(messageRemove, 4000); + + function messageRemove() { + if (messageBlock.parentElement) { + messageBlock.classList.remove('show'); + setTimeout(() => { + messageBlock.remove(); + messageIsCreating = false; + messageCreate(); + }, 150); + } + } +} + +/** @brief Флаг, подтвержден ли пользователь в сообщении-вопросе */ +let userConfirmed = false; +window.messageCreateQuestion = messageCreateQuestion; +/** + * @brief Создает сообщение-вопрос (да/нет) + * @return Promise true если пользователь нажал "Да", иначе false +*/ +function messageCreateQuestion() { + return new Promise((resolve, reject) => { + if (messageQueue.length === 0) return resolve(false); + + messageIsCreating = true; + + let messageBlock = document.createElement("div"); + messageBlock.className = 'messageBlock borderStyle'; + document.body.appendChild(messageBlock); + + requestAnimationFrame(() => { + messageBlock.classList.add('show'); + }); + + let messageBasicText = document.createElement("div"); + messageBasicText.classList.add('messageBasicText', 'borderStyle'); + messageBasicText.textContent = "{{message}}"; + + let messageText = document.createElement("div"); + messageText.className = 'messageText'; + messageText.textContent = messageQueue.shift(); + + let messageButtonNo = document.createElement("div"); + messageButtonNo.classList.add('messageButton', 'borderStyle'); + messageButtonNo.textContent = "{{no}}"; + messageButtonNo.style.float = "right"; + messageButtonNo.onclick = function() { + messageBlock.classList.remove('show'); + setTimeout(() => { + messageBlock.remove(); + messageIsCreating = false; + reject(false); + }, 150); + }; + + let messageButton = document.createElement("div"); + messageButton.classList.add('messageButton', 'borderStyle'); + messageButton.textContent = "{{yes}}"; + messageButton.style.float = "left"; + messageButton.onclick = function() { + messageBlock.classList.remove('show'); + setTimeout(() => { + messageBlock.remove(); + messageIsCreating = false; + resolve(true); + }, 0); + }; + + messageBlock.appendChild(messageBasicText); + messageBlock.appendChild(messageText); + messageBlock.appendChild(messageButtonNo); + messageBlock.appendChild(messageButton); + }); +} + +/** + * @brief Создает сообщение с полем ввода текста + * @param String initial Начальное значение для ввода + * @return Promise Введенный пользователем текст или null при отмене +*/ +function messageCreateInput(initial = '') { + return new Promise((resolve, reject) => { + if (messageQueue.length === 0) return resolve(false); + + messageIsCreating = true; + + const messageBlock = document.createElement("div"); + messageBlock.classList.add("messageBlock", "borderStyle"); + document.body.appendChild(messageBlock); + + requestAnimationFrame(() => { + messageBlock.classList.add("show"); + }); + + const messageBasicText = document.createElement("div"); + messageBasicText.classList.add("messageBasicText", "borderStyle"); + messageBasicText.style.fontSize = '1.4em'; + messageBasicText.textContent = messageQueue.shift(); + + const messageInput = document.createElement("input"); + messageInput.classList.add("messageInput", "borderStyle"); + messageInput.value = initial; + messageInput.type = "text"; + + const messageButtonOk = document.createElement("div"); + messageButtonOk.classList.add("messageButton", "borderStyle"); + messageButtonOk.textContent = "{{ok}}"; + messageButtonOk.onclick = function() { + const value = messageInput.value; + messageBlock.classList.remove("show"); + setTimeout(() => { + messageBlock.remove(); + messageIsCreating = false; + resolve(value); + messageCreate(); + }, 150); + }; + + const messageButtonCancel = document.createElement("div"); + messageButtonCancel.classList.add("messageButton", "borderStyle"); + messageButtonCancel.textContent = "{{cancel}}"; + messageButtonCancel.style.width = 'auto'; + messageButtonCancel.style.float = 'right'; + messageButtonCancel.onclick = function() { + messageBlock.classList.remove("show"); + setTimeout(() => { + messageBlock.remove(); + messageIsCreating = false; + resolve(null); + messageCreate(); + }, 150); + }; + + messageBlock.appendChild(messageBasicText); + messageBlock.appendChild(messageInput); + messageBlock.appendChild(messageButtonOk); + messageBlock.appendChild(messageButtonCancel); + }); +} + +/** @brief Счётчик для переключения режима отображения HTML */ +let cou=1; +/** + * @brief Показать/скрыть HTML-код страницы в textarea +*/ +function showHtmlCode() { + if (cou==1) { + document.getElementById("tex").value=document.getElementById("content").innerHTML; + document.getElementById("tex").value = decodeHtmlEntities(document.getElementById("tex").value); + document.getElementById("tex").value = formatHTML(document.getElementById("tex").value); + let sbe=document.getElementsByClassName("sb"); + for(let i=0; i { + if (ans == 'true') { + console.log("{{main_block_saved}}"); + } else { + messageFunction("{{main_block_not_saved}}"); + } + }); + } + +/** + * @brief Сохраняет данные подключённых плагинов (левой и правой колонок) +*/ + function savePlugins() { + let pluginsFloatsId = ["left-float", "right-float"]; + let floatsBlockKeys = ["lblock", "rblock"]; + let requestsData = { + left: [], + right: [] + }; + + pluginsFloatsId.forEach((pluginsFloatId, i) => { + let plugins = document.getElementById(pluginsFloatId).querySelectorAll('.plugin-url'); + plugins.forEach(plugin => { + let pluginData = { + pluginUrl: plugin.pluginUrl, + title: "", + tclass: "", + bclass: "" + }; + let tElem = plugin.querySelector('[tclass]'); + pluginData.title = tElem ? tElem.textContent.trim() : ""; + pluginData.tclass = tElem ? tElem.getAttribute('class') : ""; + let bElem = plugin.querySelector('[bclass]'); + pluginData.bclass = bElem ? bElem.getAttribute('class') : ""; + + let blockKey = floatsBlockKeys[i]; + let blockArray = (blockKey === "lblock") ? requestsData.left : requestsData.right; + blockArray.push(pluginData); + }); + }); + + let data = `floatsBlock=${encodeURIComponent(JSON.stringify(requestsData))}`; + + jsonrpcRequest("savePageSideBlocks", { floatsBlock: JSON.stringify(requestsData) }).then(response => { + console.log(response); + }); +} + +/** + * @brief Сохраняет заголовок страницы +*/ +function saveHeading() { + document.querySelectorAll('#mainTitle').forEach((editTitle) => { + if (functionOpenPage === true) { + messageFunction("{{open_page}}"); + } else { + let newTitle = editTitle.innerHTML.trim(); + if (newTitle === "") { + messageFunction("{{plugin_title_empty_error}}"); + } else { + jsonrpcRequest("savePageTitle", { newTitle }).then(response => { + console.log(response); + }); + } + } + }); +} + +/** + * @brief Декодирует HTML-сущности (&...;) + * @param String str Строка для декодирования + * @return String Декодированная строка +*/ +function decodeHtmlEntities(str) { + var textarea = document.createElement('textarea'); + textarea.innerHTML = str; + return textarea.value; +} +/** + * @brief Форматирует HTML-код (переносы строк и отступы) + * @param String html Исходный HTML + * @return String Отформатированный HTML +*/ +function formatHTML(html) { + html = html.replace(/<([^\/][^>\s]*)[^>]*>/g, "\n$&\n"); + html = html.replace(/<\/([^>\s]*)>/g, "\n$&\n"); + html = html.replace(/^\s*[\r\n]/gm, ''); + + let lines = html.split('\n'); + let indentLevel = 0; + let indentSize = 2; + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + if (line.match(/^<\/[^>]+>/)) indentLevel--; + if (line.match(/^<\/[^>]+>/) || line.match(/^<[^\/>]+[^>]*>$/)) lines[i] = ' '.repeat(indentLevel * indentSize) + line; + if (line.match(/^<[^\/>]+[^>]*>$/)) indentLevel++; + } + html = lines.join('\n'); + return html; +} + +/** + * @brief Сохраняет изменения в новый файл + * @param String currentPath Текущий путь + * @return Promise +*/ +window.saveContentIdHow = async function (currentPath) { + if (cou == 1) { + document.getElementById("content").innerHTML = decodeHtmlEntities(document.getElementById("content").innerHTML); + document.getElementById("tex").value = document.getElementById("content").innerHTML; + } + document.getElementById("tex").value = decodeHtmlEntities(document.getElementById("tex").value); + let saveContentIdData = document.getElementById("tex").value.trim(); + let nameFile = document.getElementById('saveHowName').value; + if (!nameFile.endsWith('.page.php')) { + nameFile += '.page.php'; + messageQueue.push('{{page_must_end_with_page_php}}'); + return; + } + messageQueue.push('{{save_file_as}} ' + nameFile + '?'); + if (!(await messageCreateQuestion())) { + return; + } + let ans = await jsonrpcRequest("checkFile", { path: currentPath, nameFile: nameFile }); + if (ans == 'true') { + messageQueue.push(`{{file}} ${nameFile} {{exists_overwrite_prompt}}`); + if (!(await messageCreateQuestion())) { + return; + } + sendSaveRequest(currentPath, nameFile, saveContentIdData, true); + window.newPageFunValue = ""; + document.getElementById("mainTitle").innerHTML = "{{new_file}}"; + } else if (ans == 'false') { + createNewFile(currentPath, nameFile, saveContentIdData); + window.newPageFunValue = ""; + document.getElementById("mainTitle").innerHTML = "{{new_file}}"; + } else { + messageQueue.push("{{file_save_failed}}"); + } + managerData(currentPath); + document.getElementById("managerDiv").style.visibility = "hidden"; +}; + +/** + * @brief Отправляет запрос на сохранение страницы + * @param String currentPath Текущий путь + * @param String nameFile Имя файла + * @param String saveContentIdData Содержимое + * @param Boolean overwrite Перезаписать существующий файл +*/ +function sendSaveRequest(currentPath, nameFile, saveContentIdData, overwrite = false) { + let pluginsFloatsId = ["left-float", "right-float"]; + let floatsBlockKeys = ["lblock", "rblock"]; + let requestsData = { floatsBlock: [], title: [], pluginUrl: [], tclass: [], bclass: [] }; + + pluginsFloatsId.forEach((id, i) => { + document.getElementById(id).querySelectorAll('.plugin-url').forEach(plugin => { + requestsData.floatsBlock.push(floatsBlockKeys[i]); + let tElem = plugin.querySelector('[tclass]'); + requestsData.title.push(tElem ? tElem.textContent.trim() : ""); + requestsData.pluginUrl.push(plugin.pluginUrl); + requestsData.tclass.push(tElem ? tElem.getAttribute('class') : ""); + let bElem = plugin.querySelector('[bclass]'); + requestsData.bclass.push(bElem.getAttribute('class')); + }); + }); + + let params = { + page_url: currentPath, + nameFile: nameFile, + overwrite: overwrite, + saveContentIdData: saveContentIdData, + floatsBlock: requestsData.floatsBlock, + title: requestsData.title, + pluginUrl: requestsData.pluginUrl, + tclass: requestsData.tclass, + bclass: requestsData.bclass, + }; + + jsonrpcRequest("saveHowPageContent", params).then(ans => { + messageFunction("{{changes_saved_successfully}}"); + managerData(currentPath); + document.getElementById("managerDiv").style.visibility = "hidden"; + }); +} + +/** + * @brief Создаёт новый файл страницы + * @param String currentPath Текущий путь + * @param String nameFile Имя файла + * @param String saveContentIdData Содержимое +*/ +function createNewFile(currentPath, nameFile, saveContentIdData) { + jsonrpcRequest("createNewPage", { saveContentIdData, page_url: currentPath, nameFile }).then(ans => { + if (ans == 'true') { + messageFunction(`{{file}} ${nameFile} {{created_successfully}}!`); + } + managerData(currentPath); + document.getElementById("managerDiv").style.visibility = "hidden"; + }); +} + +/** + * @brief Формирует строку запроса для XMLHttpRequest + * @param Array dataNames Массив имён параметров + * @param Array dataValues Массив значений параметров + * @return String Строка запроса +*/ +function createQueryString(dataNames, dataValues) { + let data = ""; + for (let i = 0; i < dataNames.length; i++) { + data += `${dataNames[i]}=${encodeURIComponent(dataValues[i])}&`; + } + return data.slice(0, -1); +} + +/** + * @brief Переключает отображение меню настроек сайта +*/ +window.toggleMenu = function() { + document.getElementById('siteSettings').style.display = document.getElementById('siteSettings').style.display === 'none' || document.getElementById('siteSettings').style.display === '' ? 'block' : 'none'; +}; + +/** + * @brief Скрывает меню настроек сайта при клике вне кнопки +*/ +window.onclick = function(event) { + var btn = document.getElementById('siteSettingsButton'); + var settings = document.getElementById('siteSettings'); + if (btn && !btn.contains(event.target)) { + settings && (settings.style.display = 'none'); + } +}; + +/** @brief Режим настроек древа сайта */ +window.treeSettingsMode = ""; +/** + * @brief Открывает/закрывает древо сайта +*/ +function basisVisSiteTree() { + siteTreeGeneration(); + window.treeSettingsMode = ""; + let treeDiv = document.getElementById("treeDiv"); + if (treeDiv.style.visibility=="hidden") { + treeDiv.style.visibility = "visible"; + if(isPhone) closeWindows("treeDiv"); + } else { + treeDiv.style.visibility = "hidden"; + document.getElementById("treeProperties").style.visibility = "hidden"; + } + + document.getElementById('treeCloseFun').onclick = function() { + treeDiv.style.visibility = "hidden"; + document.getElementById("treeProperties").style.visibility = "hidden"; + }; + + treeSettings(); +} +window.basisVisSiteTree = basisVisSiteTree; + +/** + * @brief Включает режим выбора ссылки из древа сайта +*/ +function linkFromPage() { + siteTreeGeneration(); + window.treeSettingsMode = 'linkFromPage'; + let treeDiv = document.getElementById("treeDiv"); + treeDiv.style.visibility = "visible"; + + document.getElementById('treeCloseFun').onclick = function() { + treeDiv.style.visibility = "hidden"; + document.getElementById("treeProperties").style.visibility = "hidden"; + }; + + treeSettings(); +} +window.linkFromPage = linkFromPage; + +/** + * @brief Переключает отображение дочерних элементов в древе + * @param HTMLElement el Элемент, по которому кликнули +*/ +function toggleChildren(el) { + let details = el.closest('li').querySelector('.details'); + if (!details) return; + details.style.display = details.style.display === 'none' ? 'block' : 'none'; + el.querySelector('.tree-marker').textContent = details.style.display === 'block' ? '▼' : '►'; +} +window.toggleChildren = toggleChildren; + +/** + * @brief Открывает/закрывает менеджер файлов и папок +*/ +function basisVisManager() { + let managerDiv = document.getElementById('managerDiv'); + if (managerDiv.style.visibility === "hidden") { + managerDiv.style.visibility = "visible"; + window.managerDataAction = ""; + managerData(currentPath); + if(isPhone) closeWindows("managerDiv"); + } else { + managerDiv.style.visibility = "hidden"; + document.getElementById("managerProperties").style.visibility = "hidden"; + } +} +window.basisVisManager = basisVisManager; + +/** + * @brief Закрывает одно окно при открытии другого (managerDiv/treeDiv) + * @param String div Идентификатор открываемого окна +*/ +function closeWindows(div) { + if (div == "managerDiv") { + document.getElementById("treeDiv").style.visibility = "hidden"; + document.getElementById("treeProperties").style.visibility = "hidden"; + } else if (div == "treeDiv") { + document.getElementById("managerDiv").style.visibility = "hidden"; + document.getElementById("managerProperties").style.visibility = "hidden"; + } +} + +/** + * @brief Обновляет данные менеджера файлов для указанного пути + * @param String path Путь к папке +*/ +function managerData(path) { + currentPath = path + if (managerHistoryPaths[managerHistoryIndex] !== currentPath) { + managerHistoryPaths = managerHistoryPaths.slice(0, managerHistoryIndex + 1) + managerHistoryPaths.push(currentPath) + managerHistoryIndex++ + } + jsonrpcRequest("getFolderContents", { managerPathFolder: path }).then(data => { + let rows = '' + for (let i = 0; i < data.length; i++) { + if (data[i].name) { + let newPath = `${path}/${data[i].name}` + let attr = 'style="cursor: pointer; display: flex; align-items: center;" ' + if (data[i].type === '{{file}}') { + let dbl = 'ondblclick="managerData(\'' + newPath + '\');"' + attr += isPhone + ? 'onclick="managerData(\'' + newPath + '\');" ' + dbl + : dbl + } else if (data[i].name.endsWith('.page.php')) { + let page = newPath.replace('.page.php', '') + let dbl = 'ondblclick="getPage(\'' + page + '\');"' + attr += isPhone + ? 'onclick="getPage(\'' + page + '\');" ' + dbl + : dbl + } + let icon = data[i].type === '{{file}}' + ? '
' + : '
' + let unit = data[i].type === '{{file}}' ? ' files' : ' bytes' + let sizeText = data[i].size + unit + let nameCell = isPhone + ? `
+
${icon}${data[i].name}
+
${sizeText}
+
` + : `${icon}${data[i].name}` + rows += ` + + ${nameCell} + ${isPhone ? '' : `${sizeText}`} + ${data[i].creationTime} + ` + } + } + + let actionButton = '' + if (document.getElementById('saveHowName')) { + if (document.getElementById('saveHowName').value === '{{select_file}}') { + document.getElementById('saveHowName').value = 'index.page.php' + } + saveHowNameLast = document.getElementById('saveHowName').value + document.getElementById('saveHowButton').removeEventListener('click', saveHow) + document.getElementById('saveHowButton').removeEventListener('click', openPageBut) + } + let managerTopTitleName = '{{file_manager_title}}' + if (window.managerDataAction === 'saveHow') { + actionButton = `
{{name}}: {{save}}
` + managerTopTitleName = '{{save}} как' + } else if (window.managerDataAction === 'getPage') { + actionButton = `
{{name}}: {{open}}
` + managerTopTitleName = '{{open}}' + } else if (window.managerDataAction === 'propertiesUrl') { + actionButton = `
{{name}}: Выбрать
` + managerTopTitleName = '{{open}}' + } else if (window.managerDataAction === 'selectImgForm') { + actionButton = `
{{name}}: {{open}}
` + managerTopTitleName = '{{choose}}' + } else if (window.managerDataAction === 'selectImgFormToForm') { + actionButton = `
{{name}}: {{open}}
` + managerTopTitleName = '{{choose}}' + } + + let sizeHeader = isPhone ? '' : `{{column_size_bytes}}` + let dateWidth = isPhone ? '55%' : '23%' + + managerDiv.innerHTML = ` +
+ ${managerTopTitleName} + +
+
+ + + + +  /  + ${currentPath.split('/').filter(Boolean).map((seg, idx) => { + let segPath = '/' + currentPath.split('/').slice(1, idx + 2).join('/') + return ` ${seg} /` + }).join('')} + +
+
+ + + + ${sizeHeader} + + + ${rows} +
{{name}}{{column_creation_date}}
+
+ ${actionButton} + ` + + if (window.managerDataAction === 'saveHow') { + document.getElementById('saveHowButton').addEventListener('click', saveHow) + } else if (window.managerDataAction === 'getPage') { + document.getElementById('saveHowButton').addEventListener('click', openPageBut) + } else if (window.managerDataAction === 'propertiesUrl') { + document.getElementById('saveHowButton').addEventListener('click', propertiesUrlFun) + } else if (window.managerDataAction === 'selectImgForm') { + document.getElementById('saveHowButton').addEventListener('click', selectImgFormButFun) + } else if (window.managerDataAction === 'selectImgFormToForm') { + document.getElementById('saveHowButton').addEventListener('click', selectImgFormToFormButFun) + } + + openPageButPath = 'no/Select' + if (window.managerDataAction === 'getPage') { + document.querySelectorAll('.managerTableDivFile').forEach(el => { + el.addEventListener('click', function() { + openPageButPath = 'no/Select' + const td = this.querySelector('td') + const dbl = td.getAttribute('ondblclick') || '' + if (dbl.includes('getPage')) { + const m = dbl.match(/getPage\(['"]([^'"]+)['"]\)/) + if (m) openPageButPath = m[1] + const inp = document.getElementById('saveHowName') + if (inp) inp.value = td.innerText + } + }) + }) + } else if (window.managerDataAction === 'selectImgForm') { + document.querySelectorAll('.managerTableDivFile').forEach(el => { + el.addEventListener('click', function() { + openPageButPath = 'no/Select' + const td = this.querySelector('td') + if (td) { + openPageButPath = td.getAttribute('data-path') || openPageButPath + const inp = document.getElementById('saveHowName') + if (inp) inp.value = td.innerText + } + }) + }) + } else if (window.managerDataAction === 'selectImgFormToForm') { + document.querySelectorAll('.managerTableDivFile').forEach(el => { + el.addEventListener('click', function() { + openPageButPath = 'no/Select' + const td = this.querySelector('td') + if (td) { + openPageButPath = td.getAttribute('data-path') || openPageButPath + const inp = document.getElementById('saveHowName') + if (inp) inp.value = td.innerText + } + }) + }) + } else if (window.managerDataAction === 'saveHow' || window.managerDataAction === 'propertiesUrl') { + document.querySelectorAll('.managerTableDivFile').forEach(el => { + el.addEventListener('click', function() { + openPageButPath = 'no/Select' + const td = this.querySelector('td') + if (!td) return + let dbl = td.getAttribute('ondblclick') || '' + if (dbl.includes('getPage')) { + let nd = dbl.replace(/getPage\(['"][^'"]+['"]\)/, '') + if (!nd.trim()) td.removeAttribute('ondblclick') + else td.setAttribute('ondblclick', nd) + } + const inp = document.getElementById('saveHowName') + if (inp) inp.value = td.innerText + }) + }) + } + + managerSettings() + managerFun() + }) +} + +/** @brief Флаг открытия страницы */ +window.functionOpenPage = false; +/** + * @brief Загружает страницу по указанному пути + * @param String newPath Путь к новой странице +*/ +function getPage(newPath) { + window.functionOpenPage = true; + jsonrpcRequest("getPage", { newPath }).then(page => { + document.getElementById("right-float").innerHTML = page.right; + document.getElementById("left-float").innerHTML = page.left; + document.getElementById("content").innerHTML = page.content; + document.getElementById("managerDiv").style.visibility = "hidden"; + // history.pushState(null, '', page.pagePath); + document.getElementById("mainTitle").innerHTML = "{{new_file}}!"; + }); + window.newPageFunValue = ""; +} + +//обьявление функции для того, чтобы обращатся к ней из других файлов +window.getPage = getPage; +window.managerData = managerData; + +/* Функция z-index элементов */ +document.addEventListener("DOMContentLoaded", function() { + var selectors = [ + '#basis3 .cust', + '#managerDiv #managerSettings', + '#managerProperties', + '#treeDiv #treeSettings', + '#treeProperties', + '#authorizationDiv' + ]; + + var groups = selectors.map(function(sel) { + var parts = sel.split(' '); + var elements = []; + + parts.forEach(function(part) { + if (part.startsWith('#')) { + var el = document.getElementById(part.slice(1)); + if (el) elements.push(el); + } + if (part.startsWith('.')) { + elements.push(...document.getElementsByClassName(part.slice(1))); + } + }); + + return elements; + }); + + var queue = []; + + document.addEventListener('pointerdown', function(e) { + var clickedGroup = -1; + + groups.forEach(function(group, idx) { + if (group.some(el => el.contains(e.target))) { + clickedGroup = idx; + } + }); + + if (clickedGroup !== -1) { + var i = queue.indexOf(clickedGroup); + if (i !== -1) queue.splice(i, 1); + queue.unshift(clickedGroup); + } + + var result = selectors.map((_, idx) => { + var pos = queue.indexOf(idx); + return pos === -1 ? 100 : 199 - pos; + }); + + groups.forEach(function(group, idx) { + group.forEach(function(el) { + el.style.zIndex = result[idx]; + }); + }); + }); + + var selectorsElements = [ + '#basis3', + '.cust', + '#managerDiv', + '#managerSettings', + '#managerProperties', + '#treeDiv', + '#treeSettings', + '#treeProperties', + '#authorizationDiv' + ]; + + var observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + if (mutation.attributeName === 'style') { + var el = mutation.target; + var oldVal = mutation.oldValue || ''; + var newVis = el.style.visibility; + if (newVis === 'visible' && !/visibility\s*:\s*visible/.test(oldVal)) { + selectorsElements.forEach(function(sel) { + document.querySelectorAll(sel).forEach(function(item) { + if (item === el) { + item.style.zIndex = 199; + } else { + let z = parseInt(item.style.zIndex, 10) || 100; + item.style.zIndex = z > 100 ? z - 1 : 100; + } + }); + }); + } + } + }); + }); + + selectorsElements.forEach(function(sel) { + document.querySelectorAll(sel).forEach(function(el) { + observer.observe(el, { + attributes: true, + attributeFilter: ['style'], + attributeOldValue: true + }); + }); + }); + + document.querySelectorAll('.cust').forEach(el=>{ + let hideTimer, watchTimer, watching=false + const observer = new MutationObserver(muts=>{ + muts.forEach(m=>{ + if(m.attributeName==='style' && getComputedStyle(el).visibility==='visible'){ + watching = false + clearTimeout(watchTimer) + watchTimer = setTimeout(()=> watching = true, 0) + } + }) + }) + observer.observe(el, { attributes: true, attributeFilter: ['style'] }) + + document.addEventListener('pointerdown', e=>{ + if(watching && getComputedStyle(el).visibility==='visible' && !el.contains(e.target)){ + clearTimeout(hideTimer) + hideTimer = setTimeout(()=> el.style.visibility = 'hidden', 0) + } + }) + + el.addEventListener('pointerdown', e=>{ + e.stopPropagation() + clearTimeout(hideTimer) + }) + }) + + function updateZIndices() { + const result = selectors.map((_, idx) => { + const pos = queue.indexOf(idx); + return pos === -1 ? 100 : 199 - pos; + }); + groups.forEach((group, idx) => { + group.forEach(el => el.style.zIndex = result[idx]); + }); + } + + var observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + if (mutation.attributeName === 'style') { + const el = mutation.target; + const oldVal = mutation.oldValue || ''; + const newVis = getComputedStyle(el).visibility; + if (newVis === 'visible' && !/visibility\s*:\s*visible/.test(oldVal)) { + selectors.forEach((sel, idx) => { + groups[idx].forEach(member => { + if (member === el) { + const i = queue.indexOf(idx); + if (i !== -1) queue.splice(i, 1); + queue.unshift(idx); + updateZIndices(); + } + }); + }); + } + } + }); + }); +}); + +/* путь элементов */ +document.querySelectorAll('#left-float [plugin-url], #right-float [plugin-url]').forEach((el) => { + el.pluginUrl = el.getAttribute('plugin-url'); + el.classList.add('plugin-url'); + el.removeAttribute('plugin-url'); +}); + +/* редактирования заголовков */ +window.addEventListener('load', function() { + const editable = document.querySelector('#mainTitle'); + const observer = new MutationObserver(() => { + const txt = editable.textContent.replace(/\u00A0/g, ' '); + if (editable.innerHTML !== txt) { + const sel = window.getSelection(); + const anchorNode = sel.anchorNode; + const anchorOffset = sel.anchorOffset; + observer.disconnect(); + editable.textContent = txt; + const range = document.createRange(); + let node = editable.firstChild || editable; + const offset = Math.min(anchorOffset, node.textContent.length); + range.setStart(node, offset); + range.collapse(true); + sel.removeAllRanges(); + sel.addRange(range); + observer.observe(editable, { childList: true, subtree: true, characterData: true }); + } + }); + if(editable && editable.nodeType === 1){ + observer.observe(editable, { childList: true, subtree: true, characterData: true }); + } +}); diff --git a/data/createSite.page.php b/data/createSite.page.php new file mode 100755 index 0000000..ee93dac --- /dev/null +++ b/data/createSite.page.php @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + Добро пожаловать на страницу создания сайта!

+

Для начала редактирования намите на шестерёнку, чтобы открыть меню:

+

+ +
+

Чтобы редактировать страницу нажмите на :

+

+

Для сохранения, открытия и создания новой страницы используйте .

+

Для создания боковых панелей используйте .

+ +
+

Чтобы редактировать древо сайта нажмите на :

+

+

Чтобы сохранить изменения на странице, используйте кнопку на панели древа сайта.

+

Для изменения свойств элемента в древе сайта нажмите на страницу правой кнопкой мыши или зажмите пальцем, выберите , внесите нужные изменения и нажмите , чтобы сохранить их.

+ +
+

Чтобы редактировать файлы нажмите на :

+

+

Для открытия папок в файловом менеджере используйте одинарный или двойной клик по папке. Перемещаться по папкам можно также с помощью стрелок истории и или кнопки из папки.

+

Чтобы открыть свойства файла, нажмите или зажмите файл и выберите .

+ ]]>
+Welcome to the site creation page!

+

To start editing, click the gear to open the menu:

+

+ +
+

To edit the page, click :

+

+

To save, open, or create a new page, use the .

+

To create side panels use the .

+ +
+

To edit the site tree click :

+

+

To save changes on the page use the button on the site tree panel.

+

To change the properties of an element in the site tree, right-click the page or press and hold it, select , make the changes and click to save them.

+ +
+

To edit files click :

+

+

To open folders in the file manager use a single or double click on the folder. You can also navigate folders using the history arrows and or the folder's button.

+

To open file properties, click or press and hold the file and choose .

+]]>
+ +Laipni lūdzam vietnes izveides lapā!

+

Lai sāktu rediģēšanu, noklikšķiniet uz zobrata, lai atvērtu izvēlni:

+

+ +
+

Lai rediģētu lapu, noklikšķiniet uz :

+

+

Lai saglabātu, atvērtu vai izveidotu jaunu lapu, izmantojiet .

+

Sānu paneļu izveidei izmantojiet .

+ +
+

Lai rediģētu vietnes struktūru, noklikšķiniet uz :

+

+

Lai saglabātu izmaiņas lapā, izmantojiet pogu uz vietnes koka paneļa.

+

Lai mainītu elementa īpašības vietnes kokā, noklikšķiniet uz lapas ar peles labo pogu vai paturiet to nospiestu ar pirkstu, izvēlieties , veiciet izmaiņas un nospiediet , lai saglabātu tās.

+ +
+

Lai rediģētu failus noklikšķiniet uz :

+

+

Lai atvērtu mapes failu pārvaldniekā, izmantojiet vienreizēju vai dubultklikšķi uz mapes. Pārvietoties pa mapēm var arī ar vēstures bultiņām un vai pogu mapē.

+

Lai atvērtu faila īpašības, noklikšķiniet vai paturiet failu un izvēlieties .

+]]>
+
+
diff --git a/data/filepath.en.php b/data/filepath.en.php new file mode 100755 index 0000000..eec5350 --- /dev/null +++ b/data/filepath.en.php @@ -0,0 +1,9 @@ + + + + Raspberry Pi + + Raspberry Pi + + + \ No newline at end of file diff --git a/data/filepath.lv.php b/data/filepath.lv.php new file mode 100755 index 0000000..ad01772 --- /dev/null +++ b/data/filepath.lv.php @@ -0,0 +1,7 @@ + + + RaspberryqePi + Raspberry Pi + + + diff --git a/data/filepath.ru.php b/data/filepath.ru.php new file mode 100755 index 0000000..6aa3697 --- /dev/null +++ b/data/filepath.ru.php @@ -0,0 +1,19 @@ + + + site + site + + + + + + + + + + + + + + + diff --git a/data/fonts/Lora/Lora-Bold.ttf b/data/fonts/Lora/Lora-Bold.ttf new file mode 100755 index 0000000..530c9e1 Binary files /dev/null and b/data/fonts/Lora/Lora-Bold.ttf differ diff --git a/data/fonts/Lora/Lora-Italic.ttf b/data/fonts/Lora/Lora-Italic.ttf new file mode 100755 index 0000000..d93bc5f Binary files /dev/null and b/data/fonts/Lora/Lora-Italic.ttf differ diff --git a/data/fonts/Lora/Lora-Regular.ttf b/data/fonts/Lora/Lora-Regular.ttf new file mode 100755 index 0000000..2b1dab4 Binary files /dev/null and b/data/fonts/Lora/Lora-Regular.ttf differ diff --git a/data/fonts/Merriweather/Merriweather-Bold.ttf b/data/fonts/Merriweather/Merriweather-Bold.ttf new file mode 100755 index 0000000..3e10e02 Binary files /dev/null and b/data/fonts/Merriweather/Merriweather-Bold.ttf differ diff --git a/data/fonts/Merriweather/Merriweather-Italic.ttf b/data/fonts/Merriweather/Merriweather-Italic.ttf new file mode 100755 index 0000000..8e9d03d Binary files /dev/null and b/data/fonts/Merriweather/Merriweather-Italic.ttf differ diff --git a/data/fonts/Merriweather/Merriweather-Regular.ttf b/data/fonts/Merriweather/Merriweather-Regular.ttf new file mode 100755 index 0000000..3fecc77 Binary files /dev/null and b/data/fonts/Merriweather/Merriweather-Regular.ttf differ diff --git a/data/fonts/Montserrat/Montserrat-Bold.ttf b/data/fonts/Montserrat/Montserrat-Bold.ttf new file mode 100755 index 0000000..0927b81 Binary files /dev/null and b/data/fonts/Montserrat/Montserrat-Bold.ttf differ diff --git a/data/fonts/Montserrat/Montserrat-Italic.ttf b/data/fonts/Montserrat/Montserrat-Italic.ttf new file mode 100755 index 0000000..cff3ceb Binary files /dev/null and b/data/fonts/Montserrat/Montserrat-Italic.ttf differ diff --git a/data/fonts/Montserrat/Montserrat-Regular.ttf b/data/fonts/Montserrat/Montserrat-Regular.ttf new file mode 100755 index 0000000..f4a266d Binary files /dev/null and b/data/fonts/Montserrat/Montserrat-Regular.ttf differ diff --git a/data/fonts/OpenSans/OpenSans-Bold.ttf b/data/fonts/OpenSans/OpenSans-Bold.ttf new file mode 100755 index 0000000..98c74e0 Binary files /dev/null and b/data/fonts/OpenSans/OpenSans-Bold.ttf differ diff --git a/data/fonts/OpenSans/OpenSans-Italic.ttf b/data/fonts/OpenSans/OpenSans-Italic.ttf new file mode 100755 index 0000000..29ff693 Binary files /dev/null and b/data/fonts/OpenSans/OpenSans-Italic.ttf differ diff --git a/data/fonts/OpenSans/OpenSans-Regular.ttf b/data/fonts/OpenSans/OpenSans-Regular.ttf new file mode 100755 index 0000000..67803bb Binary files /dev/null and b/data/fonts/OpenSans/OpenSans-Regular.ttf differ diff --git a/data/fonts/PT_Serif/PTSerif-Bold.ttf b/data/fonts/PT_Serif/PTSerif-Bold.ttf new file mode 100755 index 0000000..36d47eb Binary files /dev/null and b/data/fonts/PT_Serif/PTSerif-Bold.ttf differ diff --git a/data/fonts/PT_Serif/PTSerif-Italic.ttf b/data/fonts/PT_Serif/PTSerif-Italic.ttf new file mode 100755 index 0000000..9b110a4 Binary files /dev/null and b/data/fonts/PT_Serif/PTSerif-Italic.ttf differ diff --git a/data/fonts/PT_Serif/PTSerif-Regular.ttf b/data/fonts/PT_Serif/PTSerif-Regular.ttf new file mode 100755 index 0000000..f87c0f1 Binary files /dev/null and b/data/fonts/PT_Serif/PTSerif-Regular.ttf differ diff --git a/data/fonts/Playfair_Display/PlayfairDisplay-Bold.ttf b/data/fonts/Playfair_Display/PlayfairDisplay-Bold.ttf new file mode 100755 index 0000000..029a1a6 Binary files /dev/null and b/data/fonts/Playfair_Display/PlayfairDisplay-Bold.ttf differ diff --git a/data/fonts/Playfair_Display/PlayfairDisplay-Italic.ttf b/data/fonts/Playfair_Display/PlayfairDisplay-Italic.ttf new file mode 100755 index 0000000..436dff0 Binary files /dev/null and b/data/fonts/Playfair_Display/PlayfairDisplay-Italic.ttf differ diff --git a/data/fonts/Playfair_Display/PlayfairDisplay-Regular.ttf b/data/fonts/Playfair_Display/PlayfairDisplay-Regular.ttf new file mode 100755 index 0000000..503b7c4 Binary files /dev/null and b/data/fonts/Playfair_Display/PlayfairDisplay-Regular.ttf differ diff --git a/data/fonts/Roboto/Roboto-Bold.ttf b/data/fonts/Roboto/Roboto-Bold.ttf new file mode 100755 index 0000000..43da14d Binary files /dev/null and b/data/fonts/Roboto/Roboto-Bold.ttf differ diff --git a/data/fonts/Roboto/Roboto-Italic.ttf b/data/fonts/Roboto/Roboto-Italic.ttf new file mode 100755 index 0000000..1b5eaa3 Binary files /dev/null and b/data/fonts/Roboto/Roboto-Italic.ttf differ diff --git a/data/fonts/Roboto/Roboto-Regular.ttf b/data/fonts/Roboto/Roboto-Regular.ttf new file mode 100755 index 0000000..ddf4bfa Binary files /dev/null and b/data/fonts/Roboto/Roboto-Regular.ttf differ diff --git a/data/fonts/Source_Sans_3/SourceSans3-Bold.ttf b/data/fonts/Source_Sans_3/SourceSans3-Bold.ttf new file mode 100755 index 0000000..969d7d4 Binary files /dev/null and b/data/fonts/Source_Sans_3/SourceSans3-Bold.ttf differ diff --git a/data/fonts/Source_Sans_3/SourceSans3-Italic.ttf b/data/fonts/Source_Sans_3/SourceSans3-Italic.ttf new file mode 100755 index 0000000..5eb2375 Binary files /dev/null and b/data/fonts/Source_Sans_3/SourceSans3-Italic.ttf differ diff --git a/data/fonts/Source_Sans_3/SourceSans3-Regular.ttf b/data/fonts/Source_Sans_3/SourceSans3-Regular.ttf new file mode 100755 index 0000000..c906bda Binary files /dev/null and b/data/fonts/Source_Sans_3/SourceSans3-Regular.ttf differ diff --git a/data/fonts/fonts.css b/data/fonts/fonts.css new file mode 100755 index 0000000..5ec0661 --- /dev/null +++ b/data/fonts/fonts.css @@ -0,0 +1,153 @@ +/*Начало шрифты*/ +@font-face { + font-family: 'Lora'; + src: url('Lora/Lora-Regular.ttf') format('truetype'); + font-weight: 400; + font-style: normal; +} +@font-face { + font-family: 'Lora'; + src: url('Lora/Lora-Bold.ttf') format('truetype'); + font-weight: 700; + font-style: normal; +} +@font-face { + font-family: 'Lora'; + src: url('Lora/Lora-Italic.ttf') format('truetype'); + font-weight: 400; + font-style: italic; +} + +@font-face { + font-family: 'Merriweather'; + src: url('Merriweather/Merriweather-Regular.ttf') format('truetype'); + font-weight: 400; + font-style: normal; +} +@font-face { + font-family: 'Merriweather'; + src: url('Merriweather/Merriweather-Bold.ttf') format('truetype'); + font-weight: 700; + font-style: normal; +} +@font-face { + font-family: 'Merriweather'; + src: url('Merriweather/Merriweather-Italic.ttf') format('truetype'); + font-weight: 400; + font-style: italic; +} + +@font-face { + font-family: 'Montserrat'; + src: url('Montserrat/Montserrat-Regular.ttf') format('truetype'); + font-weight: 400; + font-style: normal; +} +@font-face { + font-family: 'Montserrat'; + src: url('Montserrat/Montserrat-Bold.ttf') format('truetype'); + font-weight: 700; + font-style: normal; +} +@font-face { + font-family: 'Montserrat'; + src: url('Montserrat/Montserrat-Italic.ttf') format('truetype'); + font-weight: 400; + font-style: italic; +} + +@font-face { + font-family: 'OpenSans'; + src: url('OpenSans/OpenSans-Regular.ttf') format('truetype'); + font-weight: 400; + font-style: normal; +} +@font-face { + font-family: 'OpenSans'; + src: url('OpenSans/OpenSans-Bold.ttf') format('truetype'); + font-weight: 700; + font-style: normal; +} +@font-face { + font-family: 'OpenSans'; + src: url('OpenSans/OpenSans-Italic.ttf') format('truetype'); + font-weight: 400; + font-style: italic; +} + +@font-face { + font-family: 'Playfair_Display'; + src: url('Playfair_Display/PlayfairDisplay-Regular.ttf') format('truetype'); + font-weight: 400; + font-style: normal; +} +@font-face { + font-family: 'Playfair_Display'; + src: url('Playfair_Display/PlayfairDisplay-Bold.ttf') format('truetype'); + font-weight: 700; + font-style: normal; +} +@font-face { + font-family: 'Playfair_Display'; + src: url('Playfair_Display/PlayfairDisplay-Italic.ttf') format('truetype'); + font-weight: 400; + font-style: italic; +} + +@font-face { + font-family: 'PT_Serif'; + src: url('PT_Serif/PTSerif-Regular.ttf') format('truetype'); + font-weight: 400; + font-style: normal; +} +@font-face { + font-family: 'PT_Serif'; + src: url('PT_Serif/PTSerif-Bold.ttf') format('truetype'); + font-weight: 700; + font-style: normal; +} +@font-face { + font-family: 'PT_Serif'; + src: url('PT_Serif/PTSerif-Italic.ttf') format('truetype'); + font-weight: 400; + font-style: italic; +} + +@font-face { + font-family: 'Roboto'; + src: url('Roboto/Roboto-Regular.ttf') format('truetype'); + font-weight: 400; + font-style: normal; +} +@font-face { + font-family: 'Roboto'; + src: url('Roboto/Roboto-Bold.ttf') format('truetype'); + font-weight: 700; + font-style: normal; +} +@font-face { + font-family: 'Roboto'; + src: url('Roboto/Roboto-Italic.ttf') format('truetype'); + font-weight: 400; + font-style: italic; +} + +@font-face { + font-family: 'Source_Sans_3'; + src: url('Source_Sans_3/SourceSans3-Regular.ttf') format('truetype'); + font-weight: 400; + font-style: normal; +} +@font-face { + font-family: 'Source_Sans_3'; + src: url('Source_Sans_3/SourceSans3-Bold.ttf') format('truetype'); + font-weight: 700; + font-style: normal; +} +@font-face { + font-family: 'Source_Sans_3'; + src: url('Source_Sans_3/SourceSans3-Italic.ttf') format('truetype'); + font-weight: 400; + font-style: italic; +} +/*Конец шрифты*/ \ No newline at end of file diff --git a/data/foot.php b/data/foot.php new file mode 100755 index 0000000..5d6ca72 --- /dev/null +++ b/data/foot.php @@ -0,0 +1,8 @@ +
+
+ + + diff --git a/data/footer.css.php b/data/footer.css.php new file mode 100755 index 0000000..c131948 --- /dev/null +++ b/data/footer.css.php @@ -0,0 +1,43 @@ +#fclear{ + clear :both; +} + +#footer { + text-align :center; + position :relative; + width :100%; + margin :0px auto; +/* + background :#ffffff; + border :1px solid #0ffff0; + height :20px; +*/ + } + +.left-footer, +.right-footer, +.center-footer { + position :relative; + padding :0px; +/* + border :1px solid #0ffff0; +*/ + } + +.left-footer { + float :left; + width :200px; + } +.right-footer { + float :right; + width :200px; + } + +.center-footer { + float :none; + width :auto; + overflow :hidden; +/* + text-align :left; +*/ + } diff --git a/data/func.php b/data/func.php new file mode 100755 index 0000000..33d8a6b --- /dev/null +++ b/data/func.php @@ -0,0 +1,790 @@ + 'Неизвестное действие', + 'action' => $handleRequestAction, + 'post_data' => $_POST, + 'get_data' => $_GET, + 'server' => $_SERVER['REQUEST_URI'] + ]); + } +} + +/** + * @brief Обрабатывает входящий JSON-RPC запрос + * @return string JSON-ответ с результатом выполнения метода или ошибкой +*/ +function jsonrpcRequest() { + $raw = file_get_contents("php://input"); + $data = json_decode($raw, true); + $id = $data["id"] ?? null; + + try { + if (json_last_error() !== JSON_ERROR_NONE) { + throw new Exception("Parse error", -32700); + } + $method = $data["method"] ?? ""; + $params = $data["params"] ?? []; + if (!function_exists($method)) { + throw new Exception("Method not found", -32601); + } + $result = $method($params); + header("Content-Type: application/json"); + echo json_encode(["jsonrpc" => "2.0", "id" => $id, "result" => $result]); + } + catch (Exception $e) { + header("Content-Type: application/json"); + echo json_encode(["jsonrpc" => "2.0", "id" => $id, "error" => ["code" => $e->getCode(), "message" => $e->getMessage()]]); + } +} + +/** + * @brief Подключает плагин или плагины из директории main_plugin + * @param array $params Параметры подключения, ключ 'plugin' содержит имя плагина + * @return string HTML-код подключённых плагинов +*/ +function includePlugin($params) { + global $path, $config; + $html = ''; + $pluginDir = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'main_plugin' . DIRECTORY_SEPARATOR; + + $requested = isset($params['plugin']) ? trim($params['plugin']) : null; + if ($requested !== null && ($requested === '' || strpos($requested, '..') !== false)) { + throw new Exception("Invalid plugin name", -32602); + } + if (!is_dir($pluginDir)) return $html; + + $dirs = $requested ? [$requested] : array_diff(scandir($pluginDir), ['.', '..']); + + foreach ($dirs as $dir) { + $dirPath = $pluginDir . $dir; + if (!is_dir($dirPath)) continue; + + $file = $dirPath . '/plug.php'; + if (is_file($file)) { + ob_start(); + include $file; + $html .= ob_get_clean(); + } + } + return $html; +} + +/** + * @brief Получает список файлов и DOM-элементов плагина + * @param array $params Параметры, ключ 'plugin' содержит имя плагина + * @return array Массив ссылок на CSS, JS файлы и id элементов плагина +*/ +function removePluginDom($params) { + global $path; + $plugin = isset($params['plugin']) ? trim($params['plugin']) : null; + + if (!$plugin || strpos($plugin, '..') !== false || !preg_match('/^[A-Za-z0-9_\-]+$/', $plugin) || !is_dir($path . 'main_plugin/' . $plugin)) { + throw new Exception("Invalid plugin name"); + } + + $pluginDir = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'main_plugin' . DIRECTORY_SEPARATOR . $plugin; + $plugFile = $pluginDir . '/plug.php'; + if (!is_file($plugFile)) throw new Exception("plug.php not found"); + + ob_start(); + include $plugFile; + $html = ob_get_clean(); + + $files = []; + if (preg_match_all('/]+href=["\']([^"\']+)["\']/i', $html, $m)) $files = array_merge($files, $m[1]); + if (preg_match_all('/]+src=["\']([^"\']+)["\']/i', $html, $m)) $files = array_merge($files, $m[1]); + + $doc = new DOMDocument(); + libxml_use_internal_errors(true); + $doc->loadHTML('
' . $html . '
', LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); + libxml_clear_errors(); + + $wrapper = $doc->getElementById('wrapper'); + foreach ($wrapper->childNodes as $child) { + if ($child instanceof DOMElement && $child->hasAttribute('id')) { + $files[] = '#' . $child->getAttribute('id'); + } + } + + return array_values($files); +} + +/** + * @brief Подключает все PHP-файлы функций из папки main_plugin + * @return int Количество подключённых файлов +*/ +function includePluginsPhp() { + global $path; + $count = 0; + $pluginDir = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'main_plugin' . DIRECTORY_SEPARATOR; + if (!is_dir($pluginDir)) return $count; + $dirs = array_diff(scandir($pluginDir), ['.', '..']); + foreach ($dirs as $dir) { + $fullDir = $pluginDir . $dir . DIRECTORY_SEPARATOR; + if (!is_dir($fullDir)) continue; + foreach (glob($fullDir . 'func.*.php') as $file) { + if (is_file($file)) { + include_once $file; + $count++; + } + } + } + return $count; +} + +/** + * @brief Устанавливает язык пользователя в сессии + * @param array $params Параметры, ключ 'lng' содержит код языка + * @return string Строка "true" при успешной установке +*/ +function setLng($params) { + global $_SESSION; + if (!isset($params['lng'])) { + throw new Exception("Missing parameter: lng", -32602); + } + $_SESSION['lng'] = $params['lng']; + return "true"; +} + +/** + * @brief Завершает сессию пользователя + * @param array $params Параметры, ключ 'logoff' инициирует выход + * @return string Строка "true" при успешной разлогине +*/ +function logoutUser($params) { + if (!isset($params['logoff'])) { + throw new Exception("Missing parameter: logoff", -32602); + } + session_destroy(); + return "true"; +} + +/** + * @brief Выполняет вход пользователя с проверкой логина и пароля + * @param array $params Параметры, ключи 'log', 'login' и 'pass' для авторизации + * @return string "true" если вход успешен, "false" если нет +*/ +function loginUser($params) { + global $_SESSION; + if (!isset($params['log']) || $params['log'] !== "Войти" || !isset($params['login']) || !isset($params['pass'])) { + throw new Exception("Missing login action or credentials", -32602); + } + if (check($params['login'], md5($params['pass']))) { + $_SESSION['username'] = $params['login']; + $_SESSION['pass'] = $params['pass']; + $_SESSION['Login'] = 'true'; + setcookie('Login', 'true', time() + 2419200, "/"); + $_SESSION['log_in'] = false; + return "true"; + } else { + $_SESSION['Login'] = 'false'; + setcookie('Login', 'false', time() + 2419200, "/"); + return "false"; + } +} + +/** + * @brief Проверяет соответствие логина и пароля с данными пользователей + * @param string $login Имя пользователя + * @param string $pass Хеш пароля пользователя + * @return bool true если пользователь найден и пароль совпадает, false иначе +*/ +function check($login, $pass) { + global $config, $uxml, $path; + $xmlstr = simplexml_load_file($path . $config['users']); + $result = false; + foreach ($xmlstr->users->user as $user) { + if ((string)$user['name'] === $login && (string)$user['pass'] === $pass) { + $result = true; + } + } + return $result; +} + +/** + * @brief Загружает конфигурацию сайта из XML и пользователей + * @return void Возвращает значения в глобальный массив $config +*/ +function SetConfig() +{ +global $config, $path; +$xmlstr = simplexml_load_file($path . 'config/config_site.php'); +$config['icon'] = $xmlstr->general->icon; +$config['encoding'] = $xmlstr->general->encoding; +$config['users'] = $xmlstr->general->users; +$config['usersRequest'] = $xmlstr->general->usersrequest; + +$xmlstr = simplexml_load_file($path . 'data/users.php'); +$config['emailAdmin'] = ''; +foreach ($xmlstr->users->user as $user) { + $access = explode(',', (string)$user['access']); + $access = array_map('trim', $access); + if (in_array('creatingAccounts', $access)) { + $config['emailAdmin'] = (string)$user['email']; + break; + } +} +} + +/** + * @brief Получает список пользователей с правами администратора + * @return array Массив имён пользователей с правами Admin +*/ +function adminsConfig() { + global $path; + $xml = simplexml_load_file($path . 'data/users.php'); + + $admins = []; + foreach ($xml->users->user as $user) { + $accessList = array_map('trim', explode(', ', (string)$user['access'])); + + if (in_array('Admin', $accessList, true)) { + $admins[] = (string)$user['name']; + } + } + + return $admins; +} + +/** + * @brief Генерирует HTML-ссылки для меню + * @param array $menuVar Массив пунктов меню с ключами 'url', 'title', 'name' + * @return string Сформированные HTML-ссылки для меню +*/ +function GetMenuItems($menuVar){ + global $config; + $menu = ''; + for ($i = 0; $i <= count($menuVar)-1; $i+=1) + { + $menu.= ''.$menuVar[$i]['name'] . ' '; + if ($i <= count($menuVar)-2) + { + $menu.= ':: '; + } + } + return $menu; +} + +/** + * @brief Формирует HTML-блоки для отображения на странице + * @param array $BlockVar Массив блоков с ключами 'url', 'title', 'tclass', 'bclass' + * @param string $side Сторона или тип блока + * @return string Сформированные HTML-блоки +*/ +function GetBlock ($BlockVar, $side) { + global $path, $ansv, $REQUEST_URI,$menu, $config, $EditPage; + $Block = ''; + if (is_countable($BlockVar) && count($BlockVar) > 0){ + for ($i = 0; $i <= count($BlockVar)-1; $i+=1){ + ob_start(); + include $path . $BlockVar[$i]['url'].'plug.php'; + $Xblock = ob_get_contents(); + ob_end_clean(); + + $Block.='
'; + if ($BlockVar[$i]['title']!=''){ + $Block.='
'.$BlockVar[$i]['title'].'
'; + } + $Block.='
'.$Xblock.'
'; + $Block.= '
'; + $Block.='
'; + + } + } + return $Block; + + // $Block.='
ku ku
'; + /*is_countable($$BlockVar) && count($BlockVar) + $Block = ""; + if (is_countable($$BlockVar) && count($BlockVar) > 0){ + $Block = "true"; + } + else{ + $Block = "false"; + } + $Block = count($BlockVar);*/ +} + + +/** + * @brief Обрабатывает ошибку 404 и выводит страницу ошибки + * @param bool $pageout Если true, выводит содержимое файла 404.shtml + * @param string $encoding Кодировка страницы + * @return void Завершает выполнение скрипта +*/ +function error404($pageout = false, $encoding = 'utf-8') +{ + header('Cache-Control: no-cache, no-store'); + header('Content-Type: text/html; charset=' . $encoding); + header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found'); + if ($pageout) + readfile('404.shtml'); + die; +} + +/** + * @brief Обрабатывает ошибку 405 и выводит страницу ошибки + * @param bool $pageout Если true, выводит содержимое файла 405.shtml + * @param string $encoding Кодировка страницы + * @return void Завершает выполнение скрипта +*/ +function error405($pageout = false, $encoding = 'utf-8') +{ + header('Cache-Control: no-cache, no-store'); + header('Content-Type: text/html; charset=' . $encoding); + header($_SERVER['SERVER_PROTOCOL'] . ' 405 Not Found'); + if ($pageout) + readfile('405.shtml'); + die; +} + +# Функция HTTP авторизации. Логин и пароль задаются в файле users.xml +# Форма авторизации +/* function Log_Form($Vector,$act) { + if ($Vector=='h') $sep = ' '; + else $sep = '
'; + $string = '
'; + $string .= ''; + switch ($act){ + case 'log_on':{ + $string .= ''; + $string .= $sep; + $string .= ''; + $string .= $sep; + $string .= ''; + $string .= $sep; + $string .= ''; + $string .= $sep; + $string .= ' +
'; + break; + } + case 'log_off':{ + $string .= '
+
'; + break; + } + case 'log_err':{ + $string .= ''; + $string .= $sep; + $string .= '
+
'; + break; + } + } + $string .= ''; + $_SESSION['Login'] =''; + + return $string; +} */ + +/** + * @brief Генерирует HTML-меню для выбора языка с кнопками для каждого доступного языка + * @return string Сформированный HTML-код меню выбора языка с встроенным скриптом для отправки запроса +*/ +function LngMenu() { + $s = '
  • ' . $_SESSION['lng'] . '
      '; + + if ($_SESSION['lng'] != 'lv') { + $s .= '
      '; + } + if ($_SESSION['lng'] != 'en') { + $s .= '
      '; + } + if ($_SESSION['lng'] != 'ru') { + $s .= '
      '; + } + + $s .= '
'; + + $s .= ' + +'; + + return $s; +} + +/** + * @brief Определяет текущий язык пользователя и сохраняет его в сессии + * @return string Текущий язык (например, 'en', 'ru', 'lv') +*/ +function SetLanguage(){ + global $_SESSION, $path; + if (isset($_POST['lng']) && $_POST['lng'] != '') + $_SESSION['lng'] = $_POST['lng']; + if (empty($_SESSION['lng'])){ + $s = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']); + $a = explode('-', $s[0]); + $_SESSION['lng'] = $a[0]; + } + return $_SESSION['lng']; +} + +/** + * @brief Разбирает URL запроса и определяет действие и путь к странице + * @param string $URL URL запроса + * @return array Массив с ключами 'act' и 'str', где 'act' — действие, 'str' — путь к странице +*/ +function GetRequestURL($URL){ +$c=explode('.',$URL); +if ($c[1]=='html'&&count($c)!=1){ + $mURL['act'] ='view'; + $mURL['str'] = explode('/',$c[0]); + $mURL['str'][0]="index"; + if ($mURL['str'][1]=='index'){ + $mURL['str'][1]=''; + } + if ($mURL['str'][count($mURL['str'])-1]==''){ + array_pop($mURL['str']); + } + } +else{ + if ($c[1]=='xml'&&count($c)!=1){ + $mURL['act'] ='edit'; + $mURL['str'] = explode('/',$c[0]); + $mURL['str'][0]="index"; + } + else{ + $mURL['str']='error'; + } + } +return $mURL; +} + +/** + * @brief Получает новости из XML-файла и формирует HTML-блоки для отображения + * @param array $BlockVar Массив блоков с настройками отображения + * @param string $side Сторона страницы, для которой формируются новости + * @return string Сформированные HTML-блоки с новостями +*/ +function getNews($BlockVar, $side) { + global $path, $_SESSION; + + $lng = $_SESSION['lng'] ?? 'en'; + $file = $path . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'filepath.' . $lng . '.php'; + $content = @file_get_contents($file); + if (!$content) $content = ''; + $content = preg_replace('/^\s*<\?php.*?\?>\s*/s', '', $content); + $xml = @simplexml_load_string($content); + $rootReal = realpath(rtrim($path, DIRECTORY_SEPARATOR)); + $html = ''; + $tplClass = isset($BlockVar[0]['tclass']) ? $BlockVar[0]['tclass'] : 'btitle'; + $bclass = isset($BlockVar[0]['bclass']) ? $BlockVar[0]['bclass'] : 'bfloat'; + $now = new DateTime(); + + $walk = function($node) use (&$walk, &$html, $path, $side, $lng, $rootReal, $tplClass, $bclass, $now) { + $newsAttr = trim((string)$node['news']); + if ($newsAttr === '') { + foreach ($node->children() as $child) $walk($child); + return; + } + $parts = explode(',', $newsAttr); + if (count($parts) === 0) { + foreach ($node->children() as $child) $walk($child); + return; + } + $period = array_shift($parts); + $dates = explode('/', $period); + if (count($dates) !== 2) { + foreach ($node->children() as $child) $walk($child); + return; + } + $parseDate = function($str) { + $parts = explode('.', $str); + if (count($parts) < 5) return false; + list($Y, $m, $d, $H, $i) = $parts; + $dateStr = sprintf('%04d-%02d-%02d %02d:%02d:00', $Y, $m, $d, $H, $i); + return DateTime::createFromFormat('Y-m-d H:i:s', $dateStr); + }; + $start = $parseDate($dates[0]); + $end = $parseDate($dates[1]); + if (!$start || !$end || $now < $start || $now > $end) { + foreach ($node->children() as $child) $walk($child); + return; + } + $blocks = array_map('trim', $parts); + if (!empty($blocks) && !in_array($side, $blocks)) { + foreach ($node->children() as $child) $walk($child); + return; + } + + $urlAttrRaw = trim((string)$node['url']); + $titleRaw = (string)$node['title']; + $urlPart = trim($urlAttrRaw, "/\\"); + $pageFile = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $urlPart . '.page.php'; + $pageFileReal = realpath($pageFile); + $pageContent = ''; + if ($pageFileReal && strpos($pageFileReal, $rootReal) === 0 && is_file($pageFileReal) && is_readable($pageFileReal)) { + $pageXml = @simplexml_load_file($pageFileReal); + if ($pageXml && isset($pageXml->content->{$lng})) { + $pageContent = strip_tags((string)$pageXml->content->{$lng}); + $maxLength = ($side === 'center') ? 300 : 100; + $pageContent = mb_substr($pageContent, 0, $maxLength) . (mb_strlen($pageContent) > $maxLength ? '...' : ''); + } + } + $nameRaw = trim((string)$node['name']); + $tagPath = []; + $n = $node; + while ($n) { + $tag = $n->getName(); + if ($tag !== 'site' && $tag !== 'index') { + $tagPath[] = $tag; + } + $n = $n->xpath('..') ? $n->xpath('..')[0] : null; + } + $tagPath = array_reverse($tagPath); + if (empty($tagPath)) { + $link = '/'; + } else { + $link = implode('/', $tagPath) . '.html'; + } + $link = htmlspecialchars($link); + $readMore = 'читать дальше'; + $title = $titleRaw !== '' ? htmlspecialchars($titleRaw) : ''; + + $html .= '
'; + if ($side === "center") $html .= '
'; + if ($title !== '') $html .= '
' . $title . '
'; + $html .= '
' . $pageContent . ' ' . $readMore . '
'; + if ($side !== 'center') $html .= '
'; + $html .= '
'; + foreach ($node->children() as $child) $walk($child); + }; + if ($xml && isset($xml->index)) $walk($xml->index); + return $html; +} + +/** + * @brief Генерирует HTML-строку горизонтального меню из XML-структуры + * @param object $menuVar XML-объект меню + * @param array $RURLstr Массив сегментов URL для определения вложенности + * @param int $ItemNo Индекс текущего элемента в URL + * @param string $Vector Вертикальное ('v') или горизонтальное отображение + * @return string Сформированное HTML-меню +*/ +function GetXMLMenu($menuVar,$RURLstr,$ItemNo,$Vector){ + global $config, $path, $_SESSION; + + $child_menu = ""; + $topURL = ''; + + if ($ItemNo!=0) { + for ($i = 1; $i <= $ItemNo; $i+=1) { + $topURL .=$RURLstr[$i].'/'; + $menuVar =$menuVar->{$RURLstr[$i]}; + } + } + + $i = 0; + foreach ($menuVar->children() as $child_page) { + if (FindPageUser($child_page['users'],$_SESSION['username'])) { + if ($i!=0) { + if ($Vector!='v') { + $child_menu .=' :: '; + } else { + $child_menu .='
'; + } + } + $child_menu .= '' . $child_page['title'] . ''; + $i=$i+1; + } + } + + return $child_menu; +} + +/** + * @brief Генерирует HTML-блок бокового меню из XML-структуры + * @param object $menuVar XML-объект меню + * @param array $RURLstr Массив сегментов URL для определения вложенности + * @param int $ItemNo Индекс текущего элемента в URL + * @return string Сформированное HTML боковое меню +*/ +function GetSideXMLMenu($menuVar,$RURLstr,$ItemNo){ + global $config, $path, $_SESSION; + + $child_menu = ""; + $topURL = ''; + + if ($ItemNo!=0) { + for ($i = 1; $i <= $ItemNo; $i+=1) { + $topURL .=$RURLstr[$i].'/'; + $menuVar =$menuVar->{$RURLstr[$i]}; + } + } + + $child_menu.='
'; + $child_menu.=''; + $child_menu.='Home'; + $child_menu.='
'; + + foreach ($menuVar->children() as $child_page) { + if (FindPageUser($child_page['users'],$_SESSION['username'])) { + $child_menu.=''.$child_page['title'].''; + } + } + + return $child_menu; +} + +/** + * @brief Проверяет, имеет ли пользователь доступ к странице + * @param string $PageUser Список пользователей, имеющих доступ, через запятую + * @param string $user Имя пользователя + * @return bool true если доступ разрешён, false если нет +*/ +function FindPageUser($PageUser,$user){ +if ($PageUser==''){ + $test =true; + } +else{ + $test =false; + $PageUser =explode(',',$PageUser); + for ($i = 0; $i <= count($PageUser)-1; $i+=1){ + if ($PageUser[$i]==$user){ + $test =true; + } + } + } +return $test; +} + +/** + * @brief Разбирает файл XML страницы и возвращает информацию о запрошенном URL + * @param string $FPfile Путь к XML-файлу с описанием страниц + * @param mixed $RURLstr Массив сегментов URL или строка 'error' + * @return array Массив с информацией о странице, включая URL, шаблон, заголовок и плагины +*/ +function URLstr($FPfile,$RURLstr){ +global $path, $server, $config; +$xmlstr =simplexml_load_file($FPfile); +if (!isset($xmlstr->index)) { + $index = $xmlstr->addChild('index', "\n"); + $index->addAttribute('url', 'data/createSite'); + + $lang = isset($config['lng']) ? $config['lng'] : 'ru'; + $titles = [ 'ru' => 'Страница создание нового сайта', 'en' => 'New site creation page', 'lv' => 'Jaunas vietnes izveides lapa' ]; + $index->addAttribute('title', isset($titles[$lang]) ? $titles[$lang] : $titles['ru']); + + $index->addAttribute('name', 'index'); + $index->addAttribute('template', 'MedWait'); + $index->addAttribute('PageMenu', '0,1,2'); + $index->addAttribute('users', ''); + $index->addAttribute('group', ''); + $index->addAttribute('news', ''); + $index->addAttribute('plugins', ''); + $xmlstr->asXML($FPfile); +} +$ansv['sitename'] =$xmlstr->sitename; +$ansv['XML'] =$xmlstr; +$ansv['pageURL'] =$xmlstr->sitename; +$fileURL ='http://'.$_SERVER['HTTP_HOST']; +$ansv['URLLine'] =""; +if ($RURLstr!='error'){ + for ($i = 0; $i <= count($RURLstr)-1; $i+=1){ + if ($xmlstr->{$RURLstr[$i]}['name']!=''){ + if ($i!=count($RURLstr)-1) { + if ($i!=0){ + $fileURL .='/'.$xmlstr->{$RURLstr[$i]}->getName(); + $end ='.html'; + } + else{ + $end ='/index.html'; + } + $ansv['URLLine'] .= ''.$xmlstr->{$RURLstr[$i]}['name'].'>>'; + } + else{ + $ansv['URLLine'] .= $xmlstr->{$RURLstr[$i]}['name']; + $ansv['FileURL'] = $xmlstr->{$RURLstr[$i]}['url']; + $ansv['template'] = $xmlstr->{$RURLstr[$i]}['template']; + $ansv['title'] = $xmlstr->{$RURLstr[$i]}['title']; + $ansv['page'] = $xmlstr->{$RURLstr[$i]}; + $ansv['page_plugins'] = (string)($xmlstr->{$RURLstr[$i]}['plugins'] ?? ''); + } + $xmlstr = $xmlstr->{$RURLstr[$i]}; + } + else { + $ansv['URLLine'] = 'error'; + $ansv['FileURL'] = 'error'; + } + } + } + + return $ansv; +} + +/** + * @brief Разбирает файл XML страницы и возвращает информацию о запрошенном URL + * @param string $FPfile Путь к XML-файлу с описанием страниц + * @param mixed $RURLstr Массив сегментов URL или строка 'error' + * @return array Массив с информацией о странице, включая URL, шаблон, заголовок и плагины +*/ +function loadPluginsInCenterBlock() { + global $_SESSION, $path, $config; + if ($_SESSION['Login'] == 'true') { + $availablePlugins = ['dgrm', 'SvgEditorM']; + $pluginDir = $path . 'main_plugin/'; + if (is_dir($pluginDir)) { + $dirs = array_diff(scandir($pluginDir), ['.', '..']); + foreach ($dirs as $dir) { + if (is_dir($pluginDir . $dir)) { + if (!in_array($dir, $availablePlugins) || strpos($config['page_plugins'] ?? '', $dir) !== false) { + if ($dir === 'SvgEditorM' || $dir === 'dgrm') { + $html .= includePlugin(['plugin' => $dir]); + } + } + } + } + } + } + $html .= includePlugin(['plugin' => 'form_editor']); + return $html; +} +?> \ No newline at end of file diff --git a/data/lang.php b/data/lang.php new file mode 100755 index 0000000..f4a2754 --- /dev/null +++ b/data/lang.php @@ -0,0 +1,113 @@ + [ + 'error' => 'Ошибка', + 'message' => 'Сообщение:', + 'ok' => 'ОК', + 'cancel' => 'Отмена', + 'yes' => 'Да', + 'no' => 'Нет', + 'main_block_saved' => 'Изменения главного блока сохранились!', + 'main_block_not_saved' => 'Изменения главного блока не сохранились!', + 'plugins_not_saved' => 'Плагины не сохранились!', + 'page_must_end_with_page_php' => 'Страница должна заканчиваться на ".page.php"!', + 'save_file_as' => 'Сохранить файл как:', + 'file' => 'Файл', + 'exists_overwrite_prompt' => 'уже существует. Перезаписать?', + 'new_file' => 'Новый файл!', + 'file_save_failed' => 'Не удалось сохранить файл!', + 'changes_saved_successfully' => 'Изменения успешно сохранены!', + 'data_save_error' => 'Ошибка сохранения данных!', + 'created_successfully' => 'успешно создан!', + 'file_creation_error' => 'Ошибка при создании файла', + 'folder' => 'Папка', + 'select_file' => 'Выберите файл', + 'file_manager_title' => 'Файловый менеджер', + 'name' => 'Имя', + 'save' => 'Сохранить', + 'open' => 'Открыть', + 'choose' => 'Выбрать', + 'column_size_bytes' => 'Размер (байт)', + 'column_creation_date' => 'Дата создания', + + 'plugin_title_empty_error' => 'Заголовок пустой!', + 'open_page' => 'Откройте страницу на сайте, а не через менеджер, чтобы сохранить заголовки!', + 'enter_new_title' => 'Введите новый заголовок:', + 'title_saved' => 'Заголовок сохранён!', + 'new_file' => 'Новый файл' + ], + 'en' => [ + 'error' => 'Error', + 'message' => 'Message:', + 'ok' => 'OK', + 'cancel' => 'Cancel', + 'yes' => 'Yes', + 'no' => 'No', + 'main_block_saved' => 'Main block changes saved!', + 'main_block_not_saved' => 'Main block changes not saved!', + 'plugins_not_saved' => 'Plugins not saved!', + 'page_must_end_with_page_php' => 'Page must end with ".page.php"!', + 'save_file_as' => 'Save file as:', + 'file' => 'File', + 'exists_overwrite_prompt' => 'already exists. Overwrite?', + 'new_file' => 'New file!', + 'file_save_failed' => 'Failed to save file!', + 'changes_saved_successfully' => 'Changes saved successfully!', + 'data_save_error' => 'Data save error!', + 'created_successfully' => 'created successfully!', + 'file_creation_error' => 'Error creating file', + 'folder' => 'Folder', + 'select_file' => 'Select file', + 'file_manager_title' => 'File Manager', + 'name' => 'Name', + 'save' => 'Save', + 'open' => 'Open', + 'choose' => 'Choose', + 'column_size_bytes' => 'Size (bytes)', + 'column_creation_date' => 'Creation Date', + + 'plugin_title_empty_error' => 'Title is empty!', + 'open_page' => 'Open the page on the website, not through the manager, to save the headings!', + 'enter_new_title' => 'Enter a new title:', + 'title_saved' => 'Title saved!', + 'new_file' => 'Jauns fails' + ], + 'lv' => [ + 'error' => 'Kļūda', + 'message' => 'Ziņojums:', + 'ok' => 'Ok', + 'cancel' => 'Atcelt', + 'yes' => 'Jā', + 'no' => 'Nē', + 'main_block_saved' => 'Galvenā bloka izmaiņas saglabātas!', + 'main_block_not_saved' => 'Galvenā bloka izmaiņas nesaglabājās!', + 'plugins_not_saved' => 'Spraudņi nav saglabāti!', + 'page_must_end_with_page_php' => 'Lapa jābeidz ar ".page.php"!', + 'save_file_as' => 'Saglabāt kā failu:', + 'file' => 'Fails', + 'exists_overwrite_prompt' => 'jau pastāv. Pārrakstīt?', + 'new_file' => 'Jauns fails!', + 'file_save_failed' => 'Neizdevās saglabāt failu!', + 'changes_saved_successfully' => 'Izmaiņas veiksmīgi saglabātas!', + 'data_save_error' => 'Datu saglabāšanas kļūda!', + 'created_successfully' => 'veiksmīgi izveidots!', + 'file_creation_error' => 'Kļūda, izveidojot failu', + 'folder' => 'Mape', + 'select_file' => 'Izvēlieties failu', + 'file_manager_title' => 'Failu pārvaldnieks', + 'name' => 'Nosaukums', + 'save' => 'Saglabāt', + 'open' => 'Atvērt', + 'choose' => 'Izvēlēties', + 'column_size_bytes' => 'Izmērs (baiti)', + 'column_creation_date' => 'Izveides datums', + + 'plugin_title_empty_error' => 'Virsraksts ir tukšs!', + 'open_page' => 'Atveriet lapu vietnē, nevis caur pārvaldnieku, lai saglabātu virsrakstus!', + 'enter_new_title' => 'Ievadiet jauno virsrakstu:', + 'title_saved' => 'Virsraksts saglabāts!', + 'new_file' => 'Jauns fails' + ], +]; + +return $lang_Basic_functions; diff --git a/data/request_on_users.php b/data/request_on_users.php new file mode 100755 index 0000000..15c2696 --- /dev/null +++ b/data/request_on_users.php @@ -0,0 +1,7 @@ + + + + + + + diff --git a/data/template.page.php b/data/template.page.php new file mode 100755 index 0000000..896ac75 --- /dev/null +++ b/data/template.page.php @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/top.css.php b/data/top.css.php new file mode 100755 index 0000000..abca7ad --- /dev/null +++ b/data/top.css.php @@ -0,0 +1,196 @@ +#hbody { + text-align :center; + position :fixed; + width :-webkit-fill-available; + height :1.2em; + padding: 2px 25px; + background :rgb(237,232,237); + background-image :linear-gradient(bottom, rgb(194,194,194) 15%, rgb(237,232,237) 57%); + background-image :-o-linear-gradient(bottom, rgb(194,194,194) 15%, rgb(237,232,237) 57%); + background-image :-moz-linear-gradient(bottom, rgb(194,194,194) 15%, rgb(237,232,237) 57%); + background-image :-webkit-linear-gradient(bottom, rgb(194,194,194) 15%, rgb(237,232,237) 57%); + background-image :-ms-linear-gradient(bottom, rgb(194,194,194) 15%, rgb(237,232,237) 57%); + background-image :-webkit-gradient(linear, left bottom, left top, color-stop(0.15, rgb(194,194,194)), color-stop(0.57, rgb(237,232,237))); + color :#666; + text-shadow :1px 1px 3px #666, -1px -1px 3px #FFF, 1px 1px #666, -1px -1px #FFF; +/* + font-family :Arial, Tahoma, Verdana, sans-serif; +*/ + font-size :1.3em; + top :0px; + z-index :1000; + white-space: nowrap; + } + +.side-link{ + white-space: normal; + overflow-wrap: break-word; + word-break: break-word; + padding: 10px 20px 10px 20px; +} +.side-menu-header{ + padding: 30px 20px 20px 20px; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.15, rgb(233 233 233)), color-stop(0.57, rgb(194 194 194))); +} +/*- меню страниц */ +.menu-btn { + cursor: pointer; + position: relative; + float: right; + margin-left: 9px; +} +.side-menu { + position: fixed; + top: 0; + right: -100%; + width: 70%; + max-width: 13em; + height: 100%; + box-sizing: border-box; + transition: left 0.3s ease; + display: flex; + flex-direction: column; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.15, rgb(194, 194, 194)), color-stop(0.57, rgb(237, 232, 237))); + z-index: 1006; +} +.menu-toggle { + font-size: 2em; + margin: -3px 0px 0px 0px; +} +.menu-toggle:checked ~ .side-menu { + right: 0; +} +#overlay { + position: fixed; + top: 0; left: 0; right: 0; bottom: 0; + background: rgba(0, 0, 0, 0.2); + pointer-events: none; + opacity: 0; + transition: opacity 0.3s ease; + z-index: 1005; +} +#overlay.active { + pointer-events: auto; + opacity: 1; +} + +#shome{ + position :relative; + float :left; + } + + +#smenu{ + position: relative; + margin: 0px auto; + overflow: hidden; + display: inline-block; + margin: 0px 10px; + padding: 0px 3px; + } + +#slng{ + text-transform :uppercase; + position :relative; + float :right; + } + +#slng ul li a, +#slng ul li a:visited { + display :block; + text-decoration :none; + text-align :center; + line-height :20px; + overflow :hidden; + } + +#slng ul { + padding :0; + margin :0; + list-style :none; + } + +#slng ul li { + float :left; + position :relative; + } + +#slng ul li ul { + display :none; + background :rgb(237,232,237); + position: absolute; + right: 4px; +} + +/* specific to non IE browsers */ +#slng ul li:hover a { } + +#slng ul li:hover ul { + display :block; + } + +#slng ul li:hover ul li a.hide { } + +#slng ul li:hover ul li:hover a.hide { } + +#slng ul li:hover ul li ul { + display :none; + } + +#slng ul li:hover ul li a { + display :block; + } + +#slng ul li:hover ul li a:hover { } + +#slng ul li:hover ul li:hover ul { + display :block; + position :absolute; + left :50px; + top :0; + } + +#slng ul li:hover ul li:hover ul.left { + left :-105px; + } + +#f button{ + color :#666; + background :none; + cursor :pointer; + border :0; + text-shadow :1px 1px 3px #666, + -1px -1px 3px #FFF, + 1px 1px #666, + -1px -1px #FFF; + font-family :serif; + font-size :1em; + } + +#f, #f button{ + display :inline; + margin :1px; + padding :0; + } + +#f button:hover{ + color :rgb(153,153,153); + text-shadow :-1px -1px #666, + 1px 1px #FFF; + } + +#hbody a{ + color :#666; + text-shadow :1px 1px 3px #666, + -1px -1px 3px #FFF, + 1px 1px #666, + -1px -1px #FFF; + text-decoration :none; + } + +#hbody a:hover{ + color :rgb(153,153,153); + text-shadow :-1px -1px #666, + 1px 1px #FFF; + } + diff --git a/data/top.php b/data/top.php new file mode 100755 index 0000000..1aebbd0 --- /dev/null +++ b/data/top.php @@ -0,0 +1,31 @@ + + + + +%sitename% + + + + + + +
+
+ Home +
+
+ %TopMenu% +
+ + + + +
+
+ %LngMenu% +
+
+ + diff --git a/data/users.php b/data/users.php new file mode 100755 index 0000000..fa5dba5 --- /dev/null +++ b/data/users.php @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/error.txt b/error.txt new file mode 100755 index 0000000..e69de29 diff --git a/img/Raspberry_Pi_Logo.svg b/img/Raspberry_Pi_Logo.svg new file mode 100755 index 0000000..403edbc --- /dev/null +++ b/img/Raspberry_Pi_Logo.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/img/Thumbs.db b/img/Thumbs.db new file mode 100755 index 0000000..2820a1e Binary files /dev/null and b/img/Thumbs.db differ diff --git a/img/createSite/editor.png b/img/createSite/editor.png new file mode 100755 index 0000000..a746345 Binary files /dev/null and b/img/createSite/editor.png differ diff --git a/img/createSite/manager.png b/img/createSite/manager.png new file mode 100755 index 0000000..6929f58 Binary files /dev/null and b/img/createSite/manager.png differ diff --git a/img/createSite/settings.png b/img/createSite/settings.png new file mode 100755 index 0000000..0fe3110 Binary files /dev/null and b/img/createSite/settings.png differ diff --git a/img/createSite/siteTree.png b/img/createSite/siteTree.png new file mode 100755 index 0000000..1ef0da2 Binary files /dev/null and b/img/createSite/siteTree.png differ diff --git a/img/favicon.ico b/img/favicon.ico new file mode 100755 index 0000000..797b369 Binary files /dev/null and b/img/favicon.ico differ diff --git a/img/gor.jpg b/img/gor.jpg new file mode 100755 index 0000000..25882b7 Binary files /dev/null and b/img/gor.jpg differ diff --git a/img/hall.jpg b/img/hall.jpg new file mode 100755 index 0000000..7847f67 Binary files /dev/null and b/img/hall.jpg differ diff --git a/img/head.jpg b/img/head.jpg new file mode 100755 index 0000000..d27ac44 Binary files /dev/null and b/img/head.jpg differ diff --git a/img/img/backgr.jpg b/img/img/backgr.jpg new file mode 100755 index 0000000..ab34ea3 Binary files /dev/null and b/img/img/backgr.jpg differ diff --git a/img/img/close.png b/img/img/close.png new file mode 100755 index 0000000..64d4ac1 Binary files /dev/null and b/img/img/close.png differ diff --git a/img/img/net.jpg b/img/img/net.jpg new file mode 100755 index 0000000..fc7d809 Binary files /dev/null and b/img/img/net.jpg differ diff --git a/img/img/pla.jpg b/img/img/pla.jpg new file mode 100755 index 0000000..437e221 Binary files /dev/null and b/img/img/pla.jpg differ diff --git a/img/menu_1.jpg b/img/menu_1.jpg new file mode 100755 index 0000000..26d6040 Binary files /dev/null and b/img/menu_1.jpg differ diff --git a/img/menu_2.jpg b/img/menu_2.jpg new file mode 100755 index 0000000..6f32337 Binary files /dev/null and b/img/menu_2.jpg differ diff --git a/img/menu_3.jpg b/img/menu_3.jpg new file mode 100755 index 0000000..3bb2d1e Binary files /dev/null and b/img/menu_3.jpg differ diff --git a/img/menu_4.jpg b/img/menu_4.jpg new file mode 100755 index 0000000..77fd481 Binary files /dev/null and b/img/menu_4.jpg differ diff --git a/img/menu_5.jpg b/img/menu_5.jpg new file mode 100755 index 0000000..5029797 Binary files /dev/null and b/img/menu_5.jpg differ diff --git a/img/menu_6.jpg b/img/menu_6.jpg new file mode 100755 index 0000000..d4d8cd9 Binary files /dev/null and b/img/menu_6.jpg differ diff --git a/img/menu_7.jpg b/img/menu_7.jpg new file mode 100755 index 0000000..ab4bcea Binary files /dev/null and b/img/menu_7.jpg differ diff --git a/img/pict/b_iconslyb.svg b/img/pict/b_iconslyb.svg new file mode 100755 index 0000000..4549e2c --- /dev/null +++ b/img/pict/b_iconslyb.svg @@ -0,0 +1,12320 @@ + + + +FiBUSAZZA0990123abc123XZ Z</>TXT1TTT diff --git a/img/pict/g_iconslyb.svg b/img/pict/g_iconslyb.svg new file mode 100755 index 0000000..1f97c0d --- /dev/null +++ b/img/pict/g_iconslyb.svg @@ -0,0 +1,12326 @@ + + + +FiBUSAZZA0990123123XZ Z</>TXT1TTTabc diff --git a/img/pict/mc_iconslyb.svg b/img/pict/mc_iconslyb.svg new file mode 100755 index 0000000..ba891f2 --- /dev/null +++ b/img/pict/mc_iconslyb.svg @@ -0,0 +1,12103 @@ + + + +FiBUSAZZA0990123123XZ Z</>TXT1TTT diff --git a/img/pict/w_iconslyb.svg b/img/pict/w_iconslyb.svg new file mode 100755 index 0000000..70c0b24 --- /dev/null +++ b/img/pict/w_iconslyb.svg @@ -0,0 +1,12031 @@ + + + +FiBUSAZZA0990123123XZ Z</>TXT1T diff --git a/img/rpi.gif b/img/rpi.gif new file mode 100755 index 0000000..f2225f3 Binary files /dev/null and b/img/rpi.gif differ diff --git a/img/rpi.ico b/img/rpi.ico new file mode 100755 index 0000000..8f8ce5c Binary files /dev/null and b/img/rpi.ico differ diff --git a/img/rpi.png b/img/rpi.png new file mode 100755 index 0000000..2386d7a Binary files /dev/null and b/img/rpi.png differ diff --git a/img/rpi.svg b/img/rpi.svg new file mode 100755 index 0000000..b572cb5 --- /dev/null +++ b/img/rpi.svg @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/rpi1.jpg b/img/rpi1.jpg new file mode 100755 index 0000000..6c66c2e Binary files /dev/null and b/img/rpi1.jpg differ diff --git a/img/rpi2.jpg b/img/rpi2.jpg new file mode 100755 index 0000000..d8afaad Binary files /dev/null and b/img/rpi2.jpg differ diff --git a/img/rpi3.jpg b/img/rpi3.jpg new file mode 100755 index 0000000..fee9ea9 Binary files /dev/null and b/img/rpi3.jpg differ diff --git a/img/rpi_2.svg b/img/rpi_2.svg new file mode 100755 index 0000000..afe88c4 --- /dev/null +++ b/img/rpi_2.svg @@ -0,0 +1,213 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/rpi_label.png b/img/rpi_label.png new file mode 100755 index 0000000..92d1500 Binary files /dev/null and b/img/rpi_label.png differ diff --git a/img/rpi_logo.jpg b/img/rpi_logo.jpg new file mode 100755 index 0000000..166a06d Binary files /dev/null and b/img/rpi_logo.jpg differ diff --git a/img/test.jpg b/img/test.jpg new file mode 100755 index 0000000..86fa9f1 Binary files /dev/null and b/img/test.jpg differ diff --git a/img/users_img/Admin/WhatsApp Image 2024-02-20 at 20.26.58(1).jpeg b/img/users_img/Admin/WhatsApp Image 2024-02-20 at 20.26.58(1).jpeg new file mode 100755 index 0000000..17b32c6 Binary files /dev/null and b/img/users_img/Admin/WhatsApp Image 2024-02-20 at 20.26.58(1).jpeg differ diff --git a/img/users_img/Admin/WhatsApp Image 2024-02-20 at 20.26.58(1)_1.jpeg b/img/users_img/Admin/WhatsApp Image 2024-02-20 at 20.26.58(1)_1.jpeg new file mode 100755 index 0000000..17b32c6 Binary files /dev/null and b/img/users_img/Admin/WhatsApp Image 2024-02-20 at 20.26.58(1)_1.jpeg differ diff --git a/img/users_img/Admin/dgrm.svg b/img/users_img/Admin/dgrm.svg new file mode 100755 index 0000000..0a85ca9 --- /dev/null +++ b/img/users_img/Admin/dgrm.svg @@ -0,0 +1,400 @@ + + + + + index.php + ,,, + + + Title$path = dirname(__FILE__) . '/'; + ,,, + + + + + + + + + + + + + + session_start(); + ,,, + + + + + + + + + + + + + + $_SESSION['access'] = true; + ,,, + + + + + + + + + + + + + + include_once $path . 'data/func.php'; + ,,, + + + + + + + + + + + + + + includePluginsPhp(); + ,,, + + + + + + + + + + + + + + SetConfig(); + ,,, + + + + + + + + + + + + + + $configAdmins = adminsConfig(); + ,,, + + + $REQUEST_URI = $_SERVER['REQUEST_URI'] === '/' ? GetRequestURL('/index.html')['str'] : GetRequestURL($_SERVER['REQUEST_URI'])['str']; + ,,, + + + $config['lng'] = SetLanguage(); + ,,, + + + $ansv = URLstr($path . 'data/filepath.'.$config['lng'].'.php', $REQUEST_URI); + ,,, + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $config['page_url'] = $ansv['FileURL']; + ,,, + + + + + + + + + + + + + + $_SESSION['page_url'] = $config['page_url']; + ,,, + + + $methodRpc = null; + ,,, + + + + + + + + + + + + + + if (!isset($_SESSION['page_url'])) { + ,,, + + + + + + + + + + + + + + + + + + + + + + + + + if ($_SERVER["REQUEST_METHOD"] === "POST" && strpos($_SERVER["CONTENT_TYPE"] ?? "", "application/json") !== false) { + ,,, + + + + + + + + + + + + + + $methodRpc = json_decode(file_get_contents("php://input"), true)["method"] ?? null; + ,,, + + + jsonrpcRequest(); + ,,, + + + if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['handleRequestAction'])) { + ,,, + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + handleRequest($_POST['handleRequestAction']); + ,,, + + + + + + + + + + + + + + setcookie('Login', $_SESSION['Login'] === 'true' ? 'true' : 'false', time() + 2419200, "/"); + ,,, + + + + + + + + + + + + + + + + + + + + + + + + + setcookie('User', $config['User'] ?? '', time() + 2419200, '/'); + ,,, + + + + + + + + + + + + + + $allowed = ['loginUser', 'setLng']; + ,,, + + + + + + + + + + + + + + if (($_POST['handleRequestAction'] && !in_array($_POST['handleRequestAction'], $allowed)) ||    ($methodRpc && !in_array($methodRpc, $allowed))) { + ,,, + + + + + + + + + + + + + + exit; + ,,, + + + + + + + + + + + + \ No newline at end of file diff --git a/img/users_img/Admin/dgrm_1.svg b/img/users_img/Admin/dgrm_1.svg new file mode 100755 index 0000000..0a85ca9 --- /dev/null +++ b/img/users_img/Admin/dgrm_1.svg @@ -0,0 +1,400 @@ + + + + + index.php + ,,, + + + Title$path = dirname(__FILE__) . '/'; + ,,, + + + + + + + + + + + + + + session_start(); + ,,, + + + + + + + + + + + + + + $_SESSION['access'] = true; + ,,, + + + + + + + + + + + + + + include_once $path . 'data/func.php'; + ,,, + + + + + + + + + + + + + + includePluginsPhp(); + ,,, + + + + + + + + + + + + + + SetConfig(); + ,,, + + + + + + + + + + + + + + $configAdmins = adminsConfig(); + ,,, + + + $REQUEST_URI = $_SERVER['REQUEST_URI'] === '/' ? GetRequestURL('/index.html')['str'] : GetRequestURL($_SERVER['REQUEST_URI'])['str']; + ,,, + + + $config['lng'] = SetLanguage(); + ,,, + + + $ansv = URLstr($path . 'data/filepath.'.$config['lng'].'.php', $REQUEST_URI); + ,,, + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $config['page_url'] = $ansv['FileURL']; + ,,, + + + + + + + + + + + + + + $_SESSION['page_url'] = $config['page_url']; + ,,, + + + $methodRpc = null; + ,,, + + + + + + + + + + + + + + if (!isset($_SESSION['page_url'])) { + ,,, + + + + + + + + + + + + + + + + + + + + + + + + + if ($_SERVER["REQUEST_METHOD"] === "POST" && strpos($_SERVER["CONTENT_TYPE"] ?? "", "application/json") !== false) { + ,,, + + + + + + + + + + + + + + $methodRpc = json_decode(file_get_contents("php://input"), true)["method"] ?? null; + ,,, + + + jsonrpcRequest(); + ,,, + + + if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['handleRequestAction'])) { + ,,, + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + handleRequest($_POST['handleRequestAction']); + ,,, + + + + + + + + + + + + + + setcookie('Login', $_SESSION['Login'] === 'true' ? 'true' : 'false', time() + 2419200, "/"); + ,,, + + + + + + + + + + + + + + + + + + + + + + + + + setcookie('User', $config['User'] ?? '', time() + 2419200, '/'); + ,,, + + + + + + + + + + + + + + $allowed = ['loginUser', 'setLng']; + ,,, + + + + + + + + + + + + + + if (($_POST['handleRequestAction'] && !in_array($_POST['handleRequestAction'], $allowed)) ||    ($methodRpc && !in_array($methodRpc, $allowed))) { + ,,, + + + + + + + + + + + + + + exit; + ,,, + + + + + + + + + + + + \ No newline at end of file diff --git a/img/users_img/Admin/Рисунок.png b/img/users_img/Admin/Рисунок.png new file mode 100755 index 0000000..83a0289 Binary files /dev/null and b/img/users_img/Admin/Рисунок.png differ diff --git a/img/users_img/Admin/Рисунок_1.png b/img/users_img/Admin/Рисунок_1.png new file mode 100755 index 0000000..83a0289 Binary files /dev/null and b/img/users_img/Admin/Рисунок_1.png differ diff --git a/img/users_img/Admin/Рисунок_2.png b/img/users_img/Admin/Рисунок_2.png new file mode 100755 index 0000000..83a0289 Binary files /dev/null and b/img/users_img/Admin/Рисунок_2.png differ diff --git a/img/users_img/Admin/Рисунок_3.png b/img/users_img/Admin/Рисунок_3.png new file mode 100755 index 0000000..83a0289 Binary files /dev/null and b/img/users_img/Admin/Рисунок_3.png differ diff --git a/index.php b/index.php old mode 100644 new mode 100755 diff --git a/main_plugin/SvgEditorM/SvgEditorM.css b/main_plugin/SvgEditorM/SvgEditorM.css new file mode 100755 index 0000000..b845d55 --- /dev/null +++ b/main_plugin/SvgEditorM/SvgEditorM.css @@ -0,0 +1,88 @@ +#message { + color: rgb(255, 255, 255); + font-size: 3em; + text-align: center; +} + +.sidebar { + display: flex; + flex-direction: column; + height: 80vh; +} +.sidebar__menu { + width: 100px; + float: left; + background-color: #f0f0f0; + box-sizing: border-box; +} + +#main { + margin: 7px 10px 7px 110px; + background-color: #ffffff; + box-sizing: border-box; +} + +.sidebar__title { + font-size: 1.5em; + text-align: center; +} +.sidebar__buttons { + font-size: 1.3em; + display: flex; + flex-direction: column; +} +.sidebar__button { + border: solid; + text-align: center; + padding: 5px; + margin: 5px; + border: 1px solid rgb(0, 0, 0); +} +.sidebar__shapes { + font-size: 1.3em; + margin-top: 0.5em; + display: flex; + flex-direction: column; +} +.sidebar__shape { + border: solid; + text-align: center; + padding: 5px; + margin: 5px; + border: 1px solid rgb(0, 0, 0); +} +.sidebar__selectors { + display: flex; + flex-direction: column; + margin-top: 0.5em; + font-size: 1.3em; +} +.sidebar__selector { + border: solid; + text-align: center; + padding: 5px; + margin: 5px; + border: 1px solid rgb(0, 0, 0); +} +.sidebar__selector.active { + background-color: #e4e4e4; +} +.sidebar__footer { + text-align: center; + margin-top: auto; +} + +.main { + height: 600px; +} + +.selection { + position: absolute; + display: none; + outline: rgb(153, 153, 255) solid 2px; + pointer-events: none; + left: 333.617px; + top: 55px; + width: 175.5px; + height: 175.5px; +} \ No newline at end of file diff --git a/main_plugin/SvgEditorM/SvgEditorM.js b/main_plugin/SvgEditorM/SvgEditorM.js new file mode 100755 index 0000000..519b994 --- /dev/null +++ b/main_plugin/SvgEditorM/SvgEditorM.js @@ -0,0 +1,762 @@ +/** + * @file SvgEditorM.js + * @brief Основной файл SvgEditorM, реализует функционал редактирования SVG-графики на сайте +*/ + +/** + * @brief Базовый SVG-элемент + * @param width Ширина + * @param height Высота + * @param posX Позиция X + * @param posY Позиция Y + * @param id ID элемента + * @param type Тип SVG-элемента +*/ +class SVGElement { + constructor({ width, height, posX, posY, id, type } = {}) { + this.width = width || 100; + this.height = height || 100; + this.posX = posX || 100; + this.posY = posY || 100; + this.id = id || `svgElement_${Date.now()}`; + this.type = type || 'svg'; + this.domNode = this.createSVGDOMNode(this.type); + } + + createSVGDOMNode(type) { + let { height, width, posY, posX, id } = this; + let svg = document.createElementNS('http://www.w3.org/2000/svg', type); + svg.setAttribute('style', 'border: 1px solid black; box-sizing: border-box;'); + svg.setAttribute('id', id); + if (type !== 'svg') { + svg.setAttribute('x', posX); + svg.setAttribute('y', posY); + svg.setAttribute('width', width); + svg.setAttribute('height', height); + } else { + svg.setAttribute('width', width); + svg.setAttribute('height', height); + } + svg.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', 'http://www.w3.org/1999/xlink'); + return svg; + } +} + +/** + * @brief Класс для модификации SVG-элементов +*/ +class SVGElementModifier { + static moveSelectedElement({ handler, event }) { + const { selected, selector, editor, offset } = handler; + const { clientX, clientY } = event; + if (selected) { + if (selected.tagName.toLowerCase() === 'circle') { + selected.setAttribute('cx', clientX + offset.x); + selected.setAttribute('cy', clientY + offset.y); + } else { + selected.setAttribute('x', clientX + offset.x); + selected.setAttribute('y', clientY + offset.y); + selector.updateSelection(selected, editor); + } + selector.updateSelection(selected); + } + } + + static deselectElement({ handler }) { + handler.selected = null; + } + + static toggelHoveredElement({ handler, target }) { + return handler.selector.updateSelection(target, handler.editor); + } + + static selectElement({ handler, event }) { + let { target, clientX, clientY } = event; + const { selector, editor } = handler; + if (selector.isSelectable(target, editor)) { + handler.offset.x = parseFloat(target.getAttribute('x')) - clientX || 0; + handler.offset.y = parseFloat(target.getAttribute('y')) - clientY || 0; + handler.selected = target; + } + } +} + +/** + * @brief Прямоугольник + * @param posX Позиция X + * @param posY Позиция Y + * @param width Ширина + * @param height Высота + * @param id ID элемента +*/ +class Rect extends SVGElement { + constructor({ posX, posY, width, height, id } = {}) { + super({ type: 'rect', posX, posY, width, height, id }); + this.domNode.setAttribute('width', width || 100); + this.domNode.setAttribute('height', height || 100); + this.domNode.setAttribute('x', posX || 100); + this.domNode.setAttribute('y', posY || 100); + this.domNode.setAttribute('fill', 'rgba(0,120,200,0.2)'); + this.domNode.setAttribute('stroke', '#0078c8'); + } +} + +/** + * @brief Класс выбора фигур + * @param id ID селектора +*/ +class ShapeSelector { + constructor(id) { + this.id = id; + this.selectorElem = document.getElementById(this.id); + } + + isSelectable(element, area) { + if (!element) return false; + if (element.isSameNode(area)) return false; + const tag = element.tagName ? element.tagName.toLowerCase() : ''; + return (tag === 'rect' || tag === 'circle' || tag === 'g' || tag === 'path' || tag === 'ellipse'); + } + + toggleSelectionOverElement(element) { + let bound = element.getBoundingClientRect(); + const { style } = this.selectorElem; + style.left = bound.left + 'px'; + style.top = bound.top + 'px'; + style.width = bound.width + 'px'; + style.height = bound.height + 'px'; + style.display = 'block'; + } + + updateSelection(element, area) { + if (this.isSelectable(element, area)) { + return this.toggleSelectionOverElement(element); + } + return this.hideSelection(); + } + + hideSelection() { + if (this.selectorElem) this.selectorElem.style.display = 'none'; + } +} + +/** + * @brief Обработчик событий редактора +*/ +class EditorEventHandler { + constructor() { + this.editor = null; + this.selector = null; + this.selected = null; + this.offset = { x: 0, y: 0 }; + } + + startListening({ editor, selector }) { + this.editor = editor; + this.selector = selector; + this.handleEditorEvents(); + } + + handleEditorEvents() { + this.handleElementsHover(); + this.handleElementSelect(); + this.handleMoveElement(); + this.handleElementDeselect(); + } + + handleElementsHover() { + this.editor.addEventListener('mouseover', ({ target }) => { + SVGElementModifier.toggelHoveredElement({ handler: this, target }); + }); + } + + handleElementSelect() { + this.editor.addEventListener('mousedown', event => { + SVGElementModifier.selectElement({ handler: this, event }); + }); + } + + handleElementDeselect() { + this.editor.addEventListener('mouseup', event => { + SVGElementModifier.deselectElement({ handler: this }); + }); + } + + handleMoveElement() { + this.editor.addEventListener('mousemove', event => { + SVGElementModifier.moveSelectedElement({ handler: this, event }); + }); + } +} + +/** + * @brief Область для рисования + * @param options Параметры области +*/ +class Area extends SVGElement { + constructor(options = {}) { + super({ type: 'svg', width: options.width || 800, height: options.height || 400, id: options.id || 'mySVG' }); + this.domNode.style.border = '3px solid black'; + } + + appendElement(element) { + this.domNode.appendChild(element); + } + + setDimentions() { } +} + +/** + * @brief Редактор SVG + * @param targetNode Узел-цель + * @param playGround Игровая область + * @param eventHandler Обработчик событий + * @param selector Селектор фигур +*/ +class Editor { + constructor({ targetNode, playGround, eventHandler, selector }) { + this.targetNode = targetNode; + this.playGround = playGround; + this.domNode = this.createEditor(); + this.selector = selector; + this.svgElements = []; + this.EditorEventHandler = eventHandler; + this.EditorEventHandler.startListening({ + editor: this.domNode, + selector: this.selector + }); + } + + setDimentions(node, width, height) { + node.style.width = '-webkit-fill-available'; + node.style.height = '-webkit-fill-available'; + return node; + } + + createEditor() { + let editor = this.playGround.domNode; + const { width, height } = this.getEditorParams(); + this.setDimentions(editor, width, height); + return editor; + } + + getEditorParams() { + let width = Math.max(this.targetNode.offsetWidth - 10, 0); + let height = Math.max(this.targetNode.offsetHeight - 10, 0); + return { width, height }; + } + + addElement(element) { + if (!element || !element.domNode) return; + this.playGround.appendElement(element.domNode); + this.svgElements.push(element); + } +} + +/* ----------------------------- + Инициализация (выполняется после загрузки DOM) + ----------------------------- */ + +window.addEventListener('DOMContentLoaded', () => { + let main = document.getElementById('main') || document.body; + + let selection = document.getElementById('selector'); + if (!selection) { + selection = document.createElement('div'); + selection.id = 'selector'; + Object.assign(selection.style, { + position: 'absolute', + display: 'none', + border: '1px dashed #333', + pointerEvents: 'none', + zIndex: 9999 + }); + document.body.appendChild(selection); + } + + const area = new Area({ id: 'mySVG', width: 800, height: 400 }); + main.appendChild(area.domNode); + + const selector = new ShapeSelector('selector'); + + const editorEventHandler = new EditorEventHandler(); + const editor = new Editor({ + targetNode: main, + playGround: area, + selector, + eventHandler: editorEventHandler + }); + + const testRect = new Rect({ posX: 20, posY: 20, width: 120, height: 80, id: 'r1' }); + const testRect2 = new Rect({ posX: 200, posY: 150, width: 140, height: 90, id: 'r2' }); + editor.addElement(testRect); + editor.addElement(testRect2); + + area.domNode.addEventListener('mouseover', (e) => { + const tgt = e.target; + selector.updateSelection(tgt, area.domNode); + }); + + window.addEventListener('resize', () => { + const { width, height } = editor.getEditorParams(); + editor.setDimentions(area.domNode, width, height); + }); + + console.log('SVG Editor initialized', { area, editor, selector }); +}); + +/* ----------------------------- + edit + ----------------------------- */ + +/** @brief Селектор основного контейнера */ +const MAIN_SEL = "#main"; +/** @brief ID элемента outline */ +const OUTLINE_ID = "outline"; +/** @brief Селектор боковой панели с фигурами */ +const SIDEBAR_SHAPES = ".sidebar__shapes"; +/** @brief Селектор боковой панели с режимами */ +const SIDEBAR_SELECTORS = ".sidebar__selectors"; +/** @brief Ключ для сохранения количества изменений */ +const saveCountKey = 'SvgEditorM_saveCount'; + +/** @brief Основной контейнер DOM */ +const main = document.querySelector(MAIN_SEL); +if (!main) throw new Error("Не найден #main"); + +/** @brief Массив svg элементов внутри main */ +let svgsInMain = Array.from(main.querySelectorAll("svg")); +/** @brief Рабочий svg элемент */ +let svg; +if (svgsInMain.length === 0) { + svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + svg.setAttribute("style", "border: 1px solid #ccc; box-sizing: border-box; width: -webkit-fill-available; height: -webkit-fill-available;"); + svg.setAttribute("width", "1000"); + svg.setAttribute("height", "600"); + main.appendChild(svg); +} else { + // keep first svg, remove extras to avoid duplicates + svg = svgsInMain[0]; + for (let i = 1; i < svgsInMain.length; i++) svgsInMain[i].remove(); +} + +/** @brief Создает и добавляет маркер стрелки к SVG */ +(function ensureArrowMarker() { + let defs = svg.querySelector("defs"); + if (!defs) { + defs = document.createElementNS("http://www.w3.org/2000/svg", "defs"); + svg.appendChild(defs); + } + if (!svg.querySelector("#arrowhead")) { + const marker = document.createElementNS("http://www.w3.org/2000/svg", "marker"); + marker.setAttribute("id", "arrowhead"); + marker.setAttribute("markerWidth", "6"); + marker.setAttribute("markerHeight", "4"); + marker.setAttribute("refX", "4.8"); + marker.setAttribute("refY", "2"); + marker.setAttribute("orient", "auto"); + const path = document.createElementNS("http://www.w3.org/2000/svg", "path"); + path.setAttribute("d", "M0,0 L6,2 L0,4 z"); + path.setAttribute("fill", "#495057"); + marker.appendChild(path); + defs.appendChild(marker); + } +})(); + +/** @brief Получает элемент outline из DOM */ +const outline = document.getElementById(OUTLINE_ID); +/** @brief Счетчик для генерации уникальных ID */ +let uid = 1; + +/** + * @brief Генерирует уникальный идентификатор для элемента + * @param prefix префикс для ID +*/ +function makeId(prefix = "el") { return `${prefix}_${Date.now().toString(36)}_${uid++}`; } + +/** + * @brief Преобразует координаты из клиентских в координаты SVG + * @param clientX координата X в пикселях + * @param clientY координата Y в пикселях +*/ +function clientToSvgPoint(clientX, clientY) { + const pt = svg.createSVGPoint(); + pt.x = clientX; pt.y = clientY; + const ctm = svg.getScreenCTM(); + if (!ctm) return { x: clientX, y: clientY }; + const inv = ctm.inverse(); + const p = pt.matrixTransform(inv); + return { x: p.x, y: p.y }; +} + +/** + * @brief Возвращает размеры и позицию элемента в координатах экрана + * @param el элемент SVG +*/ +function screenBBoxOf(el) { + try { + const bbox = el.getBBox(); + const p1 = svg.createSVGPoint(); p1.x = bbox.x; p1.y = bbox.y; + const p2 = svg.createSVGPoint(); p2.x = bbox.x + bbox.width; p2.y = bbox.y + bbox.height; + const s1 = p1.matrixTransform(svg.getScreenCTM()); + const s2 = p2.matrixTransform(svg.getScreenCTM()); + return { + left: Math.min(s1.x, s2.x), + top: Math.min(s1.y, s2.y), + width: Math.abs(s2.x - s1.x), + height: Math.abs(s2.y - s1.y) + }; + } catch (e) { + const r = el.getBoundingClientRect(); + return { left: r.left, top: r.top, width: r.width, height: r.height }; + } +} + +/** + * @brief Показывает или скрывает outline вокруг элемента + * @param el элемент SVG или null +*/ +function showOutlineFor(el) { + if (!outline) return; + if (!el) { outline.style.display = "none"; return; } + const b = screenBBoxOf(el); + outline.style.display = "block"; + outline.style.position = "fixed"; + outline.style.left = `${b.left-2}px`; + outline.style.top = `${b.top-2}px`; + outline.style.width = `${b.width}px`; + outline.style.height = `${b.height}px`; + outline.style.border = "2px solid rgba(0,120,255,0.6)"; + outline.style.pointerEvents = "none"; +} + +/** @brief Режим работы редактора */ +let mode = "Move"; +/** @brief Текущий выбранный элемент */ +let currentSelected = null; +/** @brief Состояние перетаскивания элемента */ +let dragState = null; + +document.querySelectorAll(`${SIDEBAR_SHAPES} .sidebar__shape`).forEach(node => { + node.addEventListener("click", () => { + const shapeName = node.textContent.trim().toLowerCase(); + createShape(shapeName); + }); +}); + +document.querySelectorAll(`${SIDEBAR_SELECTORS} .sidebar__selector`).forEach(node => { + node.addEventListener("click", () => { + document.querySelectorAll(`${SIDEBAR_SELECTORS} .sidebar__selector`).forEach(n => n.classList.remove("active")); + node.classList.add("active"); + mode = node.textContent.trim(); + }); +}); + +const defaultSel = document.querySelector(`${SIDEBAR_SELECTORS} .sidebar__selector`); +if (defaultSel) { + defaultSel.classList.add("active"); + mode = defaultSel.textContent.trim(); +} + +/** + * @brief Создает фигуру указанного типа в центре SVG + * @param kind тип фигуры: rect, circle, line, arrow +*/ +function createShape(kind) { + const center = { x: parseFloat(svg.getAttribute("width"))/2 || 200, y: parseFloat(svg.getAttribute("height"))/2 || 150 }; + const id = makeId(kind); + let el = null; + if (kind === "rect") { + el = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + el.setAttribute("x", center.x - 50); + el.setAttribute("y", center.y - 25); + el.setAttribute("width", 100); + el.setAttribute("height", 50); + el.setAttribute("fill", "#1aaee5"); + } else if (kind === "circle") { + el = document.createElementNS("http://www.w3.org/2000/svg", "circle"); + el.setAttribute("cx", center.x); + el.setAttribute("cy", center.y); + el.setAttribute("r", 30); + el.setAttribute("fill", "#ff6600"); + } else if (kind === "line") { + el = document.createElementNS("http://www.w3.org/2000/svg", "line"); + el.setAttribute("x1", center.x - 60); + el.setAttribute("y1", center.y); + el.setAttribute("x2", center.x + 60); + el.setAttribute("y2", center.y); + el.setAttribute("stroke", "#495057"); + el.setAttribute("stroke-width", 4); + } else if (kind === "arrow") { + el = document.createElementNS("http://www.w3.org/2000/svg", "line"); + el.setAttribute("x1", center.x - 60); + el.setAttribute("y1", center.y - 10); + el.setAttribute("x2", center.x + 60); + el.setAttribute("y2", center.y + 10); + el.setAttribute("stroke", "#495057"); + el.setAttribute("stroke-width", 4); + el.setAttribute("marker-end", "url(#arrowhead)"); + } else { + alert("Unknown shape: " + kind); + return; + } + el.setAttribute("id", id); + el.classList.add("draggable"); + svg.appendChild(el); + attachShapeListeners(el); + selectElement(el); +} + +/** + * @brief Подключает обработчики событий для фигуры + * @param el элемент SVG +*/ +function attachShapeListeners(el) { + el.addEventListener("mousedown", (ev) => { + ev.stopPropagation(); + const startClient = { x: ev.clientX, y: ev.clientY }; + const startSvg = clientToSvgPoint(ev.clientX, ev.clientY); + const startAttrs = readElementAttrs(el); + const action = mode === "Resize" ? "resize" : "move"; + dragState = { type: action, el, startClient, startSvg, startAttrs }; + selectElement(el); + window.addEventListener("mousemove", onWindowMouseMove); + window.addEventListener("mouseup", onWindowMouseUp); + }); + el.addEventListener("click", (e) => { e.stopPropagation(); selectElement(el); }); +} + +/** + * @brief Считывает атрибуты элемента SVG + * @param el элемент SVG +*/ +function readElementAttrs(el) { + const tag = el.tagName.toLowerCase(); + if (tag === "rect") { + return { + x: parseFloat(el.getAttribute("x")||0), + y: parseFloat(el.getAttribute("y")||0), + width: parseFloat(el.getAttribute("width")||0), + height: parseFloat(el.getAttribute("height")||0) + }; + } else if (tag === "circle") { + return { + cx: parseFloat(el.getAttribute("cx")||0), + cy: parseFloat(el.getAttribute("cy")||0), + r: parseFloat(el.getAttribute("r")||0) + }; + } else if (tag === "line") { + return { + x1: parseFloat(el.getAttribute("x1")||0), + y1: parseFloat(el.getAttribute("y1")||0), + x2: parseFloat(el.getAttribute("x2")||0), + y2: parseFloat(el.getAttribute("y2")||0) + }; + } + return {}; +} + +/** + * @brief Обрабатывает движение мыши при перетаскивании/изменении размера + * @param ev событие мыши +*/ +function onWindowMouseMove(ev) { + if (!dragState) return; + const { type, el, startSvg, startAttrs } = dragState; + const curSvg = clientToSvgPoint(ev.clientX, ev.clientY); + const dx = curSvg.x - startSvg.x; + const dy = curSvg.y - startSvg.y; + const tag = el.tagName.toLowerCase(); + + if (type === "move") { + if (tag === "rect") { + el.setAttribute("x", startAttrs.x + dx); + el.setAttribute("y", startAttrs.y + dy); + } else if (tag === "circle") { + el.setAttribute("cx", startAttrs.cx + dx); + el.setAttribute("cy", startAttrs.cy + dy); + } else if (tag === "line") { + el.setAttribute("x1", startAttrs.x1 + dx); + el.setAttribute("y1", startAttrs.y1 + dy); + el.setAttribute("x2", startAttrs.x2 + dx); + el.setAttribute("y2", startAttrs.y2 + dy); + } + } else { + if (tag === "rect") { + const newW = Math.max(6, startAttrs.width + dx); + const newH = Math.max(6, startAttrs.height + dy); + el.setAttribute("width", newW); + el.setAttribute("height", newH); + } else if (tag === "circle") { + const center = { x: startAttrs.cx, y: startAttrs.cy }; + const newR = Math.max(4, Math.hypot(curSvg.x - center.x, curSvg.y - center.y)); + el.setAttribute("r", newR); + } else if (tag === "line") { + el.setAttribute("x2", startAttrs.x2 + dx); + el.setAttribute("y2", startAttrs.y2 + dy); + } + } + + showOutlineFor(el); +} + +/** + * @brief Обрабатывает отпускание кнопки мыши при перетаскивании/изменении размера +*/ +function onWindowMouseUp() { + if (dragState) { + dragState = null; + window.removeEventListener("mousemove", onWindowMouseMove); + window.removeEventListener("mouseup", onWindowMouseUp); + } +} + +svg.addEventListener("mousedown", (ev) => { + if (ev.target === svg) selectElement(null); +}); + +/** + * @brief Выбирает элемент или снимает выбор + * @param el элемент SVG или null +*/ +function selectElement(el) { + if (currentSelected === el) return; + if (currentSelected) currentSelected.classList.remove("selected"); + currentSelected = el; + if (el) { + el.classList.add("selected"); + showOutlineFor(el); + } else { + showOutlineFor(null); + } +} + +Array.from(svg.querySelectorAll(".draggable, rect, circle, line")).forEach(attachShapeListeners); + +window.addEventListener("resize", () => showOutlineFor(currentSelected)); +window.addEventListener("scroll", () => showOutlineFor(currentSelected)); +window.addEventListener("keydown", (ev) => { + if ((ev.key === "Delete" || ev.key === "Backspace") && currentSelected) { + currentSelected.remove(); + selectElement(null); + } +}); + + + +/** @brief Кнопки панели сайдбара */ +const buttons = Array.from(document.querySelectorAll('.sidebar__button')); +/** @brief Кнопка сохранения */ +const saveBtn = buttons.find(b => b.textContent.trim().toLowerCase() === 'save'); +/** @brief Кнопка загрузки */ +const loadBtn = buttons.find(b => b.textContent.trim().toLowerCase() === 'load'); + +/** @brief Генерирует следующее имя файла для сохранения */ +function nextFilename() { + localStorage.setItem(saveCountKey, String((parseInt(localStorage.getItem(saveCountKey) || '0', 10) || 0) + 1)); + const n = parseInt(localStorage.getItem(saveCountKey), 10) || 1; + return n === 1 ? 'SvgEditorM.svg' : `SvgEditorM-${n}.svg`; +} + +/** @brief Возвращает SVG внутри main */ +function getMainSvg() { + return main.querySelector('svg'); +} + +/** + * @brief Устанавливает атрибуты xmlns для элемента SVG, если их нет + * @param el элемент SVG +*/ +function ensureXmlns(el) { + if (!el.getAttribute('xmlns')) el.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); + if (!el.getAttribute('xmlns:xlink')) el.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); + return el; +} + +/** @brief Сохраняет SVG из main в файл */ +function saveSvg() { + const svg = getMainSvg(); + if (!svg) return; + const clone = svg.cloneNode(true); + ensureXmlns(clone); + const xml = new XMLSerializer().serializeToString(clone); + const blob = new Blob([xml], { type: 'image/svg+xml;charset=utf-8' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = nextFilename(); + document.body.appendChild(a); + a.click(); + a.remove(); + setTimeout(() => URL.revokeObjectURL(url), 10000); +} + +/** @brief Элемент input для загрузки файлов */ +const fileInput = document.createElement('input'); +fileInput.type = 'file'; +fileInput.accept = '.svg,image/svg+xml'; +fileInput.style.display = 'none'; +document.body.appendChild(fileInput); + +/** + * @brief Делает узел и его потомков интерактивными + * @param node элемент SVG +*/ +function makeInteractiveForNode(node) { + if (!(node instanceof Element)) return; + const tag = node.tagName.toLowerCase(); + if (['rect','circle','line','path','polyline','polygon','g'].includes(tag)) { + if (!node.classList.contains('draggable')) node.classList.add('draggable'); + if (typeof attachShapeListeners === 'function') { + attachShapeListeners(node); + } + } + Array.from(node.children || []).forEach(ch => makeInteractiveForNode(ch)); +} + +/** + * @brief Загружает SVG из файла в main + * @param file объект File +*/ +async function loadSvgFile(file) { + if (!file) return; + const text = await file.text(); + const parser = new DOMParser(); + const doc = parser.parseFromString(text, 'image/svg+xml'); + const parsedSvg = doc.querySelector('svg'); + if (!parsedSvg) { + alert('Выбранный файл не содержит SVG'); + return; + } + const targetSvg = getMainSvg(); + if (!targetSvg) { + const imported = document.importNode(parsedSvg, true); + ensureXmlns(imported); + main.appendChild(imported); + Array.from(imported.querySelectorAll('*')).forEach(n => makeInteractiveForNode(n)); + } else { + const preservedOutline = document.getElementById('outline'); + while (targetSvg.firstChild) targetSvg.removeChild(targetSvg.firstChild); + Array.from(parsedSvg.childNodes).forEach(n => { + const imp = document.importNode(n, true); + targetSvg.appendChild(imp); + }); + Array.from(parsedSvg.attributes).forEach(attr => { + if (attr.name === 'xmlns' || attr.name === 'xmlns:xlink') return; + targetSvg.setAttribute(attr.name, attr.value); + }); + ensureXmlns(targetSvg); + Array.from(targetSvg.querySelectorAll('*')).forEach(n => makeInteractiveForNode(n)); + if (preservedOutline && preservedOutline.parentElement !== document.body) { + } + } + main.dispatchEvent(new CustomEvent('svg-loaded', { detail: { fileName: file.name } })); +} + +fileInput.addEventListener('change', () => { + const f = fileInput.files && fileInput.files[0]; + loadSvgFile(f).finally(() => { fileInput.value = ''; }); +}); + +if (saveBtn) saveBtn.addEventListener('click', (e) => { e.stopPropagation(); saveSvg(); }); +if (loadBtn) loadBtn.addEventListener('click', (e) => { e.stopPropagation(); fileInput.click(); }); diff --git a/main_plugin/SvgEditorM/index.php b/main_plugin/SvgEditorM/index.php new file mode 100755 index 0000000..194dfa7 --- /dev/null +++ b/main_plugin/SvgEditorM/index.php @@ -0,0 +1,30 @@ + + + + diff --git a/main_plugin/SvgEditorM/plug.php b/main_plugin/SvgEditorM/plug.php new file mode 100755 index 0000000..c22aa20 --- /dev/null +++ b/main_plugin/SvgEditorM/plug.php @@ -0,0 +1,25 @@ +'; + echo ""; +} +?> diff --git a/main_plugin/auth/auth.css b/main_plugin/auth/auth.css new file mode 100755 index 0000000..255e2e0 --- /dev/null +++ b/main_plugin/auth/auth.css @@ -0,0 +1,88 @@ +#authorizationButton { + width: 26px; + height: 26px; + position: relative; + cursor: pointer; + user-select: none; + float: right; + margin-left: 5px; +} +#authorizationButton:hover { + background-image: url(../../img/pict/g_iconslyb.svg); +} +#loginButton { + margin: 0px 3px; +} + +#authorizationDiv { + font-size: 0.85em; + display: inline-block; + position: fixed; + user-select: none; + background-color: rgba(255, 255, 255, 0.92); + width: 370px; + border-radius: 5px; + height: 230px; + box-shadow: 0px 0px 5px #777; + + color: #000000; + text-shadow: none; + z-index: 100; + min-height: fit-content; +} +#authorizationDiv input, #authorizationDiv textarea, #authorizationDiv select, #authorizationDiv button { + font-size: 0.85em; +} + +.authorizationDivTop { + text-align: center; + border: none; + border-bottom: inherit; + padding: 5px; + background-color: rgba(255, 255, 255, 0.6); +} +.authorizationDivCloseFun { + background-image: url(../../img/pict/b_iconslyb.svg); + float: right; + width: 22px; + height: 22px; + background-position: -159px -120px; + cursor: pointer; +} + +.authorizationDivMainDiv { + display: flex; + align-items: center; + height: 200px; + justify-content: center; + flex-direction: column; + padding: 10px 0px; +} +.formRow { + display: flex; + justify-content: center; + width: -webkit-fill-available; + margin: 5px 45px; +} +.formRow label { + margin-right: 10px; + white-space: nowrap; +} +.formRow input { + flex: 1; + min-width: 0; +} + +#BackArrow { + background-position: -77px -37px; + background-image: url(../../img/pict/b_iconslyb.svg); + width: 26px; + height: 26px; + position: absolute; + left: 0px; + top: 33px; +} +#BackArrow:hover { + background-image: url(../../img/pict/g_iconslyb.svg); + cursor: pointer; +} \ No newline at end of file diff --git a/main_plugin/auth/auth.js b/main_plugin/auth/auth.js new file mode 100755 index 0000000..7ff6155 --- /dev/null +++ b/main_plugin/auth/auth.js @@ -0,0 +1,161 @@ +/** + * @file auth.js + * @brief Скрипт авторизации, содержит функции и переменные для входа, регистрации и управления блоком авторизации +*/ + +addEventListener("load", function() { +movementMenu("authorizationDiv"); + +let authorizationButtonId = document.getElementById("authorizationButton"); +const authorizationDivId = document.getElementById("authorizationDiv"); + +if (getCookie('Login') == "true") { + authorizationButtonId.style.background = "url(../../img/pict/mc_iconslyb.svg) -1038px 1px"; + document.documentElement.style.setProperty('--autButBackX', '-1038'); + document.documentElement.style.setProperty('--autButBackY', '1'); + authorizationButtonId.onclick = function() { + jsonrpcRequest("logoutUser", { logoff: "Выйти" }) + .then(response => { + location.reload(); + }) + }; +} else if (getCookie('Login') == "false") { + authorizationButtonId.style.background = "url(../../img/pict/mc_iconslyb.svg) -756px 1px"; + document.documentElement.style.setProperty('--autButBackX', '-756'); + document.documentElement.style.setProperty('--autButBackY', '1'); + authorizationButtonId.onclick = function() { + const el = authorizationDivId; + if (el.style.visibility === "visible") { + el.style.visibility = "hidden"; + } else { + el.style.visibility = "visible"; + el.style.top = "20%"; + el.style.left = "50%"; + el.style.transform = "translate(-50%, -20%)"; + } + }; +} + +}); + +/** + * @brief Закрывает блок авторизации +*/ +function authorizationDivCloseFun() { + document.getElementById("authorizationDiv").style.visibility = "hidden"; +} + +/** + * @brief Создаёт форму кнопки входа +*/ +function loginButtonFunCreate() { + document.querySelector(".authorizationDivMainDiv").innerHTML = ` +
+
+ + +
+
+ + +
+
+ +
+ `; + + const inputLogin = document.getElementById('loginInput'); + const inputPass = document.getElementById('passInput'); + const loginBtn = document.getElementById('loginButton'); + [inputLogin, inputPass].forEach(input => { + input.addEventListener('keydown', function(e) { + if (e.key === 'Enter') { + if (loginBtn.getAttribute('onClick') === 'loginButtonFun()') { + loginBtn.click(); + } + } + }); + }); +} +/** + * @brief Обрабатывает нажатие кнопки входа +*/ +function loginButtonFun() { + var login = document.getElementById("loginInput").value; + var pass = document.getElementById("passInput").value; + jsonrpcRequest("loginUser", { login: login, pass: pass, log: "Войти" }) + .then(response => { + if (response == "true") { + location.reload(); + } else { + messageFunction("{{incorrect_login_password}}"); + } + }); +} + +/** + * @brief Создаёт форму кнопки регистрации +*/ +function registrationButtonFunCreate() { + document.querySelector(".authorizationDivMainDiv").innerHTML = ` +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ `; +} +/** + * @brief Обрабатывает нажатие кнопки регистрации +*/ +function registrationButtonFun() { + var login = document.getElementById("loginInput").value; + var pass = document.getElementById("passInput").value; + var passСheck = document.getElementById("passСheckInput").value; + var email = document.getElementById("emailInput").value; + if (login.trim() == "" || pass.trim() == "" || passСheck.trim() == "" || email.trim() == "" ) { + messageFunction("{{fill_all_fields}}"); + return; + } + if (pass != passСheck) { + messageFunction("{{passwords_do_not_match}}"); + return; + } + jsonrpcRequest("registerUser", { login: login, pass: pass, email: email }).then(response => { + if (response == "true") { + messageFunction("{{account_creation_request_sent}}"); + } else if (response == "name_exists") { + messageFunction("{{user_exists}}"); + } else { + messageFunction("{{account_creation_request_error}}"); + } + }); +} + +/** + * @brief Создаёт главную форму выбора между входом и регистрацией +*/ +function mainButtonFunCreate() { + document.querySelector(".authorizationDivMainDiv").innerHTML = ` +
{{account_authorization}}
+
+ + +
+ `; +} diff --git a/main_plugin/auth/auth.php b/main_plugin/auth/auth.php new file mode 100755 index 0000000..ae97755 --- /dev/null +++ b/main_plugin/auth/auth.php @@ -0,0 +1,43 @@ + + + + + + + + + \ No newline at end of file diff --git a/main_plugin/auth/func.auth.php b/main_plugin/auth/func.auth.php new file mode 100755 index 0000000..e4b3f1b --- /dev/null +++ b/main_plugin/auth/func.auth.php @@ -0,0 +1,82 @@ +users->user as $child) { + if ((string)$child['name'] === $params['login']) { + $exists = true; + break; + } + } + $usersFile = simplexml_load_file($path . $config['users']); + foreach ($usersFile->users->user as $child) { + if ((string)$child['name'] === $params['login']) { + $exists = true; + break; + } + } + + if ($exists) { + return "name_exists"; + } else { + $requestFile = simplexml_load_file($path . $config['usersRequest']); + $requestFilePath = $path . $config['usersRequest']; + + $newUser = $requestFile->users->addChild('user'); + $newUser->addAttribute('name', $params['login']); + $newUser->addAttribute('pass', $params['pass']); + $newUser->addAttribute('access', ''); + $newUser->addAttribute('email', $params['email']); + $newUser->addAttribute('link', md5($params['login'].$params['pass'])); + + $dom = new DOMDocument('1.0', 'UTF-8'); + $dom->preserveWhiteSpace = false; + $dom->formatOutput = true; + $dom->loadXML($requestFile->asXML()); + + if ($dom->save($requestFilePath)) { + return sendRegistrationEmail($params); + } else { + throw new Exception("Error while creating user request", -32003); + } + } +} + +/** + * @brief Отправляет уведомление о регистрации пользователю и администратору + * @param array $paramsEmail Массив с ключами 'login', 'pass', 'email' + * @return string "true" при успешной отправке + * @throws Exception Если произошла ошибка при отправке email +*/ +function sendRegistrationEmail($paramsEmail) { + global $config; + + $to = $config['emailAdmin']; + $subject = '=?UTF-8?B?'.base64_encode('Запрос на создание аккаунта на сайте ').'?=' . $_SERVER['HTTP_HOST']; + $message = 'Логин: ' . $paramsEmail['login'] . "\r\n"; + $message .= 'Пароль: ' . $paramsEmail['pass'] . "\r\n"; + $message .= 'Почта: ' . $paramsEmail['email'] . "\r\n"; + $message .= 'Сайт: ' . $config['server'] . "\r\n"; + $headers = "MIME-Version: 1.0" . "\r\n"; + $headers .= "Content-type: text/html; charset=UTF-8" . "\r\n"; + $headers .= "From: info@oblat.lv"; + + if (!mail($to, $subject, $message, $headers)) { + throw new Exception("Error sending email", -32002); + } + + return "true"; +} +?> \ No newline at end of file diff --git a/main_plugin/auth/lang.js.php b/main_plugin/auth/lang.js.php new file mode 100755 index 0000000..450c6d2 --- /dev/null +++ b/main_plugin/auth/lang.js.php @@ -0,0 +1,23 @@ + $value) { + $placeholders['{{' . $key . '}}'] = $value; +} + +echo strtr(file_get_contents($path . 'auth.js'), $placeholders); +?> diff --git a/main_plugin/auth/lang.php b/main_plugin/auth/lang.php new file mode 100755 index 0000000..c40b692 --- /dev/null +++ b/main_plugin/auth/lang.php @@ -0,0 +1,61 @@ + [ + 'authorization' => 'Авторизация', + 'login_label' => 'Логин', + 'password_label' => 'Пароль', + 'incorrect_login_password' => 'Неверный логин или пароль!', + 'repeat_password_label' => 'Повторите пароль', + 'email_label' => 'Почта', + 'fill_all_fields' => 'Вы должны заполнить все поля!', + 'passwords_do_not_match' => 'Пароли не совпадают!', + 'account_creation_request_sent' => 'Запрос на создание аккаунта отправлен!', + 'user_exists' => 'Пользователь с таким логином уже существует!', + 'account_creation_error' => 'Ошибка при создании аккаунта!', + 'incorrect_email' => 'Вы ввели неправильную почту!', + 'account_creation_request_error' => 'Ошибка при отправке запроса на создание аккаунта!', + 'account_authorization' => 'Авторизация аккаунта', + 'login' => 'Войти', + 'register' => 'Зарегистрироваться', + 'logoff' => 'Выйти', + ], + 'en' => [ + 'authorization' => 'Authorization', + 'login_label' => 'Login', + 'password_label' => 'Password', + 'incorrect_login_password' => 'Incorrect login or password!', + 'repeat_password_label' => 'Repeat password', + 'email_label' => 'Email', + 'fill_all_fields' => 'You must fill out all fields!', + 'passwords_do_not_match' => 'Passwords do not match!', + 'account_creation_request_sent' => 'Account creation request sent!', + 'user_exists' => 'User with this login already exists!', + 'account_creation_error' => 'Error while creating the account!', + 'incorrect_email' => 'Incorrect email!', + 'account_creation_request_error' => 'Error sending account creation request!', + 'account_authorization' => 'Account authorization', + 'login' => 'Login', + 'register' => 'Register', + 'logoff' => 'Log out', + ], + 'lv' => [ + 'authorization' => 'Autentifikācija', + 'login_label' => 'Lietotājvārds', + 'password_label' => 'Parole', + 'incorrect_login_password' => 'Nepareizs lietotājvārds vai parole!', + 'repeat_password_label' => 'Atkārtot paroli', + 'email_label' => 'E-pasts', + 'fill_all_fields' => 'Jums jāaizpilda visi lauki!', + 'passwords_do_not_match' => 'Paroles nesakrīt!', + 'account_creation_request_sent' => 'Pieprasījums par konta izveidi nosūtīts!', + 'user_exists' => 'Lietotājs ar šo lietotājvārdu jau pastāv!', + 'account_creation_error' => 'Kļūda, izveidojot kontu!', + 'incorrect_email' => 'Nepareizs e-pasts!', + 'account_creation_request_error' => 'Kļūda, nosūtot pieprasījumu par konta izveidi!', + 'account_authorization' => 'Konta autentifikācija', + 'login' => 'Ieiet', + 'register' => 'Reģistrēties', + 'logoff' => 'Iziet', + ], +]; +return $lang; \ No newline at end of file diff --git a/main_plugin/auth/plug.php b/main_plugin/auth/plug.php new file mode 100755 index 0000000..97b5bc3 --- /dev/null +++ b/main_plugin/auth/plug.php @@ -0,0 +1,27 @@ + $value) { + $Html = str_replace('{{' . $key . '}}', $value, $Html); +} + +echo $Html; +echo ''; +echo ''; +?> diff --git a/main_plugin/dgrm/dgrm.css b/main_plugin/dgrm/dgrm.css new file mode 100755 index 0000000..d186549 --- /dev/null +++ b/main_plugin/dgrm/dgrm.css @@ -0,0 +1,149 @@ +#diagram { + height: 100%; + width: 100%; + margin: 0; + user-select: none; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + font-size: 16px; + color: rgb(73, 80, 87); + outline: none; + height: calc(95% + 2px); +} + +a { + color: #0d6efd; + text-decoration: underline; +} + +#dgrmDiv { + display: inline-block; + user-select: none; + width: -webkit-fill-available; + border-radius: 5px; + height: 600px; + font-size: 1em; + max-width: calc(100% - 20px); + overflow-y: hidden; + transform: translate(0%, 0%); +} + +#dgrmTop { + text-align: center; + border-bottom: 1px #40464d solid; + padding: 5px; + background-color: rgba(255, 255, 255, 0.6); +} +#dgrmTopTitle { + text-align: center; +} + +#options { + position: absolute !important; +} +.menu { + position: absolute !important; +} +#menu { + position: absolute !important; +} + + + + text { + white-space: pre-wrap; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + font-size: 16px; + color: rgb(73, 80, 87); + } + + textarea { + text-align: center; + border: none;; + padding: 10px; + padding-top: 0.8em; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + font-size: 16px; + background-color: transparent; + color: transparent; + outline: none; + overflow: hidden; + resize: none; + line-height: 1em; + caret-color: #fff; + } + + [data-connect] { display: none; } + + .select path[data-key="selected"], + .select .path-end, + .select [data-connect], + .highlight-e [data-key="end"] .path-end, + .highlight-s [data-key="start"] .path-end, + .hover [data-connect] { + display: unset; + opacity: 0.51; + stroke: rgb(108 187 247); + fill: rgb(108 187 247); + } + [data-connect].hover { stroke-width: 25px; } + + .select path[data-key="selected"] { fill:none; } + + .highlight [data-key="main"]{ + paint-order: stroke; + stroke-width: 10px; + stroke: rgb(108 187 247 / 51%); + } + + .shpath [data-key="end"] .path, + .shpath [data-key="start"] .path { display: none;} + .shpath.arw-e [data-key="end"] .path, + .shpath.arw-s [data-key="start"] .path { display: unset;} + .shpath.dash [data-key="path"] { stroke-dasharray:5; } + + @media (pointer: coarse) { + circle.path-end { r: 20px; } + .ative-elem { + stroke: rgb(108 187 247 / 51%); + stroke-width: 70px; + } + + [data-connect] { stroke-width: 15px; } + [data-connect].hover { stroke-width: 70px; } + } + + + .shrect.ta-1 text, .shtxt.ta-1 text { text-anchor: start; } + .shrect.ta-2 text, .shtxt.ta-2 text { text-anchor: middle; } + .shrect.ta-3 text, .shtxt.ta-3 text { text-anchor: end; } + .shrect.ta-1 textarea, .shtxt.ta-1 textarea { text-align: left; } + .shrect.ta-2 textarea, .shtxt.ta-2 textarea { text-align: center; } + .shrect.ta-3 textarea, .shtxt.ta-3 textarea { text-align: right; } + .shtxt textarea { caret-color: rgb(73, 80, 87); } + .shtxt text { fill:rgb(73, 80, 87); } + .shtxt [data-key="main"] { fill: transparent; stroke: transparent; } + .shtxt.select [data-key="main"], .shtxt.highlight [data-key="main"] { stroke: rgb(108 187 247 / 51%); stroke-width: 2px; } + + .shrhomb.highlight [data-key="border"] { stroke-width: 28px; stroke: rgb(108 187 247 / 51%); } + .shrhomb.highlight [data-key="main"] { stroke-width:18px; stroke:#1D809F; } + + .cl-red [data-key="main"] { fill: #E74C3C; } .cl-red .path { stroke: #E74C3C;} + .cl-orange [data-key="main"] { fill: #ff6600;} .cl-orange .path { stroke: #ff6600;} + .cl-green [data-key="main"] { fill: #19bc9b;} .cl-green .path { stroke: #19bc9b;} + .cl-blue [data-key="main"] { fill: #1aaee5;} .cl-blue .path { stroke: #1aaee5;} + .cl-dblue [data-key="main"] { fill: #1D809F;} .cl-dblue .path { stroke: #1D809F;} + .cl-dgray [data-key="main"] { fill: #495057;} .cl-dgray .path { stroke: #495057;} + + .shtxt.cl-red [data-key="main"] { fill: transparent; } .shtxt.cl-red text { fill: #E74C3C; } + .shtxt.cl-orange [data-key="main"] { fill: transparent; } .shtxt.cl-orange text { fill: #ff6600; } + .shtxt.cl-green [data-key="main"] { fill: transparent; } .shtxt.cl-green text { fill: #19bc9b; } + .shtxt.cl-blue [data-key="main"] { fill: transparent; } .shtxt.cl-blue text { fill: #1aaee5; } + .shtxt.cl-dblue [data-key="main"] { fill: transparent; } .shtxt.cl-dblue text { fill: #1D809F; } + .shtxt.cl-dgray [data-key="main"] { fill: transparent; } .shtxt.cl-dgray text { fill: #495057; } + + .shrhomb.cl-red [data-key="main"] { stroke-width:18px; stroke:#E74C3C; } + .shrhomb.cl-orange [data-key="main"] { stroke-width:18px; stroke:#ff6600; } + .shrhomb.cl-green [data-key="main"] { stroke-width:18px; stroke:#19bc9b; } + .shrhomb.cl-blue [data-key="main"] { stroke-width:18px; stroke:#1aaee5; } + .shrhomb.cl-dblue [data-key="main"] { stroke-width:18px; stroke:#1D809F; } + .shrhomb.cl-dgray [data-key="main"] { stroke-width:18px; stroke:#495057; } \ No newline at end of file diff --git a/main_plugin/dgrm/diagram/canvas-clear.js b/main_plugin/dgrm/diagram/canvas-clear.js new file mode 100755 index 0000000..bcfed38 --- /dev/null +++ b/main_plugin/dgrm/diagram/canvas-clear.js @@ -0,0 +1,26 @@ +import { CanvasSmbl } from '../infrastructure/canvas-smbl.js'; +import { PathSmbl } from '../shapes/path-smbl.js'; +import { ShapeSmbl } from '../shapes/shape-smbl.js'; + +/** @param {CanvasElement} canvas */ +export function canvasClear(canvas) { + while (canvas.firstChild) { + (canvas.firstChild[ShapeSmbl] || canvas.firstChild[PathSmbl]).del(); + } + canvas[CanvasSmbl].move(0, 0, 1); +} + +// +// selection clear function + +/** @param {CanvasElement} canvas */ +export function canvasSelectionClear(canvas) { + if (canvas[CanvasSmbl].selectClear) { canvas[CanvasSmbl].selectClear(); }; +} + +/** @param {CanvasElement} canvas, @param {()=>void} clearFn */ +export function canvasSelectionClearSet(canvas, clearFn) { + canvas[CanvasSmbl].selectClear = clearFn; +} + +/** @typedef { import('../infrastructure/move-scale-applay.js').CanvasElement } CanvasElement */ diff --git a/main_plugin/dgrm/diagram/dgrm-png.js b/main_plugin/dgrm/diagram/dgrm-png.js new file mode 100755 index 0000000..3b6443b --- /dev/null +++ b/main_plugin/dgrm/diagram/dgrm-png.js @@ -0,0 +1,30 @@ +import { CanvasSmbl } from '../infrastructure/canvas-smbl.js'; + +/** + * @param {CanvasElement} canvas + * @param {any} serializedData + * @param {function(Blob):void} callBack + */ +export function fileSaveSvg(canvas, serializedData, callBack) { + const svgVirtual = /** @type {SVGSVGElement} */(canvas.ownerSVGElement.cloneNode(true)); + + svgVirtual.style.backgroundImage = null; + svgVirtual.querySelectorAll('.select, .highlight').forEach(el => el.classList.remove('select', 'highlight')); + + const nonSvgElems = svgVirtual.getElementsByTagName('foreignObject'); + while (nonSvgElems[0]) { nonSvgElems[0].parentNode.removeChild(nonSvgElems[0]); } + +/* svgVirtual.querySelectorAll('g.hovertrack.shtxt.ta-1').forEach(group => { + group.querySelectorAll('text, tspan').forEach(el => console.log(el)); + }); */ + + const svgStr = new XMLSerializer().serializeToString(svgVirtual); + const blob = new Blob([svgStr], { type: 'image/svg+xml;charset=utf-8' }); + callBack(blob); +} + + + + +/** @typedef { {x:number, y:number} } Point */ +/** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */ diff --git a/main_plugin/dgrm/diagram/dgrm-serialization.js b/main_plugin/dgrm/diagram/dgrm-serialization.js new file mode 100755 index 0000000..9d17b8a --- /dev/null +++ b/main_plugin/dgrm/diagram/dgrm-serialization.js @@ -0,0 +1,108 @@ +import { CanvasSmbl } from '../infrastructure/canvas-smbl.js'; +import { PathSmbl } from '../shapes/path-smbl.js'; +import { ShapeSmbl } from '../shapes/shape-smbl.js'; +import { canvasClear } from './canvas-clear.js'; + +const v = '1.1'; + +/** @param {Element} canvas */ +export const serialize = (canvas) => serializeShapes(/** @type {Array} */([...canvas.children])); + +/** @param {Array} shapes */ +export function serializeShapes(shapes) { + /** @type {DiagramSerialized} */ + const diagramSerialized = { v, s: [] }; + for (const shape of shapes) { + if (shape[ShapeSmbl]) { + // shape + diagramSerialized.s.push(shape[ShapeSmbl].data); + } else { + // path + + /** @param {PathEnd} pathEnd */ + function pathSerialize(pathEnd) { + const shapeIndex = shapes.indexOf(pathEnd.shape?.shapeEl); + return (shapeIndex !== -1) + ? { s: shapeIndex, k: pathEnd.shape.connectorKey } + : { p: pathEnd.data }; + } + + const pathData = shape[PathSmbl].data; + const pathJson = { type: 0, s: pathSerialize(pathData.s), e: pathSerialize(pathData.e) }; + if (pathData.styles) { pathJson.c = pathData.styles; } + + diagramSerialized.s.push(pathJson); + } + } + + return diagramSerialized; +} + +/** + * @param {CanvasElement} canvas + * @param {DiagramSerialized} data + * @param {Boolean=} dontClear + */ +export function deserialize(canvas, data, dontClear) { + if (data.v !== v) { alert('Wrong format'); return null; } + if (!dontClear) { canvasClear(canvas); } + + /** @type {Map} */ + const shapeDataToElem = new Map(); + + /** @param {ShapeData} shapeData */ + function shapeEnsure(shapeData) { + let shapeEl = shapeDataToElem.get(shapeData); + if (!shapeEl) { + shapeEl = canvas[CanvasSmbl].shapeMap[shapeData.type].create(shapeData); + canvas.append(shapeEl); + shapeDataToElem.set(shapeData, shapeEl); + } + return shapeEl; + } + + /** @param {number?} index */ + const shapeByIndex = index => shapeEnsure(/** @type {ShapeData} */(data.s[index])); + + /** @type {PathElement[]} */ + const paths = []; + for (const shape of data.s) { + switch (shape.type) { + // path + case 0: { + /** @param {PathEndSerialized} pathEnd */ + const pathDeserialize = pathEnd => pathEnd.p + ? { data: pathEnd.p } + : { shape: { shapeEl: shapeByIndex(pathEnd.s), connectorKey: pathEnd.k } }; + + const path = canvas[CanvasSmbl].shapeMap[0].create({ + styles: /** @type {PathSerialized} */(shape).c, + s: pathDeserialize(/** @type {PathSerialized} */(shape).s), + e: pathDeserialize(/** @type {PathSerialized} */(shape).e) + }); + paths.push(path); + canvas.append(path); + break; + } + default: shapeEnsure(/** @type {ShapeData} */(shape)); break; + } + } + + return [...shapeDataToElem.values(), ...paths]; +} + +/** @typedef {{v:string, s: Array}} DiagramSerialized */ + +/** @typedef { import("../shapes/shape-smbl").ShapeElement } ShapeElement */ +/** @typedef { import('../shapes/shape-evt-proc').ShapeData } ShapeData */ + +/** @typedef { import("../shapes/path-smbl").PathElement } PathElement */ +/** @typedef { import('../shapes/path').PathEndData } PathEndData */ +/** @typedef { import('../shapes/path').PathEnd } PathEnd */ +/** @typedef { import('../shapes/path').PathData } PathData */ + +/** @typedef { {s?:number, k?:string, p?:PathEndData} } PathEndSerialized */ +/** @typedef { {type:number, c?:string, s:PathEndSerialized, e:PathEndSerialized} } PathSerialized */ + +/** @typedef { import('../shapes/shape-evt-proc').CanvasData } CanvasData */ +/** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */ diff --git a/main_plugin/dgrm/diagram/dgrm-srv.js b/main_plugin/dgrm/diagram/dgrm-srv.js new file mode 100755 index 0000000..fe65072 --- /dev/null +++ b/main_plugin/dgrm/diagram/dgrm-srv.js @@ -0,0 +1,32 @@ +const svrApi = 'https://localhost:7156/api'; + +/** + * @param {string} key + * @param {DiagramSerialized} serialized + * @returns {Promise} + */ +export async function srvSave(key, serialized) { + return await fetch(`${svrApi}/${key}`, { + method: 'POST', + headers: { 'Content-Type': 'application/json;charset=utf-8' }, + body: JSON.stringify(serialized) + }); +} + +/** + * get diagram json by key + * @param {string} key + * @returns {Promise} + */ +export async function srvGet(key) { + return (await fetch(`${svrApi}/${key}`)).json(); +} + +export function generateKey() { + const arr = new Uint8Array((8 / 2)); + window.crypto.getRandomValues(arr); + const date = new Date(); + return `${date.getUTCFullYear()}${(date.getUTCMonth() + 1).toString().padStart(2, '0')}${Array.from(arr, dec => dec.toString(16).padStart(2, '0')).join('')}`; +} + +/** @typedef { import("./dgrm-serialization").DiagramSerialized } DiagramSerialized */ diff --git a/main_plugin/dgrm/diagram/group-move.js b/main_plugin/dgrm/diagram/group-move.js new file mode 100755 index 0000000..5a92971 --- /dev/null +++ b/main_plugin/dgrm/diagram/group-move.js @@ -0,0 +1,61 @@ +import { CanvasSmbl } from '../infrastructure/canvas-smbl.js'; +import { placeToCell, pointInCanvas } from '../infrastructure/move-scale-applay.js'; +import { pointShift } from '../infrastructure/util.js'; + +/** @param {CanvasElement} canvas, @param {DiagramSerialized} data */ +export function groupMoveToCenter(canvas, data) { + const screenCenter = pointInCanvas(canvas[CanvasSmbl].data, window.innerWidth / 2, window.innerHeight / 2); + placeToCell(screenCenter, canvas[CanvasSmbl].data.cell); + + const shift = pointShift(screenCenter, centerCalc(data), -1); + iteratePoints(data, point => { if (point) { pointShift(point, shift); } }); +} + +/** @param {DiagramSerialized} data */ +function centerCalc(data) { + const minMax = maxAndMinPoint(data); + return { + x: minMax.min.x + (minMax.max.x - minMax.min.x) / 2, + y: minMax.min.y + (minMax.max.y - minMax.min.y) / 2 + }; +} + +/** @param {DiagramSerialized} data */ +function maxAndMinPoint(data) { + /** @type {Point} */ + const min = { x: Infinity, y: Infinity }; + + /** @type {Point} */ + const max = { x: -Infinity, y: -Infinity }; + + iteratePoints(data, point => { + if (!point) { return; } + + if (min.x > point.x) { min.x = point.x; } + if (min.y > point.y) { min.y = point.y; } + + if (max.x < point.x) { max.x = point.x; } + if (max.y < point.y) { max.y = point.y; } + }); + return { min, max }; +} + +/** @param {DiagramSerialized} data, @param {(point:Point)=>void} callbackfn */ +function iteratePoints(data, callbackfn) { + data.s.forEach(shapeOrPath => { + if (shapeOrPath.type === 0) { + // path + callbackfn(/** @type {PathSerialized} */(shapeOrPath).s.p?.position); + callbackfn(/** @type {PathSerialized} */(shapeOrPath).e.p?.position); + } else { + // shape + callbackfn(/** @type {ShapeData} */(shapeOrPath).position); + } + }); +} + +/** @typedef { {x:number, y:number} } Point */ +/** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */ +/** @typedef { import('./dgrm-serialization.js').DiagramSerialized } DiagramSerialized */ +/** @typedef { import('./dgrm-serialization.js').PathSerialized } PathSerialized */ +/** @typedef { import('../shapes/shape-evt-proc.js').ShapeData } ShapeData */ diff --git a/main_plugin/dgrm/diagram/group-select-applay.js b/main_plugin/dgrm/diagram/group-select-applay.js new file mode 100755 index 0000000..6f43e14 --- /dev/null +++ b/main_plugin/dgrm/diagram/group-select-applay.js @@ -0,0 +1,396 @@ +import { CanvasSmbl } from '../infrastructure/canvas-smbl.js'; +import { movementApplay, ProcessedSmbl, shapeSelect } from '../infrastructure/move-evt-proc.js'; +import { placeToCell, pointInCanvas } from '../infrastructure/move-scale-applay.js'; +import { arrPop, classAdd, classDel, deepCopy, listen, listenDel, positionSet, svgEl } from '../infrastructure/util.js'; +import { PathSmbl } from '../shapes/path-smbl.js'; +import { ShapeSmbl } from '../shapes/shape-smbl.js'; +import { GroupSettings } from './group-settings.js'; +import { modalCreate } from '../shapes/modal-create.js'; +import { groupMoveToCenter } from './group-move.js'; +import { deserialize, serializeShapes } from './dgrm-serialization.js'; +import { canvasSelectionClear, canvasSelectionClearSet } from './canvas-clear.js'; +import { tipShow } from '../ui/ui.js'; + +// +// copy past + +const clipboardDataKey = 'dgrm'; + +/** @param {() => Array} shapesToClipboardGetter */ +export function listenCopy(shapesToClipboardGetter) { + /** @param {ClipboardEvent & {target:HTMLElement | SVGElement}} evt */ + function onCopy(evt) { + const shapes = shapesToClipboardGetter(); + if (document.activeElement === shapes[0].ownerSVGElement) { + evt.preventDefault(); + evt.clipboardData.setData( + clipboardDataKey, + JSON.stringify(copyDataCreate(shapes))); + } + } + document.addEventListener('copy', onCopy); + + // dispose fn + return function() { + listenDel(document, 'copy', onCopy); + }; +} + +/** @param {CanvasElement} canvas */ +export function copyPastApplay(canvas) { + listen(document, 'paste', /** @param {ClipboardEvent & {target:HTMLElement | SVGElement}} evt */ evt => { + if (evt.target.tagName.toUpperCase() === 'TEXTAREA') { return; } + // if (document.activeElement !== canvas.ownerSVGElement) { return; } + + const dataStr = evt.clipboardData.getData(clipboardDataKey); + if (!dataStr) { return; } + + tipShow(false); + canvasSelectionClear(canvas); + past(canvas, JSON.parse(dataStr)); + }); +} + +/** @param {CanvasElement} canvas, @param {Array} shapes */ +export const copyAndPast = (canvas, shapes) => past(canvas, copyDataCreate(shapes)); + +/** @param {Array} shapes */ +const copyDataCreate = shapes => deepCopy(serializeShapes(shapes)); + +/** @param {CanvasElement} canvas, @param {DiagramSerialized} data */ +function past(canvas, data) { + canvasSelectionClear(canvas); + groupMoveToCenter(canvas, data); + groupSelect(canvas, deserialize(canvas, data, true)); +} + +// +// group select + +const highlightSClass = 'highlight-s'; +const highlightEClass = 'highlight-e'; +const highlightClass = 'highlight'; + +/** wait long press and draw selected rectangle + * @param {CanvasElement} canvas + */ +export function groupSelectApplay(canvas) { + const svg = canvas.ownerSVGElement; + let timer; + /** @type {Point} */ let selectStart; + /** @type {SVGCircleElement} */ let startCircle; + /** @type {SVGRectElement} */ let selectRect; + /** @type {Point} */ let selectRectPos; + + /** @param {PointerEvent} evt */ + function onMove(evt) { + if (evt[ProcessedSmbl] || !selectRect) { reset(); return; } + evt[ProcessedSmbl] = true; + + if (startCircle) { startCircle.remove(); startCircle = null; } + + // draw rect + const x = evt.clientX - selectStart.x; + const y = evt.clientY - selectStart.y; + selectRect.width.baseVal.value = Math.abs(x); + selectRect.height.baseVal.value = Math.abs(y); + if (x < 0) { selectRectPos.x = evt.clientX; } + if (y < 0) { selectRectPos.y = evt.clientY; } + selectRect.style.transform = `translate(${selectRectPos.x}px, ${selectRectPos.y}px)`; + } + + function onUp() { + if (selectRect) { + /** @param {Point} point */ + const inRect = point => pointInRect( + pointInCanvas(canvas[CanvasSmbl].data, selectRectPos.x, selectRectPos.y), + selectRect.width.baseVal.value / canvas[CanvasSmbl].data.scale, + selectRect.height.baseVal.value / canvas[CanvasSmbl].data.scale, + point.x, point.y); + + // select shapes in rect + groupSelect( + canvas, + /** @type {Iterable} */(canvas.children), + inRect); + } + + reset(); + } + + function reset() { + clearTimeout(timer); timer = null; + startCircle?.remove(); startCircle = null; + selectRect?.remove(); selectRect = null; + + listenDel(svg, 'pointermove', onMove); + listenDel(svg, 'wheel', reset); + listenDel(svg, 'pointerup', onUp); + } + + listen(svg, 'pointerdown', /** @param {PointerEvent} evt */ evt => { + if (evt[ProcessedSmbl] || !evt.isPrimary) { reset(); return; } + + listen(svg, 'pointermove', onMove); + listen(svg, 'wheel', reset, true); + listen(svg, 'pointerup', onUp, true); + + timer = setTimeout(_ => { + canvasSelectionClear(canvas); + + startCircle = svgEl('circle'); + classAdd(startCircle, 'ative-elem'); + startCircle.style.cssText = 'r:10px; fill: rgb(108 187 247 / 51%)'; + positionSet(startCircle, { x: evt.clientX, y: evt.clientY }); + svg.append(startCircle); + + selectStart = { x: evt.clientX, y: evt.clientY }; + selectRectPos = { x: evt.clientX, y: evt.clientY }; + selectRect = svgEl('rect'); + selectRect.style.cssText = 'rx:10px; fill: rgb(108 187 247 / 51%)'; + positionSet(selectRect, selectRectPos); + svg.append(selectRect); + }, 500); + }); +} + +/** + * Highlight selected shapes and procces group operations (move, del, copy) + * @param {CanvasElement} canvas + * @param {Iterable} elems + * @param {{(position:Point):boolean}=} inRect + */ +export function groupSelect(canvas, elems, inRect) { + /** @param {{position:Point}} data */ + const shapeInRect = data => inRect ? inRect(data.position) : true; + + /** @type {Selected} */ + const selected = { + shapes: [], + shapesPaths: [], + pathEnds: [], + pathEndsPaths: [] + }; + + /** + * @param {ShapeOrPathElement} pathEl, @param {PathEnd} pathEnd, @param {string} highlightClass + * @returns {1|2|0} + */ + function pathEndInRect(pathEl, pathEnd, highlightClass) { + if (!pathEnd.shape && shapeInRect(pathEnd.data)) { + selected.pathEnds.push(pathEnd); + classAdd(pathEl, highlightClass); + return 1; // connect to end in rect + } else if (pathEnd.shape && shapeInRect(pathEnd.shape.shapeEl[ShapeSmbl].data)) { + return 2; // connect to shape in rect + } + return 0; // not in rect + } + + for (const shapeEl of elems) { + if (shapeEl[ShapeSmbl]) { + if (shapeInRect(shapeEl[ShapeSmbl].data)) { + classAdd(shapeEl, highlightClass); + selected.shapes.push(shapeEl); + } + } else if (shapeEl[PathSmbl]) { + const isStartIn = pathEndInRect(shapeEl, shapeEl[PathSmbl].data.s, highlightSClass); + const isEndIn = pathEndInRect(shapeEl, shapeEl[PathSmbl].data.e, highlightEClass); + + if (isStartIn === 1 || isEndIn === 1) { + selected.pathEndsPaths.push(shapeEl); + } + + if (isStartIn === 2 || isEndIn === 2) { + selected.shapesPaths.push(shapeEl); + } + } + } + + groupEvtProc(canvas, selected); +} + +/** + * @param {CanvasElement} canvas + * @param {Selected} selected + */ +function groupEvtProc(canvas, selected) { + // only one shape selected + if (selected.shapes?.length === 1 && !selected.pathEnds?.length) { + classDel(selected.shapes[0], 'highlight'); + shapeSelect(selected.shapes[0]); + return; + } + + // only one pathEnd selected + if (!selected.shapes?.length && selected.pathEnds?.length === 1) { + pathUnhighlight(selected.pathEndsPaths[0]); + return; + } + + // only one path selected + if (!selected.shapes?.length && selected.pathEnds?.length === 2 && selected.pathEndsPaths?.length === 1) { + pathUnhighlight(selected.pathEndsPaths[0]); + shapeSelect(selected.pathEndsPaths[0]); + return; + } + + const svg = canvas.ownerSVGElement; + let isMove = false; + let isDownOnSelectedShape = false; + + /** @type {{del():void}} */ + let settingsPnl; + const pnlDel = () => { settingsPnl?.del(); settingsPnl = null; }; + + /** @param {PointerEvent & {target:Node}} evt */ + function down(evt) { + pnlDel(); + isDownOnSelectedShape = + selected.shapes?.some(shapeEl => shapeEl.contains(evt.target)) || + selected.pathEnds?.some(pathEnd => pathEnd.el.contains(evt.target)); + + // down on not selected shape + if (!isDownOnSelectedShape && evt.target !== svg) { + dispose(); + return; + } + + if (isDownOnSelectedShape) { + evt.stopImmediatePropagation(); + } + + svg.setPointerCapture(evt.pointerId); + listen(svg, 'pointerup', up, true); + listen(svg, 'pointermove', move); + } + + /** @param { {(point:Point):void} } pointMoveFn */ + function drawSelection(pointMoveFn) { + selected.shapes?.forEach(shapeEl => { + pointMoveFn(shapeEl[ShapeSmbl].data.position); + shapeEl[ShapeSmbl].drawPosition(); + }); + selected.pathEnds?.forEach(pathEnd => pointMoveFn(pathEnd.data.position)); + selected.pathEndsPaths?.forEach(path => path[PathSmbl].draw()); + } + + /** @param {PointerEvent} evt */ + function up(evt) { + if (!isMove) { + // click on canvas + if (!isDownOnSelectedShape) { dispose(); return; } + + // click on selected shape - show settings panel + settingsPnl = modalCreate(evt.clientX - 10, evt.clientY - 10, new GroupSettings(cmd => { + switch (cmd) { + case 'del': + arrPop(selected.shapes, shapeEl => shapeEl[ShapeSmbl].del()); + arrPop(selected.pathEndsPaths, pathEl => pathEl[PathSmbl].del()); + dispose(); + break; + case 'copy': { + copyAndPast(canvas, elemsToCopyGet(selected)); // will call dispose + break; + } + } + })); + } else { + // move end + drawSelection(point => placeToCell(point, canvas[CanvasSmbl].data.cell)); + } + + dispose(true); + } + + /** @param {PointerEventFixMovement} evt */ + function move(evt) { + // move canvas + if (!isDownOnSelectedShape) { dispose(true); return; } + + // move selected shapes + isMove = true; + drawSelection(point => movementApplay(point, canvas[CanvasSmbl].data.scale, evt)); + } + + /** @param {boolean=} saveOnDown */ + function dispose(saveOnDown) { + listenDel(svg, 'pointerup', up); + listenDel(svg, 'pointermove', move); + isMove = false; + isDownOnSelectedShape = false; + + if (!saveOnDown) { + canvasSelectionClearSet(canvas, null); + if (listenCopyDispose) { listenCopyDispose(); listenCopyDispose = null; } + + listenDel(svg, 'pointerdown', down, true); + pnlDel(); + arrPop(selected.shapes, shapeEl => classDel(shapeEl, highlightClass)); + arrPop(selected.pathEndsPaths, pathEl => pathUnhighlight(pathEl)); + selected.pathEnds = null; + selected.shapesPaths = null; + } + } + + svg.addEventListener('pointerdown', down, { passive: true, capture: true }); + + canvasSelectionClearSet(canvas, dispose); + let listenCopyDispose = listenCopy(() => elemsToCopyGet(selected)); +} + +/** @param {Selected} selected */ +function elemsToCopyGet(selected) { + /** @type {Set} */ + const fullSelectedPaths = new Set(); + + /** @param {PathEnd} pathEnd */ + const pathEndSelected = pathEnd => + selected.shapes.includes(pathEnd.shape?.shapeEl) || selected.pathEnds.includes(pathEnd); + + /** @param {PathElement} pathEl */ + function fullSelectedPathAdd(pathEl) { + if (pathEndSelected(pathEl[PathSmbl].data.s) && pathEndSelected(pathEl[PathSmbl].data.e)) { + fullSelectedPaths.add(pathEl); + } + } + + selected.shapesPaths?.forEach(fullSelectedPathAdd); + selected.pathEndsPaths?.forEach(fullSelectedPathAdd); + + return [...selected.shapes, ...fullSelectedPaths]; +} + +/** @param {PathElement} pathEl`` */ +function pathUnhighlight(pathEl) { + classDel(pathEl, highlightSClass); + classDel(pathEl, highlightEClass); +} + +/** + * @param {Point} rectPosition + * @param {number} rectWidth, @param {number} rectHeight + * @param {number} x, @param {number} y + */ +const pointInRect = (rectPosition, rectWidth, rectHeight, x, y) => + rectPosition.x <= x && x <= rectPosition.x + rectWidth && + rectPosition.y <= y && y <= rectPosition.y + rectHeight; + +/** + * @typedef { { + * shapes:ShapeElement[] + * shapesPaths:PathElement[] + * pathEnds: PathEnd[] + * pathEndsPaths: PathElement[] + * } } Selected + */ +/** @typedef { {x:number, y:number} } Point */ +/** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */ +/** @typedef { import('../shapes/shape-smbl').ShapeElement } ShapeElement */ +/** @typedef { import('../shapes/shape-evt-proc').Shape } Shape */ +/** @typedef { import('../shapes/path').Path } Path */ +/** @typedef { import('../shapes/path').PathEnd } PathEnd */ +/** @typedef { import('../shapes/path-smbl').PathElement } PathElement */ +/** @typedef { SVGGraphicsElement & { [ShapeSmbl]?: Shape, [PathSmbl]?:Path }} ShapeOrPathElement */ +/** @typedef { import('../infrastructure/move-evt-mobile-fix.js').PointerEventFixMovement} PointerEventFixMovement */ +/** @typedef { import('./dgrm-serialization.js').DiagramSerialized } DiagramSerialized */ diff --git a/main_plugin/dgrm/diagram/group-settings.js b/main_plugin/dgrm/diagram/group-settings.js new file mode 100755 index 0000000..fbe52b3 --- /dev/null +++ b/main_plugin/dgrm/diagram/group-settings.js @@ -0,0 +1,32 @@ +import { copySvg, delSvg } from '../infrastructure/assets.js'; +import { clickForAll, evtTargetAttr } from '../infrastructure/util.js'; + +export class GroupSettings extends HTMLElement { + /** @param {(cms:string)=>void} cmdHandler */ + constructor(cmdHandler) { + super(); + /** @private */ + this._cmdHandler = cmdHandler; + } + + connectedCallback() { + const shadow = this.attachShadow({ mode: 'closed' }); + shadow.innerHTML = ` + +
+ ${copySvg} + ${delSvg} +
`; + + clickForAll(shadow, '[data-cmd]', + evt => this._cmdHandler(evtTargetAttr(evt, 'data-cmd'))); + } +} +customElements.define('ap-grp-settings', GroupSettings); diff --git a/main_plugin/dgrm/index.js b/main_plugin/dgrm/index.js new file mode 100755 index 0000000..d7cd2e6 --- /dev/null +++ b/main_plugin/dgrm/index.js @@ -0,0 +1,52 @@ +/** + * @file index.js + * @brief Основной файл диаграммного редактора, содержит инициализацию канваса, загрузку диаграмм и подключение модулей UI +*/ + +import { moveEvtMobileFix } from './infrastructure/move-evt-mobile-fix.js'; +import { CanvasSmbl } from './infrastructure/canvas-smbl.js'; +import { moveScaleApplay } from './infrastructure/move-scale-applay.js'; +import { evtRouteApplay } from './infrastructure/evt-route-applay.js'; +import { tipShow, uiDisable } from './ui/ui.js'; +import { srvGet } from './diagram/dgrm-srv.js'; +import { deserialize } from './diagram/dgrm-serialization.js'; +import { copyPastApplay, groupSelectApplay } from './diagram/group-select-applay.js'; +import { shapeTypeMap } from './shapes/shape-type-map.js'; +import './ui/menu.js'; +import './ui/shape-menu.js'; + +// @ts-ignore +/** @type {import('./infrastructure/canvas-smbl.js').CanvasElement} */ +/** @brief Элемент канваса */ +const canvas = document.getElementById('canvas'); +/** @brief Данные канваса и отображение фигур */ +canvas[CanvasSmbl] = { + data: { + position: { x: 0, y: 0 }, + scale: 1, + cell: 24 + }, + shapeMap: shapeTypeMap(canvas) +}; + +moveEvtMobileFix(canvas.ownerSVGElement); +evtRouteApplay(canvas.ownerSVGElement); +copyPastApplay(canvas); +groupSelectApplay(canvas); // groupSelectApplay must go before moveScaleApplay +moveScaleApplay(canvas); + +/** @type { import('./ui/menu').Menu } */(document.getElementById('menu')).init(canvas); +/** @type { import('./ui/shape-menu').ShapeMenu } */(document.getElementById('menu-shape')).init(canvas); + +/** @brief Загружает диаграмму по ссылке, если указан параметр k */ +let url = new URL(window.location.href); +if (url.searchParams.get('k')) { + uiDisable(true); + srvGet(url.searchParams.get('k')).then(appData => { + url.searchParams.delete('k'); + if (deserialize(canvas, appData)) { tipShow(false); } + history.replaceState(null, null, url); + uiDisable(false); + url = null; + }); +} else { url = null; } diff --git a/main_plugin/dgrm/index.php b/main_plugin/dgrm/index.php new file mode 100755 index 0000000..6ef3200 --- /dev/null +++ b/main_plugin/dgrm/index.php @@ -0,0 +1,17 @@ + + + +
+
Блок схема
+ + +
+ + + +
\ No newline at end of file diff --git a/main_plugin/dgrm/infrastructure/assets.js b/main_plugin/dgrm/infrastructure/assets.js new file mode 100755 index 0000000..c78e4e2 --- /dev/null +++ b/main_plugin/dgrm/infrastructure/assets.js @@ -0,0 +1,2 @@ +export const delSvg = ''; +export const copySvg = ''; diff --git a/main_plugin/dgrm/infrastructure/canvas-smbl.js b/main_plugin/dgrm/infrastructure/canvas-smbl.js new file mode 100755 index 0000000..979ba26 --- /dev/null +++ b/main_plugin/dgrm/infrastructure/canvas-smbl.js @@ -0,0 +1,15 @@ +export const CanvasSmbl = Symbol('Canvas'); + +/** @typedef { {x:number, y:number} } Point */ +/** @typedef {{position:Point, scale:number, cell: number}} CanvasData */ +/** @typedef {SVGGElement & { [CanvasSmbl]?: Canvas }} CanvasElement */ +/** +@typedef {{ + move?(x:number, y:number, scale:number): void + data: CanvasData + + // TODO: it is not infrastructure methods -> shouldn't be here + selectClear?(): void + shapeMap: Record +}} Canvas +*/ diff --git a/main_plugin/dgrm/infrastructure/evt-route-applay.js b/main_plugin/dgrm/infrastructure/evt-route-applay.js new file mode 100755 index 0000000..2b0bf2c --- /dev/null +++ b/main_plugin/dgrm/infrastructure/evt-route-applay.js @@ -0,0 +1,35 @@ +/** @param {Element} elem */ +export function evtRouteApplay(elem) { + elem.addEventListener('pointerdown', /** @param {RouteEvent} evt */ evt => { + if (!evt.isPrimary || evt[RouteedSmbl] || !evt.isTrusted) { return; } + + evt.stopImmediatePropagation(); + + const newEvt = new PointerEvent('pointerdown', evt); + newEvt[RouteedSmbl] = true; + activeElemFromPoint(evt).dispatchEvent(newEvt); + }, { capture: true, passive: true }); +} + +/** @param { {clientX:number, clientY:number} } evt */ +function activeElemFromPoint(evt) { + return elemFromPointByPrioity(evt).find(el => !el.hasAttribute('data-evt-no')); +} + +/** @param { {clientX:number, clientY:number} } evt */ +export function priorityElemFromPoint(evt) { + return elemFromPointByPrioity(evt)[0]; +} + +/** @param { {clientX:number, clientY:number} } evt */ +function elemFromPointByPrioity(evt) { + return document.elementsFromPoint(evt.clientX, evt.clientY) + .sort((a, b) => { + const ai = a.getAttribute('data-evt-index'); + const bi = b.getAttribute('data-evt-index'); + return (ai === bi) ? 0 : ai > bi ? -1 : 1; + }); +} + +const RouteedSmbl = Symbol('routeed'); +/** @typedef {PointerEvent & { [RouteedSmbl]?: boolean }} RouteEvent */ diff --git a/main_plugin/dgrm/infrastructure/file.js b/main_plugin/dgrm/infrastructure/file.js new file mode 100755 index 0000000..1ddc6d6 --- /dev/null +++ b/main_plugin/dgrm/infrastructure/file.js @@ -0,0 +1,60 @@ +/** + * save file to user + * @param {Blob} blob + * @param {string} name + */ +export function fileSave(blob, name) { ('showSaveFilePicker' in window) ? fileSaveAs(blob) : fileDownload(blob, name); } + +/** + * save file with "File save as" dialog + * @param {Blob} blob + */ +async function fileSaveAs(blob) { + try { + // @ts-ignore + const writable = await (await window.showSaveFilePicker({ + types: [ + { + description: 'PNG Image', + accept: { + 'image/png': ['.png'] + } + } + ] + })).createWritable(); + await writable.write(blob); + await writable.close(); + } catch { + alert('File not saved'); + } +} + +/** + * save file with default download process + * @param {Blob} blob + * @param {string} name + */ +function fileDownload(blob, name) { + const link = document.createElement('a'); + link.download = name; + link.href = URL.createObjectURL(blob); + link.click(); + URL.revokeObjectURL(link.href); + link.remove(); +} + +/** + * @param {string} accept + * @param {BlobCallback} callBack + */ +export function fileOpen(accept, callBack) { + const input = document.createElement('input'); + input.type = 'file'; + input.multiple = false; + input.accept = accept; + input.onchange = async function() { + callBack((!input.files?.length) ? null : input.files[0]); + }; + input.click(); + input.remove(); +} diff --git a/main_plugin/dgrm/infrastructure/move-evt-mobile-fix.js b/main_plugin/dgrm/infrastructure/move-evt-mobile-fix.js new file mode 100755 index 0000000..a21bbff --- /dev/null +++ b/main_plugin/dgrm/infrastructure/move-evt-mobile-fix.js @@ -0,0 +1,50 @@ +import { listenDel } from './util.js'; + +/** @param {Element} elem */ +export function moveEvtMobileFix(elem) { + /** @type {Point} */ let pointDown; + /** @type {number} */ let prevX; + /** @type {number} */ let prevY; + + /** @param {PointerEventFixMovement} evt */ + function move(evt) { + if (!evt.isPrimary || !evt.isTrusted) { return; } + + // fix old Android + if (pointDown && + Math.abs(pointDown.x - evt.clientX) < 3 && + Math.abs(pointDown.y - evt.clientY) < 3) { + evt.stopImmediatePropagation(); + return; + } + pointDown = null; + + // fix iOS + if (evt.movementX === undefined) { + evt[MovementXSmbl] = (prevX ? evt.clientX - prevX : 0); + evt[MovementYSmbl] = (prevY ? evt.clientY - prevY : 0); + prevX = evt.clientX; + prevY = evt.clientY; + } else { + evt[MovementXSmbl] = evt.movementX; + evt[MovementYSmbl] = evt.movementY; + } + } + + elem.addEventListener('pointerdown', /** @param {PointerEvent} evt */ evt => { + pointDown = { x: evt.clientX, y: evt.clientY }; + prevX = null; + prevY = null; + elem.addEventListener('pointermove', move, { capture: true, passive: true }); + + elem.addEventListener('pointerup', _ => { + listenDel(elem, 'pointermove', move, true); + }, { capture: true, once: true, passive: true }); + }, { capture: true, passive: true }); +} + +export const MovementXSmbl = Symbol('movementX'); +export const MovementYSmbl = Symbol('movementY'); +/** @typedef {PointerEvent & { [MovementXSmbl]: number, [MovementYSmbl]: number }} PointerEventFixMovement */ + +/** @typedef { {x:number, y:number} } Point */ diff --git a/main_plugin/dgrm/infrastructure/move-evt-proc.js b/main_plugin/dgrm/infrastructure/move-evt-proc.js new file mode 100755 index 0000000..11059a4 --- /dev/null +++ b/main_plugin/dgrm/infrastructure/move-evt-proc.js @@ -0,0 +1,117 @@ +import { MovementXSmbl, MovementYSmbl } from './move-evt-mobile-fix.js'; +import { listenDel, listen } from './util.js'; + +/** + * @param { Element } elemTrackOutdown poitdows in this element will be tracking to fire {onOutdown} callback + * @param { Element } elem + * @param { {scale:number} } canvasScale + * @param { Point } shapePosition + * @param { {(evt:PointerEvent):void} } onMoveStart + * @param { {(evt:PointerEvent):void} } onMove + * @param { {(evt:PointerEvent):void} } onMoveEnd + * @param { {(evt:PointerEvent):void} } onClick + * @param { {():void} } onOutdown + */ +export function moveEvtProc(elemTrackOutdown, elem, canvasScale, shapePosition, onMoveStart, onMove, onMoveEnd, onClick, onOutdown) { + let isMoved = false; + let isInit = false; + /** @type {Element} */ let target; + + /** @param {PointerEventFixMovement} evt */ + function move(evt) { + if (!isInit) { return; } + + if (!isMoved) { + onMoveStart(evt); + + // if reset + if (!isInit) { return; } + } + + movementApplay(shapePosition, canvasScale.scale, evt); + isMoved = true; + onMove(evt); + } + + /** @param {PointerEvent} evt */ + function cancel(evt) { + if (isMoved) { + onMoveEnd(evt); + } else { + onClick(evt); + } + reset(true); + } + + /** @param {PointerEvent & { target:Node}} docEvt */ + function docDown(docEvt) { + if (!elem.contains(docEvt.target)) { + reset(); + onOutdown(); + } + } + + function wheel() { + reset(); + onOutdown(); + } + + /** + * @param {ProcEvent} evt + */ + function init(evt) { + if (evt[ProcessedSmbl] || !evt.isPrimary) { + return; + } + + evt[ProcessedSmbl] = true; + target = /** @type {Element} */(evt.target); + if (evt.pointerId !== fakePointerId) { target.setPointerCapture(evt.pointerId); } + listen(target, 'pointercancel', cancel, true); + listen(target, 'pointerup', cancel, true); + listen(target, 'pointermove', move); + + listen(elemTrackOutdown, 'wheel', wheel, true); + listen(elemTrackOutdown, 'pointerdown', docDown); + + isInit = true; + } + + listen(elem, 'pointerdown', init); + + /** @param {boolean=} saveOutTrack */ + function reset(saveOutTrack) { + listenDel(target, 'pointercancel', cancel); + listenDel(target, 'pointerup', cancel); + listenDel(target, 'pointermove', move); + if (!saveOutTrack) { + listenDel(elemTrackOutdown, 'pointerdown', docDown); + listenDel(elemTrackOutdown, 'wheel', wheel); + } + target = null; + isMoved = false; + isInit = false; + } + + return reset; +} + +/** @param {Point} point, @param {number} scale, @param {PointerEventFixMovement} evt */ +export function movementApplay(point, scale, evt) { + point.x += evt[MovementXSmbl] / scale; + point.y += evt[MovementYSmbl] / scale; +} + +const fakePointerId = 42; // random number +/** @param {SVGGraphicsElement} shapeOrPathEl */ +export function shapeSelect(shapeOrPathEl) { + shapeOrPathEl.ownerSVGElement.focus(); + shapeOrPathEl.dispatchEvent(new PointerEvent('pointerdown', { isPrimary: true, pointerId: fakePointerId })); + shapeOrPathEl.dispatchEvent(new PointerEvent('pointerup', { isPrimary: true })); +} + +export const ProcessedSmbl = Symbol('processed'); + +/** @typedef {PointerEvent & { [ProcessedSmbl]?: boolean }} ProcEvent */ +/** @typedef {import('./move-evt-mobile-fix.js').PointerEventFixMovement} PointerEventFixMovement */ +/** @typedef { {x:number, y:number} } Point */ diff --git a/main_plugin/dgrm/infrastructure/move-scale-applay.js b/main_plugin/dgrm/infrastructure/move-scale-applay.js new file mode 100755 index 0000000..f56316c --- /dev/null +++ b/main_plugin/dgrm/infrastructure/move-scale-applay.js @@ -0,0 +1,223 @@ +import { CanvasSmbl } from './canvas-smbl.js'; +import { ProcessedSmbl } from './move-evt-proc.js'; +import { listen, listenDel } from './util.js'; + +/** + * Get point in canvas given the scale and position of the canvas + * @param {{position:{x:number, y:number}, scale:number}} canvasData + * @param {number} x, @param {number} y + */ +export const pointInCanvas = (canvasData, x, y) => ({ + x: (x - canvasData.position.x) / canvasData.scale, + y: (y - canvasData.position.y) / canvasData.scale +}); + +/** + * @param {Point} point + * @param {number} cell + */ +export function placeToCell(point, cell) { + const cellSizeHalf = cell / 2; + function placeToCell(coordinate) { + const coor = (Math.round(coordinate / cell) * cell); + return (coordinate - coor > 0) ? coor + cellSizeHalf : coor - cellSizeHalf; + } + + point.x = placeToCell(point.x); + point.y = placeToCell(point.y); +} + +/** @param { CanvasElement } canvas */ +export function moveScaleApplay(canvas) { + const canvasData = canvas[CanvasSmbl].data; + + const gripUpdate = applayGrid(canvas.ownerSVGElement, canvasData); + + function transform() { + canvas.style.transform = `matrix(${canvasData.scale}, 0, 0, ${canvasData.scale}, ${canvasData.position.x}, ${canvasData.position.y})`; + gripUpdate(); + } + + /** + * @param {number} nextScale + * @param {Point} originPoint + */ + function scale(nextScale, originPoint) { + if (nextScale < 0.25 || nextScale > 4) { return; } + + const divis = nextScale / canvasData.scale; + canvasData.scale = nextScale; + + canvasData.position.x = divis * (canvasData.position.x - originPoint.x) + originPoint.x; + canvasData.position.y = divis * (canvasData.position.y - originPoint.y) + originPoint.y; + + transform(); + } + + // move, scale with fingers + applayFingers(canvas.ownerSVGElement, canvasData, scale, transform); + + // scale with mouse wheel + canvas.ownerSVGElement.addEventListener('wheel', /** @param {WheelEvent} evt */ evt => { + evt.preventDefault(); + const delta = evt.deltaY || evt.deltaX; + const scaleStep = Math.abs(delta) < 50 + ? 0.05 // trackpad pitch + : 0.25; // mouse wheel + + scale( + canvasData.scale + (delta < 0 ? scaleStep : -scaleStep), + evtPoint(evt)); + }); + + canvas[CanvasSmbl].move = function (x, y, scale) { + canvasData.position.x = x; + canvasData.position.y = y; + canvasData.scale = scale; + transform(); + }; +} + +/** + * @param { SVGSVGElement } svg + * @param { {position:Point, scale:number} } canvasData + * @param { {(nextScale:number, originPoint:Point):void} } scaleFn + * @param { {():void} } transformFn + * @return + */ +function applayFingers(svg, canvasData, scaleFn, transformFn) { + /** @type { Pointer } */ + let firstPointer; + + /** @type { Pointer} */ + let secondPointer; + + /** @type {number} */ + let distance; + + /** @type {Point} */ + let center; + + /** @param {PointerEvent} evt */ + function cancel(evt) { + distance = null; + center = null; + if (firstPointer?.id === evt.pointerId) { firstPointer = null; } + if (secondPointer?.id === evt.pointerId) { secondPointer = null; } + + if (!firstPointer && !secondPointer) { + listenDel(svg, 'pointermove', move); + listenDel(svg, 'pointercancel', cancel); + listenDel(svg, 'pointerup', cancel); + } + }; + + /** @param {PointerEvent} evt */ + function move(evt) { + if (evt[ProcessedSmbl]) { return; } + + if ((firstPointer && !secondPointer) || (!firstPointer && secondPointer)) { + // move with one pointer + canvasData.position.x = evt.clientX + (firstPointer || secondPointer).shift.x; + canvasData.position.y = evt.clientY + (firstPointer || secondPointer).shift.y; + transformFn(); + return; + } + + if (!secondPointer || !firstPointer || (secondPointer?.id !== evt.pointerId && firstPointer?.id !== evt.pointerId)) { return; } + + const distanceNew = Math.hypot(firstPointer.pos.x - secondPointer.pos.x, firstPointer.pos.y - secondPointer.pos.y); + const centerNew = { + x: (firstPointer.pos.x + secondPointer.pos.x) / 2, + y: (firstPointer.pos.y + secondPointer.pos.y) / 2 + }; + + // not first move + if (distance) { + canvasData.position.x = canvasData.position.x + centerNew.x - center.x; + canvasData.position.y = canvasData.position.y + centerNew.y - center.y; + + scaleFn( + canvasData.scale / distance * distanceNew, + centerNew); + } + + distance = distanceNew; + center = centerNew; + + if (firstPointer.id === evt.pointerId) { firstPointer = evtPointer(evt, canvasData); } + if (secondPointer.id === evt.pointerId) { secondPointer = evtPointer(evt, canvasData); } + } + + listen(svg, 'pointerdown', /** @param {PointerEvent} evt */ evt => { + if (evt[ProcessedSmbl] || (!firstPointer && !evt.isPrimary) || (firstPointer && secondPointer)) { + return; + } + + svg.setPointerCapture(evt.pointerId); + if (!firstPointer) { + listen(svg, 'pointermove', move); + listen(svg, 'pointercancel', cancel); + listen(svg, 'pointerup', cancel); + } + + if (!firstPointer) { firstPointer = evtPointer(evt, canvasData); return; } + if (!secondPointer) { secondPointer = evtPointer(evt, canvasData); } + }); +} + +/** + * @param { SVGSVGElement } svg + * @param { import('./canvas-smbl.js').CanvasData } canvasData + */ +function applayGrid(svg, canvasData) { + let curOpacity; + /** @param {number} opacity */ + function backImg(opacity) { + if (curOpacity !== opacity) { + curOpacity = opacity; + svg.style.backgroundImage = `radial-gradient(rgb(73 80 87 / ${opacity}) 1px, transparent 0)`; + } + } + + backImg(0.7); + svg.style.backgroundSize = `${canvasData.cell}px ${canvasData.cell}px`; + + return function() { + const size = canvasData.cell * canvasData.scale; + + if (canvasData.scale < 0.5) { backImg(0); } else + if (canvasData.scale <= 0.9) { backImg(0.3); } else { backImg(0.7); } + + svg.style.backgroundSize = `${size}px ${size}px`; + svg.style.backgroundPosition = `${canvasData.position.x}px ${canvasData.position.y}px`; + }; +} + +/** + * @param {PointerEvent | MouseEvent} evt + * @return {Point} + */ +function evtPoint(evt) { return { x: evt.clientX, y: evt.clientY }; } + +/** + * @param { PointerEvent } evt + * @param { {position:Point, scale:number} } canvasData + * @return { Pointer } + */ +function evtPointer(evt, canvasData) { + return { + id: evt.pointerId, + pos: evtPoint(evt), + shift: { + x: canvasData.position.x - evt.clientX, + y: canvasData.position.y - evt.clientY + } + }; +} + +/** @typedef { {x:number, y:number} } Point */ +/** @typedef { {id:number, pos:Point, shift:Point} } Pointer */ +/** @typedef { import("./move-evt-proc").ProcEvent } DgrmEvent */ +/** @typedef { import('./canvas-smbl.js').CanvasData } CanvasData */ +/** @typedef { import('./canvas-smbl.js').CanvasElement } CanvasElement */ diff --git a/main_plugin/dgrm/infrastructure/png-chunk.js b/main_plugin/dgrm/infrastructure/png-chunk.js new file mode 100755 index 0000000..e2a7bef --- /dev/null +++ b/main_plugin/dgrm/infrastructure/png-chunk.js @@ -0,0 +1,93 @@ +/** + * @param {Blob} png + * @param {string} chunkName 4 symbol string + * @returns {Promise} chunk data + */ +export async function pngChunkGet(png, chunkName) { + return chunkGet( + await png.arrayBuffer(), + toUit32(chunkName)); +} + +/** + * @param {Blob} png + * @param {string} chunkName 4 symbol string + * @param {Uint8Array} data + * @returns {Promise} new png + */ +export async function pngChunkSet(png, chunkName, data) { + return chunkSet( + await png.arrayBuffer(), + toUit32(chunkName), + data + ); +} + +/** + * @param {ArrayBuffer} pngData + * @param {number} chunkNameUint32 chunk name as Uint32 + * @param {Uint8Array} data + * @returns {Blob} new png + */ +function chunkSet(pngData, chunkNameUint32, data) { + /** @type {DataView} */ + let startPart; + /** @type {DataView} */ + let endPart; + + const existingChunk = chunkGet(pngData, chunkNameUint32); + if (existingChunk) { + startPart = new DataView(pngData, 0, existingChunk.byteOffset - 8); + endPart = new DataView(pngData, existingChunk.byteOffset + existingChunk.byteLength + 4); + } else { + const endChunkStart = pngData.byteLength - 12; // 12 - end chunk length + startPart = new DataView(pngData, 0, endChunkStart); + endPart = new DataView(pngData, endChunkStart); + } + + const chunkHeader = new DataView(new ArrayBuffer(8)); + chunkHeader.setUint32(0, data.length); + chunkHeader.setUint32(4, chunkNameUint32); + + return new Blob([ + startPart, + + // new chunk + chunkHeader, + data, + new Uint32Array([0]), // CRC fake - not calculated + + endPart + ], + { type: 'image/png' }); +} + +/** + * @param {ArrayBuffer} pngData + * @param {number} chunkNameUint32 chunk name as Uint32 + * @returns {DataView | null} chunk data + */ +function chunkGet(pngData, chunkNameUint32) { + const dataView = new DataView(pngData, 8); // 8 byte - png signature + + let chunkPosition = 0; + let chunkUint = dataView.getUint32(4); + let chunkLenght; + while (chunkUint !== 1229278788) { // last chunk 'IEND' + chunkLenght = dataView.getUint32(chunkPosition); + if (chunkUint === chunkNameUint32) { + return new DataView(pngData, chunkPosition + 16, chunkLenght); + } + chunkPosition = chunkPosition + 12 + chunkLenght; + chunkUint = dataView.getUint32(chunkPosition + 4); + } + return null; +} + +/** + * @param {string} chunkName 4 symbol string + * @return {number} uit32 + */ +function toUit32(chunkName) { + return new DataView((new TextEncoder()).encode(chunkName).buffer).getUint32(0); +} diff --git a/main_plugin/dgrm/infrastructure/svg-text-area.js b/main_plugin/dgrm/infrastructure/svg-text-area.js new file mode 100755 index 0000000..e636e5e --- /dev/null +++ b/main_plugin/dgrm/infrastructure/svg-text-area.js @@ -0,0 +1,70 @@ +import { svgTextDraw } from './svg-text-draw.js'; +import { svgEl } from './util.js'; + +/** + * Create teaxtArea above SVGTextElement 'textEl' + * update 'textEl' with text from teaxtArea + * resize teaxtArea - so teaxtArea always cover all 'textEl' + * @param {SVGTextElement} textEl + * @param {number} verticalMiddle em + * @param {string} val + * @param {{(val:string):void}} onchange + * @param {{(val:string):void}} onblur + */ +export function textareaCreate(textEl, verticalMiddle, val, onchange, onblur) { + let foreign = svgEl('foreignObject'); + const textarea = document.createElement('textarea'); + const draw = () => foreignWidthSet(textEl, foreign, textarea, textareaPaddingAndBorder, textareaStyle.textAlign); + + textarea.value = val || ''; + textarea.oninput = function() { + svgTextDraw(textEl, verticalMiddle, textarea.value); + onchange(textarea.value); + draw(); + }; + textarea.onblur = function() { + onblur(textarea.value); + }; + textarea.onpointerdown = function(evt) { + evt.stopImmediatePropagation(); + }; + + foreign.appendChild(textarea); + textEl.parentElement.appendChild(foreign); + + const textareaStyle = getComputedStyle(textarea); + // must be in px + const textareaPaddingAndBorder = parseInt(textareaStyle.paddingLeft) + parseInt(textareaStyle.borderWidth); + draw(); + + textarea.focus(); + + return { + dispose: () => { foreign.remove(); foreign = null; }, + draw + }; +} + +/** + * @param {SVGTextElement} textEl + * @param {SVGForeignObjectElement} foreign + * @param {HTMLTextAreaElement} textarea + * @param {number} textareaPaddingAndBorder + * @param {string} textAlign + */ +function foreignWidthSet(textEl, foreign, textarea, textareaPaddingAndBorder, textAlign) { + const textBbox = textEl.getBBox(); + const width = textBbox.width + 20; // +20 paddings for iPhone + + foreign.width.baseVal.value = width + 2 * textareaPaddingAndBorder + 2; // +2 magic number for FireFox + foreign.x.baseVal.value = textBbox.x - textareaPaddingAndBorder - ( + textAlign === 'center' + ? 10 + : textAlign === 'right' ? 20 : 0); + + foreign.height.baseVal.value = textBbox.height + 2 * textareaPaddingAndBorder + 3; // +3 magic number for FireFox + foreign.y.baseVal.value = textBbox.y - textareaPaddingAndBorder; + + textarea.style.width = `${width}px`; + textarea.style.height = `${textBbox.height}px`; +} diff --git a/main_plugin/dgrm/infrastructure/svg-text-draw.js b/main_plugin/dgrm/infrastructure/svg-text-draw.js new file mode 100755 index 0000000..9851efb --- /dev/null +++ b/main_plugin/dgrm/infrastructure/svg-text-draw.js @@ -0,0 +1,43 @@ +/** + * @param {SVGTextElement} textEl target text element + * @param {number} verticalMiddle + * @param {string} str + * @returns {void} + */ +export function svgTextDraw(textEl, verticalMiddle, str) { + const strData = svgStrToTspan( + (str || ''), + textEl.x?.baseVal[0]?.value ?? 0); + + textEl.innerHTML = strData.s; + + textEl.y.baseVal[0].newValueSpecifiedUnits( + textEl.y.baseVal[0].SVG_LENGTHTYPE_EMS, // em + strData.c > 0 ? verticalMiddle - (strData.c) / 2 : verticalMiddle); +} + +/** + * create multiline tspan markup + * @param {string} str + * @param {number} x + * @returns { {s:string, c:number} } + */ +function svgStrToTspan(str, x) { + let c = 0; + return { + s: str.split('\n') + .map((t, i) => { + c = i; + return `${t.length === 0 ? '.' : escapeHtml(t).replaceAll(' ', ' ')}`; + }).join(''), + c + }; +} + +/** + * @param {string} str + * @returns {string} + */ +function escapeHtml(str) { + return str.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", '''); +} diff --git a/main_plugin/dgrm/infrastructure/svg-to-png.js b/main_plugin/dgrm/infrastructure/svg-to-png.js new file mode 100755 index 0000000..f72b320 --- /dev/null +++ b/main_plugin/dgrm/infrastructure/svg-to-png.js @@ -0,0 +1,93 @@ +// src/infrastructure/svg-to-png.js +/** + * @param {SVGElement} svg - виртуальный SVG (готовый для рендеринга) + * @param {{x:number,y:number,width:number,height:number}} rect - область в единицах SVG user units + * @param {number} scale - множитель (вызов передаёт, например, 3) + * @param {(blob:Blob|null)=>void} callBack + */ +export function svgToPng(svg, rect, scale, callBack) { + if (!svg || !rect || rect.width <= 0 || rect.height <= 0) { + callBack(null); + return; + } + + // output размеры с учётом devicePixelRatio + const dpr = window.devicePixelRatio || 1; + const outputWidth = Math.round(rect.width * scale * dpr); + const outputHeight = Math.round(rect.height * scale * dpr); + + // Сериализуем svg в строку и делаем blob/url + let svgString; + try { + svgString = new XMLSerializer().serializeToString(svg); + } catch (e) { + callBack(null); + return; + } + + let url; + try { + url = URL.createObjectURL(new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' })); + } catch (e) { + callBack(null); + return; + } + + const img = new Image(); + // crossOrigin можно добавить, если нужно: img.crossOrigin = 'anonymous'; + img.onload = function () { + try { + const canvas = document.createElement('canvas'); + canvas.width = outputWidth; + canvas.height = outputHeight; + canvas.style.width = `${outputWidth}px`; + canvas.style.height = `${outputHeight}px`; + + const ctx = canvas.getContext('2d'); + if (!ctx) { + URL.revokeObjectURL(url); + callBack(null); + return; + } + ctx.imageSmoothingEnabled = false; + + // Если rect.x/rect.y отрицательные => смещение исходного изображения внутри canvas + const sx = Math.max(0, rect.x * scale * dpr); + const sy = Math.max(0, rect.y * scale * dpr); + const sWidth = rect.width * scale * dpr; + const sHeight = rect.height * scale * dpr; + + // dx/dy: смещение на canvas (если rect.x < 0, то мы сдвигаем вправо) + const dx = rect.x < 0 ? -rect.x * scale * dpr : 0; + const dy = rect.y < 0 ? -rect.y * scale * dpr : 0; + + // drawImage с указанием исходной области и целевой области + ctx.drawImage( + img, + sx, // sx + sy, // sy + sWidth, // sWidth + sHeight, // sHeight + dx, // dx (на canvas) + dy, // dy + outputWidth, // dWidth + outputHeight // dHeight + ); + + URL.revokeObjectURL(url); + canvas.toBlob(blob => { + callBack(blob); + }, 'image/png'); + } catch (err) { + URL.revokeObjectURL(url); + callBack(null); + } + }; + + img.onerror = function () { + try { URL.revokeObjectURL(url); } catch (e) {} + callBack(null); + }; + + img.src = url; +} diff --git a/main_plugin/dgrm/infrastructure/util.js b/main_plugin/dgrm/infrastructure/util.js new file mode 100755 index 0000000..df90c8b --- /dev/null +++ b/main_plugin/dgrm/infrastructure/util.js @@ -0,0 +1,146 @@ +// +// dom utils + +/** + * @template T + * @param {Element} parent + * @param {string} key + * @returns T + */ +export const child = (parent, key) => /** @type {T} */(parent.querySelector(`[data-key="${key}"]`)); + +/** @param {HTMLElement|SVGElement} crcl, @param {Point} pos */ +export function positionSet(crcl, pos) { crcl.style.transform = `translate(${pos.x}px, ${pos.y}px)`; } + +/** @param {Element} el, @param {string[]} cl */ +export const classAdd = (el, ...cl) => el?.classList.add(...cl); + +/** @param {Element} el, @param {string} cl */ +export const classDel = (el, cl) => el?.classList.remove(cl); + +/** @param {Element} el, @param {string} cl */ +export const classHas = (el, cl) => el?.classList.contains(cl); + +/** @param {Element} shapeEl, @param {{styles?:string[]}} shapeData, @param {string} classPrefix, @param {string} classToAdd */ +export function classSingleAdd(shapeEl, shapeData, classPrefix, classToAdd) { + if (!shapeData.styles) { shapeData.styles = []; } + + const currentClass = shapeData.styles.findIndex(ss => ss.startsWith(classPrefix)); + if (currentClass > -1) { + classDel(shapeEl, shapeData.styles[currentClass]); + shapeData.styles.splice(currentClass, 1); + } + shapeData.styles.push(classToAdd); + classAdd(shapeEl, classToAdd); +} + +/** @param {Element | GlobalEventHandlers} el, @param {string} type, @param {EventListenerOrEventListenerObject} listener, @param {boolean?=} once */ +export const listen = (el, type, listener, once) => { + if (el) el.addEventListener(type, listener, { passive: true, once }); +}; + +/** @param {Element | GlobalEventHandlers} el, @param {string} type, @param {EventListenerOrEventListenerObject} listener, @param {boolean?=} capture */ +export const listenDel = (el, type, listener, capture) => el?.removeEventListener(type, listener, { capture }); + +/** @param {ParentNode} el, @param {string} selector, @param {(this: GlobalEventHandlers, ev: PointerEvent & { currentTarget: Element }) => any} handler */ +export function clickForAll(el, selector, handler) { el.querySelectorAll(selector).forEach(/** @param {HTMLElement} el */ el => { el.onclick = handler; }); } + +/** @param {PointerEvent & { currentTarget: Element }} evt, @param {string} attr */ +export const evtTargetAttr = (evt, attr) => evt.currentTarget.getAttribute(attr); + +/** + * @template {keyof SVGElementTagNameMap} T + * @param {T} qualifiedName + * @param {string?=} innerHTML + * @returns {SVGElementTagNameMap[T]} + */ +export function svgEl(qualifiedName, innerHTML) { + const svgGrp = document.createElementNS('http://www.w3.org/2000/svg', qualifiedName); + if (innerHTML) { svgGrp.innerHTML = innerHTML; } + return svgGrp; +} + +/** + * calc farthest point of s bbox in {textEl} + * origin is in the center + * @param {SVGTextElement} textEl + */ +export function svgTxtFarthestPoint(textEl) { + /** @type {Point} */ + let maxPoint; + let maxAbsSum = 0; + for (const span of textEl.getElementsByTagName('tspan')) { + for (const point of boxPoints(span.getBBox())) { + const pointAbsSum = Math.abs(point.x) + Math.abs(point.y); + if (maxAbsSum < pointAbsSum) { + maxPoint = point; + maxAbsSum = pointAbsSum; + } + } + } + return maxPoint; +} + +/** @param {DOMRect} box */ +const boxPoints = (box) => [ + { x: box.x, y: box.y }, + { x: box.right, y: box.y }, + { x: box.x, y: box.bottom }, + { x: box.right, y: box.bottom } +]; + +// +// math, arr utils + +/** + * Get the ceiling for a number {val} with a given floor height {step} + * @param {number} min + * @param {number} step + * @param {number} val + */ +export function ceil(min, step, val) { + if (val <= min) { return min; } + return min + Math.ceil((val - min) / step) * step; +} + +/** + * @template T + * @param {Array} arr + * @param {{(el:T):void}} action + */ +export function arrPop(arr, action) { + let itm = arr.pop(); + while (itm) { action(itm); itm = arr.pop(); }; +} + +/** + * @template T + * @param {Array} arr + * @param {T} el + */ +export function arrDel(arr, el) { + const index = arr.indexOf(el); + if (index > -1) { + arr.splice(index, 1); + } +} + +/** @param {Point} point, @param {Point} shift, @param {number=} coef */ +export function pointShift(point, shift, coef) { + const _coef = coef ?? 1; + point.x += _coef * shift.x; + point.y += _coef * shift.y; + return point; +} + +// +// object utils + +/** + * @template T + * @param {T} obj + * @returns {T} + */ +export const deepCopy = obj => JSON.parse(JSON.stringify(obj)); + +/** @typedef { {x:number, y:number} } Point */ diff --git a/main_plugin/dgrm/plug.php b/main_plugin/dgrm/plug.php new file mode 100755 index 0000000..4180670 --- /dev/null +++ b/main_plugin/dgrm/plug.php @@ -0,0 +1,25 @@ + +document.addEventListener('DOMContentLoaded', () => { + const c = document.querySelector('.center-float'); + const d = document.getElementById('dgrmDiv'); + if (c && d) { + c.appendChild(document.createElement('br')); + c.appendChild(d); + import('/main_plugin/dgrm/index.js'); + } else if (d) { + d.remove(); + } +}); +"; +echo ''; +} +?> diff --git a/main_plugin/dgrm/shapes/circle.js b/main_plugin/dgrm/shapes/circle.js new file mode 100755 index 0000000..1a87e99 --- /dev/null +++ b/main_plugin/dgrm/shapes/circle.js @@ -0,0 +1,69 @@ +import { ceil, child, positionSet, svgTxtFarthestPoint } from '../infrastructure/util.js'; +import { shapeCreate } from './shape-evt-proc.js'; + +/** + * @param {CanvasElement} canvas + * @param {CircleData} circleData + */ +export function circle(canvas, circleData) { + const templ = ` + + +  `; + + const shape = shapeCreate(canvas, circleData, templ, + { + right: { dir: 'right', position: { x: 48, y: 0 } }, + left: { dir: 'left', position: { x: -48, y: 0 } }, + bottom: { dir: 'bottom', position: { x: 0, y: 48 } }, + top: { dir: 'top', position: { x: 0, y: -48 } } + }, + // onTextChange + txtEl => { + const newRadius = textElRadius(txtEl, 48, 24); + if (newRadius !== circleData.r) { + circleData.r = newRadius; + resize(); + } + }); + + function resize() { + shape.cons.right.position.x = circleData.r; + shape.cons.left.position.x = -circleData.r; + shape.cons.bottom.position.y = circleData.r; + shape.cons.top.position.y = -circleData.r; + + for (const connectorKey in shape.cons) { + positionSet(child(shape.el, connectorKey), shape.cons[connectorKey].position); + } + + radiusSet(shape.el, 'outer', circleData.r + 24); + radiusSet(shape.el, 'main', circleData.r); + shape.draw(); + } + + if (!!circleData.r && circleData.r !== 48) { resize(); } else { shape.draw(); } + + return shape.el; +} + +/** @param {Element} svgGrp, @param {string} key, @param {number} r */ +function radiusSet(svgGrp, key, r) { /** @type {SVGCircleElement} */(child(svgGrp, key)).r.baseVal.value = r; } + +/** + * calc radius that cover all in SVGTextElement + * origin is in the center of the circle + * @param {SVGTextElement} textEl + * @param {*} minR + * @param {*} step + */ +function textElRadius(textEl, minR, step) { + const farthestPoint = svgTxtFarthestPoint(textEl); + return ceil(minR, step, Math.sqrt(farthestPoint.x ** 2 + farthestPoint.y ** 2)); +} + +/** @typedef { {x:number, y:number} } Point */ +/** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */ +/** @typedef { import('./shape-evt-proc').CanvasData } CanvasData */ +/** @typedef { import('./shape-evt-proc').ConnectorsData } ConnectorsData */ +/** @typedef { {type:number, position: Point, title?: string, styles?: string[], r?:number} } CircleData */ diff --git a/main_plugin/dgrm/shapes/modal-create.js b/main_plugin/dgrm/shapes/modal-create.js new file mode 100755 index 0000000..044e6e6 --- /dev/null +++ b/main_plugin/dgrm/shapes/modal-create.js @@ -0,0 +1,27 @@ +/** @type {HTMLDivElement} */ +let editModalDiv; + +/** @param {number} bottomX, @param {number} bottomY, @param {HTMLElement} elem */ +export function modalCreate(bottomX, bottomY, elem) { + editModalDiv = document.createElement('div'); + editModalDiv.style.cssText = 'position: fixed; box-shadow: 0px 0px 58px 2px rgb(34 60 80 / 20%); border-radius: 16px; background-color: rgba(255,255,255, .9);'; + editModalDiv.append(elem); + document.body.append(editModalDiv); + + function position(btmX, btmY) { + editModalDiv.style.left = `${btmX}px`; + editModalDiv.style.top = `${btmY - 35}px`; + } + + position(bottomX, bottomY); + + return { + position, + del: () => { editModalDiv.remove(); editModalDiv = null; } + }; +} + +/** @param {number} dif */ +export function modalChangeTop(dif) { + editModalDiv.style.top = `${editModalDiv.getBoundingClientRect().top - 90}px`; +} diff --git a/main_plugin/dgrm/shapes/path-settings.js b/main_plugin/dgrm/shapes/path-settings.js new file mode 100755 index 0000000..68ba234 --- /dev/null +++ b/main_plugin/dgrm/shapes/path-settings.js @@ -0,0 +1,75 @@ +import { copyAndPast } from '../diagram/group-select-applay.js'; +import { classAdd, classDel, clickForAll, listen, classSingleAdd, evtTargetAttr } from '../infrastructure/util.js'; +import { PathSmbl } from './path-smbl.js'; + +export class PathSettings extends HTMLElement { + /** + * @param {CanvasElement} canvas + * @param {PathElement} pathElement + */ + constructor(canvas, pathElement) { + super(); + /** @private */ + this._pathElement = pathElement; + + /** @private */ + this._canvas = canvas; + } + + connectedCallback() { + const pathStyles = this._pathElement[PathSmbl].data.styles; + const actStyle = style => this._pathElement[PathSmbl].data.styles?.includes(style) ? 'class="actv"' : ''; + + const shadow = this.attachShadow({ mode: 'closed' }); + shadow.innerHTML = ` + + +
+ + + +
+
`; + + // colors, del + listen(shadow.getElementById('edit'), 'cmd', /** @param {CustomEvent<{cmd:string, arg:string}>} evt */ evt => { + switch (evt.detail.cmd) { + case 'style': classSingleAdd(this._pathElement, this._pathElement[PathSmbl].data, 'cl-', evt.detail.arg); break; + case 'del': this._pathElement[PathSmbl].del(); break; + case 'copy': copyAndPast(this._canvas, [this._pathElement]); break; + } + }); + + // arrows, dotted + clickForAll(shadow, '[data-cmd]', evt => { + const argStyle = evtTargetAttr(evt, 'data-cmd-arg'); + const currentArr = pathStyles.indexOf(argStyle); + if (currentArr > -1) { + classDel(this._pathElement, argStyle); + pathStyles.splice(currentArr, 1); + classDel(evt.currentTarget, 'actv'); + } else { + classAdd(this._pathElement, argStyle); + pathStyles.push(argStyle); + classAdd(evt.currentTarget, 'actv'); + } + }); + } +} +customElements.define('ap-path-settings', PathSettings); + +/** @typedef { import('./path-smbl').PathElement } PathElement */ +/** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */ diff --git a/main_plugin/dgrm/shapes/path-smbl.js b/main_plugin/dgrm/shapes/path-smbl.js new file mode 100755 index 0000000..00232d1 --- /dev/null +++ b/main_plugin/dgrm/shapes/path-smbl.js @@ -0,0 +1,2 @@ +export const PathSmbl = Symbol('path'); +/** @typedef {SVGGraphicsElement & { [PathSmbl]?: import("./path").Path }} PathElement */ diff --git a/main_plugin/dgrm/shapes/path.js b/main_plugin/dgrm/shapes/path.js new file mode 100755 index 0000000..396b070 --- /dev/null +++ b/main_plugin/dgrm/shapes/path.js @@ -0,0 +1,402 @@ +import { child, classAdd, classDel, classHas, listen, listenDel, svgEl } from '../infrastructure/util.js'; +import { moveEvtProc, movementApplay } from '../infrastructure/move-evt-proc.js'; +import { placeToCell, pointInCanvas } from '../infrastructure/move-scale-applay.js'; +import { priorityElemFromPoint } from '../infrastructure/evt-route-applay.js'; +import { ShapeSmbl } from './shape-smbl.js'; +import { PathSettings } from './path-settings.js'; +import { PathSmbl } from './path-smbl.js'; +import { CanvasSmbl } from '../infrastructure/canvas-smbl.js'; +import { modalCreate } from './modal-create.js'; +import { canvasSelectionClearSet } from '../diagram/canvas-clear.js'; +import { listenCopy } from '../diagram/group-select-applay.js'; + +/** + * @param {CanvasElement} canvas + * @param {PathData} pathData + */ +export function path(canvas, pathData) { + + /** @type {PathElement} */ + const svgGrp = svgEl('g', ` + + + + + + + + + + + `); + classAdd(svgGrp, 'shpath'); + + pathData.s.el = child(svgGrp, 'start'); + pathData.e.el = child(svgGrp, 'end'); + pathData.styles = pathData.styles ?? ['arw-e']; + const paths = childs(svgGrp, 'path', 'outer', 'selected'); + +function draw() { + const endDir = dirByAngle(pathData.s.data.position, pathData.e.data.position); + pathData.e.data.dir = endDir; + pathData.s.data.dir = dirReverse(endDir); + + const dAttr = pathCalc(pathData); + paths.forEach(pp => pp.setAttribute('d', dAttr)); + + endDraw(pathData.s); + endDraw(pathData.e); +} + + + /** @param {PathEnd} pathEnd */ + function pathDelFromShape(pathEnd) { shapeObj(pathEnd.shape)?.pathDel(svgGrp); } + + /** @param {PathEnd} pathEnd */ + function pathAddToShape(pathEnd) { + if (pathEnd.shape) { + pathEnd.data = shapeObj(pathEnd.shape).pathAdd(pathEnd.shape.connectorKey, svgGrp); + } + }; + + /** @type { {position:(bottomX:number, bottomY:number)=>void, del:()=>void} } */ + let settingsPnl; + function del() { + unSelect(); + reset(); + pathDelFromShape(pathData.s); + pathDelFromShape(pathData.e); + svgGrp.remove(); + } + + /** + * @type {0|1|2} + * 0 - init, 1 - selected, 2 - edit + */ + let state = 0; + + /** @type {()=>void} */ + let listenCopyDispose; + + /** @param {PointerEvent} evt */ + function select(evt) { + // in edit mode + if (state === 2) { return; } + + // to edit mode + if (state === 1) { + state = 2; + settingsPnl = modalCreate(evt.clientX - 10, evt.clientY - 10, new PathSettings(canvas, svgGrp)); + return; + } + + // to select mode + state = 1; + classAdd(svgGrp, 'select'); + endSetEvtIndex(pathData.s, 2); + endSetEvtIndex(pathData.e, 2); + + canvasSelectionClearSet(canvas, unSelect); + listenCopyDispose = listenCopy(() => [svgGrp]); + }; + + /** @type { {():void} } */ + let hoverEmulateDispose; + function unSelect() { + state = 0; + classDel(svgGrp, 'select'); + endSetEvtIndex(pathData.s, 1); + endSetEvtIndex(pathData.e, 1); + + settingsPnl?.del(); settingsPnl = null; + + if (hoverEmulateDispose) { + hoverEmulateDispose(); + hoverEmulateDispose = null; + svgGrp.style.pointerEvents = 'unset'; + } + + canvasSelectionClearSet(canvas, null); + if (listenCopyDispose) { listenCopyDispose(); listenCopyDispose = null; } + }; + + /** @type {'s'|'e'} */ + let movedEnd; + + const reset = moveEvtProc( + canvas.ownerSVGElement, + svgGrp, + canvas[CanvasSmbl].data, + // data.end.position, + { + get x() { return pathData[movedEnd]?.data.position.x; }, + set x(val) { if (movedEnd) { pathData[movedEnd].data.position.x = val; } }, + + get y() { return pathData[movedEnd]?.data.position.y; }, + set y(val) { if (movedEnd) { pathData[movedEnd].data.position.y = val; } } + }, + // onMoveStart + /** @param {PointerEvent & { target: Element} } evt */ evt => { + unSelect(); + + movedEnd = pathData.e.el.contains(evt.target) ? 'e' : pathData.s.el.contains(evt.target) ? 's' : null; + + // + // move whole path + if (!movedEnd) { + return; + } + + // + // move path end + + // disconnect from shape + if (pathData[movedEnd].shape) { + if (pathData[movedEnd].shape.shapeEl !== pathData[movedEnd === 's' ? 'e' : 's'].shape?.shapeEl) { + pathDelFromShape(pathData[movedEnd]); + } + pathData[movedEnd].shape = null; + pathData[movedEnd].data = { + dir: pathData[movedEnd].data.dir, + position: pointInCanvas(canvas[CanvasSmbl].data, evt.clientX, evt.clientY) + }; + } + + // hover emulation - start + svgGrp.style.pointerEvents = 'none'; + hoverEmulateDispose = hoverEmulate(svgGrp.parentElement); + }, + // onMove +/** @param {PointerEventFixMovement} evt */ +evt => { + if (!movedEnd) { + moveWholePath(canvas[CanvasSmbl].data, pathData, draw, evt); + } else { + const diagram = document.getElementById('diagram'); + const rect = diagram.getBoundingClientRect(); + pathData[movedEnd].data.position = { + x: evt.clientX - rect.left, + y: evt.clientY - rect.top + }; + draw(); + } +}, + // onMoveEnd + evt => { + if (!movedEnd) { + moveWholePathFinish(canvas[CanvasSmbl].data, pathData, draw); + } else { + // connect to shape + const elemFromPoint = priorityElemFromPoint(evt); + const connectorKey = elemFromPoint?.getAttribute('data-connect'); + if (connectorKey) { + // @ts-ignore + pathData[movedEnd].shape = { shapeEl: elemFromPoint.parentElement, connectorKey }; + pathAddToShape(pathData[movedEnd]); + } else { + placeToCell(pathData[movedEnd].data.position, canvas[CanvasSmbl].data.cell); + } + draw(); + } + + // hover emulation - end + unSelect(); + }, + // onClick + select, + // onOutdown + unSelect + ); + + svgGrp[PathSmbl] = { + draw, + /** @param {PointerEventInit} evt */ + pointerCapture: evt => pathData.e.el.dispatchEvent(new PointerEvent('pointerdown', evt)), + del, + data: pathData + }; + + if (pathData.styles) { classAdd(svgGrp, ...pathData.styles); } + pathAddToShape(pathData.s); + pathAddToShape(pathData.e); + draw(); + + return svgGrp; +} + +/** + * @param {{scale:number}} canvasData + * @param {PathData} pathData + * @param {{():void}} draw + * @param {PointerEventFixMovement} evt + */ +function moveWholePath(canvasData, pathData, draw, evt) { + /** @param {Point} point */ + const move = point => movementApplay(point, canvasData.scale, evt); + moveShapeOrEnd(pathData.s, move); + moveShapeOrEnd(pathData.e, move); + + // if any shape connected - shape will draw connected path + if (!pathData.s.shape && !pathData.e.shape) { draw(); } +} + +/** + * @param {{cell:number}} canvasData + * @param {PathData} pathData + * @param {{():void}} draw + */ +function moveWholePathFinish(canvasData, pathData, draw) { + /** @param {Point} point */ + const toCell = point => placeToCell(point, canvasData.cell); + moveShapeOrEnd(pathData.s, toCell); + moveShapeOrEnd(pathData.e, toCell); + + if (!pathData.s.shape || !pathData.e.shape) { draw(); } +} + +/** + * applay moveFn to connected shape or to path end point + * @param {PathEnd} pathEnd, @param {{(point:Point):void}} moveFn */ +function moveShapeOrEnd(pathEnd, moveFn) { + if (pathEnd.shape) { + moveFn(shapeObj(pathEnd.shape).data.position); + shapeObj(pathEnd.shape).drawPosition(); + } else { + moveFn(pathEnd.data.position); + } +} + +/** @param {PathConnectedShape} pathConnectedShape */ +const shapeObj = pathConnectedShape => pathConnectedShape?.shapeEl[ShapeSmbl]; + +/** @param {PathEnd} pathEnd */ +function endDraw(pathEnd) { + pathEnd.el.style.transform = `translate(${pathEnd.data.position.x}px, ${pathEnd.data.position.y}px) rotate(${arrowAngle(pathEnd.data.dir)}deg)`; +} + +/** @param {PathEnd} pathEnd, @param {number} index */ +function endSetEvtIndex(pathEnd, index) { pathEnd.el.firstElementChild.setAttribute('data-evt-index', index.toString()); } + +/** @param {Dir} dir */ +const arrowAngle = dir => dir === 'right' + ? 180 + : dir === 'left' + ? 0 + : dir === 'bottom' + ? 270 + : 90; + +/** @param {Dir} dir, @return {Dir} */ +export const dirReverse = dir => dir === 'left' + ? 'right' + : dir === 'right' + ? 'left' + : dir === 'top' ? 'bottom' : 'top'; + +/** @param {Point} s, @param {Point} e, @return {Dir} */ +function dirByAngle(s, e) { + const rad = Math.atan2(e.y - s.y, e.x - s.x); + return numInRangeIncludeEnds(rad, -0.8, 0.8) + ? 'left' + : numInRangeIncludeEnds(rad, 0.8, 2.4) + ? 'top' + : numInRangeIncludeEnds(rad, 2.4, 3.2) || numInRangeIncludeEnds(rad, -3.2, -2.4) ? 'right' : 'bottom'; +} + +/** @param {PathData} data */ +function pathCalc(data) { + let coef = Math.hypot( + data.s.data.position.x - data.e.data.position.x, + data.s.data.position.y - data.e.data.position.y) * 0.5; + coef = coef > 70 + ? 70 + : coef < 15 ? 15 : coef; + + /** @param {PathEndData} pathEnd */ + function cx(pathEnd) { + return (pathEnd.dir === 'right' || pathEnd.dir === 'left') + ? pathEnd.dir === 'right' ? pathEnd.position.x + coef : pathEnd.position.x - coef + : pathEnd.position.x; + } + + /** @param {PathEndData} pathEnd */ + function cy(pathEnd) { + return (pathEnd.dir === 'right' || pathEnd.dir === 'left') + ? pathEnd.position.y + : pathEnd.dir === 'bottom' ? pathEnd.position.y + coef : pathEnd.position.y - coef; + } + + return `M ${data.s.data.position.x} ${data.s.data.position.y} C ${cx(data.s.data)} ${cy(data.s.data)}, ` + + `${cx(data.e.data)} ${cy(data.e.data)}, ${data.e.data.position.x} ${data.e.data.position.y}`; +} + +/** @param {Element} element */ +function hoverEmulate(element) { + /** @type {Element} */ + let elemFromPoint = null; + + /** @param {PointerEvent} evt */ + function move(evt) { + const elemFromPointNew = priorityElemFromPoint(evt); + if (elemFromPoint !== elemFromPointNew) { + if (classHas(elemFromPointNew, 'hovertrack')) { + classAdd(elemFromPointNew, 'hover'); + } + let parentHover = false; + if (classHas(elemFromPointNew?.parentElement, 'hovertrack')) { + classAdd(elemFromPointNew.parentElement, 'hover'); + parentHover = true; + } + + classDel(elemFromPoint, 'hover'); + if (elemFromPoint?.parentElement !== elemFromPointNew?.parentElement || !parentHover) { + classDel(elemFromPoint?.parentElement, 'hover'); + } + + elemFromPoint = elemFromPointNew; + } + } + + listen(element, 'pointermove', move); + // dispose fn + return function() { + listenDel(element, 'pointermove', move); + classDel(elemFromPoint, 'hover'); + classDel(elemFromPoint?.parentElement, 'hover'); + elemFromPoint = null; + }; +} + +/** @param {Element} el, @param {...string} keys */ +const childs = (el, ...keys) => keys.map(kk => child(el, kk)); + +/** @param {number} num, @param {number} a, @param {number} b */ +const numInRangeIncludeEnds = (num, a, b) => a <= num && num <= b; + +/** @typedef { {x:number, y:number} } Point */ +/** @typedef { 'left' | 'right' | 'top' | 'bottom' } Dir */ +/** @typedef { {shapeEl: ShapeElement, connectorKey: string} } PathConnectedShape */ +/** @typedef { {position: Point, dir: Dir }} PathEndData */ +/** @typedef { {shape?:PathConnectedShape, data?:PathEndData, el?:SVGElement} } PathEnd */ +/** +@typedef {{ + s: PathEnd, + e: PathEnd, + styles?: string[], +}} PathData +*/ +/** @typedef { {shape?:PathConnectedShape, data?:PathEndData, oppositeShape?:PathConnectedShape, type:number} } MovedEnd */ +/** +@typedef {{ + draw(): void + pointerCapture: (evt:PointerEventInit)=>void + del(): void + data: PathData +}} Path +*/ + +/** @typedef { import('./path-smbl.js').PathElement } PathElement */ +/** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */ +/** @typedef { import('./shape-smbl').ShapeElement } ShapeElement */ +/** @typedef { import('./shape-evt-proc').Shape } Shape */ +/** @typedef { import('../infrastructure/move-evt-mobile-fix.js').PointerEventFixMovement } PointerEventFixMovement */ diff --git a/main_plugin/dgrm/shapes/rect-txt-settings.js b/main_plugin/dgrm/shapes/rect-txt-settings.js new file mode 100755 index 0000000..665462a --- /dev/null +++ b/main_plugin/dgrm/shapes/rect-txt-settings.js @@ -0,0 +1,86 @@ +import { copyAndPast } from '../diagram/group-select-applay.js'; +import { classAdd, classDel, clickForAll, listen, classSingleAdd, evtTargetAttr } from '../infrastructure/util.js'; +import { modalCreate } from './modal-create.js'; +import { ShapeSmbl } from './shape-smbl.js'; + +/** + * @param {import('../infrastructure/canvas-smbl.js').CanvasElement} canvas + * @param {import('./shape-smbl').ShapeElement} shapeElement + * @param {number} bottomX positon of the bottom left corner of the panel + * @param {number} bottomY positon of the bottom left corner of the panel + */ +export const rectTxtSettingsPnlCreate = (canvas, shapeElement, bottomX, bottomY) => + modalCreate(bottomX, bottomY, new RectTxtSettings(canvas, shapeElement)); + +class RectTxtSettings extends HTMLElement { + /** + * @param {import('../infrastructure/canvas-smbl.js').CanvasElement} canvas + * @param {import('./shape-smbl').ShapeElement} rectElement + */ + constructor(canvas, rectElement) { + super(); + /** @private */ + this._rectElement = rectElement; + + /** @private */ + this._canvas = canvas; + } + + connectedCallback() { + const shadow = this.attachShadow({ mode: 'closed' }); + shadow.innerHTML = ` + + +
+ + + +
+
`; + + const rectData = /** @type {import('./rect.js').RectData} */(this._rectElement[ShapeSmbl].data); + + const editEl = shadow.getElementById('edit'); + classAdd(editEl, `ta-${rectData.a}`); + + // colors, del + listen(editEl, 'cmd', /** @param {CustomEvent<{cmd:string, arg:string}>} evt */ evt => { + switch (evt.detail.cmd) { + case 'style': classSingleAdd(this._rectElement, rectData, 'cl-', evt.detail.arg); break; + case 'del': this._rectElement[ShapeSmbl].del(); break; + case 'copy': copyAndPast(this._canvas, [this._rectElement]); break; + } + }); + + // text align + clickForAll(shadow, '[data-cmd]', evt => { + const alignNew = /** @type {1|2|3} */(Number.parseInt(evtTargetAttr(evt, 'data-cmd-arg'))); + if (alignNew === rectData.a) { return; } + + const alignOld = rectData.a; + + // applay text align to shape + rectData.a = alignNew; + this._rectElement[ShapeSmbl].draw(); + + // highlight text align btn in settings panel + classDel(editEl, `ta-${alignOld}`); + classAdd(editEl, `ta-${rectData.a}`); + }); + } +} +customElements.define('ap-rect-txt-settings', RectTxtSettings); diff --git a/main_plugin/dgrm/shapes/rect.js b/main_plugin/dgrm/shapes/rect.js new file mode 100755 index 0000000..c78e744 --- /dev/null +++ b/main_plugin/dgrm/shapes/rect.js @@ -0,0 +1,142 @@ +import { ceil, child, classAdd, classDel, positionSet } from '../infrastructure/util.js'; +import { rectTxtSettingsPnlCreate } from './rect-txt-settings.js'; +import { shapeCreate } from './shape-evt-proc.js'; +import { settingsPnlCreate } from './shape-settings.js'; +import { ShapeSmbl } from './shape-smbl.js'; + +/** + * @param {CanvasElement} canvas + * @param {RectData} rectData + */ +export function rect(canvas, rectData) { + rectData.w = rectData.w ?? 96; + rectData.h = rectData.h ?? 48; + rectData.a = rectData.a ?? (rectData.t ? 1 : 2); + + const templ = ` + + +  `; + + const shape = shapeCreate(canvas, rectData, templ, + { + right: { dir: 'right', position: { x: 48, y: 0 } }, + left: { dir: 'left', position: { x: -48, y: 0 } }, + bottom: { dir: 'bottom', position: { x: 0, y: 24 } }, + top: { dir: 'top', position: { x: 0, y: -24 } } + }, + // onTextChange + txtEl => { + const textBox = txtEl.getBBox(); + const newWidth = ceil(96, 48, textBox.width + (rectData.t ? 6 : 0)); // 6 px right padding for text shape + const newHeight = ceil(48, 48, textBox.height); + + if (rectData.w !== newWidth || rectData.h !== newHeight) { + rectData.w = newWidth; + rectData.h = newHeight; + resize(); + } + }, + // settingsPnlCreateFn + rectData.t ? rectTxtSettingsPnlCreate : settingsPnlCreate); + + classAdd(shape.el, rectData.t ? 'shtxt' : 'shrect'); + + let currentW = rectData.w; + let currentTxtAlign = rectData.a; + /** @param {boolean?=} fixTxtAlign */ + function resize(fixTxtAlign) { + const mainX = rectData.w / -2; + const mainY = rectData.h / -2; + const middleX = 0; + + shape.cons.right.position.x = -mainX; + shape.cons.left.position.x = mainX; + shape.cons.bottom.position.y = -mainY; + shape.cons.bottom.position.x = middleX; + shape.cons.top.position.y = mainY; + shape.cons.top.position.x = middleX; + for (const connectorKey in shape.cons) { + positionSet(child(shape.el, connectorKey), shape.cons[connectorKey].position); + } + + rectSet(shape.el, 'main', rectData.w, rectData.h, mainX, mainY); + rectSet(shape.el, 'outer', rectData.w + 48, rectData.h + 48, mainX - 24, mainY - 24); + + // if text align or width changed + // fix text align + if (fixTxtAlign || currentTxtAlign !== rectData.a || currentW !== rectData.w) { + let txtX; + let posXDelta; + switch (rectData.a) { + // text align left + case 1: + txtX = mainX + 8; + posXDelta = (rectData.w - currentW) / 2; + break; + case 2: + txtX = 0; + posXDelta = 0; + break; + // text align right + case 3: + txtX = -mainX - 8; + posXDelta = (rectData.w - currentW) / -2; + break; + } + + const txtEl = child(shape.el, 'text'); + txtEl.x.baseVal[0].value = txtX; + txtEl.querySelectorAll('tspan').forEach(ss => { ss.x.baseVal[0].value = txtX; }); + + rectData.position.x += posXDelta; + + classDel(shape.el, `ta-${currentTxtAlign}`); + classAdd(shape.el, `ta-${rectData.a}`); + + currentTxtAlign = rectData.a; + currentW = rectData.w; + } + + shape.draw(); + } + + classAdd(shape.el, `ta-${rectData.a}`); + if (rectData.w !== 96 || rectData.h !== 48) { resize(true); } else { shape.draw(); } + + shape.el[ShapeSmbl].draw = resize; + + return shape.el; +} + +/** + * @param {Element} svgGrp, @param {string} key, + * @param {number} w, @param {number} h + * @param {number} x, @param {number} y + */ +function rectSet(svgGrp, key, w, h, x, y) { + /** @type {SVGRectElement} */ const rect = child(svgGrp, key); + rect.width.baseVal.value = w; + rect.height.baseVal.value = h; + rect.x.baseVal.value = x; + rect.y.baseVal.value = y; +} + +/** @param {RectData} rectData */ +const rectTxtXByAlign = rectData => rectData.a === 1 + ? -40 // text align keft + : rectData.a === 2 + ? 0 // text align middle + : 40; // text align right + +/** @typedef { {x:number, y:number} } Point */ +/** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */ +/** @typedef { import('./shape-evt-proc').CanvasData } CanvasData */ +/** @typedef { import('./shape-evt-proc').ConnectorsData } ConnectorsData */ +/** +@typedef {{ + type:number, position: Point, title?: string, styles?: string[], + w?:number, h?:number + t?:boolean, + a?: 1|2|3 +}} RectData */ diff --git a/main_plugin/dgrm/shapes/rhomb.js b/main_plugin/dgrm/shapes/rhomb.js new file mode 100755 index 0000000..6a65df6 --- /dev/null +++ b/main_plugin/dgrm/shapes/rhomb.js @@ -0,0 +1,101 @@ +import { ceil, child, classAdd, positionSet, svgTxtFarthestPoint } from '../infrastructure/util.js'; +import { shapeCreate } from './shape-evt-proc.js'; + +/** + * @param {CanvasElement} canvas + * @param {RhombData} rhombData + */ +export function rhomb(canvas, rhombData) { + const templ = ` + + + +  `; + + const shape = shapeCreate(canvas, rhombData, templ, + { + right: { dir: 'right', position: { x: 48, y: 0 } }, + left: { dir: 'left', position: { x: -48, y: 0 } }, + bottom: { dir: 'bottom', position: { x: 0, y: 48 } }, + top: { dir: 'top', position: { x: 0, y: -48 } } + }, + // onTextChange + txtEl => { + const newWidth = ceil(96, 48, textElRhombWidth(txtEl) - 20); // -20 experemental val + if (newWidth !== rhombData.w) { + rhombData.w = newWidth; + resize(); + } + }); + classAdd(shape.el, 'shrhomb'); + + function resize() { + const connectors = rhombCalc(rhombData.w, 0); + shape.cons.right.position.x = connectors.r.x; + shape.cons.left.position.x = connectors.l.x; + shape.cons.bottom.position.y = connectors.b.y; + shape.cons.top.position.y = connectors.t.y; + for (const connectorKey in shape.cons) { + positionSet(child(shape.el, connectorKey), shape.cons[connectorKey].position); + } + + const mainRhomb = rhombCalc(rhombData.w, 9); + rhombSet(shape.el, 'main', mainRhomb); + rhombSet(shape.el, 'border', mainRhomb); + rhombSet(shape.el, 'outer', rhombCalc(rhombData.w, -24)); + + shape.draw(); + } + + if (!!rhombData.w && rhombData.w !== 96) { resize(); } else { shape.draw(); } + + return shape.el; +} + +/** + * @param {Element} svgGrp, @param {string} key, + * @param {RhombPoints} rhomb + */ +function rhombSet(svgGrp, key, rhomb) { + /** @type {SVGPathElement} */(child(svgGrp, key)).setAttribute('d', `M${rhomb.l.x} ${rhomb.l.y} L${rhomb.t.x} ${rhomb.t.y} L${rhomb.r.x} ${rhomb.r.y} L${rhomb.b.x} ${rhomb.b.y} Z`); +} + +/** + * calc square rhomb points by width + * origin is in the center of the rhomb + * @param {number} width, @param {number} margin + * @returns {RhombPoints} + */ +function rhombCalc(width, margin) { + const half = width / 2; + const mrgnMinHalf = margin - half; + const halfMinMrgn = half - margin; + return { + l: { x: mrgnMinHalf, y: 0 }, + t: { x: 0, y: mrgnMinHalf }, + r: { x: halfMinMrgn, y: 0 }, + b: { x: 0, y: halfMinMrgn } + }; +} + +/** + * calc width of the square rhomb that cover all tspan in {textEl} + * origin is in the center of the rhomb + * @param {SVGTextElement} textEl + */ +function textElRhombWidth(textEl) { + const farthestPoint = svgTxtFarthestPoint(textEl); + return 2 * (Math.abs(farthestPoint.x) + Math.abs(farthestPoint.y)); +} + +/** @typedef { {x:number, y:number} } Point */ +/** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */ +/** @typedef { import('./shape-evt-proc').CanvasData } CanvasData */ +/** @typedef { import('./shape-evt-proc').ConnectorsData } ConnectorsData */ +/** +@typedef {{ + type:number, position: Point, title?: string, styles?: string[] + w?:number +}} RhombData +*/ +/** @typedef { { l:Point, t:Point, r:Point, b:Point } } RhombPoints */ diff --git a/main_plugin/dgrm/shapes/shape-evt-proc.js b/main_plugin/dgrm/shapes/shape-evt-proc.js new file mode 100755 index 0000000..d3186a3 --- /dev/null +++ b/main_plugin/dgrm/shapes/shape-evt-proc.js @@ -0,0 +1,306 @@ +import { child, classAdd, classDel, deepCopy, svgEl } from '../infrastructure/util.js'; +import { moveEvtProc } from '../infrastructure/move-evt-proc.js'; +import { path, dirReverse } from './path.js'; +import { textareaCreate } from '../infrastructure/svg-text-area.js'; +import { settingsPnlCreate } from './shape-settings.js'; +import { placeToCell, pointInCanvas } from '../infrastructure/move-scale-applay.js'; +import { ShapeSmbl } from './shape-smbl.js'; +import { svgTextDraw } from '../infrastructure/svg-text-draw.js'; +import { PathSmbl } from './path-smbl.js'; +import { CanvasSmbl } from '../infrastructure/canvas-smbl.js'; +import { canvasSelectionClearSet } from '../diagram/canvas-clear.js'; +import { listenCopy } from '../diagram/group-select-applay.js'; + +/** + * provides: + * - shape move + * - connectors + * + * - text editor + * - standard edit panel + * - onTextChange callback + * @param {CanvasElement} canvas + * @param {string} shapeHtml must have '' + * @param {ShapeData & { title?: string, styles?: string[]}} shapeData + * @param {ConnectorsData} cons + * @param {SettingsPnlCreateFn=} settingsPnlCreateFn + * @param {{(txtEl:SVGTextElement):void}} onTextChange + */ +export function shapeCreate(canvas, shapeData, shapeHtml, cons, onTextChange, settingsPnlCreateFn) { + /** @type {ShapeElement} */ + const el = svgEl('g', `${shapeHtml} + ${Object.entries(cons) + .map(cc => ``) + .join()}`); + + const textSettings = { + /** @type {SVGTextElement} */ + el: child(el, 'text'), + /** vericale middle, em */ + vMid: 0 + }; + + svgTextDraw(textSettings.el, textSettings.vMid, shapeData.title); + + const shapeProc = shapeEditEvtProc(canvas, el, shapeData, cons, textSettings, + settingsPnlCreateFn, + // onTextChange + () => onTextChange(textSettings.el)); + + return { + el, + cons, + draw: shapeProc.draw + }; +} + +/** + * provides: + * - shape move + * - connectors + * - copy fn + * + * - text editor + * - standard edit panel + * - onTextChange callback + * @param {CanvasElement} canvas + * @param {ShapeElement} svgGrp + * @param {ShapeData & { title?: string, styles?: string[]}} shapeData + * @param {ConnectorsData} connectorsInnerPosition + * @param { {el:SVGTextElement, vMid: number} } textSettings vMid in em + * @param {{():void}} onTextChange + * @param {SettingsPnlCreateFn} settingsPnlCreateFn + */ +function shapeEditEvtProc(canvas, svgGrp, shapeData, connectorsInnerPosition, textSettings, settingsPnlCreateFn, onTextChange) { + /** @type {{dispose():void, draw():void}} */ + let textEditor; + + /** @type { {position:(bottomX:number, bottomY:number)=>void, del:()=>void} } */ + let settingsPnl; + + function unSelect() { + textEditor?.dispose(); textEditor = null; + settingsPnl?.del(); settingsPnl = null; + } + + /** @param {string} txt */ + function onTxtChange(txt) { + shapeData.title = txt; + onTextChange(); + } + + const settingPnlCreate = settingsPnlCreateFn ?? settingsPnlCreate; + const shapeProc = shapeEvtProc(canvas, svgGrp, shapeData, connectorsInnerPosition, + // onEdit + () => { + textEditor = textareaCreate(textSettings.el, textSettings.vMid, shapeData.title, onTxtChange, onTxtChange); + + const position = svgGrp.getBoundingClientRect(); + settingsPnl = settingPnlCreate(canvas, svgGrp, position.left + 10, position.top + 10); + }, + // onUnselect + unSelect + ); + + if (shapeData.styles) { classAdd(svgGrp, ...shapeData.styles); } + + svgGrp[ShapeSmbl].del = function() { + shapeProc.del(); + svgGrp.remove(); + }; + + return { + draw: () => { + shapeProc.drawPosition(); + + if (settingsPnl) { + const position = svgGrp.getBoundingClientRect(); + settingsPnl.position(position.left + 10, position.top + 10); + } + + if (textEditor) { textEditor.draw(); } + } + }; +} + +/** + * provides: + * - shape move + * - connectors + * - copy fn + * - onEdit, onEditStop callbacks + * @param {CanvasElement} canvas + * @param {ShapeElement} svgGrp + * @param {ShapeData} shapeData + * @param {ConnectorsData} connectorsInnerPosition + * @param {{():void}} onEdit + * @param {{():void}} onUnselect + */ +function shapeEvtProc(canvas, svgGrp, shapeData, connectorsInnerPosition, onEdit, onUnselect) { + classAdd(svgGrp, 'hovertrack'); + + /** @type {ConnectorsData} */ + const connectorsData = deepCopy(connectorsInnerPosition); + + /** @type { Set } */ + const paths = new Set(); + + function drawPosition() { + svgGrp.style.transform = `translate(${shapeData.position.x}px, ${shapeData.position.y}px)`; + + // paths + for (const connectorKey in connectorsInnerPosition) { + connectorsData[connectorKey].position = { + x: connectorsInnerPosition[connectorKey].position.x + shapeData.position.x, + y: connectorsInnerPosition[connectorKey].position.y + shapeData.position.y + }; + } + + for (const path of paths) { + path[PathSmbl].draw(); + } + }; + + /** + * @type {0|1|2} + * 0 - init, 1 - selected, 2 - edit + */ + let state = 0; + + /** @type {()=>void} */ + let listenCopyDispose; + + function unSelect() { + onUnselect(); + + state = 0; + classDel(svgGrp, 'select'); + classDel(svgGrp, 'highlight'); + + canvasSelectionClearSet(canvas, null); + if (listenCopyDispose) { listenCopyDispose(); listenCopyDispose = null; } + } + + const moveProcReset = moveEvtProc( + canvas.ownerSVGElement, + svgGrp, + canvas[CanvasSmbl].data, + shapeData.position, + // onMoveStart + /** @param {PointerEvent & { target: Element} } evt */ + evt => { + unSelect(); + + const connectorKey = evt.target.getAttribute('data-connect'); + if (connectorKey) { + moveProcReset(); + +const diagramEl = document.getElementById('diagram'); +const rect = diagramEl.getBoundingClientRect(); +const x = evt.clientX - rect.left; +const y = evt.clientY - rect.top; + +const pathEl = path(canvas, { + s: { shape: { shapeEl: svgGrp, connectorKey } }, + e: { + data: { + dir: dirReverse(connectorsData[connectorKey].dir), + position: pointInCanvas(canvas[CanvasSmbl].data, x, y) + } + } +}); + + svgGrp.parentNode.append(pathEl); + pathEl[PathSmbl].pointerCapture(evt); + paths.add(pathEl); + } + }, + // onMove + drawPosition, + // onMoveEnd + _ => { + placeToCell(shapeData.position, canvas[CanvasSmbl].data.cell); + drawPosition(); + }, + // onClick + _ => { + // in edit mode + if (state === 2) { return; } + + // to edit mode + if (state === 1) { + state = 2; + classDel(svgGrp, 'select'); + classAdd(svgGrp, 'highlight'); + // edit mode + onEdit(); + return; + } + + // to select mode + state = 1; + classAdd(svgGrp, 'select'); + + canvasSelectionClearSet(canvas, unSelect); + listenCopyDispose = listenCopy(() => [svgGrp]); + }, + // onOutdown + unSelect); + + svgGrp[ShapeSmbl] = { + /** + * @param {string} connectorKey + * @param {PathElement} pathEl + */ + pathAdd: function(connectorKey, pathEl) { + paths.add(pathEl); + return connectorsData[connectorKey]; + }, + + /** @param {PathElement} pathEl */ + pathDel: function(pathEl) { + paths.delete(pathEl); + }, + + drawPosition, + + data: shapeData + }; + + return { + drawPosition, + del: () => { + unSelect(); + moveProcReset(); + for (const path of paths) { + path[PathSmbl].del(); + } + } + }; +} + +/** @typedef { {x:number, y:number} } Point */ +/** @typedef { {position:Point, scale:number, cell:number} } CanvasData */ + +/** @typedef { 'left' | 'right' | 'top' | 'bottom' } PathDir */ +/** @typedef { {position: Point, dir: PathDir} } PathEnd */ +/** @typedef { Object. } ConnectorsData */ + +/** @typedef { {type: number, position: Point, styles?:string[]} } ShapeData */ +/** +@typedef {{ + pathAdd(connectorKey:string, pathEl:PathElement): PathEnd + pathDel(pathEl:PathElement): void + drawPosition: ()=>void + data: ShapeData + del?: ()=>void + draw?: ()=>void +}} Shape + */ + +/** @typedef { {(canvas:CanvasElement, shapeElement:ShapeElement, bottomX:number, bottomY:number):{position(btmX:number, btmY:number):void, del():void} } } SettingsPnlCreateFn */ + +/** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */ +/** @typedef {import('./shape-smbl').ShapeElement} ShapeElement */ +/** @typedef {import('./path').Path} Path */ +/** @typedef {import('./path-smbl').PathElement} PathElement */ diff --git a/main_plugin/dgrm/shapes/shape-settings.js b/main_plugin/dgrm/shapes/shape-settings.js new file mode 100755 index 0000000..8a6d32a --- /dev/null +++ b/main_plugin/dgrm/shapes/shape-settings.js @@ -0,0 +1,121 @@ +import { copyAndPast } from '../diagram/group-select-applay.js'; +import { copySvg, delSvg } from '../infrastructure/assets.js'; +import { clickForAll, listen, classSingleAdd, evtTargetAttr } from '../infrastructure/util.js'; +import { modalChangeTop, modalCreate } from './modal-create.js'; +import { ShapeSmbl } from './shape-smbl.js'; + +/** + * @param {import('../infrastructure/canvas-smbl').CanvasElement} canvas + * @param {import('./shape-smbl').ShapeElement} shapeElement + * @param {number} bottomX positon of the bottom left corner of the panel + * @param {number} bottomY positon of the bottom left corner of the panel + */ +export function settingsPnlCreate(canvas, shapeElement, bottomX, bottomY) { + const shapeSettings = new ShapeEdit(); + listen(shapeSettings, 'cmd', /** @param {CustomEvent<{cmd:string, arg:string}>} evt */ evt => { + switch (evt.detail.cmd) { + case 'style': classSingleAdd(shapeElement, shapeElement[ShapeSmbl].data, 'cl-', evt.detail.arg); break; + case 'del': shapeElement[ShapeSmbl].del(); break; + case 'copy': copyAndPast(canvas, [shapeElement]); break; + } + }); + return modalCreate(bottomX, bottomY, shapeSettings); +} + +class ShapeEdit extends HTMLElement { + connectedCallback() { + const shadow = this.attachShadow({ mode: 'closed' }); + shadow.innerHTML = + ` +
+ + +
+
+ + + ${copySvg} + ${delSvg} +
`; + + // + // tabs + + { + const pnl = shadow.getElementById('pnl'); + + /** @param {1|-1} coef */ + function modalSetTop(coef) { + modalChangeTop(window.scrollY + coef * pnl.getBoundingClientRect().height); // window.scrollY fix IPhone keyboard + } + + /** @type {HTMLElement} */ + let currentTab; + + clickForAll(shadow, '[data-toggle]', evt => { + if (currentTab) { + modalSetTop(1); + display(currentTab, false); + } + + const tab = shadow.getElementById(evtTargetAttr(evt, 'data-toggle')); + if (currentTab !== tab) { + display(tab, true); + modalSetTop(-1); + currentTab = tab; + } else { + currentTab = null; + } + }); + } + + // + // commands + + clickForAll(shadow, '[data-cmd]', evt => { + this.dispatchEvent(new CustomEvent('cmd', { + detail: { + cmd: evtTargetAttr(evt, 'data-cmd'), + arg: evtTargetAttr(evt, 'data-cmd-arg') + } + })); + }); + } +} +customElements.define('ap-shape-edit', ShapeEdit); + +/** @param {ElementCSSInlineStyle} el, @param {boolean} isDisp */ +function display(el, isDisp) { el.style.display = isDisp ? 'unset' : 'none'; } diff --git a/main_plugin/dgrm/shapes/shape-smbl.js b/main_plugin/dgrm/shapes/shape-smbl.js new file mode 100755 index 0000000..4bf6026 --- /dev/null +++ b/main_plugin/dgrm/shapes/shape-smbl.js @@ -0,0 +1,3 @@ +export const ShapeSmbl = Symbol('shape'); + +/** @typedef {SVGGraphicsElement & { [ShapeSmbl]?: import('./shape-evt-proc').Shape }} ShapeElement */ diff --git a/main_plugin/dgrm/shapes/shape-type-map.js b/main_plugin/dgrm/shapes/shape-type-map.js new file mode 100755 index 0000000..61c299c --- /dev/null +++ b/main_plugin/dgrm/shapes/shape-type-map.js @@ -0,0 +1,27 @@ +import { circle } from './circle.js'; +import { path } from './path.js'; +import { rect } from './rect.js'; +import { rhomb } from './rhomb.js'; + +/** + * @param {CanvasElement} canvas + * @returns {Record} + */ +export function shapeTypeMap(canvas) { + return { + 0: { create: shapeData => path(canvas, shapeData) }, + 1: { create: shapeData => circle(canvas, shapeData) }, + 2: { create: shapeData => rect(canvas, shapeData) }, + 3: { create: shapeData => { /** @type {RectData} */(shapeData).t = true; return rect(canvas, shapeData); } }, + 4: { create: shapeData => rhomb(canvas, shapeData) } + }; +} + +/** @typedef { {x:number, y:number} } Point */ +/** @typedef { import('./rect.js').RectData } RectData */ +/** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */ +/** +@typedef {{ + create: (shapeData)=>SVGGraphicsElement +}} ShapeType +*/ diff --git a/main_plugin/dgrm/ui/menu.js b/main_plugin/dgrm/ui/menu.js new file mode 100755 index 0000000..ee6196a --- /dev/null +++ b/main_plugin/dgrm/ui/menu.js @@ -0,0 +1,371 @@ +import { canvasClear } from '../diagram/canvas-clear.js'; +import { fileSaveSvg } from '../diagram/dgrm-png.js'; +import { deserialize, serialize } from '../diagram/dgrm-serialization.js'; +import { generateKey, srvSave } from '../diagram/dgrm-srv.js'; +import { fileOpen, fileSave } from '../infrastructure/file.js'; +import { tipShow, uiDisable } from './ui.js'; + +export class Menu extends HTMLElement { + connectedCallback() { + const shadow = this.attachShadow({ mode: 'closed' }); + shadow.innerHTML = ` + + + `; + + const options = shadow.getElementById('options'); + function toggle() { options.style.visibility = options.style.visibility === 'visible' ? 'hidden' : 'visible'; } + + /** @param {string} id, @param {()=>void} handler */ + function click(id, handler) { + shadow.getElementById(id).onclick = _ => { + uiDisable(true); + handler(); + toggle(); + uiDisable(false); + }; + } + + shadow.getElementById('menu').onclick = toggle; + shadow.getElementById('menu2').onclick = toggle; + + click('new', () => { canvasClear(this._canvas); }); + +click('save', () => { + const serialized = serialize(this._canvas); + if (serialized.s.length === 0) { alertEmpty(); return; } + + fileSaveSvg(this._canvas, serialized, blob => { + fileSave(blob, 'dgrm.svg'); + }); +}); + +click('open', () => + fileOpen('.svg', async svgFile => await loadData(this._canvas, svgFile)) +); + + click('link', async () => { + const serialized = serialize(this._canvas); + if (serialized.s.length === 0) { alertEmpty(); return; } + + const key = generateKey(); + const url = new URL(window.location.href); + url.searchParams.set('k', key); + // use clipboard before server call - to fix 'Document is not focused' + await navigator.clipboard.writeText(url.toString()); + await srvSave(key, serialized); + + alert('Link to diagram copied to clipboard'); + }); + } + + /** @param {CanvasElement} canvas */ + init(canvas) { + /** @private */ this._canvas = canvas; + + // file drag to window + document.body.addEventListener('dragover', evt => { evt.preventDefault(); }); + document.body.addEventListener('drop', async evt => { + evt.preventDefault(); + + if (evt.dataTransfer?.items?.length !== 1 || + evt.dataTransfer.items[0].kind !== 'file' || + evt.dataTransfer.items[0].type !== 'image/png') { + alertCantOpen(); return; + } + + await loadData(this._canvas, evt.dataTransfer.items[0].getAsFile()); + }); + } +}; +customElements.define('ap-menu', Menu); + + + + +/** @param {CanvasElement} canvas, @param {File|Blob} svgFile */ +import { CanvasSmbl } from '../infrastructure/canvas-smbl.js'; + +function parseTranslateFromString(str) { + if (!str) return { x: 0, y: 0 }; + const m = /translate\(\s*([-\d.]+)(?:px)?\s*(?:,|\s)\s*([-\d.]+)(?:px)?\s*\)/.exec(str); + if (m) return { x: parseFloat(m[1]), y: parseFloat(m[2]) }; + const mm = /matrix\(\s*([-\d.e]+)[,\s]+([-\d.e]+)[,\s]+([-\d.e]+)[,\s]+([-\d.e]+)[,\s]+([-\d.e]+)[,\s]+([-\d.e]+)\s*\)/.exec(str); + if (mm && mm.length >= 7) return { x: parseFloat(mm[5]), y: parseFloat(mm[6]) }; + return { x: 0, y: 0 }; +} + +function getEffectiveTranslate(el) { + // priority: style attribute "transform: translate(...)" -> attribute transform -> HTMLElement.style.transform + if (!el || !el.getAttribute) return { x: 0, y: 0 }; + const styleAttr = el.getAttribute('style'); + if (styleAttr) { + const m = /transform\s*:\s*([^;]+)/.exec(styleAttr); + if (m) { + const p = parseTranslateFromString(m[1]); + if (Number.isFinite(p.x) || Number.isFinite(p.y)) return p; + } + } + const trAttr = el.getAttribute('transform'); + if (trAttr) { + const p = parseTranslateFromString(trAttr); + if (Number.isFinite(p.x) || Number.isFinite(p.y)) return p; + } + if (el instanceof HTMLElement && el.style && el.style.transform) { + const p = parseTranslateFromString(el.style.transform); + if (Number.isFinite(p.x) || Number.isFinite(p.y)) return p; + } + return { x: 0, y: 0 }; +} + +function extractCoordsFromPathD(d) { + if (!d) return { start: { x: 0, y: 0 }, end: { x: 0, y: 0 } }; + const nums = (d.match(/-?\d+(\.\d+)?/g) || []).map(Number); + if (nums.length >= 4) { + return { start: { x: nums[0], y: nums[1] }, end: { x: nums[nums.length - 2], y: nums[nums.length - 1] } }; + } + return { start: { x: 0, y: 0 }, end: { x: 0, y: 0 } }; +} + +function detectMainTag(el) { + if (!el || !el.querySelector) return null; + const main = el.querySelector('[data-key="main"]'); + if (main) return main.tagName?.toLowerCase() || null; + // fallback: check for presence of common tags + if (el.querySelector('circle')) return 'circle'; + if (el.querySelector('rect')) return 'rect'; + if (el.querySelector('path')) return 'path'; + return null; +} + +export async function loadData(canvas, svgFile) { + try { + const text = await svgFile.text(); + + const parser = new DOMParser(); + const svgDoc = parser.parseFromString(text, 'image/svg+xml'); + const svgElement = svgDoc.documentElement; + + const srcCanvasContainer = svgElement.querySelector('#canvas') || svgElement; + const canvasContainerOffset = getEffectiveTranslate(srcCanvasContainer); + + const sourceElements = Array.from(srcCanvasContainer.children || []); + + const shapeMap = canvas[CanvasSmbl] && canvas[CanvasSmbl].shapeMap; + if (!shapeMap) { + console.error('canvas[CanvasSmbl].shapeMap not found'); + return; + } + + const mapKeys = Object.keys(shapeMap); + + // Найдём ключ для стрелок (проверкой create с s/e данными) + let arrowKey = null; + for (const k of mapKeys) { + try { + const testData = { + s: { data: { dir: 'right', position: { x: 0, y: 0 } } }, + e: { data: { dir: 'right', position: { x: 10, y: 0 } } } + }; + const proto = shapeMap[k].create(testData); + // если create вернул элемент и в нём есть path или g[data-key="start"] + if (proto && (proto.querySelector && (proto.querySelector('path') || proto.querySelector('[data-key="start"]')))) { + arrowKey = k; + proto.remove && proto.remove(); + break; + } + proto.remove && proto.remove(); + } catch (err) { + // ignore + } + } + // fallback обычно '0' + if (arrowKey == null) arrowKey = mapKeys.find(mk => String(mk) === '0') || null; + + // Сопоставление kind(tag) -> key: создаём один proto на ключ и смотрим main tag + const keyByTag = {}; + for (const k of mapKeys) { + try { + const proto = shapeMap[k].create({ type: k, position: { x: 0, y: 0 }, title: 'T' }); + const tag = detectMainTag(proto); + if (tag) { + if (!keyByTag[tag]) keyByTag[tag] = k; + } + proto.remove && proto.remove(); + } catch (e) { + // ignore + } + } + + const createdShapes = []; + + // 1) создаём фигуры (non-path) + for (const node of sourceElements) { + if (!(node instanceof Element)) continue; + const looksLikePath = node.classList.contains('shpath') || !!node.querySelector('path.path') || !!node.querySelector('path[data-key="path"]'); + if (looksLikePath) continue; + + const groupPos = getEffectiveTranslate(node); // visible transform of group + const absPos = { x: (groupPos.x || 0) + (canvasContainerOffset.x || 0), y: (groupPos.y || 0) + (canvasContainerOffset.y || 0) }; + + const tag = detectMainTag(node) || 'unknown'; + const key = keyByTag[tag] || null; + + if (!key) { + // fallback: просто клонируем — визуал будет, но интерактивность может отсутствовать + try { + const clone = node.cloneNode(true); + canvas.append(clone); + } catch (e) { + console.error('clone failed', e); + } + continue; + } + + const title = node.querySelector('text')?.textContent || 'Title'; + const shapeData = { type: key, position: { x: absPos.x, y: absPos.y }, title }; + + try { + const shapeEl = shapeMap[key].create(shapeData); + // apply visible transform (absolute) + shapeEl.setAttribute && shapeEl.setAttribute('transform', `translate(${absPos.x},${absPos.y})`); + canvas.append(shapeEl); + shapeEl.dispatchEvent && shapeEl.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true })); + + // collect connectors absolute positions from source node + const connectors = {}; + const connNodes = Array.from(node.querySelectorAll('circle[data-connect]') || []); + connNodes.forEach(cn => { + const connName = cn.getAttribute('data-connect') || cn.getAttribute('data-key') || 'conn'; + const connTr = getEffectiveTranslate(cn); + // connector absolute = canvasContainerOffset + groupPos + connTr + const cpos = { + x: (canvasContainerOffset.x || 0) + (groupPos.x || 0) + (connTr.x || 0), + y: (canvasContainerOffset.y || 0) + (groupPos.y || 0) + (connTr.y || 0) + }; + connectors[connName] = cpos; + }); + + createdShapes.push({ key, el: shapeEl, tag, absPos, connectors }); + } catch (e) { + console.error('create shape failed', e); + } + } + + // 2) создаём стрелки точно как в _shapeCreate: формируем s/e с data.position и вызываем create +for (const node of sourceElements) { + if (!(node instanceof Element)) continue; + const looksLikePath = node.classList.contains('shpath') || !!node.querySelector('path.path') || !!node.querySelector('path[data-key="path"]'); + if (!looksLikePath) continue; + + let sPos = { x: 0, y: 0 }, ePos = { x: 0, y: 0 }; + + const startG = node.querySelector('[data-key="start"]'); + const endG = node.querySelector('[data-key="end"]'); + + if (startG) { + const p = getEffectiveTranslate(startG); + sPos.x = (p.x || 0) + (canvasContainerOffset.x || 0); + sPos.y = (p.y || 0) + (canvasContainerOffset.y || 0); + } + if (endG) { + const p = getEffectiveTranslate(endG); + ePos.x = (p.x || 0) + (canvasContainerOffset.x || 0); + ePos.y = (p.y || 0) + (canvasContainerOffset.y || 0); + } + + if ((sPos.x === 0 && sPos.y === 0) || (ePos.x === 0 && ePos.y === 0)) { + const pathEl = node.querySelector('path[data-key="path"]') || node.querySelector('path'); + if (pathEl) { + const coords = extractCoordsFromPathD(pathEl.getAttribute('d')); + sPos.x = coords.start?.x || sPos.x; + sPos.y = coords.start?.y || sPos.y; + ePos.x = coords.end?.x || ePos.x; + ePos.y = coords.end?.y || ePos.y; + } + } + + // Найти реальные shape и connector для s/e + const findConnector = (pos) => { + let best = null; + let minDist = Infinity; + for (const sh of createdShapes) { + for (const key in sh.connectors) { + const c = sh.connectors[key]; + const dx = c.x - pos.x; + const dy = c.y - pos.y; + const dist = dx*dx + dy*dy; + if (dist < minDist) { + minDist = dist; + best = { shapeEl: sh.el, connectorKey: key }; + } + } + } + return best; + } + + const sShape = findConnector(sPos); + const eShape = findConnector(ePos); + + const shapeData = { + s: sShape ? { shape: sShape, data: { dir:'right', position: {...sPos} } } : { data: { dir:'right', position: {...sPos} } }, + e: eShape ? { shape: eShape, data: { dir:'right', position: {...ePos} } } : { data: { dir:'right', position: {...ePos} } } + }; + + const shapeEl = arrowKey != null ? shapeMap[arrowKey].create(shapeData) : node.cloneNode(true); + canvas.append(shapeEl); + shapeEl.dispatchEvent && shapeEl.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true })); +} + + + console.log('loadData finished. shapes created:', createdShapes.length); + } catch (e) { + console.error('Ошибка при загрузке SVG', e); + } +} + + + + +const alertCantOpen = () => alert('File cannot be read. Use the exact image file you got from the application.'); +const alertEmpty = () => alert('Diagram is empty'); + +/** @typedef { {x:number, y:number} } Point */ +/** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */ diff --git a/main_plugin/dgrm/ui/shape-menu.js b/main_plugin/dgrm/ui/shape-menu.js new file mode 100755 index 0000000..717449e --- /dev/null +++ b/main_plugin/dgrm/ui/shape-menu.js @@ -0,0 +1,183 @@ +import { CanvasSmbl } from '../infrastructure/canvas-smbl.js'; +import { pointInCanvas } from '../infrastructure/move-scale-applay.js'; +import { listen } from '../infrastructure/util.js'; +import { tipShow } from './ui.js'; + +export class ShapeMenu extends HTMLElement { + connectedCallback() { + const shadow = this.attachShadow({ mode: 'closed' }); + shadow.innerHTML = + ` + `; + + const menu = shadow.getElementById('menu'); + menu.querySelectorAll('[data-cmd="shapeAdd"]').forEach(el => listen(el, 'pointerdown', this)); + listen(menu, 'pointerleave', this); + listen(menu, 'pointerup', this); + listen(menu, 'pointermove', this); + }; + + /** @param {CanvasElement} canvas */ + init(canvas) { + /** @private */ this._canvas = canvas; + } + + /** @param {PointerEvent & { currentTarget: Element }} evt */ + handleEvent(evt) { + switch (evt.type) { + case 'pointermove': + if (!this._isNativePointerleaveTriggered) { + // emulate pointerleave for mobile + + const pointElem = document.elementFromPoint(evt.clientX, evt.clientY); + if (pointElem === this._pointElem) { + return; + } + + // pointerleave + if (this._parentElem === this._pointElem) { + // TODO: check mobile + this._canvas.ownerSVGElement.setPointerCapture(evt.pointerId); + } + + /** + * @type {Element} + * @private + */ + this._pointElem = pointElem; + } + break; + case 'pointerleave': + this._isNativePointerleaveTriggered = true; + if (this._pressedShapeTemplKey != null) { + // when shape drag out from menu panel + this._shapeCreate(evt); + } + this._clean(); + break; + case 'pointerdown': + this._pressedShapeTemplKey = parseInt(evt.currentTarget.getAttribute('data-cmd-arg')); + + // for emulate pointerleave + this._parentElem = document.elementFromPoint(evt.clientX, evt.clientY); + this._pointElem = this._parentElem; + this._isNativePointerleaveTriggered = null; + break; + case 'pointerup': + this._clean(); + break; + } + } + + /** + * @param {PointerEvent} evt + * @private + */ +_shapeCreate(evt) { + tipShow(false); + if (this._pressedShapeTemplKey == null) return; + + const svg = this._canvas.ownerSVGElement; + const pt = svg.createSVGPoint(); + pt.x = evt.clientX; pt.y = evt.clientY; + const loc = pt.matrixTransform(this._canvas.getScreenCTM().inverse()); + const x = loc.x, y = loc.y; + + let shapeData; + if (this._pressedShapeTemplKey === 0) { + shapeData = { + s: { data: { dir: 'right', position: { x: x - 24, y } } }, + e: { data: { dir: 'right', position: { x: x + 24, y } } } + }; + } else { + shapeData = { + type: this._pressedShapeTemplKey, + position: { x, y }, + title: 'Title' + }; + } + + const shapeEl = this._canvas[CanvasSmbl].shapeMap[this._pressedShapeTemplKey].create(shapeData); + this._canvas.append(shapeEl); + + // Для стрелки и других форм диспатчим pointerdown + shapeEl.dispatchEvent(new PointerEvent('pointerdown', evt)); + + // transform ставим только для фигур, которые не path + if (this._pressedShapeTemplKey !== 0) { + shapeEl.setAttribute('transform', `translate(${x},${y})`); + } +} + + + /** @private */ + _clean() { + this._pressedShapeTemplKey = null; + this._parentElem = null; + this._pointElem = null; + } +} +customElements.define('ap-menu-shape', ShapeMenu); + +/** @typedef { import('../shapes/shape-type-map.js').ShapeType } ShapeType */ +/** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */ diff --git a/main_plugin/dgrm/ui/ui.js b/main_plugin/dgrm/ui/ui.js new file mode 100755 index 0000000..239978c --- /dev/null +++ b/main_plugin/dgrm/ui/ui.js @@ -0,0 +1,29 @@ +/** @type {HTMLDivElement} */ let overlay; +/** @param {boolean} isDisable */ +export function uiDisable(isDisable) { +/* if (isDisable && !overlay) { + overlay = document.createElement('div'); + overlay.style.cssText = 'z-index: 2; position: fixed; left: 0; top: 0; width:100%; height:100%; background: #fff; opacity: 0'; + overlay.innerHTML = + ``; + overlay.classList.add('blnk'); + document.body.append(overlay); + } else if (!isDisable) { + overlay.remove(); + overlay = null; + } */ +} + +/** @param {boolean} show */ +tipShow(false); +export function tipShow(show) { + document.getElementById('diagram').style.pointerEvents = show ? 'none' : 'unset'; + document.getElementById('tip').style.display = show ? 'unset' : 'none'; +} diff --git a/main_plugin/editor/editor.css b/main_plugin/editor/editor.css new file mode 100755 index 0000000..f872bb8 --- /dev/null +++ b/main_plugin/editor/editor.css @@ -0,0 +1,787 @@ +/* Главное */ +#basis3 { + left: 0 !important; + top: 33px !important; + transform: none !important; +} +#copyr_sym *, .deploy *, .elementEditPanelElement * { + margin-top: 2px; + margin-bottom: 2px; +} + +.selectedColor { + background: #3a6e62; + color: #ffffff; +} +.textGrey:hover { + color: #787878; + cursor: pointer; +} +.toolbar-container { + touch-action: none; +} + +#panel { + position: absolute; + display: flex; + align-items: center; + max-width: -webkit-fill-available; + border-radius: 5px; + background: rgba(255, 255, 255, 0.8); + overflow-x: clip; + overflow-y: visible; + z-index: 100; +} +.toolbar-container { + display: flex; + align-items: center; + white-space: nowrap; + padding: 4px; + margin: 0; + flex-shrink: 0; + padding: 4px 0px; + width: 100%; +} +.arrow { + position: absolute; + top: 50%; + transform: translateY(-50%); + width: 24px; + height: 36px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + z-index: 10; + background: rgba(255, 255, 255, 0.8); +} +#arrow-left { + left: 0; + border: none; + border-right: inherit; +} +#arrow-right { + right: 0; + border: none; + border-left: inherit; +} + +/* Стили контейнера для показа увеличенных изображений */ +#bas, +#C { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + visibility: hidden; +} + +#bas { + z-index: 1; + background: #FFFFFF; + opacity: 0.95; +} + +#view { + z-index: 2; + display: flex; + justify-content: center; + align-items: center; +} + +/* Стили контейнера, содержащего страницу */ +#basis { + position: relative; + width: -webkit-fill-available; + margin: auto; +} + +/* Стили таблицы, содержащей страницу */ +#tab { + width: 1000px; +} + +/* Стили меню */ + +#sect { + display: flex; + margin-bottom: 15px; + font-family: Tahoma; + font-weight: bold; +} + +/* Стили пунктов меню */ +.lin { + margin: 9px; + width: 180px; + height: 50px; + color: #FFFFFF; + text-align: center; + box-shadow: 5px 5px 10px #000066; + background: #660033; + line-height: 50px; + border-radius: 5px; +} + +/* Стили ячейки для рекламы */ +#rec { + width: 300px; + text-align: center; + vertical-align: top; + font-weight: bold; + color: #660033; +} + + + +/* Стили контейнера, содержащего страницу */ +#basis3 { + position: fixed; + width: -webkit-fill-available; + margin: auto; + z-index: 100; + user-select: none; + font-size: 0.97em; +} + +/* Стили вкладок с настройками */ +.cust { + height: auto; + padding: 8px; + position: fixed; + visibility: hidden; + z-index: 100; + background: url(../../img/img/backgr.jpg); + border-radius: 5px; + top: 30%; + left: 0; + right: 0; + margin-left: auto; + margin-right: auto; + width: calc(100% - 20px); + max-width: max-content; +} +.cust2 { + height: auto; + padding: 5px; + position: absolute; + top: 236%; + width: 1118px; + border: 1px solid #000000; + visibility: hidden; + z-index: 100; + background: url(../../img/img/backgr.jpg); + border-radius: 5px; + max-width: -webkit-fill-available; +} + +/* Стили кнопок (крестиков) для закрытия вкладок */ +.cldiv { + margin: 2px; + cursor: pointer; +} + +/* Стили вкладки с изображениями с сервера */ + +#p_list { + text-align: center; +} + +.roster { + width: 180px; + margin: 5px; + cursor: pointer; +} + +/* Стили главной панели редактора */ +.toolbar-group { + position: relative; + padding: 0px 5px; + margin: 0px 2px; + display: inline-block; +} +.toolbar-group::before { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: -3.1px; + width: 5px; + background: linear-gradient( + to right, + #000 0px 1px, + transparent 1px 2px, + #000 2px 3px, + transparent 3px 4px, + #000 4px 5px + ); +} +.toolbar-group.open { + margin-left: 7px; +} +.toolbar-group-button { + transition: transform 0.1s ease, left 0.1s ease; +} +.toolbar-group.open .toolbar-group-button { + position: absolute; + left: -9px; + transform: scale(0.6); + transform-origin: top left; + z-index: 1; +} +.toolbar-group-content { + transition: margin-left 0.1s ease; +} +.toolbar-group.open .toolbar-group-content { + margin-left: 7px; +} + +#toolbar-group-button-main { + background-position: -318px -117px; +} +#toolbar-group-button-text { + background-position: -237px 1664px; +} +#toolbar-group-button-paste { + background-position: 166px 517px; +} + +.align-dropdown, .align-dropdown-oneImg { + position: relative; + display: inline-block; +} +.align-dropdown-text { + position: relative; + display: inline-block; + cursor: pointer; + border: 1px solid #000000; + height: 26px; + border-radius: 5px; + vertical-align: middle; + background: #FFFFFF; + padding-right: 13px; +} +.align-dropdown-text .dropdown-arrow { + position: absolute; + right: 5px; + top: 50%; + transform: translateY(-50%); + pointer-events: none; +} +.align-dropdown-text .current { + padding: 0 3px; + height: 28px; + line-height: 28px; + display: inline-block; + cursor: pointer; +} +.align-dropdown .current { + cursor: pointer; +} +.align-list { + list-style: none; + margin: 0; + padding: 4px 0; + position: absolute; + top: 100%; + left: -9px; + background: #fff; + border: 1px solid #000000; + display: none; + z-index: 10; + font-size: 0.95em; +} +.align-list li { + padding: 4px 8px; + cursor: pointer; +} +.align-list li:hover { + background: #eee; +} + + + +/* Стили выпадающего списка панели */ +#sel { + font-size: 1.1em; + font-family: Tahoma; + border: 1px solid #000000; +} + +/* Стили кнопок навигации по этапам редактирования */ +#forw, +#bac { + right: 10px; + cursor: pointer; +} + +/* Стили кнопок на главной панели редактора */ +.but, +.pers, +.swit, +.swit2, +.pers2, +.pers3 { + border: 1px solid #000000; + cursor: pointer; +} + +.editt { + display: inline-block; +} + +.editi { + border-radius: 5px; + background: #FFFFFF; + display: inline-block; + width: 26px; + height: 26px; + vertical-align: middle; +} +.edits { + border-radius: 5px; + display: inline-block; + vertical-align: middle; +} + +.editib { + background-image: url(../../img/pict/b_iconslyb.svg); +} + +.editimc { + background-image: url(../../img/pict/mc_iconslyb.svg); +} + +.editib:hover { + background-image: url(../../img/pict/g_iconslyb.svg); +} + +.editimc:hover { + background-image: url(../../img/pict/g_iconslyb.svg); +} + +.editf.active { + background-image: url(../../img/pict/b_iconslyb.svg); + background-color: #e7e7e7; +} +.editf.active:hover { + background-image: url(../../img/pict/g_iconslyb.svg); + background-color: #e7e7e7; +} + +#settingsMain { + background-position: -197px -597px; +} + +#forma { + background-position: 45px -117px; +} + +#htm { + background-position: -318px 1824px; +} + +#bac { + background-position: 645px 716px; +} + +#forw { + background-position: 605px 716px; +} + +#img, #oneImg { + background-position: 645px 477px; +} + +#hr { + background-position: 766px 676px; +} + +#tabl { + background-position: 1006px 597px; +} + +#link { + background-position: 245px 277px; +} + +#linkdel { + background-position: 205px 277px; +} + +#delin { + background-position: 205px 277px; +} + +#copyr { + background-position: 445px 517px; +} + +#bol { + background-position: 1006px 517px; +} + +#ital { + background-position: 966px 517px; +} + +#under { + background-position: 926px 517px; +} + +#col { + background-position: -237px 1664px; +} + +#backgr { + background-position: -278px 1664px; +} + +#font { + background-position: 1046px 517px; +} + +#strik { + background-position: 885px 517px; +} + +#sup { + background-position: 846px 517px; +} + +#sub { + background-position: 806px 517px; +} + +#titleEdit { + background-position: 1045px 557px; +} + +/* #pluginSave { + background-position: -479px 1665px; +} +#pluginCreateLeft { + background-position: -598px 1665px; +} +#pluginAddLeft { + background-position: -677px 1665px; +} +#pluginCreateRight { + background-position: -558px 1665px; +} +#pluginAddRight { + background-position: -638px 1665px; +} +#pluginDelete { + background-position: -518px 1665px; +} +#pluginMove { + background-position: -438px 1665px; +} */ + +#contentPageCreate { + background-position: 926px 676px; +} +#contentPageMove { + background-position: -1077px 1704px; +} +#contentPageSettings { + background-position: -156px 1704px; +} + +#elementEdit { + background-position: 965px 557px; +} + +#coup { + background-position: -357px 1662px; +} + +#contentPageCreateUrlManager { + background-position: -679px 1820px; +} + +.indent { + display: inline-block; + width: 5px; +} + +/* картинки списков */ +#equar, .align-dropdown .current.equar { + background-position: 685px 517px; +} +#equac, .align-dropdown .current.equac { + background-position: 725px 517px; +} +#equal, .align-dropdown .current.equal { + background-position: 765px 517px; +} +#equaj, .align-dropdown .current.equaj { + background-position: 645px 517px; +} + +#listNone, .align-dropdown .current.listNone { + background-position: -798px 1666px; +} +#listDots, .align-dropdown .current.listDots { + background-position: 764px 437px; +} +#listNumbers, .align-dropdown .current.listNumbers { + background-position: 724px 437px; +} +#listLetters, .align-dropdown .current.listLetters { + background-position: -757px 1666px; +} + +/* Стили маленьких окон на главной панели редактора */ +.smbut { + position: absolute; + cursor: pointer; + visibility: hidden; +} +#ccc { + position: absolute; + opacity: 0; + left: 470px; + top: 17px; + pointer-events: none; +} +#list { + width: 100px; + height: 28px; +} +#fs { + width: 50px; + height: 28px; +} +#ff { + width: 145px; + height: 28px; +} + +#mainActions { + height: 28px; +} +#pluginDropdownContent { + height: 28px; +} +#elementDropdownContent { + width: 170px; + height: 28px; +} + +/* Стили контейнеров вкладок с настройками */ +.deploy { + text-align: center; + line-height: 25px; +} + +/* Стили textarea */ +.textar { + width: 400px; + height: 70px; + font-size: 0.9em; + border: 1px solid #000000; + margin-left: 5px; + margin-right: 20px; +} + +/* Стили коротких текстовых полей */ +.inptx { + width: 51px; + height: 22px; + font-size: 0.9em; + border: 1px solid #000000; + margin-right: 10px; + border-radius: 5px; +} + +/* Стили средних текстовых полей */ +.inpmid { + width: 120px; + height: 18px; + font-size: 0.9em; + border: 1px solid #000000; + margin-right: 10px; + border-radius: 5px; +} + +/* Стили длинных текстовых полей */ +.inpbig { + width: 190px; + height: 18px; + font-size: 0.9em; + border: 1px solid #000000; + margin-right: 10px; + border-radius: 5px; +} + +/* Стили для формы */ +.inform { + display: inline-block; + margin-block-end: 0em; +} + +/* Стили кнопок вставки и просмотра на вкладках с настройками */ +.butin { + height: 22px; + font-size: 0.9em; + border: 1px solid #000000; + background: #FFFFFF; + cursor: pointer; + border-radius: 5px; +} +.butinAuto { + width: min-content; + height: 22px; + font-size: 0.92em; + cursor: pointer; + padding: 1px 5px 1px 5px; + cursor: pointer; +} +.butinAuto:hover { + color: #787878; +} +.buttonEditTable { + height: 22px; + font-size: 0.9em; + border: 1px solid #000000; + background: #FFFFFF; + cursor: pointer; + border-radius: 5px; +} +.buttonEditTable.active { + background-color: #e7e7e7; +} + +/* Стили выпадающих списков */ +.sele { + height: 22px; + font-size: 0.9em; + border: 1px solid #000000; + margin-right: 10px; + border-radius: 5px; +} + +.colored { + width: 28px; + height: 22px; + cursor: pointer; + margin-right: 10px; +} + +/* Стили выпадающих списков без зазора справа */ +.selena { + height: 22px; + font-size: 0.9em; + border: 1px solid #000000; + margin-right: 2px; +} + +/* Стили кнопок выбора цвета на вкладках с настройками */ +.colored { + width: 28px; + height: 22px; + cursor: pointer; + margin-right: 10px; +} + +/* Стиль кнопок зарузок изоброжений */ +#selectImgForm { + width: 77px; + height: 22px; + font-size: 0.9em; + border: 1px solid #000000; + background: #FFFFFF; + cursor: pointer; + border-radius: 5px; + margin: 0px 5px 0px -15px; +} + +/* Стиль окна текстового редактора */ +#tex { + position: absolute; + top: 236%; + width: 1100px; + height: 380px; + border: 1px solid #000000; + padding: 10px; + font-size: 1.2em; + font-family: Tahoma; + visibility: hidden; + z-index: 6; + border-radius: 5px; + left: 0px; +} + +/* Стили контейнера с кнопками для символов и самих кнопок */ +#copyr_sym { + text-align: center; +} + +.sym { + vertical-align: middle; + width: 25px; + height: 25px; + margin: 1px; + border: 1px solid #000000; + font-size: 1em; + font-family: Tahoma; + background: #FFFFFF; + cursor: pointer; +} + +#pluginRulesButton1, #pluginRulesButton2 { + width: 1em; + display: inline-block; +} +#pluginRulesBlock1, #pluginRulesBlock2 { + width: 240px; + position: absolute; + display: inline-block; + background: #efefef; + font-size: 0.9em; + padding: 2px; + line-height: 1.6; + border-radius: 5px; + opacity: 0; + transition: max-height 0.18s ease-out, opacity 0.18s ease-out; + pointer-events: none; +} +#pluginRulesBlock1.show, #pluginRulesBlock2.show { + opacity: 1; + pointer-events: all; +} + +p { + margin-block-start: 5px; + margin-block-end: 5px; +} + +.pluginEditable { + outline-offset: 15px; + overflow-x: hidden; + font-family: 'Roboto', sans-serif; +} + +/* поля для редактирование элементов */ +#editingMenuItems { + display: inline-block; + position: fixed; + z-index: 10; + user-select: none; + background-color: rgba(255, 255, 255, 0.92); + border-radius: 5px; + font-size: 1em; + box-shadow: 0px 0px 5px #777; + padding: 5px; + visibility: hidden; +} +.editingMenuItemsElement { + padding: 2px; + cursor: pointer; +} +.editingMenuItemsElement:hover { + color: #787878; +} \ No newline at end of file diff --git a/main_plugin/editor/editor.js b/main_plugin/editor/editor.js new file mode 100755 index 0000000..8f10e14 --- /dev/null +++ b/main_plugin/editor/editor.js @@ -0,0 +1,2272 @@ +/** + * @file editor.js + * @brief Основной файл редактора, содержит базовые функции и переменные для работы с элементами страницы +*/ + +function pluginFun(action, side) { + if (action === 'add') { + jsonrpcRequest('getFolders', { folder: 'plugin' }) + .then(folders => { + let pluginAddSideName = document.getElementById('pluginAdd' + (side === 'left' ? 'Left' : 'Right') + 'Name'); + pluginAddSideName.innerHTML = ''; + folders.forEach(folder => { + let option = document.createElement('option'); + option.value = folder; + option.textContent = folder; + pluginAddSideName.appendChild(option); + }); + }); + } +} + +addEventListener("LoadeditorJs", function() +{ +/* movementMenu("basis3"); */ +addEventListener("scroll", del); + +let view=document.getElementById("view"); // Ссылка на элементы окна просмотра +let bas=document.getElementById("bas").style; +let pict=document.getElementById("pict"); + +/* view.addEventListener("click", del); */ + +function del() // Функция закрытия окна просмотра + { + if (view) { + view.style.visibility="hidden"; + } + bas.visibility="hidden"; + } + + +}, { once: true }); + +/** @brief Список редактируемых элементов */ +let editableElements; +/** @brief Режим редактирования: -1 = выключен */ +let editMode = -1; +/** @brief Массив ID кнопок редактирования */ +let editId = ['pluginDelete', 'titleEdit', 'pluginMove', 'elementEdit', + 'editTableButtonAddLine', 'editTableButtonDeleteLine', 'editTableButtonAddColumn', 'editTableButtonDeleteColumn'] ; + +/** @brief Переключает видимость и редактируемость элементов */ +function basisVis() { + editableElementsFun(); + let basis3 = document.getElementById('basis3'); + let sideFloatClass = basis3 ? basis3.querySelectorAll('[style*="visibility: visible;"]') : null; + if (!basis3 || !sideFloatClass || !editableElements || editableElements.length === 0) return; + elementsСhecked = [basis3, ...sideFloatClass, ...editableElements]; + + if (basis3.style.visibility === "visible") { + basis3.style.visibility = "hidden"; + sessionStorage.setItem('basis3_visibility', 'hidden'); + editableElements.forEach(function(element) { + if (element) { + element.setAttribute("contenteditable", false); + } + }); + document.querySelector('#mainTitle').setAttribute('contenteditable', 'false'); + sideFloatClass.forEach(function(element) { + element.style.visibility = "hidden"; + }); + for (let i = 0; i < editId.length; i++) { + editMode = -1; + if (document.getElementById(editId[i])) { + document.getElementById(editId[i]).classList.remove('active'); + } + } + document.getElementById('bcbody').style.top = '0px'; + document.querySelectorAll('.bfloat').forEach(e=>e.style.fontSize='') + } else { + basis3.style.visibility = "visible"; + sessionStorage.setItem('basis3_visibility', 'visible'); + editableElements.forEach(function(element) { + if (element) { + element.setAttribute("contenteditable", true); + } + }); + document.querySelector('#mainTitle').setAttribute('contenteditable', 'true'); + basis3.style.left = '10px'; + basis3.style.top = '20%'; + basis3.style.transform = 'translate(0%, -20%)'; + document.getElementById('bcbody').style.top = '30px'; + document.querySelectorAll('.bfloat').forEach(e=>e.style.fontSize='1em') + + } +} +window.basisVis = basisVis; + +/** @brief Сбор всех редактируемых элементов */ +function editableElementsFun() { + let content = document.getElementById('content'); + editableElements = document.querySelectorAll('.pluginEditable'); + editableElements = Array.from(editableElements); + editableElements.push(content); + + editableElements.forEach(function(element) { + if (!element) { + console.log("Element " + element + " not found."); + return; + } + }); +} + + +addEventListener("LoadeditorJs", function() +{ + +let te=document.getElementById("tex"); // Ссылка на текстовое поле +let tex=document.getElementById("tex"); // Ссылка на стили текстового поля + +if (document.getElementById("content") == "") { +te.value=document.getElementById("content").innerHTML; // Передача данных из области контента в текстовое поле +} + +// Символы клавиш со знаками препинания или перевода строки +let symb = ["Enter", "!", "?", ";", ":", ",", ".", " ", "-", "'", "\"", "(", ")", "{", "}", "[", "]", "_", "&", "/", "\\", "*"]; + +// Запись в память введенного текста при нажатии клавиши со знаком препинания или перевода строки +if (document.getElementById("content")) { + document.getElementById("content").addEventListener("keyup", function(ev) + { + for(let i=0; i { + const list = dropdown.querySelector('.align-list'); + dropdown.addEventListener('click', e => { + if (e.target.closest('.align-list')) { + const cmd = e.target.closest('li').dataset.cmd; + handleImageAction(cmd); + list.style.display = 'none'; + return; + } + list.style.display = list.style.display === 'block' ? 'none' : 'block'; + }); + document.addEventListener('click', e => { + if (!dropdown.contains(e.target)) { + list.style.display = 'none'; + } + }); +}); + +function handleImageAction(id) { + var sel = window.getSelection(); + if (sel.rangeCount) { + var node = sel.anchorNode.nodeType === 1 ? sel.anchorNode : sel.anchorNode.parentElement; + if (!node.closest('[contenteditable="true"]')) { + return; + } + } + switch (id) { + case "imgLink": + messageQueue.push("Enter image URL") + ;(async () => { + const url = await messageCreateInput() + if (url) { + const img = document.createElement("img") + img.src = url + img.style.cssText = "float: left; margin: 10px; width: 250px; border: 0; overflow: hidden;" + insertNodeAtSelection(img) + } + })() + break + case "imgPc": + var input = document.createElement("input"); + input.type = "file"; + input.accept = "image/*"; + input.style.display = "none"; + document.body.appendChild(input); + + input.addEventListener("change", function() { + if (input.files.length > 0) { + var reader = new FileReader(); + reader.onload = function(e) { + var base64Data = e.target.result.split(',')[1]; + jsonrpcRequest('uploadImage', { userImgBase64: base64Data, userImgName: input.files[0].name }) + .then(response => { + if (response) { + try { + var img = document.createElement("img"); + img.src = response; + img.setAttribute("style", "float: left; margin: 10px; width: 250px; border: 0px solid rgb(0, 0, 0); overflow: hidden;"); + insertNodeAtSelection(img); + } catch (e) { + messageFunction("{{img_upload_error}}"); + } + } else { + messageFunction("{{img_upload_error}}"); + } + }) + .catch(() => messageFunction("{{img_upload_error}}")); + }; + reader.readAsDataURL(input.files[0]); + } + document.body.removeChild(input); + }); + input.click(); + break; + case "imgManager": + window.managerDataAction = "selectImgForm"; + let userName = getCookie('User'); + if (userName) { + managerData("/img/users_img/" + userName); + managerDiv.style.visibility = "visible"; + document.getElementById("settingsMain_d").style.visibility = "hidden"; + } + break; + } +} + +function insertHR() { + const hr = document.createElement("hr") + hr.style.cssText = "height: 5px; width: 50%; background: rgb(0, 0, 0); border: 0;" + insertNodeAtSelection(hr) +} +document.getElementById("hr").addEventListener("click", insertHR) + +function insertTable() { + const table = document.createElement("table") + table.style.cssText = "width: 50%; margin: 1px; float: left; border: 1px solid rgb(0, 0, 0); background-color: rgb(255, 255, 255); border-collapse: collapse;" + for (let i = 0; i < 4; i++) { + const tr = document.createElement("tr") + for (let j = 0; j < 4; j++) { + const td = document.createElement("td") + td.style.cssText = "padding: 1px; border: 1px solid rgb(0, 0, 0);" + tr.appendChild(td) + } + table.appendChild(tr) + } + insertNodeAtSelection(table) +} +document.getElementById("tabl").addEventListener("click", insertTable) + +function insertNodeAtSelection(node) { + var sel = window.getSelection(); + if (!sel.rangeCount) return; + var range = sel.getRangeAt(0); + range.deleteContents(); + range.insertNode(node); +} + +/*let t=document.querySelectorAll(".cldiv"); +for(let i=0; i { + option.style.backgroundColor = '#efefef'; + }); + if (activeOption) { + pluginDropdownContentId.style.backgroundColor = '#d8d8d8'; + } else { + pluginDropdownContentId.style.backgroundColor = ''; + } + if (editMode == -1) { + pluginDropdownContentId.style.backgroundColor = ''; + } +}); + +// действия блока элементов +/* let elementDropdownContentId = document.getElementById("elementDropdownContent"); +elementDropdownContentId.addEventListener('click', function () { + let targetElement = document.getElementById(this.value); + if (targetElement) { + targetElement.click(); + } else { + console.log("{{action_not_defined}}2"); + } +}); */ + +// действия блока главных действий +/* let mainActionsId = document.getElementById("mainActions"); +mainActionsId.addEventListener('click', function () { + switch (this.value) { + case "save": + saveChanges(); + break; + case "saveHow": + saveChangesHow(); + break; + case "htm": + showHtmlCode(); + break; + default: + console.log("{{action_not_defined}}"); + } +}); */ + +document.getElementById("save").addEventListener("click", saveChanges); + +// Загрузка изменений как +document.getElementById("saveHow").addEventListener("click", saveChangesHow); +function saveChangesHow() { + window.managerDataAction = "saveHow"; + managerData("/content"); + managerDiv.style.visibility = "visible"; + document.getElementById("settingsMain_d").style.visibility="hidden"; +} + +// Открытие страницы +document.getElementById("getPage").addEventListener("click", openPageFun); +function openPageFun() { + window.managerDataAction = "getPage"; + managerData("/content"); + managerDiv.style.visibility = "visible"; + document.getElementById("settingsMain_d").style.visibility="hidden"; +} + +// Создание новой страницы +document.getElementById("newPage").addEventListener("click", newPageFun); +function newPageFun() { + document.getElementById("right-float").innerHTML = ""; + document.getElementById("left-float").innerHTML = ""; + document.getElementById("content").innerHTML = ""; + document.getElementById("mainTitle").innerHTML = "{{new_file}}!"; + window.newPageFunValue = "newPage"; + document.getElementById("settingsMain_d").style.visibility="hidden"; +} + +// Сохранение выделение + +document.addEventListener('selectionchange', () => { + const content = document.getElementById('content'); + const sel = window.getSelection(); + if (!sel.rangeCount) return; + const range = sel.getRangeAt(0); + const startNode = range.startContainer; + if (content.contains(startNode)) { + saveSelection(); + } +}); + +let savedSel = null; + +function saveSelection() { + const content = document.getElementById('content'); + const sel = window.getSelection(); + if (!sel.rangeCount) return; + const range = sel.getRangeAt(0); + if (!content.contains(range.commonAncestorContainer)) return; + const pre = range.cloneRange(); + pre.selectNodeContents(content); + pre.setEnd(range.startContainer, range.startOffset); + const start = pre.toString().length; + const end = start + range.toString().length; + savedSel = { start, end }; +} + +function restoreSelection() { + if (!savedSel) return; + const content = document.getElementById('content'); + const { start, end } = savedSel; + let charIndex = 0; + const range = document.createRange(); + range.setStart(content, 0); + range.collapse(true); + try { + (function traverse(node) { + if (node.nodeType === Node.TEXT_NODE) { + const next = charIndex + node.length; + if (charIndex <= start && next >= start) { + range.setStart(node, start - charIndex); + } + if (charIndex <= end && next >= end) { + range.setEnd(node, end - charIndex); + throw 'done'; + } + charIndex = next; + } else { + node.childNodes.forEach(traverse); + } + })(content); + } catch (e) {} + const sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); +} + +// Взаимодействие с плагинами +/* document.getElementById('pluginCreateLeft').onclick = function() { pluginFun('create', 'left'); }; +document.getElementById('pluginCreateRight').onclick = function() { pluginFun('create', 'right'); }; */ +document.getElementById('pluginAddLeft').onclick = function() { pluginFun('add', 'left'); }; +document.getElementById('pluginAddRight').onclick = function() { pluginFun('add', 'right'); }; + + +/* document.getElementById('pluginRulesButton1').onclick = function() { pluginRulesFun('pluginRulesBlock1'); }; +document.getElementById('pluginRulesButton2').onclick = function() { pluginRulesFun('pluginRulesBlock2'); }; */ + +function pluginRulesFun(id) { + let element = document.getElementById(id); + if (element.classList.contains('show')) { + element.classList.remove('show'); + } else { + element.classList.add('show'); +/* jsonrpcRequest('funcEditor', { action: 'add', side: '', pluginName: '' }).then(pluginsText => { + let plugins = pluginsText.trim().split("\n"); + element.innerHTML = `
{{plugin_name_guidelines}}

{{used_plugin_names}}
`; + plugins.forEach(plugin => { + let div = document.createElement('div'); + div.innerHTML = plugin; + element.appendChild(div); + }); + }); */ + } +} + +document.getElementById('pluginCreateLeftFun_d').onclick = function() { pluginFun_d('pluginCreateLeftName', 'left-float', 'pluginCreateLeftTitle', ' {{plugin_created_left_suffix}}', 'create', 'pluginCreateLeft_d'); }; +document.getElementById('pluginAddLeftFun_d').onclick = function() { pluginFun_d('pluginAddLeftName', 'left-float', 'pluginAddLeftTitle', ' {{plugin_added_left_suffix}}', 'add', 'pluginAddLeft_d'); }; +document.getElementById('pluginCreateRightFun_d').onclick = function() { pluginFun_d('pluginCreateRightName', 'right-float', 'pluginCreateRightTitle', ' {{plugin_created_right_suffix}}', 'create', 'pluginCreateRight_d'); }; +document.getElementById('pluginAddRightFun_d').onclick = function() { pluginFun_d('pluginAddRightName', 'right-float', 'pluginAddRightTitle', ' {{plugin_added_right_suffix}}', 'add', 'pluginAddRight_d'); }; + +function pluginFun_d(inputIdName, side_float, inputIdTitle, pluginText, action, pluginAddSide_d) { + let pluginName = document.getElementById(inputIdName).value.trim(); + let pluginTitle = document.getElementById(inputIdTitle).value.trim(); + + if (pluginName === "") { + messageFunction(action === 'create' ? "{{plugin_name_empty_error}}" : "{{plugin_not_selected_error}}") + return; + } + + let allowedCharacters = /^[a-zA-Z0-9 _]*$/; + if (!allowedCharacters.test(pluginName)) { + messageFunction("{{plugin_name_guidelines}}") + return; + } + + if (action === 'create') { + jsonrpcRequest('checkFile', { path: 'plugin', nameFile: pluginName }) + .then(response => { + if (response.trim() === "true") { + messageFunction(pluginName + "{{plugin_name_exists_suffix}}"); + } else { + sendRequest('create', side_float, pluginName, pluginTitle, pluginText); + } + }); + } else { + pluginHtml('add', pluginName, side_float, pluginTitle); + inter(); + } + document.getElementById(pluginAddSide_d).style.visibility = "hidden"; +} +/* if (pluginTitle === "") { + messageFunction("{{plugin_title_empty_error}}"); + return; + } */ + +function sendRequest(action, side_float, pluginName, pluginTitle, pluginText) { + jsonrpcRequest('createPlugin', { pluginName, side: side_float, pluginTitle, pluginText }).then(response => { + if (response.trim() === "Plugin created: " + pluginName) { + pluginHtml('create', pluginName, side_float, pluginTitle); + inter(); + } + }); +} +function pluginHtml(action, pluginName, side_float, pluginTitle) { + let sideFloat = document.getElementById(side_float); + let sideFloatElement = sideFloat; + + let pluginUrl = document.createElement("div"); + pluginUrl.classList.add('plugin-url'); + pluginUrl.pluginUrl = '/plugin/' + pluginName + '/'; + + let br = document.createElement("br"); + let tclass = null; + if (pluginTitle != "") { + tclass = document.createElement("div"); + tclass.setAttribute("tclass", 'tclass'); + tclass.setAttribute("plugin-title", 'pluginTitle'); + tclass.className = 'btitle'; + tclass.textContent = pluginTitle; + } + + let bclass = document.createElement("div"); + bclass.setAttribute("bclass", 'bclass'); + bclass.className = 'bfloat'; + + let bcont = document.createElement("div"); + bcont.className = 'bcont'; + + sideFloatElement.appendChild(pluginUrl); + if (tclass) { + pluginUrl.appendChild(tclass); + } + pluginUrl.appendChild(bclass); + pluginUrl.appendChild(br); + bclass.appendChild(bcont); + + if (action === 'add') { + jsonrpcRequest('getPlugin', { pluginName2: pluginName }).then(pluginContent => { + bcont.innerHTML = pluginContent; + }); + } else { + let pluginEditable = document.createElement("div"); + pluginEditable.className = 'pluginEditable'; + pluginEditable.contentEditable = 'true'; + bcont.appendChild(pluginEditable); + } +} + +for (let i = 0; i < editId.length; i++) { + if (document.getElementById(editId[i])) { + document.getElementById(editId[i]).onclick = function() { editFun(editId[i]); }; + } +} + +function editFun(whichEditId) { + for (let i = 0; i < editId.length; i++) { + if (whichEditId === editId[i]) { + if (editMode != i) { + editFun1_1(i); + } else { + editFun1_2(i); + } + + } else { + editFun3(i); + } + + if (i == 3 && editMode != 3) { + editFun4(i); + } + if (editMode != 0 && editMode != 2 && editMode != 3) { + editFun5(i); + } + } +} + +function editFun1_1(i) { + editMode = i; + document.getElementById(editId[i]).classList.add('active'); +} +function editFun1_2(i) { + editMode = -1; + document.getElementById(editId[i]).classList.remove('active'); +} +/* function editFun2_1(i) { + let pluginElements = document.querySelectorAll('[plugin-url]'); + for (let i = 0; i < pluginElements.length; i++) { + let pluginTitleElement = pluginElements[i].querySelector('[plugin-title]'); + if (pluginTitleElement) { + let pluginUrl = pluginElements[i].getAttribute('plugin-url'); + let newDiv = document.createElement('div'); + newDiv.className = 'pluginTitleUrl'; + newDiv.textContent = pluginUrl; + pluginTitleElement.insertAdjacentElement('afterbegin', newDiv); + } + } +} */ +function editFun3(i) { + /* document.getElementById(editId[i]).classList.remove('active'); */ +} +function editFun4(i) { +} +function editFun5(i) { + pluginDropdownContentId.style.backgroundColor = ''; +} + +let pluginTakeCheck = 0; +let targetElement; +document.onclick = function(event) { +if (editMode === 0) { + yourFunction(event); +} + +async function yourFunction(event) { + let target = event.target; + let pluginElement = target.closest('.plugin-url'); + if (pluginElement) { + messageQueue.push("{{delete_plugin_confirm}}"); + if (await messageCreateQuestion()) { + pluginElement.remove(); + + /* let floatElements = [document.querySelector('.right-float'), document.querySelector('.left-float')]; + floatElements.forEach(element => { + if (element && element.children.length === 0 && element.textContent.trim() === "") { + element.remove(); + } + }); */ + + inter(); + } + } +} + + + if (editMode === 1) { +/* let target = event.target; + let pluginTitle = target.closest('[plugin-title]'); + let mainTitle = target.closest('#mainTitle'); + + let secondDiv = pluginTitle ? pluginTitle.closest('div').parentElement.closest('div') : null; + let thirdDiv = secondDiv ? secondDiv.parentElement.closest('div') : null; + let allDivsInParent = secondDiv ? Array.from(secondDiv.parentElement.children).filter(child => child.tagName === 'DIV') : []; + let indexOfSecondDiv = secondDiv ? allDivsInParent.indexOf(secondDiv) : null; + let classOfThirdDiv = thirdDiv ? thirdDiv.className.replace(/-float/g, '') : null; + + if (pluginTitle || mainTitle) { + let editTitle = mainTitle ? mainTitle : pluginTitle; + let whichTitle = mainTitle ? "mainTitle" : "pluginTitle"; + console.log(whichTitle+" "+functionOpenPage); + + if (whichTitle === "mainTitle" && functionOpenPage === true) { + messageFunction("{{open_page}}"); + } else { + let title = prompt("{{enter_new_title}}", editTitle.textContent.trim()); + if (title !== null) { + let newTitle = title.trim(); + + if (newTitle !== "") { + jsonrpcRequest('newTitle', { newTitle, whichTitle, side: classOfThirdDiv, pluginNumber: indexOfSecondDiv }).then(response => { + console.log(response); + editTitle.innerHTML = newTitle; + messageFunction("{{title_saved}}") + inter(); + }); + } else { + messageFunction("{{plugin_title_empty_error}}"); + } + + } + } + + } */ + } + + if (editMode === 2 && pluginTakeCheck == 0) { + let pluginElement = event.target.closest('.plugin-url'); + + if (pluginElement) { + pluginElement.style.border = '3px dashed #000000'; + pluginElement.classList.add('pluginElementl'); + + let indicator = document.createElement("div"); + indicator.style.width = '20px'; + indicator.style.height = '20px'; + indicator.style.position = 'absolute'; + indicator.style.left = (event.clientX - 10) + 'px'; + indicator.style.top = (event.clientY - 10) + 'px'; + indicator.style.backgroundImage = "url(../../img/pict/b_iconslyb.svg)"; + indicator.style.backgroundPosition = "0px -80px"; + indicator.style.pointerEvents = "none"; + document.body.appendChild(indicator); + + function pointerMove(event) { + indicator.style.left = (event.clientX - 10) + 'px'; + indicator.style.top = (event.clientY - 10) + 'px'; + + let dropTarget = document.elementFromPoint(event.clientX, event.clientY); + let leftFloatElement = document.getElementById('left-float'); + let rightFloatElement = document.getElementById('right-float'); + let isLeftFloat = leftFloatElement ? leftFloatElement.contains(dropTarget) : false; + let isRightFloat = rightFloatElement ? rightFloatElement.contains(dropTarget) : false; + + if (isLeftFloat || isRightFloat) { + let targetCheck = document.elementFromPoint(event.clientX, event.clientY).closest('.plugin-url'); + let floatElement = isLeftFloat ? leftFloatElement : rightFloatElement; + + if (pluginElement !== targetCheck) { + pluginTakeCheck = 1; + } + + pluginElement.classList.remove('pluginElementl'); + + if (targetCheck) { + let side = getTargetSide(targetCheck, event.clientY); + + if (side === 0) { + if (targetCheck.parentNode === floatElement) { + floatElement.insertBefore(pluginElement, targetCheck.nextSibling); + } else { + floatElement.appendChild(pluginElement); + } + indicator.style.backgroundPosition = "-40px -80px"; + } else if (side === 1) { + if (targetCheck.parentNode === floatElement) { + floatElement.insertBefore(pluginElement, targetCheck); + } else { + floatElement.appendChild(pluginElement); + } + indicator.style.backgroundPosition = "0px -80px"; + } + } else { + floatElement.appendChild(pluginElement); + } + +/* let floatElements = [document.querySelector('.right-float'), document.querySelector('.left-float')]; + floatElements.forEach(element => { + if (element && element.children.length === 0 && element.textContent.trim() === "") { + element.remove(); + } + }); */ + } + } + + document.addEventListener('pointermove', pointerMove); + document.addEventListener('pointerup', function pointerup() { + document.removeEventListener('pointermove', pointerMove); + document.removeEventListener('pointerup', pointerup); + + pluginElement.style.border = ''; + pluginElement.style.padding = ''; + indicator.remove(); + inter(); + }); + } + } + pluginTakeCheck = 0; + + if (editMode === 3) { + } + + let table = event.target.closest('table'); + if (table) { + let rowIndex, cellIndex; + let targetRow = event.target.closest('tr'); + let targetCell = event.target.closest('td'); + + if (targetRow) { + rowIndex = Array.from(targetRow.parentNode.children).indexOf(targetRow); + } + + if (targetCell) { + cellIndex = Array.from(targetCell.parentNode.children).indexOf(targetCell); + } + + if (editMode === 4 && targetRow) { + let row = table.insertRow(rowIndex + 1); + let cellCount = targetRow.cells.length; + for (let i = 0; i < cellCount; i++) { + let newCell = row.insertCell(i); + if (targetRow.cells.length > 0) { + let referenceCell = targetRow.cells[i]; + newCell.style.cssText = referenceCell.style.cssText; + } + } + } + + if (editMode === 5 && targetRow) { + if (table.rows.length > 1) { + table.deleteRow(rowIndex); + } + } + + if (editMode === 6 && targetCell) { + for (let i = 0; i < table.rows.length; i++) { + let row = table.rows[i]; + let newCell = row.insertCell(cellIndex + 1); + if (row.cells.length > cellIndex) { + let referenceCell = row.cells[cellIndex]; + newCell.style.cssText = referenceCell.style.cssText; + } + } + } + + if (editMode === 7 && targetCell) { + if (targetCell.parentNode.cells.length > 1) { + for (let i = 0; i < table.rows.length; i++) { + let row = table.rows[i]; + if (row.cells.length > cellIndex) { + row.deleteCell(cellIndex); + } + } + } + } + + inter(); + } + +}; + +function getTargetSide(targetCheck, mouseY) { + if (targetCheck) { + let targetRect = targetCheck.getBoundingClientRect(); + let targetY = targetRect.top + targetRect.height / 2; + return mouseY < targetY ? 1 : 0; + } else { + return -1; + } +} + +/* выделение элементов */ +let clipboard = ['', ''] +let selectedElement = null +let selectedElementOriginalOutline = '' +let selectedElementCut = '' + +document.addEventListener('contextmenu',editingElements) +function editingElements(event) { + var editable = event.target.closest('[contenteditable="true"]') + if (!editable) return + event.preventDefault() + var menu = document.getElementById('editingMenuItems') + var copy = document.getElementById('editingMenuItemsCopy') + var cut = document.getElementById('editingMenuItemsCut') + var paste = document.getElementById('editingMenuItemsPaste') + copy.style.display = 'none' + cut.style.display = 'none' + paste.style.display = 'none' + var element = event.target.closest('hr, img, table') + + if (editable && element) { + if (selectedElement && selectedElement !== element) { + selectedElement.style.outline = selectedElementOriginalOutline + } + selectedElementOriginalOutline = element.style.outline || '' + element.style.outline = '1px dashed black' + selectedElement = element + menu.style.visibility = 'visible' + copy.style.display = '' + cut.style.display = '' + if (clipboard[0]) paste.style.display = '' + } else if (editable && clipboard[0]) { + if (selectedElement) { + selectedElement.style.outline = selectedElementOriginalOutline + selectedElement = null + } + menu.style.visibility = 'visible' + paste.style.display = '' + } else { + if (selectedElement) { + selectedElement.style.outline = selectedElementOriginalOutline + selectedElement = null + } + menu.style.visibility = 'hidden' + } + + targetElement = null + if (element) { + targetElement = element + var sel = window.getSelection() + var range = document.createRange() + range.selectNode(targetElement) + sel.removeAllRanges() + sel.addRange(range) + } + document.querySelectorAll('.elementEditPanelElement').forEach(function(panel) { + panel.style.display = 'none' + document.getElementById('editingMenuItemsHr').style.display = 'none' + }) + if (targetElement !== null && event.target.closest('[contenteditable="true"]')) { + editElement() + } + + const pad=10 + const menuRect=menu.getBoundingClientRect() + let x=(event.clientX!==undefined?event.clientX:touchX) + let y=(event.clientY!==undefined?event.clientY:touchY) + let left=Math.min(x,window.innerWidth-menuRect.width-pad) + let top=Math.min(y,window.innerHeight-menuRect.height-pad) + if (!isPhone) { + menu.style.left = `${Math.max(pad, left)}px` + menu.style.top = `${Math.max(pad, top)}px` + } else { + menu.style.top = '30%' + menu.style.left = '0' + menu.style.right = '0' + menu.style.marginLeft = 'auto' + menu.style.marginRight = 'auto' + menu.style.width = 'calc(100% - 20px)' + menu.style.maxWidth = 'max-content' + } +} + +function editElement() { + var panelMap = { + 'HR': 'elementEditPanelHr', + 'IMG': 'elementEditPanelImg', + 'TABLE': 'elementEditPanelTable' + } + var panelId = panelMap[targetElement.tagName] + if (panelId) { + var panel = document.getElementById(panelId) + if (panel) { + panel.style.display = '' + document.getElementById('editingMenuItemsHr').style.display = '' + } + } + if (panelId === 'elementEditPanelHr') { + document.getElementById('hr1Edit').value = parseInt(targetElement.style.height, 10) || 1 + document.getElementById('hr2Edit').value = targetElement.style.width || '95%' + document.getElementById('hr3cEdit').value = targetElement.style.backgroundColor + ? rgbToHex(targetElement.style.backgroundColor) + : '#000000' + document.getElementById('hrMarginTopEdit').value = parseInt(targetElement.style.marginTop, 10) || 0 + document.getElementById('hrMarginRightEdit').value = parseInt(targetElement.style.marginRight, 10) || 0 + document.getElementById('hrMarginBottomEdit').value = parseInt(targetElement.style.marginBottom, 10) || 0 + document.getElementById('hrMarginLeftEdit').value = parseInt(targetElement.style.marginLeft, 10) || 0 + var m = targetElement.style.margin + if (m === '0.5em auto 0.5em 0px') { + document.getElementById('hr4Edit').value = 'left_clear' + } else if (m === '0.5em 0px 0.5em auto') { + document.getElementById('hr4Edit').value = 'right_clear' + } else if (targetElement.style.display === 'inline-block' + && targetElement.style.verticalAlign === 'middle') { + document.getElementById('hr4Edit').value = 'left_text' + } else { + document.getElementById('hr4Edit').value = 'center_clear' + } + } + if (panelId === 'elementEditPanelImg') { + document.getElementById('ima1Edit').value = targetElement.src || '' + document.getElementById('ima6Edit').value = parseInt(targetElement.style.width, 10) || 250 + document.getElementById('ima6aEdit').value = parseInt(targetElement.style.height, 10) || '' + document.getElementById('ima7Edit').value = parseInt(targetElement.style.borderWidth, 10) || 0 + document.getElementById('ima8cEdit').value = targetElement.style.borderColor + ? rgbToHex(targetElement.style.borderColor) + : '#000000' + document.getElementById('imaMarginTopEdit').value = parseInt(targetElement.style.marginTop, 10) || 0 + document.getElementById('imaMarginRightEdit').value = parseInt(targetElement.style.marginRight, 10) || 0 + document.getElementById('imaMarginBottomEdit').value = parseInt(targetElement.style.marginBottom, 10) || 0 + document.getElementById('imaMarginLeftEdit').value = parseInt(targetElement.style.marginLeft, 10) || 0 + document.getElementById('ima4Edit').value = targetElement.style.float + ? (targetElement.style.float === 'left' ? 'left_clear' + : 'right_clear') + : 'center_clear' + var link = targetElement.closest('a') + document.getElementById('imaLinkEdit').value = link ? link.href : '' + var captionEl = targetElement.nextElementSibling + } + if (panelId === 'elementEditPanelTable') { + document.getElementById('tab1Edit').value = targetElement.style.width || '50%' + document.getElementById('tabMarginTopEdit').value = parseInt(targetElement.style.marginTop, 10) || 0 + document.getElementById('tabMarginRightEdit').value = parseInt(targetElement.style.marginRight, 10) || 0 + document.getElementById('tabMarginBottomEdit').value = parseInt(targetElement.style.marginBottom, 10) || 0 + document.getElementById('tabMarginLeftEdit').value = parseInt(targetElement.style.marginLeft, 10) || 0 + document.getElementById('tab9Edit').value = parseInt(targetElement.style.borderWidth, 10) || 1 + document.getElementById('tab11cEdit').value = targetElement.style.backgroundColor + ? rgbToHex(targetElement.style.backgroundColor) + : '#000000' + var firstCell = targetElement.querySelector('td') + document.getElementById('tab4Edit').value = firstCell + ? parseInt(firstCell.style.padding, 10) || 1 + : 1 + document.getElementById('tab10cEdit').value = firstCell + ? rgbToHex(firstCell.style.borderColor) + : '#000000' + document.getElementById('tab6Edit').value = targetElement.style.float + ? (targetElement.style.float === 'left' ? 'left_clear' + : 'right_clear') + : 'center_clear' + } +} + +/* меню изменение элемнтов */ +document.addEventListener('pointerdown', clearMenu) +document.addEventListener('keydown', clearMenu) +function clearMenu(event) { + if (event.type === 'pointerdown' && event.button !== 0) { + return; + } + if (event.target.closest('#editingMenuItems')) { + return; + } + var menu = document.getElementById("editingMenuItems"); + if (selectedElement) { + selectedElement.style.outline = selectedElementOriginalOutline; + selectedElement = null; + } + if (menu) menu.style.visibility = "hidden"; +} + +document.getElementById("editingMenuItemsCopy").addEventListener('click', function() { + if (selectedElement) { + clipboard = [selectedElement.cloneNode(true), 'copy']; + } +}); + +document.getElementById("editingMenuItemsCut").addEventListener('click', function() { + if (selectedElement) { + clipboard = [selectedElement.cloneNode(true), 'cut']; + selectedElementCut = selectedElement; + } +}); + +document.getElementById("editingMenuItemsPaste").addEventListener('click', function() { + if (clipboard && clipboard[0]) { + var sel = window.getSelection(); + if (!sel.rangeCount) return; + var range = sel.getRangeAt(0); + range.collapse(false); + range.insertNode(clipboard[0]); + if (clipboard[1] == 'cut' && selectedElementCut) { + selectedElementCut.remove(); + selectedElementCut = null; + } + clipboard[0] = clipboard[0].cloneNode(true); + document.getElementById("editingMenuItems").style.visibility = "hidden"; + } +}); + +//редактирования меню страниц +/* document.getElementById("contentPageCreateFun_d").addEventListener("click", function() { + inter(); +}); +document.getElementById("contentPageMove").addEventListener("click", function() { + inter(); +}); +document.getElementById("contentPageSettingsFun_d").addEventListener("click", function() { + inter(); +}); */ + +// панель редактирования для элементов +document.getElementById("buthrEdit").addEventListener("click", function() { + let hr1_v = document.getElementById("hr1Edit").value + let hr2_v = document.getElementById("hr2Edit").value + let hr3_v = document.getElementById("hr3cEdit").value + let hr4_v = document.getElementById("hr4Edit").value + let mt = document.getElementById("hrMarginTopEdit").value + let mr = document.getElementById("hrMarginRightEdit").value + let mb = document.getElementById("hrMarginBottomEdit").value + let ml = document.getElementById("hrMarginLeftEdit").value + + let style = "" + style += "height: " + (hr1_v || 1) + "px; " + if (hr2_v) style += "width: " + hr2_v + "; " + style += "background: " + hr3_v + "; " + style += "margin: " + (mt||0) + "px " + (mr||0) + "px " + (mb||0) + "px " + (ml||0) + "px; " + + switch (hr4_v) { + case "left_clear": style += "margin-left: 0; "; break + case "right_clear": style += "margin-right: 0; "; break + case "center_clear": style += "position: relative; left: 50%; transform: translateX(-50%); "; break + case "left_text": style += "display: inline-block; vertical-align: middle; float: left; "; break + case "right_text": style += "display: inline-block; vertical-align: middle; float: right; "; break + case "text": style += "display: inline-block; vertical-align: middle; "; break + } + + style += "border: 0;" + change(targetElement, style, "") + inter() +}) + +document.getElementById("butimaEdit").addEventListener("click", function() { + let url = document.getElementById("ima1Edit").value + let pos = document.getElementById("ima4Edit").value + let mt = document.getElementById("imaMarginTopEdit").value + let mr = document.getElementById("imaMarginRightEdit").value + let mb = document.getElementById("imaMarginBottomEdit").value + let ml = document.getElementById("imaMarginLeftEdit").value + let w = document.getElementById("ima6Edit").value + let h = document.getElementById("ima6aEdit").value + let bw = document.getElementById("ima7Edit").value + let bc = document.getElementById("ima8cEdit").value + let link = document.getElementById("imaLinkEdit").value + + if (!url) { + messageFunction("{{insert_url}}") + return + } + + let style = "" + if (pos === "left_clear") style += "float: left; " + if (pos === "right_clear") style += "float: right; " + if (pos === "center_clear") style += "position: relative; left: 50%; transform: translateX(-50%); margin-top: " + (mt||0) + "px; display: block; " + if (pos === "left_text") style += "float: left; display: inline-block; vertical-align: middle; " + if (pos === "right_text") style += "float: right; display: inline-block; vertical-align: middle; " + if (pos === "text") style += "vertical-align: middle; display: inline-block; " + if (pos !== "center_clear") style += "margin: " + (mt||0) + "px " + (mr||0) + "px " + (mb||0) + "px " + (ml||0) + "px; " + + if (w) style += "width: " + w + "px; " + if (h) style += "height: " + h + "px; " + if (bw) style += "border: " + bw + "px solid " + bc + "; " + + change(targetElement, style, url) + + if (link) { + let a = document.createElement("a") + a.href = link + targetElement.parentNode.insertBefore(a, targetElement) + a.appendChild(targetElement) + } + + inter() +}) + + +document.getElementById("butabEdit").addEventListener("click", function() { + let width_v = document.getElementById("tab1Edit").value + let mt = document.getElementById("tabMarginTopEdit").value + let mr = document.getElementById("tabMarginRightEdit").value + let mb = document.getElementById("tabMarginBottomEdit").value + let ml = document.getElementById("tabMarginLeftEdit").value + let pad_i_v = document.getElementById("tab4Edit").value + let float_v = document.getElementById("tab6Edit").value + let border_v = document.getElementById("tab9Edit").value + let bc_v = document.getElementById("tab10cEdit").value + let bg_v = document.getElementById("tab11cEdit").value + + let style = "" + if (width_v) style += "width: " + width_v + "; " + if (float_v === "left_clear") style += "float: left; " + if (float_v === "right_clear") style += "float: right; " + if (float_v === "center_clear") style += "position: relative; left: 50%; transform: translateX(-50%); " + if (float_v === "left_text") style += "float: left; display: inline-table; vertical-align: middle; " + if (float_v === "right_text") style += "float: right; display: inline-table; vertical-align: middle; " + if (float_v === "text") style += "display: inline-table; vertical-align: middle; " + if (float_v !== "center_clear") style += "margin: " + (mt||0) + "px " + (mr||0) + "px " + (mb||0) + "px " + (ml||0) + "px; " + + if (border_v) style += "border: " + border_v + "px solid " + bc_v + "; " + if (bg_v) style += "background-color: " + bg_v + "; " + style += "border-collapse: collapse;" + + change(targetElement, style, "") + + let cells = targetElement.querySelectorAll("td") + cells.forEach(function(cell) { + let cellStyle = "" + if (pad_i_v) cellStyle += "padding: " + pad_i_v + "px; " + if (border_v) cellStyle += "border: " + border_v + "px solid " + bc_v + "; " + cell.style.cssText = cellStyle + }) + + inter() +}) + +function change(element, style, src) { + if (element) { + if (style) element.style.cssText = style + if (src) element.src = src + } +} + +function rgbToHex(rgb) { + let rgbArray = rgb.match(/\d+/g); + return "#" + rgbArray.map(x => { + let hex = parseInt(x).toString(16); + return hex.length === 1 ? "0" + hex : hex; + }).join(''); +} + +/* const visibility = sessionStorage.getItem('basis3_visibility'); +if (visibility === "visible" && document.getElementById("siteSettingsButton")) { + basisVis(); +} */ +}, { once: true }); //addEventListener("LoadeditorJs", function()' + +/** @brief Список редактируемых элементов */ +let editableElduyjements; + +addEventListener("LoadeditorJs", function() +{ + +document.querySelectorAll('.swit').forEach(btn => { + btn.addEventListener('click', () => { + const target = document.getElementById(btn.id + '_d'); + if (!target) return; + target.style.display = + (getComputedStyle(target).display === 'none') ? '' : 'none'; + }); +}); + +const container = document.querySelector('.toolbar-container'); +const panel = document.getElementById('panel'); +const arrowLeft = document.getElementById('arrow-left'); +const arrowRight = document.getElementById('arrow-right'); +let interval; +let offset = 0; + +function getBounds() { + const containerWidth = container.scrollWidth; + const panelWidth = panel.clientWidth; + const arrowWidth = arrowLeft.clientWidth; + const extra = arrowWidth; + const maxOffset = 24; + const minOffset = panelWidth - containerWidth - extra; + return { containerWidth, panelWidth, maxOffset, minOffset }; +} + +function updateArrowsVisibility() { + const { containerWidth, panelWidth, minOffset, maxOffset } = getBounds(); + + if (containerWidth <= panelWidth) { + arrowLeft.style.display = 'none'; + arrowRight.style.display = 'none'; + panel.style.overflowX = 'visible'; + offset = 0; + container.style.transform = 'translateX(0px)'; + } else { + arrowLeft.style.display = 'inline-flex'; + arrowRight.style.display = 'inline-flex'; + panel.style.overflowX = 'clip'; + if (offset > maxOffset) offset = maxOffset; + if (offset < minOffset) offset = minOffset; + } +} + +const events = ['resize', 'scroll', 'pointerdown', 'pointerup', 'pointermove', 'keydown', 'touchstart']; +events.forEach(evt => { + window.addEventListener(evt, updateArrowsVisibility, { passive: true }); + document.addEventListener(evt, updateArrowsVisibility, { passive: true }); +}); +if (window.visualViewport) { + window.visualViewport.addEventListener('resize', updateArrowsVisibility); +} + +updateArrowsVisibility(); + +function startScroll(direction) { + const { maxOffset, minOffset } = getBounds(); + interval = setInterval(() => { + if (direction === 'left') { + offset += 10; + } else { + offset -= 10; + } + if (offset > maxOffset) offset = maxOffset; + if (offset < minOffset) offset = minOffset; + container.style.transform = `translateX(${offset}px)`; + }, 16); +} + +function stopScroll() { + clearInterval(interval); +} + +arrowLeft.addEventListener('pointerdown', e => { + if (e.pointerType === 'touch') e.preventDefault(); + startScroll('left'); +}); +arrowLeft.addEventListener('pointerup', stopScroll); +arrowLeft.addEventListener('pointerleave', stopScroll); +arrowLeft.addEventListener('pointercancel', stopScroll); +arrowLeft.addEventListener('contextmenu', e => { + if (e.pointerType === 'touch') e.preventDefault(); +}); + +arrowRight.addEventListener('pointerdown', e => { + if (e.pointerType === 'touch') e.preventDefault(); + startScroll('right'); +}); +arrowRight.addEventListener('pointerup', stopScroll); +arrowRight.addEventListener('pointerleave', stopScroll); +arrowRight.addEventListener('pointercancel', stopScroll); +arrowRight.addEventListener('contextmenu', e => { + if (e.pointerType === 'touch') e.preventDefault(); +}); + + +}, { once: true }); + + +/** @brief Простые стили текста */ +const simpleFormats = [ + { id: 'bol', style: { fontWeight: 'bold' }, prop: 'font-weight', test: v => (parseInt(v) >= 700 || v === 'bold') }, + { id: 'ital', style: { fontStyle: 'italic' }, prop: 'font-style', test: v => v === 'italic' }, + { id: 'under', style: { textDecorationLine: 'underline' },prop: 'text-decoration-line', test: v => v.split(' ').includes('underline') }, + { id: 'strik', style: { textDecorationLine: 'line-through' },prop: 'text-decoration-line', test: v => v.split(' ').includes('line-through') }, + { id: 'sup', style: { verticalAlign: 'super' }, prop: 'vertical-align', test: v => v === 'super' }, + { id: 'sub', style: { verticalAlign: 'sub' }, prop: 'vertical-align', test: v => v === 'sub' } +]; +/** @brief Стили выравнивания для блоков */ +const divFormats = [ + { id: 'equal', style: { textAlign: 'left' } }, + { id: 'equac', style: { textAlign: 'center' } }, + { id: 'equar', style: { textAlign: 'right' } }, + { id: 'equaj', style: { textAlign: 'justify'} } +]; +/** @brief Стили списков */ +const listFormats = [ + { id: 'listNone', style: { listStyleType: 'none' } }, + { id: 'listDots', style: { listStyleType: 'disc' } }, + { id: 'listNumbers', style: { listStyleType: 'decimal' } }, + { id: 'listLetters', style: { listStyleType: 'lower-alpha'} } +]; +/** @brief Отдельные свойства текста */ +const singleFormats = [ + { id: 'ff', prop: 'font-family'}, + { id: 'fs', prop: 'font-size'} +]; +/** @brief Специальные форматы */ +const specialFormats = ['butlink', 'linkdel', 'forma', 'col', 'backgr']; + +addEventListener("LoadeditorJs", function() { +const content = document.getElementById('content'); + +simpleFormats.forEach(f => { + document.getElementById(f.id).addEventListener('click', () => { + const sel = window.getSelection(); + if (!sel.rangeCount) return; + const range = sel.getRangeAt(0); + if (!content.contains(range.commonAncestorContainer)) return; + let all = true; + const it = document.createNodeIterator( + range.commonAncestorContainer, + NodeFilter.SHOW_ALL, + { acceptNode: n => range.intersectsNode(n) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT } + ); + let n; + while (n = it.nextNode()) { + if (n.nodeType === Node.TEXT_NODE && n.textContent.trim()) { + let cur = n.parentElement, ok = false; + while (cur) { + const v = getComputedStyle(cur)[f.prop] || ''; + if (f.test(v)) { ok = true; break; } + cur = cur.parentElement; + } + if (!ok) { all = false; break; } + } + } + all ? simpleUnformat(range, f) : simpleApplyformat(range, f); + sel.removeAllRanges(); + sel.addRange(range); + inter(); + }); +}); + +divFormats.forEach(f => { + document.getElementById(f.id).addEventListener('click', () => { + const sel = window.getSelection(); + if (!sel.rangeCount) return; + const range = sel.getRangeAt(0); + if (!content.contains(range.commonAncestorContainer)) return; + divApplyformat(range, f); + inter(); + }); +}); + +listFormats.forEach(f => { + document.getElementById(f.id).addEventListener('click', () => { + const sel = window.getSelection(); + if (!sel.rangeCount) return; + const range = sel.getRangeAt(0); + if (!content.contains(range.commonAncestorContainer)) return; + listApplyformat(range, f); + inter(); + }); +}); + +singleFormats.forEach(f => { + const el = document.getElementById(f.id) + el.addEventListener('click', e => { + const list = el.querySelector('.align-list') + if (!list || getComputedStyle(list).display === 'none') return + const cmdEl = e.target.closest('[data-cmd]') + if (!cmdEl) return + f.value = cmdEl.dataset.cmd + const sel = window.getSelection() + if (!sel.rangeCount) return + const range = sel.getRangeAt(0) + if (!content.contains(range.commonAncestorContainer)) return + singleApplyformat(range, f) + inter() + }) +}) + +specialFormats.forEach(f => { + document.getElementById(f).addEventListener('click', () => { + const sel = window.getSelection(); + if (!sel.rangeCount) return; + const range = sel.getRangeAt(0); + if (!content.contains(range.commonAncestorContainer)) return; + if (typeof document[f + 'Fun'] === 'function') document[f + 'Fun'](range); + else window[f + 'Fun'](range); + inter(); + }); +}); + +const events = ['pointerup','keyup','input','focus','blur','click']; +events.forEach(evt => { + if (!content) return; + content.addEventListener(evt, () => { + updateToolbarStyles(); + updateSingleSelectors(); + }); +}); + +}, { once: true }); + +/////////////////// Начало блока, выполняющего навигацию по внесенным изменениям ==================== + +/** @brief История изменений контента */ +let arr = [] +/** @brief Текущий индекс в истории изменений */ +let currentIndex = 0 + +/** @brief Сохраняет текущее состояние контента, если оно изменилось */ +function inter() { + const editable = document.getElementById("content") + if (editable) { + let currentContent = editable.innerHTML + if (currentContent !== arr[currentIndex]) { + currentIndex++ + arr = arr.slice(0, currentIndex) + arr.push(currentContent) + } + } +} + +if (document.getElementById("content")) { + arr[0] = document.getElementById("content").innerHTML +} + +document.getElementById("forw").addEventListener("click", function() { + if (currentIndex < arr.length - 1) { + currentIndex++ + const editable = document.getElementById("content") + editable.innerHTML = arr[currentIndex] + editable.setAttribute("contenteditable", "true") + } +}) + +document.getElementById("bac").addEventListener("click", function() { + if (currentIndex > 0) { + currentIndex-- + const editable = document.getElementById("content") + editable.innerHTML = arr[currentIndex] + editable.setAttribute("contenteditable", "true") + } +}) + +/////////////////// Конец блока, выполняющего навигацию по внесенным изменениям ==================== + +/** + * @brief Применяет форматирование к выделенному диапазону текста + * @param range Диапазон выделения текста + * @param createElement Функция создания нового элемента для форматирования +*/ +function applyformat(range, createElement) { + const arr = [], it = document.createNodeIterator( + range.commonAncestorContainer, + NodeFilter.SHOW_TEXT, + n => range.intersectsNode(n) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT + ); + let n; + while (n = it.nextNode()) arr.push(n); + let firstEl, lastEl; + arr.forEach((tn, i) => { + const p = tn.parentNode; + const start = tn === range.startContainer ? range.startOffset : 0; + const end = tn === range.endContainer ? range.endOffset : tn.textContent.length; + let newEl; + if (tn === range.startContainer && tn === range.endContainer) { + const b = tn.splitText(start), m = b.splitText(end - start); + newEl = createElement(); + newEl.textContent = b.textContent; + p.replaceChild(newEl, b); + p.insertBefore(m, newEl.nextSibling); + } else if (tn === range.startContainer) { + const aNode = tn.splitText(start); + newEl = createElement(); + newEl.textContent = aNode.textContent; + p.replaceChild(newEl, aNode); + } else if (tn === range.endContainer) { + const b = tn.splitText(end); + newEl = createElement(); + newEl.textContent = tn.textContent; + p.replaceChild(newEl, tn); + p.insertBefore(b, newEl.nextSibling); + } else { + newEl = createElement(); + newEl.textContent = tn.textContent; + p.replaceChild(newEl, tn); + } + if (i === 0) firstEl = newEl; + if (i === arr.length - 1) lastEl = newEl; + }); + if (firstEl && lastEl) { + range.setStartBefore(firstEl); + range.setEndAfter(lastEl); + } + mergeTextNodes(range.commonAncestorContainer); +} + +/** + * @brief Применяет простой стиль (bold, italic и т.д.) к диапазону текста + * @param range Диапазон выделения текста + * @param format Объект с описанием формата +*/ +function simpleApplyformat(range, format) { + const span = document.createElement('span'); + Object.assign(span.style, format.style); + applyformat(range, () => span.cloneNode()); +} + +/** + * @brief Убирает простой стиль (bold, italic и т.д.) из диапазона текста + * @param range Диапазон выделения текста + * @param format Объект с описанием формата +*/ +function simpleUnformat(range, format) { + const { prop, test } = format; + + const spans = new Set(); + const it = document.createNodeIterator( + range.commonAncestorContainer, + NodeFilter.SHOW_TEXT, + n => { + if (!range.intersectsNode(n)) return NodeFilter.FILTER_REJECT; + let node = n.parentNode; + while (node && node !== range.commonAncestorContainer) { + if (node.tagName === 'SPAN' && test(node.style.getPropertyValue(prop) || '')) { + return NodeFilter.FILTER_ACCEPT; + } + node = node.parentNode; + } + return NodeFilter.FILTER_REJECT; + } + ); + + let tn; + while (tn = it.nextNode()) { + let node = tn.parentNode; + while (node && node !== range.commonAncestorContainer) { + if (node.tagName === 'SPAN' && test(node.style.getPropertyValue(prop) || '')) { + if (range.intersectsNode(node)) { + spans.add(node); + } + } + node = node.parentNode; + } + } + + spans.forEach(span => { + const full = span.textContent; + let total = 0, startAbs = 0, endAbs = full.length; + const walker = document.createTreeWalker(span, NodeFilter.SHOW_TEXT, null); + let t; + while (walker.nextNode()) { + t = walker.currentNode; + if (t === range.startContainer) startAbs = total + range.startOffset; + if (t === range.endContainer) endAbs = total + range.endOffset; + total += t.textContent.length; + } + if (startAbs >= endAbs) return; + + const bef = full.slice(0, startAbs); + const sel = full.slice(startAbs, endAbs); + const aft = full.slice(endAbs); + + const p = span.parentNode; + if (!p) return; + + function cloneWithText(node, text) { + const clone = node.cloneNode(false); + for (let child of node.childNodes) { + if (text.length === 0) break; + if (child.nodeType === Node.TEXT_NODE) { + const len = child.textContent.length; + const take = text.slice(0, len); + clone.appendChild(document.createTextNode(take)); + text = text.slice(len); + } else { + const sub = child.textContent; + const taken = text.slice(0, sub.length); + clone.appendChild(cloneWithText(child, taken)); + text = text.slice(sub.length); + } + } + return clone; + } + + if (bef) p.insertBefore(cloneWithText(span, bef), span); + if (sel) { + const unwrapped = document.createDocumentFragment(); + const mid = cloneWithText(span, sel); + while (mid.firstChild) unwrapped.appendChild(mid.firstChild); + p.insertBefore(unwrapped, span); + } + if (aft) p.insertBefore(cloneWithText(span, aft), span); + span.remove(); + }); +} + +/** + * @brief Объединяет соседние текстовые узлы + * @param node Элемент, внутри которого объединяются текстовые узлы +*/ +function mergeTextNodes(node) { + let c = node.firstChild; + while (c) { + let nx = c.nextSibling; + if (c.nodeType === Node.TEXT_NODE) { + while (nx && nx.nodeType === Node.TEXT_NODE) { + c.textContent += nx.textContent; + const next = nx.nextSibling; + if (nx.parentNode) nx.parentNode.removeChild(nx); + nx = next; + } + } else if (c.nodeType === Node.ELEMENT_NODE) { + mergeTextNodes(c); + } + c = nx; + } +} + +/** + * @brief Применяет стиль выравнивания к блочным элементам + * @param range Диапазон выделения текста + * @param format Объект с описанием формата +*/ +function divApplyformat(range, format) { + const style = format.style; + if (!style || !style.textAlign) return; + const externals = new Set(); + const intersects = element => { + const er = document.createRange(); + er.selectNodeContents(element); + return range.compareBoundaryPoints(Range.END_TO_START, er) < 0 && + range.compareBoundaryPoints(Range.START_TO_END, er) > 0; + }; + + Array.from(content.children).forEach(child => { + if (intersects(child)) externals.add(child); + }); + + externals.forEach(div => { + div.style.textAlign = style.textAlign; + }); +} + +/** + * @brief Применяет стиль списка к выделенным элементам + * @param range Диапазон выделения текста + * @param format Объект с описанием формата +*/ +function listApplyformat(range, format) { + const intersects = el => { + const er = document.createRange(); + er.selectNodeContents(el); + return range.compareBoundaryPoints(Range.END_TO_START, er) < 0 && + range.compareBoundaryPoints(Range.START_TO_END, er) > 0; + }; + + const type = format.id; + + if (type === 'listNone') { + const lists = new Set(); + Array.from(content.querySelectorAll('li')).forEach(li => { + if (intersects(li)) lists.add(li.parentNode); + }); + + lists.forEach(list => { + const parent = list.parentNode; + const lis = Array.from(list.children); + const selected = lis.filter(li => intersects(li)); + if (!selected.length) return; + + const firstIdx = lis.indexOf(selected[0]); + const lastIdx = lis.indexOf(selected[selected.length - 1]); + const before = lis.slice(0, firstIdx); + const after = lis.slice(lastIdx + 1); + + if (before.length) { + const ul1 = list.cloneNode(false); + before.forEach(li => ul1.appendChild(li)); + parent.insertBefore(ul1, list); + } + + selected.forEach(li => { + const wrapper = li.firstElementChild && li.firstElementChild.cloneNode(true) || document.createElement('div'); + if (!li.firstElementChild) { + while (li.firstChild) wrapper.appendChild(li.firstChild); + } + parent.insertBefore(wrapper, list); + }); + + if (after.length) { + const ul2 = list.cloneNode(false); + after.forEach(li => ul2.appendChild(li)); + parent.insertBefore(ul2, list); + } + + parent.removeChild(list); + }); + } else { + const items = Array.from(content.children).filter(child => intersects(child)); + if (!items.length) return; + + let listEl; + if (type === 'listNumbers' || type === 'listLetters') { + listEl = document.createElement('ol'); + listEl.style.listStyleType = format.style.listStyleType; + } else { + listEl = document.createElement('ul'); + listEl.style.listStyleType = format.style.listStyleType; + } + content.insertBefore(listEl, items[0]); + + items.forEach(node => { + if (node.tagName === 'UL' || node.tagName === 'OL') { + Array.from(node.children).forEach(li => { + listEl.appendChild(li); + }); + content.removeChild(node); + } else { + const li = document.createElement('li'); + content.removeChild(node); + li.appendChild(node); + listEl.appendChild(li); + } + }); + } +} + +/** + * @brief Применяет одиночный стиль к диапазону текста + * @param range Диапазон выделения текста + * @param f Объект с описанием формата + * @return span Элемент span с применённым стилем +*/ +function singleApplyformat(range, f) { + const val = f.value; + if (!val) return; + applyformat(range, () => { + const span = document.createElement('span'); + span.style[f.prop] = val; + return span; + }); +} + +/** + * @brief Применяет ссылку к диапазону текста + * @param range Диапазон выделения текста + * @return a Элемент a с применёнными атрибутами и стилем +*/ +function butlinkFun(range) { + const url = document.getElementById('link2').value; + const targetBlank = document.getElementById('link3').value === 'yes'; + const underline = document.getElementById('link5').value === 'yes'; + const color = document.getElementById('link6c').value; + applyformat(range, () => { + const a = document.createElement('a'); + a.href = url; + if (targetBlank) a.target = '_blank'; + if (underline) a.style.textDecoration = 'underline'; + if (color) a.style.color = color; + return a; + }); + inter(); +} + +/** + * @brief Удаляет все ссылки из диапазона текста + * @param range Диапазон выделения текста + * @return frag Фрагмент документа без ссылок +*/ +function linkdelFun(range) { + const frag = range.extractContents(); + const cleaned = unwrapAllLinks(frag); + range.insertNode(cleaned); + + function unwrapAllLinks(node) { + const frag = document.createDocumentFragment(); + Array.from(node.childNodes).forEach(ch => { + if (ch.nodeType === Node.ELEMENT_NODE && ch.tagName === 'A') { + frag.appendChild(unwrapAllLinks(ch)); + } else if (ch.nodeType === Node.ELEMENT_NODE) { + const copy = ch.cloneNode(false); + copy.appendChild(unwrapAllLinks(ch)); + frag.appendChild(copy); + } else { + frag.appendChild(ch.cloneNode(true)); + } + }); + return frag; + } +} + +/** + * @brief Убирает все спаны и ссылки из диапазона текста + * @param range Диапазон выделения текста + * @return frag Фрагмент документа без span и a +*/ +function formaFun(range) { + const frag = range.extractContents(); + const cleaned = unwrapAllSpansAndLinks(frag); + range.insertNode(cleaned); + + const externals = new Set(); + const intersects = element => { + const er = document.createRange(); + er.selectNodeContents(element); + return range.compareBoundaryPoints(Range.END_TO_START, er) < 0 + && range.compareBoundaryPoints(Range.START_TO_END, er) > 0; + }; + Array.from(content.children).forEach(child => { + if (intersects(child)) externals.add(child); + }); + externals.forEach(el => { + el.style.textAlign = ''; + }); + + const itList = document.createNodeIterator( + content, + NodeFilter.SHOW_ELEMENT, + { + acceptNode: n => + (n.tagName === 'UL' || n.tagName === 'OL') && + range.intersectsNode(n) + ? NodeFilter.FILTER_ACCEPT + : NodeFilter.FILTER_REJECT + } + ); + let listEl; + while (listEl = itList.nextNode()) { + const parent = listEl.parentNode; + Array.from(listEl.children).forEach(li => { + while (li.firstChild) parent.insertBefore(li.firstChild, listEl); + }); + parent.removeChild(listEl); + } + + function unwrapAllSpansAndLinks(node) { + const frag = document.createDocumentFragment(); + Array.from(node.childNodes).forEach(ch => { + if ( + ch.nodeType === Node.ELEMENT_NODE && + (ch.tagName === 'SPAN' || ch.tagName === 'A') + ) { + frag.appendChild(unwrapAllSpansAndLinks(ch)); + } else if (ch.nodeType === Node.ELEMENT_NODE) { + const copy = ch.cloneNode(false); + copy.appendChild(unwrapAllSpansAndLinks(ch)); + frag.appendChild(copy); + } else { + frag.appendChild(ch.cloneNode(true)); + } + }); + return frag; + } +} + +/** @brief Текущий формат для применения */ +let currentFormat = null; +/** @brief Текущий диапазон выделения */ +let currentRange = null; +/** + * @brief Открывает палитру выбора цвета текста + * @param range Диапазон выделения текста +*/ +window.colFun = function(range) { + currentFormat = { prop: 'color', test: v => !!v }; + currentRange = range; + const app = document.querySelector('.pcr-app'); + app.style.marginLeft = '-61px'; + app.style.left = ''; + app.classList.remove('hide'); +} +/** + * @brief Открывает палитру выбора фона текста + * @param range Диапазон выделения текста +*/ +window.backgrFun = function(range) { + currentFormat = { prop: 'background-color', test: v => !!v }; + currentRange = range; + const app = document.querySelector('.pcr-app'); + app.style.marginLeft = '-29px'; + app.style.left = ''; + app.classList.remove('hide'); +} +/** + * @brief Применяет выбранный цвет текста или фона +*/ +function setColorFun() { + const input = document.querySelector('.pcr-result'); + const val = input.value; + if (!currentRange || !currentFormat) return; + if (!val) { + simpleUnformat(currentRange, currentFormat); + } else { + applyformat(currentRange, () => { + const span = document.createElement('span'); + span.style[currentFormat.prop] = val; + return span; + }); + } + const app = document.querySelector('.pcr-app'); + app.classList.add('hide'); +} +document.addEventListener('LoadeditorJs', () => { + document.addEventListener('pointerdown', e => { + if (document.querySelector('.pcr-app') && !e.target.closest('.pcr-app') && !e.target.closest('#col') && !e.target.closest('#backgr')) { + setColorFun(); + } + }); +}, { once: true }); + +/** @brief Кнопки панели инструментов */ +const toolbarButtons = ['bol','ital','under','strik','sup','sub']; +/** @brief Цвета фона кнопок панели инструментов */ +const bgColors = { + none: 'rgb(255 255 255)', + partial: 'rgb(231 231 231)', + full: 'rgb(203 203 203)' +}; + +/** + * @brief Определяет текущее состояние формата (выделено/не выделено/частично) + * @param format Идентификатор формата + * @return string Состояние формата: 'none', 'partial', 'full' +*/ +function detectFormatState(format) { + const sel = window.getSelection(); + if (!sel.rangeCount) return 'none'; + const range = sel.getRangeAt(0); + if (!content.contains(range.commonAncestorContainer)) return 'none'; + const it = document.createNodeIterator( + range.commonAncestorContainer, + NodeFilter.SHOW_TEXT, + { acceptNode: n => range.intersectsNode(n) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT } + ); + let node, total = 0, styled = 0; + while (node = it.nextNode()) { + const text = node.textContent.trim(); + if (!text) continue; + total++; + let cur = node.parentElement, ok = false; + while (cur && cur !== content) { + const fmt = simpleFormats.find(f => f.id === format); + const v = fmt ? getComputedStyle(cur)[fmt.prop] || '' : ''; + if (fmt && fmt.test(v)) { ok = true; break; } + cur = cur.parentElement; + } + if (ok) styled++; + } + if (total === 0) return 'none'; + if (styled === 0) return 'none'; + if (styled === total) return 'full'; + return 'partial'; +} + +/** + * @brief Обновляет стили кнопок панели инструментов в зависимости от состояния форматирования +*/ +function updateToolbarStyles() { + toolbarButtons.forEach(id => { + const btn = document.getElementById(id); + const state = detectFormatState(id); + btn.style.backgroundColor = bgColors[state]; + }); +} + +/** @brief Одиночные селекторы панели инструментов */ +const singleSelectors = ['ff','fs']; + +/** + * @brief Определяет текущее состояние одиночного селектора (шрифт, размер) + * @param format Идентификатор селектора + * @return string Текущее значение или пустая строка +*/ +function detectSingleState(format) { + const sel = window.getSelection(); + if (!sel.rangeCount) return ''; + const range = sel.getRangeAt(0); + if (!content.contains(range.commonAncestorContainer)) return ''; + const it = document.createNodeIterator( + range.commonAncestorContainer, + NodeFilter.SHOW_TEXT, + { acceptNode: n => range.intersectsNode(n) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT } + ); + let node, values = [], uniform = true; + while (node = it.nextNode()) { + const text = node.textContent.trim(); + if (!text) continue; + const cur = node.parentElement; + const fmt = singleFormats.find(f => f.id === format); + const v = getComputedStyle(cur)[fmt.prop] || ''; + values.push(v); + } + if (values.length === 0) return ''; + const first = values[0]; + for (let i = 1; i < values.length; i++) { + if (values[i] !== first) { uniform = false; break; } + } + return uniform ? values[0] : ''; +} + +/** + * @brief Обновляет отображение одиночных селекторов на панели инструментов +*/ +function updateSingleSelectors() { + singleSelectors.forEach(id => { + const dropdown = document.getElementById(id); + const current = dropdown.querySelector('.current'); + const list = dropdown.querySelectorAll('li'); + let value = detectSingleState(id); + if (!value) return; + let cmd = id === 'ff' + ? value.replace(/["']/g, '') + : value; + if (id === 'fs') { + const num = parseFloat(cmd); + const unit = (cmd.match(/[a-z%]+$/) || [''])[0]; + cmd = num.toFixed(1) + unit; + } + let found = Array.from(list).some(li => li.dataset.cmd === cmd); + if (!found && id === 'ff') { + const li = document.createElement('li'); + li.dataset.cmd = cmd; + const div = document.createElement('div'); + div.textContent = cmd.split(',')[0].trim(); + li.appendChild(div); + dropdown.querySelector('.align-list').appendChild(li); + } + current.textContent = id === 'ff' + ? cmd.split(',')[0].trim() + : cmd; + current.dataset.cmd = cmd; + }); +} + +addEventListener("LoadeditorJs", function() +{ +document.querySelectorAll("#panel .toolbar-group").forEach(g => { + const btn = g.querySelector(".toolbar-group-button"); + const content = g.querySelector(".toolbar-group-content"); + if (btn && content) { + btn.addEventListener("click", () => { + const isHidden = content.style.display === "none"; + content.style.display = isHidden ? "" : "none"; + if (btn && content) { + const isHidden = content.style.display === "none"; + g.classList.toggle("open", !isHidden); + } + }); + if (btn && content) { + const isHidden = content.style.display === "none"; + g.classList.toggle("open", !isHidden); + } + } +}); + +document.querySelectorAll('.swit').forEach(btn => { + btn.addEventListener('click', () => { + const target = document.getElementById(btn.id + '_d'); + if (!target) return; + target.style.display = + (getComputedStyle(target).display === 'none') ? '' : 'none'; + }); +}); + +document.querySelectorAll('.align-dropdown').forEach(dropdown => { + const current = dropdown.querySelector('.current'); + const list = dropdown.querySelector('.align-list'); + current.addEventListener('click', () => { + list.style.display = list.style.display === 'block' ? 'none' : 'block'; + if (list.style.display === 'none' && current.dataset.cmd) { + const cmd = current.dataset.cmd; + const iconEl = document.getElementById(cmd); + if (iconEl) iconEl.click(); + } + }); + document.addEventListener('click', e => { + if (!dropdown.contains(e.target)) list.style.display = 'none'; + }); + list.querySelectorAll('li').forEach(li => { + li.addEventListener('click', () => { + const icon = li.firstElementChild; + const cmd = icon.id; + current.dataset.cmd = cmd; + current.removeAttribute('style'); + current.className = 'current editi editib pers'; + current.classList.add(cmd); + list.style.display = 'none'; + }); + }); +}); + +document.querySelectorAll('.align-dropdown-text').forEach(dropdown => { + const current = dropdown.querySelector('.current') + const list = dropdown.querySelector('.align-list') + dropdown.addEventListener('click', e => { + if (e.target.closest('.align-list')) return + list.style.display = list.style.display === 'block' ? 'none' : 'block' + }) + document.addEventListener('click', e => { + if (!dropdown.contains(e.target)) list.style.display = 'none' + }) + list.querySelectorAll('li').forEach(li => { + li.addEventListener('click', () => { + const cmd = li.dataset.cmd + current.innerHTML = li.querySelector('img')?.outerHTML || li.textContent + current.dataset.cmd = cmd + list.style.display = 'none' + const f = singleFormats.find(ff => ff.id === dropdown.id) + f.value = cmd + const sel = window.getSelection() + if (sel.rangeCount) { + const range = sel.getRangeAt(0) + if (content.contains(range.commonAncestorContainer)) { + singleApplyformat(range, f) + inter() + } + } + }) + }) +}) + +}, { once: true }); \ No newline at end of file diff --git a/main_plugin/editor/editor.php b/main_plugin/editor/editor.php new file mode 100755 index 0000000..63f9745 --- /dev/null +++ b/main_plugin/editor/editor.php @@ -0,0 +1,377 @@ + + +
+
+
+
+
+ + + + + +
+
{{copy}}
+
{{cut}}
+
{{paste}}
+
+ +
+ {{thickness_px}}:
+ {{width_px_percent}}:
+ {{position}}:
+ {{color}}:
+ {{margin_top_px}}:
+ {{margin_right_px}}:
+ {{margin_bottom_px}}:
+ {{margin_left_px}}:
+ +
+ +
+ {{image_url}}:
+ {{image_width_px}}:
+ {{image_height_px}}:
+ {{position}}:
+ {{margin_top_px}}:
+ {{margin_right_px}}:
+ {{margin_bottom_px}}:
+ {{margin_left_px}}:
+ {{border_px}}:
+ {{border_color}}:
+ {{link_tooltip}}:
+
+
+ +
+
+
+
+
+ {{width_px_percent}}:
+ {{position}}:
+ {{padding_inner_px}}:
+ {{margin_top_px}}:
+ {{margin_right_px}}:
+ {{margin_bottom_px}}:
+ {{margin_left_px}}:
+ {{border_px}}:
+ {{border_color}}:
+ {{background_color}}:
+
+
+ +
\ No newline at end of file diff --git a/main_plugin/editor/func.editor.php b/main_plugin/editor/func.editor.php new file mode 100755 index 0000000..958b175 --- /dev/null +++ b/main_plugin/editor/func.editor.php @@ -0,0 +1,292 @@ +content->{$_SESSION['lng']}; + + $file->content->{$_SESSION['lng']} = ''; + $node = dom_import_simplexml($node); + $doc = $node->ownerDocument; + $appended = $node->appendChild($doc->createCDATASection("\n" . $saveContentIdData . "\n")); + $saved = $file->asXML($saveContentIdXml); + + if ($appended && $saved) { + return 'true'; + } + + throw new Exception("Problem saving content", -32003); +} + +/** + * @brief Сохраняет левый и правый блоки страницы + * @param array $params Массив с данными блоков, ключ 'floatsBlock' содержит массив левых и правых блоков + * @return string 'true' в случае успешного сохранения + * @throws Exception В случае проблем с сохранением блоков +*/ +function savePageSideBlocks($params) { + global $config, $path, $_SESSION; + + $saveContentIdXml = $path . $_SESSION['page_url'] . ".page.php"; + $file = @simplexml_load_file($saveContentIdXml); + + $floatsBlock = json_decode($params['floatsBlock'] ?? '[]', true); + $left = $floatsBlock['left'] ?? []; + $right = $floatsBlock['right'] ?? []; + + unset($file->lblock->block, $file->rblock->block); + + foreach ($left as $d) { + $b = $file->lblock->addChild('block'); + $b->addAttribute('url', htmlspecialchars($d['pluginUrl'] ?? '', ENT_QUOTES, 'UTF-8')); + $b->addAttribute('title', htmlspecialchars($d['title'] ?? '', ENT_QUOTES, 'UTF-8')); + $b->addAttribute('tclass',htmlspecialchars($d['tclass'] ?? '', ENT_QUOTES, 'UTF-8')); + $b->addAttribute('bclass',htmlspecialchars($d['bclass'] ?? '', ENT_QUOTES, 'UTF-8')); + } + foreach ($right as $d) { + $b = $file->rblock->addChild('block'); + $b->addAttribute('url', htmlspecialchars($d['pluginUrl'] ?? '', ENT_QUOTES, 'UTF-8')); + $b->addAttribute('title', htmlspecialchars($d['title'] ?? '', ENT_QUOTES, 'UTF-8')); + $b->addAttribute('tclass',htmlspecialchars($d['tclass'] ?? '', ENT_QUOTES, 'UTF-8')); + $b->addAttribute('bclass',htmlspecialchars($d['bclass'] ?? '', ENT_QUOTES, 'UTF-8')); + } + + $dom = new DOMDocument('1.0', 'UTF-8'); + $dom->preserveWhiteSpace = false; + $dom->formatOutput = true; + $dom->loadXML($file->asXML()); + $ok = $dom->save($saveContentIdXml); + + if ($ok) { + return 'true'; + } + + throw new Exception("Problem saving floats block", -32003); +} + +/** + * @brief Сохраняет заголовок страницы + * @param array $params Массив с данными для сохранения, ключ 'newTitle' содержит новый заголовок + * @return string 'true' в случае успешного сохранения + * @throws Exception В случае проблем с сохранением заголовка или если узел не найден +*/ +function savePageTitle($params) { + global $config, $path, $_SESSION; + + $newTitle = htmlspecialchars($params['newTitle'] ?? '', ENT_QUOTES, 'UTF-8'); + $filePath = $path . "data/filepath." . $_SESSION['lng'] . ".php"; + $file = @simplexml_load_file($filePath); + + $fileNode = rtrim($config['REQUEST_URI'], '.html'); + $nodes = array_filter(explode('/', $fileNode)); + $node = $file->index; + $current = 'index'; + + foreach ($nodes as $n) { + if ($n !== '' && isset($node->$n)) { + $node = $node->$n; + $current .= '->' . $n; + } else { + $error = "Node not found: $current->$n"; + break; + } + } + + if (isset($error)) { + throw new Exception($error, -32602); + } + + $node['title'] = $newTitle; + $saved = $file->asXML($filePath); + + if ($saved) { + return 'true'; + } + + throw new Exception("Problem saving title", -32003); +} + +/** + * @brief Сохраняет весь контент страницы, включая центральный блок, боковые блоки и атрибуты + * @param array $params Массив с данными страницы, включая 'page_url', 'nameFile', 'saveContentIdData', 'floatsBlock', 'title', 'pluginUrl', 'tclass', 'bclass' + * @return string 'true' в случае успешного сохранения + * @throws Exception В случае проблем с сохранением содержимого страницы +*/ +function saveHowPageContent($params) { + global $config, $path, $_SESSION; + + $_SESSION['page_url'] = $params['page_url'] . str_replace('.page.php', '', $params['nameFile']); + $filePath = $path . $params['page_url'] . $params['nameFile']; + $contentData = $params['saveContentIdData'] ?? ''; + $file = simplexml_load_file($filePath); + $langNode = $file->content->{$_SESSION['lng']}; + $file->content->{$_SESSION['lng']} = ''; + $node = dom_import_simplexml($langNode); + $doc = $node->ownerDocument; + $node->appendChild($doc->createCDATASection("\n" . $contentData . "\n")); + + $file->rblock = ''; + $file->lblock = ''; + $blocks = $params['floatsBlock'] ?? []; + $titles = $params['title'] ?? []; + $urls = $params['pluginUrl'] ?? []; + $tclasses = $params['tclass'] ?? []; + $bclasses = $params['bclass'] ?? []; + foreach ($blocks as $i => $blockName) { + $newBlock = $file->$blockName->addChild('block'); + $newBlock->addAttribute('url', htmlspecialchars($urls[$i] ?? '', ENT_QUOTES,'UTF-8')); + $newBlock->addAttribute('title', htmlspecialchars($titles[$i] ?? '', ENT_QUOTES,'UTF-8')); + $newBlock->addAttribute('tclass',htmlspecialchars($tclasses[$i] ?? '',ENT_QUOTES,'UTF-8')); + $newBlock->addAttribute('bclass',htmlspecialchars($bclasses[$i] ?? '',ENT_QUOTES,'UTF-8')); + } + + $dom = new DOMDocument('1.0','UTF-8'); + $dom->preserveWhiteSpace = false; + $dom->formatOutput = true; + $dom->loadXML($file->asXML()); + + $saved = $dom->save($filePath); + if ($saved === false) { + throw new Exception("Failed to save content", -32003); + } + return 'true'; +} + +/** + * @brief Создаёт новую страницу на основе шаблона + * @param array $params Массив с данными страницы, включая 'page_url', 'nameFile', 'saveContentIdData' + * @return string 'true' в случае успешного создания страницы + * @throws Exception В случае ошибок при создании файла или записи XML +*/ +function createNewPage($params) { + global $config, $path, $_SESSION; + + $_SESSION['page_url'] = $params['page_url'] . str_replace('.page.php', '', $params['nameFile']); + $saveContentIdXml = $path . $params['page_url'] . $params['nameFile']; + $templatePage = $path . "data/template.page.php"; + $saveContentIdData = $params['saveContentIdData'] ?? ''; + $templateContent = file_get_contents($templatePage); + if ($templateContent === false || file_put_contents($saveContentIdXml, $templateContent) === false) { + throw new Exception("Failed to create file", -32004); + } + + $file = simplexml_load_file($saveContentIdXml); + $node = $file->content->{$_SESSION['lng']}; + $file->content->{$_SESSION['lng']} = ''; + $node = dom_import_simplexml($node); + $no = $node->ownerDocument; + $node->appendChild($no->createCDATASection("\n" . $saveContentIdData . "\n")); + + $saved = $file->asXML($saveContentIdXml); + if ($saved === false) { + throw new Exception("Failed to write XML", -32003); + } + return 'true'; +} + +/** + * @brief Проверяет существование файла по указанному пути + * @param array $params Массив с данными проверки, включая 'path' и 'nameFile' + * @return string "true" если файл существует, иначе "false" + * @throws Exception В случае некорректного пути +*/ +function checkFile($params) { + global $path; + + $rel = trim($params['path'], "/\\"); + if ($rel !== '' && strpos($rel, '..') !== false) { + throw new Exception("Invalid path", -32602); + } + + $name = basename($params['nameFile']); + $full = rtrim($path, DIRECTORY_SEPARATOR) + . ($rel !== '' ? DIRECTORY_SEPARATOR . $rel : '') + . DIRECTORY_SEPARATOR . $name; + + return file_exists($full) ? "true" : "false"; +} + +/** + * @brief Создаёт новый плагин с базовым шаблоном + * @param array $params Массив с данными плагина, включая 'pluginName' + * @return string Сообщение о создании плагина или "false", если плагин уже существует + * @throws Exception В случае отсутствия имени плагина или ошибок записи файла +*/ +function createPlugin($params) { + $pluginName = $params['pluginName'] ?? ''; + $baseDir = __DIR__ . '/../../plugin/'; + + if ($pluginName === '') { + throw new Exception("Missing pluginName", -32602); + } + + $dir = $baseDir . $pluginName; + if (!is_dir($dir)) { + umask(0); + $stub = "'; \n?>"; + if (file_put_contents("$dir/plug.php", $stub) === false) { + throw new Exception("Failed to write plug.php", -32004); + } + return "Plugin created: $pluginName"; + } + + return "false"; +} + +/** + * @brief Получает содержимое плагина + * @param array $params Массив с данными плагина, включая 'pluginName2' + * @return string HTML-контент плагина + * @throws Exception В случае если файл плагина не найден +*/ +function getPlugin($params) { + $pluginName = $params['pluginName2'] ?? ''; + $file = __DIR__ . '/../../plugin/' . $pluginName . '/plug.php'; + if (!is_file($file)) { + throw new Exception("Plugin not found", -32602); + } + ob_start(); + include $file; + return ob_get_clean(); +} + +/** + * @brief Загружает изображение пользователя из Base64 и сохраняет на сервер + * @param array $params Массив с данными изображения, включая 'userImgBase64' и 'userImgName' + * @return string Путь к сохранённому изображению + * @throws Exception В случае ошибок при сохранении изображения +*/ +function uploadImage($params) { + global $config, $path, $_SESSION; + $base64 = $params['userImgBase64'] ?? ''; + $filename= $params['userImgName'] ?? 'image.png'; + $uploaddir = 'img/users_img/' . ($_SESSION['username'] ?? '') . '/'; + $name = pathinfo($filename, PATHINFO_FILENAME); + $ext = pathinfo($filename, PATHINFO_EXTENSION) ?: 'png'; + $target = $uploaddir . $name . '.' . $ext; + $i = 1; + while (file_exists($target)) { + $target = $uploaddir . $name . "_$i." . $ext; + $i++; + } + $data = base64_decode($base64, true); + if (file_put_contents($target, $data) === false) { + throw new Exception("Error saving image", -32004); + } + return $target; +} + +?> \ No newline at end of file diff --git a/main_plugin/editor/lang.js.php b/main_plugin/editor/lang.js.php new file mode 100755 index 0000000..3582cb5 --- /dev/null +++ b/main_plugin/editor/lang.js.php @@ -0,0 +1,24 @@ + $value) { + $placeholders['{{' . $key . '}}'] = $value; +} + +$js = file_get_contents($path . 'editor.js'); +$js = strtr($js, $placeholders); + +echo "window.editorJs = (function() {\n" . $js . "\n})();"; +?> diff --git a/main_plugin/editor/lang.php b/main_plugin/editor/lang.php new file mode 100755 index 0000000..ae84466 --- /dev/null +++ b/main_plugin/editor/lang.php @@ -0,0 +1,514 @@ + [ + 'insert_line' => 'Вставить линию', + 'thickness_px' => 'Толщина (px)', + 'width_px_percent' => 'Ширина (px, %)', + 'position' => 'Положение', + 'left' => 'Слева', + 'center' => 'По центру', + 'right' => 'Справа', + 'in_text' => 'В тексте', + 'color' => 'Цвет', + 'choose_color' => 'Нажмите, чтобы выбрать цвет', + 'insert' => 'Вставить', + 'insert_hr' => 'Вставить горизонтальную линию', + 'insert_table' => 'Вставить таблицу', + 'rows' => 'Строки', + 'columns' => 'Колонки', + 'padding_inner_px' => 'Внутренний отступ (px)', + 'padding_outer_px' => 'Внешний отступ (px)', + 'border_px' => 'Рамка (px)', + 'border_color' => 'Цвет рамки', + 'background_color' => 'Цвет фона', + 'upload' => 'Загрузить', + 'select' => 'Выбрать', + 'image_url' => 'URL изображения', + 'image_width_px' => 'Ширина изображения (px)', + 'image_height_px' => 'Высота изображения (px)', + 'margin_outer_px' => 'Внешний отступ (px)', + 'link' => 'Ссылка', + 'select_page_from_site' => 'Выбрать страницу с сайта', + 'open_in_new_window' => 'Открывать в новом окне', + 'yes' => 'Да', + 'no' => 'Нет', + 'underline' => 'Подчеркивание', + 'insert_link' => 'Вставить ссылку', + 'change_text_color' => 'Изменить цвет текста', + 'change_text_background' => 'Изменить цвет фона текста', + 'create_plugin_left' => 'Создать плагин слева', + 'enter_plugin_name' => 'Введите имя плагина', + 'plugin_name_guidelines' => 'В имени плагина только англ. буквы, цифры, пробелы, _', + 'used_plugin_names' => 'Используемые имена плагинов', + 'enter_plugin_title' => 'Введите заголовок плагина', + 'add' => 'Добавить', + 'add_plugin_left' => 'Добавить левый плагин', + 'select_plugin' => 'Выберите плагин', + 'create_plugin_right' => 'Создать плагин справа', + 'add_plugin_right' => 'Добавить правый плагин', + 'create_page' => 'Создать страницу', + 'select_or_create_file' => 'Выбрать или создать файл', + 'menu_name' => 'Название в меню', + 'tab_title' => 'Название во вкладке', + 'design' => 'Дизайн', + 'create' => 'Создать', + 'edit' => 'Изменить', + 'save' => 'Сохранить', + 'save_as' => 'Сохранить как', + 'open' => 'Открыть', + 'new' => 'Новый', + 'html_code_main_block_alt' => 'HTML-код главного блока', + 'html_code_main_block_title' => 'HTML-код главного блока', + 'undo_action_alt' => 'Отменить действие', + 'undo_action_title' => 'Отменить действие', + 'redo_action_alt' => 'Повторить действие', + 'redo_action_title' => 'Повторить действие', + 'bold_alt' => 'Жирный', + 'bold_title' => 'Сделать текст жирным', + 'italic_alt' => 'Курсив', + 'italic_title' => 'Сделать текст курсивом', + 'underline_alt' => 'Подчеркнутый', + 'underline_title' => 'Сделать текст подчеркнутым', + 'strikethrough_alt' => 'Зачеркнутый', + 'strikethrough_title' => 'Сделать текст зачеркнутым', + 'font_color_alt' => 'Цвет шрифта', + 'font_color_title' => 'Сделать текст другим цветом', + 'background_color_alt' => 'Цвет фона', + 'background_color_title' => 'Сделать фон другим цветом', + 'superscript_alt' => 'Надстрочный', + 'superscript_title' => 'Сделать текст надстрочным', + 'subscript_alt' => 'Подстрочный', + 'subscript_title' => 'Сделать текст подстрочным', + 'list_none' => 'Без списка', + 'align_left_alt' => 'Выравнить влево', + 'align_left_title' => 'Выравнивание влево', + 'align_center_alt' => 'Выравнить по центру', + 'align_center_title' => 'Выравнивание по центру', + 'align_right_alt' => 'Выравнить вправо', + 'align_right_title' => 'Выравнивание вправо', + 'align_justify_alt' => 'Выровнять по ширине', + 'align_justify_title' => 'Выровнять по ширине', + 'remove_format_alt' => 'Удалить форматирование', + 'remove_format_title' => 'Удалить форматирование', + 'insert_link_alt' => 'Вставить ссылку', + 'insert_link_title' => 'Вставить ссылку', + 'remove_link_alt' => 'Удалить ссылку', + 'remove_link_title' => 'Удалить ссылку', + 'edit_title_title' => 'Изменить заголовок', + 'insert_image_link' => 'Вставить изображение по ссылке', + 'insert_image_PC' => 'Загрузить изображение с компьютера', + 'insert_image_manager' => 'Выбрать изображение через менеджер', + 'insert_symbol' => 'Вставить символ', + 'delete_plugin' => 'Удалить плагин', + 'move_plugin' => 'Переместить плагин', + 'copy' => 'Копировать', + 'cut' => 'Вырезать', + 'paste' => 'Вставить', + 'auto' => 'авто', + + 'insert_url' => 'Вставьте URL!', + 'delete_plugin_confirm' => 'Удалить плагин?', + 'action_not_defined' => 'Действие не определено', + 'plugin_name_empty_error' => 'Имя плагина не может быть пустым!', + 'plugin_not_selected_error' => 'Плагин не выбран!', + 'plugin_name_guidelines' => 'В имени плагина можно использовать только английские буквы, цифры, пробелы и подчеркивания!', + 'plugin_name_exists_suffix' => ' - это имя плагина уже используется!', + 'used_plugin_names' => 'Используемые имена плагина:', + 'plugin_created_left_suffix' => 'создан на левую', + 'plugin_added_left_suffix' => 'добавлен на левую', + 'plugin_created_right_suffix' => 'создан на правую', + 'plugin_added_right_suffix' => 'добавлен на правую', + 'img_upload_error' => 'Ошибка при загрузке изображения!', + 'rows_or_columns_not_specified' => 'Вы не указали количество строк или столбцов!', + 'insert_url_or_select_image' => 'Вставьте URL или выберите изображение!', + 'cursor_not_in_editable_field' => 'Курсор не в редактируемом поле!', + 'cursor_or_selection_not_in_editable_field' => 'Курсор или выделение не в редактируемом поле!', + 'no_text_selected' => 'Вы не выделили текст!', + + 'padding_top_px' => 'Отступ сверху (px)', + 'padding_right_px' => 'Отступ справа (px)', + 'padding_bottom_px' => 'Отступ снизу (px)', + 'padding_left_px' => 'Отступ слева (px)', + 'thickness_tooltip' => 'Толщина линии в пикселях', + 'width_tooltip' => 'Ширина в процентах или пикселях', + 'position_tooltip' => 'Позиция элемента', + 'padding_top_tooltip' => 'Задайте верхний отступ в пикселях', + 'padding_right_tooltip' => 'Задайте правый отступ в пикселях', + 'padding_bottom_tooltip' => 'Задайте нижний отступ в пикселях', + 'padding_left_tooltip' => 'Задайте левый отступ в пикселях', + 'url_tooltip' => 'Введите URL изображения', + 'height_tooltip' => 'Высота изображения в пикселях', + 'margin_tooltip' => 'Внешний отступ в пикселях', + 'border_tooltip' => 'Толщина рамки в пикселях', + 'link_tooltip' => 'Ссылка при клике на изображение', + 'caption' => 'Подпись к изображению', + 'caption_tooltip' => 'Текст подписи под изображением', + 'add_row_tooltip' => 'Добавить строку в таблицу', + 'delete_row_tooltip' => 'Удалить строку из таблицы', + 'add_column_tooltip' => 'Добавить столбец в таблицу', + 'delete_column_tooltip' => 'Удалить столбец из таблицы', + 'padding_inner_tooltip' => 'Внутренний отступ в пикселях', + 'padding_outer_tooltip' => 'Внешний отступ в пикселях', + 'plugin_title_empty_error' => 'Заголовок пустой!', + 'open_page' => 'Откройте страницу на сайте, а не через менеджер!', + 'enter_new_title' => 'Введите новый заголовок:', + 'title_saved' => 'Заголовок сохранён!', + 'new_file' => 'Новый файл', + 'add_row' => 'Добавить строку', + 'delete_row' => 'Удалить строку', + 'add_column' => 'Добавить столбец', + 'delete_column'=> 'Удалить столбец', + 'left_clear' => 'Слева (без текста)', + 'right_clear' => 'Справа (без текста)', + 'center_clear'=> 'По центру (без текста)', + 'left_text' => 'Слева с текстом', + 'right_text' => 'Справа с текстом', + 'link_tooltip' => 'Ссылка при клике на изображение', + 'margin_top_px' => 'Внешний отступ сверху (px)', + 'margin_right_px' => 'Внешний отступ справа (px)', + 'margin_bottom_px' => 'Внешний отступ снизу (px)', + 'margin_left_px' => 'Внешний отступ слева (px)', + 'in_text' => 'В тексте' + ], + 'en' => [ + 'insert_line' => 'Insert line', + 'thickness_px' => 'Thickness (px)', + 'width_px_percent' => 'Width (px, %)', + 'position' => 'Position', + 'left' => 'Left', + 'center' => 'Center', + 'right' => 'Right', + 'in_text' => 'In text', + 'color' => 'Color', + 'choose_color' => 'Click to choose color', + 'insert' => 'Insert', + 'insert_hr' => 'Insert horizontal line', + 'insert_table' => 'Insert table', + 'rows' => 'Rows', + 'columns' => 'Columns', + 'padding_inner_px' => 'Inner padding (px)', + 'padding_outer_px' => 'Outer padding (px)', + 'border_px' => 'Border (px)', + 'border_color' => 'Border color', + 'background_color' => 'Background color', + 'upload' => 'Upload', + 'select' => 'Select', + 'image_url' => 'Image URL', + 'image_width_px' => 'Image width (px)', + 'image_height_px' => 'Image height (px)', + 'margin_outer_px' => 'Outer margin (px)', + 'link' => 'Link', + 'select_page_from_site' => 'Select page from site', + 'open_in_new_window' => 'Open in new window', + 'yes' => 'Yes', + 'no' => 'No', + 'underline' => 'Underline', + 'insert_link' => 'Insert link', + 'change_text_color' => 'Change text color', + 'change_text_background' => 'Change text background', + 'create_plugin_left' => 'Create plugin left', + 'enter_plugin_name' => 'Enter plugin name', + 'plugin_name_guidelines' => 'Plugin name: letters, digits, spaces, underscores', + 'used_plugin_names' => 'Used plugin names', + 'enter_plugin_title' => 'Enter plugin title', + 'add' => 'Add', + 'add_plugin_left' => 'Add left plugin', + 'select_plugin' => 'Select plugin', + 'create_plugin_right' => 'Create plugin right', + 'add_plugin_right' => 'Add right plugin', + 'create_page' => 'Create page', + 'select_or_create_file' => 'Select or create file', + 'menu_name' => 'Menu name', + 'tab_title' => 'Tab title', + 'design' => 'Design', + 'create' => 'Create', + 'edit' => 'Edit', + 'save' => 'Save', + 'save_as' => 'Save as', + 'open' => 'Open', + 'new' => 'New', + 'html_code_main_block_alt' => 'HTML code main block', + 'html_code_main_block_title' => 'HTML code main block', + 'undo_action_alt' => 'Undo action', + 'undo_action_title' => 'Undo action', + 'redo_action_alt' => 'Redo action', + 'redo_action_title' => 'Redo action', + 'bold_alt' => 'Bold', + 'bold_title' => 'Make text bold', + 'italic_alt' => 'Italic', + 'italic_title' => 'Make text italic', + 'underline_alt' => 'Underline', + 'underline_title' => 'Underline text', + 'strikethrough_alt' => 'Strikethrough', + 'strikethrough_title' => 'Strikethrough text', + 'font_color_alt' => 'Font color', + 'font_color_title' => 'Change font color', + 'background_color_alt' => 'Background color', + 'background_color_title' => 'Change background color', + 'superscript_alt' => 'Superscript', + 'superscript_title' => 'Make text superscript', + 'subscript_alt' => 'Subscript', + 'subscript_title' => 'Make text subscript', + 'list_none' => 'Without a list', + 'align_left_alt' => 'Align left', + 'align_left_title' => 'Align text left', + 'align_center_alt' => 'Align center', + 'align_center_title' => 'Align text center', + 'align_right_alt' => 'Align right', + 'align_right_title' => 'Align text right', + 'align_justify_alt' => 'Justify', + 'align_justify_title' => 'Justify text', + 'remove_format_alt' => 'Remove format', + 'remove_format_title' => 'Remove formatting', + 'insert_link_alt' => 'Insert link', + 'insert_link_title' => 'Insert link', + 'remove_link_alt' => 'Remove link', + 'remove_link_title' => 'Remove link', + 'edit_title_title' => 'Edit title', +'insert_image_link' => 'Insert image by link', +'insert_image_PC' => 'Upload image from PC', +'insert_image_manager' => 'Choose image from manager', + 'insert_symbol' => 'Insert symbol', + 'delete_plugin' => 'Delete plugin', + 'move_plugin' => 'Move plugin', + 'copy' => 'Copy', + 'cut' => 'Cut', + 'paste' => 'Paste', + 'auto' => 'auto', + + 'insert_url' => 'Insert URL!', + 'delete_plugin_confirm' => 'Delete plugin?', + 'action_not_defined' => 'Action not defined', + 'plugin_name_empty_error' => 'Plugin name cannot be empty!', + 'plugin_not_selected_error' => 'Plugin not selected!', + 'plugin_name_guidelines' => 'Plugin name can only contain English letters, numbers, spaces, and underscores!', + 'plugin_name_exists_suffix' => ' - this plugin name is already taken!', + 'used_plugin_names' => 'Used plugin names:', + 'plugin_created_left_suffix' => 'created on the left', + 'plugin_added_left_suffix' => 'added on the left', + 'plugin_created_right_suffix' => 'created on the right', + 'plugin_added_right_suffix' => 'added on the right', + 'img_upload_error' => 'Image upload error!', + 'rows_or_columns_not_specified' => 'You didn\'t specify the number of rows or columns!', + 'insert_url_or_select_image' => 'Insert URL or select an image!', + 'cursor_not_in_editable_field' => 'Cursor is not in an editable field!', + 'cursor_or_selection_not_in_editable_field' => 'Cursor or selection is not in an editable field!', + 'no_text_selected' => 'No text selected!', + + 'padding_top_px' => 'Padding top (px)', + 'padding_right_px' => 'Padding right (px)', + 'padding_bottom_px' => 'Padding bottom (px)', + 'padding_left_px' => 'Padding left (px)', + 'thickness_tooltip' => 'Line thickness in pixels', + 'width_tooltip' => 'Width in percent or pixels', + 'position_tooltip' => 'Element position', + 'padding_top_tooltip' => 'Set top padding in pixels', + 'padding_right_tooltip' => 'Set right padding in pixels', + 'padding_bottom_tooltip' => 'Set bottom padding in pixels', + 'padding_left_tooltip' => 'Set left padding in pixels', + 'url_tooltip' => 'Enter image URL', + 'height_tooltip' => 'Image height in pixels', + 'margin_tooltip' => 'Outer margin in pixels', + 'border_tooltip' => 'Border width in pixels', + 'link_tooltip' => 'Link on image click', + 'caption' => 'Image caption', + 'caption_tooltip' => 'Text displayed under the image', + 'add_row_tooltip' => 'Add a row to the table', + 'delete_row_tooltip' => 'Delete a row from the table', + 'add_column_tooltip' => 'Add a column to the table', + 'delete_column_tooltip' => 'Delete a column from the table', + 'padding_inner_tooltip' => 'Inner padding in pixels', + 'padding_outer_tooltip' => 'Outer padding in pixels', + 'plugin_title_empty_error' => 'Title is empty!', + 'open_page' => 'Open the page on the website, not through the manager!', + 'enter_new_title' => 'Enter a new title:', + 'title_saved' => 'Title saved!', + 'new_file' => 'Jauns fails', + 'add_row' => 'Add row', + 'delete_row' => 'Delete row', + 'add_column' => 'Add column', + 'delete_column'=> 'Delete column', + 'left_clear' => 'Left (no text)', + 'right_clear' => 'Right (no text)', + 'center_clear'=> 'Center (no text)', + 'left_text' => 'Left with text', + 'link_tooltip' => 'Link on image click', + 'margin_top_px' => 'Margin top (px)', + 'margin_right_px' => 'Margin right (px)', + 'margin_bottom_px' => 'Margin bottom (px)', + 'margin_left_px' => 'Margin left (px)', + 'right_text' => 'Right with text' + ], + 'lv' => [ + 'insert_line' => 'Ievietot līniju', + 'thickness_px' => 'Biezums (px)', + 'width_px_percent' => 'Platums (px, %)', + 'position' => 'Novietojums', + 'left' => 'Pa kreisi', + 'center' => 'Centrā', + 'right' => 'Pa labi', + 'in_text' => 'Tekstā', + 'color' => 'Krāsa', + 'choose_color' => 'Klikšķiniet, lai izvēlētos krāsu', + 'insert' => 'Ievietot', + 'insert_hr' => 'Ievietot horizontālu līniju', + 'insert_table' => 'Ievietot tabulu', + 'rows' => 'Rindas', + 'columns' => 'Kolonnas', + 'padding_inner_px' => 'Iekšējais atkāpums (px)', + 'padding_outer_px' => 'Ārējais atkāpums (px)', + 'border_px' => 'Rāmja biezums (px)', + 'border_color' => 'Rāmja krāsa', + 'background_color' => 'Fona krāsa', + 'upload' => 'Augšupielādēt', + 'select' => 'Izvēlēties', + 'image_url' => 'Attēla URL', + 'image_width_px' => 'Attēla platums (px)', + 'image_height_px' => 'Attēla augstums (px)', + 'margin_outer_px' => 'Ārējais atkāpums (px)', + 'link' => 'Saite', + 'select_page_from_site' => 'Izvēlēties lapu no vietnes', + 'open_in_new_window' => 'Atvērt jaunā logā', + 'yes' => 'Jā', + 'no' => 'Nē', + 'underline' => 'Pasvītrojums', + 'insert_link' => 'Ievietot saiti', + 'change_text_color' => 'Mainīt teksta krāsu', + 'change_text_background' => 'Mainīt teksta fona krāsu', + 'create_plugin_left' => 'Izveidot spraudni pa kreisi', + 'enter_plugin_name' => 'Ievadiet spraudņa nosaukumu', + 'plugin_name_guidelines' => 'Nosaukumā tikai angļu burtu, ciparu, atstarpju un apakšsvītru', + 'used_plugin_names' => 'Izmantotie spraudņu nosaukumi', + 'enter_plugin_title' => 'Ievadiet spraudņa virsrakstu', + 'add' => 'Pievienot', + 'add_plugin_left' => 'Pievienot kreiso spraudni', + 'select_plugin' => 'Izvēlēties spraudni', + 'create_plugin_right' => 'Izveidot spraudni pa labi', + 'add_plugin_right' => 'Pievienot labo spraudni', + 'create_page' => 'Izveidot lapu', + 'select_or_create_file' => 'Izvēlēties vai izveidot failu', + 'menu_name' => 'Nosaukums izvēlnē', + 'tab_title' => 'Cilnes virsraksts', + 'design' => 'Dizains', + 'create' => 'Izveidot', + 'edit' => 'Rediģēt', + 'save' => 'Saglabāt', + 'save_as' => 'Saglabāt kā', + 'open' => 'Atvērt', + 'new' => 'Jauns', + 'html_code_main_block_alt' => 'Galvenā bloka HTML kods', + 'html_code_main_block_title' => 'Galvenā bloka HTML kods', + 'undo_action_alt' => 'Atcelt darbību', + 'undo_action_title' => 'Atcelt darbību', + 'redo_action_alt' => 'Atkārtot darbību', + 'redo_action_title' => 'Atkārtot darbību', + 'bold_alt' => 'Treknraksts', + 'bold_title' => 'Padarīt tekstu treknu', + 'italic_alt' => 'Kursīvs', + 'italic_title' => 'Padarīt tekstu kursīvu', + 'underline_alt' => 'Pasvītrot', + 'underline_title' => 'Pasvītrot tekstu', + 'strikethrough_alt' => 'Pārvilkt', + 'strikethrough_title' => 'Pārvilkt tekstu', + 'font_color_alt' => 'Fonta krāsa', + 'font_color_title' => 'Mainīt fonta krāsu', + 'background_color_alt' => 'Fona krāsa', + 'background_color_title' => 'Mainīt fona krāsu', + 'superscript_alt' => 'Augšraksts', + 'superscript_title' => 'Padarīt tekstu augšrakstu', + 'subscript_alt' => 'Apakšraksts', + 'subscript_title' => 'Padarīt tekstu apakšrakstu', + 'list_none' => 'Bez saraksta', + 'align_left_alt' => 'Līdzināt pa kreisi', + 'align_left_title' => 'Līdzināt pa kreisi', + 'align_center_alt' => 'Centrēt', + 'align_center_title' => 'Centrēt tekstu', + 'align_right_alt' => 'Līdzināt pa labi', + 'align_right_title' => 'Līdzināt pa labi', + 'align_justify_alt' => 'Izlīdzināt', + 'align_justify_title' => 'Izlīdzināt tekstu', + 'remove_format_alt' => 'Noņemt formatējumu', + 'remove_format_title' => 'Noņemt formatējumu', + 'insert_link_alt' => 'Ievietot saiti', + 'insert_link_title' => 'Ievietot saiti', + 'remove_link_alt' => 'Noņemt saiti', + 'remove_link_title' => 'Noņemt saiti', + 'edit_title_title' => 'Rediģēt virsrakstu', +'insert_image_link' => 'Ievietot attēlu pēc saites', +'insert_image_PC' => 'Augšupielādēt attēlu no datora', +'insert_image_manager' => 'Izvēlēties attēlu no pārvaldnieka', + 'insert_symbol' => 'Ievietot simbolu', + 'delete_plugin' => 'Dzēst spraudni', + 'move_plugin' => 'Pārvietot spraudni', + 'copy' => 'Kopēt', + 'cut' => 'Izgriezt', + 'paste' => 'Ielīmēt', + 'auto' => 'auto', + + 'insert_url' => 'Ievietojiet URL!', + 'delete_plugin_confirm' => 'Vai dzēst spraudni?', + 'action_not_defined' => 'Darbība nav definēta', + 'plugin_name_empty_error' => 'Spraudņa nosaukums nedrīkst būt tukšs!', + 'plugin_not_selected_error' => 'Spraudnis nav izvēlēts!', + 'plugin_name_guidelines' => 'Spraudņa nosaukumā var izmantot tikai angļu alfabēta burtus, ciparus, atstarpes un zemsvītras līnijas!', + 'plugin_name_exists_suffix' => ' - šis spraudņa nosaukums jau ir izmantots!', + 'used_plugin_names' => 'Izmantotie spraudņu nosaukumi:', + 'plugin_created_left_suffix' => 'izveidots kreisajā pusē', + 'plugin_added_left_suffix' => 'pievienots kreisajā pusē', + 'plugin_created_right_suffix' => 'izveidots labajā pusē', + 'plugin_added_right_suffix' => 'pievienots labajā pusē', + 'img_upload_error' => 'Attēla augšupielādes kļūda!', + 'rows_or_columns_not_specified' => 'Jūs neesat norādījis rindu vai kolonnu skaitu!', + 'insert_url_or_select_image' => 'Ievietojiet URL vai izvēlieties attēlu!', + 'cursor_not_in_editable_field' => 'Kursors nav rediģējamā laukā!', + 'cursor_or_selection_not_in_editable_field' => 'Kursors vai atlase nav rediģējamā laukā!', + 'no_text_selected' => 'Nav izvēlēts teksts!', + + 'padding_top_px' => 'Augšējais polsterējums (px)', + 'padding_right_px' => 'Labais polsterējums (px)', + 'padding_bottom_px' => 'Apakšējais polsterējums (px)', + 'padding_left_px' => 'Kreisais polsterējums (px)', + 'thickness_tooltip' => 'Līnijas biezums pikseļos', + 'width_tooltip' => 'Platums procentos vai pikseļos', + 'position_tooltip' => 'Elementa pozīcija', + 'padding_top_tooltip' => 'Iestatiet augšējo polsterējumu pikseļos', + 'padding_right_tooltip' => 'Iestatiet labo polsterējumu pikseļos', + 'padding_bottom_tooltip' => 'Iestatiet apakšējo polsterējumu pikseļos', + 'padding_left_tooltip' => 'Iestatiet kreiso polsterējumu pikseļos', + 'url_tooltip' => 'Ievadiet attēla URL', + 'height_tooltip' => 'Attēla augstums pikseļos', + 'margin_tooltip' => 'Ārējais attālums pikseļos', + 'border_tooltip' => 'Rāmja platums pikseļos', + 'link_tooltip' => 'Saite, kad klikšķina uz attēla', + 'caption' => 'Attēla paraksts', + 'caption_tooltip' => 'Teksts zem attēla', + 'add_row_tooltip' => 'Pievienot rindu tabulai', + 'delete_row_tooltip' => 'Dzēst rindu no tabulas', + 'add_column_tooltip' => 'Pievienot kolonnu tabulai', + 'delete_column_tooltip' => 'Dzēst kolonnu no tabulas', + 'padding_inner_tooltip' => 'Iekšējais polsterējums pikseļos', + 'padding_outer_tooltip' => 'Ārējais polsterējums pikseļos', + 'plugin_title_empty_error' => 'Virsraksts ir tukšs!', + 'open_page' => 'Atveriet lapu vietnē, nevis caur pārvaldnieku!', + 'enter_new_title' => 'Ievadiet jauno virsrakstu:', + 'title_saved' => 'Virsraksts saglabāts!', + 'new_file' => 'Jauns fails', + 'add_row' => 'Pievienot rindu', + 'delete_row' => 'Dzēst rindu', + 'add_column' => 'Pievienot kolonnu', + 'delete_column'=> 'Dzēst kolonnu', + 'left_clear' => 'Pa kreisi (bez teksta)', + 'right_clear' => 'Pa labi (bez teksta)', + 'center_clear'=> 'Centrēti (bez teksta)', + 'left_text' => 'Pa kreisi ar tekstu', + 'right_text' => 'Pa labi ar tekstu', + 'link_tooltip' => 'Saite kad klikšķina uz attēla', + 'margin_top_px' => 'Ārējais attālums augšā (px)', + 'margin_right_px' => 'Ārējais attālums pa labi (px)', + 'margin_bottom_px' => 'Ārējais attālums apakšā (px)', + 'margin_left_px' => 'Ārējais attālums pa kreisi (px)', + 'in_text' => 'Tekstā' + ], +]; + +return $lang; \ No newline at end of file diff --git a/main_plugin/editor/plug.php b/main_plugin/editor/plug.php new file mode 100755 index 0000000..b60e89e --- /dev/null +++ b/main_plugin/editor/plug.php @@ -0,0 +1,26 @@ + $value) { + $Html = str_replace('{{' . $key . '}}', $value, $Html); + } + echo $Html; + echo ''; + echo ''; +} +?> diff --git a/main_plugin/form_editor/form_editor.css b/main_plugin/form_editor/form_editor.css new file mode 100755 index 0000000..eab63b7 --- /dev/null +++ b/main_plugin/form_editor/form_editor.css @@ -0,0 +1,172 @@ +#formEditorContent { + position: relative; + width: 100%; + height: 800px; + padding-top: 5px; +} +.formEditorArea { + width: 100%; + height: 100%; + background-color: #fff; + box-sizing: border-box; + overflow: auto; + position: relative; + user-select: none; +} + +#formEditorButtons, +.formEditorProperties { + display: flex; + flex-direction: column; + gap: 5px; +} + +#panelButtons { + position: absolute; + left: 10px; + top: 50%; + transform: translateY(-50%); + background-color: #f0f0f0; + padding: 5px; + box-sizing: border-box; + display: flex; + flex-direction: column; + gap: 5px; + z-index: 50; + border: 1px solid #ccc; + border-radius: 4px; +} +.fe-btn { + width: 30px; + height: 30px; + border: 1px solid #000; + border-radius: 5px; + text-align: center; + cursor: pointer; +} + +#panelProperties { + position: absolute; + top: 5px; + right: 0; + margin: 10px; + width: 17%; + background-color: #f0f0f0; + padding: 5px; + box-sizing: border-box; + display: flex; + flex-direction: column; + gap: 15px; + z-index: 50; + border: 1px solid #ccc; + border-radius: 4px; + height: -webkit-fill-available; + min-width: 160px; + padding-top: 15px; + overflow-y: auto; + word-break: break-all; +} + +.panelHeader { + font-weight: bold; + display: flex; + justify-content: space-between; + align-items: center; + cursor: pointer; +} +.formEditorProperties { + display: flex; + flex-direction: column; + gap: 5px; +} + +/* окно действий с элементами */ +#formEditorActions { + display: none; +position: absolute; +background-color: #f0f0f0; +border: 1px solid #ccc; +border-radius: 4px; +padding: 5px; +box-sizing: border-box; +z-index: 50; + position: fixed; +} + +.formEditorActionPanel { +display: flex; +flex-direction: column; +gap: 5px; +} + +.formEditorAction { +text-align: center; +border: 1px solid #000; +border-radius: 3px; +padding: 3px; +cursor: pointer; +background-color: #fff; +} + +.image-chooser { + position: absolute; + z-index: 50; + background: #fff; + border: 1px solid #ccc; + padding: 6px; + display: flex; + flex-direction: column; + gap: 6px; +} +.image-chooser button { + cursor: pointer; +} + + +#formMainPanel { + position: relative; + background: #f0f0f0; +} + +#menuToggle { + border-radius: 4px; + border: 1px solid #ccc; + background-color: #f0f0f0; + position: absolute; + top: 10px; + left: 10px; + z-index: 10; + padding: 4px; + cursor: pointer; + width: 32px; +} + +#menuPanel { + border-radius: 4px; + position: absolute; + top: 45px; + left: 10px; + display: none; + background: #fff; + border: 1px solid #ccc; + padding: 5px; + border: 1px solid #ccc; + background-color: #f0f0f0; + z-index: 9; +} + +#menuPanel button { + padding: 4px; + cursor: pointer; + margin-bottom: 4px; + display: block; +} + +#menuPanel label { + display: block; + margin-top: 5px; +} + +#gridInput { + width: 60px; +} \ No newline at end of file diff --git a/main_plugin/form_editor/form_editor.js b/main_plugin/form_editor/form_editor.js new file mode 100755 index 0000000..6d5e257 --- /dev/null +++ b/main_plugin/form_editor/form_editor.js @@ -0,0 +1,1595 @@ +/** + * @file form_editor.js + * @brief Основной файл form_editor, удля создании form +*/ + + + +/* окно создания */ + +/** @brief Выбранная кнопка формы */ +let selectedBtnId = null; +/** @brief Отложенный источник изображения */ +window.pendingImageSrc = null; + +document.querySelectorAll('#formEditorButtons .fe-btn').forEach(btn => { + btn.addEventListener('click', () => { + const isActive = btn.style.backgroundColor === 'darkgray'; + document.querySelectorAll('#formEditorButtons .fe-btn').forEach(b => b.style.backgroundColor = ''); + if(isActive){ + selectedBtnId = null; + window.pendingImageSrc = null; + closeImageChooser(); + } else { + btn.style.backgroundColor = 'darkgray'; + selectedBtnId = btn.id; + openImageChooser(btn); + } + }); +}); + +document.querySelector('.formEditorArea').addEventListener('click', function(e){ + if(!selectedBtnId) return; + const area = this; + const areaRect = area.getBoundingClientRect(); + let el; + + if(selectedBtnId === 'addDiv') { + el = document.createElement('div'); + el.style.width = '300px'; + el.style.height = '200px'; + el.style.border = '1px solid #000'; + el.style.display = 'flex'; + el.style.justifyContent = 'center'; + el.style.alignContent = 'center'; + el.style.flexWrap = 'wrap'; + } else if(selectedBtnId === 'addText') { + el = document.createElement('span'); + el.textContent = 'Text'; + el.style.textAlign = 'center'; + } else if(selectedBtnId === 'addInput') { + el = document.createElement('input'); + el.type = 'text'; + el.placeholder = 'Input'; + el.style.width = '150px'; + } else if(selectedBtnId === 'addButton') { + el = document.createElement('button'); + el.type = 'button'; + el.textContent = 'Button'; + el.style.width = '100px'; + } else if(selectedBtnId === 'addImg'){ + if(!window.pendingImageSrc) return; + el = document.createElement('img'); + el.src = window.pendingImageSrc; + el.style.width = '300px'; + } + + if(el){ + el.style.position = 'absolute'; + el.style.padding = '2px'; + el.style.margin = '2px'; + const w = parseInt(el.style.width || 50); + const h = parseInt(el.style.height || 30); + el.style.left = (e.clientX - areaRect.left + area.scrollLeft) / currentZoom - w / 2 + 'px'; + el.style.top = (e.clientY - areaRect.top + area.scrollTop) / currentZoom - h / 2 + 'px'; + makeDraggable(el); + area.appendChild(el); + } +}); + +/** + * @brief Открывает окно выбора изображения + * @param btn кнопка, для которой открывается окно +*/ +function openImageChooser(btn){ + const box = document.querySelector('.image-chooser'); + const rect = btn.getBoundingClientRect(); + box.style.left = (rect.right + 6 + window.scrollX) + 'px'; + box.style.top = (rect.top + window.scrollY) + 'px'; + box.style.display = 'flex'; +} + +/** @brief Закрывает окно выбора изображения */ +function closeImageChooser(){ + document.querySelector('.image-chooser').style.display='none' +} + +document.getElementById('imgByUrl').onclick = async function() { + messageQueue.push("Enter image URL"); + const url = await messageCreateInput(); + if (url) { + window.pendingImageSrc = url; + selectedBtnId = 'addImg'; + closeImageChooser(); + document.querySelectorAll('#formEditorButtons .fe-btn').forEach(b => b.style.backgroundColor = ''); + document.getElementById('addImg').style.backgroundColor = 'darkgray'; + } +}; +document.getElementById('imgUpload').onclick = function() { + const input = document.createElement("input"); + document.getElementById('imgUpload').type = 'button'; + input.type = "file"; + input.accept = "image/*"; + input.style.display = "none"; + document.body.appendChild(input); + + input.addEventListener("change", function() { + if (input.files.length > 0) { + const reader = new FileReader(); + reader.onload = function(e) { + const base64Data = e.target.result.split(',')[1]; + jsonrpcRequest('uploadImage', { userImgBase64: base64Data, userImgName: input.files[0].name }) + .then(response => { + if (response) { + window.pendingImageSrc = response; + selectedBtnId = 'addImg'; + closeImageChooser(); + document.querySelectorAll('#formEditorButtons .fe-btn').forEach(b => b.style.backgroundColor = ''); + document.getElementById('addImg').style.backgroundColor = 'darkgray'; + } else { + messageFunction("{{img_upload_error}}"); + } + }) + .catch(() => messageFunction("{{img_upload_error}}")); + }; + reader.readAsDataURL(input.files[0]); + } + document.body.removeChild(input); + }); + + input.click(); +}; +document.getElementById('imgData').onclick = function() { + window.managerDataAction = "selectImgFormToForm"; + let userName = getCookie('User'); + if (userName) { + managerData("/img/users_img/" + userName); + managerDiv.style.visibility = "visible"; + document.getElementById("settingsMain_d")?.style && (document.getElementById("settingsMain_d").style.visibility = "hidden"); + } +}; + +document.addEventListener('click',function(e){ + const chooser=document.querySelector('.image-chooser') + if(chooser.style.display==='flex' && !chooser.contains(e.target) && !e.target.closest('#addImg')){ + closeImageChooser() + } +}) + +/* сетка и привязка к ней */ +let GRID = 20; +let currentSnapX = 0; +let currentSnapY = 0; + +function createGrid(){ + const area = document.querySelector('.formEditorArea'); + if(!area) return; + area.style.position = area.style.position || 'relative'; + if(GRID > 1){ + area.style.backgroundImage = 'radial-gradient(circle at 0 0, rgba(0,0,0,0.6) 1px, transparent 2px)'; + area.style.backgroundSize = GRID + 'px ' + GRID + 'px'; + area.style.backgroundRepeat = 'repeat'; + area.style.backgroundPosition = '0 0'; + } else { + area.style.backgroundImage = ''; + } +} + +/* передвижение */ + +/** @brief Флаг перетаскивания */ +let isDragging = false; +/** @brief Смещение по X при перетаскивании */ +let offsetX = 0; +/** @brief Смещение по Y при перетаскивании */ +let offsetY = 0; +/** @brief Перетаскиваемый элемент */ +let draggedElement = null; + +/** + * @brief Делаем элемент перетаскиваемым + * @param el элемент для перетаскивания + */ +function makeDraggable(el){ + el.style.touchAction = 'none'; + if(el.tagName.toLowerCase() !== 'form') el.isDraggable = true; + el.addEventListener('mousedown', function(e){ startDrag(e, el); }); +} + +/** + * @brief Начало перетаскивания элемента + * @param e событие мыши + * @param el элемент для перетаскивания + */ +function startDrag(e, el){ + if(e.button !== 0) return; + if(el.tagName.toLowerCase() !== 'form' && !el.isDraggable) return; + isDragging = true; + draggedElement = el; + const rect = el.getBoundingClientRect(); + offsetX = e.clientX - rect.left; + offsetY = e.clientY - rect.top; + document.addEventListener('mousemove', dragMove); + document.addEventListener('mouseup', stopDrag); + e.preventDefault(); +} + +/** + * @brief Обработка движения мыши при перетаскивании + * @param e событие мыши + */ +function dragMove(e){ + if(!isDragging || !draggedElement) return; + const el = draggedElement; + const area = document.querySelector('.formEditorArea'); + if(!area) return; + + const areaRect = area.getBoundingClientRect(); + + let rawLeft = (e.clientX - areaRect.left - offsetX + area.scrollLeft) / currentZoom; + let rawTop = (e.clientY - areaRect.top - offsetY + area.scrollTop) / currentZoom; + + let newLeft = Math.round(rawLeft / GRID) * GRID; + let newTop = Math.round(rawTop / GRID) * GRID; + + const maxLeft = Math.max(0, (area.scrollWidth) - el.offsetWidth); + const maxTop = Math.max(0, (area.scrollHeight) - el.offsetHeight); + newLeft = Math.max(0, Math.min(newLeft, maxLeft)); + newTop = Math.max(0, Math.min(newTop, maxTop)); + + currentSnapX = newLeft; + currentSnapY = newTop; + + el.style.position = 'absolute'; + el.style.left = newLeft + 'px'; + el.style.top = newTop + 'px'; + + if(draggedElement === activeElement && activeResizer){ + const rect = activeElement.getBoundingClientRect(); + const areaRect = document.querySelector('.formEditorArea').getBoundingClientRect(); + activeResizer.style.left = (rect.right - areaRect.left - 5 + area.scrollLeft) / currentZoom + 'px'; + activeResizer.style.top = (rect.bottom - areaRect.top - 5 + area.scrollTop) / currentZoom + 'px'; + } +} + +/** @brief Завершение перетаскивания элемента */ +function stopDrag(e){ + if(!isDragging || !draggedElement) return; + const el = draggedElement; + isDragging = false; + document.removeEventListener('mousemove', dragMove); + document.removeEventListener('mouseup', stopDrag); + + const area = document.querySelector('.formEditorArea'); + if(!area){ + draggedElement = null; + return; + } + + const areaRect = area.getBoundingClientRect(); + let rawLeft = (e.clientX - areaRect.left - offsetX + area.scrollLeft) / currentZoom; + let rawTop = (e.clientY - areaRect.top - offsetY + area.scrollTop) / currentZoom; + + let snappedLeft = Math.round(rawLeft / GRID) * GRID; + let snappedTop = Math.round(rawTop / GRID) * GRID; + + const maxLeft = Math.max(0, (area.scrollWidth) - el.offsetWidth); + const maxTop = Math.max(0, (area.scrollHeight) - el.offsetHeight); + snappedLeft = Math.max(0, Math.min(snappedLeft, maxLeft)); + snappedTop = Math.max(0, Math.min(snappedTop, maxTop)); + + el.style.position = 'absolute'; + el.style.left = snappedLeft + 'px'; + el.style.top = snappedTop + 'px'; + + currentSnapX = snappedLeft; + currentSnapY = snappedTop; + + const divs = Array.from(area.querySelectorAll('div')).filter(d => d !== el); + + let candidate = null; + for(let d of divs){ + if(el.contains(d)) continue; + + const rect = d.getBoundingClientRect(); + const elRect = el.getBoundingClientRect(); + const elCenterX = elRect.left + elRect.width / 2; + const elCenterY = elRect.top + elRect.height / 2; + + if(elCenterX >= rect.left && + elCenterY >= rect.top && + elCenterX <= rect.right && + elCenterY <= rect.bottom){ + if(!candidate || candidate.contains(d)){ + candidate = d; + } + } + } + + if(candidate){ + const candStyle = window.getComputedStyle(candidate); + if(candStyle.position === 'static'){ + candidate.style.position = 'relative'; + } + + const candRect = candidate.getBoundingClientRect(); + const candOffsetX = candRect.left - areaRect.left + area.scrollLeft; + const candOffsetY = candRect.top - areaRect.top + area.scrollTop; + + let leftInCandidate = currentSnapX - candOffsetX; + let topInCandidate = currentSnapY - candOffsetY; + + leftInCandidate = Math.round(leftInCandidate / GRID) * GRID; + topInCandidate = Math.round(topInCandidate / GRID) * GRID; + + const maxLeftInCand = Math.max(0, candidate.clientWidth - el.offsetWidth); + const maxTopInCand = Math.max(0, candidate.clientHeight - el.offsetHeight); + leftInCandidate = Math.max(0, Math.min(leftInCandidate, maxLeftInCand)); + topInCandidate = Math.max(0, Math.min(topInCandidate, maxTopInCand)); + + if(el.offsetWidth > candidate.clientWidth){ + el.style.width = (candidate.clientWidth - 16) + 'px'; + } + if(el.offsetHeight > candidate.clientHeight){ + el.style.height = Math.max(10, Math.floor(candidate.clientHeight / 4)) + 'px'; + } + + el.style.position = ''; + el.style.left = ''; + el.style.top = ''; + candidate.appendChild(el); + } else { + el.style.position = 'absolute'; + el.style.left = currentSnapX + 'px'; + el.style.top = currentSnapY + 'px'; + } + + draggedElement = null; +} + +// инициализация сетки один раз +createGrid(); + +/* Подсветка границ */ + +document.querySelector('.formEditorArea').addEventListener('mouseover', function(e){ + if(e.target !== this){ + e.target.style.outline = '1px dashed gray'; + } +}); + +document.querySelector('.formEditorArea').addEventListener('mouseout', function(e){ + if(e.target !== this){ + e.target.style.outline = ''; + } +}); + +/* изменение размеров */ + +/** @brief Активный ресайзер */ +let activeResizer = null; +/** @brief Активный элемент для изменения размера */ +let activeElement = null; + +/** + * @brief Показывает ресайзер для элемента + * @param el элемент для изменения размера +*/ +function showResizer(el){ + removeExistingResizers(); + activeElement = el; + const area = document.querySelector('.formEditorArea'); + + if(!activeResizer){ + activeResizer = document.createElement('div'); + activeResizer.style.width = '10px'; + activeResizer.style.height = '10px'; + activeResizer.style.background = '#000'; + activeResizer.style.position = 'absolute'; + activeResizer.style.cursor = 'se-resize'; + area.appendChild(activeResizer); + + let isResizing = false; + let startX, startY, startWidth, startHeight; + + activeResizer.addEventListener('mousedown', function(e){ + e.stopPropagation(); + e.preventDefault(); + isResizing = true; + startX = e.clientX; + startY = e.clientY; + startWidth = parseInt(window.getComputedStyle(activeElement).width,10); + startHeight = parseInt(window.getComputedStyle(activeElement).height,10); + document.addEventListener('mousemove', resizeElement); + document.addEventListener('mouseup', stopResize); + }); + + function resizeElement(e){ + if(!isResizing) return; + let newWidth = (startWidth + (e.clientX - startX) / currentZoom); + let newHeight = (startHeight + (e.clientY - startY) / currentZoom); + + newWidth = Math.round(newWidth / GRID) * GRID; + newHeight = Math.round(newHeight / GRID) * GRID; + + const areaRect = area.getBoundingClientRect(); + if(newWidth + activeElement.offsetLeft > areaRect.width / currentZoom) newWidth = areaRect.width / currentZoom - activeElement.offsetLeft; + if(newHeight + activeElement.offsetTop > areaRect.height / currentZoom) newHeight = areaRect.height / currentZoom - activeElement.offsetTop; + + activeElement.style.width = newWidth + 'px'; + activeElement.style.height = newHeight + 'px'; + positionResizer(); + } + + function stopResize(){ + isResizing = false; + document.removeEventListener('mousemove', resizeElement); + document.removeEventListener('mouseup', stopResize); + } + } + + function positionResizer(){ + const rect = activeElement.getBoundingClientRect(); + const areaRect = area.getBoundingClientRect(); + activeResizer.style.left = (rect.right - areaRect.left - 5 + area.scrollLeft) / currentZoom + 'px'; + activeResizer.style.top = (rect.bottom - areaRect.top - 5 + area.scrollTop) / currentZoom + 'px'; + } + + positionResizer(); +} + +/** @brief Удаляет существующие ресайзеры */ +function removeExistingResizers(){ + if(activeResizer){ + activeResizer.remove(); + activeResizer = null; + activeElement = null; + } +} + +document.querySelector('.formEditorArea').addEventListener('mousedown', function(e){ + removeExistingResizers(); + if(e.target !== this && (e.target.tagName.toLowerCase() === 'div' || e.target.tagName.toLowerCase() === 'img')){ + showResizer(e.target); + } +}); + +/* окно свойств */ + +document.querySelector('.formEditorArea').addEventListener('click', function(e){ + if(e.target === this){ + /* showActions(e.target); */ + document.getElementById("panelProperties").style.display = "none"; + } else { + showProperties(e.target); + } +}); +document.querySelector('.formEditorArea').click(); + +/** @brief Показывает свойства элемента */ +function showProperties(el){ + var props = document.querySelector('.formEditorProperties'); + props.innerHTML = ''; + + var tag = el.tagName.toLowerCase(); + + addRow('
', 'width: -webkit-fill-available; margin-block-start: 0em;'); +/* addRow('{{id}}', el.id || '', null, el); + addRow('{{class}}', el.className || '', null, el); */ + selectedElement = el + const propsContainer = document.querySelector('.formEditorProperties'); + let idClassEditor = document.getElementById('idClassEditor'); + if (!idClassEditor) { + idClassEditor = document.createElement('div'); + idClassEditor.id = 'idClassEditor'; + propsContainer.appendChild(idClassEditor); + } + createIdEditor(idClassEditor); + createClassEditor(idClassEditor); + + addRow('
', 'width: -webkit-fill-available;'); + addRow('{{width}}', el.style.width || el.offsetWidth + 'px', function(val){ el.style.width = val; }, el); + addRow('{{height}}', el.style.height || el.offsetHeight + 'px', function(val){ el.style.height = val; }, el); + addRow('{{padding}}', el.style.padding || window.getComputedStyle(el).padding, function(val){ el.style.padding = val; }, el); + addRow('{{margin}}', el.style.margin || window.getComputedStyle(el).margin, function(val){ el.style.margin = val; }, el); + addRow('{{background-color}}', el.style.backgroundColor || '', function(val){ el.style.backgroundColor = val; }, el); + addRow('{{color}}', el.style.color || '', function(val){ el.style.color = val; }, el); + addRow('{{border}}', el.style.border || window.getComputedStyle(el).border, function(val){ el.style.border = val; }, el); + addRow('{{border-radius}}', el.style.borderRadius || window.getComputedStyle(el).borderRadius, function(val){ el.style.borderRadius = val; }, el); + addRow('{{cursor}}', el.style.cursor || '', function(val){ el.style.cursor = val; }, el); + addRow('{{box-shadow}}', el.style.boxShadow || '', function(val){ el.style.boxShadow = val; }, el); + addRow('{{opacity}}', el.style.opacity || '', function(val){ el.style.opacity = val; }, el); + + addRow('
', 'width: -webkit-fill-available;'); + if(tag === 'div'){ + addRow('{{justifyContent}}', el.style.justifyContent || 'flex-start', function(val){ el.style.justifyContent = val; }, el); + addRow('{{alignContent}}', el.style.alignContent || 'flex-start', function(val){ el.style.alignContent = val; }, el); + } + if(tag === 'span'){ + addRow('{{text}}', el.textContent, function(val){ el.textContent = val; }, el); + addRow('{{font-size}}', el.style.fontSize || '', function(val){ el.style.fontSize = val; }, el); + addRow('{{font-family}}', el.style.fontFamily || '', function(val){ el.style.fontFamily = val; }, el); + addRow('{{font-weight}}', el.style.fontWeight || '', function(val){ el.style.fontWeight = val; }, el); + addRow('{{line-height}}', el.style.lineHeight || '', function(val){ el.style.lineHeight = val; }, el); + addRow('{{text-decoration}}', el.style.textDecoration || '', function(val){ el.style.textDecoration = val; }, el); + addRow('{{text-align}}', el.style.textAlign || '', function(val){ el.style.textAlign = val; }, el); + addRow('{{white-space}}', el.style.whiteSpace || '', function(val){ el.style.whiteSpace = val; }, el); + } + if(tag === 'input'){ + addRow('{{placeholder}}', el.placeholder || '', function(val){ el.placeholder = val; }, el); + addRow('{{type}}', el.type || '', function(val){ el.type = val; }, el); + addRow('{{maxLength}}', el.maxLength || '', function(val){ el.maxLength = val; }, el); + addRow('{{min}}', el.min || '', function(val){ el.min = val; }, el); + addRow('{{max}}', el.max || '', function(val){ el.max = val; }, el); + } + if(tag === 'button'){ + addRow('{{text}}', el.textContent, function(val){ el.textContent = val; }, el); + addRow('{{type}}', el.type || '', function(val){ el.type = val; }, el); + } + if(tag === 'img'){ + addRow('{{src}}', el.src || '', function(val){ el.src = val; }, el); + } + + document.getElementById('panelProperties').style.display = 'flex'; +} + +/** + * @brief Добавляет строку в окно свойств + * @param label название свойства + * @param value значение свойства + * @param propHandler функция обработки изменения свойства + * @param el элемент, к которому применяется свойство +*/ +function addRow(label, value = "", propHandler = "", el = null){ + var props = document.querySelector('.formEditorProperties'); + + // предопределённые списки для сложных свойств + var predefined = { + 'justifyContent': ['flex-start','flex-end','center','space-between','space-around'], + 'alignContent': ['flex-start','flex-end','center','space-between','space-around'], + 'text-decoration': ['none','underline','line-through','underline line-through'], + 'text-align': ['left','right','center','justify'], + 'white-space': ['normal','nowrap'], + 'cursor': ['auto','default','pointer','text','move','help'], + 'font-weight': ['normal', '100','300','500','700','800','900'] + }; + + var inputIsNumber = function(v){ + if(typeof v !== 'string') v = String(v); + return /^-?\d+(\.\d+)?$/.test(v.trim()); + }; + + if(label === '{{id}}'){ + var row = document.createElement('div'); + row.style.display = 'flex'; + row.style.flexDirection = 'column'; + row.style.marginBottom = '5px'; + + var nameDiv = document.createElement('div'); + nameDiv.textContent = label; + nameDiv.style.marginBottom = '2px'; + + var input = document.createElement('input'); + input.type = 'text'; + input.value = value || ''; + input.style.width = '100%'; + + var warn = document.createElement('div'); + warn.style.color = 'red'; + warn.style.fontSize = '12px'; + warn.style.height = '16px'; + warn.style.marginTop = '4px'; + warn.textContent = ''; + warn.style.display = 'none'; + + input.addEventListener('input', function(){ + var newId = input.value.trim(); + if(!newId){ + warn.textContent = ''; + warn.style.display = 'none'; + return; + } + var exists = document.getElementById(newId); + if(exists && exists !== el){ + warn.textContent = '{{id_already_exists}}'; + warn.style.display = ''; + } else { + warn.textContent = ''; + warn.style.display = 'none'; + } + }); + + input.addEventListener('blur', function(){ + if(!el) return; + var newId = input.value.trim(); + if(!newId){ + el.id = ''; + input.value = ''; + warn.textContent = ''; + warn.style.display = 'none'; + return; + } + var exists = document.getElementById(newId); + if(exists && exists !== el){ + var base = newId.replace(/\d+$/, ''); + var numbers = []; + document.querySelectorAll('[id^="' + base + '"]').forEach(function(item){ + var match = item.id.match(new RegExp('^' + base + '(\\d*)$')); + if(match){ + numbers.push(match[1] ? parseInt(match[1], 10) : 0); + } + }); + numbers.sort(function(a,b){ return a-b; }); + var next = 0; + for(var i=0;i 0){ + var select = document.createElement('select'); + select.style.width = '100%'; + if(!value){ + var emptyOpt = document.createElement('option'); + emptyOpt.value = ''; + emptyOpt.textContent = ''; + select.appendChild(emptyOpt); + } + options.forEach(function(opt){ + var o = document.createElement('option'); + o.value = opt; + o.textContent = opt; + select.appendChild(o); + }); + try{ select.value = value; }catch(e){} + select.addEventListener('change', function(){ + if(propHandler) propHandler(select.value); + }); + select.addEventListener('blur', function(){ + if(propHandler) propHandler(select.value); + }); + + row.appendChild(nameDiv); + row.appendChild(select); + props.appendChild(row); + return; + } + + if(inputIsNumber(value)){ + var input = document.createElement('input'); + input.type = 'number'; + input.step = 'any'; + input.value = value; + input.style.width = '100%'; + input.addEventListener('input', function(){ + if(propHandler) propHandler(input.value); + }); + input.addEventListener('blur', function(){ + if(propHandler) propHandler(input.value); + }); + input.addEventListener('keydown', function(ev){ + if(ev.key === 'Enter') input.blur(); + }); + + row.appendChild(nameDiv); + row.appendChild(input); + props.appendChild(row); + return; + } + + var input = document.createElement('input'); + input.type = 'text'; + input.value = value || ''; + input.style.width = '100%'; + input.addEventListener('input', function(){ + if(propHandler) propHandler(input.value); + }); + input.addEventListener('blur', function(){ + if(propHandler) propHandler(input.value); + }); + input.addEventListener('keydown', function(ev){ + if(ev.key === 'Enter') input.blur(); + }); + + row.appendChild(nameDiv); + row.appendChild(input); + props.appendChild(row); + + } else if (label.startsWith('<')) { + var tagName = label.slice(1, -1); + var elTag = document.createElement(tagName); + elTag.style = value; + props.appendChild(elTag); + } +} + +/* сохранение и загрузка */ + +/** + * @brief Показывает действия для области формы + * @param area область формы +*/ +function showActions(area){ + const props = document.querySelector('.formEditorProperties') + props.innerHTML = '' + + const hr1 = document.createElement('hr') + hr1.style = "width: -webkit-fill-available; margin-block-start: 0em;" + props.appendChild(hr1) + + createActionButton(props, '{{download_html}}', () => downloadFormattedHtml(area)) + createActionButton(props, '{{load_html}}', () => loadHtml(area)) + createActionButton(props, '{{download_html_and_auto_css}}', () => downloadFormattedHtmlAndCss(area)) + + const hr2 = document.createElement('hr') + hr2.style = "width: -webkit-fill-available;" + props.appendChild(hr2) + + createGridControl(props) + + const hr3 = document.createElement('hr') + hr3.style = "width: -webkit-fill-available;" + props.appendChild(hr3) + + createIdEditor(props) + createClassEditor(props) +} + +/** + * @brief Показывает действия для области формы + * @param area область формы + */ +function updateGrid(val){ + const GRID = parseInt(val) || 20; + const area = document.querySelector('.formEditorArea'); + if(!area) return; + + if(GRID > 1){ + area.style.backgroundImage = 'radial-gradient(circle at 0 0, rgba(0,0,0,0.6) 1px, transparent 2px)'; + area.style.backgroundSize = GRID + 'px ' + GRID + 'px'; + area.style.backgroundRepeat = 'repeat'; + area.style.backgroundPosition = '0 0'; + } else { + area.style.backgroundImage = ''; + } +} + +function createIdEditor(container){ + const row = document.createElement('div') + row.style.marginBottom = '5px' + + const label = document.createElement('label') + label.textContent = 'ID:' + label.style.marginRight = '5px' + + const input = document.createElement('input') + input.type = 'text' + input.style.width = '100%' + + input.value = selectedElement ? selectedElement.id || '' : '' + input.placeholder = selectedElement ? '' : 'не найдено' + + input.addEventListener('input', () => { + if(selectedElement) selectedElement.id = input.value; + showIdClassProperties(container, input.value, null); + }); + + row.appendChild(label) + row.appendChild(input) + container.appendChild(row) + + showIdClassProperties(container, input.value, null) +} + +function createClassEditor(container){ + const row = document.createElement('div') + row.style.marginBottom = '5px' + + const label = document.createElement('label') + label.textContent = 'Class:' + label.style.marginRight = '5px' + + const wrapper = document.createElement('div') + wrapper.style.display = 'flex' + wrapper.style.gap = '6px' + wrapper.style.alignItems = 'center' + + const input = document.createElement('input') + input.type = 'text' + input.style.flex = '1' + input.style.width = '100%' + + const dotsBtn = document.createElement('button') + dotsBtn.type = 'button' + dotsBtn.textContent = '⋯' + dotsBtn.style.width = '28px' + dotsBtn.style.height = '24px' + dotsBtn.style.padding = '0' + dotsBtn.style.cursor = 'pointer' + + wrapper.appendChild(input) + wrapper.appendChild(dotsBtn) + + input.value = selectedElement ? selectedElement.className || '' : '' + input.placeholder = selectedElement ? '' : 'не найдено' + + row.appendChild(label) + row.appendChild(wrapper) + container.appendChild(row) + + const manager = document.createElement('div') + manager.style.marginTop = '6px' + manager.style.display = 'none' + container.appendChild(manager) + + var activeClass = null + + function getClasses(){ + return selectedElement ? (selectedElement.className || '').trim().split(/\s+/).filter(Boolean) : [] + } + + function setClasses(arr){ + if(!selectedElement) return + selectedElement.className = arr.join(' ') + input.value = selectedElement.className + } + + function addClass(name){ + if(!selectedElement) return + name = name.trim() + if(!name) return + var arr = getClasses() + if(arr.indexOf(name) === -1) arr.push(name) + setClasses(arr) + activeClass = name + renderManager() + showIdClassProperties(container, null, activeClass) + input.value = name; + } + + function removeClass(name){ + if(!selectedElement) return + var arr = getClasses().filter(x => x !== name) + setClasses(arr) + if(activeClass === name) activeClass = null + renderManager() + showIdClassProperties(container, null, activeClass) + input.value = name; + } + + function renderManager(){ + manager.innerHTML = '' + if(!selectedElement){ + var no = document.createElement('div') + no.textContent = 'Элемент не выбран' + manager.appendChild(no) + return + } + + var titleRow = document.createElement('div') + titleRow.style.display = 'flex' + titleRow.style.justifyContent = 'space-between' + titleRow.style.alignItems = 'center' + titleRow.style.marginBottom = '6px' + + var title = document.createElement('div') + title.textContent = 'Управление классами' + title.style.fontWeight = '600' + + var closeBtn = document.createElement('button') + closeBtn.type = 'button' + closeBtn.textContent = 'x' + closeBtn.style.width = '28px' + closeBtn.style.cursor = 'pointer' + closeBtn.addEventListener('click', function(){ manager.style.display = 'none' }) + + titleRow.appendChild(title) + titleRow.appendChild(closeBtn) + manager.appendChild(titleRow) + + var list = document.createElement('div') + list.style.display = 'flex' + list.style.flexDirection = 'column' + list.style.gap = '6px' + + var classes = getClasses() + if(classes.length === 0){ + var empty = document.createElement('div') + empty.textContent = 'Классы не найдены' + list.appendChild(empty) + } else { + classes.forEach(function(cn){ + var item = document.createElement('div') + item.style.display = 'flex' + item.style.alignItems = 'center' + item.style.gap = '6px' + + var name = document.createElement('div') + name.textContent = cn + name.style.flex = '1' + name.style.cursor = 'pointer' + if(activeClass === cn){ + name.style.fontWeight = '700' + } + name.addEventListener('click', function(){ + activeClass = cn + input.value = cn + renderManager() + showIdClassProperties(container, null, activeClass) + }) + + var editBtn = document.createElement('button') + editBtn.id = 'editBtnForm' + editBtn.type = 'button' + editBtn.textContent = '✎' + editBtn.style.width = '28px' + editBtn.style.cursor = 'pointer' + editBtn.addEventListener('click', function(){ + activeClass = cn + input.value = cn + input.focus() + renderManager() + showIdClassProperties(container, null, activeClass) + }) + + var del = document.createElement('button') + del.type = 'button' + del.textContent = '-' + del.style.width = '28px' + del.style.cursor = 'pointer' + del.addEventListener('click', function(){ removeClass(cn) }) + + item.appendChild(name) + item.appendChild(editBtn) + item.appendChild(del) + list.appendChild(item) + }) + } + + manager.appendChild(list) + + var addRow = document.createElement('div') + addRow.style.display = 'flex' + addRow.style.gap = '6px' + addRow.style.marginTop = '6px' + addRow.style.alignItems = 'center' + + var newInput = document.createElement('input') + newInput.type = 'text' + newInput.placeholder = 'new_class' + newInput.style.width = '150px' + newInput.style.flex = '1' + + var addBtn = document.createElement('button') + addBtn.type = 'button' + addBtn.textContent = '+' + addBtn.style.width = '28px' + addBtn.style.cursor = 'pointer' + addBtn.addEventListener('click', function(){ + addClass(newInput.value) + newInput.value = '' + }) + + addRow.appendChild(newInput) + addRow.appendChild(addBtn) + manager.appendChild(addRow) + } + + dotsBtn.addEventListener('click', function(e){ + e.stopPropagation() + manager.style.display = manager.style.display === 'none' ? 'block' : 'none' + renderManager() + }) + + input.addEventListener('input', function(){ + if(!selectedElement) return; + var val = input.value.trim(); + if(activeClass){ + var arr = getClasses(); + var idx = arr.indexOf(activeClass); + if(idx !== -1){ + if(val) arr[idx] = val; + else arr.splice(idx, 1); + setClasses(arr); + activeClass = val || null; + renderManager(); + showIdClassProperties(container, null, activeClass); + } else { + activeClass = null; + renderManager(); + } + } else { + setClasses(val ? val.split(/\s+/) : []); + renderManager(); + showIdClassProperties(container, null, val || null); + } + }); + + container.appendChild(manager) + renderManager() + showIdClassProperties(container, null, null) +} + +var formEditorStyles = {}; + +function updateDynamicStyles(){ + var css = ''; + for(var selector in formEditorStyles){ + var props = formEditorStyles[selector]; + var decls = Object.keys(props).map(function(k){ return k + ': ' + props[k] + ';'; }).join(' '); + if(decls) css += selector + ' { ' + decls + ' }\n'; + } + var container = document.querySelector('#formEditorStyles style'); + if(container){ + container.textContent = css; + } +} + +function renderProps(propsContainer, propsMap, selector){ + propsContainer.innerHTML = ''; + var keys = Object.keys(propsMap); + if(keys.length === 0){ + var empty = document.createElement('div'); + empty.textContent = 'Свойства не найдены'; + propsContainer.appendChild(empty); + } else { + keys.forEach(function(key){ + (function(propKey){ + var wrapper = document.createElement('div'); + wrapper.style.display = 'flex'; + wrapper.style.flexDirection = 'column'; + wrapper.style.marginBottom = '5px'; + + var labelDiv = document.createElement('div'); + labelDiv.style.marginBottom = '2px'; + labelDiv.textContent = propKey; + + var valueInput = document.createElement('input'); + valueInput.type = 'text'; + valueInput.value = propsMap[propKey]; + valueInput.style.width = '100%'; + + valueInput.addEventListener('change', function(){ + propsMap[propKey] = valueInput.value; + formEditorStyles[selector] = Object.assign({}, propsMap); + updateDynamicStyles(); + }); + + wrapper.appendChild(labelDiv); + wrapper.appendChild(valueInput); + propsContainer.appendChild(wrapper); + })(key); + }); + } + + var addRow = document.createElement('div'); + addRow.style.display = 'flex'; + addRow.style.alignItems = 'center'; + addRow.style.marginTop = '6px'; + addRow.style.gap = '4px'; + + var newPropInput = document.createElement('input'); + newPropInput.type = 'text'; + newPropInput.placeholder = 'property_name'; + newPropInput.style.width = '90%'; + + var addBtn = document.createElement('button'); + addBtn.type = 'button'; + addBtn.textContent = '+'; + + addBtn.addEventListener('click', function(){ + var name = newPropInput.value.trim(); + if(!name) return; + if(!propsMap[name]) propsMap[name] = ''; + formEditorStyles[selector] = Object.assign({}, propsMap); + updateDynamicStyles(); + renderProps(propsContainer, propsMap, selector); + }); + + addRow.appendChild(newPropInput); + addRow.appendChild(addBtn); + propsContainer.appendChild(addRow); +} + +function showIdClassProperties(container, idValue, classValue){ + var old = container.querySelector('.id-class-props'); + if(old) old.remove(); + + var area = document.createElement('div'); + area.className = 'id-class-props'; + container.appendChild(area); + + var selectors = []; + if(idValue && idValue.trim()) selectors.push('#' + idValue.trim()); + if(classValue && classValue.trim()) selectors.push('.' + classValue.trim()); + + if(selectors.length === 0){ + var note = document.createElement('div'); + note.textContent = 'ID/Class не указаны'; + area.appendChild(note); + return; + } + + selectors.forEach(function(selector){ + var title = document.createElement('div'); + title.textContent = selector; + title.style.fontWeight = '600'; + title.style.marginTop = '6px'; + area.appendChild(title); + + var propsMap = {}; + + try{ + for(var si = 0; si < document.styleSheets.length; si++){ + var ss = document.styleSheets[si]; + var rules; + try{ rules = ss.cssRules; }catch(e){ continue; } + if(!rules) continue; + for(var ri = 0; ri < rules.length; ri++){ + var rule = rules[ri]; + if(rule.type === 1 && rule.selectorText){ + var parts = rule.selectorText.split(',').map(s => s.trim()); + if(parts.includes(selector)){ + var style = rule.style; + for(var i = 0; i < style.length; i++){ + var name = style[i]; + propsMap[name] = style.getPropertyValue(name).trim(); + } + } + } + } + } + }catch(e){} + + if(formEditorStyles[selector]){ + Object.assign(propsMap, formEditorStyles[selector]); + } + + var propsContainer = document.createElement('div'); + propsContainer.style.marginTop = '4px'; + area.appendChild(propsContainer); + + renderProps(propsContainer, propsMap, selector); + }); +} + +const area = document.querySelector('.formEditorArea'); +document.getElementById('downloadBtn').addEventListener('click', () => { + downloadFormattedHtml(area); +}); +document.getElementById('loadBtn').addEventListener('click', () => { + loadHtml(area); +}); +document.getElementById('downloadCssBtn').addEventListener('click', () => { + downloadFormattedHtmlAndCss(area); +}); +document.getElementById('gridInput').addEventListener('change', (e) => { + updateGrid(e.target.value); +}); + +document.getElementById('menuToggle').addEventListener('click', function() { + const menu = document.getElementById('menuPanel'); + menu.style.display = menu.style.display === 'block' ? 'none' : 'block'; +}); + +document.addEventListener('click', function(e){ + const menu = document.getElementById('menuPanel'); + const toggle = document.getElementById('menuToggle'); + if(!menu.contains(e.target) && e.target !== toggle){ + menu.style.display = 'none'; + } +}); + +function updateGrid(val){ + const GRID = parseInt(val) || 20; + const area = document.querySelector('.formEditorArea'); + if(!area) return; + + if(GRID > 1){ + area.style.backgroundImage = 'radial-gradient(circle at 0 0, rgba(0,0,0,0.6) 1px, transparent 2px)'; + area.style.backgroundSize = GRID + 'px ' + GRID + 'px'; + area.style.backgroundRepeat = 'repeat'; + area.style.backgroundPosition = '0 0'; + } else { + area.style.backgroundImage = ''; + } +} + +/** + * @brief Создает кнопку действия в панели свойств + * @param container контейнер для кнопки + * @param text текст кнопки + * @param callback функция, вызываемая при нажатии +*/ +function createActionButton(container, text, callback){ + const btn = document.createElement('button') + btn.textContent = text + btn.style.padding = '4px' + btn.style.marginTop = '5px' + btn.style.cursor = 'pointer' + container.appendChild(btn) + btn.addEventListener('click', callback) +} + +/** + * @brief Сохраняет HTML формы в формате с отформатированным кодом + * @param area область формы +*/ +function downloadFormattedHtml(area){ + const clone = area.cloneNode(true) + clone.removeAttribute('class') + clone.querySelectorAll('[resizer]').forEach(r => r.remove()) + + Array.from(clone.children).forEach(el => { + el.style.position = 'relative' + el.style.left = '' + el.style.top = '' + el.style.outline = '' + }) + + clone.querySelectorAll('*').forEach(el => el.style.outline = '') + + const formattedHtml = Array.from(clone.children).map(child => formatHtml(child)).join('') + + const blob = new Blob([formattedHtml], {type: 'text/html'}) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = url + a.download = 'form.html' + document.body.appendChild(a) + a.click() + document.body.removeChild(a) + URL.revokeObjectURL(url) +} + + +/** + * @brief Сохраняет HTML формы с отдельными стилями CSS + * @param area область формы +*/ +function downloadFormattedHtmlAndCss(area){ + const clone = area.cloneNode(true) + clone.removeAttribute('class') + clone.querySelectorAll('[resizer]').forEach(r => r.remove()) + clone.querySelectorAll('*').forEach(el => el.style.outline = '') + + Array.from(clone.children).forEach(el => { + el.style.position = 'relative' + el.style.left = '' + el.style.top = '' + el.style.outline = '' + }) + + const groups = {} + const tagCounts = {} + const elements = Array.from(clone.querySelectorAll('*')) + elements.forEach(el => { + const tag = el.tagName.toLowerCase() + const style = el.getAttribute('style') || '' + const key = tag + '|' + style + if(!groups[key]){ + tagCounts[tag] = (tagCounts[tag] || 0) + 1 + const gen = tag + tagCounts[tag] + groups[key] = { className: gen, style: style } + } + const existingClass = el.getAttribute('class') || '' + const newClass = (existingClass ? existingClass + ' ' : '') + groups[key].className + el.setAttribute('class', newClass.trim()) + if(el.hasAttribute('style')) el.removeAttribute('style') + }) + + const styleContainer = document.querySelector('#formEditorStyles style') + if(styleContainer && styleContainer.textContent.trim()){ + const styleEl = document.createElement('style') + styleEl.textContent = styleContainer.textContent + clone.prepend(styleEl) + } + + const formattedHtml = Array.from(clone.children).map(child => formatHtml(child)).join('') + + let styleBlock = '' + const groupList = Object.values(groups) + if(groupList.length){ + styleBlock += '\n' + } + + const output = formattedHtml + '\n' + styleBlock + + const blob = new Blob([output], { type: 'text/html' }) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = url + a.download = 'form_with_css.html' + document.body.appendChild(a) + a.click() + document.body.removeChild(a) + URL.revokeObjectURL(url) +} + +/** + * @brief Форматирует HTML элемент в строку с отступами + * @param el элемент + * @param indent уровень отступа +*/ +function formatHtml(el, indent = 0){ + let tab = ' '.repeat(indent) + let html = '' + if(el.nodeType === 3) return tab + el.textContent.trim() + '\n' + + let tag = el.tagName.toLowerCase() + let attrs = Array.from(el.attributes).map(a => `${a.name}="${a.value}"`).join(' ') + if(attrs) attrs = ' ' + attrs + + let selfClosing = ['input','img','br','hr','meta','link'].includes(tag) + if(selfClosing){ + html += `${tab}<${tag}${attrs}>\n` + } else { + html += `${tab}<${tag}${attrs}>\n` + Array.from(el.childNodes).forEach(child => { + html += formatHtml(child, indent + 1) + }) + html += `${tab}\n` + } + return html +} + +/** + * @brief Загружает HTML файл и вставляет его в форму + * @param area область формы +*/ +function loadHtml(area){ + const input = document.createElement('input') + input.type = 'file' + input.accept = '.html' + input.addEventListener('change', function(){ + const file = input.files[0] + if(!file) return + const reader = new FileReader() + reader.onload = function(evt){ + const parser = new DOMParser() + const doc = parser.parseFromString(evt.target.result, 'text/html') + const styleTags = doc.querySelectorAll('style') + const styleContainer = document.querySelector('.formEditorAreaStyle') || (() => { + const div = document.createElement('div') + div.className = 'formEditorAreaStyle' + div.style.display = 'none' + document.body.appendChild(div) + return div + })() + styleTags.forEach(style => { + const newStyle = document.createElement('style') + let content = style.textContent + content = content.replace(/\.(\w+)/g, function(match, className){ + let uniqueClass = className + let counter = 1 + while(document.querySelector('.' + uniqueClass)){ + uniqueClass = className + '_' + counter + counter++ + } + return '.' + uniqueClass + }) + newStyle.textContent = content + styleContainer.appendChild(newStyle) + }) + const bodyChildren = Array.from(doc.body.children).filter(el => el.tagName.toLowerCase() !== 'style') + const existingChildren = area.children.length + bodyChildren.forEach(el => area.appendChild(el)) + const newChildren = Array.from(area.children).slice(existingChildren) + newChildren.forEach(el => { + el.style.position = 'absolute' + el.style.left = '0px' + el.style.top = '0px' + el.style.outline = '' + makeDraggable(el) + }) + /* showActions(area) */ + } + reader.readAsText(file) + }) + input.click() +} + +/* окно действий */ + +/** @brief Контейнер для контекстного меню действий редактора */ +var actions = document.getElementById('formEditorActions'); +actions.style.display = 'none'; +/** @brief Последняя координата X мыши при открытии контекстного меню */ +var mouseX = 0; +/** @brief Последняя координата Y мыши при открытии контекстного меню */ +var mouseY = 0; +/** @brief Текущий выбранный элемент в форме */ +var selectedElement = null; + +/** + * @brief Копирует элемент в буфер редактора + * @param el элемент +*/ +function copyElement(el){ + if(el) window.formEditorClipboard = el.cloneNode(true); +} + +/** + * @brief Вставляет скопированный элемент в заданные координаты + * @param x координата X + * @param y координата Y +*/ +function pasteElement(x, y){ + if(window.formEditorClipboard){ + var area = document.querySelector('.formEditorArea'); + var clone = window.formEditorClipboard.cloneNode(true); + clone.style.position = 'absolute'; + clone.style.left = x + 'px'; + clone.style.top = y + 'px'; + makeDraggable(clone); + area.appendChild(clone); + } +} + +/** + * @brief Удаляет элемент из формы + * @param el элемент +*/ +function deleteElement(el){ + if(el) el.remove(); +} + +document.querySelector('.formEditorArea').addEventListener('contextmenu', function(e){ + e.preventDefault(); + var area = this; + var el = e.target !== area ? e.target : null; + selectedElement = el; + mouseX = e.clientX; + mouseY = e.clientY; + + if(el){ + actions.style.display = 'block'; + actions.style.left = mouseX + 3 + 'px'; + actions.style.top = mouseY + 3 + 'px'; + document.getElementById('copyAction').style.display = 'block'; + document.getElementById('deleteAction').style.display = 'block'; + document.getElementById('pasteAction').style.display = window.formEditorClipboard ? 'block' : 'none'; + } else if(window.formEditorClipboard){ + actions.style.display = 'block'; + actions.style.left = mouseX + 3 + 'px'; + actions.style.top = mouseY + 3 + 'px'; + document.getElementById('copyAction').style.display = 'none'; + document.getElementById('deleteAction').style.display = 'none'; + document.getElementById('pasteAction').style.display = 'block'; + } else { + actions.style.display = 'none'; + } +}); + +document.addEventListener('click', function(e){ + if(!actions.contains(e.target)){ + actions.style.display = 'none'; + } +}); + +document.getElementById('copyAction').addEventListener('click', function(){ + copyElement(selectedElement); + actions.style.display = 'none'; +}); + +document.getElementById('pasteAction').addEventListener('click', function(e){ + var area = document.querySelector('.formEditorArea'); + var rect = area.getBoundingClientRect(); + pasteElement((e.clientX - rect.left) / currentZoom, (e.clientY - rect.top) / currentZoom); + actions.style.display = 'none'; +}); + +document.getElementById('deleteAction').addEventListener('click', function(){ + deleteElement(selectedElement); + actions.style.display = 'none'; +}); + +let currentZoom = 1; + +document.addEventListener('wheel', function(e){ + if(e.ctrlKey){ + e.preventDefault(); + const area = document.querySelector('.formEditorArea'); + if(!area) return; + + currentZoom += e.deltaY < 0 ? 0.2 : -0.2; + currentZoom = Math.min(Math.max(currentZoom, 0.2), 4); + + area.style.transform = 'scale(' + currentZoom + ')'; + area.style.transformOrigin = '0 0'; + + const grid = 20 * currentZoom; + area.style.backgroundImage = 'radial-gradient(circle at 0px 0px, rgba(0, 0, 0, 0.6) 1px, transparent 2px)'; + area.style.backgroundSize = grid + 'px ' + grid + 'px'; + area.style.width = 100 / currentZoom + "%"; + area.style.height = 100 / currentZoom + "%"; + } +}, { passive: false }); diff --git a/main_plugin/form_editor/form_editor.php b/main_plugin/form_editor/form_editor.php new file mode 100755 index 0000000..40a0d66 --- /dev/null +++ b/main_plugin/form_editor/form_editor.php @@ -0,0 +1,55 @@ + + + +
+
{{form_editor}}
+
+
+ + +
+
+
+
D
+
T
+
I
+
B
+
Im
+
+
+
+ + +
+
+ + + + + + +
+
+
{{copy}}
+
{{paste}}
+
{{delete}}
+
+
\ No newline at end of file diff --git a/main_plugin/form_editor/lang.js.php b/main_plugin/form_editor/lang.js.php new file mode 100755 index 0000000..00ec0fa --- /dev/null +++ b/main_plugin/form_editor/lang.js.php @@ -0,0 +1,21 @@ + $value) { + $placeholders['{{' . $key . '}}'] = $value; +} + +echo 'window.addEventListener("load", function() {' . strtr(file_get_contents($path . 'form_editor.js'), $placeholders) . '});'; +?> diff --git a/main_plugin/form_editor/lang.php b/main_plugin/form_editor/lang.php new file mode 100755 index 0000000..ea121ae --- /dev/null +++ b/main_plugin/form_editor/lang.php @@ -0,0 +1,11 @@ + [ + ], + 'en' => [ + ], + 'lv' => [ + ], +]; + +return $lang; \ No newline at end of file diff --git a/main_plugin/form_editor/plug.php b/main_plugin/form_editor/plug.php new file mode 100755 index 0000000..b7bd12d --- /dev/null +++ b/main_plugin/form_editor/plug.php @@ -0,0 +1,40 @@ + $value) { + $Html = str_replace('{{' . $key . '}}', $value, $Html); + } + + echo $Html; + + echo ""; + + echo ''; + echo ''; +} +?> diff --git a/main_plugin/manager/func.manager.php b/main_plugin/manager/func.manager.php new file mode 100755 index 0000000..748b0ed --- /dev/null +++ b/main_plugin/manager/func.manager.php @@ -0,0 +1,309 @@ + $name, + 'path' => $relPath . "/" . $file, + 'type' => $type, + 'size' => $size, + 'creationTime' => date('Y-m-d H:i:s', filemtime($filePath)), + ]; + } + array_unshift($data, ['rootFolder' => basename($path)]); + return $data; +} + +/** + * @brief Проверяет наличие конфликта имени файла или папки + * @param array $params Массив с ключами 'name' и 'currentPath' + * @return string "true" если файл/папка уже существует, "false" если нет + * @throws Exception Если путь недействителен +*/ +function checkNameConflict($params) { + global $path; + + $nameParam = $params['name'] ?? ''; + + if (preg_match('/^\$_COOKIE\[.*\]$/', $nameParam)) { + eval('$nameParam = ' . $nameParam . ';'); + } + + $currentPath = $path . ($params['currentPath'] ?? '') . '/'; + $name = basename($nameParam); + $newPath = $currentPath . $name; + + if (strpos(realpath(dirname($newPath)), realpath($path)) !== 0) { + throw new Exception("Invalid path", -32602); + } + return file_exists($newPath) ? "true" : "false"; +} + +/** + * @brief Вставляет файл или папку из буфера обмена в указанное место + * @param array $params Массив с ключами 'managerSettingsInsert', 'clipboardPath', 'clipboardAction' + * @return string "true" при успешной операции + * @throws Exception Если действие некорректно или операция файла не удалась +*/ +function insertClipboard($params) { + global $path; + $relDest = $params['managerSettingsInsert'] ?? ''; + $dest = realpath($path . '/' . $relDest); + $clipboard = $params['clipboardPath'] ?? ''; + $action = $params['clipboardAction'] ?? ''; + + if (strpos($clipboard, '/') === 0) { + $clipboard = $path . $clipboard; + } + $newPath = $dest . '/' . basename($clipboard); + + $success = false; + if ($action === 'cut') { + $success = @rename($clipboard, $newPath); + if ($success && !file_exists($newPath)) { + $success = false; + } + } elseif ($action === 'copy') { + $success = recursiveCopy($clipboard, $newPath) && file_exists($newPath); + } else { + throw new Exception("Invalid action", -32602); + } + if (!$success) { + throw new Exception("File operation failed", -32004); + } + return "true"; +} + +/** + * @brief Рекурсивно копирует файлы и папки + * @param string $source Исходный путь + * @param string $destination Путь назначения + * @return bool true при успешном копировании, false при ошибке +*/ +function recursiveCopy($source, $destination) { + if (is_dir($source)) { + if (!is_dir($destination) && !mkdir($destination, 0755, true)) { + return false; + } + foreach (scandir($source) as $item) { + if ($item === '.' || $item === '..') continue; + if (!recursiveCopy("$source/$item", "$destination/$item")) { + return false; + } + } + } else { + if (!copy($source, $destination)) { + return false; + } + } + return true; +} + +/** + * @brief Переименовывает файл или папку + * @param array $params Массив с ключами 'managerSettingsRename' и 'managerNamePath' + * @return string "true" при успешном переименовании + * @throws Exception Если операция переименования не удалась +*/ +function renameFile($params) { + global $path; + $currentFile = realpath($path . '/' . ($params['managerSettingsRename'] ?? '')); + $newName = $params['managerNamePath'] ?? ''; + $target = dirname($currentFile) . '/' . $newName; + if (!rename($currentFile, $target)) { + throw new Exception("Rename failed", -32004); + } + return "true"; +} + +/** + * @brief Удаляет файл или папку + * @param array $params Массив с ключом 'managerSettingsDelete' + * @return string "true" при успешном удалении + * @throws Exception Если удаление файла или папки не удалось +*/ +function deleteFile($params) { + global $path; + $target = realpath($path . '/' . ($params['managerSettingsDelete'] ?? '')); + + $delete = function($p) use (&$delete) { + if (is_dir($p)) { + foreach (array_diff(scandir($p), ['.', '..']) as $f) { + $delete($p . '/' . $f); + } + $ok = rmdir($p); + } else { + $ok = unlink($p); + } + if (!$ok) { + throw new Exception("Failed to delete file or directory", -32004); + } + }; + + $delete($target); + return "true"; +} + +/** + * @brief Получает свойства файла или папки + * @param array $params Массив с ключом 'managerSettingsProperties' + * @return array Массив с информацией о файле или папке: имя, тип, путь, размер, время создания и изменения + * @throws Exception Если файл или папка не найдены +*/ +function getFileProperties($params) { + global $path, $_SESSION; + $lang = include $path . 'main_plugin/manager/lang.php'; + $target = realpath($path . '/' . ($params['managerSettingsProperties'])); + if (!$target || !file_exists($target)) { + throw new Exception($lang[$_SESSION['lng']]['file_or_folder_not_found'], -32602); + } + $isDir = is_dir($target); + return [ + ['label' => $lang[$_SESSION['lng']]['name'], 'value' => basename($target)], + ['label' => $lang[$_SESSION['lng']]['type'], 'value' => $isDir ? $lang[$_SESSION['lng']]['folder'] : $lang[$_SESSION['lng']]['file']], + ['label' => $lang[$_SESSION['lng']]['location'], 'value' => str_replace($path, '', dirname($target))], + ['label' => $lang[$_SESSION['lng']]['size'], 'value' => $isDir ? (count(scandir($target)) - 2) . ' files' : filesize($target) . ' bytes'], + ['label' => $lang[$_SESSION['lng']]['creation_time'], 'value' => date('Y-m-d H:i:s', filectime($target))], + ['label' => $lang[$_SESSION['lng']]['last_modified_time'], 'value' => date('Y-m-d H:i:s', filemtime($target))], + ]; +} + +/** + * @brief Создаёт новый файл или папку + * @param array $params Массив с ключами 'managerSettingsCreate', 'managerType', 'managerNamePath' + * @return string "true" при успешном создании, "checkItemExists" если элемент уже существует + * @throws Exception Если создание файла или папки не удалось +*/ +function createFile($params) { + global $config, $path; + + $newItemName = $params['managerSettingsCreate'] ?? ''; + $type = $params['managerType'] ?? ''; + $parentPath = realpath($path . '/' . ($params['managerNamePath'] ?? '')); + + $fullPath = $parentPath . '/' . $newItemName; + if (file_exists($fullPath)) { + return 'checkItemExists'; + } + + $success = false; + if ($type === 'папка') { + $success = mkdir($fullPath); + } elseif ($type === 'файл') { + $success = file_put_contents($fullPath, '') !== false; + } + + if (!$success) { + throw new Exception("Failed to create item", -32004); + } + return "true"; +} + +/** + * @brief Загружает страницу и возвращает её блоки и контент + * @param array $params Массив с ключом 'newPath' указывающим путь к странице + * @return array Массив с ключами 'right', 'left', 'content' + * @throws Exception Если файл страницы не найден, не удалось загрузить XML или отсутствует контент для языка +*/ +function getPage($params) { + global $config, $path, $_SESSION; + + $rel = $params['newPath'] ?? ''; + $file = $path . $rel . '.page.php'; + libxml_use_internal_errors(true); + $pageXml = @simplexml_load_file($file); + if (!$pageXml) { + throw new Exception("Failed to load page file", -32004); + } + + if (!isset($_SESSION['lng']) || !isset($pageXml->content->{$_SESSION['lng']})) { + throw new Exception("Missing language or content", -32602); + } + + $page = []; + $page['right'] = GetBlock($pageXml->rblock->block, 'right'); + $page['left'] = GetBlock($pageXml->lblock->block, 'left'); + $page['content'] = (string)$pageXml->content->{$_SESSION['lng']}; + $_SESSION['page_url'] = $rel; + session_write_close(); + return $page; +} + +/** + * @brief Загружает файл на сервер из base64-данных + * @param array $params Массив с ключами 'fileData', 'fileName', 'pathLoad' + * @return string Относительный путь загруженного файла + * @throws Exception Если отсутствуют данные файла, некорректный путь загрузки, неверный base64 или сохранение файла не удалось +*/ +function uploadFile($params) { + global $config, $path; + + $base64 = $params['fileData'] ?? ''; + $originalName = trim($params['fileName'] ?? ''); + $relDir = trim($params['pathLoad'] ?? ''); + + if ($base64 === '' || $originalName === '') { + throw new Exception("Missing file data or name", -32602); + } + + $rootDir = realpath($path); + $uploadDir = realpath($path . DIRECTORY_SEPARATOR . $relDir); + if (!$uploadDir || strpos($uploadDir, $rootDir) !== 0 || !is_dir($uploadDir) || !is_writable($uploadDir)) { + throw new Exception("Invalid upload directory", -32602); + } + + $basename = preg_replace('/[^\w\-]/u', '_', pathinfo($originalName, PATHINFO_FILENAME)); + $extension = pathinfo($originalName, PATHINFO_EXTENSION); + $counter = 0; + do { + $name = $basename . ($counter ? "_{$counter}" : ''); + $fullPath = $uploadDir . DIRECTORY_SEPARATOR . $name . ($extension ? ".{$extension}" : ''); + $counter++; + } while (file_exists($fullPath)); + + $data = base64_decode($base64, true); + if ($data === false) { + throw new Exception("Invalid base64 data", -32602); + } + + if (file_put_contents($fullPath, $data) === false) { + throw new Exception("Failed to save file", -32004); + } + + @chmod($fullPath, 0644); + $relativePath = '/' . str_replace('\\', '/', substr($fullPath, strlen($rootDir))); + return $relativePath; +} + +?> \ No newline at end of file diff --git a/main_plugin/manager/lang.js.php b/main_plugin/manager/lang.js.php new file mode 100755 index 0000000..cfc99f2 --- /dev/null +++ b/main_plugin/manager/lang.js.php @@ -0,0 +1,22 @@ + $value) { + $placeholders['{{' . $key . '}}'] = $value; +} + +$js = 'window.addEventListener("LoadmanagerJs", function() {' . strtr(file_get_contents($path . 'manager.js'), $placeholders) . '}, { once: true });git checkout main'; +echo "window.managerJs = (function() {\n" . $js . "\n})();"; +?> diff --git a/main_plugin/manager/lang.php b/main_plugin/manager/lang.php new file mode 100755 index 0000000..88b846b --- /dev/null +++ b/main_plugin/manager/lang.php @@ -0,0 +1,169 @@ + [ + 'copy' => 'Копировать', + 'cut' => 'Вырезать', + 'rename' => 'Переименовать', + 'delete' => 'Удалить', + 'properties' => 'Свойства', + 'upload_file' => 'Загрузить файл', + 'paste' => 'Вставить', + 'create_file' => 'Создать файл', + 'create_folder' => 'Создать папку', + 'rights' => 'Права', + 'ok' => 'Ок', + 'cancel' => 'Отмена', + 'file' => 'Файл', + 'to_clipboard' => 'в буфер обмена!', + 'error_when' => 'Ошибка при', + 'right_click_to_select_file' => 'Кликните правой кнопкой мыши на файл для выбора файла!', + 'file_with_same_name_exists' => 'Файл с таким именем уже существует!', + 'file_pasted_successfully' => 'Файл вставлен из буфера обмена!', + 'file_paste_unknown_error' => 'Неизвестная ошибка при вставке файла!', + 'error' => 'Ошибка', + 'enter_new_name' => 'Введите новое имя:', + 'rename_success' => 'Переименование выполнено успешно!', + 'rename_error' => 'Ошибка при переименовании!', + 'invalid_name_error' => 'Некорректное имя. Использование запрещенных символов...', + 'delete_confirm' => 'Подтвердите удаление!', + 'delete_success' => 'Удаление выполнено успешно!', + 'delete_error' => 'Ошибка при удалении!', + 'folder' => 'Папка', + 'enter_new_folder_name' => 'Введите имя новой папки:', + 'invalid_folder_name' => 'Некорректное имя папки', + 'folder_created_successfully' => 'Папка создана успешно!', + 'enter_new_file_name' => 'Введите имя нового файла:', + 'invalid_file_name' => 'Некорректное имя файла', + 'file_created_successfully' => 'Файл создан успешно!', + 'create' => 'Создать', + 'with_name' => 'с именем', + 'create_error' => 'Ошибка при создании', + 'item_already_exists' => 'с таким же именем уже есть!', + 'unknown_error' => 'Неизвестная ошибка!', + 'no_rights_yet' => 'прав пока что нету', + 'file_upload_error' => 'Ошибка загрузки файла!', + 'file_uploaded_successfully' => 'Файл успешно загружен!', + 'select_file_ending_with_page_php' => 'Выберите файл с расширением .page.php!', + + 'name' => 'Имя', + 'type' => 'Тип', + 'location' => 'Расположение', + 'size' => 'Размер', + 'creation_time' => 'Время создания', + 'last_modified_time' => 'Время последнего изменения', + 'error' => 'Ошибка', + 'file_or_folder_not_found' => 'Файл или папка не найдены' + ], + 'en' => [ + 'copy' => 'Copy', + 'cut' => 'Cut', + 'rename' => 'Rename', + 'delete' => 'Delete', + 'properties' => 'Properties', + 'upload_file' => 'Upload file', + 'paste' => 'Paste', + 'create_file' => 'Create file', + 'create_folder' => 'Create folder', + 'rights' => 'Permissions', + 'ok' => 'OK', + 'cancel' => 'Cancel', + 'file' => 'File', + 'to_clipboard' => 'to clipboard!', + 'error_when' => 'Error when', + 'right_click_to_select_file' => 'Right-click to select a file!', + 'file_with_same_name_exists' => 'File with this name already exists!', + 'file_pasted_successfully' => 'File pasted successfully!', + 'file_paste_unknown_error' => 'Unknown error while pasting!', + 'error' => 'Error', + 'enter_new_name' => 'Enter new name:', + 'rename_success' => 'Renamed successfully!', + 'rename_error' => 'Error renaming!', + 'invalid_name_error' => 'Invalid name contains forbidden characters', + 'delete_confirm' => 'Confirm deletion!', + 'delete_success' => 'Deleted successfully!', + 'delete_error' => 'Error deleting!', + 'folder' => 'Folder', + 'enter_new_folder_name' => 'Enter folder name:', + 'invalid_folder_name' => 'Invalid folder name', + 'folder_created_successfully' => 'Folder created successfully!', + 'enter_new_file_name' => 'Enter file name:', + 'invalid_file_name' => 'Invalid file name', + 'file_created_successfully' => 'File created successfully!', + 'create' => 'Create', + 'with_name' => 'with name', + 'create_error' => 'Error creating', + 'item_already_exists' => 'already exists!', + 'unknown_error' => 'Unknown error!', + 'no_rights_yet' => 'No permissions set', + 'file_upload_error' => 'File upload error!', + 'file_uploaded_successfully' => 'File uploaded successfully!', + 'select_file_ending_with_page_php' => 'Select file ending with .page.php!', + + 'name' => 'Name', + 'type' => 'Type', + 'location' => 'Location', + 'size' => 'Size', + 'creation_time' => 'Creation Time', + 'last_modified_time' => 'Last Modified Time', + 'file' => 'File', + 'error' => 'Error', + 'file_or_folder_not_found' => 'File or folder not found' + ], + 'lv' => [ + 'copy' => 'Kopēt', + 'cut' => 'Izgriezt', + 'rename' => 'Pārdēvēt', + 'delete' => 'Dzēst', + 'properties' => 'Īpašības', + 'upload_file' => 'Augšupielādēt failu', + 'paste' => 'Ielīmēt', + 'create_file' => 'Izveidot failu', + 'create_folder' => 'Izveidot mapi', + 'rights' => 'Tiesības', + 'ok' => 'Labi', + 'cancel' => 'Atcelt', + 'file' => 'Fails', + 'to_clipboard' => 'starpliktuvi!', + 'error_when' => 'Kļūda, mēģinot', + 'right_click_to_select_file' => 'Ar peles labo pogu atlasiet failu!', + 'file_with_same_name_exists' => 'Fails ar šādu nosaukumu jau pastāv!', + 'file_pasted_successfully' => 'Fails veiksmīgi ielīmēts!', + 'file_paste_unknown_error' => 'Nezināma kļūda ielīmējot!', + 'error' => 'Kļūda', + 'enter_new_name' => 'Ievadiet jaunu nosaukumu:', + 'rename_success' => 'Pārdēvēts veiksmīgi!', + 'rename_error' => 'Kļūda pārdēvējot!', + 'invalid_name_error' => 'Nederīgs nosaukums', + 'delete_confirm' => 'Apstipriniet dzēšanu!', + 'delete_success' => 'Dzēsts veiksmīgi!', + 'delete_error' => 'Kļūda dzēšot!', + 'folder' => 'Mape', + 'enter_new_folder_name' => 'Ievadiet mapes nosaukumu:', + 'invalid_folder_name' => 'Nederīgs mapes nosaukums', + 'folder_created_successfully' => 'Mape izveidota veiksmīgi!', + 'enter_new_file_name' => 'Ievadiet faila nosaukumu:', + 'invalid_file_name' => 'Nederīgs faila nosaukums', + 'file_created_successfully' => 'Fails izveidots veiksmīgi!', + 'create' => 'Izveidot', + 'with_name' => 'ar nosaukumu', + 'create_error' => 'Kļūda izveidojot', + 'item_already_exists' => 'jau eksistē!', + 'unknown_error' => 'Nezināma kļūda!', + 'no_rights_yet' => 'Nav piešķirtu tiesību', + 'file_upload_error' => 'Kļūda augšupielādējot failu!', + 'file_uploaded_successfully' => 'Fails augšupielādēts veiksmīgi!', + 'select_file_ending_with_page_php' => 'Atlasiet failu ar paplašinājumu .page.php!', + + 'name' => 'Vārds', + 'type' => 'Tips', + 'location' => 'Atrašanās vieta', + 'size' => 'Izmērs', + 'creation_time' => 'Izveidošanas laiks', + 'last_modified_time' => 'Pēdējās izmaiņas', + 'file' => 'Fails', + 'error' => 'Kļūda', + 'file_or_folder_not_found' => 'Fails vai mape nav atrasti' + ] +]; + +return $lang; \ No newline at end of file diff --git a/main_plugin/manager/manager.css b/main_plugin/manager/manager.css new file mode 100755 index 0000000..908919e --- /dev/null +++ b/main_plugin/manager/manager.css @@ -0,0 +1,279 @@ +/* менеджер */ +#managerDiv { + display: inline-block; + position: fixed; + z-index: 100; + user-select: none; + background-color: rgba(255, 255, 255, 0.92); + border: 1px solid #000000; + width: 800px; + border-radius: 5px; + height: 600px; + font-size: 1em; + box-shadow: 0px 0px 5px #777; +} +#managerCloseFun { + float: right; + width: 20px; + height: 20px; + background-position: -159px -121px; + cursor: pointer; +} +#managerHistoryBackFun { + margin-right: 2px; + float: left; + width: 20px; + height: 14px; + background-position: -400px -43px; + cursor: pointer; +} +#managerHistoryForwFun { + margin-right: 2px; + float: left; + width: 20px; + height: 14px; + background-position: -441px -43px; + cursor: pointer; +} +#managerBackFun { + margin-right: 12px; + float: left; + width: 20px; + height: 14px; + background-position: -481px -43px; + cursor: pointer; +} + +#managerTop { + text-align: center; + border-bottom: 1px #40464d solid; + padding: 5px; + background-color: rgba(255, 255, 255, 0.6); +} +#managerTopTitle { + text-align: center; +} +#managerPath { + display: inline-block; + flex: 1; + height: 18px; + background-color: rgba(255, 255, 255, 0.8); + border-radius: 5px; + padding: 2px; +} +#managerPath.active { + border: 1px #40464d solid; +} +.managerPathButton { + background-color: rgba(255, 255, 255, 1); + border-radius: 5px; + cursor: pointer; +} +.managerPathButton:hover { + color: #787878; +} + +#managerTopDiv { + display: flex; + align-items: center; + flex-wrap: wrap; +} + +#managerTableDiv { + height: 480px; + margin: 0px 20px 0px 20px; + border: 1px #40464d solid; + overflow-y: overlay; + border-radius: 5px; +} +#managerTable { + font-size: 1em; + border-collapse: collapse; + background-color: rgba(255, 255, 255, 0.8); + width: -webkit-fill-available; +} +#managerTableTitle { + position: sticky; + top: 0; + font-weight: bold; + background-color: rgba(255, 255, 255, 1); +} +#managerTable td { + padding: 5px; +} +.managerTableDivFile:hover td { + background-color: #c5e7f9; + cursor: pointer; +} + +/* #managerTableDiv::-webkit-scrollbar { + width: 10px; +} +#managerTableDiv::-webkit-scrollbar-track { + border: 1px solid #000; + padding: 2px 0; + background-color: #ffffff; +} +#managerTableDiv::-webkit-scrollbar-thumb { + border-radius: 10px; + box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); + background-color: #ffffff; + border: 1px solid #000; + border-right: 0px solid #000; +} */ + +/* сохронение как*/ + +#saveHowDiv { + margin: 8px 20px 0px 20px; + white-space: nowrap; + display: flex; + align-items: center; +} + +#saveHowName { + border: 1px #40464d solid; + border-radius: 5px; + padding: 5px; + width: 594px; + font-size: 1em; + display: inline-block; + margin-left: 10px; +} +#saveHowButton { + border: 1px #40464d solid; + border-radius: 5px; + padding: 5px; + margin: 0px 0px 0px 10px; + cursor: pointer; + display: inline-block; + width: 91px; +} +#saveHowButton:hover { + color: #787878; +} + +/* окно менеджер */ +#managerSettings { + display: inline-block; + position: fixed; + z-index: 100; + user-select: none; + background-color: rgba(255, 255, 255, 0.92); + border: 1px solid #000000; + border-radius: 5px; + font-size: 1em; + box-shadow: 0px 0px 5px #777; + padding: 5px; + animation: fadeIn 0.5s ease-in forwards; +} +.managerSettingsButtonButtons { + background-color: rgba(255, 255, 255, 0.8); + border-radius: 5px; + padding: 5px; + border: 1px #40464d solid; + cursor: pointer; +} +.managerSettingsButtonButtons:hover { + color: #787878; +} + +/* окно свойств */ +#managerProperties { + display: inline-block; + position: fixed; + z-index: 100; + user-select: none; + background-color: rgba(255, 255, 255, 0.97); + border: 1px solid #000000; + border-radius: 5px; + font-size: 1em; + box-shadow: 0px 0px 5px #777; + width: 600px; +} +#managerPropertiesMiddle { + margin: 0px 20px 0px 20px; +} + +#managerPropertiesTop { + border-bottom: 1px solid #000000; + padding: 5px; + text-align: center; +} +#managerPropertiesTopName { + text-align: center; +} +#managerPropertiesTopClose { + float: right; + width: 20px; + height: 20px; + background-position: -159px -121px; + cursor: pointer; +} + +#managerPropertiesWindow { + text-align: center; + display: flex; +} +.managerPropertiesWindowDiv { + cursor: pointer; + text-align: center; + width: 50%; + display: inline-block; + padding: 9px; +} +.managerPropertiesWindowDiv:hover { + color: #787878; +} + +#managerPropertiesDiv { + border: 1px solid #000000; + border-radius: 5px; +} +.managerPropertiesDivDivs { + padding: 6px 8px 6px 8px; + border-radius: 5px; +} + +#managerPropertiesDivButtons { + padding: 9px; + display: flex; + justify-content: right; + align-items: center; +} +#managerPropertiesDivButtons { + text-align: center; +} +.managerPropertiesDivButton { + margin: 3px 3px 3px 15px; + cursor: pointer; + display: inline-block; +} +.managerPropertiesDivButton:hover { + color: #787878; +} + +.editib { + background-image: url(../../img/pict/b_iconslyb.svg); +} + +.editimc { + background-image: url(../../img/pict/mc_iconslyb.svg); +} + +.editib:hover { + background-image: url(../../img/pict/g_iconslyb.svg); +} + +.editimc:hover { + background-image: url(../../img/pict/g_iconslyb.svg); +} + +.editf.active { + background-image: url(../../img/pict/b_iconslyb.svg); + background-color: #e7e7e7; +} +.editf.active:hover { + background-image: url(../../img/pict/g_iconslyb.svg); + background-color: #e7e7e7; +} \ No newline at end of file diff --git a/main_plugin/manager/manager.js b/main_plugin/manager/manager.js new file mode 100755 index 0000000..d73686e --- /dev/null +++ b/main_plugin/manager/manager.js @@ -0,0 +1,524 @@ +/** + * @file manager.js + * @brief Основной файл manager, отвечает за управление файлами +*/ + +movementMenu("managerDiv"); +movementMenu("managerProperties"); + +/** @brief Элемент менеджера папок */ +let managerDiv = document.getElementById('managerDiv'); +managerData(currentPath); + +/** @brief Основные кнопки и редактируемые поля в менеджере */ +function managerFun() { + document.getElementById('managerCloseFun').onclick = function() { + managerDiv.style.visibility = "hidden"; + }; + document.getElementById('managerHistoryBackFun').onclick = function() { + if (managerHistoryIndex > 0) { + managerHistoryIndex--; + managerData(managerHistoryPaths[managerHistoryIndex]); + } + }; + document.getElementById('managerHistoryForwFun').onclick = function() { + if (managerHistoryIndex < managerHistoryPaths.length - 1) { + managerHistoryIndex++; + managerData(managerHistoryPaths[managerHistoryIndex]); + } + }; + document.getElementById('managerBackFun').onclick = function() { + managerData(removeLastSegment(currentPath)); + }; + + document.getElementById('managerSettingsCopy').onclick = function() { + managerClipboard("copy", "{{copy}}"); + }; + document.getElementById('managerSettingsCut').onclick = function() { + managerClipboard("cut", "{{cut}}"); + }; +/** + * @brief Выполняет операции с буфером (копирование/вставка/вырезание) + * @param action действие: copy/cut + * @param messageText текст сообщения +*/ +function managerClipboard(action, messageText) { + if (managerTableDivFilePath) { + let textToCopy = managerTableDivFilePath + '|' + action; + navigator.clipboard.writeText(textToCopy).then(() => { + document.getElementById('managerSettings').style.visibility = "hidden"; + }).catch(err => { + console.error('Ошибка копирования в буфер:', err); + }); + } else { + messageFunction("{{right_click_to_select_file}}"); + } +} + + +let managerSettingsInsertId = document.getElementById('managerSettingsInsert'); +managerSettingsInsertId.onclick = function() { + navigator.clipboard.readText().then(clipboardText => { + let [clipboardPath, clipboardAction] = clipboardText.split('|'); + if (!clipboardPath || !clipboardAction) { + messageFunction("{{right_click_to_select_file}}"); + return; + } + jsonrpcRequest("checkNameConflict", { + name: clipboardPath, + currentPath: currentPath + }).then(response => { + if (response == "true") { + messageFunction("{{file_with_same_name_exists}}"); + } else { + jsonrpcRequest("insertClipboard", { + managerSettingsInsert: currentPath, + clipboardPath: clipboardPath, + clipboardAction: clipboardAction + }).then(response => { + if (response === "true") { + messageFunction("{{file_pasted_successfully}}"); + } else { + let errorMessage = response.error ? response.error : "{{file_paste_unknown_error}}"; + messageFunction("{{error}}: " + errorMessage); + } + managerData(currentPath); + }); + } + }); + }).catch(err => { + console.error('Ошибка чтения из буфера:', err); + }); +}; + + let managerSettingsRenameId = document.getElementById('managerSettingsRename'); + managerSettingsRenameId.onclick = async function() { + if (managerTableDivFilePath) { + let invalidCharacters = /[\/\\:*?"<>|]/; + let managerTableDivFileName = managerTableDivFilePath.split(/[/\\]/).pop(); + messageQueue.push("{{enter_new_name}}"); + let title = await messageCreateInput(managerTableDivFileName || ''); + let isFolder = !/\./.test(managerTableDivFileName); + if (title !== null) { + if (title && !invalidCharacters.test(title) && (!isFolder || !title.includes('.'))) { + messageQueue.push("{{rename_confirm}} " + title + "?"); + if (await messageCreateQuestion()) { + let data = await jsonrpcRequest("checkNameConflict", { name: title, currentPath: currentPath }); + if (data == "true") { + messageFunction("{{file_with_same_name_exists}}"); + } else { + let res = await jsonrpcRequest("renameFile", { managerSettingsRename: managerTableDivFilePath, managerNamePath: title }); + if (res === "true") { + messageFunction("{{rename_success}}"); + } else { + messageFunction("{{rename_error}}"); + } + managerData(currentPath); + } + } + } else { + messageFunction("{{invalid_name_error}}"); + } + } + } else { + messageFunction("{{right_click_to_select_file}}"); + } + }; + + let managerSettingsDeleteId = document.getElementById('managerSettingsDelete'); + managerSettingsDeleteId.onclick = async function() { + if (managerTableDivFilePath) { + messageQueue.push("{{delete_confirm}}"); + if (await messageCreateQuestion()) { + let response = await jsonrpcRequest("deleteFile", { managerSettingsDelete: managerTableDivFilePath }); + if (response === "true") { + messageFunction("{{delete_success}}"); + } else { + messageFunction("{{delete_error}}"); + } + managerData(currentPath); + } + } else { + messageFunction("{{right_click_to_select_file}}"); + } + }; + + document.getElementById('managerSettingsButtonCreateFolder').onclick = async function() { + await createManagerItem("папка", "{{enter_new_folder_name}}", "{{invalid_folder_name}}", "{{folder_created_successfully}}"); + }; + document.getElementById('managerSettingsButtonCreateFile').onclick = async function() { + await createManagerItem("файл", "{{enter_new_file_name}}", "{{invalid_file_name}}", "{{file_created_successfully}}"); + }; + + async function createManagerItem(type, promptMessage, errorMessage, successMessage, nameSuffix = '') { + messageQueue.push(promptMessage); + let title = await messageCreateInput(); + if (title !== null) { + let invalidCharacters = /[\/\\:*?"<>|]/; + let isValidTitle = title && !invalidCharacters.test(title) && !title.startsWith('.') && !title.endsWith('.'); + if (type === "{{folder}}") { + isValidTitle = isValidTitle && !title.includes('.'); + } + if (isValidTitle) { + title += nameSuffix; + messageQueue.push("{{create}} " + type + " {{with_name}} " + title + "?"); + if (await messageCreateQuestion()) { + let data = await jsonrpcRequest("checkNameConflict", { name: title, currentPath: currentPath }); + if (data == "true") { + messageFunction("{{file_with_same_name_exists}}!"); + } else { + let response = await jsonrpcRequest("createFile", { managerSettingsCreate: title, managerType: type, managerNamePath: currentPath }); + if (response === "true") { + messageFunction(successMessage); + } else if (response === "checkItemExists") { + messageFunction(type + " {{item_already_exists}}"); + } else { + messageFunction("{{create_error}} " + type + "!"); + } + managerData(currentPath); + } + } + } else { + messageFunction(errorMessage); + } + } + } + + let managerSettingsPropertiesId = document.getElementById('managerSettingsProperties'); + managerSettingsPropertiesId.onclick = function() { + document.getElementById('managerProperties').style.visibility = 'hidden'; + if (managerTableDivFilePath) { + jsonrpcRequest("getFileProperties", { managerSettingsProperties: managerTableDivFilePath }).then(data => { + let managerPropertiesId = document.getElementById('managerProperties'); + let managerPropertiesDivId = document.getElementById('managerPropertiesDiv'); + let managerPropertiesTopNameId = document.getElementById('managerPropertiesTopName'); + let managerPropertiesWindowPropertiesId = document.getElementById('managerPropertiesWindowProperties'); + let managerPropertiesWindowRightsId = document.getElementById('managerPropertiesWindowRights'); + + let tableProperties = document.createElement('table'); + tableProperties.style.width = "100%"; + + data.forEach(item => { + let row = document.createElement('tr'); + let labelCell = document.createElement('td'); + let valueCell = document.createElement('td'); + labelCell.className = 'managerPropertiesDivDivs'; + valueCell.className = 'managerPropertiesDivDivs'; + labelCell.textContent = item.label; + valueCell.textContent = item.value; + row.appendChild(labelCell); + row.appendChild(valueCell); + tableProperties.appendChild(row); + }); + + let tableRights = document.createElement('div'); + tableRights.innerHTML = "{{no_rights_yet}}"; + + managerPropertiesTopNameId.textContent = "{{properties}} " + data[0].value; + managerPropertiesDivId.innerHTML = ''; + + managerPropertiesWindowPropertiesId.onclick = function() { + managerPropertiesDivId.innerHTML = ''; + managerPropertiesDivId.appendChild(tableProperties); + managerPropertiesWindowPropertiesId.style.backgroundColor = "#f3f3f3"; + managerPropertiesWindowRightsId.style.backgroundColor = ""; + }; + + managerPropertiesWindowRightsId.onclick = function() { + managerPropertiesDivId.innerHTML = ''; + managerPropertiesDivId.appendChild(tableRights); + managerPropertiesWindowPropertiesId.style.backgroundColor = ""; + managerPropertiesWindowRightsId.style.backgroundColor = "#f3f3f3"; + }; + + managerPropertiesWindowPropertiesId.click(); + + if (managerPropertiesId.style.visibility == 'hidden') { + managerPropertiesId.style.visibility = 'visible'; + } + + let managerPropertiesTopCloseId = document.getElementById('managerPropertiesTopClose'); + let managerPropertiesDivButtonOkId = document.getElementById('managerPropertiesDivButtonOk'); + let managerPropertiesDivButtonCancelId = document.getElementById('managerPropertiesDivButtonCancel'); + + managerPropertiesTopCloseId.onclick = function() { + managerPropertiesId.style.visibility = 'hidden'; + }; + managerPropertiesDivButtonOkId.onclick = function() { + managerPropertiesId.style.visibility = 'hidden'; + }; + managerPropertiesDivButtonCancelId.onclick = function() { + managerPropertiesId.style.visibility = 'hidden'; + }; + }); + } else { + messageFunction("{{right_click_to_select_file}}"); + } + }; + + //загрузка файла для менеджера + let managerSettingsLoadId = document.getElementById('managerSettingsLoad'); + managerSettingsLoadId.onclick = function() { + let fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.addEventListener('change', function() { + + jsonrpcRequest("checkNameConflict", { name: fileInput.files[0].name, currentPath: currentPath }).then(data => { + if (data == "true") { + messageFunction("{{file_with_same_name_exists}}") + } else { + const file = fileInput.files[0]; + const reader = new FileReader(); + reader.onload = function() { + const base64Data = reader.result.split(',')[1]; + jsonrpcRequest("uploadFile", { + fileName: file.name, + fileData: base64Data, + pathLoad: currentPath + }).then(response => { + messageFunction("{{file_uploaded_successfully}}") + managerData(currentPath) + }).catch(() => { + messageFunction("{{file_with_same_name_exists}}") + }) + }; + reader.readAsDataURL(file); + } + }); + + }); + fileInput.click(); + }; +} + +/** @brief Удаляет последний сегмент пути */ +function removeLastSegment(str) { + const segments = str.split('/'); + if (segments.length > 1) { + segments.pop(); + } + return segments.join('/'); +} + +/** @brief Инициализация окна настроек менеджера */ +function managerSettings() { + let managerDiv = document.getElementById('managerDiv'); + let managerSettingsDiv = document.getElementById('managerSettings'); + + managerDiv.addEventListener('contextmenu', managerSettingsClick); + touchLong(managerDiv, managerSettingsClick); +} + +/** + * @brief Обрабатывает клик правой кнопкой мыши для показа настроек + * @param event событие мыши +*/ +function managerSettingsClick(event) { + event.preventDefault(); + let managerSettingsDiv = document.getElementById('managerSettings'); + if (!isPhone) { + managerSettingsDiv.style.left = `${touchX}px`; + managerSettingsDiv.style.top = `${touchY}px`; + } else { + managerSettingsDiv.style.bottom = '15px'; + managerSettingsDiv.style.width = 'calc(100vw - 42px)'; + managerSettingsDiv.style.height = '42px'; + managerSettingsDiv.style.left = '15px'; + managerSettingsDiv.style.top = 'auto'; + managerSettingsDiv.style.boxShadow = 'none'; + } + + let ids = [ + 'managerSettingsCopy', + 'managerSettingsCut', + 'managerSettingsRename', + 'managerSettingsDelete', + 'managerSettingsProperties', + 'managerSettingsLoad', + 'managerSettingsInsert', + 'managerSettingsButtonCreateFolder', + 'managerSettingsButtonCreateFile' + ]; + ids.forEach(id => { + let el = document.getElementById(id); + if (el) { + if (el.dataset.oldDisplay === undefined) { + el.dataset.oldDisplay = getComputedStyle(el).display; + } + el.style.display = 'none'; + } + }); + + if (event.target.closest('.managerTableDivFile')) { + ['managerSettingsCopy','managerSettingsCut','managerSettingsRename','managerSettingsDelete','managerSettingsProperties'] + .forEach(id => { + let el = document.getElementById(id); + el.style.display = el.dataset.oldDisplay; + }); + } else { + document.getElementById('managerSettingsLoad').style.display = document.getElementById('managerSettingsLoad').dataset.oldDisplay; +navigator.clipboard.readText().then(text => { + if (text) { + let parts = text.split('|'); + if (parts.length === 2 && parts[0].trim() !== '' && parts[1].trim() !== '') { + let el = document.getElementById('managerSettingsInsert'); + el.style.display = el.dataset.oldDisplay; + } + } +}).catch(err => { + console.error('Ошибка чтения буфера:', err); +}); + + + ['managerSettingsButtonCreateFolder','managerSettingsButtonCreateFile'] + .forEach(id => { + let el = document.getElementById(id); + el.style.display = el.dataset.oldDisplay; + }); + } + + managerSettingsDiv.style.visibility = 'visible'; + document.addEventListener('pointerdown', function hideMenu(e) { + if (!managerSettingsDiv.contains(e.target)) { + managerSettingsDiv.style.visibility = 'hidden'; + document.removeEventListener('pointerdown', hideMenu); + } + }); +} + +/** + * @brief Обрабатывает контекстное меню пути + * @param event событие контекстного меню +*/ +function managerPathContext(event){ + let targetElement=event.target.closest('[path]') + if(targetElement){ + let pathValue=targetElement.getAttribute('path') + managerTableDivFilePath=pathValue + } +} +document.addEventListener('contextmenu',managerPathContext) +touchLong(document, managerPathContext) + +/** @brief Сохраняет файл через функцию "Сохранить как" */ +function saveHow() { + let currentPathHow = currentPath; + if (currentPathHow.startsWith('/')) { + currentPathHow = currentPathHow.slice(1); + } + if (!currentPathHow.endsWith('/')) { + currentPathHow += '/'; + } + window.saveContentIdHow(currentPathHow); +} + +/** @brief Открывает выбранную страницу */ +function openPageBut() { + if (openPageButPath != "no/Select") { + getPage(openPageButPath); + } else { + messageFunction('{{select_file_ending_with_page_php}}'); + } +} + +/** @brief Обрабатывает выбор страницы через URL */ +function propertiesUrlFun() { + let saveHowNameValue = document.getElementById('saveHowName').value; + if (!saveHowNameValue.includes('.page.php')) return; + let newValue = saveHowNameValue.replace(/\.page\.php/, ""); + let cp = currentPath; + if (cp.charAt(0) === "/") { + cp = cp.substring(1); + } + document.getElementById('treePropertiesDivUrlValue').innerHTML = cp + "/" + newValue; + window.managerDataAction = ""; + managerDiv.style.visibility = "hidden"; +} + +/** @brief Обрабатывает выбор изображения для вставки */ +function selectImgFormButFun() { + var rawPath = document.getElementById('managerPath').textContent; + var cleanPath = rawPath.trim().replace(/\s*\/\s*/g, '/').replace(/\s+/g, ''); + var fileName = document.getElementById('saveHowName').value.trim(); + var fullPath = cleanPath + fileName; + if (fullPath.startsWith('/')) { + fullPath = fullPath.slice(1); + } + var img = document.createElement("img"); + img.src = fullPath; + img.setAttribute("style", "float: left; margin: 10px; width: 250px; border: 0px solid rgb(0, 0, 0); overflow: hidden;"); + var sel = window.getSelection(); + if (sel.rangeCount) { + var range = sel.getRangeAt(0); + range.deleteContents(); + range.insertNode(img); + } + window.managerDataAction = ""; + managerDiv.style.visibility = "hidden"; +} + +/** @brief Обрабатывает выбор изображения для вставки в форму */ +function selectImgFormToFormButFun() { + var rawPath = document.getElementById('managerPath').textContent; + var cleanPath = rawPath.trim().replace(/\s*\/\s*/g, '/').replace(/\s+/g, ''); + var fileName = document.getElementById('saveHowName').value.trim(); + var fullPath = cleanPath + fileName; + if (fullPath.startsWith('/')) fullPath = fullPath.slice(1); + window.pendingImageSrc = fullPath; + window.managerDataAction = ""; + managerDiv.style.visibility = "hidden"; +} + +if (isPhone) document.getElementById('managerDiv').style.paddingBottom = "150px" +if (!isPhone) { + document.querySelectorAll('.managerSettingsButtons').forEach(btn=>{ + btn.style.backgroundColor='rgba(255, 255, 255, 1)' + btn.style.borderRadius='5px' + btn.style.padding='2px' + btn.style.margin='3px' + btn.style.cursor='pointer' + btn.style.display='block' + btn.addEventListener('mouseover',()=>btn.style.color='#787878') + btn.addEventListener('mouseout',()=>btn.style.color='') + }) +} else { + document.querySelectorAll('.managerSettingsButtons').forEach(btn=>{ + btn.style.backgroundImage='url(../../img/pict/b_iconslyb.svg)' + btn.style.height='42px' + btn.style.minWidth='42px' + btn.style.setProperty('background-size','calc(1122px* 1.5)','important') + btn.style.display='inline-block' + btn.style.borderRadius='5px' + btn.style.cursor='pointer' + btn.style.display='flex' + btn.style.flexDirection='column' + btn.style.alignItems='center' + btn.style.fontSize='10px' + btn.style.lineHeight='1' + btn.style.justifyContent = 'flex-end' + btn.style.top='2px' + btn.style.position = 'relative' + btn.style.width = 'auto' + }) + let wrap = document.getElementById('managerSettings') + wrap.style.display = 'flex' + wrap.style.maxWidth = '-webkit-fill-available' + wrap.style.overflowX = 'auto' + wrap.style.overflowY = 'hidden' + wrap.style.justifyContent = 'center' + let div = document.getElementById('managerSettingsDiv') + div.style.height = '-webkit-fill-available' + div.style.display = 'inline-flex' + div.style.whiteSpace = 'nowrap' + div.style.width = 'max-content' + div.style.gap = '7px' + div.style.alignItems = 'center' +} + +window.managerSettings = managerSettings; +window.managerFun = managerFun; +window.saveHow = saveHow; +window.openPageBut = openPageBut; +window.propertiesUrlFun = propertiesUrlFun; +window.selectImgFormButFun = selectImgFormButFun; +window.selectImgFormToFormButFun = selectImgFormToFormButFun; \ No newline at end of file diff --git a/main_plugin/manager/manager.php b/main_plugin/manager/manager.php new file mode 100755 index 0000000..4bdadcc --- /dev/null +++ b/main_plugin/manager/manager.php @@ -0,0 +1,45 @@ + + + + + + + + + + diff --git a/main_plugin/manager/plug.php b/main_plugin/manager/plug.php new file mode 100755 index 0000000..4017ef6 --- /dev/null +++ b/main_plugin/manager/plug.php @@ -0,0 +1,27 @@ + $value) { + $Html = str_replace('{{' . $key . '}}', $value, $Html); + } + echo $Html; + + echo ''; + echo ''; +} +?> diff --git a/main_plugin/pickr/lang.js.php b/main_plugin/pickr/lang.js.php new file mode 100755 index 0000000..a07ef01 --- /dev/null +++ b/main_plugin/pickr/lang.js.php @@ -0,0 +1,21 @@ + $value) { + $placeholders['{{' . $key . '}}'] = $value; +} + +$js = strtr(file_get_contents($path . 'pickr.js'), $placeholders); +echo "window.pickrJs = (function() {\n" . $js . "\n return this;})();"; diff --git a/main_plugin/pickr/pickr.css b/main_plugin/pickr/pickr.css new file mode 100755 index 0000000..87465ed --- /dev/null +++ b/main_plugin/pickr/pickr.css @@ -0,0 +1,511 @@ +.pcr-app { + position: absolute; + z-index: 1; +} +.pcr-app.hide { + display: none; +} + +.theme-container button { + font-family: 'Montserrat', sans-serif; + font-weight: 500; + font-size: 0.95em; + color: #36425b; + outline: none; + background: #e4f1ff; + border: none; + border-bottom: 2px solid rgba(80, 139, 234, 0.67); + padding: 0.6em 0.8em 0.5em; + cursor: pointer; + transition: all 0.3s; + margin: 0 0.5em; + opacity: 0.45; + text-transform: capitalize; +} + +.theme-container button.active { + opacity: 1; +} + +.theme-container h3 { + font-weight: 500; + color: #36425b; +} + +.pickr-container { + margin-top: 2em; + display: none; +} + +main > p { + margin-top: 0.35em; + font-size: 0.75em; + font-weight: 500; + color: #42445a; +} + +@-webkit-keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@media screen and (max-width: 1000px) { + body header { + font-size: 0.6em; + padding: 7vh 0; + } + + body header a { + padding: 1em 2em; + font-weight: 600; + font-size: 1.05em; + } + + main > section { + min-width: 90%; + } + + main > section h2 { + font-size: 1em; + } + + main > section pre { + font-size: 0.9em; + } + + main section.demo .hint svg { + height: 1.2em; + } + + main section.demo .hint span { + transform: translate3d(-3em, -1.4em, 0); + font-size: 0.6em; + } +} + + +/* --------------------- */ + + +/*! Pickr 1.9.1 MIT | https://github.com/Simonwep/pickr */ +.pickr { + position: relative; + overflow: visible; + transform: translateY(0) +} + +.pickr * { + box-sizing: border-box; + outline: none; + border: none; + -webkit-appearance: none +} + +.pickr .pcr-button { + position: relative; + height: 2em; + width: 2em; + padding: .5em; + cursor: pointer; + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Helvetica Neue",Arial,sans-serif; + border-radius: .15em; + background: url("data:image/svg+xml;utf8, ") no-repeat center; + background-size: 0; + transition: all .3s +} + +.pickr .pcr-button::before { + position: absolute; + content: ""; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: url("data:image/svg+xml;utf8, "); + background-size: .5em; + border-radius: .15em; + z-index: -1 +} + +.pickr .pcr-button::before { + z-index: initial +} + +.pickr .pcr-button::after { + position: absolute; + content: ""; + top: 0; + left: 0; + height: 100%; + width: 100%; + transition: background .3s; + background: var(--pcr-color); + border-radius: .15em +} + +.pickr .pcr-button.clear { + background-size: 70% +} + +.pickr .pcr-button.clear::before { + opacity: 0 +} + +.pickr .pcr-button.clear:focus { + box-shadow: 0 0 0 1px rgba(255,255,255,.85),0 0 0 3px var(--pcr-color) +} + +.pickr .pcr-button.disabled { + cursor: not-allowed +} + +.pickr *,.pcr-app * { + box-sizing: border-box; + outline: none; + border: none; + -webkit-appearance: none +} + +.pickr input:focus,.pickr input.pcr-active,.pickr button:focus,.pickr button.pcr-active,.pcr-app input:focus,.pcr-app input.pcr-active,.pcr-app button:focus,.pcr-app button.pcr-active { + box-shadow: 0 0 0 1px rgba(255,255,255,.85),0 0 0 3px var(--pcr-color) +} + +.pickr .pcr-palette,.pickr .pcr-slider,.pcr-app .pcr-palette,.pcr-app .pcr-slider { + transition: box-shadow .3s +} + +.pickr .pcr-palette:focus,.pickr .pcr-slider:focus,.pcr-app .pcr-palette:focus,.pcr-app .pcr-slider:focus { + box-shadow: 0 0 0 1px rgba(255,255,255,.85),0 0 0 3px rgba(0,0,0,.25) +} + +.pcr-app { + display: flex; + flex-direction: column; + z-index: 10000; + border-radius: .1em; + background: #fff; + transition: opacity .3s,visibility 0s .3s; + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Helvetica Neue",Arial,sans-serif; + box-shadow: 0 .15em 1.5em 0 rgba(0,0,0,.1),0 0 1em 0 rgba(0,0,0,.03); +} + +.pcr-app.visible { + transition: opacity .3s; + visibility: visible; + opacity: 1 +} + +.pcr-app .pcr-swatches { + display: flex; + flex-wrap: wrap; + margin-top: .75em +} + +.pcr-app .pcr-swatches.pcr-last { + margin: 0 +} + +@supports(display: grid) { + .pcr-app .pcr-swatches { + display:grid; + align-items: center; + grid-template-columns: repeat(auto-fit, 1.75em) + } +} + +.pcr-app .pcr-swatches>button { + font-size: 1em; + position: relative; + width: calc(1.75em - 5px); + height: calc(1.75em - 5px); + border-radius: .15em; + cursor: pointer; + margin: 2.5px; + flex-shrink: 0; + justify-self: center; + transition: all .15s; + overflow: hidden; + background: rgba(0,0,0,0); + z-index: 1 +} + +.pcr-app .pcr-swatches>button::before { + position: absolute; + content: ""; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: url("data:image/svg+xml;utf8, "); + background-size: 6px; + border-radius: .15em; + z-index: -1 +} + +.pcr-app .pcr-swatches>button::after { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: var(--pcr-color); + border: 1px solid rgba(0,0,0,.05); + border-radius: .15em; + box-sizing: border-box +} + +.pcr-app .pcr-swatches>button:hover { + filter: brightness(1.05) +} + +.pcr-app .pcr-swatches>button:not(.pcr-active) { + box-shadow: none +} + +.pcr-app .pcr-interaction { + display: flex; + flex-wrap: wrap; + align-items: center; + margin: 0 -0.2em 0 -0.2em +} + +.pcr-app .pcr-interaction>* { + /* margin: 0 .2em */ +} + +.pcr-app .pcr-interaction input { + letter-spacing: .07em; + font-size: .75em; + text-align: center; + cursor: pointer; + color: #75797e; + background: #f1f3f4; + border-radius: .15em; + transition: all .15s; + padding: .45em .5em; +} + +.pcr-app .pcr-interaction input:hover { + filter: brightness(0.975) +} + +.pcr-app .pcr-interaction input:focus { + box-shadow: 0 0 0 1px rgba(255,255,255,.85),0 0 0 3px rgba(66,133,244,.75) +} + +.pcr-app .pcr-interaction .pcr-result { + color: #75797e; + text-align: left; + /* flex: 1 1 8em; */ + width: 6em; + transition: all .2s; + border-radius: .15em; + background: #f1f3f4; + cursor: text +} + +.pcr-app .pcr-interaction .pcr-result::-moz-selection { + background: #4285f4; + color: #fff +} + +.pcr-app .pcr-interaction .pcr-result::selection { + background: #4285f4; + color: #fff +} + +.pcr-app .pcr-interaction .pcr-type.active { + color: #fff; + background: #4285f4 +} + +.pcr-app .pcr-interaction .pcr-save,.pcr-app .pcr-interaction .pcr-cancel,.pcr-app .pcr-interaction .pcr-clear { + color: #fff; + width: auto +} + +.pcr-app .pcr-interaction .pcr-save,.pcr-app .pcr-interaction .pcr-cancel,.pcr-app .pcr-interaction .pcr-clear { + color: #fff +} + +.pcr-app .pcr-interaction .pcr-save:hover,.pcr-app .pcr-interaction .pcr-cancel:hover,.pcr-app .pcr-interaction .pcr-clear:hover { + filter: brightness(0.925) +} + +.pcr-app .pcr-interaction .pcr-save { + background: #4285f4 +} + +.pcr-app .pcr-interaction .pcr-clear,.pcr-app .pcr-interaction .pcr-cancel { + background: #f44250 +} + +.pcr-app .pcr-interaction .pcr-clear:focus,.pcr-app .pcr-interaction .pcr-cancel:focus { + box-shadow: 0 0 0 1px rgba(255,255,255,.85),0 0 0 3px rgba(244,66,80,.75) +} + +.pcr-app .pcr-selection .pcr-picker { + position: absolute; + height: 18px; + width: 18px; + border: 2px solid #fff; + border-radius: 100%; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none +} + +.pcr-app .pcr-selection .pcr-color-palette,.pcr-app .pcr-selection .pcr-color-chooser,.pcr-app .pcr-selection .pcr-color-opacity { + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + display: flex; + flex-direction: column; + cursor: grab; + cursor: -webkit-grab +} + +.pcr-app .pcr-selection .pcr-color-palette:active,.pcr-app .pcr-selection .pcr-color-chooser:active,.pcr-app .pcr-selection .pcr-color-opacity:active { + cursor: grabbing; + cursor: -webkit-grabbing +} + +.pcr-app[data-theme=nano] { + width: 150px; + max-width: 150px; +} + +.pcr-app[data-theme=nano] .pcr-swatches { + margin-top: .6em; + padding: 0 .6em +} + +.pcr-app[data-theme=nano] .pcr-interaction { + padding: 0 .6em .6em .6em +} + +.pcr-app[data-theme=nano] .pcr-selection { + display: grid; +/* grid-gap: .6em; + grid-template-columns: 1fr 4fr; */ + grid-template-rows: 5fr auto auto; + align-items: center; + width: 100%; + align-self: flex-start +} + +.pcr-app[data-theme=nano] .pcr-selection .pcr-color-preview { + grid-area: 2/1/4/1; + height: 100%; + width: 100%; + display: flex; + flex-direction: row; + justify-content: center; + margin-left: .6em +} + +.pcr-app[data-theme=nano] .pcr-selection .pcr-color-preview .pcr-last-color { + display: none +} + +.pcr-app[data-theme=nano] .pcr-selection .pcr-color-preview .pcr-current-color { + position: relative; + background: var(--pcr-color); + width: 2em; + height: 2em; + border-radius: 50em; + overflow: hidden +} + +.pcr-app[data-theme=nano] .pcr-selection .pcr-color-preview .pcr-current-color::before { + position: absolute; + content: ""; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: url("data:image/svg+xml;utf8, "); + background-size: .5em; + border-radius: .15em; + z-index: -1 +} + +.pcr-app[data-theme=nano] .pcr-selection .pcr-color-palette { + grid-area: 1/1/2/3; + width: 150px; + height: 100px; + z-index: 1 +} + +.pcr-app[data-theme=nano] .pcr-selection .pcr-color-palette .pcr-palette { + border-radius: .15em; + width: 100%; + height: 100% +} + +.pcr-app[data-theme=nano] .pcr-selection .pcr-color-palette .pcr-palette::before { + position: absolute; + content: ""; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: url("data:image/svg+xml;utf8, "); + background-size: .5em; + border-radius: .15em; + z-index: -1 +} + +.pcr-app[data-theme=nano] .pcr-selection .pcr-color-chooser { + grid-area: 2/2/2/2 +} + +.pcr-app[data-theme=nano] .pcr-selection .pcr-color-opacity { + grid-area: 3/2/3/2 +} + +.pcr-app[data-theme=nano] .pcr-selection .pcr-selection .pcr-color-opacity { + margin: 0 .6em +} + +.pcr-color-chooser { + height: .5em; + width: 140px; + margin: 10px 5px 0px 5px; +} + +.pcr-app[data-theme=nano] .pcr-selection .pcr-color-chooser .pcr-picker,.pcr-app[data-theme=nano] .pcr-selection .pcr-color-opacity .pcr-picker { + top: 50%; + transform: translateY(-50%) +} + +.pcr-app[data-theme=nano] .pcr-selection .pcr-color-chooser .pcr-slider,.pcr-app[data-theme=nano] .pcr-selection .pcr-color-opacity .pcr-slider { + flex-grow: 1; + border-radius: 50em +} + +.pcr-app[data-theme=nano] .pcr-selection .pcr-color-chooser .pcr-slider { + background: linear-gradient(to right, hsl(0, 100%, 50%), hsl(60, 100%, 50%), hsl(120, 100%, 50%), hsl(180, 100%, 50%), hsl(240, 100%, 50%), hsl(300, 100%, 50%), hsl(0, 100%, 50%)) +} + +.pcr-app[data-theme=nano] .pcr-selection .pcr-color-opacity .pcr-slider { + background: linear-gradient(to right, transparent, black),url("data:image/svg+xml;utf8, "); + background-size: 100%,.25em +} diff --git a/main_plugin/pickr/pickr.js b/main_plugin/pickr/pickr.js new file mode 100755 index 0000000..547c7ca --- /dev/null +++ b/main_plugin/pickr/pickr.js @@ -0,0 +1,4998 @@ +/** + * @file pickr.js + * @brief Основной файл pickr, реализует выбор цвета на сайте +*/ + +document.addEventListener('LoadpickrJs', () => { + console.log(1) + const pickrContainer = document.querySelector('.pickr-container'); + if (!pickrContainer) return; + + const themes = [ + ['nano', { + components: { + hue: true, + interaction: { + input: true, + clear: true + } + } + }] + ]; + + const buttons = []; + let pickr = null; + + for (const [theme, config] of themes) { + const button = document.createElement('button'); + button.textContent = theme; + buttons.push(button); + + button.addEventListener('click', () => { + const el = document.createElement('p'); + pickrContainer.appendChild(el); + + if (pickr) { + pickr.destroyAndRemove(); + } + + for (const btn of buttons) { + btn.classList[btn === button ? 'add' : 'remove']('active'); + } + + pickr = new Pickr(Object.assign({ + el, + theme, + default: '#000000' + }, config)); + + pickr.on('init', () => { + const app = pickr.getRoot().app; + if (app && pickrContainer.parentNode) { + pickrContainer.parentNode.replaceChild(app, pickrContainer); + if (document.querySelector('.pcr-app')) document.querySelector('.pcr-app').classList.add('hide'); + document.querySelector('.pcr-app').style.top = ''; + } + const clearBtn = document.querySelector('.pcr-clear'); + clearBtn.addEventListener('click', () => { + if (currentRange && currentFormat) { + simpleUnformat(currentRange, currentFormat); + } + const app = document.querySelector('.pcr-app'); + if (app) { + app.classList.add('hide'); + } + }); + }); + }); + } + + buttons[0].click(); +}, { once: true }); + + + +/* --------------------- */ + + +/*! Pickr 1.9.1 MIT | https://github.com/Simonwep/pickr */ +!function(t, e) { + "object" == typeof exports && "object" == typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define([], e) : "object" == typeof exports ? exports.Pickr = e() : t.Pickr = e() +}(self, ( () => ( () => { + "use strict"; + var t = { + 8280: (t, e, r) => { + var n = r(1435) + , o = r(7113) + , i = TypeError; + t.exports = function(t) { + if (n(t)) + return t; + throw new i(o(t) + " is not a function") + } + } + , + 5478: (t, e, r) => { + var n = r(4127) + , o = r(7113) + , i = TypeError; + t.exports = function(t) { + if (n(t)) + return t; + throw new i(o(t) + " is not a constructor") + } + } + , + 1420: (t, e, r) => { + var n = r(6143) + , o = String + , i = TypeError; + t.exports = function(t) { + if (n(t)) + return t; + throw new i("Can't set " + o(t) + " as a prototype") + } + } + , + 5127: (t, e, r) => { + var n = r(3633) + , o = r(8250) + , i = r(2587).f + , a = n("unscopables") + , c = Array.prototype; + void 0 === c[a] && i(c, a, { + configurable: !0, + value: o(null) + }), + t.exports = function(t) { + c[a][t] = !0 + } + } + , + 6691: (t, e, r) => { + var n = r(449).charAt; + t.exports = function(t, e, r) { + return e + (r ? n(t, e).length : 1) + } + } + , + 3349: (t, e, r) => { + var n = r(3400) + , o = String + , i = TypeError; + t.exports = function(t) { + if (n(t)) + return t; + throw new i(o(t) + " is not an object") + } + } + , + 3833: (t, e, r) => { + var n = r(9603).forEach + , o = r(4832)("forEach"); + t.exports = o ? [].forEach : function(t) { + return n(this, t, arguments.length > 1 ? arguments[1] : void 0) + } + } + , + 7022: (t, e, r) => { + var n = r(3122) + , o = r(9295) + , i = r(4683) + , a = r(325) + , c = r(9187) + , u = r(4127) + , s = r(608) + , l = r(6558) + , p = r(4663) + , f = r(2153) + , v = Array; + t.exports = function(t) { + var e = i(t) + , r = u(this) + , h = arguments.length + , d = h > 1 ? arguments[1] : void 0 + , g = void 0 !== d; + g && (d = n(d, h > 2 ? arguments[2] : void 0)); + var y, b, m, x, w, S, _ = f(e), A = 0; + if (!_ || this === v && c(_)) + for (y = s(e), + b = r ? new this(y) : v(y); y > A; A++) + S = g ? d(e[A], A) : e[A], + l(b, A, S); + else + for (b = r ? new this : [], + w = (x = p(e, _)).next; !(m = o(w, x)).done; A++) + S = g ? a(x, d, [m.value, A], !0) : m.value, + l(b, A, S); + return b.length = A, + b + } + } + , + 1675: (t, e, r) => { + var n = r(8799) + , o = r(3104) + , i = r(608) + , a = function(t) { + return function(e, r, a) { + var c = n(e) + , u = i(c); + if (0 === u) + return !t && -1; + var s, l = o(a, u); + if (t && r != r) { + for (; u > l; ) + if ((s = c[l++]) != s) + return !0 + } else + for (; u > l; l++) + if ((t || l in c) && c[l] === r) + return t || l || 0; + return !t && -1 + } + }; + t.exports = { + includes: a(!0), + indexOf: a(!1) + } + } + , + 9603: (t, e, r) => { + var n = r(3122) + , o = r(2538) + , i = r(6729) + , a = r(4683) + , c = r(608) + , u = r(3159) + , s = o([].push) + , l = function(t) { + var e = 1 === t + , r = 2 === t + , o = 3 === t + , l = 4 === t + , p = 6 === t + , f = 7 === t + , v = 5 === t || p; + return function(h, d, g, y) { + for (var b, m, x = a(h), w = i(x), S = c(w), _ = n(d, g), A = 0, O = y || u, E = e ? O(h, S) : r || f ? O(h, 0) : void 0; S > A; A++) + if ((v || A in w) && (m = _(b = w[A], A, x), + t)) + if (e) + E[A] = m; + else if (m) + switch (t) { + case 3: + return !0; + case 5: + return b; + case 6: + return A; + case 2: + s(E, b) + } + else + switch (t) { + case 4: + return !1; + case 7: + s(E, b) + } + return p ? -1 : o || l ? l : E + } + }; + t.exports = { + forEach: l(0), + map: l(1), + filter: l(2), + some: l(3), + every: l(4), + find: l(5), + findIndex: l(6), + filterReject: l(7) + } + } + , + 9331: (t, e, r) => { + var n = r(3849) + , o = r(3633) + , i = r(7722) + , a = o("species"); + t.exports = function(t) { + return i >= 51 || !n((function() { + var e = []; + return (e.constructor = {})[a] = function() { + return { + foo: 1 + } + } + , + 1 !== e[t](Boolean).foo + } + )) + } + } + , + 4832: (t, e, r) => { + var n = r(3849); + t.exports = function(t, e) { + var r = [][t]; + return !!r && n((function() { + r.call(null, e || function() { + return 1 + } + , 1) + } + )) + } + } + , + 4534: (t, e, r) => { + var n = r(1870) + , o = r(7506) + , i = TypeError + , a = Object.getOwnPropertyDescriptor + , c = n && !function() { + if (void 0 !== this) + return !0; + try { + Object.defineProperty([], "length", { + writable: !1 + }).length = 1 + } catch (t) { + return t instanceof TypeError + } + }(); + t.exports = c ? function(t, e) { + if (o(t) && !a(t, "length").writable) + throw new i("Cannot set read only .length"); + return t.length = e + } + : function(t, e) { + return t.length = e + } + } + , + 850: (t, e, r) => { + var n = r(2538); + t.exports = n([].slice) + } + , + 6535: (t, e, r) => { + var n = r(7506) + , o = r(4127) + , i = r(3400) + , a = r(3633)("species") + , c = Array; + t.exports = function(t) { + var e; + return n(t) && (e = t.constructor, + (o(e) && (e === c || n(e.prototype)) || i(e) && null === (e = e[a])) && (e = void 0)), + void 0 === e ? c : e + } + } + , + 3159: (t, e, r) => { + var n = r(6535); + t.exports = function(t, e) { + return new (n(t))(0 === e ? 0 : e) + } + } + , + 325: (t, e, r) => { + var n = r(3349) + , o = r(9857); + t.exports = function(t, e, r, i) { + try { + return i ? e(n(r)[0], r[1]) : e(r) + } catch (e) { + o(t, "throw", e) + } + } + } + , + 6786: (t, e, r) => { + var n = r(3633)("iterator") + , o = !1; + try { + var i = 0 + , a = { + next: function() { + return { + done: !!i++ + } + }, + return: function() { + o = !0 + } + }; + a[n] = function() { + return this + } + , + Array.from(a, (function() { + throw 2 + } + )) + } catch (t) {} + t.exports = function(t, e) { + try { + if (!e && !o) + return !1 + } catch (t) { + return !1 + } + var r = !1; + try { + var i = {}; + i[n] = function() { + return { + next: function() { + return { + done: r = !0 + } + } + } + } + , + t(i) + } catch (t) {} + return r + } + } + , + 2750: (t, e, r) => { + var n = r(2538) + , o = n({}.toString) + , i = n("".slice); + t.exports = function(t) { + return i(o(t), 8, -1) + } + } + , + 5361: (t, e, r) => { + var n = r(6002) + , o = r(1435) + , i = r(2750) + , a = r(3633)("toStringTag") + , c = Object + , u = "Arguments" === i(function() { + return arguments + }()); + t.exports = n ? i : function(t) { + var e, r, n; + return void 0 === t ? "Undefined" : null === t ? "Null" : "string" == typeof (r = function(t, e) { + try { + return t[e] + } catch (t) {} + }(e = c(t), a)) ? r : u ? i(e) : "Object" === (n = i(e)) && o(e.callee) ? "Arguments" : n + } + } + , + 4518: (t, e, r) => { + var n = r(379) + , o = r(2905) + , i = r(9697) + , a = r(2587); + t.exports = function(t, e, r) { + for (var c = o(e), u = a.f, s = i.f, l = 0; l < c.length; l++) { + var p = c[l]; + n(t, p) || r && n(r, p) || u(t, p, s(e, p)) + } + } + } + , + 5850: (t, e, r) => { + var n = r(3633)("match"); + t.exports = function(t) { + var e = /./; + try { + "/./"[t](e) + } catch (r) { + try { + return e[n] = !1, + "/./"[t](e) + } catch (t) {} + } + return !1 + } + } + , + 4737: (t, e, r) => { + var n = r(3849); + t.exports = !n((function() { + function t() {} + return t.prototype.constructor = null, + Object.getPrototypeOf(new t) !== t.prototype + } + )) + } + , + 9055: t => { + t.exports = function(t, e) { + return { + value: t, + done: e + } + } + } + , + 4477: (t, e, r) => { + var n = r(1870) + , o = r(2587) + , i = r(5658); + t.exports = n ? function(t, e, r) { + return o.f(t, e, i(1, r)) + } + : function(t, e, r) { + return t[e] = r, + t + } + } + , + 5658: t => { + t.exports = function(t, e) { + return { + enumerable: !(1 & t), + configurable: !(2 & t), + writable: !(4 & t), + value: e + } + } + } + , + 6558: (t, e, r) => { + var n = r(1870) + , o = r(2587) + , i = r(5658); + t.exports = function(t, e, r) { + n ? o.f(t, e, i(0, r)) : t[e] = r + } + } + , + 7448: (t, e, r) => { + var n = r(2713) + , o = r(2587); + t.exports = function(t, e, r) { + return r.get && n(r.get, e, { + getter: !0 + }), + r.set && n(r.set, e, { + setter: !0 + }), + o.f(t, e, r) + } + } + , + 2202: (t, e, r) => { + var n = r(1435) + , o = r(2587) + , i = r(2713) + , a = r(3135); + t.exports = function(t, e, r, c) { + c || (c = {}); + var u = c.enumerable + , s = void 0 !== c.name ? c.name : e; + if (n(r) && i(r, s, c), + c.global) + u ? t[e] = r : a(e, r); + else { + try { + c.unsafe ? t[e] && (u = !0) : delete t[e] + } catch (t) {} + u ? t[e] = r : o.f(t, e, { + value: r, + enumerable: !1, + configurable: !c.nonConfigurable, + writable: !c.nonWritable + }) + } + return t + } + } + , + 3135: (t, e, r) => { + var n = r(9317) + , o = Object.defineProperty; + t.exports = function(t, e) { + try { + o(n, t, { + value: e, + configurable: !0, + writable: !0 + }) + } catch (r) { + n[t] = e + } + return e + } + } + , + 60: (t, e, r) => { + var n = r(7113) + , o = TypeError; + t.exports = function(t, e) { + if (!delete t[e]) + throw new o("Cannot delete property " + n(e) + " of " + n(t)) + } + } + , + 1870: (t, e, r) => { + var n = r(3849); + t.exports = !n((function() { + return 7 !== Object.defineProperty({}, 1, { + get: function() { + return 7 + } + })[1] + } + )) + } + , + 8249: (t, e, r) => { + var n = r(9317) + , o = r(3400) + , i = n.document + , a = o(i) && o(i.createElement); + t.exports = function(t) { + return a ? i.createElement(t) : {} + } + } + , + 2387: t => { + var e = TypeError; + t.exports = function(t) { + if (t > 9007199254740991) + throw e("Maximum allowed index exceeded"); + return t + } + } + , + 1530: t => { + t.exports = { + CSSRuleList: 0, + CSSStyleDeclaration: 0, + CSSValueList: 0, + ClientRectList: 0, + DOMRectList: 0, + DOMStringList: 0, + DOMTokenList: 1, + DataTransferItemList: 0, + FileList: 0, + HTMLAllCollection: 0, + HTMLCollection: 0, + HTMLFormElement: 0, + HTMLSelectElement: 0, + MediaList: 0, + MimeTypeArray: 0, + NamedNodeMap: 0, + NodeList: 1, + PaintRequestList: 0, + Plugin: 0, + PluginArray: 0, + SVGLengthList: 0, + SVGNumberList: 0, + SVGPathSegList: 0, + SVGPointList: 0, + SVGStringList: 0, + SVGTransformList: 0, + SourceBufferList: 0, + StyleSheetList: 0, + TextTrackCueList: 0, + TextTrackList: 0, + TouchList: 0 + } + } + , + 6334: (t, e, r) => { + var n = r(8249)("span").classList + , o = n && n.constructor && n.constructor.prototype; + t.exports = o === Object.prototype ? void 0 : o + } + , + 446: t => { + t.exports = "undefined" != typeof navigator && String(navigator.userAgent) || "" + } + , + 7722: (t, e, r) => { + var n, o, i = r(9317), a = r(446), c = i.process, u = i.Deno, s = c && c.versions || u && u.version, l = s && s.v8; + l && (o = (n = l.split("."))[0] > 0 && n[0] < 4 ? 1 : +(n[0] + n[1])), + !o && a && (!(n = a.match(/Edge\/(\d+)/)) || n[1] >= 74) && (n = a.match(/Chrome\/(\d+)/)) && (o = +n[1]), + t.exports = o + } + , + 5333: t => { + t.exports = ["constructor", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "toLocaleString", "toString", "valueOf"] + } + , + 3076: (t, e, r) => { + var n = r(9317) + , o = r(9697).f + , i = r(4477) + , a = r(2202) + , c = r(3135) + , u = r(4518) + , s = r(9946); + t.exports = function(t, e) { + var r, l, p, f, v, h = t.target, d = t.global, g = t.stat; + if (r = d ? n : g ? n[h] || c(h, {}) : n[h] && n[h].prototype) + for (l in e) { + if (f = e[l], + p = t.dontCallGetSet ? (v = o(r, l)) && v.value : r[l], + !s(d ? l : h + (g ? "." : "#") + l, t.forced) && void 0 !== p) { + if (typeof f == typeof p) + continue; + u(f, p) + } + (t.sham || p && p.sham) && i(f, "sham", !0), + a(r, l, f, t) + } + } + } + , + 3849: t => { + t.exports = function(t) { + try { + return !!t() + } catch (t) { + return !0 + } + } + } + , + 2670: (t, e, r) => { + r(9981); + var n = r(9295) + , o = r(2202) + , i = r(1601) + , a = r(3849) + , c = r(3633) + , u = r(4477) + , s = c("species") + , l = RegExp.prototype; + t.exports = function(t, e, r, p) { + var f = c(t) + , v = !a((function() { + var e = {}; + return e[f] = function() { + return 7 + } + , + 7 !== ""[t](e) + } + )) + , h = v && !a((function() { + var e = !1 + , r = /a/; + return "split" === t && ((r = {}).constructor = {}, + r.constructor[s] = function() { + return r + } + , + r.flags = "", + r[f] = /./[f]), + r.exec = function() { + return e = !0, + null + } + , + r[f](""), + !e + } + )); + if (!v || !h || r) { + var d = /./[f] + , g = e(f, ""[t], (function(t, e, r, o, a) { + var c = e.exec; + return c === i || c === l.exec ? v && !a ? { + done: !0, + value: n(d, e, r, o) + } : { + done: !0, + value: n(t, r, e, o) + } : { + done: !1 + } + } + )); + o(String.prototype, t, g[0]), + o(l, f, g[1]) + } + p && u(l[f], "sham", !0) + } + } + , + 347: (t, e, r) => { + var n = r(3602) + , o = Function.prototype + , i = o.apply + , a = o.call; + t.exports = "object" == typeof Reflect && Reflect.apply || (n ? a.bind(i) : function() { + return a.apply(i, arguments) + } + ) + } + , + 3122: (t, e, r) => { + var n = r(4890) + , o = r(8280) + , i = r(3602) + , a = n(n.bind); + t.exports = function(t, e) { + return o(t), + void 0 === e ? t : i ? a(t, e) : function() { + return t.apply(e, arguments) + } + } + } + , + 3602: (t, e, r) => { + var n = r(3849); + t.exports = !n((function() { + var t = function() {} + .bind(); + return "function" != typeof t || t.hasOwnProperty("prototype") + } + )) + } + , + 9295: (t, e, r) => { + var n = r(3602) + , o = Function.prototype.call; + t.exports = n ? o.bind(o) : function() { + return o.apply(o, arguments) + } + } + , + 8784: (t, e, r) => { + var n = r(1870) + , o = r(379) + , i = Function.prototype + , a = n && Object.getOwnPropertyDescriptor + , c = o(i, "name") + , u = c && "something" === function() {} + .name + , s = c && (!n || n && a(i, "name").configurable); + t.exports = { + EXISTS: c, + PROPER: u, + CONFIGURABLE: s + } + } + , + 6632: (t, e, r) => { + var n = r(2538) + , o = r(8280); + t.exports = function(t, e, r) { + try { + return n(o(Object.getOwnPropertyDescriptor(t, e)[r])) + } catch (t) {} + } + } + , + 4890: (t, e, r) => { + var n = r(2750) + , o = r(2538); + t.exports = function(t) { + if ("Function" === n(t)) + return o(t) + } + } + , + 2538: (t, e, r) => { + var n = r(3602) + , o = Function.prototype + , i = o.call + , a = n && o.bind.bind(i, i); + t.exports = n ? a : function(t) { + return function() { + return i.apply(t, arguments) + } + } + } + , + 5793: (t, e, r) => { + var n = r(9317) + , o = r(1435); + t.exports = function(t, e) { + return arguments.length < 2 ? (r = n[t], + o(r) ? r : void 0) : n[t] && n[t][e]; + var r + } + } + , + 2153: (t, e, r) => { + var n = r(5361) + , o = r(2996) + , i = r(2303) + , a = r(1575) + , c = r(3633)("iterator"); + t.exports = function(t) { + if (!i(t)) + return o(t, c) || o(t, "@@iterator") || a[n(t)] + } + } + , + 4663: (t, e, r) => { + var n = r(9295) + , o = r(8280) + , i = r(3349) + , a = r(7113) + , c = r(2153) + , u = TypeError; + t.exports = function(t, e) { + var r = arguments.length < 2 ? c(t) : e; + if (o(r)) + return i(n(r, t)); + throw new u(a(t) + " is not iterable") + } + } + , + 9023: (t, e, r) => { + var n = r(2538) + , o = r(7506) + , i = r(1435) + , a = r(2750) + , c = r(2277) + , u = n([].push); + t.exports = function(t) { + if (i(t)) + return t; + if (o(t)) { + for (var e = t.length, r = [], n = 0; n < e; n++) { + var s = t[n]; + "string" == typeof s ? u(r, s) : "number" != typeof s && "Number" !== a(s) && "String" !== a(s) || u(r, c(s)) + } + var l = r.length + , p = !0; + return function(t, e) { + if (p) + return p = !1, + e; + if (o(this)) + return e; + for (var n = 0; n < l; n++) + if (r[n] === t) + return e + } + } + } + } + , + 2996: (t, e, r) => { + var n = r(8280) + , o = r(2303); + t.exports = function(t, e) { + var r = t[e]; + return o(r) ? void 0 : n(r) + } + } + , + 1748: (t, e, r) => { + var n = r(2538) + , o = r(4683) + , i = Math.floor + , a = n("".charAt) + , c = n("".replace) + , u = n("".slice) + , s = /\$([$&'`]|\d{1,2}|<[^>]*>)/g + , l = /\$([$&'`]|\d{1,2})/g; + t.exports = function(t, e, r, n, p, f) { + var v = r + t.length + , h = n.length + , d = l; + return void 0 !== p && (p = o(p), + d = s), + c(f, d, (function(o, c) { + var s; + switch (a(c, 0)) { + case "$": + return "$"; + case "&": + return t; + case "`": + return u(e, 0, r); + case "'": + return u(e, v); + case "<": + s = p[u(c, 1, -1)]; + break; + default: + var l = +c; + if (0 === l) + return o; + if (l > h) { + var f = i(l / 10); + return 0 === f ? o : f <= h ? void 0 === n[f - 1] ? a(c, 1) : n[f - 1] + a(c, 1) : o + } + s = n[l - 1] + } + return void 0 === s ? "" : s + } + )) + } + } + , + 9317: function(t, e, r) { + var n = function(t) { + return t && t.Math === Math && t + }; + t.exports = n("object" == typeof globalThis && globalThis) || n("object" == typeof window && window) || n("object" == typeof self && self) || n("object" == typeof r.g && r.g) || n("object" == typeof this && this) || function() { + return this + }() || Function("return this")() + }, + 379: (t, e, r) => { + var n = r(2538) + , o = r(4683) + , i = n({}.hasOwnProperty); + t.exports = Object.hasOwn || function(t, e) { + return i(o(t), e) + } + } + , + 147: t => { + t.exports = {} + } + , + 651: (t, e, r) => { + var n = r(5793); + t.exports = n("document", "documentElement") + } + , + 7527: (t, e, r) => { + var n = r(1870) + , o = r(3849) + , i = r(8249); + t.exports = !n && !o((function() { + return 7 !== Object.defineProperty(i("div"), "a", { + get: function() { + return 7 + } + }).a + } + )) + } + , + 6729: (t, e, r) => { + var n = r(2538) + , o = r(3849) + , i = r(2750) + , a = Object + , c = n("".split); + t.exports = o((function() { + return !a("z").propertyIsEnumerable(0) + } + )) ? function(t) { + return "String" === i(t) ? c(t, "") : a(t) + } + : a + } + , + 8285: (t, e, r) => { + var n = r(1435) + , o = r(3400) + , i = r(3425); + t.exports = function(t, e, r) { + var a, c; + return i && n(a = e.constructor) && a !== r && o(c = a.prototype) && c !== r.prototype && i(t, c), + t + } + } + , + 5188: (t, e, r) => { + var n = r(2538) + , o = r(1435) + , i = r(1511) + , a = n(Function.toString); + o(i.inspectSource) || (i.inspectSource = function(t) { + return a(t) + } + ), + t.exports = i.inspectSource + } + , + 5043: (t, e, r) => { + var n, o, i, a = r(740), c = r(9317), u = r(3400), s = r(4477), l = r(379), p = r(1511), f = r(6769), v = r(147), h = "Object already initialized", d = c.TypeError, g = c.WeakMap; + if (a || p.state) { + var y = p.state || (p.state = new g); + y.get = y.get, + y.has = y.has, + y.set = y.set, + n = function(t, e) { + if (y.has(t)) + throw new d(h); + return e.facade = t, + y.set(t, e), + e + } + , + o = function(t) { + return y.get(t) || {} + } + , + i = function(t) { + return y.has(t) + } + } else { + var b = f("state"); + v[b] = !0, + n = function(t, e) { + if (l(t, b)) + throw new d(h); + return e.facade = t, + s(t, b, e), + e + } + , + o = function(t) { + return l(t, b) ? t[b] : {} + } + , + i = function(t) { + return l(t, b) + } + } + t.exports = { + set: n, + get: o, + has: i, + enforce: function(t) { + return i(t) ? o(t) : n(t, {}) + }, + getterFor: function(t) { + return function(e) { + var r; + if (!u(e) || (r = o(e)).type !== t) + throw new d("Incompatible receiver, " + t + " required"); + return r + } + } + } + } + , + 9187: (t, e, r) => { + var n = r(3633) + , o = r(1575) + , i = n("iterator") + , a = Array.prototype; + t.exports = function(t) { + return void 0 !== t && (o.Array === t || a[i] === t) + } + } + , + 7506: (t, e, r) => { + var n = r(2750); + t.exports = Array.isArray || function(t) { + return "Array" === n(t) + } + } + , + 1435: t => { + var e = "object" == typeof document && document.all; + t.exports = void 0 === e && void 0 !== e ? function(t) { + return "function" == typeof t || t === e + } + : function(t) { + return "function" == typeof t + } + } + , + 4127: (t, e, r) => { + var n = r(2538) + , o = r(3849) + , i = r(1435) + , a = r(5361) + , c = r(5793) + , u = r(5188) + , s = function() {} + , l = c("Reflect", "construct") + , p = /^\s*(?:class|function)\b/ + , f = n(p.exec) + , v = !p.test(s) + , h = function(t) { + if (!i(t)) + return !1; + try { + return l(s, [], t), + !0 + } catch (t) { + return !1 + } + } + , d = function(t) { + if (!i(t)) + return !1; + switch (a(t)) { + case "AsyncFunction": + case "GeneratorFunction": + case "AsyncGeneratorFunction": + return !1 + } + try { + return v || !!f(p, u(t)) + } catch (t) { + return !0 + } + }; + d.sham = !0, + t.exports = !l || o((function() { + var t; + return h(h.call) || !h(Object) || !h((function() { + t = !0 + } + )) || t + } + )) ? d : h + } + , + 9946: (t, e, r) => { + var n = r(3849) + , o = r(1435) + , i = /#|\.prototype\./ + , a = function(t, e) { + var r = u[c(t)]; + return r === l || r !== s && (o(e) ? n(e) : !!e) + } + , c = a.normalize = function(t) { + return String(t).replace(i, ".").toLowerCase() + } + , u = a.data = {} + , s = a.NATIVE = "N" + , l = a.POLYFILL = "P"; + t.exports = a + } + , + 2303: t => { + t.exports = function(t) { + return null == t + } + } + , + 3400: (t, e, r) => { + var n = r(1435); + t.exports = function(t) { + return "object" == typeof t ? null !== t : n(t) + } + } + , + 6143: (t, e, r) => { + var n = r(3400); + t.exports = function(t) { + return n(t) || null === t + } + } + , + 4709: t => { + t.exports = !1 + } + , + 8914: (t, e, r) => { + var n = r(3400) + , o = r(2750) + , i = r(3633)("match"); + t.exports = function(t) { + var e; + return n(t) && (void 0 !== (e = t[i]) ? !!e : "RegExp" === o(t)) + } + } + , + 4975: (t, e, r) => { + var n = r(5793) + , o = r(1435) + , i = r(8559) + , a = r(9470) + , c = Object; + t.exports = a ? function(t) { + return "symbol" == typeof t + } + : function(t) { + var e = n("Symbol"); + return o(e) && i(e.prototype, c(t)) + } + } + , + 9857: (t, e, r) => { + var n = r(9295) + , o = r(3349) + , i = r(2996); + t.exports = function(t, e, r) { + var a, c; + o(t); + try { + if (!(a = i(t, "return"))) { + if ("throw" === e) + throw r; + return r + } + a = n(a, t) + } catch (t) { + c = !0, + a = t + } + if ("throw" === e) + throw r; + if (c) + throw a; + return o(a), + r + } + } + , + 1104: (t, e, r) => { + var n = r(2603).IteratorPrototype + , o = r(8250) + , i = r(5658) + , a = r(7621) + , c = r(1575) + , u = function() { + return this + }; + t.exports = function(t, e, r, s) { + var l = e + " Iterator"; + return t.prototype = o(n, { + next: i(+!s, r) + }), + a(t, l, !1, !0), + c[l] = u, + t + } + } + , + 654: (t, e, r) => { + var n = r(3076) + , o = r(9295) + , i = r(4709) + , a = r(8784) + , c = r(1435) + , u = r(1104) + , s = r(4909) + , l = r(3425) + , p = r(7621) + , f = r(4477) + , v = r(2202) + , h = r(3633) + , d = r(1575) + , g = r(2603) + , y = a.PROPER + , b = a.CONFIGURABLE + , m = g.IteratorPrototype + , x = g.BUGGY_SAFARI_ITERATORS + , w = h("iterator") + , S = "keys" + , _ = "values" + , A = "entries" + , O = function() { + return this + }; + t.exports = function(t, e, r, a, h, g, E) { + u(r, e, a); + var j, C, k, P = function(t) { + if (t === h && F) + return F; + if (!x && t && t in T) + return T[t]; + switch (t) { + case S: + case _: + case A: + return function() { + return new r(this,t) + } + } + return function() { + return new r(this) + } + }, I = e + " Iterator", R = !1, T = t.prototype, L = T[w] || T["@@iterator"] || h && T[h], F = !x && L || P(h), N = "Array" === e && T.entries || L; + if (N && (j = s(N.call(new t))) !== Object.prototype && j.next && (i || s(j) === m || (l ? l(j, m) : c(j[w]) || v(j, w, O)), + p(j, I, !0, !0), + i && (d[I] = O)), + y && h === _ && L && L.name !== _ && (!i && b ? f(T, "name", _) : (R = !0, + F = function() { + return o(L, this) + } + )), + h) + if (C = { + values: P(_), + keys: g ? F : P(S), + entries: P(A) + }, + E) + for (k in C) + (x || R || !(k in T)) && v(T, k, C[k]); + else + n({ + target: e, + proto: !0, + forced: x || R + }, C); + return i && !E || T[w] === F || v(T, w, F, { + name: h + }), + d[e] = F, + C + } + } + , + 2603: (t, e, r) => { + var n, o, i, a = r(3849), c = r(1435), u = r(3400), s = r(8250), l = r(4909), p = r(2202), f = r(3633), v = r(4709), h = f("iterator"), d = !1; + [].keys && ("next"in (i = [].keys()) ? (o = l(l(i))) !== Object.prototype && (n = o) : d = !0), + !u(n) || a((function() { + var t = {}; + return n[h].call(t) !== t + } + )) ? n = {} : v && (n = s(n)), + c(n[h]) || p(n, h, (function() { + return this + } + )), + t.exports = { + IteratorPrototype: n, + BUGGY_SAFARI_ITERATORS: d + } + } + , + 1575: t => { + t.exports = {} + } + , + 608: (t, e, r) => { + var n = r(8020); + t.exports = function(t) { + return n(t.length) + } + } + , + 2713: (t, e, r) => { + var n = r(2538) + , o = r(3849) + , i = r(1435) + , a = r(379) + , c = r(1870) + , u = r(8784).CONFIGURABLE + , s = r(5188) + , l = r(5043) + , p = l.enforce + , f = l.get + , v = String + , h = Object.defineProperty + , d = n("".slice) + , g = n("".replace) + , y = n([].join) + , b = c && !o((function() { + return 8 !== h((function() {} + ), "length", { + value: 8 + }).length + } + )) + , m = String(String).split("String") + , x = t.exports = function(t, e, r) { + "Symbol(" === d(v(e), 0, 7) && (e = "[" + g(v(e), /^Symbol\(([^)]*)\).*$/, "$1") + "]"), + r && r.getter && (e = "get " + e), + r && r.setter && (e = "set " + e), + (!a(t, "name") || u && t.name !== e) && (c ? h(t, "name", { + value: e, + configurable: !0 + }) : t.name = e), + b && r && a(r, "arity") && t.length !== r.arity && h(t, "length", { + value: r.arity + }); + try { + r && a(r, "constructor") && r.constructor ? c && h(t, "prototype", { + writable: !1 + }) : t.prototype && (t.prototype = void 0) + } catch (t) {} + var n = p(t); + return a(n, "source") || (n.source = y(m, "string" == typeof e ? e : "")), + t + } + ; + Function.prototype.toString = x((function() { + return i(this) && f(this).source || s(this) + } + ), "toString") + } + , + 4804: t => { + var e = Math.ceil + , r = Math.floor; + t.exports = Math.trunc || function(t) { + var n = +t; + return (n > 0 ? r : e)(n) + } + } + , + 3181: (t, e, r) => { + var n = r(8914) + , o = TypeError; + t.exports = function(t) { + if (n(t)) + throw new o("The method doesn't accept regular expressions"); + return t + } + } + , + 5567: (t, e, r) => { + var n = r(1870) + , o = r(2538) + , i = r(9295) + , a = r(3849) + , c = r(9866) + , u = r(2059) + , s = r(6203) + , l = r(4683) + , p = r(6729) + , f = Object.assign + , v = Object.defineProperty + , h = o([].concat); + t.exports = !f || a((function() { + if (n && 1 !== f({ + b: 1 + }, f(v({}, "a", { + enumerable: !0, + get: function() { + v(this, "b", { + value: 3, + enumerable: !1 + }) + } + }), { + b: 2 + })).b) + return !0; + var t = {} + , e = {} + , r = Symbol("assign detection") + , o = "abcdefghijklmnopqrst"; + return t[r] = 7, + o.split("").forEach((function(t) { + e[t] = t + } + )), + 7 !== f({}, t)[r] || c(f({}, e)).join("") !== o + } + )) ? function(t, e) { + for (var r = l(t), o = arguments.length, a = 1, f = u.f, v = s.f; o > a; ) + for (var d, g = p(arguments[a++]), y = f ? h(c(g), f(g)) : c(g), b = y.length, m = 0; b > m; ) + d = y[m++], + n && !i(v, g, d) || (r[d] = g[d]); + return r + } + : f + } + , + 8250: (t, e, r) => { + var n, o = r(3349), i = r(4087), a = r(5333), c = r(147), u = r(651), s = r(8249), l = r(6769), p = "prototype", f = "script", v = l("IE_PROTO"), h = function() {}, d = function(t) { + return "<" + f + ">" + t + "" + }, g = function(t) { + t.write(d("")), + t.close(); + var e = t.parentWindow.Object; + return t = null, + e + }, y = function() { + try { + n = new ActiveXObject("htmlfile") + } catch (t) {} + var t, e, r; + y = "undefined" != typeof document ? document.domain && n ? g(n) : (e = s("iframe"), + r = "java" + f + ":", + e.style.display = "none", + u.appendChild(e), + e.src = String(r), + (t = e.contentWindow.document).open(), + t.write(d("document.F=Object")), + t.close(), + t.F) : g(n); + for (var o = a.length; o--; ) + delete y[p][a[o]]; + return y() + }; + c[v] = !0, + t.exports = Object.create || function(t, e) { + var r; + return null !== t ? (h[p] = o(t), + r = new h, + h[p] = null, + r[v] = t) : r = y(), + void 0 === e ? r : i.f(r, e) + } + } + , + 4087: (t, e, r) => { + var n = r(1870) + , o = r(9576) + , i = r(2587) + , a = r(3349) + , c = r(8799) + , u = r(9866); + e.f = n && !o ? Object.defineProperties : function(t, e) { + a(t); + for (var r, n = c(e), o = u(e), s = o.length, l = 0; s > l; ) + i.f(t, r = o[l++], n[r]); + return t + } + } + , + 2587: (t, e, r) => { + var n = r(1870) + , o = r(7527) + , i = r(9576) + , a = r(3349) + , c = r(2423) + , u = TypeError + , s = Object.defineProperty + , l = Object.getOwnPropertyDescriptor + , p = "enumerable" + , f = "configurable" + , v = "writable"; + e.f = n ? i ? function(t, e, r) { + if (a(t), + e = c(e), + a(r), + "function" == typeof t && "prototype" === e && "value"in r && v in r && !r[v]) { + var n = l(t, e); + n && n[v] && (t[e] = r.value, + r = { + configurable: f in r ? r[f] : n[f], + enumerable: p in r ? r[p] : n[p], + writable: !1 + }) + } + return s(t, e, r) + } + : s : function(t, e, r) { + if (a(t), + e = c(e), + a(r), + o) + try { + return s(t, e, r) + } catch (t) {} + if ("get"in r || "set"in r) + throw new u("Accessors not supported"); + return "value"in r && (t[e] = r.value), + t + } + } + , + 9697: (t, e, r) => { + var n = r(1870) + , o = r(9295) + , i = r(6203) + , a = r(5658) + , c = r(8799) + , u = r(2423) + , s = r(379) + , l = r(7527) + , p = Object.getOwnPropertyDescriptor; + e.f = n ? p : function(t, e) { + if (t = c(t), + e = u(e), + l) + try { + return p(t, e) + } catch (t) {} + if (s(t, e)) + return a(!o(i.f, t, e), t[e]) + } + } + , + 2260: (t, e, r) => { + var n = r(2750) + , o = r(8799) + , i = r(1430).f + , a = r(850) + , c = "object" == typeof window && window && Object.getOwnPropertyNames ? Object.getOwnPropertyNames(window) : []; + t.exports.f = function(t) { + return c && "Window" === n(t) ? function(t) { + try { + return i(t) + } catch (t) { + return a(c) + } + }(t) : i(o(t)) + } + } + , + 1430: (t, e, r) => { + var n = r(134) + , o = r(5333).concat("length", "prototype"); + e.f = Object.getOwnPropertyNames || function(t) { + return n(t, o) + } + } + , + 2059: (t, e) => { + e.f = Object.getOwnPropertySymbols + } + , + 4909: (t, e, r) => { + var n = r(379) + , o = r(1435) + , i = r(4683) + , a = r(6769) + , c = r(4737) + , u = a("IE_PROTO") + , s = Object + , l = s.prototype; + t.exports = c ? s.getPrototypeOf : function(t) { + var e = i(t); + if (n(e, u)) + return e[u]; + var r = e.constructor; + return o(r) && e instanceof r ? r.prototype : e instanceof s ? l : null + } + } + , + 8559: (t, e, r) => { + var n = r(2538); + t.exports = n({}.isPrototypeOf) + } + , + 134: (t, e, r) => { + var n = r(2538) + , o = r(379) + , i = r(8799) + , a = r(1675).indexOf + , c = r(147) + , u = n([].push); + t.exports = function(t, e) { + var r, n = i(t), s = 0, l = []; + for (r in n) + !o(c, r) && o(n, r) && u(l, r); + for (; e.length > s; ) + o(n, r = e[s++]) && (~a(l, r) || u(l, r)); + return l + } + } + , + 9866: (t, e, r) => { + var n = r(134) + , o = r(5333); + t.exports = Object.keys || function(t) { + return n(t, o) + } + } + , + 6203: (t, e) => { + var r = {}.propertyIsEnumerable + , n = Object.getOwnPropertyDescriptor + , o = n && !r.call({ + 1: 2 + }, 1); + e.f = o ? function(t) { + var e = n(this, t); + return !!e && e.enumerable + } + : r + } + , + 3425: (t, e, r) => { + var n = r(6632) + , o = r(3400) + , i = r(2112) + , a = r(1420); + t.exports = Object.setPrototypeOf || ("__proto__"in {} ? function() { + var t, e = !1, r = {}; + try { + (t = n(Object.prototype, "__proto__", "set"))(r, []), + e = r instanceof Array + } catch (t) {} + return function(r, n) { + return i(r), + a(n), + o(r) ? (e ? t(r, n) : r.__proto__ = n, + r) : r + } + }() : void 0) + } + , + 6341: (t, e, r) => { + var n = r(6002) + , o = r(5361); + t.exports = n ? {}.toString : function() { + return "[object " + o(this) + "]" + } + } + , + 2988: (t, e, r) => { + var n = r(9295) + , o = r(1435) + , i = r(3400) + , a = TypeError; + t.exports = function(t, e) { + var r, c; + if ("string" === e && o(r = t.toString) && !i(c = n(r, t))) + return c; + if (o(r = t.valueOf) && !i(c = n(r, t))) + return c; + if ("string" !== e && o(r = t.toString) && !i(c = n(r, t))) + return c; + throw new a("Can't convert object to primitive value") + } + } + , + 2905: (t, e, r) => { + var n = r(5793) + , o = r(2538) + , i = r(1430) + , a = r(2059) + , c = r(3349) + , u = o([].concat); + t.exports = n("Reflect", "ownKeys") || function(t) { + var e = i.f(c(t)) + , r = a.f; + return r ? u(e, r(t)) : e + } + } + , + 5869: (t, e, r) => { + var n = r(9317); + t.exports = n + } + , + 5964: (t, e, r) => { + var n = r(9295) + , o = r(3349) + , i = r(1435) + , a = r(2750) + , c = r(1601) + , u = TypeError; + t.exports = function(t, e) { + var r = t.exec; + if (i(r)) { + var s = n(r, t, e); + return null !== s && o(s), + s + } + if ("RegExp" === a(t)) + return n(c, t, e); + throw new u("RegExp#exec called on incompatible receiver") + } + } + , + 1601: (t, e, r) => { + var n, o, i = r(9295), a = r(2538), c = r(2277), u = r(2061), s = r(4667), l = r(7175), p = r(8250), f = r(5043).get, v = r(6845), h = r(5232), d = l("native-string-replace", String.prototype.replace), g = RegExp.prototype.exec, y = g, b = a("".charAt), m = a("".indexOf), x = a("".replace), w = a("".slice), S = (o = /b*/g, + i(g, n = /a/, "a"), + i(g, o, "a"), + 0 !== n.lastIndex || 0 !== o.lastIndex), _ = s.BROKEN_CARET, A = void 0 !== /()??/.exec("")[1]; + (S || A || _ || v || h) && (y = function(t) { + var e, r, n, o, a, s, l, v = this, h = f(v), O = c(t), E = h.raw; + if (E) + return E.lastIndex = v.lastIndex, + e = i(y, E, O), + v.lastIndex = E.lastIndex, + e; + var j = h.groups + , C = _ && v.sticky + , k = i(u, v) + , P = v.source + , I = 0 + , R = O; + if (C && (k = x(k, "y", ""), + -1 === m(k, "g") && (k += "g"), + R = w(O, v.lastIndex), + v.lastIndex > 0 && (!v.multiline || v.multiline && "\n" !== b(O, v.lastIndex - 1)) && (P = "(?: " + P + ")", + R = " " + R, + I++), + r = new RegExp("^(?:" + P + ")",k)), + A && (r = new RegExp("^" + P + "$(?!\\s)",k)), + S && (n = v.lastIndex), + o = i(g, C ? r : v, R), + C ? o ? (o.input = w(o.input, I), + o[0] = w(o[0], I), + o.index = v.lastIndex, + v.lastIndex += o[0].length) : v.lastIndex = 0 : S && o && (v.lastIndex = v.global ? o.index + o[0].length : n), + A && o && o.length > 1 && i(d, o[0], r, (function() { + for (a = 1; a < arguments.length - 2; a++) + void 0 === arguments[a] && (o[a] = void 0) + } + )), + o && j) + for (o.groups = s = p(null), + a = 0; a < j.length; a++) + s[(l = j[a])[0]] = o[l[1]]; + return o + } + ), + t.exports = y + } + , + 2061: (t, e, r) => { + var n = r(3349); + t.exports = function() { + var t = n(this) + , e = ""; + return t.hasIndices && (e += "d"), + t.global && (e += "g"), + t.ignoreCase && (e += "i"), + t.multiline && (e += "m"), + t.dotAll && (e += "s"), + t.unicode && (e += "u"), + t.unicodeSets && (e += "v"), + t.sticky && (e += "y"), + e + } + } + , + 7176: (t, e, r) => { + var n = r(9295) + , o = r(379) + , i = r(8559) + , a = r(2061) + , c = RegExp.prototype; + t.exports = function(t) { + var e = t.flags; + return void 0 !== e || "flags"in c || o(t, "flags") || !i(c, t) ? e : n(a, t) + } + } + , + 4667: (t, e, r) => { + var n = r(3849) + , o = r(9317).RegExp + , i = n((function() { + var t = o("a", "y"); + return t.lastIndex = 2, + null !== t.exec("abcd") + } + )) + , a = i || n((function() { + return !o("a", "y").sticky + } + )) + , c = i || n((function() { + var t = o("^r", "gy"); + return t.lastIndex = 2, + null !== t.exec("str") + } + )); + t.exports = { + BROKEN_CARET: c, + MISSED_STICKY: a, + UNSUPPORTED_Y: i + } + } + , + 6845: (t, e, r) => { + var n = r(3849) + , o = r(9317).RegExp; + t.exports = n((function() { + var t = o(".", "s"); + return !(t.dotAll && t.test("\n") && "s" === t.flags) + } + )) + } + , + 5232: (t, e, r) => { + var n = r(3849) + , o = r(9317).RegExp; + t.exports = n((function() { + var t = o("(?b)", "g"); + return "b" !== t.exec("b").groups.a || "bc" !== "b".replace(t, "$c") + } + )) + } + , + 2112: (t, e, r) => { + var n = r(2303) + , o = TypeError; + t.exports = function(t) { + if (n(t)) + throw new o("Can't call method on " + t); + return t + } + } + , + 7621: (t, e, r) => { + var n = r(2587).f + , o = r(379) + , i = r(3633)("toStringTag"); + t.exports = function(t, e, r) { + t && !r && (t = t.prototype), + t && !o(t, i) && n(t, i, { + configurable: !0, + value: e + }) + } + } + , + 6769: (t, e, r) => { + var n = r(7175) + , o = r(5434) + , i = n("keys"); + t.exports = function(t) { + return i[t] || (i[t] = o(t)) + } + } + , + 1511: (t, e, r) => { + var n = r(4709) + , o = r(9317) + , i = r(3135) + , a = "__core-js_shared__" + , c = t.exports = o[a] || i(a, {}); + (c.versions || (c.versions = [])).push({ + version: "3.37.0", + mode: n ? "pure" : "global", + copyright: "© 2014-2024 Denis Pushkarev (zloirock.ru)", + license: "https://github.com/zloirock/core-js/blob/v3.37.0/LICENSE", + source: "https://github.com/zloirock/core-js" + }) + } + , + 7175: (t, e, r) => { + var n = r(1511); + t.exports = function(t, e) { + return n[t] || (n[t] = e || {}) + } + } + , + 5635: (t, e, r) => { + var n = r(3349) + , o = r(5478) + , i = r(2303) + , a = r(3633)("species"); + t.exports = function(t, e) { + var r, c = n(t).constructor; + return void 0 === c || i(r = n(c)[a]) ? e : o(r) + } + } + , + 449: (t, e, r) => { + var n = r(2538) + , o = r(7277) + , i = r(2277) + , a = r(2112) + , c = n("".charAt) + , u = n("".charCodeAt) + , s = n("".slice) + , l = function(t) { + return function(e, r) { + var n, l, p = i(a(e)), f = o(r), v = p.length; + return f < 0 || f >= v ? t ? "" : void 0 : (n = u(p, f)) < 55296 || n > 56319 || f + 1 === v || (l = u(p, f + 1)) < 56320 || l > 57343 ? t ? c(p, f) : n : t ? s(p, f, f + 2) : l - 56320 + (n - 55296 << 10) + 65536 + } + }; + t.exports = { + codeAt: l(!1), + charAt: l(!0) + } + } + , + 7285: (t, e, r) => { + var n = r(446); + t.exports = /Version\/10(?:\.\d+){1,2}(?: [\w./]+)?(?: Mobile\/\w+)? Safari\//.test(n) + } + , + 8155: (t, e, r) => { + var n = r(2538) + , o = r(8020) + , i = r(2277) + , a = r(1568) + , c = r(2112) + , u = n(a) + , s = n("".slice) + , l = Math.ceil + , p = function(t) { + return function(e, r, n) { + var a, p, f = i(c(e)), v = o(r), h = f.length, d = void 0 === n ? " " : i(n); + return v <= h || "" === d ? f : ((p = u(d, l((a = v - h) / d.length))).length > a && (p = s(p, 0, a)), + t ? f + p : p + f) + } + }; + t.exports = { + start: p(!1), + end: p(!0) + } + } + , + 1568: (t, e, r) => { + var n = r(7277) + , o = r(2277) + , i = r(2112) + , a = RangeError; + t.exports = function(t) { + var e = o(i(this)) + , r = "" + , c = n(t); + if (c < 0 || c === 1 / 0) + throw new a("Wrong number of repetitions"); + for (; c > 0; (c >>>= 1) && (e += e)) + 1 & c && (r += e); + return r + } + } + , + 4500: (t, e, r) => { + var n = r(8784).PROPER + , o = r(3849) + , i = r(9662); + t.exports = function(t) { + return o((function() { + return !!i[t]() || "​…᠎" !== "​…᠎"[t]() || n && i[t].name !== t + } + )) + } + } + , + 1136: (t, e, r) => { + var n = r(2538) + , o = r(2112) + , i = r(2277) + , a = r(9662) + , c = n("".replace) + , u = RegExp("^[" + a + "]+") + , s = RegExp("(^|[^" + a + "])[" + a + "]+$") + , l = function(t) { + return function(e) { + var r = i(o(e)); + return 1 & t && (r = c(r, u, "")), + 2 & t && (r = c(r, s, "$1")), + r + } + }; + t.exports = { + start: l(1), + end: l(2), + trim: l(3) + } + } + , + 2349: (t, e, r) => { + var n = r(7722) + , o = r(3849) + , i = r(9317).String; + t.exports = !!Object.getOwnPropertySymbols && !o((function() { + var t = Symbol("symbol detection"); + return !i(t) || !(Object(t)instanceof Symbol) || !Symbol.sham && n && n < 41 + } + )) + } + , + 3488: (t, e, r) => { + var n = r(9295) + , o = r(5793) + , i = r(3633) + , a = r(2202); + t.exports = function() { + var t = o("Symbol") + , e = t && t.prototype + , r = e && e.valueOf + , c = i("toPrimitive"); + e && !e[c] && a(e, c, (function(t) { + return n(r, this) + } + ), { + arity: 1 + }) + } + } + , + 402: (t, e, r) => { + var n = r(2349); + t.exports = n && !!Symbol.for && !!Symbol.keyFor + } + , + 366: (t, e, r) => { + var n = r(2538); + t.exports = n(1..valueOf) + } + , + 3104: (t, e, r) => { + var n = r(7277) + , o = Math.max + , i = Math.min; + t.exports = function(t, e) { + var r = n(t); + return r < 0 ? o(r + e, 0) : i(r, e) + } + } + , + 8799: (t, e, r) => { + var n = r(6729) + , o = r(2112); + t.exports = function(t) { + return n(o(t)) + } + } + , + 7277: (t, e, r) => { + var n = r(4804); + t.exports = function(t) { + var e = +t; + return e != e || 0 === e ? 0 : n(e) + } + } + , + 8020: (t, e, r) => { + var n = r(7277) + , o = Math.min; + t.exports = function(t) { + var e = n(t); + return e > 0 ? o(e, 9007199254740991) : 0 + } + } + , + 4683: (t, e, r) => { + var n = r(2112) + , o = Object; + t.exports = function(t) { + return o(n(t)) + } + } + , + 4499: (t, e, r) => { + var n = r(9295) + , o = r(3400) + , i = r(4975) + , a = r(2996) + , c = r(2988) + , u = r(3633) + , s = TypeError + , l = u("toPrimitive"); + t.exports = function(t, e) { + if (!o(t) || i(t)) + return t; + var r, u = a(t, l); + if (u) { + if (void 0 === e && (e = "default"), + r = n(u, t, e), + !o(r) || i(r)) + return r; + throw new s("Can't convert object to primitive value") + } + return void 0 === e && (e = "number"), + c(t, e) + } + } + , + 2423: (t, e, r) => { + var n = r(4499) + , o = r(4975); + t.exports = function(t) { + var e = n(t, "string"); + return o(e) ? e : e + "" + } + } + , + 6002: (t, e, r) => { + var n = {}; + n[r(3633)("toStringTag")] = "z", + t.exports = "[object z]" === String(n) + } + , + 2277: (t, e, r) => { + var n = r(5361) + , o = String; + t.exports = function(t) { + if ("Symbol" === n(t)) + throw new TypeError("Cannot convert a Symbol value to a string"); + return o(t) + } + } + , + 7113: t => { + var e = String; + t.exports = function(t) { + try { + return e(t) + } catch (t) { + return "Object" + } + } + } + , + 5434: (t, e, r) => { + var n = r(2538) + , o = 0 + , i = Math.random() + , a = n(1..toString); + t.exports = function(t) { + return "Symbol(" + (void 0 === t ? "" : t) + ")_" + a(++o + i, 36) + } + } + , + 9470: (t, e, r) => { + var n = r(2349); + t.exports = n && !Symbol.sham && "symbol" == typeof Symbol.iterator + } + , + 9576: (t, e, r) => { + var n = r(1870) + , o = r(3849); + t.exports = n && o((function() { + return 42 !== Object.defineProperty((function() {} + ), "prototype", { + value: 42, + writable: !1 + }).prototype + } + )) + } + , + 740: (t, e, r) => { + var n = r(9317) + , o = r(1435) + , i = n.WeakMap; + t.exports = o(i) && /native code/.test(String(i)) + } + , + 3497: (t, e, r) => { + var n = r(5869) + , o = r(379) + , i = r(8093) + , a = r(2587).f; + t.exports = function(t) { + var e = n.Symbol || (n.Symbol = {}); + o(e, t) || a(e, t, { + value: i.f(t) + }) + } + } + , + 8093: (t, e, r) => { + var n = r(3633); + e.f = n + } + , + 3633: (t, e, r) => { + var n = r(9317) + , o = r(7175) + , i = r(379) + , a = r(5434) + , c = r(2349) + , u = r(9470) + , s = n.Symbol + , l = o("wks") + , p = u ? s.for || s : s && s.withoutSetter || a; + t.exports = function(t) { + return i(l, t) || (l[t] = c && i(s, t) ? s[t] : p("Symbol." + t)), + l[t] + } + } + , + 9662: t => { + t.exports = "\t\n\v\f\r                 \u2028\u2029\ufeff" + } + , + 8168: (t, e, r) => { + var n = r(3076) + , o = r(3849) + , i = r(7506) + , a = r(3400) + , c = r(4683) + , u = r(608) + , s = r(2387) + , l = r(6558) + , p = r(3159) + , f = r(9331) + , v = r(3633) + , h = r(7722) + , d = v("isConcatSpreadable") + , g = h >= 51 || !o((function() { + var t = []; + return t[d] = !1, + t.concat()[0] !== t + } + )) + , y = function(t) { + if (!a(t)) + return !1; + var e = t[d]; + return void 0 !== e ? !!e : i(t) + }; + n({ + target: "Array", + proto: !0, + arity: 1, + forced: !g || !f("concat") + }, { + concat: function(t) { + var e, r, n, o, i, a = c(this), f = p(a, 0), v = 0; + for (e = -1, + n = arguments.length; e < n; e++) + if (y(i = -1 === e ? a : arguments[e])) + for (o = u(i), + s(v + o), + r = 0; r < o; r++, + v++) + r in i && l(f, v, i[r]); + else + s(v + 1), + l(f, v++, i); + return f.length = v, + f + } + }) + } + , + 5367: (t, e, r) => { + var n = r(3076) + , o = r(9603).find + , i = r(5127) + , a = "find" + , c = !0; + a in [] && Array(1)[a]((function() { + c = !1 + } + )), + n({ + target: "Array", + proto: !0, + forced: c + }, { + find: function(t) { + return o(this, t, arguments.length > 1 ? arguments[1] : void 0) + } + }), + i(a) + } + , + 9332: (t, e, r) => { + var n = r(3076) + , o = r(7022); + n({ + target: "Array", + stat: !0, + forced: !r(6786)((function(t) { + Array.from(t) + } + )) + }, { + from: o + }) + } + , + 1945: (t, e, r) => { + var n = r(3076) + , o = r(1675).includes + , i = r(3849) + , a = r(5127); + n({ + target: "Array", + proto: !0, + forced: i((function() { + return !Array(1).includes() + } + )) + }, { + includes: function(t) { + return o(this, t, arguments.length > 1 ? arguments[1] : void 0) + } + }), + a("includes") + } + , + 8469: (t, e, r) => { + var n = r(8799) + , o = r(5127) + , i = r(1575) + , a = r(5043) + , c = r(2587).f + , u = r(654) + , s = r(9055) + , l = r(4709) + , p = r(1870) + , f = "Array Iterator" + , v = a.set + , h = a.getterFor(f); + t.exports = u(Array, "Array", (function(t, e) { + v(this, { + type: f, + target: n(t), + index: 0, + kind: e + }) + } + ), (function() { + var t = h(this) + , e = t.target + , r = t.index++; + if (!e || r >= e.length) + return t.target = void 0, + s(void 0, !0); + switch (t.kind) { + case "keys": + return s(r, !1); + case "values": + return s(e[r], !1) + } + return s([r, e[r]], !1) + } + ), "values"); + var d = i.Arguments = i.Array; + if (o("keys"), + o("values"), + o("entries"), + !l && p && "values" !== d.name) + try { + c(d, "name", { + value: "values" + }) + } catch (t) {} + } + , + 7560: (t, e, r) => { + var n = r(3076) + , o = r(2538) + , i = r(6729) + , a = r(8799) + , c = r(4832) + , u = o([].join); + n({ + target: "Array", + proto: !0, + forced: i !== Object || !c("join", ",") + }, { + join: function(t) { + return u(a(this), void 0 === t ? "," : t) + } + }) + } + , + 4008: (t, e, r) => { + var n = r(3076) + , o = r(9603).map; + n({ + target: "Array", + proto: !0, + forced: !r(9331)("map") + }, { + map: function(t) { + return o(this, t, arguments.length > 1 ? arguments[1] : void 0) + } + }) + } + , + 1256: (t, e, r) => { + var n = r(3076) + , o = r(7506) + , i = r(4127) + , a = r(3400) + , c = r(3104) + , u = r(608) + , s = r(8799) + , l = r(6558) + , p = r(3633) + , f = r(9331) + , v = r(850) + , h = f("slice") + , d = p("species") + , g = Array + , y = Math.max; + n({ + target: "Array", + proto: !0, + forced: !h + }, { + slice: function(t, e) { + var r, n, p, f = s(this), h = u(f), b = c(t, h), m = c(void 0 === e ? h : e, h); + if (o(f) && (r = f.constructor, + (i(r) && (r === g || o(r.prototype)) || a(r) && null === (r = r[d])) && (r = void 0), + r === g || void 0 === r)) + return v(f, b, m); + for (n = new (void 0 === r ? g : r)(y(m - b, 0)), + p = 0; b < m; b++, + p++) + b in f && l(n, p, f[b]); + return n.length = p, + n + } + }) + } + , + 5280: (t, e, r) => { + var n = r(3076) + , o = r(4683) + , i = r(3104) + , a = r(7277) + , c = r(608) + , u = r(4534) + , s = r(2387) + , l = r(3159) + , p = r(6558) + , f = r(60) + , v = r(9331)("splice") + , h = Math.max + , d = Math.min; + n({ + target: "Array", + proto: !0, + forced: !v + }, { + splice: function(t, e) { + var r, n, v, g, y, b, m = o(this), x = c(m), w = i(t, x), S = arguments.length; + for (0 === S ? r = n = 0 : 1 === S ? (r = 0, + n = x - w) : (r = S - 2, + n = d(h(a(e), 0), x - w)), + s(x + r - n), + v = l(m, n), + g = 0; g < n; g++) + (y = w + g)in m && p(v, g, m[y]); + if (v.length = n, + r < n) { + for (g = w; g < x - n; g++) + b = g + r, + (y = g + n)in m ? m[b] = m[y] : f(m, b); + for (g = x; g > x - n + r; g--) + f(m, g - 1) + } else if (r > n) + for (g = x - n; g > w; g--) + b = g + r - 1, + (y = g + n - 1)in m ? m[b] = m[y] : f(m, b); + for (g = 0; g < r; g++) + m[g + w] = arguments[g + 2]; + return u(m, x - n + r), + v + } + }) + } + , + 3892: (t, e, r) => { + var n = r(1870) + , o = r(8784).EXISTS + , i = r(2538) + , a = r(7448) + , c = Function.prototype + , u = i(c.toString) + , s = /function\b(?:\s|\/\*[\S\s]*?\*\/|\/\/[^\n\r]*[\n\r]+)*([^\s(/]*)/ + , l = i(s.exec); + n && !o && a(c, "name", { + configurable: !0, + get: function() { + try { + return l(s, u(this))[1] + } catch (t) { + return "" + } + } + }) + } + , + 2264: (t, e, r) => { + var n = r(3076) + , o = r(5793) + , i = r(347) + , a = r(9295) + , c = r(2538) + , u = r(3849) + , s = r(1435) + , l = r(4975) + , p = r(850) + , f = r(9023) + , v = r(2349) + , h = String + , d = o("JSON", "stringify") + , g = c(/./.exec) + , y = c("".charAt) + , b = c("".charCodeAt) + , m = c("".replace) + , x = c(1..toString) + , w = /[\uD800-\uDFFF]/g + , S = /^[\uD800-\uDBFF]$/ + , _ = /^[\uDC00-\uDFFF]$/ + , A = !v || u((function() { + var t = o("Symbol")("stringify detection"); + return "[null]" !== d([t]) || "{}" !== d({ + a: t + }) || "{}" !== d(Object(t)) + } + )) + , O = u((function() { + return '"\\udf06\\ud834"' !== d("\udf06\ud834") || '"\\udead"' !== d("\udead") + } + )) + , E = function(t, e) { + var r = p(arguments) + , n = f(e); + if (s(n) || void 0 !== t && !l(t)) + return r[1] = function(t, e) { + if (s(n) && (e = a(n, this, h(t), e)), + !l(e)) + return e + } + , + i(d, null, r) + } + , j = function(t, e, r) { + var n = y(r, e - 1) + , o = y(r, e + 1); + return g(S, t) && !g(_, o) || g(_, t) && !g(S, n) ? "\\u" + x(b(t, 0), 16) : t + }; + d && n({ + target: "JSON", + stat: !0, + arity: 3, + forced: A || O + }, { + stringify: function(t, e, r) { + var n = p(arguments) + , o = i(A ? E : d, null, n); + return O && "string" == typeof o ? m(o, w, j) : o + } + }) + } + , + 4318: (t, e, r) => { + var n = r(3076) + , o = r(4709) + , i = r(1870) + , a = r(9317) + , c = r(5869) + , u = r(2538) + , s = r(9946) + , l = r(379) + , p = r(8285) + , f = r(8559) + , v = r(4975) + , h = r(4499) + , d = r(3849) + , g = r(1430).f + , y = r(9697).f + , b = r(2587).f + , m = r(366) + , x = r(1136).trim + , w = "Number" + , S = a[w] + , _ = c[w] + , A = S.prototype + , O = a.TypeError + , E = u("".slice) + , j = u("".charCodeAt) + , C = function(t) { + var e, r, n, o, i, a, c, u, s = h(t, "number"); + if (v(s)) + throw new O("Cannot convert a Symbol value to a number"); + if ("string" == typeof s && s.length > 2) + if (s = x(s), + 43 === (e = j(s, 0)) || 45 === e) { + if (88 === (r = j(s, 2)) || 120 === r) + return NaN + } else if (48 === e) { + switch (j(s, 1)) { + case 66: + case 98: + n = 2, + o = 49; + break; + case 79: + case 111: + n = 8, + o = 55; + break; + default: + return +s + } + for (a = (i = E(s, 2)).length, + c = 0; c < a; c++) + if ((u = j(i, c)) < 48 || u > o) + return NaN; + return parseInt(i, n) + } + return +s + } + , k = s(w, !S(" 0o1") || !S("0b1") || S("+0x1")) + , P = function(t) { + var e, r = arguments.length < 1 ? 0 : S(function(t) { + var e = h(t, "number"); + return "bigint" == typeof e ? e : C(e) + }(t)); + return f(A, e = this) && d((function() { + m(e) + } + )) ? p(Object(r), this, P) : r + }; + P.prototype = A, + k && !o && (A.constructor = P), + n({ + global: !0, + constructor: !0, + wrap: !0, + forced: k + }, { + Number: P + }); + var I = function(t, e) { + for (var r, n = i ? g(e) : "MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,isFinite,isInteger,isNaN,isSafeInteger,parseFloat,parseInt,fromString,range".split(","), o = 0; n.length > o; o++) + l(e, r = n[o]) && !l(t, r) && b(t, r, y(e, r)) + }; + o && _ && I(c[w], _), + (k || o) && I(c[w], S) + } + , + 5746: (t, e, r) => { + var n = r(3076) + , o = r(2538) + , i = r(7277) + , a = r(366) + , c = r(1568) + , u = r(3849) + , s = RangeError + , l = String + , p = Math.floor + , f = o(c) + , v = o("".slice) + , h = o(1..toFixed) + , d = function(t, e, r) { + return 0 === e ? r : e % 2 == 1 ? d(t, e - 1, r * t) : d(t * t, e / 2, r) + } + , g = function(t, e, r) { + for (var n = -1, o = r; ++n < 6; ) + o += e * t[n], + t[n] = o % 1e7, + o = p(o / 1e7) + } + , y = function(t, e) { + for (var r = 6, n = 0; --r >= 0; ) + n += t[r], + t[r] = p(n / e), + n = n % e * 1e7 + } + , b = function(t) { + for (var e = 6, r = ""; --e >= 0; ) + if ("" !== r || 0 === e || 0 !== t[e]) { + var n = l(t[e]); + r = "" === r ? n : r + f("0", 7 - n.length) + n + } + return r + }; + n({ + target: "Number", + proto: !0, + forced: u((function() { + return "0.000" !== h(8e-5, 3) || "1" !== h(.9, 0) || "1.25" !== h(1.255, 2) || "1000000000000000128" !== h(0xde0b6b3a7640080, 0) + } + )) || !u((function() { + h({}) + } + )) + }, { + toFixed: function(t) { + var e, r, n, o, c = a(this), u = i(t), p = [0, 0, 0, 0, 0, 0], h = "", m = "0"; + if (u < 0 || u > 20) + throw new s("Incorrect fraction digits"); + if (c != c) + return "NaN"; + if (c <= -1e21 || c >= 1e21) + return l(c); + if (c < 0 && (h = "-", + c = -c), + c > 1e-21) + if (r = (e = function(t) { + for (var e = 0, r = t; r >= 4096; ) + e += 12, + r /= 4096; + for (; r >= 2; ) + e += 1, + r /= 2; + return e + }(c * d(2, 69, 1)) - 69) < 0 ? c * d(2, -e, 1) : c / d(2, e, 1), + r *= 4503599627370496, + (e = 52 - e) > 0) { + for (g(p, 0, r), + n = u; n >= 7; ) + g(p, 1e7, 0), + n -= 7; + for (g(p, d(10, n, 1), 0), + n = e - 1; n >= 23; ) + y(p, 1 << 23), + n -= 23; + y(p, 1 << n), + g(p, 1, 1), + y(p, 2), + m = b(p) + } else + g(p, 0, r), + g(p, 1 << -e, 0), + m = b(p) + f("0", u); + return m = u > 0 ? h + ((o = m.length) <= u ? "0." + f("0", u - o) + m : v(m, 0, o - u) + "." + v(m, o - u)) : h + m + } + }) + } + , + 7591: (t, e, r) => { + var n = r(3076) + , o = r(5567); + n({ + target: "Object", + stat: !0, + arity: 2, + forced: Object.assign !== o + }, { + assign: o + }) + } + , + 5315: (t, e, r) => { + var n = r(3076) + , o = r(2349) + , i = r(3849) + , a = r(2059) + , c = r(4683); + n({ + target: "Object", + stat: !0, + forced: !o || i((function() { + a.f(1) + } + )) + }, { + getOwnPropertySymbols: function(t) { + var e = a.f; + return e ? e(c(t)) : [] + } + }) + } + , + 7458: (t, e, r) => { + var n = r(3076) + , o = r(4683) + , i = r(9866); + n({ + target: "Object", + stat: !0, + forced: r(3849)((function() { + i(1) + } + )) + }, { + keys: function(t) { + return i(o(t)) + } + }) + } + , + 9645: (t, e, r) => { + var n = r(6002) + , o = r(2202) + , i = r(6341); + n || o(Object.prototype, "toString", i, { + unsafe: !0 + }) + } + , + 9981: (t, e, r) => { + var n = r(3076) + , o = r(1601); + n({ + target: "RegExp", + proto: !0, + forced: /./.exec !== o + }, { + exec: o + }) + } + , + 5991: (t, e, r) => { + var n = r(8784).PROPER + , o = r(2202) + , i = r(3349) + , a = r(2277) + , c = r(3849) + , u = r(7176) + , s = "toString" + , l = RegExp.prototype + , p = l[s] + , f = c((function() { + return "/a/b" !== p.call({ + source: "a", + flags: "b" + }) + } + )) + , v = n && p.name !== s; + (f || v) && o(l, s, (function() { + var t = i(this); + return "/" + a(t.source) + "/" + a(u(t)) + } + ), { + unsafe: !0 + }) + } + , + 6490: (t, e, r) => { + var n = r(449).charAt + , o = r(2277) + , i = r(5043) + , a = r(654) + , c = r(9055) + , u = "String Iterator" + , s = i.set + , l = i.getterFor(u); + a(String, "String", (function(t) { + s(this, { + type: u, + string: o(t), + index: 0 + }) + } + ), (function() { + var t, e = l(this), r = e.string, o = e.index; + return o >= r.length ? c(void 0, !0) : (t = n(r, o), + e.index += t.length, + c(t, !1)) + } + )) + } + , + 6475: (t, e, r) => { + var n = r(9295) + , o = r(2670) + , i = r(3349) + , a = r(2303) + , c = r(8020) + , u = r(2277) + , s = r(2112) + , l = r(2996) + , p = r(6691) + , f = r(5964); + o("match", (function(t, e, r) { + return [function(e) { + var r = s(this) + , o = a(e) ? void 0 : l(e, t); + return o ? n(o, e, r) : new RegExp(e)[t](u(r)) + } + , function(t) { + var n = i(this) + , o = u(t) + , a = r(e, n, o); + if (a.done) + return a.value; + if (!n.global) + return f(n, o); + var s = n.unicode; + n.lastIndex = 0; + for (var l, v = [], h = 0; null !== (l = f(n, o)); ) { + var d = u(l[0]); + v[h] = d, + "" === d && (n.lastIndex = p(o, c(n.lastIndex), s)), + h++ + } + return 0 === h ? null : v + } + ] + } + )) + } + , + 9666: (t, e, r) => { + var n = r(3076) + , o = r(8155).start; + n({ + target: "String", + proto: !0, + forced: r(7285) + }, { + padStart: function(t) { + return o(this, t, arguments.length > 1 ? arguments[1] : void 0) + } + }) + } + , + 8171: (t, e, r) => { + r(3076)({ + target: "String", + proto: !0 + }, { + repeat: r(1568) + }) + } + , + 6230: (t, e, r) => { + var n = r(347) + , o = r(9295) + , i = r(2538) + , a = r(2670) + , c = r(3849) + , u = r(3349) + , s = r(1435) + , l = r(2303) + , p = r(7277) + , f = r(8020) + , v = r(2277) + , h = r(2112) + , d = r(6691) + , g = r(2996) + , y = r(1748) + , b = r(5964) + , m = r(3633)("replace") + , x = Math.max + , w = Math.min + , S = i([].concat) + , _ = i([].push) + , A = i("".indexOf) + , O = i("".slice) + , E = "$0" === "a".replace(/./, "$0") + , j = !!/./[m] && "" === /./[m]("a", "$0"); + a("replace", (function(t, e, r) { + var i = j ? "$" : "$0"; + return [function(t, r) { + var n = h(this) + , i = l(t) ? void 0 : g(t, m); + return i ? o(i, t, n, r) : o(e, v(n), t, r) + } + , function(t, o) { + var a = u(this) + , c = v(t); + if ("string" == typeof o && -1 === A(o, i) && -1 === A(o, "$<")) { + var l = r(e, a, c, o); + if (l.done) + return l.value + } + var h = s(o); + h || (o = v(o)); + var g, m = a.global; + m && (g = a.unicode, + a.lastIndex = 0); + for (var E, j = []; null !== (E = b(a, c)) && (_(j, E), + m); ) { + "" === v(E[0]) && (a.lastIndex = d(c, f(a.lastIndex), g)) + } + for (var C, k = "", P = 0, I = 0; I < j.length; I++) { + for (var R, T = v((E = j[I])[0]), L = x(w(p(E.index), c.length), 0), F = [], N = 1; N < E.length; N++) + _(F, void 0 === (C = E[N]) ? C : String(C)); + var M = E.groups; + if (h) { + var D = S([T], F, L, c); + void 0 !== M && _(D, M), + R = v(n(o, void 0, D)) + } else + R = y(T, c, L, F, M, o); + L >= P && (k += O(c, P, L) + R, + P = L + T.length) + } + return k + O(c, P) + } + ] + } + ), !!c((function() { + var t = /./; + return t.exec = function() { + var t = []; + return t.groups = { + a: "7" + }, + t + } + , + "7" !== "".replace(t, "$") + } + )) || !E || j) + } + , + 8402: (t, e, r) => { + var n = r(9295) + , o = r(2538) + , i = r(2670) + , a = r(3349) + , c = r(2303) + , u = r(2112) + , s = r(5635) + , l = r(6691) + , p = r(8020) + , f = r(2277) + , v = r(2996) + , h = r(5964) + , d = r(4667) + , g = r(3849) + , y = d.UNSUPPORTED_Y + , b = Math.min + , m = o([].push) + , x = o("".slice) + , w = !g((function() { + var t = /(?:)/ + , e = t.exec; + t.exec = function() { + return e.apply(this, arguments) + } + ; + var r = "ab".split(t); + return 2 !== r.length || "a" !== r[0] || "b" !== r[1] + } + )) + , S = "c" === "abbc".split(/(b)*/)[1] || 4 !== "test".split(/(?:)/, -1).length || 2 !== "ab".split(/(?:ab)*/).length || 4 !== ".".split(/(.?)(.?)/).length || ".".split(/()()/).length > 1 || "".split(/.?/).length; + i("split", (function(t, e, r) { + var o = "0".split(void 0, 0).length ? function(t, r) { + return void 0 === t && 0 === r ? [] : n(e, this, t, r) + } + : e; + return [function(e, r) { + var i = u(this) + , a = c(e) ? void 0 : v(e, t); + return a ? n(a, e, i, r) : n(o, f(i), e, r) + } + , function(t, n) { + var i = a(this) + , c = f(t); + if (!S) { + var u = r(o, i, c, n, o !== e); + if (u.done) + return u.value + } + var v = s(i, RegExp) + , d = i.unicode + , g = (i.ignoreCase ? "i" : "") + (i.multiline ? "m" : "") + (i.unicode ? "u" : "") + (y ? "g" : "y") + , w = new v(y ? "^(?:" + i.source + ")" : i,g) + , _ = void 0 === n ? 4294967295 : n >>> 0; + if (0 === _) + return []; + if (0 === c.length) + return null === h(w, c) ? [c] : []; + for (var A = 0, O = 0, E = []; O < c.length; ) { + w.lastIndex = y ? 0 : O; + var j, C = h(w, y ? x(c, O) : c); + if (null === C || (j = b(p(w.lastIndex + (y ? O : 0)), c.length)) === A) + O = l(c, O, d); + else { + if (m(E, x(c, A, O)), + E.length === _) + return E; + for (var k = 1; k <= C.length - 1; k++) + if (m(E, C[k]), + E.length === _) + return E; + O = A = j + } + } + return m(E, x(c, A)), + E + } + ] + } + ), S || !w, y) + } + , + 4430: (t, e, r) => { + var n, o = r(3076), i = r(4890), a = r(9697).f, c = r(8020), u = r(2277), s = r(3181), l = r(2112), p = r(5850), f = r(4709), v = i("".slice), h = Math.min, d = p("startsWith"); + o({ + target: "String", + proto: !0, + forced: !!(f || d || (n = a(String.prototype, "startsWith"), + !n || n.writable)) && !d + }, { + startsWith: function(t) { + var e = u(l(this)); + s(t); + var r = c(h(arguments.length > 1 ? arguments[1] : void 0, e.length)) + , n = u(t); + return v(e, r, r + n.length) === n + } + }) + } + , + 3624: (t, e, r) => { + var n = r(3076) + , o = r(1136).trim; + n({ + target: "String", + proto: !0, + forced: r(4500)("trim") + }, { + trim: function() { + return o(this) + } + }) + } + , + 2528: (t, e, r) => { + var n = r(3076) + , o = r(9317) + , i = r(9295) + , a = r(2538) + , c = r(4709) + , u = r(1870) + , s = r(2349) + , l = r(3849) + , p = r(379) + , f = r(8559) + , v = r(3349) + , h = r(8799) + , d = r(2423) + , g = r(2277) + , y = r(5658) + , b = r(8250) + , m = r(9866) + , x = r(1430) + , w = r(2260) + , S = r(2059) + , _ = r(9697) + , A = r(2587) + , O = r(4087) + , E = r(6203) + , j = r(2202) + , C = r(7448) + , k = r(7175) + , P = r(6769) + , I = r(147) + , R = r(5434) + , T = r(3633) + , L = r(8093) + , F = r(3497) + , N = r(3488) + , M = r(7621) + , D = r(5043) + , B = r(9603).forEach + , $ = P("hidden") + , H = "Symbol" + , G = "prototype" + , U = D.set + , V = D.getterFor(H) + , W = Object[G] + , z = o.Symbol + , Y = z && z[G] + , X = o.RangeError + , K = o.TypeError + , q = o.QObject + , J = _.f + , Q = A.f + , Z = w.f + , tt = E.f + , et = a([].push) + , rt = k("symbols") + , nt = k("op-symbols") + , ot = k("wks") + , it = !q || !q[G] || !q[G].findChild + , at = function(t, e, r) { + var n = J(W, e); + n && delete W[e], + Q(t, e, r), + n && t !== W && Q(W, e, n) + } + , ct = u && l((function() { + return 7 !== b(Q({}, "a", { + get: function() { + return Q(this, "a", { + value: 7 + }).a + } + })).a + } + )) ? at : Q + , ut = function(t, e) { + var r = rt[t] = b(Y); + return U(r, { + type: H, + tag: t, + description: e + }), + u || (r.description = e), + r + } + , st = function(t, e, r) { + t === W && st(nt, e, r), + v(t); + var n = d(e); + return v(r), + p(rt, n) ? (r.enumerable ? (p(t, $) && t[$][n] && (t[$][n] = !1), + r = b(r, { + enumerable: y(0, !1) + })) : (p(t, $) || Q(t, $, y(1, b(null))), + t[$][n] = !0), + ct(t, n, r)) : Q(t, n, r) + } + , lt = function(t, e) { + v(t); + var r = h(e) + , n = m(r).concat(ht(r)); + return B(n, (function(e) { + u && !i(pt, r, e) || st(t, e, r[e]) + } + )), + t + } + , pt = function(t) { + var e = d(t) + , r = i(tt, this, e); + return !(this === W && p(rt, e) && !p(nt, e)) && (!(r || !p(this, e) || !p(rt, e) || p(this, $) && this[$][e]) || r) + } + , ft = function(t, e) { + var r = h(t) + , n = d(e); + if (r !== W || !p(rt, n) || p(nt, n)) { + var o = J(r, n); + return !o || !p(rt, n) || p(r, $) && r[$][n] || (o.enumerable = !0), + o + } + } + , vt = function(t) { + var e = Z(h(t)) + , r = []; + return B(e, (function(t) { + p(rt, t) || p(I, t) || et(r, t) + } + )), + r + } + , ht = function(t) { + var e = t === W + , r = Z(e ? nt : h(t)) + , n = []; + return B(r, (function(t) { + !p(rt, t) || e && !p(W, t) || et(n, rt[t]) + } + )), + n + }; + s || (j(Y = (z = function() { + if (f(Y, this)) + throw new K("Symbol is not a constructor"); + var t = arguments.length && void 0 !== arguments[0] ? g(arguments[0]) : void 0 + , e = R(t) + , r = function(t) { + var n = void 0 === this ? o : this; + n === W && i(r, nt, t), + p(n, $) && p(n[$], e) && (n[$][e] = !1); + var a = y(1, t); + try { + ct(n, e, a) + } catch (t) { + if (!(t instanceof X)) + throw t; + at(n, e, a) + } + }; + return u && it && ct(W, e, { + configurable: !0, + set: r + }), + ut(e, t) + } + )[G], "toString", (function() { + return V(this).tag + } + )), + j(z, "withoutSetter", (function(t) { + return ut(R(t), t) + } + )), + E.f = pt, + A.f = st, + O.f = lt, + _.f = ft, + x.f = w.f = vt, + S.f = ht, + L.f = function(t) { + return ut(T(t), t) + } + , + u && (C(Y, "description", { + configurable: !0, + get: function() { + return V(this).description + } + }), + c || j(W, "propertyIsEnumerable", pt, { + unsafe: !0 + }))), + n({ + global: !0, + constructor: !0, + wrap: !0, + forced: !s, + sham: !s + }, { + Symbol: z + }), + B(m(ot), (function(t) { + F(t) + } + )), + n({ + target: H, + stat: !0, + forced: !s + }, { + useSetter: function() { + it = !0 + }, + useSimple: function() { + it = !1 + } + }), + n({ + target: "Object", + stat: !0, + forced: !s, + sham: !u + }, { + create: function(t, e) { + return void 0 === e ? b(t) : lt(b(t), e) + }, + defineProperty: st, + defineProperties: lt, + getOwnPropertyDescriptor: ft + }), + n({ + target: "Object", + stat: !0, + forced: !s + }, { + getOwnPropertyNames: vt + }), + N(), + M(z, H), + I[$] = !0 + } + , + 1725: (t, e, r) => { + var n = r(3076) + , o = r(1870) + , i = r(9317) + , a = r(2538) + , c = r(379) + , u = r(1435) + , s = r(8559) + , l = r(2277) + , p = r(7448) + , f = r(4518) + , v = i.Symbol + , h = v && v.prototype; + if (o && u(v) && (!("description"in h) || void 0 !== v().description)) { + var d = {} + , g = function() { + var t = arguments.length < 1 || void 0 === arguments[0] ? void 0 : l(arguments[0]) + , e = s(h, this) ? new v(t) : void 0 === t ? v() : v(t); + return "" === t && (d[e] = !0), + e + }; + f(g, v), + g.prototype = h, + h.constructor = g; + var y = "Symbol(description detection)" === String(v("description detection")) + , b = a(h.valueOf) + , m = a(h.toString) + , x = /^Symbol\((.*)\)[^)]+$/ + , w = a("".replace) + , S = a("".slice); + p(h, "description", { + configurable: !0, + get: function() { + var t = b(this); + if (c(d, t)) + return ""; + var e = m(t) + , r = y ? S(e, 7, -1) : w(e, x, "$1"); + return "" === r ? void 0 : r + } + }), + n({ + global: !0, + constructor: !0, + forced: !0 + }, { + Symbol: g + }) + } + } + , + 3028: (t, e, r) => { + var n = r(3076) + , o = r(5793) + , i = r(379) + , a = r(2277) + , c = r(7175) + , u = r(402) + , s = c("string-to-symbol-registry") + , l = c("symbol-to-string-registry"); + n({ + target: "Symbol", + stat: !0, + forced: !u + }, { + for: function(t) { + var e = a(t); + if (i(s, e)) + return s[e]; + var r = o("Symbol")(e); + return s[e] = r, + l[r] = e, + r + } + }) + } + , + 8381: (t, e, r) => { + r(3497)("iterator") + } + , + 905: (t, e, r) => { + r(2528), + r(3028), + r(38), + r(2264), + r(5315) + } + , + 38: (t, e, r) => { + var n = r(3076) + , o = r(379) + , i = r(4975) + , a = r(7113) + , c = r(7175) + , u = r(402) + , s = c("symbol-to-string-registry"); + n({ + target: "Symbol", + stat: !0, + forced: !u + }, { + keyFor: function(t) { + if (!i(t)) + throw new TypeError(a(t) + " is not a symbol"); + if (o(s, t)) + return s[t] + } + }) + } + , + 8190: (t, e, r) => { + var n = r(9317) + , o = r(1530) + , i = r(6334) + , a = r(3833) + , c = r(4477) + , u = function(t) { + if (t && t.forEach !== a) + try { + c(t, "forEach", a) + } catch (e) { + t.forEach = a + } + }; + for (var s in o) + o[s] && u(n[s] && n[s].prototype); + u(i) + } + , + 4207: (t, e, r) => { + var n = r(9317) + , o = r(1530) + , i = r(6334) + , a = r(8469) + , c = r(4477) + , u = r(7621) + , s = r(3633)("iterator") + , l = a.values + , p = function(t, e) { + if (t) { + if (t[s] !== l) + try { + c(t, s, l) + } catch (e) { + t[s] = l + } + if (u(t, e, !0), + o[e]) + for (var r in a) + if (t[r] !== a[r]) + try { + c(t, r, a[r]) + } catch (e) { + t[r] = a[r] + } + } + }; + for (var f in o) + p(n[f] && n[f].prototype, f); + p(i, "DOMTokenList") + } + } + , e = {}; + function r(n) { + var o = e[n]; + if (void 0 !== o) + return o.exports; + var i = e[n] = { + exports: {} + }; + return t[n].call(i.exports, i, i.exports, r), + i.exports + } + r.d = (t, e) => { + for (var n in e) + r.o(e, n) && !r.o(t, n) && Object.defineProperty(t, n, { + enumerable: !0, + get: e[n] + }) + } + , + r.g = function() { + if ("object" == typeof globalThis) + return globalThis; + try { + return this || new Function("return this")() + } catch (t) { + if ("object" == typeof window) + return window + } + }(), + r.o = (t, e) => Object.prototype.hasOwnProperty.call(t, e), + r.r = t => { + "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(t, Symbol.toStringTag, { + value: "Module" + }), + Object.defineProperty(t, "__esModule", { + value: !0 + }) + } + ; + var n = {}; + return ( () => { + r.d(n, { + default: () => R + }); + var t = {}; + r.r(t), + r.d(t, { + adjustableInputNumbers: () => f, + createElementFromString: () => u, + createFromTemplate: () => s, + eventPath: () => l, + off: () => c, + on: () => a, + resolveElement: () => p + }); + r(8168), + r(5367), + r(905), + r(1725), + r(8381), + r(9332), + r(1945), + r(8469), + r(5280), + r(4318), + r(1256), + r(3892), + r(7591), + r(7458), + r(9645), + r(9981), + r(5991), + r(6490), + r(6475), + r(8171), + r(4430), + r(8190), + r(4207), + r(6230), + r(8402), + r(3624); + function e(t, e) { + var r = "undefined" != typeof Symbol && t[Symbol.iterator] || t["@@iterator"]; + if (r) + return (r = r.call(t)).next.bind(r); + if (Array.isArray(t) || (r = function(t, e) { + if (!t) + return; + if ("string" == typeof t) + return o(t, e); + var r = Object.prototype.toString.call(t).slice(8, -1); + "Object" === r && t.constructor && (r = t.constructor.name); + if ("Map" === r || "Set" === r) + return Array.from(t); + if ("Arguments" === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)) + return o(t, e) + }(t)) || e && t && "number" == typeof t.length) { + r && (t = r); + var n = 0; + return function() { + return n >= t.length ? { + done: !0 + } : { + done: !1, + value: t[n++] + } + } + } + throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.") + } + function o(t, e) { + (null == e || e > t.length) && (e = t.length); + for (var r = 0, n = new Array(e); r < e; r++) + n[r] = t[r]; + return n + } + function i(t, r, n, o, i) { + void 0 === i && (i = {}), + r instanceof HTMLCollection || r instanceof NodeList ? r = Array.from(r) : Array.isArray(r) || (r = [r]), + Array.isArray(n) || (n = [n]); + for (var a, c = e(r); !(a = c()).done; ) + for (var u, s = a.value, l = e(n); !(u = l()).done; ) { + var p = u.value; + s[t](p, o, Object.assign({ + capture: !1 + }, i)) + } + return Array.prototype.slice.call(arguments, 1) + } + var a = i.bind(null, "addEventListener") + , c = i.bind(null, "removeEventListener"); + function u(t) { + var e = document.createElement("div"); + return e.innerHTML = t.trim(), + e.firstElementChild + } + function s(t) { + var e = function(t, e) { + var r = t.getAttribute(e); + return t.removeAttribute(e), + r + }; + return function t(r, n) { + void 0 === n && (n = {}); + var o = e(r, ":obj") + , i = e(r, ":ref") + , a = o ? n[o] = {} : n; + i && (n[i] = r); + for (var c = 0, u = Array.from(r.children); c < u.length; c++) { + var s = u[c] + , l = e(s, ":arr") + , p = t(s, l ? {} : a); + l && (a[l] || (a[l] = [])).push(Object.keys(p).length ? p : s) + } + return n + }(u(t)) + } + function l(t) { + var e = t.path || t.composedPath && t.composedPath(); + if (e) + return e; + var r = t.target.parentElement; + for (e = [t.target, r]; r = r.parentElement; ) + e.push(r); + return e.push(document, window), + e + } + function p(t) { + return t instanceof Element ? t : "string" == typeof t ? t.split(/>>/g).reduce((function(t, e, r, n) { + return t = t.querySelector(e), + r < n.length - 1 ? t.shadowRoot : t + } + ), document) : null + } + function f(t, e) { + function r(r) { + var n = [.001, .01, .1][Number(r.shiftKey || 2 * r.ctrlKey)] * (r.deltaY < 0 ? 1 : -1) + , o = 0 + , i = t.selectionStart; + t.value = t.value.replace(/[\d.]+/g, (function(t, r) { + return r <= i && r + t.length >= i ? (i = r, + e(Number(t), n, o)) : (o++, + t) + } + )), + t.focus(), + t.setSelectionRange(i, i), + r.preventDefault(), + t.dispatchEvent(new Event("input")) + } + void 0 === e && (e = function(t) { + return t + } + ), + a(t, "focus", (function() { + return a(window, "wheel", r, { + passive: !1 + }) + } + )), + a(t, "blur", (function() { + return c(window, "wheel", r) + } + )) + } + r(7560), + r(4008), + r(9666); + var v = Math.min + , h = Math.max + , d = Math.floor + , g = Math.round; + function y(t, e, r) { + e /= 100, + r /= 100; + var n = d(t = t / 360 * 6) + , o = t - n + , i = r * (1 - e) + , a = r * (1 - o * e) + , c = r * (1 - (1 - o) * e) + , u = n % 6; + return [255 * [r, a, i, i, c, r][u], 255 * [c, r, r, a, i, i][u], 255 * [i, i, c, r, r, a][u]] + } + function b(t, e, r) { + var n, o, i = v(t /= 255, e /= 255, r /= 255), a = h(t, e, r), c = a - i; + if (0 === c) + n = o = 0; + else { + o = c / a; + var u = ((a - t) / 6 + c / 2) / c + , s = ((a - e) / 6 + c / 2) / c + , l = ((a - r) / 6 + c / 2) / c; + t === a ? n = l - s : e === a ? n = 1 / 3 + u - l : r === a && (n = 2 / 3 + s - u), + n < 0 ? n += 1 : n > 1 && (n -= 1) + } + return [360 * n, 100 * o, 100 * a] + } + function m(t, e, r, n) { + e /= 100, + r /= 100; + var o = 255 * (1 - v(1, (t /= 100) * (1 - (n /= 100)) + n)) + , i = 255 * (1 - v(1, e * (1 - n) + n)) + , a = 255 * (1 - v(1, r * (1 - n) + n)); + return [].concat(b(o, i, a)) + } + function x(t, e, r) { + e /= 100; + var n = 2 * (e *= (r /= 100) < .5 ? r : 1 - r) / (r + e) * 100 + , o = 100 * (r + e); + return [t, isNaN(n) ? 0 : n, o] + } + function w(t) { + return b.apply(void 0, t.match(/.{2}/g).map((function(t) { + return parseInt(t, 16) + } + ))) + } + function S(t) { + t = t.match(/^[a-zA-Z]+$/) ? function(t) { + if ("black" === t.toLowerCase()) + return "#000"; + var e = document.createElement("canvas").getContext("2d"); + return e.fillStyle = t, + "#000" === e.fillStyle ? null : e.fillStyle + }(t) : t; + var e, r = { + cmyk: /^cmyk\D+([\d.]+)\D+([\d.]+)\D+([\d.]+)\D+([\d.]+)/i, + rgba: /^rgba?\D+([\d.]+)(%?)\D+([\d.]+)(%?)\D+([\d.]+)(%?)\D*?(([\d.]+)(%?)|$)/i, + hsla: /^hsla?\D+([\d.]+)\D+([\d.]+)\D+([\d.]+)\D*?(([\d.]+)(%?)|$)/i, + hsva: /^hsva?\D+([\d.]+)\D+([\d.]+)\D+([\d.]+)\D*?(([\d.]+)(%?)|$)/i, + hexa: /^#?(([\dA-Fa-f]{3,4})|([\dA-Fa-f]{6})|([\dA-Fa-f]{8}))$/i + }, n = function(t) { + return t.map((function(t) { + return /^(|\d+)\.\d+|\d+$/.test(t) ? Number(t) : void 0 + } + )) + }; + t: for (var o in r) + if (e = r[o].exec(t)) + switch (o) { + case "cmyk": + var i = n(e) + , a = i[1] + , c = i[2] + , u = i[3] + , s = i[4]; + if (a > 100 || c > 100 || u > 100 || s > 100) + break t; + return { + values: m(a, c, u, s), + type: o + }; + case "rgba": + var l = n(e) + , p = l[1] + , f = l[3] + , v = l[5] + , h = l[8]; + if (p = "%" === e[2] ? p / 100 * 255 : p, + f = "%" === e[4] ? f / 100 * 255 : f, + v = "%" === e[6] ? v / 100 * 255 : v, + h = "%" === e[9] ? h / 100 : h, + p > 255 || f > 255 || v > 255 || h < 0 || h > 1) + break t; + return { + values: [].concat(b(p, f, v), [h]), + a: h, + type: o + }; + case "hexa": + var d = e[1]; + 4 !== d.length && 3 !== d.length || (d = d.split("").map((function(t) { + return t + t + } + )).join("")); + var g = d.substring(0, 6) + , y = d.substring(6); + return y = y ? parseInt(y, 16) / 255 : void 0, + { + values: [].concat(w(g), [y]), + a: y, + type: o + }; + case "hsla": + var S = n(e) + , _ = S[1] + , A = S[2] + , O = S[3] + , E = S[5]; + if (E = "%" === e[6] ? E / 100 : E, + _ > 360 || A > 100 || O > 100 || E < 0 || E > 1) + break t; + return { + values: [].concat(x(_, A, O), [E]), + a: E, + type: o + }; + case "hsva": + var j = n(e) + , C = j[1] + , k = j[2] + , P = j[3] + , I = j[5]; + if (I = "%" === e[6] ? I / 100 : I, + C > 360 || k > 100 || P > 100 || I < 0 || I > 1) + break t; + return { + values: [C, k, P, I], + a: I, + type: o + } + } + return { + values: null, + type: null + } + } + r(5746); + function _(t, e, r, n) { + void 0 === t && (t = 0), + void 0 === e && (e = 0), + void 0 === r && (r = 0), + void 0 === n && (n = 1); + var o = function(t, e) { + return function(r) { + return void 0 === r && (r = -1), + e(~r ? t.map((function(t) { + return Number(t.toFixed(r)) + } + )) : t) + } + } + , i = { + h: t, + s: e, + v: r, + a: n, + toHSVA: function() { + var t = [i.h, i.s, i.v, i.a]; + return t.toString = o(t, (function(t) { + return "hsva(" + t[0] + ", " + t[1] + "%, " + t[2] + "%, " + i.a + ")" + } + )), + t + }, + toHSLA: function() { + var t = [].concat(function(t, e, r) { + var n = (2 - (e /= 100)) * (r /= 100) / 2; + return 0 !== n && (e = 1 === n ? 0 : n < .5 ? e * r / (2 * n) : e * r / (2 - 2 * n)), + [t, 100 * e, 100 * n] + }(i.h, i.s, i.v), [i.a]); + return t.toString = o(t, (function(t) { + return "hsla(" + t[0] + ", " + t[1] + "%, " + t[2] + "%, " + i.a + ")" + } + )), + t + }, + toRGBA: function() { + var t = [].concat(y(i.h, i.s, i.v), [i.a]); + return t.toString = o(t, (function(t) { + return "rgba(" + t[0] + ", " + t[1] + ", " + t[2] + ", " + i.a + ")" + } + )), + t + }, + toCMYK: function() { + var t = function(t, e, r) { + var n = y(t, e, r) + , o = n[0] / 255 + , i = n[1] / 255 + , a = n[2] / 255 + , c = v(1 - o, 1 - i, 1 - a); + return [100 * (1 === c ? 0 : (1 - o - c) / (1 - c)), 100 * (1 === c ? 0 : (1 - i - c) / (1 - c)), 100 * (1 === c ? 0 : (1 - a - c) / (1 - c)), 100 * c] + }(i.h, i.s, i.v); + return t.toString = o(t, (function(t) { + return "cmyk(" + t[0] + "%, " + t[1] + "%, " + t[2] + "%, " + t[3] + "%)" + } + )), + t + }, + toHEXA: function() { + var t = function(t, e, r) { + return y(t, e, r).map((function(t) { + return g(t).toString(16).padStart(2, "0") + } + )) + }(i.h, i.s, i.v) + , e = i.a >= 1 ? "" : Number((255 * i.a).toFixed(0)).toString(16).toUpperCase().padStart(2, "0"); + return e && t.push(e), + t.toString = function() { + return "#" + t.join("").toUpperCase() + } + , + t + }, + clone: function() { + return _(i.h, i.s, i.v, i.a) + } + }; + return i + } + var A = function(t) { + return Math.max(Math.min(t, 1), 0) + }; + function O(t) { + var e = { + options: Object.assign({ + lock: null, + onchange: function() { + return 0 + }, + onstop: function() { + return 0 + } + }, t), + _keyboard: function(t) { + var r = e.options + , n = t.type + , o = t.key; + if (document.activeElement === r.wrapper) { + var i = e.options.lock + , a = "ArrowUp" === o + , c = "ArrowRight" === o + , u = "ArrowDown" === o + , s = "ArrowLeft" === o; + if ("keydown" === n && (a || c || u || s)) { + var l = 0 + , p = 0; + "v" === i ? l = a || c ? 1 : -1 : "h" === i ? l = a || c ? -1 : 1 : (p = a ? -1 : u ? 1 : 0, + l = s ? -1 : c ? 1 : 0), + e.update(A(e.cache.x + .01 * l), A(e.cache.y + .01 * p)), + t.preventDefault() + } else + o.startsWith("Arrow") && (e.options.onstop(), + t.preventDefault()) + } + }, + _tapstart: function(t) { + a(document, ["pointerup", "touchend", "touchcancel"], e._tapstop), + a(document, ["mousemove", "touchmove"], e._tapmove), + t.cancelable && t.preventDefault(), + e._tapmove(t) + }, + _tapmove: function(t) { + var r = e.options + , n = e.cache + , o = r.lock + , i = r.element + , a = r.wrapper.getBoundingClientRect() + , c = 0 + , u = 0; + if (t) { + var s = t && t.touches && t.touches[0]; + c = t ? (s || t).clientX : 0, + u = t ? (s || t).clientY : 0, + c < a.left ? c = a.left : c > a.left + a.width && (c = a.left + a.width), + u < a.top ? u = a.top : u > a.top + a.height && (u = a.top + a.height), + c -= a.left, + u -= a.top + } else + n && (c = n.x * a.width, + u = n.y * a.height); + "h" !== o && (i.style.left = "calc(" + c / a.width * 100 + "% - " + i.offsetWidth / 2 + "px)"), + "v" !== o && (i.style.top = "calc(" + u / a.height * 100 + "% - " + i.offsetHeight / 2 + "px)"), + e.cache = { + x: c / a.width, + y: u / a.height + }; + var l = A(c / a.width) + , p = A(u / a.height); + switch (o) { + case "v": + return r.onchange(l); + case "h": + return r.onchange(p); + default: + return r.onchange(l, p) + } + }, + _tapstop: function() { + e.options.onstop(), + c(document, ["pointerup", "touchend", "touchcancel"], e._tapstop), + c(document, ["mousemove", "touchmove"], e._tapmove) + }, + trigger: function() { + e._tapmove() + }, + update: function(t, r) { + void 0 === t && (t = 0), + void 0 === r && (r = 0); + var n = e.options.wrapper.getBoundingClientRect() + , o = n.left + , i = n.top + , a = n.width + , c = n.height; + "h" === e.options.lock && (r = t), + e._tapmove({ + clientX: o + a * t, + clientY: i + c * r + }) + }, + destroy: function() { + var t = e.options + , r = e._tapstart + , n = e._keyboard; + c(document, ["keydown", "keyup"], n), + c([t.wrapper, t.element], "pointerdown", r), + c([t.wrapper, t.element], "touchstart", r, { + passive: !1 + }) + } + } + , r = e.options + , n = e._tapstart + , o = e._keyboard; + return a([r.wrapper, r.element], "pointerdown", n), + a([r.wrapper, r.element], "touchstart", n, { + passive: !1 + }), + a(document, ["keydown", "keyup"], o), + e + } + function E(e) { + void 0 === e && (e = {}), + e = Object.assign({ + onchange: function() { + return 0 + }, + className: "", + elements: [] + }, e); + var r = a(e.elements, "click", (function(t) { + e.elements.forEach((function(r) { + return r.classList[t.target === r ? "add" : "remove"](e.className) + } + )), + e.onchange(t), + t.stopPropagation() + } + )); + return { + destroy: function() { + return c.apply(t, r) + } + } + } + const j = { + variantFlipOrder: { + start: "sme", + middle: "mse", + end: "ems" + }, + positionFlipOrder: { + top: "tbrl", + right: "rltb", + bottom: "btrl", + left: "lrbt" + }, + position: "bottom", + margin: 8, + padding: 0 + } + , C = (t, e, r) => { + const n = "object" != typeof t || t instanceof HTMLElement ? { + reference: t, + popper: e, + ...r + } : t; + return { + update(t=n) { + const {reference: e, popper: r} = Object.assign(n, t); + if (!r || !e) + throw new Error("Popper- or reference-element missing."); + return ( (t, e, r) => { + const {container: n, arrow: o, margin: i, padding: a, position: c, variantFlipOrder: u, positionFlipOrder: s} = { + container: document.documentElement.getBoundingClientRect(), + ...j, + ...r + } + , {left: l, top: p} = e.style; + e.style.left = "0", + e.style.top = "0"; + const f = t.getBoundingClientRect() + , v = e.getBoundingClientRect() + , h = { + t: f.top - v.height - i, + b: f.bottom + i, + r: f.right + i, + l: f.left - v.width - i + } + , d = { + vs: f.left, + vm: f.left + f.width / 2 - v.width / 2, + ve: f.left + f.width - v.width, + hs: f.top, + hm: f.bottom - f.height / 2 - v.height / 2, + he: f.bottom - v.height + } + , [g,y="middle"] = c.split("-") + , b = s[g] + , m = u[y] + , {top: x, left: w, bottom: S, right: _} = n; + for (const t of b) { + const r = "t" === t || "b" === t; + let n = h[t]; + const [i,c] = r ? ["top", "left"] : ["left", "top"] + , [u,s] = r ? [v.height, v.width] : [v.width, v.height] + , [l,p] = r ? [S, _] : [_, S] + , [g,y] = r ? [x, w] : [w, x]; + if (!(n < g || n + u + a > l)) + for (const l of m) { + let h = d[(r ? "v" : "h") + l]; + if (!(h < y || h + s + a > p)) { + if (h -= v[c], + n -= v[i], + e.style[c] = `${h}px`, + e.style[i] = `${n}px`, + o) { + const e = r ? f.width / 2 : f.height / 2 + , a = s / 2 + , p = e > a + , v = h + { + s: p ? a : e, + m: a, + e: p ? a : s - e + }[l] + , d = n + { + t: u, + b: 0, + r: 0, + l: u + }[t]; + o.style[c] = `${v}px`, + o.style[i] = `${d}px` + } + return t + l + } + } + } + return e.style.left = l, + e.style.top = p, + null + } + )(e, r, n) + } + } + } + ; + var k; + function P(t, e) { + var r = "undefined" != typeof Symbol && t[Symbol.iterator] || t["@@iterator"]; + if (r) + return (r = r.call(t)).next.bind(r); + if (Array.isArray(t) || (r = function(t, e) { + if (!t) + return; + if ("string" == typeof t) + return I(t, e); + var r = Object.prototype.toString.call(t).slice(8, -1); + "Object" === r && t.constructor && (r = t.constructor.name); + if ("Map" === r || "Set" === r) + return Array.from(t); + if ("Arguments" === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)) + return I(t, e) + }(t)) || e && t && "number" == typeof t.length) { + r && (t = r); + var n = 0; + return function() { + return n >= t.length ? { + done: !0 + } : { + done: !1, + value: t[n++] + } + } + } + throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.") + } + function I(t, e) { + (null == e || e > t.length) && (e = t.length); + for (var r = 0, n = new Array(e); r < e; r++) + n[r] = t[r]; + return n + } + var R = function() { + function e(t) { + var r = this; + this._initializingActive = !0, + this._recalc = !0, + this._nanopop = null, + this._root = null, + this._color = _(), + this._lastColor = _(), + this._swatchColors = [], + this._setupAnimationFrame = null, + this._eventListener = { + init: [], + save: [], + hide: [], + show: [], + clear: [], + change: [], + changestop: [], + cancel: [], + swatchselect: [] + }, + this.options = t = Object.assign(Object.assign({}, e.DEFAULT_OPTIONS), t); + var n = t + , o = n.swatches + , i = n.components + , a = n.theme + , c = n.sliders + , u = n.lockOpacity + , s = n.padding; + ["nano", "monolith"].includes(a) && !c && (t.sliders = "h"), + i.interaction || (i.interaction = {}); + var l = i.preview + , p = i.opacity + , f = i.hue + , v = i.palette; + i.opacity = !u && p, + i.palette = v || l || p || f, + this._preBuild(), + this._buildComponents(), + this._bindEvents(), + this._finalBuild(), + o && o.length && o.forEach((function(t) { + return r.addSwatch(t) + } + )); + var h = this._root + , d = h.button + , g = h.app; + this._nanopop = C(d, g, { + margin: s + }), + d.setAttribute("role", "button"), + d.setAttribute("aria-label", this._t("btn:toggle")); + var y = this; + this._setupAnimationFrame = requestAnimationFrame((function e() { + if (!g.offsetWidth) + return requestAnimationFrame(e); + y.setColor(t.default), + y._rePositioningPicker(), + t.defaultRepresentation && (y._representation = t.defaultRepresentation, + y.setColorRepresentation(y._representation)), + t.showAlways && y.show(), + y._initializingActive = !1, + y._emit("init") + } + )) + } + var r = e.prototype; + return r._preBuild = function() { + for (var t, e, r, n, o, i, a, c, u, l, f, v, h = this.options, d = 0, g = ["el", "container"]; d < g.length; d++) { + var y = g[d]; + h[y] = p(h[y]) + } + this._root = (e = (t = this).options, + r = e.components, + n = e.useAsButton, + o = e.inline, + i = e.appClass, + a = e.theme, + c = e.lockOpacity, + u = function(t) { + return t ? "" : 'style="display:none" hidden' + } + , + f = s('\n
\n\n ' + (n ? "" : '') + '\n\n
\n
\n
\n \n
\n
\n\n
\n
\n
\n
\n\n
\n
\n
\n
\n\n
\n
\n
\n
\n
\n\n
\n\n
\n \n\n \n \n \n \n \n\n \n \n \n
\n
\n
\n '), + (v = f.interaction).options.find((function(t) { + return !t.hidden && !t.classList.add("active") + } + )), + v.type = function() { + return v.options.find((function(t) { + return t.classList.contains("active") + } + )) + } + , + f), + h.useAsButton && (this._root.button = h.el), + h.container.appendChild(this._root.root) + } + , + r._finalBuild = function() { + var t = this.options + , e = this._root; + if (t.container.removeChild(e.root), + t.inline) { + var r = t.el.parentElement; + t.el.nextSibling ? r.insertBefore(e.app, t.el.nextSibling) : r.appendChild(e.app) + } else + t.container.appendChild(e.app); + t.useAsButton ? t.inline && t.el.remove() : t.el.parentNode.replaceChild(e.root, t.el), + t.disabled && this.disable(), + t.comparison || (e.button.style.transition = "none", + t.useAsButton || (e.preview.lastColor.style.transition = "none")), + this.hide() + } + , + r._buildComponents = function() { + var t = this + , e = this + , r = this.options.components + , n = (e.options.sliders || "v").repeat(2) + , o = n.match(/^[vh]+$/g) ? n : [] + , i = o[0] + , a = o[1] + , c = function() { + return t._color || (t._color = t._lastColor.clone()) + } + , u = { + palette: O({ + element: e._root.palette.picker, + wrapper: e._root.palette.palette, + onstop: function() { + return e._emit("changestop", "slider", e) + }, + onchange: function(t, n) { + if (r.palette) { + var o = c() + , i = e._root + , a = e.options + , u = i.preview + , s = u.lastColor + , l = u.currentColor; + e._recalc && (o.s = 100 * t, + o.v = 100 - 100 * n, + o.v < 0 && (o.v = 0), + e._updateOutput("slider")); + var p = o.toRGBA().toString(0); + this.element.style.background = p, + this.wrapper.style.background = "\n linear-gradient(to top, rgba(0, 0, 0, " + o.a + "), transparent),\n linear-gradient(to left, hsla(" + o.h + ", 100%, 50%, " + o.a + "), rgba(255, 255, 255, " + o.a + "))\n ", + a.comparison ? a.useAsButton || e._lastColor || s.style.setProperty("--pcr-color", p) : (i.button.style.setProperty("--pcr-color", p), + i.button.classList.remove("clear")); + for (var f, v = o.toHEXA().toString(), h = P(e._swatchColors); !(f = h()).done; ) { + var d = f.value + , g = d.el + , y = d.color; + g.classList[v === y.toHEXA().toString() ? "add" : "remove"]("pcr-active") + } + l.style.setProperty("--pcr-color", p) + } + } + }), + hue: O({ + lock: "v" === a ? "h" : "v", + element: e._root.hue.picker, + wrapper: e._root.hue.slider, + onstop: function() { + return e._emit("changestop", "slider", e) + }, + onchange: function(t) { + if (r.hue && r.palette) { + var n = c(); + e._recalc && (n.h = 360 * t), + this.element.style.backgroundColor = "hsl(" + n.h + ", 100%, 50%)", + u.palette.trigger() + } + } + }), + opacity: O({ + lock: "v" === i ? "h" : "v", + element: e._root.opacity.picker, + wrapper: e._root.opacity.slider, + onstop: function() { + return e._emit("changestop", "slider", e) + }, + onchange: function(t) { + if (r.opacity && r.palette) { + var n = c(); + e._recalc && (n.a = Math.round(100 * t) / 100), + this.element.style.background = "rgba(0, 0, 0, " + n.a + ")", + u.palette.trigger() + } + } + }), + selectable: E({ + elements: e._root.interaction.options, + className: "active", + onchange: function(t) { + e._representation = t.target.getAttribute("data-type").toUpperCase(), + e._recalc && e._updateOutput("swatch") + } + }) + }; + this._components = u + } + , + r._bindEvents = function() { + var t = this + , e = this._root + , r = this.options + , n = [a(e.interaction.clear, "click", (function() { + return t._clearColor() + } + )), a([e.interaction.cancel, e.preview.lastColor], "click", (function() { + t.setHSVA.apply(t, (t._lastColor || t._color).toHSVA().concat([!0])), + t._emit("cancel") + } + )), a(e.interaction.save, "click", (function() { + !t.applyColor() && !r.showAlways && t.hide() + } + )), a(e.interaction.result, ["keyup", "input"], (function(e) { + t.setColor(e.target.value, !0) && !t._initializingActive && (t._emit("change", t._color, "input", t), + t._emit("changestop", "input", t)), + e.stopImmediatePropagation() + } + )), a(e.interaction.result, ["focus", "blur"], (function(e) { + t._recalc = "blur" === e.type, + t._recalc && t._updateOutput(null) + } + )), a([e.palette.palette, e.palette.picker, e.hue.slider, e.hue.picker, e.opacity.slider, e.opacity.picker], ["pointerdown", "touchstart"], (function() { + return t._recalc = !0 + } + ), { + passive: !0 + })]; + if (!r.showAlways) { + var o = r.closeWithKey; + n.push(a(e.button, "click", (function() { + return t.isOpen() ? t.hide() : t.show() + } + )), a(document, "keyup", (function(e) { + return t.isOpen() && (e.key === o || e.code === o) && t.hide() + } + )), a(document, ["touchstart", "pointerdown"], (function(r) { + t.isOpen() && !l(r).some((function(t) { + return t === e.app || t === e.button + } + )) && t.hide() + } + ), { + capture: !0 + })) + } + if (r.adjustableNumbers) { + var i = { + rgba: [255, 255, 255, 1], + hsva: [360, 100, 100, 1], + hsla: [360, 100, 100, 1], + cmyk: [100, 100, 100, 100] + }; + f(e.interaction.result, (function(e, r, n) { + var o = i[t.getColorRepresentation().toLowerCase()]; + if (o) { + var a = o[n] + , c = e + (a >= 100 ? 1e3 * r : r); + return c <= 0 ? 0 : Number((c < a ? c : a).toPrecision(3)) + } + return e + } + )) + } + if (r.autoReposition && !r.inline) { + var c = null + , u = this; + n.push(a(window, ["scroll", "resize"], (function() { + u.isOpen() && (r.closeOnScroll && u.hide(), + null === c ? (c = setTimeout((function() { + return c = null + } + ), 100), + requestAnimationFrame((function t() { + u._rePositioningPicker(), + null !== c && requestAnimationFrame(t) + } + ))) : (clearTimeout(c), + c = setTimeout((function() { + return c = null + } + ), 100))) + } + ), { + capture: !0 + })) + } + this._eventBindings = n + } + , + r._rePositioningPicker = function() { + var t = this.options; + if (!t.inline && !this._nanopop.update({ + container: document.body.getBoundingClientRect(), + position: t.position + })) { + var e = this._root.app + , r = e.getBoundingClientRect(); + e.style.top = (window.innerHeight - r.height) / 2 + "px", + e.style.left = (window.innerWidth - r.width) / 2 + "px" + } + } + , + r._updateOutput = function(t) { + var e = this._root + , r = this._color + , n = this.options; + if (e.interaction.type()) { + var o = "to" + e.interaction.type().getAttribute("data-type"); + e.interaction.result.value = "function" == typeof r[o] ? r[o]().toString(n.outputPrecision) : "" + } + !this._initializingActive && this._recalc && this._emit("change", r, t, this) + } + , + r._clearColor = function(t) { + void 0 === t && (t = !1); + this._lastColor = null; + const input = this._root?.app?.querySelector('.pcr-result'); + if (!this._initializingActive && !t) { + if (input) { + input.value = '#clear'; + } + this._emit("save", null); + this._emit("clear"); + } + } + + , + r._parseLocalColor = function(t) { + var e = S(t) + , r = e.values + , n = e.type + , o = e.a + , i = this.options.lockOpacity + , a = void 0 !== o && 1 !== o; + return r && 3 === r.length && (r[3] = void 0), + { + values: !r || i && a ? null : r, + type: n + } + } + , + r._t = function(t) { + return this.options.i18n[t] || e.I18N_DEFAULTS[t] + } + , + r._emit = function(t) { + for (var e = this, r = arguments.length, n = new Array(r > 1 ? r - 1 : 0), o = 1; o < r; o++) + n[o - 1] = arguments[o]; + this._eventListener[t].forEach((function(t) { + return t.apply(void 0, n.concat([e])) + } + )) + } + , + r.on = function(t, e) { + return this._eventListener[t].push(e), + this + } + , + r.off = function(t, e) { + var r = this._eventListener[t] || [] + , n = r.indexOf(e); + return ~n && r.splice(n, 1), + this + } + , + r.addSwatch = function(t) { + var e = this + , r = this._parseLocalColor(t).values; + if (r) { + var n = this._swatchColors + , o = this._root + , i = _.apply(void 0, r) + , c = u('`; + } else if (key.toLowerCase() === "title") { + inputHtml = ``; + } else if (key.toLowerCase() === "name") { + inputHtml = ``; + } else if (key.toLowerCase() === "template") { + let defaultTemplate = value; + inputHtml = ``; + setTimeout(function() { + jsonrpcRequest("getFolders", { folder: "/template" }).then(data => { + let select = document.getElementById('templateSelect'); + if (select && data) { + select.innerHTML = ''; + data.forEach(folder => { + select.innerHTML += `${folder}`; + }); + } + }); + }, 0); + } else if (key.toLowerCase() === "pagemenu") { + let values = value.split(","); + while (values.length < 3) { + values.push(""); + } + inputHtml = values.map((val, index) => + `` + ).join(" , "); + } else if (key.toLowerCase() === "users") { + inputHtml = ``; + } else if (key.toLowerCase() === "group") { + inputHtml = ``; + } else if (key.toLowerCase() === "plugins") { + let plugins = (value || '').split(','); + let allPlugins = ['dgrm','SvgEditorM']; + inputHtml = allPlugins.map(p => + `` + ).join(' '); + } + + + rows.push(`${key}${inputHtml}`); + } + setTimeout(treePropertiesDivFunc, 0); + return `${rows.join('')}
`; +} +function treePropertiesDivFunc() { + document.getElementById('treePropertiesDivUrl').onclick = function() { + window.managerDataAction = "propertiesUrl"; + managerData("/content"); + managerDiv.style.visibility = "visible"; + document.getElementById("settingsMain_d").style.visibility="hidden"; + }; +} + +let lastRightClickedItem = null; +let treePropertiesDivElement = null; +function treeContext(event){ + let treeItem=event.target.closest('.tree-item') + if(treeItem){ + lastRightClickedItem=treeItem + treePropertiesDivElement=treeItem + } +} +document.addEventListener('contextmenu',treeContext) +touchLong(document,treeContext) + +}, { once: true }); /* начало */ diff --git a/main_plugin/site_tree/site_tree.php b/main_plugin/site_tree/site_tree.php new file mode 100755 index 0000000..f394401 --- /dev/null +++ b/main_plugin/site_tree/site_tree.php @@ -0,0 +1,49 @@ + + + + + + + + + + diff --git a/plugin/foto/plug.php b/plugin/foto/plug.php new file mode 100755 index 0000000..ef06a74 --- /dev/null +++ b/plugin/foto/plug.php @@ -0,0 +1,5 @@ + + '; +?> diff --git a/plugin/plugintest/plug.php b/plugin/plugintest/plug.php new file mode 100755 index 0000000..ec4aad6 --- /dev/null +++ b/plugin/plugintest/plug.php @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/rse/10-USB-media-automount.rules b/rse/10-USB-media-automount.rules new file mode 100755 index 0000000..55ea349 --- /dev/null +++ b/rse/10-USB-media-automount.rules @@ -0,0 +1,32 @@ +# /etc/udev/rules.d/10-USB-media-automount.rules + +# проверка всех разделов +KERNEL!="sd[a-z][0-9]", GOTO="end" +# инфа о файловой системе +IMPORT{program}="/sbin/blkid %N" + +#/root/USB_Automount/mount.sh %N %K + + + # Получаем метку в противном случае система присваивает сама +ENV{ID_FS_LABEL}!="", ENV{dir_name}="%E{ID_FS_LABEL}" +ENV{ID_FS_LABEL}=="", ENV{dir_name}="UsbDisk-%k" + +# Создаем папку в /media и символическую ссылку на неё в /mnt%E{dir_name} +ACTION=="add", RUN+="/bin/mkdir -p '/media/%E{dir_name}'" + +# Глобальные опции +ACTION=="add", ENV{mount_options}="relatime" +# Права (777/666 папки/файлы для ntfs/vfat) +ACTION=="add", ENV{ID_FS_TYPE}=="vfat|ntfs", ENV{mount_options}="$env{mount_options},gid=100,dmask=000,fmask=000,utf8" + +# автомоунт ntfs через ntfs-3g +ACTION=="add", ENV{ID_FS_TYPE}=="ntfs", RUN+="/bin/mount -t ntfs-3g -o %E{mount_options} /dev/%k '/media/%E{dir_name}'" +# для остальных система сама определяет +ACTION=="add", ENV{ID_FS_TYPE}!="ntfs", RUN+="/bin/mount -t auto -o %E{mount_options} /dev/%k '/media/%E{dir_name}'" + +# чистка после изьятия +ACTION=="remove", ENV{dir_name}!="", RUN+="/bin/umount -l '/media/%E{dir_name}'", RUN+="/bin/rmdir '/media/%E{dir_name}'" + +# выход +LABEL="end" diff --git a/rse/automount.rules b/rse/automount.rules new file mode 100755 index 0000000..0c226e5 --- /dev/null +++ b/rse/automount.rules @@ -0,0 +1,31 @@ +# /etc/udev/rules.d/10-my-media-automount.rules + +# проверка всех разделов +KERNEL!="sd[a-z]*", GOTO="end" +ACTION=="add", PROGRAM!="/sbin/blkid %N", GOTO="end" + +# инфа о файловой системе +IMPORT{program}="/sbin/blkid -o udev -p %N" + +# Получаем метку в противном случае система присваивает сама +ENV{ID_FS_LABEL}!="", ENV{dir_name}="%E{ID_FS_LABEL}" +ENV{ID_FS_LABEL}=="", ENV{dir_name}="usbhd-%k" + +# Создаем папку в /media и символическую ссылку на неё в /mnt +ACTION=="add", RUN+="/bin/mkdir -p '/media/%E{dir_name}'" + +# Глобальные опции +ACTION=="add", ENV{mount_options}="relatime" +# Права (777/666 папки/файлы для ntfs/vfat) +ACTION=="add", ENV{ID_FS_TYPE}=="vfat|ntfs", ENV{mount_options}="$env{mount_options},gid=100,dmask=000,fmask=111,utf8" + +# автомоунт ntfs через ntfs-3g +ACTION=="add", ENV{ID_FS_TYPE}=="ntfs", RUN+="/bin/mount -t ntfs-3g -o %E{mount_options} /dev/%k '/media/%E{dir_name}'" +# для остальных система сама определяет +ACTION=="add", ENV{ID_FS_TYPE}!="ntfs", RUN+="/bin/mount -t auto -o %E{mount_options} /dev/%k '/media/%E{dir_name}'" + +# чистка после изьятия +ACTION=="remove", ENV{dir_name}!="", RUN+="/bin/umount -l '/media/%E{dir_name}'", RUN+="/bin/rmdir '/media/%E{dir_name}'" + +# выход +LABEL="end" diff --git a/rse/dhcpd.conf.en b/rse/dhcpd.conf.en new file mode 100755 index 0000000..e4368e7 --- /dev/null +++ b/rse/dhcpd.conf.en @@ -0,0 +1,107 @@ +# +# Sample configuration file for ISC dhcpd for Debian +# +# + +# The ddns-updates-style parameter controls whether or not the server will +# attempt to do a DNS update when a lease is confirmed. We default to the +# behavior of the version 2 packages ('none', since DHCP v2 didn't +# have support for DDNS.) +ddns-update-style none; + +# option definitions common to all supported networks... +option domain-name "example.org"; +option domain-name-servers ns1.example.org, ns2.example.org; + +default-lease-time 600; +max-lease-time 7200; + +# If this DHCP server is the official DHCP server for the local +# network, the authoritative directive should be uncommented. +#authoritative; + +# Use this to send dhcp log messages to a different log file (you also +# have to hack syslog.conf to complete the redirection). +log-facility local7; + +# No service will be given on this subnet, but declaring it helps the +# DHCP server to understand the network topology. + +#subnet 10.152.187.0 netmask 255.255.255.0 { +#} + +# This is a very basic subnet declaration. + +#subnet 10.254.239.0 netmask 255.255.255.224 { +# range 10.254.239.10 10.254.239.20; +# option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org; +#} + +# This declaration allows BOOTP clients to get dynamic addresses, +# which we don't really recommend. + +#subnet 10.254.239.32 netmask 255.255.255.224 { +# range dynamic-bootp 10.254.239.40 10.254.239.60; +# option broadcast-address 10.254.239.31; +# option routers rtr-239-32-1.example.org; +#} + +# A slightly different configuration for an internal subnet. +#subnet 10.5.5.0 netmask 255.255.255.224 { +# range 10.5.5.26 10.5.5.30; +# option domain-name-servers ns1.internal.example.org; +# option domain-name "internal.example.org"; +# option routers 10.5.5.1; +# option broadcast-address 10.5.5.31; +# default-lease-time 600; +# max-lease-time 7200; +#} + +# Hosts which require special configuration options can be listed in +# host statements. If no address is specified, the address will be +# allocated dynamically (if possible), but the host-specific information +# will still come from the host declaration. + +#host passacaglia { +# hardware ethernet 0:0:c0:5d:bd:95; +# filename "vmunix.passacaglia"; +# server-name "toccata.fugue.com"; +#} + +# Fixed IP addresses can also be specified for hosts. These addresses +# should not also be listed as being available for dynamic assignment. +# Hosts for which fixed IP addresses have been specified can boot using +# BOOTP or DHCP. Hosts for which no fixed address is specified can only +# be booted with DHCP, unless there is an address range on the subnet +# to which a BOOTP client is connected which has the dynamic-bootp flag +# set. +#host fantasia { +# hardware ethernet 08:00:07:26:c0:a5; +# fixed-address fantasia.fugue.com; +#} + +# You can declare a class of clients and then do address allocation +# based on that. The example below shows a case where all clients +# in a certain class get addresses on the 10.17.224/24 subnet, and all +# other clients get addresses on the 10.0.29/24 subnet. + +#class "foo" { +# match if substring (option vendor-class-identifier, 0, 4) = "SUNW"; +#} + +#shared-network 224-29 { +# subnet 10.17.224.0 netmask 255.255.255.0 { +# option routers rtr-224.example.org; +# } +# subnet 10.0.29.0 netmask 255.255.255.0 { +# option routers rtr-29.example.org; +# } +# pool { +# allow members of "foo"; +# range 10.17.224.10 10.17.224.250; +# } +# pool { +# deny members of "foo"; +# range 10.0.29.10 10.0.29.230; +# } +#} diff --git a/rse/dhcpd.conf.ru b/rse/dhcpd.conf.ru new file mode 100755 index 0000000..99d2b1f --- /dev/null +++ b/rse/dhcpd.conf.ru @@ -0,0 +1,119 @@ +# +# Пример файла конфигурации для ISC DHCPD для Debian +# +# + +# ddns-стиль-обновления параметров определяет, будет ли или не сервер +# пытаются сделать обновление DNS, когда договор аренды подтверждается. По умолчанию используется +# поведение версии 2 пакета ("None", так как DHCP v2 не имеет поддержки DDNS.) +ddns-update-style none; + +# определения параметров общих для всех поддерживаемых сетей... +#option domain-name "example.org"; +option domain-name-servers 192.168.1.254; + +#default-lease-time 600; +#max-lease-time 7200; + +# Если этот DHCP сервер является официальным DHCP сервером для локальной сети +# раскоментируйте (authoritative). +authoritative; + +# Используется для отправки сообщения DHCP log-a в другой файл log-a (вам также +# придется править syslog.conf для завершения перенаправления). +log-facility local7; + +subnet 192.168.10.0 netmask 255.255.0.0 { +# +default-lease-time 600; +max-lease-time 7200; +# +option netbios-name-servers 192.168.10.2; +option netbios-dd-server 192.168.10.2; +optionnetbios-node-type 8; +# +range 192.168.10.2 192.168.10.254; +option routers 192.168.10.1 +} + +# No service will be given on this subnet, but declaring it helps the +# DHCP server to understand the network topology. + +#subnet 10.152.187.0 netmask 255.255.255.0 { +#} + +# This is a very basic subnet declaration. + +#subnet 10.254.239.0 netmask 255.255.255.224 { +# range 10.254.239.10 10.254.239.20; +# option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org; +#} + +# This declaration allows BOOTP clients to get dynamic addresses, +# which we don't really recommend. + +#subnet 10.254.239.32 netmask 255.255.255.224 { +# range dynamic-bootp 10.254.239.40 10.254.239.60; +# option broadcast-address 10.254.239.31; +# option routers rtr-239-32-1.example.org; +#} + +# A slightly different configuration for an internal subnet. +#subnet 10.5.5.0 netmask 255.255.255.224 { +# range 10.5.5.26 10.5.5.30; +# option domain-name-servers ns1.internal.example.org; +# option domain-name "internal.example.org"; +# option routers 10.5.5.1; +# option broadcast-address 10.5.5.31; +# default-lease-time 600; +# max-lease-time 7200; +#} + +# Hosts which require special configuration options can be listed in +# host statements. If no address is specified, the address will be +# allocated dynamically (if possible), but the host-specific information +# will still come from the host declaration. + +#host passacaglia { +# hardware ethernet 0:0:c0:5d:bd:95; +# filename "vmunix.passacaglia"; +# server-name "toccata.fugue.com"; +#} + +# Fixed IP addresses can also be specified for hosts. These addresses +# should not also be listed as being available for dynamic assignment. +# Hosts for which fixed IP addresses have been specified can boot using +# BOOTP or DHCP. Hosts for which no fixed address is specified can only +# be booted with DHCP, unless there is an address range on the subnet +# to which a BOOTP client is connected which has the dynamic-bootp flag +# set. +#host fantasia { +# hardware ethernet 08:00:07:26:c0:a5; +# fixed-address fantasia.fugue.com; +#} + +# You can declare a class of clients and then do address allocation +# based on that. The example below shows a case where all clients +# in a certain class get addresses on the 10.17.224/24 subnet, and all +# other clients get addresses on the 10.0.29/24 subnet. + +#class "foo" { +# match if substring (option vendor-class-identifier, 0, 4) = "SUNW"; +#} + +#shared-network 224-29 { +# subnet 10.17.224.0 netmask 255.255.255.0 { +# option routers rtr-224.example.org; +# } +# subnet 10.0.29.0 netmask 255.255.255.0 { +# option routers rtr-29.example.org; +# } +# pool { +# allow members of "foo"; +# range 10.17.224.10 10.17.224.250; +# } +# pool { +# deny members of "foo"; +# range 10.0.29.10 10.0.29.230; +# } +#} diff --git a/rse/dhcpd.log b/rse/dhcpd.log new file mode 100755 index 0000000..e69de29 diff --git a/rse/media-automount.rules.save b/rse/media-automount.rules.save new file mode 100755 index 0000000..1af3bd0 --- /dev/null +++ b/rse/media-automount.rules.save @@ -0,0 +1,31 @@ +# /etc/udev/rules.d/10-my-media-automount.rules + +# nachinajem s sdb, dabi izbezatj montirovanija sistemnih diskov +KERNEL!="sd[b-z]*", GOTO="konec_montirovanija" +ACTION=="add", PROGRAM!="/sbin/blkid %N", GOTO="konec_montirovanija" + +# i +IMPORT{program}="/sbin/blkid -o udev -p %N" + +# get the label if present, otherwise assign one based on device/partition +ENV{ID_FS_LABEL}!="", ENV{dir_name}="%E{ID_FS_LABEL}" +ENV{ID_FS_LABEL}=="", ENV{dir_name}="usbhd-%k" + +# create the dir in /media and symlink it to /mnt +ACTION=="add", RUN+="/bin/mkdir -p '/media/%E{dir_name}'" + +# global mount options +ACTION=="add", ENV{mount_options}="relatime" +# filesystem-specific mount options (777/666 dir/file perms for ntfs/vfat) +ACTION=="add", ENV{ID_FS_TYPE}=="vfat|ntfs", ENV{mount_options}="$env{mount_options},gid=100,dmask=000,fmask=111,utf8" + +# automount ntfs filesystems using ntfs-3g driver +ACTION=="add", ENV{ID_FS_TYPE}=="ntfs", RUN+="/bin/mount -t ntfs-3g -o %E{mount_options} /dev/%k '/media/%E{dir_name}'" +# automount all other filesystems +ACTION=="add", ENV{ID_FS_TYPE}!="ntfs", RUN+="/bin/mount -t auto -o %E{mount_options} /dev/%k '/media/%E{dir_name}'" + +# clean up after device removal +ACTION=="remove", ENV{dir_name}!="", RUN+="/bin/umount -l '/media/%E{dir_name}'", RUN+="/bin/rmdir '/media/%E{dir_name}'" + +# exit +LABEL="konec_montirovanija" diff --git a/template/MedWait/css.php b/template/MedWait/css.php new file mode 100755 index 0000000..10471c7 --- /dev/null +++ b/template/MedWait/css.php @@ -0,0 +1,382 @@ +/*- основные стили и стили для плагинов */ + +body, html{ + margin: 0px; + margin-bottom: 30px; + padding: 0px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: default; +} + +body, html, .textStyle, input, textarea, select, button { + font-size: 17px; + font-family: Arial, Tahoma, Verdana, sans-serif; +} + +.titleBackground, .btitle, .mainBackground, .bfloat { + background-color: rgba(255, 255, 255, 0.5); +} + +.borderStyle, #sslogan, #hmenu { + border: 1px solid #000000; +} + +button { + background-color: #ffffff; + border: 1px solid rgb(0, 0, 0); + border-radius: 2px; +} +ul, ol { + margin-block-start: 0em; + margin-block-end: 0em; +} + + + +/*- тело */ + +#bcbody { + background: #ffffff; + position: relative; +} + +#bibody { + opacity: 0.3; + background-image: url("/img/hall.jpg"); + background-position: center; + background-size: cover; + background-repeat: no-repeat; + width: 100%; + height: 100%; + position: fixed; + top: 0; + bottom: 0; + left: 0; +} + +#pbody { + width: 1800px; + max-width: -webkit-fill-available !important; + min-height: 100%; + margin-left: auto; + margin-right: auto; + padding-left: 16px; + padding-right: 16px; + top: 13px; +} + + + +/*- верхняя часть */ + +#head { + height: 30px; + left: -1px; + top: -1px; + width: 100%; + position: relative; +} + +#slogo { + left: 5px; + float: left; + position: relative; + width: 80px; + height: 99px; + background-repeat: no-repeat; + padding-right: 5px; +} + +#sname { + width: 200px; + height: 37px; + overflow: hidden; + position: relative; + background-image: url(/img/rpi.svg); + background-repeat: no-repeat; + top: 40px; +} + +#sslogan { + overflow: hidden; + text-align: left; + margin-top: 10px; +} + +#hmemo { + position: relative; + width: 150px; + height: 99px; + float: right; + background-image: url(/img/rpi.gif); + background-repeat: no-repeat; + background-size: auto 100px; + padding-right: 5px; +} + +#hmenu { + display: none; + position: relative; + width: 600px; + margin: 0 auto; + margin-bottom: 0px; + height: 30px; +} + +#smap { + position: relative; + margin: 0 auto; + margin-top: 5px; + width: 99%; + height: 20px; +} + +#smap a { + text-decoration: none; +} + + + +/*- центральный блок */ + +#left-float, +#right-float, +.center-float { + padding: 5px; +} + +#right-float, +#left-float { + z-index: 1; + position: relative; +} + +#left-float { + float: left; + padding-right: 10px; +} + +#right-float { + float: right; +} + +#left-float:empty, +#right-float:empty { + width: 0px; +} + +#left-float:not(:empty), +#right-float:not(:empty) { + width: 20%; +} + +.center-float { + float: none; + width: auto; + display: inline-block; + width: calc(60% - 40px); +} + +.center-float .bfloat { + overflow-x: visible; +} + +.bfloat { + overflow-x: hidden; + left: -1px; + top: -1px; + position: relative; + border-radius: 0 0 10px 10px; + padding: 10px; + font-size: 1em; +} + +.cfloat { + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; +} + +.btitle { + padding: 10px; + left: -1px; + top: -1px; + position: relative; + line-height: 30px; + font-size: 2em; + font-weight: bold; + background-size: auto 30px; + border-radius: 10px 10px 0 0; + color: #000000; + overflow-wrap: break-word; + padding: 5px; +} + +.ctitle { + left: 0px; + top: -1px; + position: relative; + width: 100%; + height: 20px; + text-align: center; + line-height: 20px; + font-weight: bold; +} + +#content { + overflow-x: hidden; + overflow-y: hidden; +} +#content td { + height: 19px; +} +#editor a { + text-decoration: none; + color: inherit; +} +[contenteditable="true"]:focus { + outline: 1px solid #000; + outline-offset: 2px; + border-radius: 2px; +} + + + +/*- показ сообщений */ + +.messageBlock { + width: 400px; + height: auto; + top: 10px; + z-index: 1003; + right: 0; + position: fixed; + display: inline-block; + border-radius: 10px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); + margin: 15px; + font-family: 'Roboto', sans-serif; + transition: opacity 0.15s ease-in-out; + background-color: rgba(255, 255, 255, 0.92); + max-width: -webkit-fill-available; +} +.messageBlock.show { + opacity: 1; +} +.messageBasicText { + padding: 10px 15px 10px 15px; + border: none; + border-bottom: inherit; + font-size: 1.5em; +} +.messageText { + font-size: 1.15em; + margin: 15px; +} +.messageInput { + font-size: 1.15em; + margin: 18px 18px 3px 18px; + padding: 2px; + width: -webkit-fill-available; +} +.messageButton { + background-color: rgba(255, 255, 255, 0.92); + padding: 8px; + border-radius: 15px; + float: left; + font-size: 1.15em; + width: 35px; + text-align: center; + cursor: pointer; + margin: 15px; +} + + + + + + + +/*- размер окна */ + +@media (min-width: 1240px) { + #pbody { padding-left: 40px; padding-right: 40px; } + .center-float { width: calc(64% - 40px); } + #left-float:not(:empty), #right-float:not(:empty) { width: 18%; } +} +@media (min-width: 700px) and (max-width: 1239px) { + .center-float { width: calc(60% - 30px); } + #left-float:not(:empty), #right-float:not(:empty) { width: 20%; } + #left-float, #right-float, .center-float { padding: 5px !important; } +} +@media (min-width: 550px) and (max-width: 699px) { + .center-float { width: calc(56% - 30px); } + #left-float:not(:empty), #right-float:not(:empty) { width: 22%; } + #left-float, #right-float, .center-float { padding: 5px !important; } +} +@media (min-width: 550px) { + #editableArea { display: flex; } + .center-float { order: 2; flex: 1; } + #left-float { order: 1; } + #right-float { order: 3; } + #hbody { font-size: 1.3em; } +} + +@media only screen and (pointer: coarse) { + #panel { border-radius: 0px !important; } + #managerDiv, #treeDiv { + position: fixed; + top: 72px !important; + left: 0 !important; + width: 100vw !important; + height: calc(100vh - 74px) !important; + overflow-x: hidden !important; + overflow-y: auto !important; + box-shadow: none !important; + border-radius: 0 !important; + transform: none !important; + } + #treeTableDiv { + margin: 0px 10px 0px 10px !important; overflow-y: hidden !important; height: auto !important; + } + #managerTableDiv { + margin: 0px 10px 0px 10px !important; overflow-y: overlay !important; height: -webkit-fill-available !important; + } + #treeTableDiv, #managerProperties { width: calc(100% - 20px) !important; } +} + +@media (min-width: 0px) and (max-width: 549px) { + #hbody { font-size: 1.4em !important; } + #treeDiv { font-size: 1.05em !important; } + #authorizationButton { + background: url(../../img/pict/mc_iconslyb.svg) calc(var(--autButBackX) * 1.27px) calc(var(--autButBackY) * 1.27px) !important; + background-size: calc(1122px * 1.27) !important; width: 28px !important; height: 28px !important; margin-left: 9px; + } + #siteSettingsButton { + background: url(../../img/pict/mc_iconslyb.svg) calc(-1840px * 1.27) calc(1664px * 1.27 - 1px) !important; + background-size: calc(1122px * 1.27) !important; width: 28px !important; height: 28px !important; margin-left: 9px; + } + #left-float:not(:empty), #right-float:not(:empty) { width: calc(50% - 10px); } + .center-float { width: 100%; } + #left-float, #right-float { padding: 5px 0px !important; } + .center-float { padding: 5px 0px 15px 0px !important; } + .menu-btn { margin-left: 14px; } + #slng { margin-left: 3px; } + #authorizationDiv { width: 90% !important; } + #BackArrow { + background: url(../../img/pict/mc_iconslyb.svg) calc(-77px * 1.27) calc(-37px * 1.27) !important; + background-size: calc(1122px * 1.27) !important; width: 28px !important; height: 28px !important; top: 37px !important; + } + .authorizationDivCloseFun { + background: url(../../img/pict/mc_iconslyb.svg) calc(-159px * 1.27) calc(-120px * 1.27) !important; + background-size: calc(1122px * 1.27) !important; width: 28px !important; height: 28px !important; + } + .butinAuto, .butin, .sele { height: 25px !important; font-size: 1em !important; } + .cust2 { top: 247% !important; } +} + diff --git a/template/MedWait/page.php b/template/MedWait/page.php new file mode 100755 index 0000000..8bde895 --- /dev/null +++ b/template/MedWait/page.php @@ -0,0 +1,27 @@ +
+
+
+ +
+ %smap% +
+
+
+
+ %title% +
+
+
%content%
+
+
+ %left% + %right% +
+
+
+ + diff --git a/template/default/css.php b/template/default/css.php new file mode 100755 index 0000000..78ebd31 --- /dev/null +++ b/template/default/css.php @@ -0,0 +1,181 @@ + + + + +#pbody { + min-height: 100%; + position: relative; + width: 95%; + margin: 0px auto; + background: #ffffff; + top:20px; + } + + +#head { + height: 100px; + left:-1px; + top:-1px; + width: 100%; + position: relative; + } + +#slogo{ + left: 5px; + float: left; + position: relative; + width: 80px; + height: 99px; + background-image: url(/img/Raspberry_Pi_Logo.svg); + background-repeat: no-repeat; + padding-right: 5px; + } + +#sname{ + width:200px; +/* max-width:10%;*/ + height: 37px; + overflow: hidden; + position: relative; + background-image: url(/img/rpi.svg); + background-repeat: no-repeat; + top: 40px; + } + +#sslogan{ + border: 1px solid #000000; + overflow: hidden; + text-align: left; + margin-top:10px; + } + +#hmemo{ + position: relative; + width: 150px; + height: 99px; + float: right; + background-image: url(/img/rpi.gif); + background-repeat: no-repeat; + background-size: auto 100px; + padding-right: 5px; + } + +#hmenu{ + top: -30px; + border: 1px solid #000000; + position: relative; + width: 600px; + margin: 0 auto; + margin-bottom:0px; + height: 30px; + } + +#smap{ +/* border: 1px solid #000000; + text-align: left;*/ + position: relative; + margin: 0 auto; + margin-top:5px; + width: 99%; + height: 20px; + } + +#smap a{ + text-decoration: none; + } + + +#left-float, +#right-float, +.center-float { + padding: 5px; + } + +#left-float { + float: left; +} +#right-float { + float: right; +} +#left-float:empty, +#right-float:empty { + width: 0px; +} +#left-float:not(:empty), +#right-float:not(:empty) { + width: 200px; +} + + +.center-float { + float: none; + width: auto; + overflow: hidden; + } + +.bfloat{ + overflow-x: hidden; + border: 1px solid #f44180; + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + border-radius: 0 0 10px 10px; + } + +.cfloat{ + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + } + +.btitle{ +white-space: normal; +word-wrap: break-word; + left: -1px; + top: -1px; + position: relative; + width: calc(100% + 2px); + text-align: center; + line-height: 30px; + font-weight: bold; + color: #ffffff; + background-image: url(/img/menu_7.jpg); + background-size: auto 100% ; + border-radius: 10px 10px 0 0; + } + +.ctitle{ + left: 0px; + top: -1px; + position: relative; + width: 100%; + height: 20px; + text-align: center; + line-height: 20px; + font-weight: bold; + } +.cctitle{ + left: 0px; + top: -1px; + margin-top: -4px; + position: relative; + width: 100%; + height: 0px; + line-height: 00px; + } +.youtubef{ + max-width:100%; + width:650px; + height:360px; + { + diff --git a/template/default/page.php b/template/default/page.php new file mode 100755 index 0000000..817fdaa --- /dev/null +++ b/template/default/page.php @@ -0,0 +1,34 @@ +
+ +
+ %smap% +
+ +
+%left% +%right% +
+
+ %title% +
+
+
%content%
+
+
+
diff --git a/template/default1/css.php b/template/default1/css.php new file mode 100755 index 0000000..5b15df2 --- /dev/null +++ b/template/default1/css.php @@ -0,0 +1,175 @@ + +#pbody { + min-height: 100%; + position: relative; + width: 95%; + margin: 0px auto; + background: #ffffff; + top:20px; + } + + +#head { + height: 100px; + left:-1px; + top:-1px; + width: 100%; + position: relative; + } + +#slogo{ + left: 5px; + float: left; + position: relative; + width: 80px; + height: 99px; + background-image: url(/img/Raspberry_Pi_Logo.svg); + background-repeat: no-repeat; + padding-right: 5px; + } + +#sname{ + width:200px; +/* max-width:10%;*/ + height: 37px; + overflow: hidden; + position: relative; + background-image: url(/img/rpi.svg); + background-repeat: no-repeat; + top: 40px; + } + +#sslogan{ + border: 1px solid #000000; + overflow: hidden; + text-align: left; + margin-top:10px; + } + +#hmemo{ + position: relative; + width: 150px; + height: 99px; + float: right; + background-image: url(/img/rpi.gif); + background-repeat: no-repeat; + background-size: auto 100px; + padding-right: 5px; + } + +#hmenu{ + top: -30px; + border: 1px solid #000000; + position: relative; + width: 600px; + margin: 0 auto; + margin-bottom:0px; + height: 30px; + } + +#smap{ +/* border: 1px solid #000000; + text-align: left;*/ + position: relative; + margin: 0 auto; + margin-top:5px; + width: 99%; + height: 20px; + } + +#smap a{ + text-decoration: none; + } + +#left-float, +#right-float, +.center-float { + padding: 5px; + } + +#left-float { + float: left; +} +#right-float { + float: right; +} +#left-float:empty, +#right-float:empty { + width: 0px; +} +#left-float:not(:empty), +#right-float:not(:empty) { + width: 200px; +} + +.center-float { + float: none; + width: auto; + overflow: hidden; + } + +.bfloat{ + overflow-x: hidden; + border-radius: 0 0 100px 10px; + border: 1px solid #f44180; + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + border-radius: 0 0 10px 10px; + } + +.cfloat{ + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + } + +.btitle{ +white-space: normal; +word-wrap: break-word; + left: -1px; + top: -1px; + position: relative; + width: calc(100% + 2px); + text-align: center; + line-height: 30px; + font-weight: bold; + color: #ffffff; + background-image: url(/img/menu_4.jpg); + background-size: auto 100% ; + border-radius: 10px 10px 0 0; + } + +.ctitle{ + left: 0px; + top: -1px; + position: relative; + width: 100%; + height: 20px; + text-align: center; + line-height: 20px; + font-weight: bold; + } +.cctitle{ + left: 0px; + top: -1px; + margin-top: -4px; + position: relative; + width: 100%; + height: 0px; + line-height: 00px; + } +.youtubef{ + max-width:100%; + width:650px; + height:360px; + { + diff --git a/template/default1/page.php b/template/default1/page.php new file mode 100755 index 0000000..005fe3f --- /dev/null +++ b/template/default1/page.php @@ -0,0 +1,34 @@ +
+ +
+ %smap% +
+ +
+%left% +%right% +
+
+ %title% +
+
+
%content%
+
+
+
diff --git a/template/default2/css.php b/template/default2/css.php new file mode 100755 index 0000000..2ca7a16 --- /dev/null +++ b/template/default2/css.php @@ -0,0 +1,174 @@ + +#pbody { + min-height: 100%; + position: relative; + width: 95%; + margin: 0px auto; + background: #ffffff; + top:20px; + } + + +#head { + height: 100px; + left:-1px; + top:-1px; + width: 100%; + position: relative; + } + +#slogo{ + left: 5px; + float: left; + position: relative; + width: 80px; + height: 99px; + background-image: url(/img/Raspberry_Pi_Logo.svg); + background-repeat: no-repeat; + padding-right: 5px; + } + +#sname{ + width:200px; +/* max-width:10%;*/ + height: 37px; + overflow: hidden; + position: relative; + background-image: url(/img/rpi.svg); + background-repeat: no-repeat; + top: 40px; + } + +#sslogan{ + border: 1px solid #000000; + overflow: hidden; + text-align: left; + margin-top:10px; + } + +#hmemo{ + position: relative; + width: 150px; + height: 99px; + float: right; + background-image: url(/img/rpi.gif); + background-repeat: no-repeat; + background-size: auto 100px; + padding-right: 5px; + } + +#hmenu{ + top: -30px; + border: 1px solid #000000; + position: relative; + width: 600px; + margin: 0 auto; + margin-bottom:0px; + height: 30px; + } + +#smap{ +/* border: 1px solid #000000; + text-align: left;*/ + position: relative; + margin: 0 auto; + margin-top:5px; + width: 99%; + height: 20px; + } + +#smap a{ + text-decoration: none; + } + +#left-float, +#right-float, +.center-float { + padding: 5px; + } + +#left-float { + float: left; +} +#right-float { + float: right; +} +#left-float:empty, +#right-float:empty { + width: 0px; +} +#left-float:not(:empty), +#right-float:not(:empty) { + width: 200px; +} + +.center-float { + float: none; + width: auto; + overflow: hidden; + } + +.bfloat{ + overflow-x: hidden; + border: 1px solid #f44180; + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + border-radius: 0 0 10px 10px; + } + +.cfloat{ + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + } + +.btitle{ +white-space: normal; +word-wrap: break-word; + left: -1px; + top: -1px; + position: relative; + width: calc(100% + 2px); + text-align: center; + line-height: 30px; + font-weight: bold; + color: #ffffff; + background-image: url(/img/menu_5.jpg); + background-size: auto 30px ; + border-radius: 10px 10px 0 0; + } + +.ctitle{ + left: 0px; + top: -1px; + position: relative; + width: 100%; + height: 20px; + text-align: center; + line-height: 20px; + font-weight: bold; + } +.cctitle{ + left: 0px; + top: -1px; + margin-top: -4px; + position: relative; + width: 100%; + height: 0px; + line-height: 00px; + } +.youtubef{ + max-width:100%; + width:650px; + height:360px; + { + diff --git a/template/default2/page.php b/template/default2/page.php new file mode 100755 index 0000000..a6dc22d --- /dev/null +++ b/template/default2/page.php @@ -0,0 +1,34 @@ +
+ +
+ %smap% +
+ +
+%left% +%right% +
+
+ %title% +
+
+
%content%
+
+
+
diff --git a/template/default3/css.php b/template/default3/css.php new file mode 100755 index 0000000..e978372 --- /dev/null +++ b/template/default3/css.php @@ -0,0 +1,174 @@ + +#pbody { + min-height: 100%; + position: relative; + width: 95%; + margin: 0px auto; + background: #ffffff; + top:20px; + } + + +#head { + height: 100px; + left:-1px; + top:-1px; + width: 100%; + position: relative; + } + +#slogo{ + left: 5px; + float: left; + position: relative; + width: 80px; + height: 99px; + background-image: url(/img/Raspberry_Pi_Logo.svg); + background-repeat: no-repeat; + padding-right: 5px; + } + +#sname{ + width:200px; +/* max-width:10%;*/ + height: 37px; + overflow: hidden; + position: relative; + background-image: url(/img/rpi.svg); + background-repeat: no-repeat; + top: 40px; + } + +#sslogan{ + border: 1px solid #000000; + overflow: hidden; + text-align: left; + margin-top:10px; + } + +#hmemo{ + position: relative; + width: 150px; + height: 99px; + float: right; + background-image: url(/img/rpi.gif); + background-repeat: no-repeat; + background-size: auto 100px; + padding-right: 5px; + } + +#hmenu{ + top: -30px; + border: 1px solid #000000; + position: relative; + width: 600px; + margin: 0 auto; + margin-bottom:0px; + height: 30px; + } + +#smap{ +/* border: 1px solid #000000; + text-align: left;*/ + position: relative; + margin: 0 auto; + margin-top:5px; + width: 99%; + height: 20px; + } + +#smap a{ + text-decoration: none; + } + +#left-float, +#right-float, +.center-float { + padding: 5px; + } + +#left-float { + float: left; +} +#right-float { + float: right; +} +#left-float:empty, +#right-float:empty { + width: 0px; +} +#left-float:not(:empty), +#right-float:not(:empty) { + width: 200px; +} + +.center-float { + float: none; + width: auto; + overflow: hidden; + } + +.bfloat{ + overflow-x: hidden; + border: 1px solid #f44180; + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + border-radius: 0 0 10px 10px; + } + +.cfloat{ + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + } + +.btitle{ +white-space: normal; +word-wrap: break-word; + left: -1px; + top: -1px; + position: relative; + width: calc(100% + 2px); + text-align: center; + line-height: 30px; + font-weight: bold; + color: #ffffff; + background-image: url(/img/menu_1.jpg); + background-size: auto 100% ; + border-radius: 10px 10px 0 0; + } + +.ctitle{ + left: 0px; + top: -1px; + position: relative; + width: 100%; + height: 20px; + text-align: center; + line-height: 20px; + font-weight: bold; + } +.cctitle{ + left: 0px; + top: -1px; + margin-top: -4px; + position: relative; + width: 100%; + height: 0px; + line-height: 00px; + } +.youtubef{ + max-width:100%; + width:650px; + height:360px; + { + diff --git a/template/default3/page.php b/template/default3/page.php new file mode 100755 index 0000000..a6dc22d --- /dev/null +++ b/template/default3/page.php @@ -0,0 +1,34 @@ +
+ +
+ %smap% +
+ +
+%left% +%right% +
+
+ %title% +
+
+
%content%
+
+
+
diff --git a/template/default4/css.php b/template/default4/css.php new file mode 100755 index 0000000..88e89a5 --- /dev/null +++ b/template/default4/css.php @@ -0,0 +1,175 @@ + +#pbody { + min-height: 100%; + position: relative; + width: 95%; + margin: 0px auto; + background: #ffffff; + top:20px; + } + + +#head { + height: 100px; + left:-1px; + top:-1px; + width: 100%; + position: relative; + } + +#slogo{ + left: 5px; + float: left; + position: relative; + width: 80px; + height: 99px; + background-image: url(/img/Raspberry_Pi_Logo.svg); + background-repeat: no-repeat; + padding-right: 5px; + } + +#sname{ + width:200px; +/* max-width:10%;*/ + height: 37px; + overflow: hidden; + position: relative; + background-image: url(/img/rpi.svg); + background-repeat: no-repeat; + top: 40px; + } + +#sslogan{ + border: 1px solid #000000; + overflow: hidden; + text-align: left; + margin-top:10px; + } + +#hmemo{ + position: relative; + width: 150px; + height: 99px; + float: right; + background-image: url(/img/rpi.gif); + background-repeat: no-repeat; + background-size: auto 100px; + padding-right: 5px; + } + +#hmenu{ + top: -30px; + border: 1px solid #000000; + position: relative; + width: 600px; + margin: 0 auto; + margin-bottom:0px; + height: 30px; + } + +#smap{ +/* border: 1px solid #000000; + text-align: left;*/ + position: relative; + margin: 0 auto; + margin-top:5px; + width: 99%; + height: 20px; + } + +#smap a{ + text-decoration: none; + } + +#left-float, +#right-float, +.center-float { + padding: 5px; + } + +#left-float { + float: left; +} +#right-float { + float: right; +} +#left-float:empty, +#right-float:empty { + width: 0px; +} +#left-float:not(:empty), +#right-float:not(:empty) { + width: 200px; +} + +.center-float { + float: none; + width: auto; + overflow: hidden; + } + +.bfloat{ + overflow-x: hidden; + border: 1px solid #f44180; + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + border-radius: 0 0 10px 10px; + padding: 5px; + } + +.cfloat{ + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + } + +.btitle{ +white-space: normal; +word-wrap: break-word; + left: -1px; + top: -1px; + position: relative; + width: calc(100% + 2px); + text-align: center; + line-height: 30px; + font-weight: bold; + color: #ffffff; + background-image: url(/img/menu_5.jpg); + background-size: auto 100% ; + border-radius: 10px 10px 0 0; + } + +.ctitle{ + left: 0px; + top: -1px; + position: relative; + width: 100%; + height: 20px; + text-align: center; + line-height: 20px; + font-weight: bold; + } +.cctitle{ + left: 0px; + top: -1px; + margin-top: -4px; + position: relative; + width: 100%; + height: 0px; + line-height: 00px; + } +.youtubef{ + max-width:100%; + width:650px; + height:360px; + { + diff --git a/template/default4/page.php b/template/default4/page.php new file mode 100755 index 0000000..2e8686a --- /dev/null +++ b/template/default4/page.php @@ -0,0 +1,34 @@ +
+ +
+ %smap% +
+ +
+%left% +%right% +
+
+ %title% +
+
+
%content%
+
+
+
diff --git a/template/error.php b/template/error.php new file mode 100755 index 0000000..d0e5029 --- /dev/null +++ b/template/error.php @@ -0,0 +1,29 @@ + + + + +%sitename% + + + + +
+ +
+ %LngMenu% +
+
+ %TopMenu% +
+
+
+
+
+ %title% +
+
+
%content%
+
+
diff --git a/template/kip/css.php b/template/kip/css.php new file mode 100755 index 0000000..01334cc --- /dev/null +++ b/template/kip/css.php @@ -0,0 +1,298 @@ + +body, html{ + margin: 0px; + padding: 0px; + text-align: center; + background: #f4f4f4; +} +/* Главные контейнеры */ +#hbody { + position: fixed; + height: 30px; + width: 100%; + background: rgb(237,232,237); + background-image: linear-gradient(bottom, rgb(194,194,194) 15%, rgb(237,232,237) 57%); + background-image: -o-linear-gradient(bottom, rgb(194,194,194) 15%, rgb(237,232,237) 57%); + background-image: -moz-linear-gradient(bottom, rgb(194,194,194) 15%, rgb(237,232,237) 57%); + background-image: -webkit-linear-gradient(bottom, rgb(194,194,194) 15%, rgb(237,232,237) 57%); + background-image: -ms-linear-gradient(bottom, rgb(194,194,194) 15%, rgb(237,232,237) 57%); + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.15, rgb(194,194,194)), color-stop(0.57, rgb(237,232,237))); + color: #666; +/* text-shadow: -1px -1px #666, 1px 1px #FFF;*/ + text-shadow: 1px 1px 3px #666, -1px -1px 3px #FFF, 1px 1px #666, -1px -1px #FFF; + font-family: serif; + font-size:20px; + top:0px; + z-index:10; + } + +#shome{ + position: relative; + top: 0px; + float: left; + left: 0px; + width:100px; + } + + +#smenu{ + position: relative; + margin: 0px auto; + width:400px; + } + +#slng{ + text-transform: uppercase; + position: relative; + float: right; + width:100px; + } + +/*#slng {position:relative;z-index:100;}*/ + +#slng ul li a,#slng ul li a:visited {display:block;text-decoration:none;text-align:center;line-height:20px;overflow:hidden;} + +#slng ul {padding:0;margin:0;list-style: none;} + +#slng ul li {float:left;position:relative;width:100px;} + +#slng ul li ul {display: none; background: rgb(237,232,237);} + +/* specific to non IE browsers */ +#slng ul li:hover a { } + +#slng ul li:hover ul {display:block;position:absolute;top:21px;left:0;width:50px;} + +#slng ul li:hover ul li a.hide { } + +#slng ul li:hover ul li:hover a.hide { } + +#slng ul li:hover ul li ul {display: none;} + +#slng ul li:hover ul li a {display:block;} + +#slng ul li:hover ul li a:hover { } + +#slng ul li:hover ul li:hover ul {display:block;position:absolute;left:50px;top:0;} + +#slng ul li:hover ul li:hover ul.left {left:-105px;} + +#f button{ +/**/ color:#666; + background:none; + cursor:pointer; + border:0; + text-shadow: 1px 1px 3px #666, -1px -1px 3px #FFF, 1px 1px #666, -1px -1px #FFF; + font-family: serif; + font-size:20px; + } + +#f, #f button{ + display:inline; + margin:0; + padding:0; + } + + + +#f button:hover{ + color: rgb(153,153,153); + text-shadow: -1px -1px #666, 1px 1px #FFF; + } + + + +#hbody a{ + color: #666; + text-shadow: 1px 1px 3px #666, -1px -1px 3px #FFF, 1px 1px #666, -1px -1px #FFF; + text-decoration: none;/**/ + } + +#hbody a:hover{ + color: rgb(153,153,153); + text-shadow: -1px -1px #666, 1px 1px #FFF; + } + +#pbody { + min-height: 100%; + position: relative; + width: 95%; + margin: 0px auto; + background: #ffffff; + top:50px; + } + + +#head { + height: 100px; + left:-1px; + top:-1px; + width: 100%; + position: relative; + } + +#slogo{ + left: 5px; + float: left; + position: relative; + width: 80px; + height: 99px; + background-image: url(/img/Raspberry_Pi_Logo.svg); + background-repeat: no-repeat; + padding-right: 5px; + } + +#sname{ + width:200px; +/* max-width:10%;*/ + height: 37px; + overflow: hidden; + position: relative; + background-image: url(/img/rpi.svg); + background-repeat: no-repeat; + top: 40px; + } + +#sslogan{ + border: 1px solid #000000; + overflow: hidden; + text-align: left; + margin-top:10px; + } + +#hmemo{ + position: relative; + width: 150px; + height: 99px; + float: right; + background-image: url(/img/rpi.gif); + background-repeat: no-repeat; + background-size: auto 100px; + padding-right: 5px; + } + +#hmenu{ + top: -30px; + border: 1px solid #000000; + position: relative; + width: 600px; + margin: 0 auto; + margin-bottom:0px; + height: 30px; + } + +#smap{ +/* border: 1px solid #000000; + text-align: left;*/ + position: relative; + margin: 0 auto; + margin-top:5px; + width: 99%; + height: 20px; + } + +#smap a{ + text-decoration: none; + } + +#fclear{ + clear:both; +} +#footer { + height: 100px; + position: relative; + left: -1px; + bottom: -1px; + width: 100%; + border: 1px solid #0ffff0; + } + +#left-float, +#right-float, +.center-float { + padding: 5px; + } + +#left-float { + float: left; +} +#right-float { + float: right; +} +#left-float:empty, +#right-float:empty { + width: 0px; +} +#left-float:not(:empty), +#right-float:not(:empty) { + width: 200px; +} + +.center-float { + float: none; + width: auto; + overflow: hidden; + } + +.bfloat{ + overflow-x: hidden; + border: 1px solid #f44180; + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + border-radius: 0 0 10px 10px; + } + +.cfloat{ + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + } + +.btitle{ +white-space: normal; +word-wrap: break-word; + left: -1px; + top: -1px; + position: relative; + width: calc(100% + 2px); + text-align: center; + line-height: 30px; + font-weight: bold; + color: #ffffff; + background-image: url(/img/menu_7.jpg); + background-size: auto 100% ; + border-radius: 10px 10px 0 0; + } + +.ctitle{ + left: 0px; + top: -1px; + position: relative; + width: 100%; + height: 20px; + text-align: center; + line-height: 20px; + font-weight: bold; + } +.cctitle{ + left: 0px; + top: -1px; + margin-top: -4px; + position: relative; + width: 100%; + height: 0px; + line-height: 00px; + } +.youtubef{ + max-width:100%; + width:650px; + height:360px; + { + diff --git a/template/kip/page.php b/template/kip/page.php new file mode 100755 index 0000000..e3978c6 --- /dev/null +++ b/template/kip/page.php @@ -0,0 +1,62 @@ + + + + +%sitename% + + + + + +
+ +
+ %smap% +
+ +
+%left% +%right% +
+
+ %title% +
+
+
%content%
+
+
+
+ +
+ + diff --git a/template/rpi/bootstrap-responsive.min.css b/template/rpi/bootstrap-responsive.min.css new file mode 100755 index 0000000..5cb833f --- /dev/null +++ b/template/rpi/bootstrap-responsive.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap Responsive v2.2.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */@-ms-viewport{width:device-width}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} diff --git a/template/rpi/bootstrap.min.css b/template/rpi/bootstrap.min.css new file mode 100755 index 0000000..81bb833 --- /dev/null +++ b/template/rpi/bootstrap.min.css @@ -0,0 +1,873 @@ +/*! + * Bootstrap v2.3.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0;} +.clearfix:after{clear:both;} +.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;} +.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} +article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;} +audio,canvas,video{display:inline-block;*display:inline;*zoom:1;} +audio:not([controls]){display:none;} +html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;} +a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +a:hover,a:active{outline:0;} +sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;} +sup{top:-0.5em;} +sub{bottom:-0.25em;} +img{max-width:100%;width:auto\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic;} +#map_canvas img,.google-maps img{max-width:none;} +button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;} +button,input{*overflow:visible;line-height:normal;} +button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;} +button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;} +label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer;} +input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield;} +input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;} +textarea{overflow:auto;vertical-align:top;} +@media print{*{text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important;} a,a:visited{text-decoration:underline;} a[href]:after{content:" (" attr(href) ")";} abbr[title]:after{content:" (" attr(title) ")";} .ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:"";} pre,blockquote{border:1px solid #999;page-break-inside:avoid;} thead{display:table-header-group;} tr,img{page-break-inside:avoid;} img{max-width:100% !important;} @page {margin:0.5cm;}p,h2,h3{orphans:3;widows:3;} h2,h3{page-break-after:avoid;}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333333;background-color:#ffffff;} +a{color:#0088cc;text-decoration:none;} +a:hover,a:focus{color:#005580;text-decoration:underline;} +.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);} +.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px;} +.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} +.row:after{clear:both;} +[class*="span"]{float:left;min-height:1px;margin-left:20px;} +.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;} +.span12{width:940px;} +.span11{width:860px;} +.span10{width:780px;} +.span9{width:700px;} +.span8{width:620px;} +.span7{width:540px;} +.span6{width:460px;} +.span5{width:380px;} +.span4{width:300px;} +.span3{width:220px;} +.span2{width:140px;} +.span1{width:60px;} +.offset12{margin-left:980px;} +.offset11{margin-left:900px;} +.offset10{margin-left:820px;} +.offset9{margin-left:740px;} +.offset8{margin-left:660px;} +.offset7{margin-left:580px;} +.offset6{margin-left:500px;} +.offset5{margin-left:420px;} +.offset4{margin-left:340px;} +.offset3{margin-left:260px;} +.offset2{margin-left:180px;} +.offset1{margin-left:100px;} +.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} +.row-fluid:after{clear:both;} +.row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;} +.row-fluid [class*="span"]:first-child{margin-left:0;} +.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%;} +.row-fluid .span12{width:100%;*width:99.94680851063829%;} +.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%;} +.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%;} +.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%;} +.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%;} +.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%;} +.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%;} +.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%;} +.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%;} +.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%;} +.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%;} +.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%;} +.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%;} +.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%;} +.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%;} +.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%;} +.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%;} +.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%;} +.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%;} +.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%;} +.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%;} +.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%;} +.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%;} +.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%;} +.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%;} +.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%;} +.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%;} +.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%;} +.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%;} +.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%;} +.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%;} +.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%;} +.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%;} +.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%;} +.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%;} +.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%;} +[class*="span"].hide,.row-fluid [class*="span"].hide{display:none;} +[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right;} +.container{margin-right:auto;margin-left:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";line-height:0;} +.container:after{clear:both;} +.container-fluid{padding-right:20px;padding-left:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";line-height:0;} +.container-fluid:after{clear:both;} +p{margin:0 0 10px;} +.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px;} +small{font-size:85%;} +strong{font-weight:bold;} +em{font-style:italic;} +cite{font-style:normal;} +.muted{color:#999999;} +a.muted:hover,a.muted:focus{color:#808080;} +.text-warning{color:#c09853;} +a.text-warning:hover,a.text-warning:focus{color:#a47e3c;} +.text-error{color:#b94a48;} +a.text-error:hover,a.text-error:focus{color:#953b39;} +.text-info{color:#3a87ad;} +a.text-info:hover,a.text-info:focus{color:#2d6987;} +.text-success{color:#468847;} +a.text-success:hover,a.text-success:focus{color:#356635;} +.text-left{text-align:left;} +.text-right{text-align:right;} +.text-center{text-align:center;} +h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999999;} +h1,h2,h3{line-height:40px;} +h1{font-size:38.5px;} +h2{font-size:31.5px;} +h3{font-size:24.5px;} +h4{font-size:17.5px;} +h5{font-size:14px;} +h6{font-size:11.9px;} +h1 small{font-size:24.5px;} +h2 small{font-size:17.5px;} +h3 small{font-size:14px;} +h4 small{font-size:14px;} +.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eeeeee;} +ul,ol{padding:0;margin:0 0 10px 25px;} +ul ul,ul ol,ol ol,ol ul{margin-bottom:0;} +li{line-height:20px;} +ul.unstyled,ol.unstyled{margin-left:0;list-style:none;} +ul.inline,ol.inline{margin-left:0;list-style:none;}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;*zoom:1;padding-left:5px;padding-right:5px;} +dl{margin-bottom:20px;} +dt,dd{line-height:20px;} +dt{font-weight:bold;} +dd{margin-left:10px;} +.dl-horizontal{*zoom:1;}.dl-horizontal:before,.dl-horizontal:after{display:table;content:"";line-height:0;} +.dl-horizontal:after{clear:both;} +.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;} +.dl-horizontal dd{margin-left:180px;} +hr{margin:20px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;} +abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999999;} +abbr.initialism{font-size:90%;text-transform:uppercase;} +blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25;} +blockquote small{display:block;line-height:20px;color:#999999;}blockquote small:before{content:'\2014 \00A0';} +blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;} +blockquote.pull-right small:before{content:'';} +blockquote.pull-right small:after{content:'\00A0 \2014';} +q:before,q:after,blockquote:before,blockquote:after{content:"";} +address{display:block;margin-bottom:20px;font-style:normal;line-height:20px;} +code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;white-space:nowrap;} +pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}pre.prettyprint{margin-bottom:20px;} +pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0;} +.pre-scrollable{max-height:340px;overflow-y:scroll;} +.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#ffffff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;} +.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.badge{padding-left:9px;padding-right:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;} +.label:empty,.badge:empty{display:none;} +a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#ffffff;text-decoration:none;cursor:pointer;} +.label-important,.badge-important{background-color:#b94a48;} +.label-important[href],.badge-important[href]{background-color:#953b39;} +.label-warning,.badge-warning{background-color:#f89406;} +.label-warning[href],.badge-warning[href]{background-color:#c67605;} +.label-success,.badge-success{background-color:#468847;} +.label-success[href],.badge-success[href]{background-color:#356635;} +.label-info,.badge-info{background-color:#3a87ad;} +.label-info[href],.badge-info[href]{background-color:#2d6987;} +.label-inverse,.badge-inverse{background-color:#333333;} +.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a;} +.btn .label,.btn .badge{position:relative;top:-1px;} +.btn-mini .label,.btn-mini .badge{top:0;} +table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0;} +.table{width:100%;margin-bottom:20px;}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #dddddd;} +.table th{font-weight:bold;} +.table thead th{vertical-align:bottom;} +.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0;} +.table tbody+tbody{border-top:2px solid #dddddd;} +.table .table{background-color:#ffffff;} +.table-condensed th,.table-condensed td{padding:4px 5px;} +.table-bordered{border:1px solid #dddddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;} +.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;} +.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;} +.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;} +.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} +.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} +.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;-moz-border-radius-bottomleft:0;border-bottom-left-radius:0;} +.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;-moz-border-radius-bottomright:0;border-bottom-right-radius:0;} +.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;} +.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;} +.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9;} +.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5;} +table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0;} +.table td.span1,.table th.span1{float:none;width:44px;margin-left:0;} +.table td.span2,.table th.span2{float:none;width:124px;margin-left:0;} +.table td.span3,.table th.span3{float:none;width:204px;margin-left:0;} +.table td.span4,.table th.span4{float:none;width:284px;margin-left:0;} +.table td.span5,.table th.span5{float:none;width:364px;margin-left:0;} +.table td.span6,.table th.span6{float:none;width:444px;margin-left:0;} +.table td.span7,.table th.span7{float:none;width:524px;margin-left:0;} +.table td.span8,.table th.span8{float:none;width:604px;margin-left:0;} +.table td.span9,.table th.span9{float:none;width:684px;margin-left:0;} +.table td.span10,.table th.span10{float:none;width:764px;margin-left:0;} +.table td.span11,.table th.span11{float:none;width:844px;margin-left:0;} +.table td.span12,.table th.span12{float:none;width:924px;margin-left:0;} +.table tbody tr.success>td{background-color:#dff0d8;} +.table tbody tr.error>td{background-color:#f2dede;} +.table tbody tr.warning>td{background-color:#fcf8e3;} +.table tbody tr.info>td{background-color:#d9edf7;} +.table-hover tbody tr.success:hover>td{background-color:#d0e9c6;} +.table-hover tbody tr.error:hover>td{background-color:#ebcccc;} +.table-hover tbody tr.warning:hover>td{background-color:#faf2cc;} +.table-hover tbody tr.info:hover>td{background-color:#c4e3f3;} +form{margin:0 0 20px;} +fieldset{padding:0;margin:0;border:0;} +legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333333;border:0;border-bottom:1px solid #e5e5e5;}legend small{font-size:15px;color:#999999;} +label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px;} +input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;} +label{display:block;margin-bottom:5px;} +select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555555;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;vertical-align:middle;} +input,textarea,.uneditable-input{width:206px;} +textarea{height:auto;} +textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#ffffff;border:1px solid #cccccc;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear .2s, box-shadow linear .2s;-moz-transition:border linear .2s, box-shadow linear .2s;-o-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s;}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82, 168, 236, 0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);} +input[type="radio"],input[type="checkbox"]{margin:4px 0 0;*margin-top:0;margin-top:1px \9;line-height:normal;} +input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto;} +select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px;} +select{width:220px;border:1px solid #cccccc;background-color:#ffffff;} +select[multiple],select[size]{height:auto;} +select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +.uneditable-input,.uneditable-textarea{color:#999999;background-color:#fcfcfc;border-color:#cccccc;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;} +.uneditable-input{overflow:hidden;white-space:nowrap;} +.uneditable-textarea{width:auto;height:auto;} +input:-moz-placeholder,textarea:-moz-placeholder{color:#999999;} +input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999999;} +input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999999;} +.radio,.checkbox{min-height:20px;padding-left:20px;} +.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px;} +.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;} +.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;} +.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;} +.input-mini{width:60px;} +.input-small{width:90px;} +.input-medium{width:150px;} +.input-large{width:210px;} +.input-xlarge{width:270px;} +.input-xxlarge{width:530px;} +input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0;} +.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block;} +input,textarea,.uneditable-input{margin-left:0;} +.controls-row [class*="span"]+[class*="span"]{margin-left:20px;} +input.span12,textarea.span12,.uneditable-input.span12{width:926px;} +input.span11,textarea.span11,.uneditable-input.span11{width:846px;} +input.span10,textarea.span10,.uneditable-input.span10{width:766px;} +input.span9,textarea.span9,.uneditable-input.span9{width:686px;} +input.span8,textarea.span8,.uneditable-input.span8{width:606px;} +input.span7,textarea.span7,.uneditable-input.span7{width:526px;} +input.span6,textarea.span6,.uneditable-input.span6{width:446px;} +input.span5,textarea.span5,.uneditable-input.span5{width:366px;} +input.span4,textarea.span4,.uneditable-input.span4{width:286px;} +input.span3,textarea.span3,.uneditable-input.span3{width:206px;} +input.span2,textarea.span2,.uneditable-input.span2{width:126px;} +input.span1,textarea.span1,.uneditable-input.span1{width:46px;} +.controls-row{*zoom:1;}.controls-row:before,.controls-row:after{display:table;content:"";line-height:0;} +.controls-row:after{clear:both;} +.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left;} +.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px;} +input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eeeeee;} +input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent;} +.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;} +.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;} +.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;} +.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;} +.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;} +.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;} +.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;} +.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;} +.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;} +.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;} +.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;} +.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;} +.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad;} +.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad;} +.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;} +.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad;} +input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;} +.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1;}.form-actions:before,.form-actions:after{display:table;content:"";line-height:0;} +.form-actions:after{clear:both;} +.help-block,.help-inline{color:#595959;} +.help-block{display:block;margin-bottom:10px;} +.help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;} +.input-append,.input-prepend{display:inline-block;margin-bottom:10px;vertical-align:middle;font-size:0;white-space:nowrap;}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px;} +.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2;} +.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #ffffff;background-color:#eeeeee;border:1px solid #ccc;} +.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546;} +.input-prepend .add-on,.input-prepend .btn{margin-right:-1px;} +.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} +.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px;} +.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} +.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.input-prepend.input-append .btn-group:first-child{margin-left:0;} +input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} +.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;} +.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;} +.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;} +.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;} +.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;vertical-align:middle;} +.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;} +.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block;} +.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;} +.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;} +.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0;} +.control-group{margin-bottom:10px;} +legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate;} +.form-horizontal .control-group{margin-bottom:20px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";line-height:0;} +.form-horizontal .control-group:after{clear:both;} +.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right;} +.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0;}.form-horizontal .controls:first-child{*padding-left:180px;} +.form-horizontal .help-block{margin-bottom:0;} +.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px;} +.form-horizontal .form-actions{padding-left:180px;} +.btn{display:inline-block;*display:inline;*zoom:1;padding:4px 12px;margin-bottom:0;font-size:14px;line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333333;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(to bottom, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #cccccc;*border:0;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333333;background-color:#e6e6e6;*background-color:#d9d9d9;} +.btn:active,.btn.active{background-color:#cccccc \9;} +.btn:first-child{*margin-left:0;} +.btn:hover,.btn:focus{color:#333333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} +.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);} +.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px;} +.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0;} +.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px;} +.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.btn-block{display:block;width:100%;padding-left:0;padding-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} +.btn-block+.btn-block{margin-top:5px;} +input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%;} +.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255, 255, 255, 0.75);} +.btn-primary{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(to bottom, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#0044cc;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#ffffff;background-color:#0044cc;*background-color:#003bb3;} +.btn-primary:active,.btn-primary.active{background-color:#003399 \9;} +.btn-warning{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#ffffff;background-color:#f89406;*background-color:#df8505;} +.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;} +.btn-danger{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#ffffff;background-color:#bd362f;*background-color:#a9302a;} +.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;} +.btn-success{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(to bottom, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#ffffff;background-color:#51a351;*background-color:#499249;} +.btn-success:active,.btn-success.active{background-color:#408140 \9;} +.btn-info{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(to bottom, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#ffffff;background-color:#2f96b4;*background-color:#2a85a0;} +.btn-info:active,.btn-info.active{background-color:#24748c \9;} +.btn-inverse{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444444, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));background-image:-webkit-linear-gradient(top, #444444, #222222);background-image:-o-linear-gradient(top, #444444, #222222);background-image:linear-gradient(to bottom, #444444, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#222222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#ffffff;background-color:#222222;*background-color:#151515;} +.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;} +button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;} +button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;} +button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;} +button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;} +.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +.btn-link{border-color:transparent;cursor:pointer;color:#0088cc;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent;} +.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333333;text-decoration:none;} +[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../../img/glyphicons-halflings.png");background-position:0px 0px;background-repeat:no-repeat;margin-top:1px;} +.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png");} +.icon-glass{background-position:0 0;} +.icon-music{background-position:-24px 0;} +.icon-search{background-position:-48px 0;} +.icon-envelope{background-position:-72px 0;} +.icon-heart{background-position:-96px 0;} +.icon-star{background-position:-120px 0;} +.icon-star-empty{background-position:-144px 0;} +.icon-user{background-position:-168px 0;} +.icon-film{background-position:-192px 0;} +.icon-th-large{background-position:-216px 0;} +.icon-th{background-position:-240px 0;} +.icon-th-list{background-position:-264px 0;} +.icon-ok{background-position:-288px 0;} +.icon-remove{background-position:-312px 0;} +.icon-zoom-in{background-position:-336px 0;} +.icon-zoom-out{background-position:-360px 0;} +.icon-off{background-position:-384px 0;} +.icon-signal{background-position:-408px 0;} +.icon-cog{background-position:-432px 0;} +.icon-trash{background-position:-456px 0;} +.icon-home{background-position:0 -24px;} +.icon-file{background-position:-24px -24px;} +.icon-time{background-position:-48px -24px;} +.icon-road{background-position:-72px -24px;} +.icon-download-alt{background-position:-96px -24px;} +.icon-download{background-position:-120px -24px;} +.icon-upload{background-position:-144px -24px;} +.icon-inbox{background-position:-168px -24px;} +.icon-play-circle{background-position:-192px -24px;} +.icon-repeat{background-position:-216px -24px;} +.icon-refresh{background-position:-240px -24px;} +.icon-list-alt{background-position:-264px -24px;} +.icon-lock{background-position:-287px -24px;} +.icon-flag{background-position:-312px -24px;} +.icon-headphones{background-position:-336px -24px;} +.icon-volume-off{background-position:-360px -24px;} +.icon-volume-down{background-position:-384px -24px;} +.icon-volume-up{background-position:-408px -24px;} +.icon-qrcode{background-position:-432px -24px;} +.icon-barcode{background-position:-456px -24px;} +.icon-tag{background-position:0 -48px;} +.icon-tags{background-position:-25px -48px;} +.icon-book{background-position:-48px -48px;} +.icon-bookmark{background-position:-72px -48px;} +.icon-print{background-position:-96px -48px;} +.icon-camera{background-position:-120px -48px;} +.icon-font{background-position:-144px -48px;} +.icon-bold{background-position:-167px -48px;} +.icon-italic{background-position:-192px -48px;} +.icon-text-height{background-position:-216px -48px;} +.icon-text-width{background-position:-240px -48px;} +.icon-align-left{background-position:-264px -48px;} +.icon-align-center{background-position:-288px -48px;} +.icon-align-right{background-position:-312px -48px;} +.icon-align-justify{background-position:-336px -48px;} +.icon-list{background-position:-360px -48px;} +.icon-indent-left{background-position:-384px -48px;} +.icon-indent-right{background-position:-408px -48px;} +.icon-facetime-video{background-position:-432px -48px;} +.icon-picture{background-position:-456px -48px;} +.icon-pencil{background-position:0 -72px;} +.icon-map-marker{background-position:-24px -72px;} +.icon-adjust{background-position:-48px -72px;} +.icon-tint{background-position:-72px -72px;} +.icon-edit{background-position:-96px -72px;} +.icon-share{background-position:-120px -72px;} +.icon-check{background-position:-144px -72px;} +.icon-move{background-position:-168px -72px;} +.icon-step-backward{background-position:-192px -72px;} +.icon-fast-backward{background-position:-216px -72px;} +.icon-backward{background-position:-240px -72px;} +.icon-play{background-position:-264px -72px;} +.icon-pause{background-position:-288px -72px;} +.icon-stop{background-position:-312px -72px;} +.icon-forward{background-position:-336px -72px;} +.icon-fast-forward{background-position:-360px -72px;} +.icon-step-forward{background-position:-384px -72px;} +.icon-eject{background-position:-408px -72px;} +.icon-chevron-left{background-position:-432px -72px;} +.icon-chevron-right{background-position:-456px -72px;} +.icon-plus-sign{background-position:0 -96px;} +.icon-minus-sign{background-position:-24px -96px;} +.icon-remove-sign{background-position:-48px -96px;} +.icon-ok-sign{background-position:-72px -96px;} +.icon-question-sign{background-position:-96px -96px;} +.icon-info-sign{background-position:-120px -96px;} +.icon-screenshot{background-position:-144px -96px;} +.icon-remove-circle{background-position:-168px -96px;} +.icon-ok-circle{background-position:-192px -96px;} +.icon-ban-circle{background-position:-216px -96px;} +.icon-arrow-left{background-position:-240px -96px;} +.icon-arrow-right{background-position:-264px -96px;} +.icon-arrow-up{background-position:-289px -96px;} +.icon-arrow-down{background-position:-312px -96px;} +.icon-share-alt{background-position:-336px -96px;} +.icon-resize-full{background-position:-360px -96px;} +.icon-resize-small{background-position:-384px -96px;} +.icon-plus{background-position:-408px -96px;} +.icon-minus{background-position:-433px -96px;} +.icon-asterisk{background-position:-456px -96px;} +.icon-exclamation-sign{background-position:0 -120px;} +.icon-gift{background-position:-24px -120px;} +.icon-leaf{background-position:-48px -120px;} +.icon-fire{background-position:-72px -120px;} +.icon-eye-open{background-position:-96px -120px;} +.icon-eye-close{background-position:-120px -120px;} +.icon-warning-sign{background-position:-144px -120px;} +.icon-plane{background-position:-168px -120px;} +.icon-calendar{background-position:-192px -120px;} +.icon-random{background-position:-216px -120px;width:16px;} +.icon-comment{background-position:-240px -120px;} +.icon-magnet{background-position:-264px -120px;} +.icon-chevron-up{background-position:-288px -120px;} +.icon-chevron-down{background-position:-313px -119px;} +.icon-retweet{background-position:-336px -120px;} +.icon-shopping-cart{background-position:-360px -120px;} +.icon-folder-close{background-position:-384px -120px;width:16px;} +.icon-folder-open{background-position:-408px -120px;width:16px;} +.icon-resize-vertical{background-position:-432px -119px;} +.icon-resize-horizontal{background-position:-456px -118px;} +.icon-hdd{background-position:0 -144px;} +.icon-bullhorn{background-position:-24px -144px;} +.icon-bell{background-position:-48px -144px;} +.icon-certificate{background-position:-72px -144px;} +.icon-thumbs-up{background-position:-96px -144px;} +.icon-thumbs-down{background-position:-120px -144px;} +.icon-hand-right{background-position:-144px -144px;} +.icon-hand-left{background-position:-168px -144px;} +.icon-hand-up{background-position:-192px -144px;} +.icon-hand-down{background-position:-216px -144px;} +.icon-circle-arrow-right{background-position:-240px -144px;} +.icon-circle-arrow-left{background-position:-264px -144px;} +.icon-circle-arrow-up{background-position:-288px -144px;} +.icon-circle-arrow-down{background-position:-312px -144px;} +.icon-globe{background-position:-336px -144px;} +.icon-wrench{background-position:-360px -144px;} +.icon-tasks{background-position:-384px -144px;} +.icon-filter{background-position:-408px -144px;} +.icon-briefcase{background-position:-432px -144px;} +.icon-fullscreen{background-position:-456px -144px;} +.btn-group{position:relative;display:inline-block;*display:inline;*zoom:1;font-size:0;vertical-align:middle;white-space:nowrap;*margin-left:.3em;}.btn-group:first-child{*margin-left:0;} +.btn-group+.btn-group{margin-left:5px;} +.btn-toolbar{font-size:0;margin-top:10px;margin-bottom:10px;}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px;} +.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.btn-group>.btn+.btn{margin-left:-1px;} +.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px;} +.btn-group>.btn-mini{font-size:10.5px;} +.btn-group>.btn-small{font-size:11.9px;} +.btn-group>.btn-large{font-size:17.5px;} +.btn-group>.btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} +.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} +.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;} +.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;} +.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2;} +.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;} +.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);*padding-top:5px;*padding-bottom:5px;} +.btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px;} +.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px;} +.btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px;} +.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);} +.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6;} +.btn-group.open .btn-primary.dropdown-toggle{background-color:#0044cc;} +.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406;} +.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f;} +.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351;} +.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4;} +.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222222;} +.btn .caret{margin-top:8px;margin-left:0;} +.btn-large .caret{margin-top:6px;} +.btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px;} +.btn-mini .caret,.btn-small .caret{margin-top:8px;} +.dropup .btn-large .caret{border-bottom-width:5px;} +.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;} +.btn-group-vertical{display:inline-block;*display:inline;*zoom:1;} +.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.btn-group-vertical>.btn+.btn{margin-left:0;margin-top:-1px;} +.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;} +.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;} +.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0;} +.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;} +.nav{margin-left:0;margin-bottom:20px;list-style:none;} +.nav>li>a{display:block;} +.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eeeeee;} +.nav>li>a>img{max-width:none;} +.nav>.pull-right{float:right;} +.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;} +.nav li+.nav-header{margin-top:9px;} +.nav-list{padding-left:15px;padding-right:15px;margin-bottom:0;} +.nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);} +.nav-list>li>a{padding:3px 15px;} +.nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;} +.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px;} +.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;} +.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";line-height:0;} +.nav-tabs:after,.nav-pills:after{clear:both;} +.nav-tabs>li,.nav-pills>li{float:left;} +.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;} +.nav-tabs{border-bottom:1px solid #ddd;} +.nav-tabs>li{margin-bottom:-1px;} +.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eeeeee #eeeeee #dddddd;} +.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;} +.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} +.nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#ffffff;background-color:#0088cc;} +.nav-stacked>li{float:none;} +.nav-stacked>li>a{margin-right:0;} +.nav-tabs.nav-stacked{border-bottom:0;} +.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;} +.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} +.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{border-color:#ddd;z-index:2;} +.nav-pills.nav-stacked>li>a{margin-bottom:3px;} +.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;} +.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;} +.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.nav .dropdown-toggle .caret{border-top-color:#0088cc;border-bottom-color:#0088cc;margin-top:6px;} +.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580;} +.nav-tabs .dropdown-toggle .caret{margin-top:8px;} +.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff;} +.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555555;border-bottom-color:#555555;} +.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer;} +.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#ffffff;background-color:#999999;border-color:#999999;} +.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100);} +.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999999;} +.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";line-height:0;} +.tabbable:after{clear:both;} +.tab-content{overflow:auto;} +.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0;} +.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;} +.tab-content>.active,.pill-content>.active{display:block;} +.tabs-below>.nav-tabs{border-top:1px solid #ddd;} +.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0;} +.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-bottom-color:transparent;border-top-color:#ddd;} +.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd;} +.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none;} +.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;} +.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;} +.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} +.tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eeeeee #dddddd #eeeeee #eeeeee;} +.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;} +.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;} +.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eeeeee #eeeeee #eeeeee #dddddd;} +.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;} +.nav>.disabled>a{color:#999999;} +.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;background-color:transparent;cursor:default;} +.navbar{overflow:visible;margin-bottom:20px;*position:relative;*z-index:2;} +.navbar-inner{min-height:40px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top, #ffffff, #f2f2f2);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2));background-image:-webkit-linear-gradient(top, #ffffff, #f2f2f2);background-image:-o-linear-gradient(top, #ffffff, #f2f2f2);background-image:linear-gradient(to bottom, #ffffff, #f2f2f2);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);-moz-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);*zoom:1;}.navbar-inner:before,.navbar-inner:after{display:table;content:"";line-height:0;} +.navbar-inner:after{clear:both;} +.navbar .container{width:auto;} +.nav-collapse.collapse{height:auto;overflow:visible;} +.navbar .brand{float:left;display:block;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777777;text-shadow:0 1px 0 #ffffff;}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none;} +.navbar-text{margin-bottom:0;line-height:40px;color:#777777;} +.navbar-link{color:#777777;}.navbar-link:hover,.navbar-link:focus{color:#333333;} +.navbar .divider-vertical{height:40px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #ffffff;} +.navbar .btn,.navbar .btn-group{margin-top:5px;} +.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0;} +.navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";line-height:0;} +.navbar-form:after{clear:both;} +.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;} +.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0;} +.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;} +.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap;}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0;} +.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0;}.navbar-search .search-query{margin-bottom:0;padding:4px 14px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} +.navbar-static-top{position:static;margin-bottom:0;}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0;} +.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px;} +.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0;} +.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;} +.navbar-fixed-top{top:0;} +.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,.1);box-shadow:0 1px 10px rgba(0,0,0,.1);} +.navbar-fixed-bottom{bottom:0;}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,.1);box-shadow:0 -1px 10px rgba(0,0,0,.1);} +.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;} +.navbar .nav.pull-right{float:right;margin-right:0;} +.navbar .nav>li{float:left;} +.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777777;text-decoration:none;text-shadow:0 1px 0 #ffffff;} +.navbar .nav .dropdown-toggle .caret{margin-top:8px;} +.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333333;text-decoration:none;} +.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);-moz-box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);} +.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#ededed;background-image:-moz-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));background-image:-webkit-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-o-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:linear-gradient(to bottom, #f2f2f2, #e5e5e5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e5e5e5;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#ffffff;background-color:#e5e5e5;*background-color:#d9d9d9;} +.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#cccccc \9;} +.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);} +.btn-navbar .icon-bar+.icon-bar{margin-top:3px;} +.navbar .nav>li>.dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;} +.navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;} +.navbar-fixed-bottom .nav>li>.dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0, 0, 0, 0.2);border-bottom:0;bottom:-7px;top:auto;} +.navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #ffffff;border-bottom:0;bottom:-6px;top:auto;} +.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333333;border-bottom-color:#333333;} +.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{background-color:#e5e5e5;color:#555555;} +.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777777;border-bottom-color:#777777;} +.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555555;border-bottom-color:#555555;} +.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{left:auto;right:0;}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{left:auto;right:12px;} +.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{left:auto;right:13px;} +.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{left:auto;right:100%;margin-left:0;margin-right:-1px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;} +.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top, #222222, #111111);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111));background-image:-webkit-linear-gradient(top, #222222, #111111);background-image:-o-linear-gradient(top, #222222, #111111);background-image:linear-gradient(to bottom, #222222, #111111);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);border-color:#252525;} +.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999999;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#ffffff;} +.navbar-inverse .brand{color:#999999;} +.navbar-inverse .navbar-text{color:#999999;} +.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#ffffff;} +.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#ffffff;background-color:#111111;} +.navbar-inverse .navbar-link{color:#999999;}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#ffffff;} +.navbar-inverse .divider-vertical{border-left-color:#111111;border-right-color:#222222;} +.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{background-color:#111111;color:#ffffff;} +.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;} +.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999999;border-bottom-color:#999999;} +.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;} +.navbar-inverse .navbar-search .search-query{color:#ffffff;background-color:#515151;border-color:#111111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none;}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#cccccc;} +.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#cccccc;} +.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#cccccc;} +.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;} +.navbar-inverse .btn-navbar{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e0e0e;background-image:-moz-linear-gradient(top, #151515, #040404);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));background-image:-webkit-linear-gradient(top, #151515, #040404);background-image:-o-linear-gradient(top, #151515, #040404);background-image:linear-gradient(to bottom, #151515, #040404);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);border-color:#040404 #040404 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#040404;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#ffffff;background-color:#040404;*background-color:#000000;} +.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000000 \9;} +.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.breadcrumb>li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #ffffff;}.breadcrumb>li>.divider{padding:0 5px;color:#ccc;} +.breadcrumb>.active{color:#999999;} +.pagination{margin:20px 0;} +.pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);} +.pagination ul>li{display:inline;} +.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#ffffff;border:1px solid #dddddd;border-left-width:0;} +.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5;} +.pagination ul>.active>a,.pagination ul>.active>span{color:#999999;cursor:default;} +.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999999;background-color:transparent;cursor:default;} +.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} +.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} +.pagination-centered{text-align:center;} +.pagination-right{text-align:right;} +.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px;} +.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;} +.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;} +.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-top-left-radius:3px;-moz-border-radius-topleft:3px;border-top-left-radius:3px;-webkit-border-bottom-left-radius:3px;-moz-border-radius-bottomleft:3px;border-bottom-left-radius:3px;} +.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;-moz-border-radius-topright:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;-moz-border-radius-bottomright:3px;border-bottom-right-radius:3px;} +.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px;} +.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px;} +.pager{margin:20px 0;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";line-height:0;} +.pager:after{clear:both;} +.pager li{display:inline;} +.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} +.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5;} +.pager .next>a,.pager .next>span{float:right;} +.pager .previous>a,.pager .previous>span{float:left;} +.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999999;background-color:#fff;cursor:default;} +.thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";line-height:0;} +.thumbnails:after{clear:both;} +.row-fluid .thumbnails{margin-left:0;} +.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px;} +.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;} +a.thumbnail:hover,a.thumbnail:focus{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);} +.thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;} +.thumbnail .caption{padding:9px;color:#555555;} +.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.alert,.alert h4{color:#c09853;} +.alert h4{margin:0;} +.alert .close{position:relative;top:-2px;right:-21px;line-height:20px;} +.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;} +.alert-success h4{color:#468847;} +.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;} +.alert-danger h4,.alert-error h4{color:#b94a48;} +.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;} +.alert-info h4{color:#3a87ad;} +.alert-block{padding-top:14px;padding-bottom:14px;} +.alert-block>p,.alert-block>ul{margin-bottom:0;} +.alert-block p+p{margin-top:5px;} +@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-o-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(to bottom, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.progress .bar{width:0%;height:100%;color:#ffffff;float:left;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(to bottom, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;} +.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);} +.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;} +.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;} +.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(to bottom, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0);} +.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(to bottom, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0);} +.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(to bottom, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0);} +.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);} +.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eeeeee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px;} +.hero-unit li{line-height:30px;} +.media,.media-body{overflow:hidden;*overflow:visible;zoom:1;} +.media,.media .media{margin-top:15px;} +.media:first-child{margin-top:0;} +.media-object{display:block;} +.media-heading{margin:0 0 5px;} +.media>.pull-left{margin-right:10px;} +.media>.pull-right{margin-left:10px;} +.media-list{margin-left:0;list-style:none;} +.tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);} +.tooltip.top{margin-top:-3px;padding:5px 0;} +.tooltip.right{margin-left:3px;padding:0 5px;} +.tooltip.bottom{margin-top:3px;padding:5px 0;} +.tooltip.left{margin-left:-3px;padding:0 5px;} +.tooltip-inner{max-width:200px;padding:8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid;} +.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000000;} +.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000000;} +.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000000;} +.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000000;} +.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#ffffff;-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);white-space:normal;}.popover.top{margin-top:-10px;} +.popover.right{margin-left:10px;} +.popover.bottom{margin-top:10px;} +.popover.left{margin-left:-10px;} +.popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0;}.popover-title:empty{display:none;} +.popover-content{padding:9px 14px;} +.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid;} +.popover .arrow{border-width:11px;} +.popover .arrow:after{border-width:10px;content:"";} +.popover.top .arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0, 0, 0, 0.25);bottom:-11px;}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#ffffff;} +.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0, 0, 0, 0.25);}.popover.right .arrow:after{left:1px;bottom:-10px;border-left-width:0;border-right-color:#ffffff;} +.popover.bottom .arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0, 0, 0, 0.25);top:-11px;}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#ffffff;} +.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0, 0, 0, 0.25);}.popover.left .arrow:after{right:1px;border-right-width:0;border-left-color:#ffffff;bottom:-10px;} +.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;} +.modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);} +.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;outline:none;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;} +.modal.fade.in{top:10%;} +.modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;} +.modal-header h3{margin:0;line-height:30px;} +.modal-body{position:relative;overflow-y:auto;max-height:400px;padding:15px;} +.modal-form{margin-bottom:0;} +.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";line-height:0;} +.modal-footer:after{clear:both;} +.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0;} +.modal-footer .btn-group .btn+.btn{margin-left:-1px;} +.modal-footer .btn-block+.btn-block{margin-left:0;} +.dropup,.dropdown{position:relative;} +.dropdown-toggle{*margin-bottom:-3px;} +.dropdown-toggle:active,.open .dropdown-toggle{outline:0;} +.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000000;border-right:4px solid transparent;border-left:4px solid transparent;content:"";} +.dropdown .caret{margin-top:8px;margin-left:2px;} +.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#ffffff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;}.dropdown-menu.pull-right{right:0;left:auto;} +.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;} +.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333333;white-space:nowrap;} +.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{text-decoration:none;color:#ffffff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);} +.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#ffffff;text-decoration:none;outline:0;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);} +.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999999;} +.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:default;} +.open{*z-index:1000;}.open>.dropdown-menu{display:block;} +.pull-right>.dropdown-menu{right:0;left:auto;} +.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000000;content:"";} +.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px;} +.dropdown-submenu{position:relative;} +.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;} +.dropdown-submenu:hover>.dropdown-menu{display:block;} +.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0;} +.dropdown-submenu>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#cccccc;margin-top:5px;margin-right:-10px;} +.dropdown-submenu:hover>a:after{border-left-color:#ffffff;} +.dropdown-submenu.pull-left{float:none;}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;} +.dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px;} +.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.accordion{margin-bottom:20px;} +.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.accordion-heading{border-bottom:0;} +.accordion-heading .accordion-toggle{display:block;padding:8px 15px;} +.accordion-toggle{cursor:pointer;} +.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;} +.carousel{position:relative;margin-bottom:20px;line-height:1;} +.carousel-inner{overflow:hidden;width:100%;position:relative;} +.carousel-inner>.item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1;} +.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block;} +.carousel-inner>.active{left:0;} +.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%;} +.carousel-inner>.next{left:100%;} +.carousel-inner>.prev{left:-100%;} +.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0;} +.carousel-inner>.active.left{left:-100%;} +.carousel-inner>.active.right{left:100%;} +.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;} +.carousel-control:hover,.carousel-control:focus{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);} +.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none;}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255, 255, 255, 0.25);border-radius:5px;} +.carousel-indicators .active{background-color:#fff;} +.carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333333;background:rgba(0, 0, 0, 0.75);} +.carousel-caption h4,.carousel-caption p{color:#ffffff;line-height:20px;} +.carousel-caption h4{margin:0 0 5px;} +.carousel-caption p{margin-bottom:0;} +.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);} +.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover,.close:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;filter:alpha(opacity=40);} +button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;} +.pull-right{float:right;} +.pull-left{float:left;} +.hide{display:none;} +.show{display:block;} +.invisible{visibility:hidden;} +.affix{position:fixed;} +.fade{opacity:0;-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;}.fade.in{opacity:1;} +.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;}.collapse.in{height:auto;} +@-ms-viewport{width:device-width;}.hidden{display:none;visibility:hidden;} +.visible-phone{display:none !important;} +.visible-tablet{display:none !important;} +.hidden-desktop{display:none !important;} +.visible-desktop{display:inherit !important;} +@media (min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit !important;} .visible-desktop{display:none !important ;} .visible-tablet{display:inherit !important;} .hidden-tablet{display:none !important;}}@media (max-width:767px){.hidden-desktop{display:inherit !important;} .visible-desktop{display:none !important;} .visible-phone{display:inherit !important;} .hidden-phone{display:none !important;}}.visible-print{display:none !important;} +@media print{.visible-print{display:inherit !important;} .hidden-print{display:none !important;}}@media (max-width:767px){body{padding-left:20px;padding-right:20px;} .navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-left:-20px;margin-right:-20px;} .container-fluid{padding:0;} .dl-horizontal dt{float:none;clear:none;width:auto;text-align:left;} .dl-horizontal dd{margin-left:0;} .container{width:auto;} .row-fluid{width:100%;} .row,.thumbnails{margin-left:0;} .thumbnails>li{float:none;margin-left:0;} [class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{float:none;display:block;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .row-fluid [class*="offset"]:first-child{margin-left:0;} .input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto;} .controls-row [class*="span"]+[class*="span"]{margin-left:0;} .modal{position:fixed;top:20px;left:20px;right:20px;width:auto;margin:0;}.modal.fade{top:-100px;} .modal.fade.in{top:20px;}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0);} .page-header h1 small{display:block;line-height:20px;} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc;} .form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left;} .form-horizontal .controls{margin-left:0;} .form-horizontal .control-list{padding-top:0;} .form-horizontal .form-actions{padding-left:10px;padding-right:10px;} .media .pull-left,.media .pull-right{float:none;display:block;margin-bottom:10px;} .media-object{margin-right:0;margin-left:0;} .modal{top:10px;left:10px;right:10px;} .modal-header .close{padding:10px;margin:-10px;} .carousel-caption{position:static;}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} .row:after{clear:both;} [class*="span"]{float:left;min-height:1px;margin-left:20px;} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px;} .span12{width:724px;} .span11{width:662px;} .span10{width:600px;} .span9{width:538px;} .span8{width:476px;} .span7{width:414px;} .span6{width:352px;} .span5{width:290px;} .span4{width:228px;} .span3{width:166px;} .span2{width:104px;} .span1{width:42px;} .offset12{margin-left:764px;} .offset11{margin-left:702px;} .offset10{margin-left:640px;} .offset9{margin-left:578px;} .offset8{margin-left:516px;} .offset7{margin-left:454px;} .offset6{margin-left:392px;} .offset5{margin-left:330px;} .offset4{margin-left:268px;} .offset3{margin-left:206px;} .offset2{margin-left:144px;} .offset1{margin-left:82px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} .row-fluid:after{clear:both;} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;} .row-fluid [class*="span"]:first-child{margin-left:0;} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%;} .row-fluid .span12{width:100%;*width:99.94680851063829%;} .row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%;} .row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%;} .row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%;} .row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%;} .row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%;} .row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%;} .row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%;} .row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%;} .row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%;} .row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%;} .row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%;} .row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%;} .row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%;} .row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%;} .row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%;} .row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%;} .row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%;} .row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%;} .row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%;} .row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%;} .row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%;} .row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%;} .row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%;} .row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%;} .row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%;} .row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%;} .row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%;} .row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%;} .row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%;} .row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%;} .row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%;} .row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%;} .row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%;} .row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%;} .row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%;} input,textarea,.uneditable-input{margin-left:0;} .controls-row [class*="span"]+[class*="span"]{margin-left:20px;} input.span12,textarea.span12,.uneditable-input.span12{width:710px;} input.span11,textarea.span11,.uneditable-input.span11{width:648px;} input.span10,textarea.span10,.uneditable-input.span10{width:586px;} input.span9,textarea.span9,.uneditable-input.span9{width:524px;} input.span8,textarea.span8,.uneditable-input.span8{width:462px;} input.span7,textarea.span7,.uneditable-input.span7{width:400px;} input.span6,textarea.span6,.uneditable-input.span6{width:338px;} input.span5,textarea.span5,.uneditable-input.span5{width:276px;} input.span4,textarea.span4,.uneditable-input.span4{width:214px;} input.span3,textarea.span3,.uneditable-input.span3{width:152px;} input.span2,textarea.span2,.uneditable-input.span2{width:90px;} input.span1,textarea.span1,.uneditable-input.span1{width:28px;}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} .row:after{clear:both;} [class*="span"]{float:left;min-height:1px;margin-left:30px;} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px;} .span12{width:1170px;} .span11{width:1070px;} .span10{width:970px;} .span9{width:870px;} .span8{width:770px;} .span7{width:670px;} .span6{width:570px;} .span5{width:470px;} .span4{width:370px;} .span3{width:270px;} .span2{width:170px;} .span1{width:70px;} .offset12{margin-left:1230px;} .offset11{margin-left:1130px;} .offset10{margin-left:1030px;} .offset9{margin-left:930px;} .offset8{margin-left:830px;} .offset7{margin-left:730px;} .offset6{margin-left:630px;} .offset5{margin-left:530px;} .offset4{margin-left:430px;} .offset3{margin-left:330px;} .offset2{margin-left:230px;} .offset1{margin-left:130px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} .row-fluid:after{clear:both;} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;} .row-fluid [class*="span"]:first-child{margin-left:0;} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%;} .row-fluid .span12{width:100%;*width:99.94680851063829%;} .row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%;} .row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%;} .row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%;} .row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%;} .row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%;} .row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%;} .row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%;} .row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%;} .row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%;} .row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%;} .row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%;} .row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%;} .row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%;} .row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%;} .row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%;} .row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%;} .row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%;} .row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%;} .row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%;} .row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%;} .row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%;} .row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%;} .row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%;} .row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%;} .row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%;} .row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%;} .row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%;} .row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%;} .row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%;} .row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%;} .row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%;} .row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%;} .row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%;} .row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%;} .row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%;} input,textarea,.uneditable-input{margin-left:0;} .controls-row [class*="span"]+[class*="span"]{margin-left:30px;} input.span12,textarea.span12,.uneditable-input.span12{width:1156px;} input.span11,textarea.span11,.uneditable-input.span11{width:1056px;} input.span10,textarea.span10,.uneditable-input.span10{width:956px;} input.span9,textarea.span9,.uneditable-input.span9{width:856px;} input.span8,textarea.span8,.uneditable-input.span8{width:756px;} input.span7,textarea.span7,.uneditable-input.span7{width:656px;} input.span6,textarea.span6,.uneditable-input.span6{width:556px;} input.span5,textarea.span5,.uneditable-input.span5{width:456px;} input.span4,textarea.span4,.uneditable-input.span4{width:356px;} input.span3,textarea.span3,.uneditable-input.span3{width:256px;} input.span2,textarea.span2,.uneditable-input.span2{width:156px;} input.span1,textarea.span1,.uneditable-input.span1{width:56px;} .thumbnails{margin-left:-30px;} .thumbnails>li{margin-left:30px;} .row-fluid .thumbnails{margin-left:0;}}@media (max-width:979px){body{padding-top:0;} .navbar-fixed-top,.navbar-fixed-bottom{position:static;} .navbar-fixed-top{margin-bottom:20px;} .navbar-fixed-bottom{margin-top:20px;} .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px;} .navbar .container{width:auto;padding:0;} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px;} .nav-collapse{clear:both;} .nav-collapse .nav{float:none;margin:0 0 10px;} .nav-collapse .nav>li{float:none;} .nav-collapse .nav>li>a{margin-bottom:2px;} .nav-collapse .nav>.divider-vertical{display:none;} .nav-collapse .nav .nav-header{color:#777777;text-shadow:none;} .nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} .nav-collapse .dropdown-menu li+li a{margin-bottom:2px;} .nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2;} .navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999999;} .navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111111;} .nav-collapse.in .btn-group{margin-top:5px;padding:0;} .nav-collapse .dropdown-menu{position:static;top:auto;left:auto;float:none;display:none;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} .nav-collapse .open>.dropdown-menu{display:block;} .nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none;} .nav-collapse .dropdown-menu .divider{display:none;} .nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none;} .nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);} .navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111111;border-bottom-color:#111111;} .navbar .nav-collapse .nav.pull-right{float:none;margin-left:0;} .nav-collapse,.nav-collapse.collapse{overflow:hidden;height:0;} .navbar .btn-navbar{display:block;} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px;}}@media (min-width:980px){.nav-collapse.collapse{height:auto !important;overflow:visible !important;}} diff --git a/template/rpi/css.php b/template/rpi/css.php new file mode 100755 index 0000000..f5e8352 --- /dev/null +++ b/template/rpi/css.php @@ -0,0 +1,246 @@ + + +#pbody { + min-height: 100%; + position: relative; + width: 100%; + margin: 0px 0%; + background-image:url(/img/gor.jpg); + background-size: 430px 100%; + background-repeat:repeat-y; + top:0px; + } + +#pbody a{ + font-weight :bold; +/* +*/ + } + + +#head { + height: 150px; + left:-1px; + top:-1px; + width: 100%; + position: relative; + background-image: url(/img/head.jpg); + background-size: 100% 150px; + } + +#slogo{ + left: 0px; + top:0px;/*-1*/ + float: left; + position: relative; + width: 450px; + height: 150px; + background-image: url(/img/rpi_logo.jpg); + background-repeat: no-repeat; + background-size: 100% 150px; + padding-right: 0px; + } + +#sname{ + width:200px; + height: 37px; + overflow: hidden; + position: relative; + background-repeat: no-repeat; + top: 40px; + } + +#sslogan{ + position: relative; + overflow: hidden; + text-align: left; + top: 80px; + } + +#hmemo{ + position: relative; + top: 40px; + width: 150px; + height: 99px; + float: right; + padding-left: -55px; + background-image: url(/img/rpi.gif); + background-repeat: no-repeat; + background-size: 100% 100px; + padding-right: 25px; + } + +#hmenu{ + text-align :center; + top: 50px; + left:15%; + position: absolute; + width: 70%; + height: 30px; +/* + font-family: serif; + color: #666; +*/ + font-family : Arial, Tahoma, Verdana, sans-serif; + text-shadow: 1px 1px 3px #666, -1px -1px 3px #FFF, 1px 1px #666, -1px -1px #FFF; + font-size: 20px; + } + +#hmenu a{ + color: #000; + text-shadow: 1px 1px 3px #666, + -1px -1px 3px #FFF, + 1px 1px #666, + -1px -1px #FFF; + text-decoration: none; + } + +#hmenu a:hover{ + color: rgb(100,100,100); + text-shadow: -1px -1px #666, + 1px 1px #FFF; + } + +#smap{ + text-align :center; + position: relative; + margin: 0 auto; + margin-top:5px; + width: 99%; + height: 20px; + } + +#smap a{ + text-decoration: none; + } + +#cont{ + width: 90%; + margin: 0 auto; + } + +.bcont{ + padding: 15px; + } + +#left-float, +#right-float, +.center-float { + padding: 5px; + text-align: left; + } + +#left-float { + float: left; +} +#right-float { + float: right; +} +#left-float:empty, +#right-float:empty { + width: 0px; +} +#left-float:not(:empty), +#right-float:not(:empty) { + width: 200px; +} + +.center-float { + float: none; + width: auto; + overflow: hidden; + } + +.bfloat{ + overflow-x: hidden; +/* + padding :5px; + margin :5px; +*/ + border: 1px solid #f44180; + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + border-radius: 0 0 10px 10px; + } + +/* + -webkit-box-shadow: 5px 5px 5px #222; + -moz-box-shadow: 5px 5px 5px #222; + box-shadow: 0px 0px 5px #111; + } +*/ + +.bfloat, +.btitle{ +white-space: normal; +word-wrap: break-word; +/* + -webkit-box-shadow: 5px 5px 5px #222; + -moz-box-shadow: 5px 5px 5px #222; +*/ + box-shadow: 0px 0px 5px #777; + } + +.bfloat a{ + text-decoration: none; + } +/* +*/ + +.cfloat{ + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + } + +.btitle{ +white-space: normal; +word-wrap: break-word; + left: -1px; + top: -1px; + position: relative; + width: calc(100% + 2px); + text-align: center; + line-height: 30px; + font-weight: bold; + color: #ffffff; + background-image: url(/img/menu_7.jpg); + background-size: 100% 100% ; + border-radius: 10px 10px 0 0; + } + +.ctitle{ + left: 0px; + top: -1px; + position: relative; + width: 100%; + height: 20px; + text-align: center; + line-height: 20px; + font-weight: bold; + } +.cctitle{ + left: 0px; + top: -1px; + margin-top: -4px; + position: relative; + width: 100%; + height: 0px; + line-height: 00px; + } +.youtubef{ + max-width:100%; + width:650px; + height:360px; + { + diff --git a/template/rpi/page.php b/template/rpi/page.php new file mode 100755 index 0000000..7052dc2 --- /dev/null +++ b/template/rpi/page.php @@ -0,0 +1,37 @@ +
+ +
+
+ %smap% +
+ +
+ %left% + %right% +
+
+ %title% +
+
+
%content%
+
+
+
+ +
\ No newline at end of file diff --git a/template/rpi/raspcontrol.css b/template/rpi/raspcontrol.css new file mode 100755 index 0000000..bce4e39 --- /dev/null +++ b/template/rpi/raspcontrol.css @@ -0,0 +1,179 @@ +/* + * Commun style + */ + +.container, .navbar .container { + max-width: 650px; +} + + +.center { + text-align: center; +} + +/* + * Header + */ + +header { + margin: 0; + height: 140px; + color: #fff; + background: #464646; + background: -moz-linear-gradient(top,#464646 0%,#303130 100%); + background: -webkit-gradient(linear,left top,left bottom,color-stop(0%,#464646),color-stop(100%,#303130)); + background: -webkit-linear-gradient(top,#464646 0%,#303130 100%); + background: -o-linear-gradient(top,#464646 0%,#303130 100%); + background: -ms-linear-gradient(top,#464646 0%,#303130 100%); + background: linear-gradient(to bottom,#464646 0%,#303130 100%); +} + +header h1 { + margin: 32px 0 -10px 0; + font-size: 40px; + font-weight: normal; + letter-spacing: 0px; +} + +header a, +header a:hover, +header a:focus { + color: #fff; + text-decoration: none; +} +header a:hover { + color: #ededed; +} + +header h2 { + margin: 0; + font-size: 16px; + font-weight: normal; + color: #aaa; +} + +header img { + float: left; + margin: 15px 0 0 0; +} + +/* + * Pages + */ + +.form-login { + margin: 20px 0 60px 0; +} +.form-login input { + margin-bottom: 10px; +} + +.details table { + width: 100%; +} +.details tr { + vertical-align: top; + /*border-bottom: 1px solid #dedede;*/ +} +.details td { + padding: 20px 0; +} +.details td.check { + font-weight: bold; + min-width: 100px; +} +.details td.icon { + min-width: 25px; + padding-left: 10px; + padding-right: 20px; +} +.details .storage td { + padding: 15px 0; +} + +.details .progress { + margin-bottom: 8px; +} +.details .storage .progress { + margin-top: 10px; +} + +.rapid-status div { + margin-top: 20px; +} +.infos div { + margin-bottom: 20px; +} + + +/* + * Footer + */ + +footer { + margin:0; + padding: 30px 0 0 0; + color: #fff; + background: #464646; + background: -moz-linear-gradient(top,#464646 0%,#303130 100%); + background: -webkit-gradient(linear,left top,left bottom,color-stop(0%,#464646),color-stop(100%,#303130)); + background: -webkit-linear-gradient(top,#464646 0%,#303130 100%); + background: -o-linear-gradient(top,#464646 0%,#303130 100%); + background: -ms-linear-gradient(top,#464646 0%,#303130 100%); + background: linear-gradient(to bottom,#464646 0%,#303130 100%); + height: 80px; +} + +footer p { + margin: 0; +} +footer a { + color: #ccc; +} +footer a:hover { + color: #fff; +} + +/* + * Mediaqueries + */ +@media (max-width: 770px) { + body { + margin: 0; + padding: 0; + } + .container, + .progress { + max-width: 100% !important; + } + .navbar { + width: 100% !important; + margin-left: 0 !important; + } + header img { + display: none; + } + header { + padding: 0 10px 0 20px; + height: 120px; + } + footer { + padding-top: 20px; + padding-left: 20px; + padding-right: 20px; + } +} + +/* + * Bootstrap override + */ +.popover { + width: 650px; + max-width: 650px; +} +.infos div .popover-content { + margin-bottom: 0px; +} +.popover-content table { + margin-bottom: 0px; +} diff --git a/template/start/css.php b/template/start/css.php new file mode 100755 index 0000000..ee59df4 --- /dev/null +++ b/template/start/css.php @@ -0,0 +1,99 @@ + + +/* Главные контейнеры */ +#head { + background-image :url(); + background-repeat :no-repeat; + background-size :1500px; + background-position :center; + height :510px; + width :100%; + position :relative; + top :5px; + } + +#left { + top :-150px; + height :440px; + position :relative; + float :left; + width :32%; + margin-bottom :-100px; + } + +#right { + position :relative; + float :right; + width :32%; + height :300px; + top :-10px; + } + +#center { + float :none; + width :auto; + overflow :hidden; + height :230px; + position :relative; + top :-60px; + } + +#basic { + top :330px; + float :none; + width :100%; + height :150px; + position :relative; + } + +#main2 { + border :1px solid #0ffff0; + float :none; + margin :0px auto; + border :1px; + height :100%; + } + +#left:hover::after, +#right:hover::after, +#center:hover::after + { + content :attr(data-title); /* Выводим текст */ + position :absolute; /* Абсолютное позиционирование */ + left :0; + right :0; + bottom :5px; /* Положение подсказки */ + z-index :1; /* Отображаем подсказку поверх других элементов */ + background :rgba(0,42,167,0.6); /* Полупрозрачный цвет фона */ + color :#fff; /* Цвет текста */ + text-align :center; /* Выравнивание текста по центру */ + font-family :Arial, /* Гарнитура шрифта */ + sans-serif; + font-size :15px; /* Размер текста подсказки */ + padding :5px 10px; /* Поля */ + border :1px solid #333; /* Параметры рамки */ + border-radius :10px; + } + +#basic:hover::after + { + content :attr(data-title); /* Выводим текст */ + position :absolute; /* Абсолютное позиционирование */ + left :0; + right :0; + bottom :5px; /* Положение подсказки */ + z-index :1; /* Отображаем подсказку поверх других элементов */ + background :rgba(194,194,194,0.6); /* Полупрозрачный цвет фона */ + color :#fff; /* Цвет текста */ + text-align :center; /* Выравнивание текста по центру */ + font-family :Arial, /* Гарнитура шрифта */ + sans-serif; + font-size :15px; /* Размер текста подсказки */ + padding :5px 10px; /* Поля */ + border :1px solid #333; /* Параметры рамки */ + border-radius :10px; + } diff --git a/template/start/footercss.php b/template/start/footercss.php new file mode 100755 index 0000000..a6156b7 --- /dev/null +++ b/template/start/footercss.php @@ -0,0 +1,42 @@ +#fclear{ + clear: both; + top: -100px; +} + +#footer { + height: 20px; + position: relative; + width: 90%; + border: 1px solid #0ffff0; + margin: 0px auto; + top: -110px; + } + +.left-footer, +.right-footer, +.center-footer { + position: relative; + padding: 0px; + border: 1px solid #0ffff0; + } + +.left-footer { +/* + left:-400px; +*/ + float: left; + width: 30%; + } +.right-footer { + float: right; + width: 30%; + } + +.center-footer { +/* + left:-400px; +*/ + float: none; + width: auto; + overflow: hidden; + } diff --git a/template/start/page.php b/template/start/page.php new file mode 100755 index 0000000..4d1460f --- /dev/null +++ b/template/start/page.php @@ -0,0 +1,4 @@ + diff --git a/template/start/test2_.jpg b/template/start/test2_.jpg new file mode 100755 index 0000000..9b2833c Binary files /dev/null and b/template/start/test2_.jpg differ diff --git a/template/temp/new/css.php b/template/temp/new/css.php new file mode 100755 index 0000000..01334cc --- /dev/null +++ b/template/temp/new/css.php @@ -0,0 +1,298 @@ + +body, html{ + margin: 0px; + padding: 0px; + text-align: center; + background: #f4f4f4; +} +/* Главные контейнеры */ +#hbody { + position: fixed; + height: 30px; + width: 100%; + background: rgb(237,232,237); + background-image: linear-gradient(bottom, rgb(194,194,194) 15%, rgb(237,232,237) 57%); + background-image: -o-linear-gradient(bottom, rgb(194,194,194) 15%, rgb(237,232,237) 57%); + background-image: -moz-linear-gradient(bottom, rgb(194,194,194) 15%, rgb(237,232,237) 57%); + background-image: -webkit-linear-gradient(bottom, rgb(194,194,194) 15%, rgb(237,232,237) 57%); + background-image: -ms-linear-gradient(bottom, rgb(194,194,194) 15%, rgb(237,232,237) 57%); + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.15, rgb(194,194,194)), color-stop(0.57, rgb(237,232,237))); + color: #666; +/* text-shadow: -1px -1px #666, 1px 1px #FFF;*/ + text-shadow: 1px 1px 3px #666, -1px -1px 3px #FFF, 1px 1px #666, -1px -1px #FFF; + font-family: serif; + font-size:20px; + top:0px; + z-index:10; + } + +#shome{ + position: relative; + top: 0px; + float: left; + left: 0px; + width:100px; + } + + +#smenu{ + position: relative; + margin: 0px auto; + width:400px; + } + +#slng{ + text-transform: uppercase; + position: relative; + float: right; + width:100px; + } + +/*#slng {position:relative;z-index:100;}*/ + +#slng ul li a,#slng ul li a:visited {display:block;text-decoration:none;text-align:center;line-height:20px;overflow:hidden;} + +#slng ul {padding:0;margin:0;list-style: none;} + +#slng ul li {float:left;position:relative;width:100px;} + +#slng ul li ul {display: none; background: rgb(237,232,237);} + +/* specific to non IE browsers */ +#slng ul li:hover a { } + +#slng ul li:hover ul {display:block;position:absolute;top:21px;left:0;width:50px;} + +#slng ul li:hover ul li a.hide { } + +#slng ul li:hover ul li:hover a.hide { } + +#slng ul li:hover ul li ul {display: none;} + +#slng ul li:hover ul li a {display:block;} + +#slng ul li:hover ul li a:hover { } + +#slng ul li:hover ul li:hover ul {display:block;position:absolute;left:50px;top:0;} + +#slng ul li:hover ul li:hover ul.left {left:-105px;} + +#f button{ +/**/ color:#666; + background:none; + cursor:pointer; + border:0; + text-shadow: 1px 1px 3px #666, -1px -1px 3px #FFF, 1px 1px #666, -1px -1px #FFF; + font-family: serif; + font-size:20px; + } + +#f, #f button{ + display:inline; + margin:0; + padding:0; + } + + + +#f button:hover{ + color: rgb(153,153,153); + text-shadow: -1px -1px #666, 1px 1px #FFF; + } + + + +#hbody a{ + color: #666; + text-shadow: 1px 1px 3px #666, -1px -1px 3px #FFF, 1px 1px #666, -1px -1px #FFF; + text-decoration: none;/**/ + } + +#hbody a:hover{ + color: rgb(153,153,153); + text-shadow: -1px -1px #666, 1px 1px #FFF; + } + +#pbody { + min-height: 100%; + position: relative; + width: 95%; + margin: 0px auto; + background: #ffffff; + top:50px; + } + + +#head { + height: 100px; + left:-1px; + top:-1px; + width: 100%; + position: relative; + } + +#slogo{ + left: 5px; + float: left; + position: relative; + width: 80px; + height: 99px; + background-image: url(/img/Raspberry_Pi_Logo.svg); + background-repeat: no-repeat; + padding-right: 5px; + } + +#sname{ + width:200px; +/* max-width:10%;*/ + height: 37px; + overflow: hidden; + position: relative; + background-image: url(/img/rpi.svg); + background-repeat: no-repeat; + top: 40px; + } + +#sslogan{ + border: 1px solid #000000; + overflow: hidden; + text-align: left; + margin-top:10px; + } + +#hmemo{ + position: relative; + width: 150px; + height: 99px; + float: right; + background-image: url(/img/rpi.gif); + background-repeat: no-repeat; + background-size: auto 100px; + padding-right: 5px; + } + +#hmenu{ + top: -30px; + border: 1px solid #000000; + position: relative; + width: 600px; + margin: 0 auto; + margin-bottom:0px; + height: 30px; + } + +#smap{ +/* border: 1px solid #000000; + text-align: left;*/ + position: relative; + margin: 0 auto; + margin-top:5px; + width: 99%; + height: 20px; + } + +#smap a{ + text-decoration: none; + } + +#fclear{ + clear:both; +} +#footer { + height: 100px; + position: relative; + left: -1px; + bottom: -1px; + width: 100%; + border: 1px solid #0ffff0; + } + +#left-float, +#right-float, +.center-float { + padding: 5px; + } + +#left-float { + float: left; +} +#right-float { + float: right; +} +#left-float:empty, +#right-float:empty { + width: 0px; +} +#left-float:not(:empty), +#right-float:not(:empty) { + width: 200px; +} + +.center-float { + float: none; + width: auto; + overflow: hidden; + } + +.bfloat{ + overflow-x: hidden; + border: 1px solid #f44180; + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + border-radius: 0 0 10px 10px; + } + +.cfloat{ + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + } + +.btitle{ +white-space: normal; +word-wrap: break-word; + left: -1px; + top: -1px; + position: relative; + width: calc(100% + 2px); + text-align: center; + line-height: 30px; + font-weight: bold; + color: #ffffff; + background-image: url(/img/menu_7.jpg); + background-size: auto 100% ; + border-radius: 10px 10px 0 0; + } + +.ctitle{ + left: 0px; + top: -1px; + position: relative; + width: 100%; + height: 20px; + text-align: center; + line-height: 20px; + font-weight: bold; + } +.cctitle{ + left: 0px; + top: -1px; + margin-top: -4px; + position: relative; + width: 100%; + height: 0px; + line-height: 00px; + } +.youtubef{ + max-width:100%; + width:650px; + height:360px; + { + diff --git a/template/temp/new/page.php b/template/temp/new/page.php new file mode 100755 index 0000000..2fa5c2c --- /dev/null +++ b/template/temp/new/page.php @@ -0,0 +1,62 @@ + + + + +%sitename% + + + + + +
+ +
+ %smap% +
+ +
+%left% +%right% +
+
+ %title% +
+
+
%content%
+
+
+
+ +
+ + diff --git a/template/test/bootstrap-responsive.min.css b/template/test/bootstrap-responsive.min.css new file mode 100755 index 0000000..5cb833f --- /dev/null +++ b/template/test/bootstrap-responsive.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap Responsive v2.2.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */@-ms-viewport{width:device-width}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} diff --git a/template/test/bootstrap.min.css b/template/test/bootstrap.min.css new file mode 100755 index 0000000..81bb833 --- /dev/null +++ b/template/test/bootstrap.min.css @@ -0,0 +1,873 @@ +/*! + * Bootstrap v2.3.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0;} +.clearfix:after{clear:both;} +.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;} +.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} +article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;} +audio,canvas,video{display:inline-block;*display:inline;*zoom:1;} +audio:not([controls]){display:none;} +html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;} +a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +a:hover,a:active{outline:0;} +sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;} +sup{top:-0.5em;} +sub{bottom:-0.25em;} +img{max-width:100%;width:auto\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic;} +#map_canvas img,.google-maps img{max-width:none;} +button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;} +button,input{*overflow:visible;line-height:normal;} +button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;} +button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;} +label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer;} +input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield;} +input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;} +textarea{overflow:auto;vertical-align:top;} +@media print{*{text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important;} a,a:visited{text-decoration:underline;} a[href]:after{content:" (" attr(href) ")";} abbr[title]:after{content:" (" attr(title) ")";} .ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:"";} pre,blockquote{border:1px solid #999;page-break-inside:avoid;} thead{display:table-header-group;} tr,img{page-break-inside:avoid;} img{max-width:100% !important;} @page {margin:0.5cm;}p,h2,h3{orphans:3;widows:3;} h2,h3{page-break-after:avoid;}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333333;background-color:#ffffff;} +a{color:#0088cc;text-decoration:none;} +a:hover,a:focus{color:#005580;text-decoration:underline;} +.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);} +.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px;} +.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} +.row:after{clear:both;} +[class*="span"]{float:left;min-height:1px;margin-left:20px;} +.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;} +.span12{width:940px;} +.span11{width:860px;} +.span10{width:780px;} +.span9{width:700px;} +.span8{width:620px;} +.span7{width:540px;} +.span6{width:460px;} +.span5{width:380px;} +.span4{width:300px;} +.span3{width:220px;} +.span2{width:140px;} +.span1{width:60px;} +.offset12{margin-left:980px;} +.offset11{margin-left:900px;} +.offset10{margin-left:820px;} +.offset9{margin-left:740px;} +.offset8{margin-left:660px;} +.offset7{margin-left:580px;} +.offset6{margin-left:500px;} +.offset5{margin-left:420px;} +.offset4{margin-left:340px;} +.offset3{margin-left:260px;} +.offset2{margin-left:180px;} +.offset1{margin-left:100px;} +.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} +.row-fluid:after{clear:both;} +.row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;} +.row-fluid [class*="span"]:first-child{margin-left:0;} +.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%;} +.row-fluid .span12{width:100%;*width:99.94680851063829%;} +.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%;} +.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%;} +.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%;} +.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%;} +.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%;} +.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%;} +.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%;} +.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%;} +.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%;} +.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%;} +.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%;} +.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%;} +.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%;} +.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%;} +.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%;} +.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%;} +.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%;} +.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%;} +.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%;} +.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%;} +.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%;} +.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%;} +.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%;} +.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%;} +.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%;} +.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%;} +.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%;} +.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%;} +.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%;} +.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%;} +.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%;} +.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%;} +.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%;} +.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%;} +.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%;} +[class*="span"].hide,.row-fluid [class*="span"].hide{display:none;} +[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right;} +.container{margin-right:auto;margin-left:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";line-height:0;} +.container:after{clear:both;} +.container-fluid{padding-right:20px;padding-left:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";line-height:0;} +.container-fluid:after{clear:both;} +p{margin:0 0 10px;} +.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px;} +small{font-size:85%;} +strong{font-weight:bold;} +em{font-style:italic;} +cite{font-style:normal;} +.muted{color:#999999;} +a.muted:hover,a.muted:focus{color:#808080;} +.text-warning{color:#c09853;} +a.text-warning:hover,a.text-warning:focus{color:#a47e3c;} +.text-error{color:#b94a48;} +a.text-error:hover,a.text-error:focus{color:#953b39;} +.text-info{color:#3a87ad;} +a.text-info:hover,a.text-info:focus{color:#2d6987;} +.text-success{color:#468847;} +a.text-success:hover,a.text-success:focus{color:#356635;} +.text-left{text-align:left;} +.text-right{text-align:right;} +.text-center{text-align:center;} +h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999999;} +h1,h2,h3{line-height:40px;} +h1{font-size:38.5px;} +h2{font-size:31.5px;} +h3{font-size:24.5px;} +h4{font-size:17.5px;} +h5{font-size:14px;} +h6{font-size:11.9px;} +h1 small{font-size:24.5px;} +h2 small{font-size:17.5px;} +h3 small{font-size:14px;} +h4 small{font-size:14px;} +.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eeeeee;} +ul,ol{padding:0;margin:0 0 10px 25px;} +ul ul,ul ol,ol ol,ol ul{margin-bottom:0;} +li{line-height:20px;} +ul.unstyled,ol.unstyled{margin-left:0;list-style:none;} +ul.inline,ol.inline{margin-left:0;list-style:none;}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;*zoom:1;padding-left:5px;padding-right:5px;} +dl{margin-bottom:20px;} +dt,dd{line-height:20px;} +dt{font-weight:bold;} +dd{margin-left:10px;} +.dl-horizontal{*zoom:1;}.dl-horizontal:before,.dl-horizontal:after{display:table;content:"";line-height:0;} +.dl-horizontal:after{clear:both;} +.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;} +.dl-horizontal dd{margin-left:180px;} +hr{margin:20px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;} +abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999999;} +abbr.initialism{font-size:90%;text-transform:uppercase;} +blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25;} +blockquote small{display:block;line-height:20px;color:#999999;}blockquote small:before{content:'\2014 \00A0';} +blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;} +blockquote.pull-right small:before{content:'';} +blockquote.pull-right small:after{content:'\00A0 \2014';} +q:before,q:after,blockquote:before,blockquote:after{content:"";} +address{display:block;margin-bottom:20px;font-style:normal;line-height:20px;} +code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;white-space:nowrap;} +pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}pre.prettyprint{margin-bottom:20px;} +pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0;} +.pre-scrollable{max-height:340px;overflow-y:scroll;} +.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#ffffff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;} +.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.badge{padding-left:9px;padding-right:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;} +.label:empty,.badge:empty{display:none;} +a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#ffffff;text-decoration:none;cursor:pointer;} +.label-important,.badge-important{background-color:#b94a48;} +.label-important[href],.badge-important[href]{background-color:#953b39;} +.label-warning,.badge-warning{background-color:#f89406;} +.label-warning[href],.badge-warning[href]{background-color:#c67605;} +.label-success,.badge-success{background-color:#468847;} +.label-success[href],.badge-success[href]{background-color:#356635;} +.label-info,.badge-info{background-color:#3a87ad;} +.label-info[href],.badge-info[href]{background-color:#2d6987;} +.label-inverse,.badge-inverse{background-color:#333333;} +.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a;} +.btn .label,.btn .badge{position:relative;top:-1px;} +.btn-mini .label,.btn-mini .badge{top:0;} +table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0;} +.table{width:100%;margin-bottom:20px;}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #dddddd;} +.table th{font-weight:bold;} +.table thead th{vertical-align:bottom;} +.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0;} +.table tbody+tbody{border-top:2px solid #dddddd;} +.table .table{background-color:#ffffff;} +.table-condensed th,.table-condensed td{padding:4px 5px;} +.table-bordered{border:1px solid #dddddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;} +.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;} +.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;} +.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;} +.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} +.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} +.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;-moz-border-radius-bottomleft:0;border-bottom-left-radius:0;} +.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;-moz-border-radius-bottomright:0;border-bottom-right-radius:0;} +.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;} +.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;} +.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9;} +.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5;} +table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0;} +.table td.span1,.table th.span1{float:none;width:44px;margin-left:0;} +.table td.span2,.table th.span2{float:none;width:124px;margin-left:0;} +.table td.span3,.table th.span3{float:none;width:204px;margin-left:0;} +.table td.span4,.table th.span4{float:none;width:284px;margin-left:0;} +.table td.span5,.table th.span5{float:none;width:364px;margin-left:0;} +.table td.span6,.table th.span6{float:none;width:444px;margin-left:0;} +.table td.span7,.table th.span7{float:none;width:524px;margin-left:0;} +.table td.span8,.table th.span8{float:none;width:604px;margin-left:0;} +.table td.span9,.table th.span9{float:none;width:684px;margin-left:0;} +.table td.span10,.table th.span10{float:none;width:764px;margin-left:0;} +.table td.span11,.table th.span11{float:none;width:844px;margin-left:0;} +.table td.span12,.table th.span12{float:none;width:924px;margin-left:0;} +.table tbody tr.success>td{background-color:#dff0d8;} +.table tbody tr.error>td{background-color:#f2dede;} +.table tbody tr.warning>td{background-color:#fcf8e3;} +.table tbody tr.info>td{background-color:#d9edf7;} +.table-hover tbody tr.success:hover>td{background-color:#d0e9c6;} +.table-hover tbody tr.error:hover>td{background-color:#ebcccc;} +.table-hover tbody tr.warning:hover>td{background-color:#faf2cc;} +.table-hover tbody tr.info:hover>td{background-color:#c4e3f3;} +form{margin:0 0 20px;} +fieldset{padding:0;margin:0;border:0;} +legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333333;border:0;border-bottom:1px solid #e5e5e5;}legend small{font-size:15px;color:#999999;} +label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px;} +input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;} +label{display:block;margin-bottom:5px;} +select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555555;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;vertical-align:middle;} +input,textarea,.uneditable-input{width:206px;} +textarea{height:auto;} +textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#ffffff;border:1px solid #cccccc;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear .2s, box-shadow linear .2s;-moz-transition:border linear .2s, box-shadow linear .2s;-o-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s;}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82, 168, 236, 0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);} +input[type="radio"],input[type="checkbox"]{margin:4px 0 0;*margin-top:0;margin-top:1px \9;line-height:normal;} +input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto;} +select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px;} +select{width:220px;border:1px solid #cccccc;background-color:#ffffff;} +select[multiple],select[size]{height:auto;} +select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +.uneditable-input,.uneditable-textarea{color:#999999;background-color:#fcfcfc;border-color:#cccccc;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;} +.uneditable-input{overflow:hidden;white-space:nowrap;} +.uneditable-textarea{width:auto;height:auto;} +input:-moz-placeholder,textarea:-moz-placeholder{color:#999999;} +input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999999;} +input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999999;} +.radio,.checkbox{min-height:20px;padding-left:20px;} +.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px;} +.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;} +.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;} +.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;} +.input-mini{width:60px;} +.input-small{width:90px;} +.input-medium{width:150px;} +.input-large{width:210px;} +.input-xlarge{width:270px;} +.input-xxlarge{width:530px;} +input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0;} +.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block;} +input,textarea,.uneditable-input{margin-left:0;} +.controls-row [class*="span"]+[class*="span"]{margin-left:20px;} +input.span12,textarea.span12,.uneditable-input.span12{width:926px;} +input.span11,textarea.span11,.uneditable-input.span11{width:846px;} +input.span10,textarea.span10,.uneditable-input.span10{width:766px;} +input.span9,textarea.span9,.uneditable-input.span9{width:686px;} +input.span8,textarea.span8,.uneditable-input.span8{width:606px;} +input.span7,textarea.span7,.uneditable-input.span7{width:526px;} +input.span6,textarea.span6,.uneditable-input.span6{width:446px;} +input.span5,textarea.span5,.uneditable-input.span5{width:366px;} +input.span4,textarea.span4,.uneditable-input.span4{width:286px;} +input.span3,textarea.span3,.uneditable-input.span3{width:206px;} +input.span2,textarea.span2,.uneditable-input.span2{width:126px;} +input.span1,textarea.span1,.uneditable-input.span1{width:46px;} +.controls-row{*zoom:1;}.controls-row:before,.controls-row:after{display:table;content:"";line-height:0;} +.controls-row:after{clear:both;} +.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left;} +.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px;} +input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eeeeee;} +input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent;} +.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;} +.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;} +.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;} +.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;} +.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;} +.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;} +.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;} +.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;} +.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;} +.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;} +.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;} +.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;} +.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad;} +.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad;} +.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;} +.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad;} +input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;} +.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1;}.form-actions:before,.form-actions:after{display:table;content:"";line-height:0;} +.form-actions:after{clear:both;} +.help-block,.help-inline{color:#595959;} +.help-block{display:block;margin-bottom:10px;} +.help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;} +.input-append,.input-prepend{display:inline-block;margin-bottom:10px;vertical-align:middle;font-size:0;white-space:nowrap;}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px;} +.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2;} +.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #ffffff;background-color:#eeeeee;border:1px solid #ccc;} +.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546;} +.input-prepend .add-on,.input-prepend .btn{margin-right:-1px;} +.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} +.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px;} +.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} +.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.input-prepend.input-append .btn-group:first-child{margin-left:0;} +input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} +.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;} +.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;} +.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;} +.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;} +.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;vertical-align:middle;} +.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;} +.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block;} +.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;} +.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;} +.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0;} +.control-group{margin-bottom:10px;} +legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate;} +.form-horizontal .control-group{margin-bottom:20px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";line-height:0;} +.form-horizontal .control-group:after{clear:both;} +.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right;} +.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0;}.form-horizontal .controls:first-child{*padding-left:180px;} +.form-horizontal .help-block{margin-bottom:0;} +.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px;} +.form-horizontal .form-actions{padding-left:180px;} +.btn{display:inline-block;*display:inline;*zoom:1;padding:4px 12px;margin-bottom:0;font-size:14px;line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333333;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(to bottom, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #cccccc;*border:0;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333333;background-color:#e6e6e6;*background-color:#d9d9d9;} +.btn:active,.btn.active{background-color:#cccccc \9;} +.btn:first-child{*margin-left:0;} +.btn:hover,.btn:focus{color:#333333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} +.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);} +.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px;} +.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0;} +.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px;} +.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.btn-block{display:block;width:100%;padding-left:0;padding-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} +.btn-block+.btn-block{margin-top:5px;} +input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%;} +.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255, 255, 255, 0.75);} +.btn-primary{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(to bottom, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#0044cc;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#ffffff;background-color:#0044cc;*background-color:#003bb3;} +.btn-primary:active,.btn-primary.active{background-color:#003399 \9;} +.btn-warning{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#ffffff;background-color:#f89406;*background-color:#df8505;} +.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;} +.btn-danger{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#ffffff;background-color:#bd362f;*background-color:#a9302a;} +.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;} +.btn-success{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(to bottom, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#ffffff;background-color:#51a351;*background-color:#499249;} +.btn-success:active,.btn-success.active{background-color:#408140 \9;} +.btn-info{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(to bottom, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#ffffff;background-color:#2f96b4;*background-color:#2a85a0;} +.btn-info:active,.btn-info.active{background-color:#24748c \9;} +.btn-inverse{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444444, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));background-image:-webkit-linear-gradient(top, #444444, #222222);background-image:-o-linear-gradient(top, #444444, #222222);background-image:linear-gradient(to bottom, #444444, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#222222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#ffffff;background-color:#222222;*background-color:#151515;} +.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;} +button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;} +button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;} +button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;} +button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;} +.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +.btn-link{border-color:transparent;cursor:pointer;color:#0088cc;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent;} +.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333333;text-decoration:none;} +[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../../img/glyphicons-halflings.png");background-position:0px 0px;background-repeat:no-repeat;margin-top:1px;} +.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png");} +.icon-glass{background-position:0 0;} +.icon-music{background-position:-24px 0;} +.icon-search{background-position:-48px 0;} +.icon-envelope{background-position:-72px 0;} +.icon-heart{background-position:-96px 0;} +.icon-star{background-position:-120px 0;} +.icon-star-empty{background-position:-144px 0;} +.icon-user{background-position:-168px 0;} +.icon-film{background-position:-192px 0;} +.icon-th-large{background-position:-216px 0;} +.icon-th{background-position:-240px 0;} +.icon-th-list{background-position:-264px 0;} +.icon-ok{background-position:-288px 0;} +.icon-remove{background-position:-312px 0;} +.icon-zoom-in{background-position:-336px 0;} +.icon-zoom-out{background-position:-360px 0;} +.icon-off{background-position:-384px 0;} +.icon-signal{background-position:-408px 0;} +.icon-cog{background-position:-432px 0;} +.icon-trash{background-position:-456px 0;} +.icon-home{background-position:0 -24px;} +.icon-file{background-position:-24px -24px;} +.icon-time{background-position:-48px -24px;} +.icon-road{background-position:-72px -24px;} +.icon-download-alt{background-position:-96px -24px;} +.icon-download{background-position:-120px -24px;} +.icon-upload{background-position:-144px -24px;} +.icon-inbox{background-position:-168px -24px;} +.icon-play-circle{background-position:-192px -24px;} +.icon-repeat{background-position:-216px -24px;} +.icon-refresh{background-position:-240px -24px;} +.icon-list-alt{background-position:-264px -24px;} +.icon-lock{background-position:-287px -24px;} +.icon-flag{background-position:-312px -24px;} +.icon-headphones{background-position:-336px -24px;} +.icon-volume-off{background-position:-360px -24px;} +.icon-volume-down{background-position:-384px -24px;} +.icon-volume-up{background-position:-408px -24px;} +.icon-qrcode{background-position:-432px -24px;} +.icon-barcode{background-position:-456px -24px;} +.icon-tag{background-position:0 -48px;} +.icon-tags{background-position:-25px -48px;} +.icon-book{background-position:-48px -48px;} +.icon-bookmark{background-position:-72px -48px;} +.icon-print{background-position:-96px -48px;} +.icon-camera{background-position:-120px -48px;} +.icon-font{background-position:-144px -48px;} +.icon-bold{background-position:-167px -48px;} +.icon-italic{background-position:-192px -48px;} +.icon-text-height{background-position:-216px -48px;} +.icon-text-width{background-position:-240px -48px;} +.icon-align-left{background-position:-264px -48px;} +.icon-align-center{background-position:-288px -48px;} +.icon-align-right{background-position:-312px -48px;} +.icon-align-justify{background-position:-336px -48px;} +.icon-list{background-position:-360px -48px;} +.icon-indent-left{background-position:-384px -48px;} +.icon-indent-right{background-position:-408px -48px;} +.icon-facetime-video{background-position:-432px -48px;} +.icon-picture{background-position:-456px -48px;} +.icon-pencil{background-position:0 -72px;} +.icon-map-marker{background-position:-24px -72px;} +.icon-adjust{background-position:-48px -72px;} +.icon-tint{background-position:-72px -72px;} +.icon-edit{background-position:-96px -72px;} +.icon-share{background-position:-120px -72px;} +.icon-check{background-position:-144px -72px;} +.icon-move{background-position:-168px -72px;} +.icon-step-backward{background-position:-192px -72px;} +.icon-fast-backward{background-position:-216px -72px;} +.icon-backward{background-position:-240px -72px;} +.icon-play{background-position:-264px -72px;} +.icon-pause{background-position:-288px -72px;} +.icon-stop{background-position:-312px -72px;} +.icon-forward{background-position:-336px -72px;} +.icon-fast-forward{background-position:-360px -72px;} +.icon-step-forward{background-position:-384px -72px;} +.icon-eject{background-position:-408px -72px;} +.icon-chevron-left{background-position:-432px -72px;} +.icon-chevron-right{background-position:-456px -72px;} +.icon-plus-sign{background-position:0 -96px;} +.icon-minus-sign{background-position:-24px -96px;} +.icon-remove-sign{background-position:-48px -96px;} +.icon-ok-sign{background-position:-72px -96px;} +.icon-question-sign{background-position:-96px -96px;} +.icon-info-sign{background-position:-120px -96px;} +.icon-screenshot{background-position:-144px -96px;} +.icon-remove-circle{background-position:-168px -96px;} +.icon-ok-circle{background-position:-192px -96px;} +.icon-ban-circle{background-position:-216px -96px;} +.icon-arrow-left{background-position:-240px -96px;} +.icon-arrow-right{background-position:-264px -96px;} +.icon-arrow-up{background-position:-289px -96px;} +.icon-arrow-down{background-position:-312px -96px;} +.icon-share-alt{background-position:-336px -96px;} +.icon-resize-full{background-position:-360px -96px;} +.icon-resize-small{background-position:-384px -96px;} +.icon-plus{background-position:-408px -96px;} +.icon-minus{background-position:-433px -96px;} +.icon-asterisk{background-position:-456px -96px;} +.icon-exclamation-sign{background-position:0 -120px;} +.icon-gift{background-position:-24px -120px;} +.icon-leaf{background-position:-48px -120px;} +.icon-fire{background-position:-72px -120px;} +.icon-eye-open{background-position:-96px -120px;} +.icon-eye-close{background-position:-120px -120px;} +.icon-warning-sign{background-position:-144px -120px;} +.icon-plane{background-position:-168px -120px;} +.icon-calendar{background-position:-192px -120px;} +.icon-random{background-position:-216px -120px;width:16px;} +.icon-comment{background-position:-240px -120px;} +.icon-magnet{background-position:-264px -120px;} +.icon-chevron-up{background-position:-288px -120px;} +.icon-chevron-down{background-position:-313px -119px;} +.icon-retweet{background-position:-336px -120px;} +.icon-shopping-cart{background-position:-360px -120px;} +.icon-folder-close{background-position:-384px -120px;width:16px;} +.icon-folder-open{background-position:-408px -120px;width:16px;} +.icon-resize-vertical{background-position:-432px -119px;} +.icon-resize-horizontal{background-position:-456px -118px;} +.icon-hdd{background-position:0 -144px;} +.icon-bullhorn{background-position:-24px -144px;} +.icon-bell{background-position:-48px -144px;} +.icon-certificate{background-position:-72px -144px;} +.icon-thumbs-up{background-position:-96px -144px;} +.icon-thumbs-down{background-position:-120px -144px;} +.icon-hand-right{background-position:-144px -144px;} +.icon-hand-left{background-position:-168px -144px;} +.icon-hand-up{background-position:-192px -144px;} +.icon-hand-down{background-position:-216px -144px;} +.icon-circle-arrow-right{background-position:-240px -144px;} +.icon-circle-arrow-left{background-position:-264px -144px;} +.icon-circle-arrow-up{background-position:-288px -144px;} +.icon-circle-arrow-down{background-position:-312px -144px;} +.icon-globe{background-position:-336px -144px;} +.icon-wrench{background-position:-360px -144px;} +.icon-tasks{background-position:-384px -144px;} +.icon-filter{background-position:-408px -144px;} +.icon-briefcase{background-position:-432px -144px;} +.icon-fullscreen{background-position:-456px -144px;} +.btn-group{position:relative;display:inline-block;*display:inline;*zoom:1;font-size:0;vertical-align:middle;white-space:nowrap;*margin-left:.3em;}.btn-group:first-child{*margin-left:0;} +.btn-group+.btn-group{margin-left:5px;} +.btn-toolbar{font-size:0;margin-top:10px;margin-bottom:10px;}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px;} +.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.btn-group>.btn+.btn{margin-left:-1px;} +.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px;} +.btn-group>.btn-mini{font-size:10.5px;} +.btn-group>.btn-small{font-size:11.9px;} +.btn-group>.btn-large{font-size:17.5px;} +.btn-group>.btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} +.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} +.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;} +.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;} +.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2;} +.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;} +.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);*padding-top:5px;*padding-bottom:5px;} +.btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px;} +.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px;} +.btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px;} +.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);} +.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6;} +.btn-group.open .btn-primary.dropdown-toggle{background-color:#0044cc;} +.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406;} +.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f;} +.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351;} +.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4;} +.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222222;} +.btn .caret{margin-top:8px;margin-left:0;} +.btn-large .caret{margin-top:6px;} +.btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px;} +.btn-mini .caret,.btn-small .caret{margin-top:8px;} +.dropup .btn-large .caret{border-bottom-width:5px;} +.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;} +.btn-group-vertical{display:inline-block;*display:inline;*zoom:1;} +.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.btn-group-vertical>.btn+.btn{margin-left:0;margin-top:-1px;} +.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;} +.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;} +.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0;} +.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;} +.nav{margin-left:0;margin-bottom:20px;list-style:none;} +.nav>li>a{display:block;} +.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eeeeee;} +.nav>li>a>img{max-width:none;} +.nav>.pull-right{float:right;} +.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;} +.nav li+.nav-header{margin-top:9px;} +.nav-list{padding-left:15px;padding-right:15px;margin-bottom:0;} +.nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);} +.nav-list>li>a{padding:3px 15px;} +.nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;} +.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px;} +.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;} +.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";line-height:0;} +.nav-tabs:after,.nav-pills:after{clear:both;} +.nav-tabs>li,.nav-pills>li{float:left;} +.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;} +.nav-tabs{border-bottom:1px solid #ddd;} +.nav-tabs>li{margin-bottom:-1px;} +.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eeeeee #eeeeee #dddddd;} +.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;} +.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} +.nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#ffffff;background-color:#0088cc;} +.nav-stacked>li{float:none;} +.nav-stacked>li>a{margin-right:0;} +.nav-tabs.nav-stacked{border-bottom:0;} +.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;} +.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} +.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{border-color:#ddd;z-index:2;} +.nav-pills.nav-stacked>li>a{margin-bottom:3px;} +.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;} +.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;} +.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.nav .dropdown-toggle .caret{border-top-color:#0088cc;border-bottom-color:#0088cc;margin-top:6px;} +.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580;} +.nav-tabs .dropdown-toggle .caret{margin-top:8px;} +.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff;} +.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555555;border-bottom-color:#555555;} +.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer;} +.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#ffffff;background-color:#999999;border-color:#999999;} +.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100);} +.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999999;} +.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";line-height:0;} +.tabbable:after{clear:both;} +.tab-content{overflow:auto;} +.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0;} +.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;} +.tab-content>.active,.pill-content>.active{display:block;} +.tabs-below>.nav-tabs{border-top:1px solid #ddd;} +.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0;} +.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-bottom-color:transparent;border-top-color:#ddd;} +.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd;} +.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none;} +.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;} +.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;} +.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} +.tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eeeeee #dddddd #eeeeee #eeeeee;} +.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;} +.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;} +.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eeeeee #eeeeee #eeeeee #dddddd;} +.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;} +.nav>.disabled>a{color:#999999;} +.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;background-color:transparent;cursor:default;} +.navbar{overflow:visible;margin-bottom:20px;*position:relative;*z-index:2;} +.navbar-inner{min-height:40px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top, #ffffff, #f2f2f2);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2));background-image:-webkit-linear-gradient(top, #ffffff, #f2f2f2);background-image:-o-linear-gradient(top, #ffffff, #f2f2f2);background-image:linear-gradient(to bottom, #ffffff, #f2f2f2);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);-moz-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);*zoom:1;}.navbar-inner:before,.navbar-inner:after{display:table;content:"";line-height:0;} +.navbar-inner:after{clear:both;} +.navbar .container{width:auto;} +.nav-collapse.collapse{height:auto;overflow:visible;} +.navbar .brand{float:left;display:block;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777777;text-shadow:0 1px 0 #ffffff;}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none;} +.navbar-text{margin-bottom:0;line-height:40px;color:#777777;} +.navbar-link{color:#777777;}.navbar-link:hover,.navbar-link:focus{color:#333333;} +.navbar .divider-vertical{height:40px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #ffffff;} +.navbar .btn,.navbar .btn-group{margin-top:5px;} +.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0;} +.navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";line-height:0;} +.navbar-form:after{clear:both;} +.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;} +.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0;} +.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;} +.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap;}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0;} +.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0;}.navbar-search .search-query{margin-bottom:0;padding:4px 14px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} +.navbar-static-top{position:static;margin-bottom:0;}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0;} +.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px;} +.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0;} +.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;} +.navbar-fixed-top{top:0;} +.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,.1);box-shadow:0 1px 10px rgba(0,0,0,.1);} +.navbar-fixed-bottom{bottom:0;}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,.1);box-shadow:0 -1px 10px rgba(0,0,0,.1);} +.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;} +.navbar .nav.pull-right{float:right;margin-right:0;} +.navbar .nav>li{float:left;} +.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777777;text-decoration:none;text-shadow:0 1px 0 #ffffff;} +.navbar .nav .dropdown-toggle .caret{margin-top:8px;} +.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333333;text-decoration:none;} +.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);-moz-box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);} +.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#ededed;background-image:-moz-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));background-image:-webkit-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-o-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:linear-gradient(to bottom, #f2f2f2, #e5e5e5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e5e5e5;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#ffffff;background-color:#e5e5e5;*background-color:#d9d9d9;} +.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#cccccc \9;} +.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);} +.btn-navbar .icon-bar+.icon-bar{margin-top:3px;} +.navbar .nav>li>.dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;} +.navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;} +.navbar-fixed-bottom .nav>li>.dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0, 0, 0, 0.2);border-bottom:0;bottom:-7px;top:auto;} +.navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #ffffff;border-bottom:0;bottom:-6px;top:auto;} +.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333333;border-bottom-color:#333333;} +.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{background-color:#e5e5e5;color:#555555;} +.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777777;border-bottom-color:#777777;} +.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555555;border-bottom-color:#555555;} +.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{left:auto;right:0;}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{left:auto;right:12px;} +.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{left:auto;right:13px;} +.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{left:auto;right:100%;margin-left:0;margin-right:-1px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;} +.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top, #222222, #111111);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111));background-image:-webkit-linear-gradient(top, #222222, #111111);background-image:-o-linear-gradient(top, #222222, #111111);background-image:linear-gradient(to bottom, #222222, #111111);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);border-color:#252525;} +.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999999;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#ffffff;} +.navbar-inverse .brand{color:#999999;} +.navbar-inverse .navbar-text{color:#999999;} +.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#ffffff;} +.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#ffffff;background-color:#111111;} +.navbar-inverse .navbar-link{color:#999999;}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#ffffff;} +.navbar-inverse .divider-vertical{border-left-color:#111111;border-right-color:#222222;} +.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{background-color:#111111;color:#ffffff;} +.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;} +.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999999;border-bottom-color:#999999;} +.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;} +.navbar-inverse .navbar-search .search-query{color:#ffffff;background-color:#515151;border-color:#111111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none;}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#cccccc;} +.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#cccccc;} +.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#cccccc;} +.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;} +.navbar-inverse .btn-navbar{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e0e0e;background-image:-moz-linear-gradient(top, #151515, #040404);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));background-image:-webkit-linear-gradient(top, #151515, #040404);background-image:-o-linear-gradient(top, #151515, #040404);background-image:linear-gradient(to bottom, #151515, #040404);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);border-color:#040404 #040404 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#040404;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#ffffff;background-color:#040404;*background-color:#000000;} +.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000000 \9;} +.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.breadcrumb>li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #ffffff;}.breadcrumb>li>.divider{padding:0 5px;color:#ccc;} +.breadcrumb>.active{color:#999999;} +.pagination{margin:20px 0;} +.pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);} +.pagination ul>li{display:inline;} +.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#ffffff;border:1px solid #dddddd;border-left-width:0;} +.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5;} +.pagination ul>.active>a,.pagination ul>.active>span{color:#999999;cursor:default;} +.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999999;background-color:transparent;cursor:default;} +.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} +.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} +.pagination-centered{text-align:center;} +.pagination-right{text-align:right;} +.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px;} +.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;} +.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;} +.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-top-left-radius:3px;-moz-border-radius-topleft:3px;border-top-left-radius:3px;-webkit-border-bottom-left-radius:3px;-moz-border-radius-bottomleft:3px;border-bottom-left-radius:3px;} +.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;-moz-border-radius-topright:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;-moz-border-radius-bottomright:3px;border-bottom-right-radius:3px;} +.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px;} +.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px;} +.pager{margin:20px 0;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";line-height:0;} +.pager:after{clear:both;} +.pager li{display:inline;} +.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} +.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5;} +.pager .next>a,.pager .next>span{float:right;} +.pager .previous>a,.pager .previous>span{float:left;} +.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999999;background-color:#fff;cursor:default;} +.thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";line-height:0;} +.thumbnails:after{clear:both;} +.row-fluid .thumbnails{margin-left:0;} +.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px;} +.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;} +a.thumbnail:hover,a.thumbnail:focus{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);} +.thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;} +.thumbnail .caption{padding:9px;color:#555555;} +.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.alert,.alert h4{color:#c09853;} +.alert h4{margin:0;} +.alert .close{position:relative;top:-2px;right:-21px;line-height:20px;} +.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;} +.alert-success h4{color:#468847;} +.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;} +.alert-danger h4,.alert-error h4{color:#b94a48;} +.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;} +.alert-info h4{color:#3a87ad;} +.alert-block{padding-top:14px;padding-bottom:14px;} +.alert-block>p,.alert-block>ul{margin-bottom:0;} +.alert-block p+p{margin-top:5px;} +@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-o-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(to bottom, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.progress .bar{width:0%;height:100%;color:#ffffff;float:left;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(to bottom, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;} +.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);} +.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;} +.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;} +.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(to bottom, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0);} +.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(to bottom, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0);} +.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(to bottom, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0);} +.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);} +.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eeeeee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px;} +.hero-unit li{line-height:30px;} +.media,.media-body{overflow:hidden;*overflow:visible;zoom:1;} +.media,.media .media{margin-top:15px;} +.media:first-child{margin-top:0;} +.media-object{display:block;} +.media-heading{margin:0 0 5px;} +.media>.pull-left{margin-right:10px;} +.media>.pull-right{margin-left:10px;} +.media-list{margin-left:0;list-style:none;} +.tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);} +.tooltip.top{margin-top:-3px;padding:5px 0;} +.tooltip.right{margin-left:3px;padding:0 5px;} +.tooltip.bottom{margin-top:3px;padding:5px 0;} +.tooltip.left{margin-left:-3px;padding:0 5px;} +.tooltip-inner{max-width:200px;padding:8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid;} +.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000000;} +.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000000;} +.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000000;} +.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000000;} +.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#ffffff;-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);white-space:normal;}.popover.top{margin-top:-10px;} +.popover.right{margin-left:10px;} +.popover.bottom{margin-top:10px;} +.popover.left{margin-left:-10px;} +.popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0;}.popover-title:empty{display:none;} +.popover-content{padding:9px 14px;} +.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid;} +.popover .arrow{border-width:11px;} +.popover .arrow:after{border-width:10px;content:"";} +.popover.top .arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0, 0, 0, 0.25);bottom:-11px;}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#ffffff;} +.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0, 0, 0, 0.25);}.popover.right .arrow:after{left:1px;bottom:-10px;border-left-width:0;border-right-color:#ffffff;} +.popover.bottom .arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0, 0, 0, 0.25);top:-11px;}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#ffffff;} +.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0, 0, 0, 0.25);}.popover.left .arrow:after{right:1px;border-right-width:0;border-left-color:#ffffff;bottom:-10px;} +.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;} +.modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);} +.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;outline:none;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;} +.modal.fade.in{top:10%;} +.modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;} +.modal-header h3{margin:0;line-height:30px;} +.modal-body{position:relative;overflow-y:auto;max-height:400px;padding:15px;} +.modal-form{margin-bottom:0;} +.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";line-height:0;} +.modal-footer:after{clear:both;} +.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0;} +.modal-footer .btn-group .btn+.btn{margin-left:-1px;} +.modal-footer .btn-block+.btn-block{margin-left:0;} +.dropup,.dropdown{position:relative;} +.dropdown-toggle{*margin-bottom:-3px;} +.dropdown-toggle:active,.open .dropdown-toggle{outline:0;} +.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000000;border-right:4px solid transparent;border-left:4px solid transparent;content:"";} +.dropdown .caret{margin-top:8px;margin-left:2px;} +.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#ffffff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;}.dropdown-menu.pull-right{right:0;left:auto;} +.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;} +.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333333;white-space:nowrap;} +.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{text-decoration:none;color:#ffffff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);} +.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#ffffff;text-decoration:none;outline:0;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);} +.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999999;} +.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:default;} +.open{*z-index:1000;}.open>.dropdown-menu{display:block;} +.pull-right>.dropdown-menu{right:0;left:auto;} +.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000000;content:"";} +.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px;} +.dropdown-submenu{position:relative;} +.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;} +.dropdown-submenu:hover>.dropdown-menu{display:block;} +.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0;} +.dropdown-submenu>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#cccccc;margin-top:5px;margin-right:-10px;} +.dropdown-submenu:hover>a:after{border-left-color:#ffffff;} +.dropdown-submenu.pull-left{float:none;}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;} +.dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px;} +.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.accordion{margin-bottom:20px;} +.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.accordion-heading{border-bottom:0;} +.accordion-heading .accordion-toggle{display:block;padding:8px 15px;} +.accordion-toggle{cursor:pointer;} +.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;} +.carousel{position:relative;margin-bottom:20px;line-height:1;} +.carousel-inner{overflow:hidden;width:100%;position:relative;} +.carousel-inner>.item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1;} +.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block;} +.carousel-inner>.active{left:0;} +.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%;} +.carousel-inner>.next{left:100%;} +.carousel-inner>.prev{left:-100%;} +.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0;} +.carousel-inner>.active.left{left:-100%;} +.carousel-inner>.active.right{left:100%;} +.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;} +.carousel-control:hover,.carousel-control:focus{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);} +.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none;}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255, 255, 255, 0.25);border-radius:5px;} +.carousel-indicators .active{background-color:#fff;} +.carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333333;background:rgba(0, 0, 0, 0.75);} +.carousel-caption h4,.carousel-caption p{color:#ffffff;line-height:20px;} +.carousel-caption h4{margin:0 0 5px;} +.carousel-caption p{margin-bottom:0;} +.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);} +.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover,.close:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;filter:alpha(opacity=40);} +button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;} +.pull-right{float:right;} +.pull-left{float:left;} +.hide{display:none;} +.show{display:block;} +.invisible{visibility:hidden;} +.affix{position:fixed;} +.fade{opacity:0;-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;}.fade.in{opacity:1;} +.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;}.collapse.in{height:auto;} +@-ms-viewport{width:device-width;}.hidden{display:none;visibility:hidden;} +.visible-phone{display:none !important;} +.visible-tablet{display:none !important;} +.hidden-desktop{display:none !important;} +.visible-desktop{display:inherit !important;} +@media (min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit !important;} .visible-desktop{display:none !important ;} .visible-tablet{display:inherit !important;} .hidden-tablet{display:none !important;}}@media (max-width:767px){.hidden-desktop{display:inherit !important;} .visible-desktop{display:none !important;} .visible-phone{display:inherit !important;} .hidden-phone{display:none !important;}}.visible-print{display:none !important;} +@media print{.visible-print{display:inherit !important;} .hidden-print{display:none !important;}}@media (max-width:767px){body{padding-left:20px;padding-right:20px;} .navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-left:-20px;margin-right:-20px;} .container-fluid{padding:0;} .dl-horizontal dt{float:none;clear:none;width:auto;text-align:left;} .dl-horizontal dd{margin-left:0;} .container{width:auto;} .row-fluid{width:100%;} .row,.thumbnails{margin-left:0;} .thumbnails>li{float:none;margin-left:0;} [class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{float:none;display:block;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .row-fluid [class*="offset"]:first-child{margin-left:0;} .input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto;} .controls-row [class*="span"]+[class*="span"]{margin-left:0;} .modal{position:fixed;top:20px;left:20px;right:20px;width:auto;margin:0;}.modal.fade{top:-100px;} .modal.fade.in{top:20px;}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0);} .page-header h1 small{display:block;line-height:20px;} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc;} .form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left;} .form-horizontal .controls{margin-left:0;} .form-horizontal .control-list{padding-top:0;} .form-horizontal .form-actions{padding-left:10px;padding-right:10px;} .media .pull-left,.media .pull-right{float:none;display:block;margin-bottom:10px;} .media-object{margin-right:0;margin-left:0;} .modal{top:10px;left:10px;right:10px;} .modal-header .close{padding:10px;margin:-10px;} .carousel-caption{position:static;}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} .row:after{clear:both;} [class*="span"]{float:left;min-height:1px;margin-left:20px;} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px;} .span12{width:724px;} .span11{width:662px;} .span10{width:600px;} .span9{width:538px;} .span8{width:476px;} .span7{width:414px;} .span6{width:352px;} .span5{width:290px;} .span4{width:228px;} .span3{width:166px;} .span2{width:104px;} .span1{width:42px;} .offset12{margin-left:764px;} .offset11{margin-left:702px;} .offset10{margin-left:640px;} .offset9{margin-left:578px;} .offset8{margin-left:516px;} .offset7{margin-left:454px;} .offset6{margin-left:392px;} .offset5{margin-left:330px;} .offset4{margin-left:268px;} .offset3{margin-left:206px;} .offset2{margin-left:144px;} .offset1{margin-left:82px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} .row-fluid:after{clear:both;} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;} .row-fluid [class*="span"]:first-child{margin-left:0;} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%;} .row-fluid .span12{width:100%;*width:99.94680851063829%;} .row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%;} .row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%;} .row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%;} .row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%;} .row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%;} .row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%;} .row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%;} .row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%;} .row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%;} .row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%;} .row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%;} .row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%;} .row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%;} .row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%;} .row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%;} .row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%;} .row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%;} .row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%;} .row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%;} .row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%;} .row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%;} .row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%;} .row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%;} .row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%;} .row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%;} .row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%;} .row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%;} .row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%;} .row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%;} .row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%;} .row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%;} .row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%;} .row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%;} .row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%;} .row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%;} input,textarea,.uneditable-input{margin-left:0;} .controls-row [class*="span"]+[class*="span"]{margin-left:20px;} input.span12,textarea.span12,.uneditable-input.span12{width:710px;} input.span11,textarea.span11,.uneditable-input.span11{width:648px;} input.span10,textarea.span10,.uneditable-input.span10{width:586px;} input.span9,textarea.span9,.uneditable-input.span9{width:524px;} input.span8,textarea.span8,.uneditable-input.span8{width:462px;} input.span7,textarea.span7,.uneditable-input.span7{width:400px;} input.span6,textarea.span6,.uneditable-input.span6{width:338px;} input.span5,textarea.span5,.uneditable-input.span5{width:276px;} input.span4,textarea.span4,.uneditable-input.span4{width:214px;} input.span3,textarea.span3,.uneditable-input.span3{width:152px;} input.span2,textarea.span2,.uneditable-input.span2{width:90px;} input.span1,textarea.span1,.uneditable-input.span1{width:28px;}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} .row:after{clear:both;} [class*="span"]{float:left;min-height:1px;margin-left:30px;} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px;} .span12{width:1170px;} .span11{width:1070px;} .span10{width:970px;} .span9{width:870px;} .span8{width:770px;} .span7{width:670px;} .span6{width:570px;} .span5{width:470px;} .span4{width:370px;} .span3{width:270px;} .span2{width:170px;} .span1{width:70px;} .offset12{margin-left:1230px;} .offset11{margin-left:1130px;} .offset10{margin-left:1030px;} .offset9{margin-left:930px;} .offset8{margin-left:830px;} .offset7{margin-left:730px;} .offset6{margin-left:630px;} .offset5{margin-left:530px;} .offset4{margin-left:430px;} .offset3{margin-left:330px;} .offset2{margin-left:230px;} .offset1{margin-left:130px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} .row-fluid:after{clear:both;} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;} .row-fluid [class*="span"]:first-child{margin-left:0;} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%;} .row-fluid .span12{width:100%;*width:99.94680851063829%;} .row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%;} .row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%;} .row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%;} .row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%;} .row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%;} .row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%;} .row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%;} .row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%;} .row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%;} .row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%;} .row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%;} .row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%;} .row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%;} .row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%;} .row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%;} .row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%;} .row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%;} .row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%;} .row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%;} .row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%;} .row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%;} .row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%;} .row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%;} .row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%;} .row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%;} .row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%;} .row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%;} .row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%;} .row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%;} .row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%;} .row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%;} .row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%;} .row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%;} .row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%;} .row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%;} input,textarea,.uneditable-input{margin-left:0;} .controls-row [class*="span"]+[class*="span"]{margin-left:30px;} input.span12,textarea.span12,.uneditable-input.span12{width:1156px;} input.span11,textarea.span11,.uneditable-input.span11{width:1056px;} input.span10,textarea.span10,.uneditable-input.span10{width:956px;} input.span9,textarea.span9,.uneditable-input.span9{width:856px;} input.span8,textarea.span8,.uneditable-input.span8{width:756px;} input.span7,textarea.span7,.uneditable-input.span7{width:656px;} input.span6,textarea.span6,.uneditable-input.span6{width:556px;} input.span5,textarea.span5,.uneditable-input.span5{width:456px;} input.span4,textarea.span4,.uneditable-input.span4{width:356px;} input.span3,textarea.span3,.uneditable-input.span3{width:256px;} input.span2,textarea.span2,.uneditable-input.span2{width:156px;} input.span1,textarea.span1,.uneditable-input.span1{width:56px;} .thumbnails{margin-left:-30px;} .thumbnails>li{margin-left:30px;} .row-fluid .thumbnails{margin-left:0;}}@media (max-width:979px){body{padding-top:0;} .navbar-fixed-top,.navbar-fixed-bottom{position:static;} .navbar-fixed-top{margin-bottom:20px;} .navbar-fixed-bottom{margin-top:20px;} .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px;} .navbar .container{width:auto;padding:0;} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px;} .nav-collapse{clear:both;} .nav-collapse .nav{float:none;margin:0 0 10px;} .nav-collapse .nav>li{float:none;} .nav-collapse .nav>li>a{margin-bottom:2px;} .nav-collapse .nav>.divider-vertical{display:none;} .nav-collapse .nav .nav-header{color:#777777;text-shadow:none;} .nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} .nav-collapse .dropdown-menu li+li a{margin-bottom:2px;} .nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2;} .navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999999;} .navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111111;} .nav-collapse.in .btn-group{margin-top:5px;padding:0;} .nav-collapse .dropdown-menu{position:static;top:auto;left:auto;float:none;display:none;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} .nav-collapse .open>.dropdown-menu{display:block;} .nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none;} .nav-collapse .dropdown-menu .divider{display:none;} .nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none;} .nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);} .navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111111;border-bottom-color:#111111;} .navbar .nav-collapse .nav.pull-right{float:none;margin-left:0;} .nav-collapse,.nav-collapse.collapse{overflow:hidden;height:0;} .navbar .btn-navbar{display:block;} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px;}}@media (min-width:980px){.nav-collapse.collapse{height:auto !important;overflow:visible !important;}} diff --git a/template/test/css.php b/template/test/css.php new file mode 100755 index 0000000..37a8f18 --- /dev/null +++ b/template/test/css.php @@ -0,0 +1,246 @@ +git checkout main + +#pbody { + min-height: 100%; + position: relative; + width: 100%; + margin: 0px 0%; + background-image:url(/img/gor.jpg); + background-size: 430px 100%; + background-repeat:repeat-y; + top:0px; + } + +#pbody a{ + font-weight :bold; +/* +*/ + } + + +#head { + height: 150px; + left:-1px; + top:-1px; + width: 100%; + position: relative; + background-image: url(/img/head.jpg); + background-size: 100% 150px; + } + +#slogo{ + left: 0px; + top:0px;/*-1*/ + float: left; + position: relative; + width: 450px; + height: 150px; + background-image: url(/img/rpi_logo.jpg); + background-repeat: no-repeat; + background-size: 100% 150px; + padding-right: 0px; + } + +#sname{ + width:200px; + height: 37px; + overflow: hidden; + position: relative; + background-repeat: no-repeat; + top: 40px; + } + +#sslogan{ + position: relative; + overflow: hidden; + text-align: left; + top: 80px; + } + +#hmemo{ + position: relative; + top: 40px; + width: 150px; + height: 99px; + float: right; + padding-left: -55px; + background-image: url(/img/rpi.gif); + background-repeat: no-repeat; + background-size: 100% 100px; + padding-right: 25px; + } + +#hmenu{ + text-align :center; + top: 50px; + left:15%; + position: absolute; + width: 70%; + height: 30px; +/* + font-family: serif; + color: #666; +*/ + font-family : Arial, Tahoma, Verdana, sans-serif; + text-shadow: 1px 1px 3px #666, -1px -1px 3px #FFF, 1px 1px #666, -1px -1px #FFF; + font-size: 20px; + } + +#hmenu a{ + color: #000; + text-shadow: 1px 1px 3px #666, + -1px -1px 3px #FFF, + 1px 1px #666, + -1px -1px #FFF; + text-decoration: none; + } + +#hmenu a:hover{ + color: rgb(100,100,100); + text-shadow: -1px -1px #666, + 1px 1px #FFF; + } + +#smap{ + text-align :center; + position: relative; + margin: 0 auto; + margin-top:5px; + width: 99%; + height: 20px; + } + +#smap a{ + text-decoration: none; + } + +#cont{ + width: 90%; + margin: 0 auto; + } + +.bcont{ + padding: 15px; + } + +#left-float, +#right-float, +.center-float { + padding: 5px; + text-align: left; + } + +#left-float { + float: left; +} +#right-float { + float: right; +} +#left-float:empty, +#right-float:empty { + width: 0px; +} +#left-float:not(:empty), +#right-float:not(:empty) { + width: 200px; +} + +.center-float { + float: none; + width: auto; + overflow: hidden; + } + +.bfloat{ + overflow-x: hidden; +/* + padding :5px; + margin :5px; +*/ + border: 1px solid #f44180; + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + border-radius: 0 0 10px 10px; + } + +/* + -webkit-box-shadow: 5px 5px 5px #222; + -moz-box-shadow: 5px 5px 5px #222; + box-shadow: 0px 0px 5px #111; + } +*/ + +.bfloat, +.btitle{ +white-space: normal; +word-wrap: break-word; +/* + -webkit-box-shadow: 5px 5px 5px #222; + -moz-box-shadow: 5px 5px 5px #222; +*/ + box-shadow: 0px 0px 5px #777; + } + +.bfloat a{ + text-decoration: none; + } +/* +*/ + +.cfloat{ + left: -1px; + top: -1px; + position: relative; + width: 100%; + height: auto; + } + +.btitle{ +white-space: normal; +word-wrap: break-word; + left: -1px; + top: -1px; + position: relative; + width: calc(100% + 2px); + text-align: center; + line-height: 30px; + font-weight: bold; + color: #ffffff; + background-image: url(/img/menu_7.jpg); + background-size: 100% 100% ; + border-radius: 10px 10px 0 0; + } + +.ctitle{ + left: 0px; + top: -1px; + position: relative; + width: 100%; + height: 20px; + text-align: center; + line-height: 20px; + font-weight: bold; + } +.cctitle{ + left: 0px; + top: -1px; + margin-top: -4px; + position: relative; + width: 100%; + height: 0px; + line-height: 00px; + } +.youtubef{ + max-width:100%; + width:650px; + height:360px; + { + diff --git a/template/test/page.php b/template/test/page.php new file mode 100755 index 0000000..0a1c3d3 --- /dev/null +++ b/template/test/page.php @@ -0,0 +1,35 @@ +
+ +
+
+ %smap% +
+ +
+ %left% + %right% +
+
+ %title% +
+
+
%content%
+
+
+
+ +
\ No newline at end of file diff --git a/template/test/raspcontrol.css b/template/test/raspcontrol.css new file mode 100755 index 0000000..bce4e39 --- /dev/null +++ b/template/test/raspcontrol.css @@ -0,0 +1,179 @@ +/* + * Commun style + */ + +.container, .navbar .container { + max-width: 650px; +} + + +.center { + text-align: center; +} + +/* + * Header + */ + +header { + margin: 0; + height: 140px; + color: #fff; + background: #464646; + background: -moz-linear-gradient(top,#464646 0%,#303130 100%); + background: -webkit-gradient(linear,left top,left bottom,color-stop(0%,#464646),color-stop(100%,#303130)); + background: -webkit-linear-gradient(top,#464646 0%,#303130 100%); + background: -o-linear-gradient(top,#464646 0%,#303130 100%); + background: -ms-linear-gradient(top,#464646 0%,#303130 100%); + background: linear-gradient(to bottom,#464646 0%,#303130 100%); +} + +header h1 { + margin: 32px 0 -10px 0; + font-size: 40px; + font-weight: normal; + letter-spacing: 0px; +} + +header a, +header a:hover, +header a:focus { + color: #fff; + text-decoration: none; +} +header a:hover { + color: #ededed; +} + +header h2 { + margin: 0; + font-size: 16px; + font-weight: normal; + color: #aaa; +} + +header img { + float: left; + margin: 15px 0 0 0; +} + +/* + * Pages + */ + +.form-login { + margin: 20px 0 60px 0; +} +.form-login input { + margin-bottom: 10px; +} + +.details table { + width: 100%; +} +.details tr { + vertical-align: top; + /*border-bottom: 1px solid #dedede;*/ +} +.details td { + padding: 20px 0; +} +.details td.check { + font-weight: bold; + min-width: 100px; +} +.details td.icon { + min-width: 25px; + padding-left: 10px; + padding-right: 20px; +} +.details .storage td { + padding: 15px 0; +} + +.details .progress { + margin-bottom: 8px; +} +.details .storage .progress { + margin-top: 10px; +} + +.rapid-status div { + margin-top: 20px; +} +.infos div { + margin-bottom: 20px; +} + + +/* + * Footer + */ + +footer { + margin:0; + padding: 30px 0 0 0; + color: #fff; + background: #464646; + background: -moz-linear-gradient(top,#464646 0%,#303130 100%); + background: -webkit-gradient(linear,left top,left bottom,color-stop(0%,#464646),color-stop(100%,#303130)); + background: -webkit-linear-gradient(top,#464646 0%,#303130 100%); + background: -o-linear-gradient(top,#464646 0%,#303130 100%); + background: -ms-linear-gradient(top,#464646 0%,#303130 100%); + background: linear-gradient(to bottom,#464646 0%,#303130 100%); + height: 80px; +} + +footer p { + margin: 0; +} +footer a { + color: #ccc; +} +footer a:hover { + color: #fff; +} + +/* + * Mediaqueries + */ +@media (max-width: 770px) { + body { + margin: 0; + padding: 0; + } + .container, + .progress { + max-width: 100% !important; + } + .navbar { + width: 100% !important; + margin-left: 0 !important; + } + header img { + display: none; + } + header { + padding: 0 10px 0 20px; + height: 120px; + } + footer { + padding-top: 20px; + padding-left: 20px; + padding-right: 20px; + } +} + +/* + * Bootstrap override + */ +.popover { + width: 650px; + max-width: 650px; +} +.infos div .popover-content { + margin-bottom: 0px; +} +.popover-content table { + margin-bottom: 0px; +}