📄 utils.js
字号:
/** * Get the POST data associated with a bookmark, if any. * @param aBookmarkId * @returns string of POST data if set for aBookmarkId. null otherwise. */ getPostDataForBookmark: function PU_getPostDataForBookmark(aBookmarkId) { const annos = this.annotations; if (annos.itemHasAnnotation(aBookmarkId, POST_DATA_ANNO)) return annos.getItemAnnotation(aBookmarkId, POST_DATA_ANNO); return null; }, /** * Get the URI (and any associated POST data) for a given keyword. * @param aKeyword string keyword * @returns an array containing a string URL and a string of POST data */ getURLAndPostDataForKeyword: function PU_getURLAndPostDataForKeyword(aKeyword) { var url = null, postdata = null; try { var uri = this.bookmarks.getURIForKeyword(aKeyword); if (uri) { url = uri.spec; var bookmarks = this.bookmarks.getBookmarkIdsForURI(uri, {}); for (let i = 0; i < bookmarks.length; i++) { var bookmark = bookmarks[i]; var kw = this.bookmarks.getKeywordForBookmark(bookmark); if (kw == aKeyword) { postdata = this.getPostDataForBookmark(bookmark); break; } } } } catch(ex) {} return [url, postdata]; }, /** * Get all bookmarks for a URL, excluding items under tag or livemark * containers. */ getBookmarksForURI: function PU_getBookmarksForURI(aURI) { var bmkIds = this.bookmarks.getBookmarkIdsForURI(aURI, {}); // filter the ids list return bmkIds.filter(function(aID) { var parent = this.bookmarks.getFolderIdForItem(aID); // Livemark child if (this.annotations.itemHasAnnotation(parent, LMANNO_FEEDURI)) return false; var grandparent = this.bookmarks.getFolderIdForItem(parent); // item under a tag container if (grandparent == this.tagsFolderId) return false; return true; }, this); }, /** * Get the most recently added/modified bookmark for a URL, excluding items * under tag or livemark containers. -1 is returned if no item is found. */ getMostRecentBookmarkForURI: function PU_getMostRecentBookmarkForURI(aURI) { var bmkIds = this.bookmarks.getBookmarkIdsForURI(aURI, {}); for (var i = 0; i < bmkIds.length; i++) { // Find the first folder which isn't a tag container var bk = bmkIds[i]; var parent = this.bookmarks.getFolderIdForItem(bk); if (parent == this.unfiledBookmarksFolderId) return bk; var grandparent = this.bookmarks.getFolderIdForItem(parent); if (grandparent != this.tagsFolderId && !this.annotations.itemHasAnnotation(parent, LMANNO_FEEDURI)) return bk; } return -1; }, getMostRecentFolderForFeedURI: function PU_getMostRecentFolderForFeedURI(aURI) { var feedSpec = aURI.spec var annosvc = this.annotations; var livemarks = annosvc.getItemsWithAnnotation(LMANNO_FEEDURI, {}); for (var i = 0; i < livemarks.length; i++) { if (annosvc.getItemAnnotation(livemarks[i], LMANNO_FEEDURI) == feedSpec) return livemarks[i]; } return -1; }, // Returns true if a container has uris in its first level // Has better performances than checking getURLsForContainerNode(node).length hasChildURIs: function PU_hasChildURIs(aNode) { if (!this.nodeIsContainer(aNode)) return false; // in the Library left pane we use excludeItems if (this.nodeIsFolder(aNode) && asQuery(aNode).queryOptions.excludeItems) { var itemId = PlacesUtils.getConcreteItemId(aNode); var contents = this.getFolderContents(itemId, false, false).root; for (var i = 0; i < contents.childCount; ++i) { var child = contents.getChild(i); if (this.nodeIsURI(child)) return true; } return false; } var wasOpen = aNode.containerOpen; if (!wasOpen) aNode.containerOpen = true; var found = false; for (var i = 0; i < aNode.childCount && !found; i++) { var child = aNode.getChild(i); if (this.nodeIsURI(child)) found = true; } if (!wasOpen) aNode.containerOpen = false; return found; }, getURLsForContainerNode: function PU_getURLsForContainerNode(aNode) { let urls = []; if (this.nodeIsFolder(aNode) && asQuery(aNode).queryOptions.excludeItems) { // grab manually var itemId = this.getConcreteItemId(aNode); let contents = this.getFolderContents(itemId, false, false).root; for (let i = 0; i < contents.childCount; ++i) { let child = contents.getChild(i); if (this.nodeIsURI(child)) urls.push({uri: child.uri, isBookmark: this.nodeIsBookmark(child)}); } } else { let result, oldViewer, wasOpen; try { let wasOpen = aNode.containerOpen; result = aNode.parentResult; oldViewer = result.viewer; if (!wasOpen) { result.viewer = null; aNode.containerOpen = true; } for (let i = 0; i < aNode.childCount; ++i) { // Include visible url nodes only let child = aNode.getChild(i); if (this.nodeIsURI(child)) { // If the node contents is visible, add the uri only if its node is // visible. Otherwise follow viewer's collapseDuplicates property, // default to true if ((wasOpen && oldViewer && child.viewIndex != -1) || (oldViewer && !oldViewer.collapseDuplicates) || urls.indexOf(child.uri) == -1) { urls.push({ uri: child.uri, isBookmark: this.nodeIsBookmark(child) }); } } } if (!wasOpen) aNode.containerOpen = false; } finally { if (!wasOpen) result.viewer = oldViewer; } } return urls; }, /** * Restores bookmarks/tags from a JSON file. * WARNING: This method *removes* any bookmarks in the collection before * restoring from the file. * * @param aFile * nsIFile of bookmarks in JSON format to be restored. * @param aExcludeItems * Array of root item ids (ie: children of the places root) * to not delete when restoring. */ restoreBookmarksFromJSONFile: function PU_restoreBookmarksFromJSONFile(aFile, aExcludeItems) { // open file stream var stream = Cc["@mozilla.org/network/file-input-stream;1"]. createInstance(Ci.nsIFileInputStream); stream.init(aFile, 0x01, 0, 0); var converted = Cc["@mozilla.org/intl/converter-input-stream;1"]. createInstance(Ci.nsIConverterInputStream); converted.init(stream, "UTF-8", 1024, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); // read in contents var str = {}; var jsonStr = ""; while (converted.readString(4096, str) != 0) jsonStr += str.value; converted.close(); if (jsonStr.length == 0) return; // empty file this.restoreBookmarksFromJSONString(jsonStr, true, aExcludeItems); }, /** * Import bookmarks from a JSON string. * * @param aString * JSON string of serialized bookmark data. * @param aReplace * Boolean if true, replace existing bookmarks, else merge. * @param aExcludeItems * Array of root item ids (ie: children of the places root) * to not delete when restoring. */ restoreBookmarksFromJSONString: function PU_restoreBookmarksFromJSONString(aString, aReplace, aExcludeItems) { // convert string to JSON var nodes = this.unwrapNodes(aString, this.TYPE_X_MOZ_PLACE_CONTAINER); if (nodes.length == 0 || !nodes[0].children || nodes[0].children.length == 0) return; // nothing to restore // ensure tag folder gets processed last nodes[0].children.sort(function sortRoots(aNode, bNode) { return (aNode.root && aNode.root == "tagsFolder") ? 1 : (bNode.root && bNode.root == "tagsFolder") ? -1 : 0; }); var batch = { _utils: this, nodes: nodes[0].children, runBatched: function restore_runBatched() { if (aReplace) { var excludeItems = aExcludeItems || []; // delete existing children of the root node, excepting: // 1. special folders: delete the child nodes // 2. tags folder: untag via the tagging api var query = this._utils.history.getNewQuery(); query.setFolders([this._utils.placesRootId], 1); var options = this._utils.history.getNewQueryOptions(); options.expandQueries = false; var root = this._utils.history.executeQuery(query, options).root; root.containerOpen = true; var childIds = []; for (var i = 0; i < root.childCount; i++) { var childId = root.getChild(i).itemId; if (excludeItems.indexOf(childId) == -1) childIds.push(childId); } root.containerOpen = false; for (var i = 0; i < childIds.length; i++) { var rootItemId = childIds[i]; if (rootItemId == this._utils.tagsFolderId) { // remove tags via the tagging service var tags = this._utils.tagging.allTags; var uris = []; for (let i in tags) { var tagURIs = this._utils.tagging.getURIsForTag(tags[i]); for (let j in tagURIs) this._utils.tagging.untagURI(tagURIs[j], [tags[i]]); } } else if ([this._utils.toolbarFolderId, this._utils.unfiledBookmarksFolderId, this._utils.bookmarksMenuFolderId].indexOf(rootItemId) != -1) this._utils.bookmarks.removeFolderChildren(rootItemId); else this._utils.bookmarks.removeItem(rootItemId); } } var searchIds = []; var folderIdMap = []; this.nodes.forEach(function(node) { if (!node.children || node.children.length == 0) return; // nothing to restore for this root if (node.root) { var container = this.placesRootId; // default to places root switch (node.root) { case "bookmarksMenuFolder": container = this.bookmarksMenuFolderId; break; case "tagsFolder": container = this.tagsFolderId; break; case "unfiledBookmarksFolder": container = this.unfiledBookmarksFolderId; break; case "toolbarFolder": container = this.toolbarFolderId; break; } // insert the data into the db node.children.forEach(function(child) { var index = child.index; var [folders, searches] = this.importJSONNode(child, container, index); folderIdMap = folderIdMap.concat(folders); searchIds = searchIds.concat(searches); }, this); } else this.importJSONNode(node, this.placesRootId, node.index); }, this._utils); // fixup imported place: uris that contain folders searchIds.forEach(function(aId) { var oldURI = this.bookmarks.getBookmarkURI(aId); var uri = this._fixupQuery(this.bookmarks.getBookmarkURI(aId), folderIdMap); if (!uri.equals(oldURI)) this.bookmarks.changeBookmarkURI(aId, uri); }, this._utils); } }; this.bookmarks.runInBatchMode(batch, null); }, /** * Takes a JSON-serialized node and inserts it into the db. * * @param aData * The unwrapped data blob of dropped or pasted data. * @param aContainer * The container the data was dropped or pasted into * @param aIndex * The index within the container the item was dropped or pasted at * @returns an array containing of maps of old folder ids to new folder ids, * and an array of saved search ids that need to be fixed up. * eg: [[[oldFolder1, newFolder1]], [search1]] */ importJSONNode: function PU_importJSONNode(aData, aContainer, aIndex) { var folderIdMap = []; var searchIds = []; var id = -1; switch (aData.type) { case this.TYPE_X_MOZ_PLACE_CONTAINER: if (aContainer == PlacesUtils.bookmarks.tagsFolder) { if (aData.children) { aData.children.forEach(function(aChild) { this.tagging.tagURI(this._uri(aChild.uri), [aData.title]); }, this); return [folderIdMap, searchIds]; } } else if (aData.livemark && aData.annos) { // node is a livemark var feedURI = null; var siteURI = null; aData.annos = aData.annos.filter(function(aAnno) { if (aAnno.name == LMANNO_FEEDURI) { feedURI = this._uri(aAnno.value); return false; } else if (aAnno.name == LMANNO_SITEURI) { siteURI = this._uri(aAnno.value); return false; } return true; }, this); if (feedURI) id = this.livemarks.createLivemark(aContainer, aData.title, siteURI, feedURI, aIndex); } else { id = this.bookmarks.createFolder(aContainer, aData.title, aIndex); folderIdMap.push([aData.id, id]); // process children if (aData.children) { aData.children.every(function(aChild, aIndex) { var [folderIds, searches] = this.importJSONNode(aChild, id, aIndex); folderIdMap = folderIdMap.concat(folderIds); searchIds = searchIds.concat(searches); return true; }, this); } } break; case this.TYPE_X_MOZ_PLACE: id = this.bookmarks.insertBookmark(aContainer, this._uri(aData.uri), aIndex, aData.title); if (aData.keyword) this.bookmarks.setKeywordForBookmark(id, aData.keyword); if (aData.tags) { var tags = aData.tags.split(", "); if (tags.length) this.tagging.tagURI(this._uri(aData.uri), tags); } if (aData.charset) this.history.setCharsetForURI(this._uri(aData.uri), aData.charset); if (aData.uri.match(/^place:/)) searchIds.push(id); break; case this.TYPE_X_MOZ_PLACE_SEPARATOR: id = this.bookmarks.insertSeparator(aContainer, aIndex);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -