https://addons.mozilla.org/en-US/firefox/addon/contextsearch-web-ext-lite/
https://addons.mozilla.org/en-US/firefox/addon/mozlz4-edit/
Спасибо, но первое - только для quantum (я остаюсь на ESR 52, а потом Pale Moon или Waterfox),
а второе - просто редактирование поисковых систем, которое я и так умею.
Отсутствует
momo2000 пишетhttps://addons.mozilla.org/en-US/firefox/addon/contextsearch-web-ext-lite/
https://addons.mozilla.org/en-US/firefox/addon/mozlz4-edit/Спасибо, но первое - только для quantum (я остаюсь на ESR 52, а потом Pale Moon или Waterfox),
а второе - просто редактирование поисковых систем, которое я и так умею.
Я пользуюсь https://addons.mozilla.org/ru/firefox/a … ed-search/ - мне нравится.
Кроме того - посмотрите кнопку https://forum.mozilla-russia.org/viewto … 50#p703450
Отредактировано difabor (12-07-2018 02:34:53)
Хорошо, когда у человека есть выбор, но плохо, когда он перед ним стоит ©
Отсутствует
Dumby
Поправьте пожалуйста кнопочку под 60+
Не, это не то, что можно просто «поправить».
И, количество совпадений findbar'ы умеют показывать уже давно.
А если имеется в виду один findbar на окно браузера,
то я пробовал что-то сочинить, типа browser для него переставлять,
но получается какая-то ерунда, сомневаюсь, что подойдёт.
((bar, button = true, insertAtTop = true, ctrlFcloseFinbar = false) => ({ init(parent) { var has = bar = parent.querySelector("#appcontent > findbar"); has || this.initFinbar(parent); var lo = bar.linkedObject; lo.listenCtrlF = ctrlFcloseFinbar ? listen => listen ? addEventListener("keydown", lo, true) : removeEventListener("keydown", lo, true) : () => {}; has && !bar.hidden && lo.listenCtrlF(true); if (button) self._handleClick = () => bar.hidden ? bar.startFind(bar.FIND_NORMAL) : bar.collapsed || bar.close(); addDestructor(lo.destroy, lo); }, destroy(reason) { if (reason[5] != "e") return; bar.close(); bar._browser = {}; bar.remove(); this.setProgressListener(false); for(var key of ["gFindBar", "gFindBarInitialized"]) Object.defineProperty(window, key, this[key]); gBrowser[this.gBrKey] = this[this.gBrKey]; Services.ppmm.removeDelayedProcessScript(this.url); Services.ppmm.loadProcessScript("data:," + encodeURIComponent(` Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_DEFAULT && Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_CONTENT || (nsvo => { var proto = nsvo.Finder.prototype; if ("_requestMatchesCount" in proto) { proto.requestMatchesCount = proto._requestMatchesCount; delete proto._requestMatchesCount; } })(Cu.import("resource://gre/modules/Finder.jsm", {}));` ) , false); }, initFinbar(parent) { for(var tab of gBrowser.tabs) { if (!tab._findBar) continue; tab._findBar.browser = null; tab._findBar._browser = {}; tab._findBar.remove(); delete tab._findBar; } bar = document.createElement("findbar"); var p = new Proxy({}, {get: () => () => {}}); bar._browser = {finder: p, messageManager: p}; parent.insertBefore(bar, insertAtTop ? parent.firstChild : null); bar.linkedObject = this; ["gFindBar", "gFindBarInitialized"].forEach((key, ind) => { this[key] = Object.getOwnPropertyDescriptor(window, key); delete window[key]; window[key] = ind ? true : bar; }); var key = "getCachedFindBar" in gBrowser ? "getCachedFindBar" : "getFindBar"; this[this.gBrKey = key] = gBrowser[key]; gBrowser[key] = () => bar; [ "close", "startFind", "onMatchesCountResult", "_updateMatchesCount", "_onBrowserKeypress", "receiveMessage" ].forEach((key, ind) => { var func = bar[key].bind(bar); bar[key] = ind ? (...args) => this[key](...args) || func(...args) : (...args) => func(...args) || this[key](...args); }); this.url = "data:," + encodeURIComponent(` Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_DEFAULT && Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_CONTENT || (nsvo => { var proto = nsvo.Finder.prototype; if ("_requestMatchesCount" in proto) return; proto._requestMatchesCount = proto.requestMatchesCount; proto.requestMatchesCount = ${ this.newRequestMatchesCount } })(Cu.import("resource://gre/modules/Finder.jsm", {}));` ); delete this.newRequestMatchesCount; Services.ppmm.loadProcessScript(this.url, true); }, newRequestMatchesCount: async function requestMatchesCount(aWord, aLinksOnly) { if (typeof aLinksOnly != "boolean") { var {linksOnly, data} = aLinksOnly; aLinksOnly = linksOnly; this.entireWord = data.entireWord; this.caseSensitive = data.caseSensitive; this.onModalHighlightChange(data.useModalHighlight); this.onHighlightAllChange(data.highlightAll); data.highlightAll && await this.highlighter.highlight(true, aWord, linksOnly); this._iterator && this._iterator.reset(); var obj; Object.defineProperty(this, "_currentMatchesCountResult", { configurable: true, enumerable: true, get: (val = obj) => { if (val) { if (!val.total) val.total = new Number(0); val.currentFound = val._currentFound; } return obj = val; }, set: val => { if (val) return obj = val; delete this._currentMatchesCountResult; return obj = this._currentMatchesCountResult = val; } }); var lfr = this._lastFindResult; lfr !== null && lfr != Ci.nsITypeAheadFind.FIND_NOTFOUND || Object.defineProperty(this, "_lastFindResult", { configurable: true, enumerable: true, get: () => null, set: val => { if (val == Ci.nsITypeAheadFind.FIND_WRAPPED) val = Ci.nsITypeAheadFind.FIND_FOUND; delete this._lastFindResult; return this._lastFindResult = val; } }); } this._requestMatchesCount(aWord, aLinksOnly); }, close() { bar.collaped = false; this.setProgressListener(false); this.setBrowser(null, null); }, startFind() { if (this.maybeCollapse(gBrowser.selectedBrowser)) return true; if (bar.hidden) this.setBrowser(300), this.setProgressListener(true); else if (!ctrlFcloseFinbar) setTimeout(() => this.updateMatchesCount(), 100); }, onMatchesCountResult(res) { if (!("currentFound" in res) || res.total == -1 || res.currentFound) return; bar._foundMatches.value = `${+res.total || "Нет"} совпадени${ bar.pluralForm.get(res.total, "е;я;й") }.`; bar._foundMatches.hidden = false; return true; }, _updateMatchesCount() { return true; }, _onBrowserKeypress(e) { if (!bar.hidden) return; if (!e.charCode) return true; this.setBrowser(300); this.setProgressListener(true); }, receiveMessage(msg) { msg.target = bar._browser; }, progressListenerAdded: false, setProgressListener(add) { if (add) { if (this.progressListenerAdded) return; this.progressListenerAdded = true; gBrowser.addProgressListener(this); this.listenCtrlF(true); } else { if (!this.progressListenerAdded) return; this.progressListenerAdded = false; gBrowser.removeProgressListener(this); this.listenCtrlF(false); } }, handleEvent(e) { if ( e.ctrlKey && e.code == "KeyF" && !e.shiftKey && !e.altKey && !bar.collapsed ) e.preventDefault(), e.stopPropagation(), bar.close(); }, updateMatchesCount() { var str = bar._findField.value; if (!str) return; var data = { entireWord: bar._entireWord, caseSensitive: bar._typeAheadCaseSensitive, highlightAll: bar._highlightAll, useModalHighlight: bar._useModalHighlight }; bar.browser.finder.requestMatchesCount( bar._findField.value, {linksOnly: bar._findMode == bar.FIND_LINKS, data} ); }, maybeCollapse(br) { return br.isSyntheticDocument || br.documentContentType == "application/vnd.mozilla.xul+xml"; }, setBrowser(updateDelay, br = gBrowser.selectedBrowser) { if (bar._browser != br) { var b = bar._browser; if (b) { b.messageManager.removeMessageListener("Findbar:Mouseup", bar); b.finder.removeResultListener(bar); bar._highlightAll && b.finder.highlight(false); } if (br) { br.messageManager.addMessageListener("Findbar:Mouseup", bar); bar._updateBrowserWithState(); } bar._browser = br; } if (!br) return; bar._updateStatusUI(); bar._foundMatches.value = ""; br.finder.addResultListener(bar); if ( !(bar.collapsed = this.maybeCollapse(br)) && br.currentURI.spec != "about:blank" && updateDelay !== null ) updateDelay ? setTimeout(this.updateMatchesCount, updateDelay) : this.updateMatchesCount(); }, onStateChange(wpr, req, state) { state & Ci.nsIWebProgressListener.STATE_STOP && this.setBrowser(); }, onLocationChange(wpr, req) { req || Components.stack.formattedStack.includes("SessionStore.jsm") || this.setBrowser(); } }).init(document.getElementById("appcontent")))();
У немцев есть код, но он у меня на 60 ESR не работает:
https://www.camp-firefox.de/forum/viewtopic.php?f=16&t=123867&start=15Есть несколько WE-расширений для Quantum. Но в силу того, что они высокоуровнево работают (в отдельном процессе), возникают видимые дергания ("перескакивания") вкладок, когда сперва срабатывает by default браузера, а через десятую долю секунды уже расширение. Не ахти, короче.
Ну, если позволительно будет переопределить функцию браузера, то вот вариант.
Вроде должно работать, в большинстве случаев.
((blurTab, dummy, s, lastSelect) => { (s = () => lastSelect = Date.now())(); addEventListener("TabSelect", s, false, gBrowser.tabContainer || 1); gBrowser._blurTab = tab => { if (!tab.selected) return; var tabToSelect = dummy; for(var t of gBrowser.tabs) if ( !t.hidden && !t.closing && t.lastAccessed > tabToSelect.lastAccessed && t.lastAccessed < lastSelect ) tabToSelect = t; if (tabToSelect == dummy) blurTab.call(gBrowser, tab); else gBrowser.selectedTab = tabToSelect; } addDestructor(() => gBrowser._blurTab = blurTab); })(gBrowser._blurTab, {lastAccessed: 0});
А как вызвать это окно по типу паролей window.openDialog('chrome://passwordmgr/content/passwordManager.xul')
Как-то так, наверно.
var win = Services.wm.getMostRecentWindow("Browser:SiteDataSettings"); if (win) win.focus(); else ChromeUtils.import("resource:///modules/SiteDataManager.jsm", null).SiteDataManager.updateSites(), window.openDialog("chrome://browser/content/preferences/siteDataSettings.xul", "_blank", "");
т.е загнать закладку - всегда в тоже место, а надо в разные
Да, difabor правильно сказал. Можно просто повторить код,
и изменить в первой строке имя настройки, в которую заносится guid папки.
Но если пунктов нужно много, то лучше переписать под такую задачу.
Для простоты указания нужной поисковой системы, в коде кнопки можно использовать цифру из строки "order", которую я сам посмотрю файле search.json.json
json.json, order. Как странно.
((topic, popup, menuitem, order = 3) => addEventListener("popupshowing", { handleEvent(e) { if (e.target != popup || this.souldHide()) return; menuitem = document.createElement("menuitem"); menuitem.id = "context-searchselect-order" + order; menuitem.className = "menuitem-iconic"; menuitem.setAttribute("oncommand", "search();"); menuitem.search = this.search.bind(this); var before = popup.querySelector("#context-searchselect + *"); popup.insertBefore(menuitem, before); addDestructor(() => { menuitem.remove(); this._engine && Services.obs.removeObserver(this, topic); }, this); order--; (this.handleEvent = e => e.target == popup && !(menuitem.hidden = this.souldHide()) && this.update() )(e); }, search() { var submission = this.engine.getSubmission( this.selectedText, null, "contextmenu" ); submission && openLinkIn(submission.uri.spec, "tab", { postData: submission.postData, inBackground: Services.prefs.getBoolPref( "browser.search.context.loadInBackground" ), relatedToCurrent: true }); }, souldHide() { return !gContextMenu.isTextSelected && !gContextMenu.onLink || gContextMenu.onImage; }, update() { var selectedText = this.selectedText = gContextMenu.isTextSelected ? gContextMenu.textSelected : gContextMenu.linkTextStr; if (selectedText.length > 15) { var len = 15, code = selectedText[15].charCodeAt(0); if (code >= 0xDC00 && code <= 0xDFFF) len++; selectedText = selectedText.slice(0, len) + gContextMenu.ellipsis; } menuitem.label = gNavigatorBundle.getFormattedString( "contextMenuSearch", [this.engine.name, selectedText] ); }, _engine: null, get engine() { return this._engine || this.getEngine(); }, getEngine() { var engine = Services.search.getEngines()[order] || Services.search.defaultEngine; engine.iconURI && menuitem.setAttribute( "image", engine.iconURI.spec ); Services.obs.addObserver(this, topic, false); return this._engine = engine; }, observe() { this._engine = null; Services.obs.removeObserver(this, topic); } }, false, popup || 1))( "browser-search-engine-modified", document.getElementById("contentAreaContextMenu") );
Отредактировано Dumby (21-10-2018 19:09:56)
Отсутствует
А если имеется в виду один findbar на окно браузера,
то я пробовал что-то сочинить, типа browser для него переставлять,
но получается какая-то ерунда, сомневаюсь, что подойдёт.
Dumby, а в чём ерунда?
Я проверил на 60.1.0 ESR. Получилось то, что надо.
Спасибо большое.
«The Truth Is Out There»
Отсутствует
в конфиге набери alerts
я помню те времена когда обновления программ убирали проблемы и исправляли баги, а не добавляли их.
toxID:05AB9B827D896AACEE7FF4573A02FB8F025F46ADC856B98F65BC1BA9BD21A81DC98BA9C36CE3
Отсутствует
Подскажите, где устанавливается длительность вот этого оповещения
custombuttons.alertSlide(" ", " ")У меня оно висит секунд 20
Открой вкладку с адресом: chrome://global/content/alerts/alert.js
Поиск: function onAlertLoad
Там увидишь константу ALERT_DURATION_IMMEDIATE
И видно, какая настройка проверяется (зависит от версии Firefox).
Далее, если алерт самозакрывающийся, то,
в зависимости от значения настройки, два варианта:
1. Таймаут на эту константу.
2. Слушатель на событие "animationend".
В этом случае длительность анимации сразу увидишь по адресу
chrome://global/content/alerts/alert.css
Отсутствует
Dumby
Подскажите, где устанавливается длительность вот этого оповещения
custombuttons.alertSlide(" ", " ")У меня оно висит секунд 20
Не понял,что висит ? Да, хорошая кнопка Find bar, а нельзя ее использовать через гор. клавишу или дв.клик по странице?
Отсутствует
beggrr пишетПодскажите, где устанавливается длительность вот этого оповещения
custombuttons.alertSlide(" ", " ")У меня оно висит секунд 20
Открой вкладку с адресом: chrome://global/content/alerts/alert.js
Поиск: function onAlertLoadТам увидишь константу ALERT_DURATION_IMMEDIATE
И видно, какая настройка проверяется (зависит от версии Firefox).
Далее, если алерт самозакрывающийся, то,
в зависимости от значения настройки, два варианта:1. Таймаут на эту константу.
2. Слушатель на событие "animationend".
В этом случае длительность анимации сразу увидишь по адресу
chrome://global/content/alerts/alert.css
Dumby
Я открыл вкладку с адресом: chrome://global/content/alerts/alert.js там константа ALERT_DURATION_IMMEDIATE действительно была 20 000
Что я сделал. Нашел этот файл alert.js (конечно все делалось при закрытом браузере), распаковал, отредактировал в текстовом редакторе, переправил константу на 3000 и заменил этим файлом тот оригинальный. Результата никакого.
Все равно слайдер держится 20 секунд.
Может я неправильно понял что надо сделать?
Отсутствует
Dumby
спасибо, работает!
После запуска в консоли появилась ошибка: ReferenceError: addDestructor is not defined. [Запускаю весь код на Quantum как юзерхром-скрипт.]
Я удалил строку с addDestructor, и код после этого заработал.
Отсутствует
drage2 пишет:
т.е загнать закладку - всегда в тоже место, а надо в разные
Да, difabor правильно сказал. Можно просто повторить код,
и изменить в первой строке имя настройки, в которую заносится guid папки.
Но если пунктов нужно много, то лучше переписать под такую задачу.
Dumby, а можно ли написать код, который был бы видимый для других кнопок.
Тогда каждая кнопка просто бы создавала свою переменную:
var s = "CB.bookmarkFolderForSaving_1";// или _2, или _3 и т.д.
Хорошо, когда у человека есть выбор, но плохо, когда он перед ним стоит ©
Отсутствует
json.json, order. Как странно.
скрытый текстВыделить кодКод:
((topic, popup, menuitem, order = 3) => addEventListener("popupshowing", { handleEvent(e) { if (e.target != popup || this.souldHide()) return; menuitem = document.createElement("menuitem"); menuitem.id = "context-searchselect-order" + order; menuitem.className = "menuitem-iconic"; menuitem.setAttribute("oncommand", "search();"); menuitem.search = this.search.bind(this); var before = popup.querySelector("#context-searchselect + *"); popup.insertBefore(menuitem, before); addDestructor(() => { menuitem.remove(); this._engine && Services.obs.removeObserver(this, topic); }, this); order--; (this.handleEvent = e => e.target == popup && !(menuitem.hidden = this.souldHide()) && this.update() )(e); }, search() { var submission = this.engine.getSubmission( this.selectedText, null, "contextmenu" ); submission && openLinkIn(submission.uri.spec, "tab", { postData: submission.postData, inBackground: Services.prefs.getBoolPref( "browser.search.context.loadInBackground" ), relatedToCurrent: true }); }, souldHide() { return !gContextMenu.isTextSelected && !gContextMenu.onLink || gContextMenu.onImage; }, update() { var selectedText = this.selectedText = gContextMenu.isTextSelected ? gContextMenu.textSelected : gContextMenu.linkTextStr; if (selectedText.length > 15) { var len = 15, code = selectedText[15].charCodeAt(0); if (code >= 0xDC00 && code <= 0xDFFF) len++; selectedText = selectedText.slice(0, len) + gContextMenu.ellipsis; } menuitem.label = gNavigatorBundle.getFormattedString( "contextMenuSearch", [this.engine.name, selectedText] ); }, _engine: null, get engine() { return this._engine || this.getEngine(); }, getEngine() { var engine = Services.search.getEngines()[order] || Services.search.defaultEngine; engine.iconURI && menuitem.setAttribute( "image", engine.iconURI.spec ); Services.obs.addObserver(this, topic, false); return this._engine = engine; }, observe() { this._engine = null; Services.obs.removeObserver(this, topic); } }, false, popup || 1))( "browser-search-engine-modified", document.getElementById("contentAreaContextMenu") );
Нереально круто. То что нужно. Спасибо большое!
А порядковый номер я смотрю в search.json, потому что у меня поисковиков и их модификаций больше 50, и отсчитывать нужный по списку из настроек слишком утомительно.
Отредактировано firefan (13-07-2018 07:48:04)
Отсутствует
Как-то так, наверно.
Да, оно)
А если имеется в виду один findbar на окно браузера,
то я пробовал что-то сочинить, типа browser для него переставлять,
но получается какая-то ерунда, сомневаюсь, что подойдёт.
Работает!
Может быть кто подправит код, чтобы осталась только функция "один findbar на окно браузера" без всего лишнего.
Отредактировано momo2000 (14-07-2018 09:30:43)
Отсутствует
beggrr
alert.css - поставил 4сек и все ок! в alert.js - 4000/Сбросить? Просто выкинуть из профиля startupCache. И alert.js не главное, alert.css - верняк!
Да!
Подправил alert.css и все стало как надо. И startupCache не пришлось сбрасывать, заработало сразу.
Благодарю!
Отсутствует
У меня до недавнего времени безотказно работала кнопка find вот с этим кодом
const forceFind = false, forceFindCS = true; // Приклеить элемент findbar к странице( #appcontent ) ................................ const fbID = "FindToolbar-m"; delete window.gFindBar; window.gFindBar = document.getElementById(fbID); if (!gFindBar) { gFindBar = gBrowser.parentNode.insertBefore(document.createElement("findbar"), gBrowser); gFindBar.id = fbID; gFindBar.setAttribute("browserid", "content"); gFindBar.clientTop; delete window.gFindBarInitialized; window.gFindBarInitialized = true; gFindBar._selectionMaxLen = 1000; // лимит символов для поиска } // Ctrl+F, показать - скрыть панель поиска .................................... function toggleFindbar() gFindBar.hidden ? gFindBar.onFindCommand() : gFindBar.close(); addEventListener("keydown", function(e) e.keyCode == e.DOM_VK_F && e.ctrlKey && !e.altKey && !e.shiftKey && !e.preventDefault() && toggleFindbar() , false); this.onclick = function(e) { if (!e.button) toggleFindbar() }; // Показать количество совпадений на панели поиска ................................ const textbox = gFindBar.getElement("findbar-textbox"), nrm = Ci.nsISelectionController.SELECTION_NORMAL, labID = "hits-m"; var lab = document.getElementById(labID); if (!lab) { lab = textbox.parentNode.insertBefore(document.createElement("label"), textbox); lab.id = labID; } var curHit, allHits; function updateHits(arg) { if (gFindBar.hidden) return; var word = textbox.value; if (!word) { lab.value = "0/0"; textbox.removeAttribute("status"); return; } var win = arg instanceof Window && arg || content; if (win == content) curHit = allHits = 0; var findbarFinder = gFindBar._browser.finder; var controller = findbarFinder._getSelectionController(win); var doc = win.document; if (word && controller && doc && doc.documentElement) { var body = doc instanceof HTMLDocument && doc.body ? doc.body : doc.documentElement; var searchRange = doc.createRange(); searchRange.selectNodeContents(body); var startPt = searchRange.cloneRange(); startPt.collapse(true); var endPt = searchRange.cloneRange(); endPt.collapse(false); var retRange = null; var finder = Cc["@mozilla.org/embedcomp/rangefind;1"].createInstance().QueryInterface(Ci.nsIFind); finder.caseSensitive = gFindBar._shouldBeCaseSensitive(word); while ((retRange = finder.Find(word, searchRange, startPt, endPt))) { allHits++; if (!curHit) { var sel = controller.getSelection(nrm), range; if (sel.toString()) range = sel.getRangeAt(0) else { var editableNode = findbarFinder._getEditableNode(retRange.startContainer); if (editableNode) sel = editableNode.editor.selectionController.getSelection(nrm); if (sel.toString()) range = sel.getRangeAt(0); } var comp = range && ["startContainer", "endContainer", "startOffset", "endOffset"] .every(function(prop) range[prop] == retRange[prop]); if (comp) curHit = allHits; } startPt = retRange.cloneRange(); startPt.collapse(false); } Array.forEach(win.frames, function(frame) updateHits(frame)); } if (win != content) return; allHits ? textbox.removeAttribute("status") : textbox.setAttribute("status", "notfound"); forceFind && !curHit && allHits && gFindBar._find(); lab.value = curHit + "/" + allHits; } updateHits(); gFindBar.updateHits = updateHits; function insUpd(methodName, code) { const method = gFindBar[methodName]; gFindBar[methodName] = Function("arguments.callee.method.apply(this, arguments);" + (code || "") + " this.updateHits();"); gFindBar[methodName].method = method; addDestructor(function() gFindBar[methodName] = method); } insUpd("_find"); insUpd("_findAgain"); insUpd("_setCaseSensitivity", forceFindCS && " this._find();"); const progressListener = { onStateChange: function(wpr, req, state) state & Ci.nsIWebProgressListener.STATE_STOP && setTimeout(updateHits, 320), onLocationChange: function(wpr, req) !req && updateHits() }; addDestructor(function() gBrowser.removeProgressListener(progressListener)); function onFindbar() { gBrowser[(gFindBar.hidden ? "remove" : "add") + "ProgressListener"](progressListener); !gFindBar.hidden && updateHits(); } onFindbar(); const observer = new MutationObserver(onFindbar); observer.observe(gFindBar, { attributes: true, attributesFilter: ["hidden"] }); addDestructor(function() observer.disconnect()); lab.addEventListener("mousedown", function(e){ if (e.button == 0) gFindBar.hidden=true; if (e.button == 2) { textbox.value=""; textbox.removeAttribute("status", "notfound"); updateHits(); } })
И попутно вопрос: как повесить обработчик onclick или onwheel на текстовое поле родной кнопки Find браузера? Как к этому текстовому полю обратиться?
C gFindBar._findField не получается, хотя раньше работало.
Отсутствует
Добрый день. Просьба к специалистам . Возможно решить задачу? Сделать гибрид двух кнопок https://forum.mozilla-russia.org/viewto … 20#p729920 и https://forum.mozilla-russia.org/viewto … 26#p701226 . Кнопку "Открыть страницу в другом браузере из контекстного меню" по типу кнопки "Запуск портативной программы из портативного браузера", положив портативные браузеры в папку "Soft" в профайле а работали портативные браузеры как кнопка "Открыть страницу в другом браузере из контекстного меню" . Мне было бы удобно положить портативное браузеры в папку "Soft" в профайле и не переписывать пути к портативным браузерам для "открытия страницы в другом браузере из контекстного меню" . А так «Всё своё ношу с собой». Заранее спасибо.
Отредактировано Duche (20-07-2018 14:55:29)
Отсутствует
Почему в CB showPopup не пашет, а openPopup пашет в 61фф?
Пришлось многие кнопки на openPopup перевести( неудобно, а раньше только навел сразу видно меню.
bunda1 редко отвечает, может раз в пол года... тут или dumby, или кто-то другой быстрее ответят...
Отредактировано func4ptch4 (17-07-2018 17:23:05)
Отсутствует
Товарищи, помогите пожалуйста.
Для Spotify Web Player нужен глобальный хоткей (OS - Windows), при нажатии на который, даже если браузер свернут, прожималась бы кнопка в веб-плеере "Save to your Favorite Songs" (сердечко такое рядом с названием текущего трека). Если сердечко зеленое, значит песня уже в библиотеке, и прожимать его не нужно.
Вот CSS класс этого элемента:
spoticon-heart-16 - сердечко неактивно, нажимать можно.
spoticon-heart-active-16 - сердечко активно, не нажимать.
Хоть плеер и использует DRM, инструменты разработчика работают по хоткею (Ctrl+Shift+ I) по крайней мере на ESR 52.
Есть аддон Media Keys, который включает глобальные хоткеи для медиа кнопок на клавиатуре, но они контролируют только проигрывание (play/pause/next track/previous track и т.п.), а не добавление трека в фейворитс.
P.S. Зарегистрировать Spotify аккаунт можно с помощью любой US-прокси, например, подойдет бесплатный anonymox. После регистрации можно будет пользоваться web-плеером https://open.spotify.com/browse уже без прокси и без ограничений, а также, поскольку они официально в РФ не работают, то и рекламы нет.
P.P.S. Стендэлон приложение Spotify не использую, потому что из него как раз выкидывает по прошествии пары месяцев и нужно плясать с постоянно включенным прокси/впн.
P.P.P.S. Если кому-то интересно, могу скинуть профиль (или userChrome.css и ссылки на аддоны), чтобы получилось такое (я убрал все лишние элементы браузера, включая скролбар и адресную строку, убрал пустой рекламный блок и добавил возможность закреплять поверх всех окон; здесь скрин minimized окна, но также прекрасно и функционально работает в развернутом виде):
Отредактировано firefan (22-07-2018 16:53:19)
Отсутствует
Здравствуйте,
Кнопка сохраняла страницу в firefox 56
В firefox 60 не сохраняет.
custom_buttons-0.0.5.8.9-fixed7.1.xpi
Пожалуйста, помогите
var saveToFile = function (fileContent, fileName) { var uc = Components.classes['@mozilla.org/intl/scriptableunicodeconverter'].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); uc.charset = 'utf-8'; fileContent = uc.ConvertFromUnicode(fileContent); var nsIFilePicker = Components.interfaces.nsIFilePicker; var fp = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker); fp.init(window, '', fp.modeSave); fp.defaultString = fileName; fp.appendFilters(fp.filterHTML); fp.appendFilters(fp.filterAll); if(fp.show() == fp.returnCancel) return; var stream = Components.classes['@mozilla.org/network/file-output-stream;1'].createInstance(Components.interfaces.nsIFileOutputStream); stream.init(fp.file, 0x02|0x20|0x08, 0666, 0); stream.write(fileContent, fileContent.length); stream.close(); }; var resolveURL = function (url, base) { try { var ioService = Components.classes['@mozilla.org/network/io-service;1'].getService(Components.interfaces.nsIIOService); var baseURI = ioService.newURI(base, null, null); var absURI = ioService.newURI(url, null, baseURI); return absURI.spec; } catch (e) {} }; var getSelWin = function (w) { if (w.getSelection().toString()) return w; for (var i = 0, f, r; f = w.frames[i]; i++) { try { if (r = getSelWin(f)) return r; } catch(e) {} } }; var encodeImg = function (src, obj) { var canvas, img, ret = src; if (/^https?:\/\//.test(src)) { canvas = doc.createElement('canvas'); if (!obj || obj.nodeName.toLowerCase() != 'img') { img = doc.createElement('img'); img.src = src; } else { img = obj; }; if (img.complete) try{ canvas.width = img.width; canvas.height = img.height; canvas.getContext('2d').drawImage(img, 0, 0); ret = canvas.toDataURL((/\.jpe?g/i.test(src) ? 'image/jpeg' : 'image/png')); } catch (e) {}; if (img != obj) img.src = 'about:blank'; }; return ret; }; var toSrc = function (obj) { var strToSrc = function (str) { var chr, ret = '', i = 0, meta = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\x22' : '\\\x22', '\\': '\\\\'}; while (chr = str.charAt(i++)) { ret += meta[chr] || chr; }; return '\x22' + ret + '\x22'; }, arrToSrc = function (arr) { var ret = []; for (var i = 0; i < arr.length; i++) { ret[i] = toSrc(arr[i]) || 'null'; }; return '[' + ret.join(',') + ']'; }, objToSrc = function (obj) { var val, ret = []; for (var prop in obj) { if (Object.prototype.hasOwnProperty.call(obj, prop) && (val = toSrc(obj[prop]))) ret.push(strToSrc(prop) + ': ' + val); }; return '{' + ret.join(',') + '}'; }; switch (Object.prototype.toString.call(obj).slice(8, -1)) { case 'Array': return arrToSrc(obj); case 'Boolean': case 'Function': case 'RegExp': return obj.toString(); case 'Date': return 'new Date(' + obj.getTime() + ')'; case 'Math': return 'Math'; case 'Number': return isFinite(obj) ? String(obj) : 'null'; case 'Object': return objToSrc(obj); case 'String': return strToSrc(obj); default: return obj ? (obj.nodeType == 1 && obj.id ? 'document.getElementById(' + strToSrc(obj.id) + ')' : '{}') : 'null'; } }; var mainWin = document.commandDispatcher.focusedWindow.top == content ? document.commandDispatcher.focusedWindow : content; var selWin = getSelWin(mainWin), win = selWin || mainWin, doc = win.document, loc = win.location; var ele, pEle, clone, reUrl = /(url\(\x22)(.+?)(\x22\))/g; if (selWin) { var rng = win.getSelection().getRangeAt(0); pEle = rng.commonAncestorContainer; ele = rng.cloneContents(); } else { pEle = doc.documentElement; ele = (doc.body || doc.getElementsByTagName('body')[0]).cloneNode(true); }; while (pEle) { if (pEle.nodeType == 1) { clone = pEle.cloneNode(false); clone.appendChild(ele); ele = clone; }; pEle = pEle.parentNode }; var sel = doc.createElement('div'); sel.appendChild(ele); for (var el, all = sel.getElementsByTagName('*'), i = all.length; i--;) { el = all[i]; if (el.style && el.style.backgroundImage) el.style.backgroundImage = el.style.backgroundImage.replace(reUrl, function (a, prev, url, next) { if (!/^[a-z]+:/.test(url)) url = resolveURL(url, loc.href); return prev + encodeImg(url) + next; }); switch (el.nodeName.toLowerCase()) { case 'link': case 'style': case 'script': el.parentNode.removeChild(el); break; case 'a': case 'area': if (el.hasAttribute('href') && el.getAttribute('href').charAt(0) != '#') el.href = el.href; break; case 'img': case 'input': if (el.hasAttribute('src')) el.src = encodeImg(el.src, el); break; case 'audio': case 'video': case 'embed': case 'frame': case 'iframe': if (el.hasAttribute('src')) el.src = el.src; break; case 'object': if (el.hasAttribute('data')) el.data = el.data; break; case 'form': if (el.hasAttribute('action')) el.action = el.action; break; } }; var head = ele.insertBefore(doc.createElement('head'), ele.firstChild); var meta = doc.createElement('meta'); meta.httpEquiv = 'content-type'; meta.content = 'text/html; charset=utf-8'; head.appendChild(meta); var title = doc.getElementsByTagName('title')[0]; if (title) head.appendChild(title.cloneNode(true)); head.copyScript = function (unsafeWin) { if ('$' in unsafeWin) return; var f = doc.createElement('iframe'); f.src = 'about:blank'; f.setAttribute('style', 'position:fixed;left:0;top:0;visibility:hidden;width:0;height:0;'); doc.documentElement.appendChild(f); var str, script = doc.createElement('script'); script.type = 'text/javascript'; for (var name in unsafeWin) { if (name in f.contentWindow || !/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)) continue; try { str = toSrc(unsafeWin[name]); if (!/\{\s*\[native code\]\s*\}/.test(str)) { script.appendChild(doc.createTextNode('var ' + name + ' = ' + str.replace(/<\/(script>)/ig, '<\\/$1') + ';\n')); } } catch (e) {}; }; f.parentNode.removeChild(f); if (script.childNodes.length) this.nextSibling.appendChild(script); }; head.copyScript(win.wrappedJSObject || win); head.copyStyle = function (s) { if (!s) return; var style = doc.createElement('style'); style.type = 'text/css'; if (s.media && s.media.mediaText) style.media = s.media.mediaText; try { for (var i = 0, rule; rule = s.cssRules[i]; i++) { if (rule.type != 3) { if((!rule.selectorText || rule.selectorText.indexOf(':') != -1) || (!sel.querySelector || sel.querySelector(rule.selectorText))) { var css = !rule.cssText ? '' : rule.cssText.replace(reUrl, function (a, prev, url, next) { if (!/^[a-z]+:/.test(url)) url = resolveURL(url, s.href || loc.href); if(rule.type == 1 && rule.style && rule.style.backgroundImage) url = encodeImg(url); return prev + url + next; }); style.appendChild(doc.createTextNode(css + '\n')); } } else { this.copyStyle(rule.styleSheet); } } } catch(e) { if (s.ownerNode) style = s.ownerNode.cloneNode(false); }; this.appendChild(style); }; var sheets = doc.styleSheets; for (var j = 0; j < sheets.length; j++) head.copyStyle(sheets[j]); head.appendChild(doc.createTextNode('\n')); var doctype = '', dt = doc.doctype; if (dt && dt.name) { doctype += '<!DOCTYPE ' + dt.name; if (dt.publicId) doctype += ' PUBLIC \x22' + dt.publicId + '\x22'; if (dt.systemId) doctype += ' \x22' + dt.systemId + '\x22'; doctype += '>\n'; }; var fileName = selWin ? win.getSelection().toString() : (title && title.text ? title.text : loc.pathname.split('/').pop()); fileName = fileName.replace(/[:\\\/<>?*|"]+/g, '_').replace(/\s+/g, ' ').slice(0, 100).replace(/^\s+|\s+$/g, ''); fileName += (" " + new Date().toLocaleFormat("%d.%m.%Y. %H:%M:%S")); if(!/\.html?$/.test(fileName))fileName += '.html'; saveToFile(doctype + sel.innerHTML + '\n<!-- This document saved from ' + (loc.protocol != 'data:' ? loc.href : 'data:uri') + ' -->', fileName);
Отредактировано firepox (22-07-2018 21:35:42)
Отсутствует