Там eval есть, не знаю, будет ли работать не 139
Гугл не требует сейчас хеш, я без него обхожусь. Ранее гуру подсказал на смежном форуме, что эта строка с eval - обманка, запутывание кода
Отсутствует
замените в своем Save_Script.js
Спасибо, все работает как надо.
«The Truth Is Out There»
Отсутствует
// Счетчик папок/url в паках библиотеки/боковой панели (when used Places Tree)
// + восстановление создания папок/закладок для библиотеки во вкладке
/** @UCF @param {"prop":"JsAllChrome.DOMContentLoaded","urlregxp":"^chrome:\\/\\/browser\\/content\\/(?:browser|places\\/(?:bookmarksSidebar|historySidebar|places))\\.xhtml"} @UCF @UCF @param {"prop":"JsContent.DOMContentLoaded","urlregxp":"^chrome:\\/\\/browser\\/content\\/(?:browser|places\\/(?:bookmarksSidebar|historySidebar|places))\\.xhtml"} @UCF */ // Счетчик папок/url в паках библиотеки/боковой панели (when used Places Tree) // + восстановление создания папок/закладок для библиотеки во вкладке // 2025.5.25 + библиотека, правка Vitaliy V. // 2025.3.10 https://forum.mozilla-russia.org/viewtopic.php?pid=812525#p812525 (async () => { var proto = PlacesTreeView.prototype; proto.addFolderStats = node => { var title = PlacesUIUtils.getBestTitle(node, true); try { if (PlacesUtils.nodeIsContainer(node)) { let query = {}, options = {}; PlacesUtils.history.queryStringToQuery(node.uri, query, options); node = PlacesUtils.history.executeQuery(query.value, options.value).root; if (!node.hasChildren) return title += " (0/0)"; let wasClosed = !node.containerOpen; if (wasClosed) node.containerOpen = true; let urls = 0, containers = 0; for (let ind = 0, max = node.childCount; ind < max; ind++) { let child = node.getChild(ind); if (PlacesUtils.nodeIsURI(child)) urls++; else if (PlacesUtils.nodeIsContainer(child)) containers++; } if (wasClosed) node.containerOpen = false; title += ` (${urls}/${containers})`; } } catch (e) { console.error(e); } finally { return title; } }; Object.assign(proto, windowRoot.ownerGlobal.UcfPrefs.dbg .makeGlobalObjectReference(window).executeInGlobal(`({getCellText: ${proto.getCellText}})`.replace( "PlacesUIUtils.getBestTitle(node, true)", "this.addFolderStats(node)")).return.unsafeDereference()); window.top.gDialogBox ??= windowRoot.ownerGlobal.gDialogBox; window.top.BookmarksEventHandler ??= windowRoot.ownerGlobal.BookmarksEventHandler; })();
Отсутствует
Пункт в контекстном меню закладок - Вернуть удаленное, восстановлена работа для библиотеки открытой во вкладке.
/** @UCF @param {"prop":"JsAllChrome.load","urlregxp":"^chrome:\\/\\/browser\\/content\\/(?:browser|places\\/(?:bookmarksSidebar|places))\\.xhtml"} @UCF @UCF @param {"prop":"JsContent.pageshow","urlregxp":"^chrome:\\/\\/browser\\/content\\/places\\/(?:bookmarksSidebar|places)\\.xhtml"} @UCF */ // Пункт в контекстном меню закладок - Вернуть удаленное // появляется только если есть чего возвращать // https://forum.mozilla-russia.org/viewtopic.php?pid=798678#p798678 // https://forum.mozilla-russia.org/viewtopic.php?pid=801497#p801497 // https://forum.mozilla-russia.org/viewtopic.php?pid=816728#p816728 // правка Vitaliy V. 250525 (async sep => { if (!sep) return; var key = "hasRemoveTransaction"; var raws = windowRoot.ownerGlobal.UcfPrefs.dbg.ref("lazy", PlacesTransactions.undo).TransactionsHistory.proxifiedToRaw; raws[key] ??= entry => { for(var transaction of entry) { if (raws.get(transaction) instanceof PlacesTransactions.Remove) return true; } } var menuitem = document.createXULElement("menuitem"); for(var args of Object.entries({ closemenu: "single", class: "menuitem-iconic", id: "placesCmd_undoRemove", label: "Вернуть удаленное", image: "data:image/svg+xml;base64,77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNTAgNTAiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+DQogIDxwYXRoIGQ9Ik0yMC44NzUgMTFDMjAuNjkxNDA2IDExLjAyMzQzOCAyMC41MTk1MzEgMTEuMTAxNTYzIDIwLjM3NSAxMS4yMTg3NUw0LjM3NSAyNC4yMTg3NUM0LjEzNjcxOSAyNC40MTAxNTYgNCAyNC42OTUzMTMgNCAyNUM0IDI1LjMwNDY4OCA0LjEzNjcxOSAyNS41ODk4NDQgNC4zNzUgMjUuNzgxMjVMMjAuMzc1IDM4Ljc4MTI1QzIwLjY3NTc4MSAzOS4wMjM0MzggMjEuMDg1OTM4IDM5LjA3MDMxMyAyMS40MzM1OTQgMzguOTAyMzQ0QzIxLjc4MTI1IDM4LjczNDM3NSAyMiAzOC4zODI4MTMgMjIgMzhMMjIgMzEuMDkzNzVDMzIuNjA1NDY5IDMxLjMwODU5NCAzOC4wOTM3NSAzNC40OTYwOTQgNDAuOTA2MjUgMzcuNjU2MjVDNDMuNzY5NTMxIDQwLjg3ODkwNiA0My45OTIxODggNDMuOTA2MjUgNDQgNDRDNDQgNDQgNDQgNDQuMDYyNSA0NCA0NC4wNjI1QzQ0LjAxNTYyNSA0NC42MTMyODEgNDQuNDgwNDY5IDQ1LjA0Njg3NSA0NS4wMzEyNSA0NS4wMzEyNUM0NS41ODIwMzEgNDUuMDE1NjI1IDQ2LjAxNTYyNSA0NC41NTA3ODEgNDYgNDRDNDYgNDQgNDYgNDMuOTM3NSA0NiA0My45Mzc1QzQ2IDQzLjkzNzUgNDYgNDMuODc1IDQ2IDQzLjg3NUM0NS45OTYwOTQgNDMuNjgzNTk0IDQ1Ljg4NjcxOSAzNy42OTkyMTkgNDIuNzgxMjUgMzEuNTYyNUMzOS43MTg3NSAyNS41MDc4MTMgMzMuNTExNzE5IDE5LjQxNDA2MyAyMiAxOS4wNjI1TDIyIDEyQzIyLjAwMzkwNiAxMS43MTA5MzggMjEuODc4OTA2IDExLjQzNzUgMjEuNjY0MDYzIDExLjI0NjA5NEMyMS40NDkyMTkgMTEuMDU0Njg4IDIxLjE2MDE1NiAxMC45NjQ4NDQgMjAuODc1IDExIFogTSAyMCAxNC4wOTM3NUwyMCAyMEMyMCAyMC41NTA3ODEgMjAuNDQ5MjE5IDIxIDIxIDIxQzMyLjUxMTcxOSAyMSAzOC4wODIwMzEgMjYuNjcxODc1IDQxIDMyLjQzNzVDNDEuNzQyMTg4IDMzLjkwNjI1IDQyLjI5Njg3NSAzNS4zNzUgNDIuNzE4NzUgMzYuNzVDNDIuNjAxNTYzIDM2LjYwOTM3NSA0Mi41MzEyNSAzNi40ODQzNzUgNDIuNDA2MjUgMzYuMzQzNzVDMzkuMDg5ODQ0IDMyLjYxMzI4MSAzMi43NTM5MDYgMjkgMjEgMjlDMjAuNDQ5MjE5IDI5IDIwIDI5LjQ0OTIxOSAyMCAzMEwyMCAzNS45MDYyNUw2LjU5Mzc1IDI1WiIgZmlsbD0iI0I0QjRCNCIgLz4NCjwvc3ZnPg==", })) menuitem.setAttribute(...args); menuitem.addEventListener("command", () => PlacesTransactions.undo().catch(Cu.reportError)); var desc = Object.getOwnPropertyDescriptor(XULElement.prototype, "hidden"); var {set} = desc; desc.set = () => { var entry = PlacesTransactions.topUndoEntry; set.call(menuitem, !entry || !raws[key](entry)); } Object.defineProperty(menuitem, "disabled", {}); Object.defineProperty(menuitem, "hidden", desc); sep.before(menuitem); })(document.getElementById("placesContext_deleteSeparator"));
Отсутствует
xrun1
Далеко ходить не пришлось.
Строку с TKK=eval заменить на
// var TKK = ((function() { var a = 817046147; var b = -335196159; return 410049 + '.' + (a + b); })());
Отредактировано _zt (25-05-2025 21:50:25)
Отсутствует
// Счетчик папок/url в паках библиотеки/боковой панели (when used Places Tree)
// + восстановление создания папок/закладок для библиотеки во вкладке
Вернулся на свой старый вариант. Пусть у меня показывает кол-во только в боковой панели, зато работает шустро.
egorsemenov06
Спасибо за идею с иконками.
Отсутствует
Этот тоже в панели работает шустро, это в библиотеках задержка.
Хуже. Чистый портабельный 138.0.3, крайний UCF. Один скрипт №2103. Открываю боковую панель с историей. Жду, пока прочтёт. Кликаю на любое другое окно, возвращаюсь. Курсор крутится, даже скриншот сделать не могу нормальный, система не реагирует на клавишу PrtScr. История у меня не самая большая, но есть: places.sqlite - 75Мб, favicons.sqlite - 43Мб.
https://imgsh.net/i/0d4bf11256
https://imgsh.net/i/16ce17d627
Общий скриншот сделаль не получается, выше объяснил.
И даже подключение попроще
проблему не решает.
Добавлено 26-05-2025 18:49:35
Я без претензий. Обновляться дело индивидуальное. Это просто так, для информации чисто.
Отредактировано xrun1 (26-05-2025 18:49:35)
Отсутствует
Курсор крутится, даже скриншот сделать не могу нормальный, система не реагирует на клавишу PrtScr.
Интересно, что будет, если из этого тормозного скрипта удалить строчки:
PlacesUtils.history.queryStringToQuery(node.uri, query, options); node = PlacesUtils.history.executeQuery(query.value, options.value).root;
Отсутствует
xrun1
Его никто не тестировал на 138, подождите хотя бы до 139. Тем более что старый скрипт тогда и отвалится. На 140 он даже в библиотеках уже загружен, если их открыть не прямо сразу после запуска браузера.
Не надо ничего пробовать, скрипт не для 138.
Отредактировано _zt (26-05-2025 20:32:45)
Отсутствует
Независимо от версии браузера, скрипт медленный - просто потому, что использует очень медленное API, да ещё и медленным способом.
Places API медленное невероятно - перебор тех же самых элементов через SQL API у меня на компьютере отрабатывает примерно в 150 раз быстрее.
После этого скрипт начинает поштучно перебирать все эти элементы (доступаясь к каждому через getChild(i)) и смотреть - URI это или папка. Если URI - к счётчику URI прибавляется 1, если папка - 1 прибавляется к счётчику папок.
Но зачем вся эта длительная процедура нужна, если перебора можно избежать "вообще и начисто"?
В Журнале все элементы любой папки будут однотипными: либо все - папки, либо все - URI. Поэтому берём getChild(0), смотрим тип. Если папка, значит здесь childCount папок. В противном случае имеем childCount URI. Всё!
С Закладками не так просто - там в папках содержимое может быть разнотипным. Но и с этим можно справиться, что называется, "в два щелчка".
Как я уже сказал, результат того запроса, который отправляется сейчас, в childCount будет содержать число всех элементов, содержащихся в node. Но если отправить ещё один запрос, выставив для него options.excludeItems = true, то его результат у себя в childCount будет содержать число подпапок в node.
Вычитаем из числа всех элементов число подпапок и получаем... Получаем число закладок и разделителей, содержащихся в node. Увы, но получить отдельно число закладок или разделителей возможности нет.
Но если принять для себя, что показывать число не именно закладок, а и разделителей тоже, это по-своему правильно, то получаем очень быстрый алгоритм без каких-либо переборов.
Однако даже если хотеть видеть число именно закладок - тоже не страшно. Закладки в одной папке вряд ли тысячами лежать будут, а для node из какого раздела предстоит отправлять запрос, определяется элементарно - у любого node есть свойства bookmarkIndex и itemId, которые >= 0 для элементов Закладок и равны -1 во всех остальных случаях.
Так что: для Журнала используем метод, изложенный выше, а для node из Закладок можно и перебором позаниматься.
Отредактировано yup (Вчера 02:29:22)
Отсутствует
Интересно, что будет, если из этого тормозного скрипта удалить строчки:
Будет то, что, лично мне, и нужно - работает. Количества в окне библиотек не будет. Но я этим и не пользуюсь.
P.S. И чего мне бояться, что отвалится что-то в 139-й? Я уже это проходил в 2014-м, когда отвалился целиком браузер.
Добавлено 26-05-2025 23:45:47
yup
3523 - это при сортировке по дате и сайтам. По дате https://imgsh.net/i/44868e55e6
Отредактировано xrun1 (26-05-2025 23:45:47)
Отсутствует
3523 - это при сортировке по дате и сайтам. По дате https://imgsh.net/i/44868e55e6
Посмотрел на эту картинку. Сопоставил с предыдущей. Удивился. Расчехлил тот браузер, который у меня Firefox-ом считается, полез изучать его боковую панель. Я им мало пользуюсь, а боковой панелью вообще нигде и никогда, зато хорошо знаю, что у в окне Библиотека в разделе Журнал никаких группировок нет - меня это всегда удручало (радовало только то, что я
не пользуюсь).
А оказывается, там в Боковой панели группировки таки есть. Пришлось мой текст переписать.
Отсутствует
/** @UCF @param {"prop":"JsAllChrome.DOMContentLoaded","urlregxp":"^chrome:\\/\\/browser\\/content\\/places\\/(?:bookmarksSidebar|historySidebar|places)\\.xhtml"} @UCF @UCF @param {"prop":"JsContent.DOMWindowCreated","urlregxp":"^chrome:\\/\\/browser\\/content\\/places\\/(?:bookmarksSidebar|historySidebar|places)\\.xhtml"} @UCF */ // Счетчики url/папок в библиотеке, боковой панели (when used Places Tree) // 2025.5.27 улучшение быстродействия для historySidebar, правка Vitaliy V. // 2025.5.26 улучшение быстродействия, в библиотеке счетчики только в left places pane, правка Vitaliy V. // 2025.5.25 + библиотека, правка Vitaliy V. // 2025.3.10 https://forum.mozilla-russia.org/viewtopic.php?pid=812525#p812525 (async () => { var tree = document.querySelector("tree#bookmarks-view, tree#historyTree, tree#placesList"); if (!tree) return; var refunc = windowRoot.ownerGlobal.UcfPrefs.dbg .makeGlobalObjectReference(window).executeInGlobal(`({ getCellText: ${PlacesTreeView.prototype.getCellText.toString() .replace("PlacesUIUtils.getBestTitle(node, true)", "this.ucf_counter(node)")}, ucf_counter(node) { var title = PlacesUIUtils.getBestTitle(node, true); if (PlacesUtils.nodeIsContainer(node)) { ${(tree.id === "placesList") ? `let query = {}, options = {}; PlacesUtils.history.queryStringToQuery(node.uri, query, options); options.value.expandQueries = false; options.value.excludeItems = false; node = PlacesUtils.history.executeQuery(query.value, options.value).root;` : ""} if (!node.hasChildren) return title += " (0/0)"; let wasClosed = !node.containerOpen; if (wasClosed) node.containerOpen = true; let urls = 0, containers = 0; ${(tree.id === "historyTree") ? `if (PlacesUtils.nodeIsURI(node.getChild(0))) urls = node.childCount; else containers = node.childCount;` : `for (let ind = 0, max = node.childCount; ind < max; ind++) { let child = node.getChild(ind); if (PlacesUtils.nodeIsURI(child)) urls++; else if (PlacesUtils.nodeIsContainer(child)) containers++; }`} if (wasClosed) node.containerOpen = false; title += \` (\${containers}/\${urls})\`; } return title; }, })`).return.unsafeDereference(); tree.ucf_load = function() { Object.assign(this.view, refunc); }; Object.assign(tree, windowRoot.ownerGlobal.UcfPrefs.dbg .makeGlobalObjectReference(window).executeInGlobal(`({${tree.load}})` .replace(/this\.view\s*=\s*treeView/, "this.view = treeView; this.ucf_load()")).return.unsafeDereference()); // для работы во вкладке, тултипы, диалог добавления закладок и папок ... window.top.gDialogBox ??= windowRoot.ownerGlobal.gDialogBox; window.top.BookmarksEventHandler ??= windowRoot.ownerGlobal.BookmarksEventHandler; })();
Отредактировано _zt (Вчера 14:45:57)
Отсутствует
_zt
Насчёт Агата Вы зря
Самая долгая часть скрипта - не executeQuery(), а for (let ind = 0, max = node.childCount; ind < max; ind++). Именно от этого перебора избавляться надо - тогда любой калькулятор спасибо скажет.
Отсутствует
Обновил скрипт.
Приемлемо. Браузер не виснет, сортировки везде разные.
https://imgsh.net/i/73eb8f6f13
Спасибо.
А это нормально, что скрипт прописался в 3-х местах, хотя строки "@UCF @param" 2?
https://imgsh.net/i/50fbbe1489
Отсутствует
_zt
Удалил файл prefs.json. Очистил все кэши. Запускаю, скрипт прописывается в 3-х местах, но ведь "@UCF @param" в скрипте 2 строки. Т.е. это установка "на чисто". Или где-то есть ещё регистрация, кроме файла prefs.json?
UCF крайний.
Отредактировано xrun1 (Вчера 17:08:29)
Отсутствует
Виталий считает, что как раз эти синхронные запросы и вешали браузер у xrun1.
У xrun1 что, и в самом деле Агат?
У меня на ноутбуке, которому скоро 20 лет стукнет (Celeron, 2ГБ вечно забитой до упора памяти) запрос на получение примерно 6000 записей и их полный программный перебор занимают вместе занимают примерно 4 секунды. У xrun1 на показанной картинке записей чуть больше 5000.
Сам браузер использует точно те же самые синхронные запросы, что и скрипт. И если бы дело было в них, у него и просто заглядывание в старую часть Журнала всё вешало бы. Но похоже, что такого не случалось, раз только сейчас страдания начались.
И его старый скрипт браузер не вешает. Я, конечно, не знаю, как там данные получаются и обрабатываются, но сомневаюсь, что через SQL.
Тут ещё вот что плохо: скрипт (для того, чтобы свои счётчики в таблице показывать) подменяет функцию getCellText(). А у браузера, как оказалось, есть убойная "привычка" - он эту функцию вызывает каждый раз, когда курсор мыши над ячейкой проезжает. Ага - чуть ли не на каждый пиксел перемещения (точнее, на каждое событие mousemove) идёт новый вызов getCellText(). А значит - новый запрос в БД от скриптовой функции и новый подсчёт.
Отредактировано yup (Вчера 17:38:02)
Отсутствует
_zt
Можно, но не нужно. Сейчас работает нормально.
Понимаю, что задолбал. Скрипт не имеет практического смысла, косметический (информативный и для красоты). Но, как говорил герой М. Пуговкина в фильме "Два капитана":
- Палочки должны быть попендикулярны!
Спасибо всем причастным!
Отсутствует