nfmzkvmx
Junior Member | Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору Готовая кнопка (Кнопка уже не влазит в пост, поэтому ссылкой.) Либо отдельно: Код для секции "Инициализация": Код: ((bmsHndlr, listener, popupListener) => { 'use strict'; this._handleClick = () => Services.ww.openWindow(null, xul(), '', f, null); const escapeXMLChr = str => str.replace(/["'<>&]/g, m => ({'"': '"', '\'': ''', '<': '<', '>': '>', '&': '&'})[m]), f = 'chrome,titlebar,toolbar,centerscreen,modal=no,resizable', xul = (() => 'data:application/vnd.mozilla.xul+xml,' + encodeURIComponent(this.Help.split('\n\n')[0].trim().replace('_buttonId', _id) .replace('_title', escapeXMLChr(this.label)))), prefs = { PTPref: 'CB.Places-Tooltips.enabled', addBmHere: 'CB.Places-Tooltips.dblclick-add-bm-to-folder.enabled', tagging: 'CB.Places-Tooltips.tagging.enabled', saveSel: 'CB.Places-Tooltips.save-selected-text.enabled', editXtraProps: 'CB.Places-Tooltips.extra-properties.enabled', hideDefProps: 'CB.Places-Tooltips.hide-default-properties', goPrntFldr: 'CB.Places-Tooltips.goParentFolder.enabled' }, observer = { observe(win) { win.addEventListener('load', this, false); }, handleEvent(e) { let win = e ? e.target.defaultView : content.document.defaultView; win.removeEventListener('load', this, false); if (win.location != 'chrome://browser/content/places/places.xul') return; win.addEventListener('popupshowing', popupListener, false); addDestructor(() => win.removeEventListener('popupshowing', popupListener, false)) } }; if (!cbu.getPrefs(prefs.PTPref)) return; for(let pref of Object.values(prefs)) cbu.isPref(pref, false); if (cbu.getPrefs(prefs.addBmHere)) { window.addEventListener('dblclick', listener, false); addDestructor(() => window.removeEventListener('dblclick', listener, false)) }; if (cbu.getPrefs(prefs.editXtraProps) || cbu.getPrefs(prefs.goPrntFldr)) { window.addEventListener('popupshowing', popupListener, false); Services.obs.addObserver(observer, 'domwindowopened', false); addDestructor(() => { window.removeEventListener('popupshowing', popupListener, false) Services.obs.removeObserver(observer, 'domwindowopened', false) }) }; const tltpXItms = { 'CB.Places-Tooltips.show-date-add': '\n var tltpAdded = aDocument.getElementById("CB.Places-Tooltips.date-add"),\n add = node.dateAdded;\n if (!tltpAdded) {\n tltpAdded = box.appendChild(document.createElement("label"));\n tltpAdded.className = "tooltip-label cb-pltltp-extra-item";\n tltpAdded.id = "CB.Places-Tooltips.date-add";\n };\n tltpAdded.hidden = !add;\n if (!tltpAdded.hidden)\n tltpAdded.textContent = "Добавлено:\\t\\t" + formatDate(add);\n', 'CB.Places-Tooltips.show-date-modified': '\n var tltpMd = aDocument.getElementById("CB.Places-Tooltips.date-modified"),\n md = node.lastModified;\n if (!tltpMd) {\n tltpMd = box.appendChild(document.createElement("label"));\n tltpMd.className = "tooltip-label cb-pltltp-extra-item";\n tltpMd.id = "CB.Places-Tooltips.date-modified";\n };\n tltpMd.hidden = !md;\n if (!tltpMd.hidden)\n tltpMd.textContent = "Изменено:\\t\\t" + formatDate(md);\n', 'CB.Places-Tooltips.show-date-last-visit': '\n var tltpLst = aDocument.getElementById("CB.Places-Tooltips.last-visit"),\n tm = node.time;\n if (!tltpLst) {\n tltpLst = box.appendChild(document.createElement("label"));\n tltpLst.className = "tooltip-label cb-pltltp-extra-item";\n tltpLst.id = "CB.Places-Tooltips.last-visit";\n };\n tltpLst.hidden = !tm;\n if (!tltpLst.hidden)\n tltpLst.textContent = "Посещено:\\t\\t" + formatDate(tm);\n', 'CB.Places-Tooltips.show-visits': '\n var tltpVsts = aDocument.getElementById("CB.Places-Tooltips.visits"),\n cnt = node.accessCount;\n if (!tltpVsts) {\n tltpVsts = box.appendChild(document.createElement("label"));\n tltpVsts.className = "tooltip-label cb-pltltp-extra-item";\n tltpVsts.id = "CB.Places-Tooltips.visits";\n };\n tltpVsts.hidden = !cnt;\n if (!tltpVsts.hidden)\n tltpVsts.textContent = "Посещений:\\t\\t" + cnt;\n', 'CB.Places-Tooltips.show-tags': '\n var tltpTgs = aDocument.getElementById("CB.Places-Tooltips.tags"),\n tgs = node.tags;\n if (!tltpTgs) {\n tltpTgs = box.appendChild(document.createElement("label"));\n tltpTgs.className = "tooltip-label cb-pltltp-extra-item";\n tltpTgs.id = "CB.Places-Tooltips.tags";\n };\n tltpTgs.hidden = !tgs;\n if (!tltpTgs.hidden)\n tltpTgs.textContent = "Метки:\\t\\t\\t" + tgs;\n', 'CB.Places-Tooltips.show-keywords': '\n var tltpKs = aDocument.getElementById("CB.Places-Tooltips.keywords"),\n ks;\n if (!tltpKs) {\n tltpKs = box.appendChild(document.createElement("label"));\n tltpKs.className = "tooltip-label cb-pltltp-extra-item";\n tltpKs.id = "CB.Places-Tooltips.keywords";\n };\n try {ks = plBms.getKeywordForBookmark(nId)} catch(ex) {};\n tltpKs.hidden = !ks;\n if (!tltpKs.hidden)\n tltpKs.textContent = "Ключевые слова:\\t\\t" + ks;\n', 'CB.Places-Tooltips.show-inWhichFolder': '\n var getFolders = ((arr, ids) => {\n var crntNdFldrId = getFldrId(nId),\n crntNdFldr = getFldrTtl(crntNdFldrId);\n if (!ids.length) return crntNdFldr ? crntNdFldr : false;\n for(let id of ids) {\n var fldrId = getFldrId(id),\n fldr = getFldrTtl(fldrId);\n fldr && fldr != crntNdFldr && arr.push(fldr)\n };\n if (!arr.length) return crntNdFldr ? crntNdFldr : false;\n return crntNdFldr + " (" + arr.join(", ") + ")";\n })([], getIds().filter(id => id != nId));\n\n var tltpFolders = aDocument.getElementById("CB.Places-Tooltips.inWhichFolder");\n if (!tltpFolders) {\n tltpFolders = box.appendChild(document.createElement("label"));\n tltpFolders.className = "tooltip-label cb-pltltp-extra-item";\n tltpFolders.id = "CB.Places-Tooltips.inWhichFolder";\n };\n tltpFolders.hidden = !getFolders;\n if (!tltpFolders.hidden)\n tltpFolders.textContent = "Папки:\\t\\t\\t" + getFolders;\n', 'CB.Places-Tooltips.show-descriptions': '\n var desk = ((arr, ids) => {\n ids = getIds();\n if (!(ids && ids.length)) return false;\n for(var id of ids) {\n var descs = pl.getAnnotationsForItem(id);\n if (descs && !!descs.length) {\n for(var desc of descs) {\n let str;\n if (desc.value) {\n switch (desc.name) {\n case "bookmarkProperties/description":\n str = "Описание:\\t\\t" + desc.value;\n break;\n case "bookmarkProperties/loadInSidebar":\n str = "У закладки установлен флаг \\"Открывать в сайдбаре\\"";\n break;\n default:\n str = desc.name + "\\t\\t\\t" + desc.value;\n }\n arr.push(str);\n }\n }\n arr.push(undefined)\n }\n }\n return !!arr.length && arr.join("\\n");\n })([]);\n\n var tltpDesk = aDocument.getElementById("CB.Places-Tooltips.descriptions");\n if (!tltpDesk) {\n tltpDesk = box.appendChild(document.createElement("label"));\n tltpDesk.className = "tooltip-label cb-pltltp-extra-item";\n tltpDesk.id = "CB.Places-Tooltips.descriptions";\n };\n tltpDesk.hidden = !desk;\n if (!tltpDesk.hidden)\n tltpDesk.textContent = "Комментарии:\\n" + desk;\n' }; let oldStr = bmsHndlr.toString(), tmpStr = '\n var nId = node.itemId,\n box = aDocument.getElementById("bhTooltipTextBox"),\n pl = PlacesUtils,\n plBms = pl.bookmarks,\n formatDate = int => new Date(int / 1000).toLocaleString(),\n getIds = uri => {\n try {\n uri = Services.uriFixup.createFixupURI(url, 0);\n }\n catch(ex) {}\n finally {\n return uri ? pl.getBookmarksForURI(uri) : false\n }\n },\n getFldrId = id => {try {return plBms.getFolderIdForItem(id)} catch(ex) {}},\n getFldrTtl = id => {try {return plBms.getItemTitle(id)} catch(ex) {}};\n', newstr; for(let prop in tltpXItms) { cbu.isPref(prop, false); cbu.getPrefs(prop) && (tmpStr += tltpXItms[prop]); }; newstr = oldStr.slice(oldStr.indexOf('{') + 1, oldStr.lastIndexOf('}')) .split(/(?=\n.+\n\s+return true)/).join(tmpStr); window.top.BookmarksEventHandler.fillInBHTooltip = new Function('aDocument', 'aEvent', newstr); addDestructor(() => { for(let node of [...document.getElementsByClassName('cb-pltltp-extra-item')] .concat([...SidebarUI.browser.contentDocument.getElementsByClassName('cb-pltltp-extra-item')])) node.remove(); window.top.BookmarksEventHandler.fillInBHTooltip = bmsHndlr; }) })( window.top.BookmarksEventHandler.fillInBHTooltip, { plUtls: PlacesUtils, plUIUtls: PlacesUIUtils, alertS: Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService), crop(str) { typeof str != 'string' && (str = str.toString()); return str.length > 45 ? [str.substr(0,20), str.substr(-20)].join('...') : str }, wrap(str) { typeof str != 'string' && (str = str.toString()); return str.match(/.{1,60}/g).map((sub, inx, arr) => (inx < arr.length - 1) ? sub.replace(/ (?=[^ ]*$)/, '\n') : sub).join('') }, slider(img, title, txt) { return this.alertS.showAlertNotification(img, this.crop(title), this.wrap(txt), false, '', null, '') }, getBmId(uri, id) { try {id = this.plUtls.getMostRecentBookmarkForURI(uri)} catch(ex) {} finally { return id ? id : null } }, getSel(doc) { return doc.getSelection().toString().trim() }, setDesks(uri, key, val) { let id = this.getBmId(uri); return val && this.plUtls.setAnnotationsForItem(id, [{name: key, value: val}]) }, setTags(doc, uri) { let kwrds = doc.head.querySelector('meta[name="Keywords"]'); if (kwrds && kwrds.content.length) return this.plUtls.tagging.tagURI(uri, kwrds.content.split(/\s+/g)); }, handleEvent(e) { let targ = e.originalTarget, riskyTags = ['menu', 'treechildren', 'toolbarbutton']; if (e.button != 0 || riskyTags.indexOf(targ.localName) == -1) return; let node = targ._placesNode; if (targ.localName == 'treechildren') { let tree = targ.parentNode, tbo = tree.treeBoxObject, cell = tbo.getCellAt(e.clientX, e.clientY); if (cell.row == -1) return; node = tree.view.nodeForTreeIndex(cell.row); }; if (!node || !this.plUtls.nodeIsFolder(node)) return; e.preventDefault(); e.stopPropagation(); let br = window.gBrowser.selectedBrowser.contentWindow, doc = br.content.document, loc = doc.location, ttl = this.plUIUtls.getBestTitle(doc), fldId = this.plUtls.getConcreteItemId(node), fldTtl = this.plUtls.bookmarks.getItemTitle(fldId), uri = Services.uriFixup.createFixupURI(loc.href, 0), obj = { 'bookmarkProperties/description': this.plUIUtls.getDescriptionFromDocument(doc), 'Текст:': cbu.getPrefs('CB.Places-Tooltips.save-selected-text.enabled') && this.getSel(doc) }; try { this.plUtls.bookmarks.insertBookmark(fldId, uri, 0, ttl) } catch(ex) { return this.slider('chrome://browser/skin/warning.svg', 'Не удалось добавить закладку!', this.wrap(ex)); }; for(let prop in obj) this.setDesks(uri, prop, obj[prop]); cbu.getPrefs('CB.Places-Tooltips.tagging.enabled') && this.setTags(doc, uri); this.slider(gBrowser.mCurrentTab.image || 'chrome://mozapps/skin/places/defaultFavicon.png', this.crop(ttl), 'Добавлено в папку: ' + fldTtl); } }, { plProps: { bmId: null, bmTtl: null, bmURL: null, bmAdd: null, bmMod: null, bmVst: null, bmCnt: null, bmTgs: null, node: null, }, f: 'chrome,titlebar,toolbar,centerscreen,modal=no,resizable', plUtls: PlacesUtils, formatDate(int) { return int && new Date(int / 1000).toLocaleString() }, escapeXMLChr(str) { return str.replace(/["'<>&]/g, m => ({'"': '"', '\'': ''', '<': '<', '>': '>', '&': '&'})[m]) }, box() { let xul = 'data:application/vnd.mozilla.xul+xml,' + encodeURIComponent(self.Help.split('\n\n')[1].trim() .replace(/_bmId|_title|_bmURL|_bmAdd|_bmMod|_bmVst|_bmCnt|_bmTgs/g , m => ({'_bmId': this.plProps.bmId , '_title': this.plProps.bmTtl || "" , '_bmURL': this.plProps.bmURL || "" , '_bmAdd': this.plProps.bmAdd || "" , '_bmMod': this.plProps.bmMod || "" , '_bmVst': this.plProps.bmVst || "" , '_bmCnt': this.plProps.bmCnt || "" , '_bmTgs': this.plProps.bmTgs || "" })[m]) ); return xul }, shouldShow() { return (this.plProps.node && this.plUtls.nodeIsBookmark(this.plProps.node) && this.plProps.bmId) }, cnItems(popup) { let isBm = this.shouldShow(), doc = popup.ownerDocument; if (cbu.getPrefs('CB.Places-Tooltips.extra-properties.enabled')) { let editXtraProps = doc.getElementById('CB.Places-Tooltips.extra-properties'); if (!editXtraProps) { editXtraProps = popup.appendChild(document.createElement('menuitem')); editXtraProps.id = 'CB.Places-Tooltips.extra-properties'; editXtraProps.setAttribute("label", 'Свойства+'); editXtraProps.onclick = () => this.showDlg(); addDestructor(() => editXtraProps.remove()) } cbu.getPrefs('CB.Places-Tooltips.hide-default-properties') && (doc.getElementById('placesContext_show:info').collapsed = true); editXtraProps.hidden = editXtraProps.disabled = !isBm; } if (cbu.getPrefs('CB.Places-Tooltips.goParentFolder.enabled')) { let goPrntFldr = doc.getElementById('CB.Places-Tooltips.goParentFolder'); if (!goPrntFldr) { goPrntFldr = popup.insertBefore(document.createElement('menuitem'), doc.getElementById('placesContext_editSeparator')); goPrntFldr.id = "CB.Places-Tooltips.goParentFolder"; goPrntFldr.setAttribute("label", 'Go Parent Folder'); goPrntFldr.onclick = () => this.goPrntFldr(popup, doc, this.plProps.bmId); addDestructor(() => goPrntFldr.remove()) } goPrntFldr.hidden = goPrntFldr.disabled = !(isBm && doc.documentElement.id && (doc.documentElement.id == 'bookmarksPanel' || doc.documentElement.id == 'places')); } }, showDlg() { return Services.ww.openWindow(null, this.box(), '', this.f, null) }, goPrntFldr(popup, doc, bmId) { let view = popup._view, id = bmId, vis = tree => { let pos = 0.5, tbo = tree.treeBoxObject, ind = tbo.view.selection.currentIndex, first = tbo.getFirstVisibleRow(), visibleRows = tbo.height/tbo.rowHeight, newFirst = ind - pos*visibleRows + 1; tbo.scrollByLines(Math.round(newFirst - first)); }, sel = (view, id) => { let str = "node.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER", src = view.selectItems.toString(), code = src.replace(str + ";", "(" + str + " || " + str + "_SHORTCUT);"); view.place = view.place; eval("(" + code + ")").bind(view)([id]); vis(view); }; if (view.id == "placeContent") { let plView = doc.getElementById("placesList"), parentId = PlacesUtils.bookmarks.getFolderIdForItem(id); sel(plView, parentId); setTimeout(() => {view.selectItems([id]); vis(view);}, 100); } else sel(view, id); }, handleEvent(e) { if (!(e.target.id && e.target.id == 'placesContext')) return; for(let key of Object.keys(this.plProps)) delete this.plProps[key]; let popup = e.target, trNode = popup.triggerNode, node = trNode._placesNode; if (trNode.localName == 'treechildren') { let tree = trNode.parentNode, tbo = tree.treeBoxObject, cell = tbo.getCellAt(e.clientX, e.clientY); if (cell.row == -1) return; node = tree.view.nodeForTreeIndex(cell.row); }; node && Object.assign(this.plProps , {node: node} , {bmId: node.itemId} , {bmTtl: this.escapeXMLChr(node.title)} , {bmURL: this.escapeXMLChr(node.uri)} , {bmAdd: this.formatDate(node.dateAdded)} , {bmMod: this.formatDate(node.lastModified)} , {bmVst: this.formatDate(node.time)} , {bmCnt: node.accessCount} , {bmTgs: node.tags} ); this.cnItems(popup) } } ); | Для секции "Справка": Код: <?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" title = "_title" autosize="true" id="PlacesTooltipsOptions" onload="onLoad()" onunload="onUnload()"> <prefpane id="options" label="Настройки показа подсказок закладок"> <preferences> <preference name="CB.Places-Tooltips.enabled" id="state" type="bool" onchange="toggleState(this.value)"/> <preference name="CB.Places-Tooltips.dblclick-add-bm-to-folder.enabled" id="addBmToFolder" type="bool" onchange="toggleState(this.previousElementSibling.value)"/> <preference name="CB.Places-Tooltips.tagging.enabled" id="tagging" type="bool"/> <preference name="CB.Places-Tooltips.show-date-add" id="add" type="bool"/> <preference name="CB.Places-Tooltips.show-date-modified" id="modified" type="bool"/> <preference name="CB.Places-Tooltips.show-date-last-visit" id="last" type="bool"/> <preference name="CB.Places-Tooltips.show-visits" id="visits" type="bool"/> <preference name="CB.Places-Tooltips.show-tags" id="tags" type="bool"/> <preference name="CB.Places-Tooltips.show-keywords" id="keywords" type="bool"/> <preference name="CB.Places-Tooltips.show-inWhichFolder" id="folders" type="bool"/> <preference name="CB.Places-Tooltips.save-selected-text.enabled" id="savesel" type="bool"/> <preference name="CB.Places-Tooltips.extra-properties.enabled" id="edit" type="bool" onchange="!this.value && (this.nextElementSibling.value = this.value); toggleState();"/> <preference name="CB.Places-Tooltips.hide-default-properties" id="hide" type="bool"/> <preference name="CB.Places-Tooltips.goParentFolder.enabled" id="goPrntFldr" type="bool"/> <preference name="CB.Places-Tooltips.show-descriptions" id="descriptions" type="bool"/> </preferences> <groupbox> <caption> <checkbox class="header" label="Включить Places Tooltips" preference="state"/> </caption> <vbox style="padding: 5px 20px;" align="start"> <checkbox label="Показывать дату добавления" preference="add"/> <checkbox label="Показывать дату изменения" preference="modified"/> <checkbox label="Показывать дату последнего посещения" preference="last"/> <checkbox label="Показывать колличество посещений" preference="visits"/> <checkbox label="Показывать метки" preference="tags"/> <checkbox label="Показывать ключевые слова" preference="keywords"/> <checkbox label="Показывать папки закладок" preference="folders"/> <checkbox label="Показывать описания" preference="descriptions"/> <groupbox style="padding: 0 20px;"> <caption class="header" label="Дополнительно:"/> <checkbox label="Пункт меню "Go Parent Folder", для перехода в родительскуб папку закладки" preference="goPrntFldr"/> <groupbox> <caption> <checkbox class="header" id="editchck" label="Пункт меню закладок для редактирования свойств и доп. описаний" preference="edit"/> </caption> <checkbox id="hidechck" label="Скрыть дефолтный пункт редактирования свойств закладок" style="padding-inline-start: 20px;" preference="hide"/> </groupbox> <groupbox> <caption> <checkbox class="header" label="Включить добавление закладки в папку по двойному клику на ней" preference="addBmToFolder"/> </caption> <vbox id="extra" style="padding: 0 20px;" align="start"> <checkbox label="Сохранять выделенный текст в дополнительном описании" preference="savesel"/> <checkbox label="Добавлять теги, взятые из ключевых слов заголовка страницы" preference="tagging"/> </vbox> </groupbox> </groupbox> </vbox> </groupbox> </prefpane> <script type="application/javascript"> <![CDATA[ Components.utils.import("resource://gre/modules/Services.jsm"); const o = {// https://github.com/Infocatcher/Private_Tab/issues/228#issuecomment-238963363 get windows() { return (function*() { const ws = Services.wm.getEnumerator("navigator:browser"); while(ws.hasMoreElements()) yield ws.getNext() })() } }, toggleState = val => { typeof val != "boolean" && (val = document.getElementById("state").value); for(let el of document.querySelectorAll("vbox checkbox")) el.disabled = !val; if (val) { for(let el of document.querySelectorAll("#extra checkbox")) el.disabled = !document.getElementById("addBmToFolder").value; let edEl = document.getElementById("editchck"), hdEl = document.getElementById("hidechck"); hdEl.disabled = !edEl.checked; } }, onLoad = () => { toggleState() }, onUnload = () => { for(let win of o.windows) { let btn = win.document.getElementById("_buttonId"); if (btn) { btn.destroy(); btn.init() } } } ]]> </script> </prefwindow> <?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" title = "Свойства закладки" autosize="true" height="520" width="600" id="ExtraDescriptions" onload="onLoad()"> <vbox flex="1" style="overflow-x: hidden;"> <groupbox id="bmProps" flex="1" style="padding: 5px 10px;"> <caption flex="1" align="center"> <label class="header" value="Заголовок:"/> <textbox value="_title" id="title" flex="1" placeholder="не задан"/> </caption> <hbox align="center" style="padding: 5px 0;"> <label class="header" value="Адрес:"/> <textbox value="_bmURL" id="url" flex="1" placeholder="не задан"/> </hbox> <hbox align="center" style="padding: 5px 0;"> <vbox flex="1" align="center"> <label class="header" value="Создано:"/> <textbox value="_bmAdd" id="add" flex="1" class="plain" size="17" readonly="true" placeholder="неизвестно"/> </vbox> <vbox flex="1" align="center"> <label class="header" value="Изменено:"/> <textbox value="_bmMod" id="changed" flex="1" class="plain" size="17" readonly="true" placeholder="неизвестно"/> </vbox> <vbox flex="1" align="center"> <label class="header" value="Посещено:"/> <textbox value="_bmVst" id="visited" class="plain" size="17" readonly="true" placeholder="неизвестно"/> </vbox> <vbox flex="1" align="center"> <label class="header" value="Посещений:"/> <textbox value="_bmCnt" id="counts" class="plain" size="9" readonly="true" placeholder="нет"/> </vbox> </hbox> <hbox align="center" style="padding: 5px 0;"> <label class="header" value="Метки:"/> <textbox value="_bmTgs" id="tags" flex="1" placeholder="задайте метки, разделяя запятой"/> </hbox> <hbox align="center" style="padding: 5px 0;"> <label class="header" value="Ключевые слова:"/> <textbox flex="1" id="keywords" placeholder="не задано"/> </hbox> <command id="cmd_bmLdSB" oncommand="setSBFlag(this.nextElementSibling.checked ? 1 : 0)"/> <checkbox style="padding: 5px 0;" class="header" id="loadInSB" label="Открывать в боковой панели" command="cmd_bmLdSB"/> </groupbox> <groupbox id="descriptions" style="overflow-x: scroll;"> <caption flex="1" align="center"> <label class="header" value="Описания в формате, выводимом как: "Название:   Ваш текст""/> </caption> </groupbox> <button id="addDesc" label="Добавить новое описание" oncommand="crNode({}); addBtn.scrollIntoView({behavior: 'smooth'});"/> </vbox> <hbox align="center" pack="end" style="padding: 10px 20px"> <button id="accept" label="Принять" oncommand="updBm(); window.close();"/> <button id="cancel" label="Отмена" oncommand="window.close();"/> </hbox> <script type="application/javascript"> <![CDATA[ Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/PlacesUtils.jsm"); const plUtls = PlacesUtils, plBms = plUtls.bookmarks, bmId = _bmId, descs = plUtls.getAnnotationsForItem(bmId), sbdesc = "bookmarkProperties/loadInSidebar", defDesc = "bookmarkProperties/description", addBtn = document.getElementById("addDesc"), group = document.getElementById("descriptions"), setSBFlag = val => { let sbDesc = document.getElementById("loadInSB-group"); if (sbDesc) !!val ? (sbDesc.lastElementChild.value = val) : rmvNode(sbDesc); else crNode({name: sbdesc, value: val}) }, crNode = obj => { if (!(obj && typeof obj == "object")) return; let box = group.appendChild(document.createElement("groupbox")), cap = box.appendChild(document.createElement("caption")), nmBox = cap.appendChild(document.createElement("textbox")), spcr = cap.appendChild(document.createElement("spacer")), btn = cap.appendChild(document.createElement("toolbarbutton")), txtBox = box.appendChild(document.createElement("textbox")), btnAttrs = {class: "close-icon tabbable", tooltiptext: "Удалить описание (для дефолного описания удаляется только текст)", oncommand: "rmvNode(this.parentNode.parentNode)"}, nmBoxAttrs = {class: "name", placeholder: "Задайте название", maxlength: "30", spellcheck: "true"}, txtBoxAttrs = {class: "desc", value: obj.value, multiline: "true", rows: 4, placeholder: "Введите описание (описание не будет сохранено, если это поле останется пустым)", spellcheck: "true"}; cap.flex = 1; spcr.flex = 1; spcr.width = 5000; obj.name && (nmBox.defaultValue = obj.name); for(let prop in btnAttrs) btnAttrs[prop] && btn.setAttribute(prop, btnAttrs[prop]); for(let prop in nmBoxAttrs) nmBoxAttrs[prop] && nmBox.setAttribute(prop, nmBoxAttrs[prop]); for(let prop in txtBoxAttrs) txtBoxAttrs[prop] && txtBox.setAttribute(prop, txtBoxAttrs[prop]); if (obj.name == defDesc) { nmBox.value = "Описание:"; box.id = "defDesc-group"; nmBox.id = "defDesc-val"; nmBox.disabled = true }; if (obj.name == sbdesc) { document.getElementById("loadInSB").checked = !!obj.value; box.id = "loadInSB-group"; nmBox.id = "loadInSB-val"; box.collapsed = true; } }, rmvNode = (box, txtbox = box.lastElementChild) => box.id == "defDesc-group" ? (txtbox.value = '') : box.remove(), onLoad = () => { let kws; try {kws = plBms.getKeywordForBookmark(bmId)} catch(ex) {} finally {kws && (document.getElementById("keywords").defaultValue = kws)}; if (descs && !!descs.length) for(let desc of descs) crNode(desc); else crNode({name: defDesc, value: ""}); }, updBm = () => { plUtls.annotations.removeItemAnnotations(bmId); // https://stackoverflow.com/a/38916225 let names = [...document.getElementsByClassName("name")].map(n => !n.id ? n.value : n.defaultValue), descs = [...document.getElementsByClassName("desc")].map(n => n.value), obj = Object.assign({}, ...names.map((n, index) => ({[n]: descs[index]}))); for(let prop in obj) { if (obj[prop] || prop == defDesc) plUtls.setAnnotationsForItem(bmId, [{name: prop, value: obj[prop]}]); }; let uri; try {uri = Services.uriFixup.createFixupURI(document.getElementById("url").value, 0)} catch(ex) {}; for(let node of document.querySelectorAll("#bmProps textbox")) { node.value = node.value.trim(); if (node.value != node.defaultValue) { switch (node.id) { case "title": plBms.setItemTitle(bmId, node.value); break; case "url": uri && plBms.changeBookmarkURI(bmId, uri); break; case "tags": if (uri) { let tags = node.value.split(/,(?:\s+)?/g).filter(m => !!m.length); plUtls.tagging.untagURI(uri, null); !!tags.length && plUtls.tagging.tagURI(uri, tags) }; break; case "keywords": plBms.setKeywordForBookmark(bmId, node.value); break; } } } } ]]> </script> </window> | Иконка: Код: data:image/png;base64,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 | | Всего записей: 186 | Зарегистр. 09-04-2017 | Отправлено: 01:06 18-07-2017 | Исправлено: nfmzkvmx, 21:33 23-07-2017 |
|