Сортировка закладок по типу, названию и домену( Firefox 12 + )
Автор: bunda1, Dumby, hydrolizer
Версия: от 05.07.2014.
Описание: Kод добавляет в контекстное меню папок закладок новый пункт Сортировать по типу, названию и домену который сортирует закладки по типу, названию и домену. Код при сортировке удаляет разделители, а подпапки закладок если такие имеются отсортирование по названию перемещает в начало папки закладок, за подпапками ставит обычные закладки отсортирование по названию, а за ними закладки по доменным группам и каждая группа отсортирована по названию. После сортировки порядок папке будет вот такой:
1. Папки, отсортирование по названию
2. Закладки без одинаковых доменов, отсортирование по названию,
3. Закладки по доменным группам, каждая группа отсортирована по названию.
При сортировке по названию порядок сортировки вот такой: цифры --> английский --> кириллица.
// Добавить новый пункт "Сортировать по типу, названию и домену" в меню папок закладок, от 05.07.2014. ................................ (function() { var menuitem = document.createElement("menuitem"); menuitem.id = "placesContext_sortBy:locationAndName"; menuitem.setAttribute("label", "Сортировать по домену и названию"); menuitem.setAttribute("selection", "folder"); menuitem.setAttribute("closemenu", "single"); menuitem.setAttribute("oncommand", "this.run(document)"); // если клик или команда на пункте меню menuitem.run = function(doc) { // получить Id и контент папки закладок var node = PlacesUIUtils.getViewForNode( doc.popupNode ).selectedNode; var folderId = node.folderItemId ? node.folderItemId : node.itemId; var contents = PlacesUtils.getFolderContents( folderId, false, false ).root; // удалить разделители из папки закладок, создать массив с закладками и массив c подпапками закладок for ( var primaryList = [], foldersList = [], i = 0; i < contents.childCount; ++i ) { var item = contents.getChild(i); item.type == 7 ? (PlacesUtils.bookmarks.removeItem( item.itemId ), i--) // удалить разделители : (!item.type ? primaryList : foldersList).push( item ); // заполнить массивы } // создать массив с закладками у которых есть одинаковые домены и массив c обычными закладками primaryList.forEach(function(item) { var domain = item.uri.split(/\/+/g)[1]; primaryList[domain] = domain in primaryList; }); var domainList = [], placesList = []; primaryList.forEach(function(item) ( primaryList[item.uri.split(/\/+/g)[1]] ? domainList : placesList ).push(item) ); // создать функцию сортировки var sort = function(arr, prop, mod) { mod = mod || function(arg) arg; arr.sort(function(a, b) mod(a[prop]).localeCompare(mod(b[prop]), "en")); } // отсортировать все массивы по названию и массив с одинаковыми доменам по доменам sort( foldersList, "title"); sort( placesList, "title"); sort( domainList, "title"); sort( domainList, "uri", function(uri) uri.split(/\/+/g)[1] ); // соединить в нужном порядке все массивы в новом массиве var newPlacesList = foldersList.concat( placesList ).concat( domainList ); // изменить меню закладок в соответствии с новым массивом let callback = { runBatched: function() { for( let i = 0; i < newPlacesList.length; ++i ) PlacesUtils.bookmarks.setItemIndex( newPlacesList[i].itemId, i ); } } PlacesUtils.bookmarks.runInBatchMode( callback, null ); }; // добавить новый пункт во все меню папок закладок .... function handlePopup(e) { var node = e.target; if ( node.id !== 'placesContext' ) return; var sortByName = node.getElementsByAttribute("id", "placesContext_sortBy:name")[0]; setTimeout(function() { menuitem.setAttribute("disabled", sortByName.disabled ) }, 50 ); // отключать, если 'Сортировать по имени' отключено if ( node.getElementsByAttribute("id", "placesContext_sortBy:locationAndName")[0] ) return; // блокировать дублирование node.insertBefore( menuitem, sortByName ); }; addEventListener("popupshowing", handlePopup, true, window ); addDestructor(function() menuitem.parentNode && menuitem.parentNode.removeChild(menuitem) ); // Добавить новый пункт во все меню папок закладок библиотеки .... function winObs( subject ) { subject.addEventListener("load", function(e) { this.removeEventListener( e.type, arguments.callee ); if ( subject.location.href !== 'chrome://browser/content/places/places.xul' ) return; // стоп, если не библиотека // добавлять и удалять обработчик для добавления в меню папок закладок новый пункт addEventListener("popupshowing", handlePopup, true, subject ); this.addEventListener("unload", function(e) { this.removeEventListener(e.type, arguments.callee ); removeEventListener("popupshowing", handlePopup, true, subject ); }) }) }; Services.ww.registerNotification(winObs); addDestructor(function() { Services.ww.unregisterNotification(winObs) }); })();
Отредактировано bunda1 (03-08-2014 16:29:09)
Отсутствует
Странно. Почему-то у меня в кнопке popupshowing, повешенный на placesContext, отрабатывает только в случае вызова контекстного меню на папке панели закладок; в сайдбаре и в управлении закладками этот листенер просто не срабатывает. В расширении, из которого код для кнопки, листенер вешается в onLoad() главного окна, и отрабатывает в любом месте вызова. В чем разница - так и не понял.
Отсутствует
hydrolizer
Я попробовал без обработчика на placesContext и вроде все работает, может без него можно ?
Отредактировано bunda1 (23-05-2012 21:46:28)
Отсутствует
bunda1
Ну, в общем можно. Нужно только в атрибуты для пункта меню добавить selection="folder" (чтобы пункт появлялся только при вызове на папке). Там просто делаются доп. проверки на то, что папка не read-only (бывают такие моменты, но это состояние есть только на уровне UI, т.е. операции вполне могут выполняться, и было бы неправильным, если бы можно было изменять содержимое read-only папки), и что содержимое не имеет доп сортировки (а это вроде бы всегда так и есть).
Отсутствует
k1net1k
ПКМ на папке с закладками - в управлении закладками или в сайдбаре - "Сортировать по типу, домену и названию". На саму кнопку нажимать не надо, её вообще можно спрятать, т.к. весь её нужный код в инициализации.
Отсутствует
Нажал добавить кнопку -> положил верхний код в инициализацию -> нажал "Ок"
Нажал закладки -> ПКМ по папке -> контекстное меню не открывается
Зашел в "Показать все закладки" -> ПКМ по папке там есть только "Сортировать по имени"
ЧЯДНТ?
Отсутствует
ЧЯДНТ?
Всё так. Просто пока кнопка не готова.
bunda1
Я понял, в чем дело. У меня в расширении пункт меню внедряется так: в chrome.manifest указано
overlay chrome://browser/content/places/placesOverlay.xul chrome://uithings/content/places-overlay.xul
<overlay id="places-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <script type="application/javascript" src="chrome://uithings/content/sortplaces.js"/> <menupopup id="placesContext"> <menuitem id="uithings-places-sort" label="&uithings.placessort.menuitem;" closemenu="single" selection="folder" insertafter="placesContext_sortBy:name" oncommand="uithings.placessort.sort()"/> </menupopup> </overlay>
Тут нюанс в том, что chrome://browser/content/places/placesOverlay.xul, как и chrome://uithings/content/places-overlay.xul (это оверлей моего расширения) - не DOM-документы, это именно оверлеи. Из этих оверлеев конструируются документы при запуске браузера и загрузке расширений - происходит слияние оверлеев (подробнее прочитать можно, например, здесь). Поскольку у меня пункт меню уже жестко вписан в оверлей, то он в нем и находится, и при слиянии оверлеев копируется во все документы, структура которых сливается с оверлеем places. Поэтому пункт из моего расширения есть везде, где используется placesContext. В случае кнопки мы ищем placesContext по document.getElementById; т.к. документ у нас - главное окно, то и находим то, что в нем есть - placesContext панели закладок (и меню закладок). Управление закладками и сайдбар - это совсем другие документы, поэтому в их placesContext наш пункт меню просто не попадает. Нужно думать, как внедриться в них - на момент старта браузера мы в общем случае к ним не сможем получить доступа, т.к. сайдбар будет закрыт, как и управление закладками.
Отсутствует
hydrolizer
Понятно и жаль, может позже придут решение, вот сейчас я припоминаю что некоторые CB коды что то добавляют в сайдбар, правда не в контекстное меню папки закладок а на sidebar-header. Но не все так плохо - лично я практически не пользуюсь управлением закладками и сайдбаром.
К слову, как узнать название папки закладок на панели закладок, хочу сделать добавление текучей страницы в папку закладок двойным кликом на папке:
window.addEventListener("dblclick", function(event){ if(event.button !== 0) return; var target = event.originalTarget; if ( target.localName == "toolbarbutton" && !!target._placesNode && !PlacesUtils.nodeIsURI(target._placesNode) ) { alert(?????) } },true);
Отредактировано bunda1 (24-05-2012 19:25:19)
Отсутствует
К слову, как узнать название папки закладок на панели закладок
Тут нужно не название, а id этой папки. Примерно так:
document.getElementById("PlacesToolbar").addEventListener("dblclick", function(event) { if(event.button !== 0) return; var target = event.originalTarget; Cu.import("resource://gre/modules/PlacesUtils.jsm"); if (!(target.localName == "toolbarbutton" && !!target._placesNode && PlacesUtils.nodeIsFolder(target._placesNode) && !PlacesUtils.nodeIsReadOnly(target._placesNode))) return; var folderId=PlacesUtils.getConcreteItemId(target._placesNode); var currentDocURI = Services.io.newURI(gBrowser.contentDocument.location.href,null,null); let callback = { runBatched: function() { PlacesUtils.bookmarks.insertBookmark(folderId, currentDocURI, Ci.nsINavBookmarksService.DEFAULT_INDEX, null); } } PlacesUtils.bookmarks.runInBatchMode(callback, null); Services.console.logStringMessage("bookmark created"); }, false);
Отсутствует
Отсутствует
Все работает, но есть одна непонятка если открыть свойства добавленной закладки:
В PlacesUtils.bookmarks.insertBookmark последним параметром передавайте не null, а gBrowser.contentTitle.
Отсутствует
Эм теперь то можно сортировать по домену или нет?
Можно, но нужный пункт меню есть только в папках закладок на панели закладок .
Отсутствует
Можно, но нужный пункт меню есть только в папках закладок на панели закладок .
Должен быть еще в меню закладок (т.е. контекстное меню пунктов меню закладок).
Отсутствует
Должен быть еще в меню закладок (т.е. контекстное меню пунктов меню закладок).
Нету, и мне кажется не должно быть, потому что в контекстном меню пунктов меню закладок нету пункта Сортировать по имени:
SortByName = document.getElementById("placesContext_sortBy:name")
SortByName.parentNode.insertBefore(menuitem, SortByName );
Отредактировано bunda1 (30-05-2012 20:33:39)
Отсутствует
bunda1
Вот скриншот с нового чистого профиля - установлены только CB:
Отредактировано hydrolizer (31-05-2012 03:42:21)
Отсутствует
hydrolizer
Да я ошибся, я добавлю это в описание кода.
Да, кстати: чтобы при вызове операции таким вот образом - из контекстного меню на пункте другого меню - не схлопывалось основное меню, а только контекстное, для menuitem нужен еще один атрибут: closemenu="single".
Ok.
Отсутствует
Подскажите как убрать этот момент
Отредактировано bunda1 (02-06-2012 13:50:09)
Отсутствует