mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-22 16:37:31 +09:00
Issue #303 Part 1: Move basilisk files from /browser to /application/basilisk
This commit is contained in:
parent
a951f19dfd
commit
177b28a898
1938 changed files with 0 additions and 0 deletions
|
|
@ -0,0 +1,693 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* The panel is initialized based on data given in the js object passed
|
||||
* as window.arguments[0]. The object must have the following fields set:
|
||||
* @ action (String). Possible values:
|
||||
* - "add" - for adding a new item.
|
||||
* @ type (String). Possible values:
|
||||
* - "bookmark"
|
||||
* @ loadBookmarkInSidebar - optional, the default state for the
|
||||
* "Load this bookmark in the sidebar" field.
|
||||
* - "folder"
|
||||
* @ URIList (Array of nsIURI objects) - optional, list of uris to
|
||||
* be bookmarked under the new folder.
|
||||
* - "livemark"
|
||||
* @ uri (nsIURI object) - optional, the default uri for the new item.
|
||||
* The property is not used for the "folder with items" type.
|
||||
* @ title (String) - optional, the default title for the new item.
|
||||
* @ description (String) - optional, the default description for the new
|
||||
* item.
|
||||
* @ defaultInsertionPoint (InsertionPoint JS object) - optional, the
|
||||
* default insertion point for the new item.
|
||||
* @ keyword (String) - optional, the default keyword for the new item.
|
||||
* @ postData (String) - optional, POST data to accompany the keyword.
|
||||
* @ charSet (String) - optional, character-set to accompany the keyword.
|
||||
* Notes:
|
||||
* 1) If |uri| is set for a bookmark/livemark item and |title| isn't,
|
||||
* the dialog will query the history tables for the title associated
|
||||
* with the given uri. If the dialog is set to adding a folder with
|
||||
* bookmark items under it (see URIList), a default static title is
|
||||
* used ("[Folder Name]").
|
||||
* 2) The index field of the default insertion point is ignored if
|
||||
* the folder picker is shown.
|
||||
* - "edit" - for editing a bookmark item or a folder.
|
||||
* @ type (String). Possible values:
|
||||
* - "bookmark"
|
||||
* @ node (an nsINavHistoryResultNode object) - a node representing
|
||||
* the bookmark.
|
||||
* - "folder" (also applies to livemarks)
|
||||
* @ node (an nsINavHistoryResultNode object) - a node representing
|
||||
* the folder.
|
||||
* @ hiddenRows (Strings array) - optional, list of rows to be hidden
|
||||
* regardless of the item edited or added by the dialog.
|
||||
* Possible values:
|
||||
* - "title"
|
||||
* - "location"
|
||||
* - "description"
|
||||
* - "keyword"
|
||||
* - "tags"
|
||||
* - "loadInSidebar"
|
||||
* - "folderPicker" - hides both the tree and the menu.
|
||||
*
|
||||
* window.arguments[0].performed is set to true if any transaction has
|
||||
* been performed by the dialog.
|
||||
*/
|
||||
|
||||
Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PromiseUtils",
|
||||
"resource://gre/modules/PromiseUtils.jsm");
|
||||
|
||||
const BOOKMARK_ITEM = 0;
|
||||
const BOOKMARK_FOLDER = 1;
|
||||
const LIVEMARK_CONTAINER = 2;
|
||||
|
||||
const ACTION_EDIT = 0;
|
||||
const ACTION_ADD = 1;
|
||||
|
||||
var elementsHeight = new Map();
|
||||
|
||||
var BookmarkPropertiesPanel = {
|
||||
|
||||
/** UI Text Strings */
|
||||
__strings: null,
|
||||
get _strings() {
|
||||
if (!this.__strings) {
|
||||
this.__strings = document.getElementById("stringBundle");
|
||||
}
|
||||
return this.__strings;
|
||||
},
|
||||
|
||||
_action: null,
|
||||
_itemType: null,
|
||||
_itemId: -1,
|
||||
_uri: null,
|
||||
_loadInSidebar: false,
|
||||
_title: "",
|
||||
_description: "",
|
||||
_URIs: [],
|
||||
_keyword: "",
|
||||
_postData: null,
|
||||
_charSet: "",
|
||||
_feedURI: null,
|
||||
_siteURI: null,
|
||||
|
||||
_defaultInsertionPoint: null,
|
||||
_hiddenRows: [],
|
||||
_batching: false,
|
||||
|
||||
/**
|
||||
* This method returns the correct label for the dialog's "accept"
|
||||
* button based on the variant of the dialog.
|
||||
*/
|
||||
_getAcceptLabel: function BPP__getAcceptLabel() {
|
||||
if (this._action == ACTION_ADD) {
|
||||
if (this._URIs.length)
|
||||
return this._strings.getString("dialogAcceptLabelAddMulti");
|
||||
|
||||
if (this._itemType == LIVEMARK_CONTAINER)
|
||||
return this._strings.getString("dialogAcceptLabelAddLivemark");
|
||||
|
||||
if (this._dummyItem || this._loadInSidebar)
|
||||
return this._strings.getString("dialogAcceptLabelAddItem");
|
||||
|
||||
return this._strings.getString("dialogAcceptLabelSaveItem");
|
||||
}
|
||||
return this._strings.getString("dialogAcceptLabelEdit");
|
||||
},
|
||||
|
||||
/**
|
||||
* This method returns the correct title for the current variant
|
||||
* of this dialog.
|
||||
*/
|
||||
_getDialogTitle: function BPP__getDialogTitle() {
|
||||
if (this._action == ACTION_ADD) {
|
||||
if (this._itemType == BOOKMARK_ITEM)
|
||||
return this._strings.getString("dialogTitleAddBookmark");
|
||||
if (this._itemType == LIVEMARK_CONTAINER)
|
||||
return this._strings.getString("dialogTitleAddLivemark");
|
||||
|
||||
// add folder
|
||||
NS_ASSERT(this._itemType == BOOKMARK_FOLDER, "Unknown item type");
|
||||
if (this._URIs.length)
|
||||
return this._strings.getString("dialogTitleAddMulti");
|
||||
|
||||
return this._strings.getString("dialogTitleAddFolder");
|
||||
}
|
||||
if (this._action == ACTION_EDIT) {
|
||||
return this._strings.getFormattedString("dialogTitleEdit", [this._title]);
|
||||
}
|
||||
return "";
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines the initial data for the item edited or added by this dialog
|
||||
*/
|
||||
_determineItemInfo() {
|
||||
let dialogInfo = window.arguments[0];
|
||||
this._action = dialogInfo.action == "add" ? ACTION_ADD : ACTION_EDIT;
|
||||
this._hiddenRows = dialogInfo.hiddenRows ? dialogInfo.hiddenRows : [];
|
||||
if (this._action == ACTION_ADD) {
|
||||
NS_ASSERT("type" in dialogInfo, "missing type property for add action");
|
||||
|
||||
if ("title" in dialogInfo)
|
||||
this._title = dialogInfo.title;
|
||||
|
||||
if ("defaultInsertionPoint" in dialogInfo) {
|
||||
this._defaultInsertionPoint = dialogInfo.defaultInsertionPoint;
|
||||
}
|
||||
else {
|
||||
this._defaultInsertionPoint =
|
||||
new InsertionPoint(PlacesUtils.bookmarksMenuFolderId,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
Ci.nsITreeView.DROP_ON);
|
||||
}
|
||||
|
||||
switch (dialogInfo.type) {
|
||||
case "bookmark":
|
||||
this._itemType = BOOKMARK_ITEM;
|
||||
if ("uri" in dialogInfo) {
|
||||
NS_ASSERT(dialogInfo.uri instanceof Ci.nsIURI,
|
||||
"uri property should be a uri object");
|
||||
this._uri = dialogInfo.uri;
|
||||
if (typeof(this._title) != "string") {
|
||||
this._title = this._getURITitleFromHistory(this._uri) ||
|
||||
this._uri.spec;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._uri = PlacesUtils._uri("about:blank");
|
||||
this._title = this._strings.getString("newBookmarkDefault");
|
||||
this._dummyItem = true;
|
||||
}
|
||||
|
||||
if ("loadBookmarkInSidebar" in dialogInfo)
|
||||
this._loadInSidebar = dialogInfo.loadBookmarkInSidebar;
|
||||
|
||||
if ("keyword" in dialogInfo) {
|
||||
this._keyword = dialogInfo.keyword;
|
||||
this._isAddKeywordDialog = true;
|
||||
if ("postData" in dialogInfo)
|
||||
this._postData = dialogInfo.postData;
|
||||
if ("charSet" in dialogInfo)
|
||||
this._charSet = dialogInfo.charSet;
|
||||
}
|
||||
break;
|
||||
|
||||
case "folder":
|
||||
this._itemType = BOOKMARK_FOLDER;
|
||||
if (!this._title) {
|
||||
if ("URIList" in dialogInfo) {
|
||||
this._title = this._strings.getString("bookmarkAllTabsDefault");
|
||||
this._URIs = dialogInfo.URIList;
|
||||
}
|
||||
else
|
||||
this._title = this._strings.getString("newFolderDefault");
|
||||
this._dummyItem = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case "livemark":
|
||||
this._itemType = LIVEMARK_CONTAINER;
|
||||
if ("feedURI" in dialogInfo)
|
||||
this._feedURI = dialogInfo.feedURI;
|
||||
if ("siteURI" in dialogInfo)
|
||||
this._siteURI = dialogInfo.siteURI;
|
||||
|
||||
if (!this._title) {
|
||||
if (this._feedURI) {
|
||||
this._title = this._getURITitleFromHistory(this._feedURI) ||
|
||||
this._feedURI.spec;
|
||||
}
|
||||
else
|
||||
this._title = this._strings.getString("newLivemarkDefault");
|
||||
}
|
||||
}
|
||||
|
||||
if ("description" in dialogInfo)
|
||||
this._description = dialogInfo.description;
|
||||
}
|
||||
else { // edit
|
||||
this._node = dialogInfo.node;
|
||||
this._title = this._node.title;
|
||||
if (PlacesUtils.nodeIsFolder(this._node))
|
||||
this._itemType = BOOKMARK_FOLDER;
|
||||
else if (PlacesUtils.nodeIsURI(this._node))
|
||||
this._itemType = BOOKMARK_ITEM;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This method returns the title string corresponding to a given URI.
|
||||
* If none is available from the bookmark service (probably because
|
||||
* the given URI doesn't appear in bookmarks or history), we synthesize
|
||||
* a title from the first 100 characters of the URI.
|
||||
*
|
||||
* @param aURI
|
||||
* nsIURI object for which we want the title
|
||||
*
|
||||
* @returns a title string
|
||||
*/
|
||||
_getURITitleFromHistory: function BPP__getURITitleFromHistory(aURI) {
|
||||
NS_ASSERT(aURI instanceof Ci.nsIURI);
|
||||
|
||||
// get the title from History
|
||||
return PlacesUtils.history.getPageTitle(aURI);
|
||||
},
|
||||
|
||||
/**
|
||||
* This method should be called by the onload of the Bookmark Properties
|
||||
* dialog to initialize the state of the panel.
|
||||
*/
|
||||
onDialogLoad: Task.async(function* () {
|
||||
this._determineItemInfo();
|
||||
|
||||
document.title = this._getDialogTitle();
|
||||
var acceptButton = document.documentElement.getButton("accept");
|
||||
acceptButton.label = this._getAcceptLabel();
|
||||
|
||||
// Do not use sizeToContent, otherwise, due to bug 90276, the dialog will
|
||||
// grow at every opening.
|
||||
// Since elements can be uncollapsed asynchronously, we must observe their
|
||||
// mutations and resize the dialog using a cached element size.
|
||||
this._height = window.outerHeight;
|
||||
this._mutationObserver = new MutationObserver(mutations => {
|
||||
for (let mutation of mutations) {
|
||||
let target = mutation.target;
|
||||
let id = target.id;
|
||||
if (!/^editBMPanel_.*(Row|Checkbox)$/.test(id))
|
||||
continue;
|
||||
|
||||
let collapsed = target.getAttribute("collapsed") === "true";
|
||||
let wasCollapsed = mutation.oldValue === "true";
|
||||
if (collapsed == wasCollapsed)
|
||||
continue;
|
||||
|
||||
if (collapsed) {
|
||||
this._height -= elementsHeight.get(id);
|
||||
elementsHeight.delete(id);
|
||||
} else {
|
||||
elementsHeight.set(id, target.boxObject.height);
|
||||
this._height += elementsHeight.get(id);
|
||||
}
|
||||
window.resizeTo(window.outerWidth, this._height);
|
||||
}
|
||||
});
|
||||
|
||||
this._mutationObserver.observe(document,
|
||||
{ subtree: true,
|
||||
attributeOldValue: true,
|
||||
attributeFilter: ["collapsed"] });
|
||||
|
||||
// Some controls are flexible and we want to update their cached size when
|
||||
// the dialog is resized.
|
||||
window.addEventListener("resize", this);
|
||||
|
||||
this._beginBatch();
|
||||
|
||||
switch (this._action) {
|
||||
case ACTION_EDIT:
|
||||
gEditItemOverlay.initPanel({ node: this._node
|
||||
, hiddenRows: this._hiddenRows
|
||||
, focusedElement: "first" });
|
||||
acceptButton.disabled = gEditItemOverlay.readOnly;
|
||||
break;
|
||||
case ACTION_ADD:
|
||||
this._node = yield this._promiseNewItem();
|
||||
// Edit the new item
|
||||
gEditItemOverlay.initPanel({ node: this._node
|
||||
, hiddenRows: this._hiddenRows
|
||||
, postData: this._postData
|
||||
, focusedElement: "first" });
|
||||
|
||||
// Empty location field if the uri is about:blank, this way inserting a new
|
||||
// url will be easier for the user, Accept button will be automatically
|
||||
// disabled by the input listener until the user fills the field.
|
||||
let locationField = this._element("locationField");
|
||||
if (locationField.value == "about:blank")
|
||||
locationField.value = "";
|
||||
|
||||
// if this is an uri related dialog disable accept button until
|
||||
// the user fills an uri value.
|
||||
if (this._itemType == BOOKMARK_ITEM)
|
||||
acceptButton.disabled = !this._inputIsValid();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!gEditItemOverlay.readOnly) {
|
||||
// Listen on uri fields to enable accept button if input is valid
|
||||
if (this._itemType == BOOKMARK_ITEM) {
|
||||
this._element("locationField")
|
||||
.addEventListener("input", this, false);
|
||||
if (this._isAddKeywordDialog) {
|
||||
this._element("keywordField")
|
||||
.addEventListener("input", this, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
// nsIDOMEventListener
|
||||
handleEvent: function BPP_handleEvent(aEvent) {
|
||||
var target = aEvent.target;
|
||||
switch (aEvent.type) {
|
||||
case "input":
|
||||
if (target.id == "editBMPanel_locationField" ||
|
||||
target.id == "editBMPanel_keywordField") {
|
||||
// Check uri fields to enable accept button if input is valid
|
||||
document.documentElement
|
||||
.getButton("accept").disabled = !this._inputIsValid();
|
||||
}
|
||||
break;
|
||||
case "resize":
|
||||
for (let [id, oldHeight] of elementsHeight) {
|
||||
let newHeight = document.getElementById(id).boxObject.height;
|
||||
this._height += - oldHeight + newHeight;
|
||||
elementsHeight.set(id, newHeight);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
// Hack for implementing batched-Undo around the editBookmarkOverlay
|
||||
// instant-apply code. For all the details see the comment above beginBatch
|
||||
// in browser-places.js
|
||||
_batchBlockingDeferred: null,
|
||||
_beginBatch() {
|
||||
if (this._batching)
|
||||
return;
|
||||
if (PlacesUIUtils.useAsyncTransactions) {
|
||||
this._batchBlockingDeferred = PromiseUtils.defer();
|
||||
PlacesTransactions.batch(function* () {
|
||||
yield this._batchBlockingDeferred.promise;
|
||||
}.bind(this));
|
||||
}
|
||||
else {
|
||||
PlacesUtils.transactionManager.beginBatch(null);
|
||||
}
|
||||
this._batching = true;
|
||||
},
|
||||
|
||||
_endBatch() {
|
||||
if (!this._batching)
|
||||
return;
|
||||
|
||||
if (PlacesUIUtils.useAsyncTransactions) {
|
||||
this._batchBlockingDeferred.resolve();
|
||||
this._batchBlockingDeferred = null;
|
||||
}
|
||||
else {
|
||||
PlacesUtils.transactionManager.endBatch(false);
|
||||
}
|
||||
this._batching = false;
|
||||
},
|
||||
|
||||
// nsISupports
|
||||
QueryInterface: function BPP_QueryInterface(aIID) {
|
||||
if (aIID.equals(Ci.nsIDOMEventListener) ||
|
||||
aIID.equals(Ci.nsISupports))
|
||||
return this;
|
||||
|
||||
throw Cr.NS_NOINTERFACE;
|
||||
},
|
||||
|
||||
_element: function BPP__element(aID) {
|
||||
return document.getElementById("editBMPanel_" + aID);
|
||||
},
|
||||
|
||||
onDialogUnload() {
|
||||
// gEditItemOverlay does not exist anymore here, so don't rely on it.
|
||||
this._mutationObserver.disconnect();
|
||||
delete this._mutationObserver;
|
||||
|
||||
window.removeEventListener("resize", this);
|
||||
|
||||
// Calling removeEventListener with arguments which do not identify any
|
||||
// currently registered EventListener on the EventTarget has no effect.
|
||||
this._element("locationField")
|
||||
.removeEventListener("input", this, false);
|
||||
},
|
||||
|
||||
onDialogAccept() {
|
||||
// We must blur current focused element to save its changes correctly
|
||||
document.commandDispatcher.focusedElement.blur();
|
||||
// The order here is important! We have to uninit the panel first, otherwise
|
||||
// late changes could force it to commit more transactions.
|
||||
gEditItemOverlay.uninitPanel(true);
|
||||
this._endBatch();
|
||||
window.arguments[0].performed = true;
|
||||
},
|
||||
|
||||
onDialogCancel() {
|
||||
// The order here is important! We have to uninit the panel first, otherwise
|
||||
// changes done as part of Undo may change the panel contents and by
|
||||
// that force it to commit more transactions.
|
||||
gEditItemOverlay.uninitPanel(true);
|
||||
this._endBatch();
|
||||
if (PlacesUIUtils.useAsyncTransactions)
|
||||
PlacesTransactions.undo().catch(Components.utils.reportError);
|
||||
else
|
||||
PlacesUtils.transactionManager.undoTransaction();
|
||||
window.arguments[0].performed = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* This method checks to see if the input fields are in a valid state.
|
||||
*
|
||||
* @returns true if the input is valid, false otherwise
|
||||
*/
|
||||
_inputIsValid: function BPP__inputIsValid() {
|
||||
if (this._itemType == BOOKMARK_ITEM &&
|
||||
!this._containsValidURI("locationField"))
|
||||
return false;
|
||||
if (this._isAddKeywordDialog && !this._element("keywordField").value.length)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether the XUL textbox with the given ID contains a
|
||||
* string that can be converted into an nsIURI.
|
||||
*
|
||||
* @param aTextboxID
|
||||
* the ID of the textbox element whose contents we'll test
|
||||
*
|
||||
* @returns true if the textbox contains a valid URI string, false otherwise
|
||||
*/
|
||||
_containsValidURI: function BPP__containsValidURI(aTextboxID) {
|
||||
try {
|
||||
var value = this._element(aTextboxID).value;
|
||||
if (value) {
|
||||
PlacesUIUtils.createFixedURI(value);
|
||||
return true;
|
||||
}
|
||||
} catch (e) { }
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* [New Item Mode] Get the insertion point details for the new item, given
|
||||
* dialog state and opening arguments.
|
||||
*
|
||||
* The container-identifier and insertion-index are returned separately in
|
||||
* the form of [containerIdentifier, insertionIndex]
|
||||
*/
|
||||
_getInsertionPointDetails: function BPP__getInsertionPointDetails() {
|
||||
var containerId = this._defaultInsertionPoint.itemId;
|
||||
var indexInContainer = this._defaultInsertionPoint.index;
|
||||
|
||||
return [containerId, indexInContainer];
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a transaction for creating a new bookmark item representing the
|
||||
* various fields and opening arguments of the dialog.
|
||||
*/
|
||||
_getCreateNewBookmarkTransaction:
|
||||
function BPP__getCreateNewBookmarkTransaction(aContainer, aIndex) {
|
||||
var annotations = [];
|
||||
var childTransactions = [];
|
||||
|
||||
if (this._description) {
|
||||
let annoObj = { name : PlacesUIUtils.DESCRIPTION_ANNO,
|
||||
type : Ci.nsIAnnotationService.TYPE_STRING,
|
||||
flags : 0,
|
||||
value : this._description,
|
||||
expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
|
||||
let editItemTxn = new PlacesSetItemAnnotationTransaction(-1, annoObj);
|
||||
childTransactions.push(editItemTxn);
|
||||
}
|
||||
|
||||
if (this._loadInSidebar) {
|
||||
let annoObj = { name : PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO,
|
||||
value : true };
|
||||
let setLoadTxn = new PlacesSetItemAnnotationTransaction(-1, annoObj);
|
||||
childTransactions.push(setLoadTxn);
|
||||
}
|
||||
|
||||
// XXX TODO: this should be in a transaction!
|
||||
if (this._charSet && !PrivateBrowsingUtils.isWindowPrivate(window))
|
||||
PlacesUtils.setCharsetForURI(this._uri, this._charSet);
|
||||
|
||||
let createTxn = new PlacesCreateBookmarkTransaction(this._uri,
|
||||
aContainer,
|
||||
aIndex,
|
||||
this._title,
|
||||
this._keyword,
|
||||
annotations,
|
||||
childTransactions,
|
||||
this._postData);
|
||||
|
||||
return new PlacesAggregatedTransaction(this._getDialogTitle(),
|
||||
[createTxn]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a childItems-transactions array representing the URIList with
|
||||
* which the dialog has been opened.
|
||||
*/
|
||||
_getTransactionsForURIList: function BPP__getTransactionsForURIList() {
|
||||
var transactions = [];
|
||||
for (let uri of this._URIs) {
|
||||
// uri should be an object in the form { url, title }. Though add-ons
|
||||
// could still use the legacy form, where it's an nsIURI.
|
||||
let [_uri, _title] = uri instanceof Ci.nsIURI ?
|
||||
[uri, this._getURITitleFromHistory(uri)] : [uri.uri, uri.title];
|
||||
|
||||
let createTxn =
|
||||
new PlacesCreateBookmarkTransaction(_uri, -1,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
_title);
|
||||
transactions.push(createTxn);
|
||||
}
|
||||
return transactions;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a transaction for creating a new folder item representing the
|
||||
* various fields and opening arguments of the dialog.
|
||||
*/
|
||||
_getCreateNewFolderTransaction:
|
||||
function BPP__getCreateNewFolderTransaction(aContainer, aIndex) {
|
||||
var annotations = [];
|
||||
var childItemsTransactions;
|
||||
if (this._URIs.length)
|
||||
childItemsTransactions = this._getTransactionsForURIList();
|
||||
|
||||
if (this._description)
|
||||
annotations.push(this._getDescriptionAnnotation(this._description));
|
||||
|
||||
return new PlacesCreateFolderTransaction(this._title, aContainer,
|
||||
aIndex, annotations,
|
||||
childItemsTransactions);
|
||||
},
|
||||
|
||||
_createNewItem: Task.async(function* () {
|
||||
let [container, index] = this._getInsertionPointDetails();
|
||||
let txn;
|
||||
switch (this._itemType) {
|
||||
case BOOKMARK_FOLDER:
|
||||
txn = this._getCreateNewFolderTransaction(container, index);
|
||||
break;
|
||||
case LIVEMARK_CONTAINER:
|
||||
txn = new PlacesCreateLivemarkTransaction(this._feedURI, this._siteURI,
|
||||
this._title, container, index);
|
||||
break;
|
||||
default: // BOOKMARK_ITEM
|
||||
txn = this._getCreateNewBookmarkTransaction(container, index);
|
||||
}
|
||||
|
||||
PlacesUtils.transactionManager.doTransaction(txn);
|
||||
// This is a temporary hack until we use PlacesTransactions.jsm
|
||||
if (txn._promise) {
|
||||
yield txn._promise;
|
||||
}
|
||||
|
||||
let folderGuid = yield PlacesUtils.promiseItemGuid(container);
|
||||
let bm = yield PlacesUtils.bookmarks.fetch({
|
||||
parentGuid: folderGuid,
|
||||
index: index
|
||||
});
|
||||
this._itemId = yield PlacesUtils.promiseItemId(bm.guid);
|
||||
|
||||
return Object.freeze({
|
||||
itemId: this._itemId,
|
||||
bookmarkGuid: bm.guid,
|
||||
title: this._title,
|
||||
uri: this._uri ? this._uri.spec : "",
|
||||
type: this._itemType == BOOKMARK_ITEM ?
|
||||
Ci.nsINavHistoryResultNode.RESULT_TYPE_URI :
|
||||
Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER
|
||||
});
|
||||
}),
|
||||
|
||||
_promiseNewItem: Task.async(function* () {
|
||||
if (!PlacesUIUtils.useAsyncTransactions)
|
||||
return this._createNewItem();
|
||||
|
||||
let [containerId, index] = this._getInsertionPointDetails();
|
||||
let parentGuid = yield PlacesUtils.promiseItemGuid(containerId);
|
||||
let annotations = [];
|
||||
if (this._description) {
|
||||
annotations.push({ name: PlacesUIUtils.DESCRIPTION_ANNO
|
||||
, value: this._description });
|
||||
}
|
||||
if (this._loadInSidebar) {
|
||||
annotations.push({ name: PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO
|
||||
, value: true });
|
||||
}
|
||||
|
||||
let itemGuid;
|
||||
let info = { parentGuid, index, title: this._title, annotations };
|
||||
if (this._itemType == BOOKMARK_ITEM) {
|
||||
info.url = this._uri;
|
||||
if (this._keyword)
|
||||
info.keyword = this._keyword;
|
||||
if (this._postData)
|
||||
info.postData = this._postData;
|
||||
|
||||
if (this._charSet && !PrivateBrowsingUtils.isWindowPrivate(window))
|
||||
PlacesUtils.setCharsetForURI(this._uri, this._charSet);
|
||||
|
||||
itemGuid = yield PlacesTransactions.NewBookmark(info).transact();
|
||||
}
|
||||
else if (this._itemType == LIVEMARK_CONTAINER) {
|
||||
info.feedUrl = this._feedURI;
|
||||
if (this._siteURI)
|
||||
info.siteUrl = this._siteURI;
|
||||
|
||||
itemGuid = yield PlacesTransactions.NewLivemark(info).transact();
|
||||
}
|
||||
else if (this._itemType == BOOKMARK_FOLDER) {
|
||||
itemGuid = yield PlacesTransactions.NewFolder(info).transact();
|
||||
for (let uri of this._URIs) {
|
||||
let placeInfo = yield PlacesUtils.promisePlaceInfo(uri);
|
||||
let title = placeInfo ? placeInfo.title : "";
|
||||
yield PlacesTransactions.transact({ parentGuid: itemGuid, uri, title });
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Error(`unexpected value for _itemType: ${this._itemType}`);
|
||||
}
|
||||
|
||||
this._itemGuid = itemGuid;
|
||||
this._itemId = yield PlacesUtils.promiseItemId(itemGuid);
|
||||
return Object.freeze({
|
||||
itemId: this._itemId,
|
||||
bookmarkGuid: this._itemGuid,
|
||||
title: this._title,
|
||||
uri: this._uri ? this._uri.spec : "",
|
||||
type: this._itemType == BOOKMARK_ITEM ?
|
||||
Ci.nsINavHistoryResultNode.RESULT_TYPE_URI :
|
||||
Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER
|
||||
});
|
||||
})
|
||||
};
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/editBookmarkOverlay.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
|
||||
<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
|
||||
<?xul-overlay href="chrome://browser/content/places/editBookmarkOverlay.xul"?>
|
||||
|
||||
<!DOCTYPE dialog [
|
||||
<!ENTITY % editBookmarkOverlayDTD SYSTEM "chrome://browser/locale/places/editBookmarkOverlay.dtd">
|
||||
%editBookmarkOverlayDTD;
|
||||
]>
|
||||
|
||||
<dialog id="bookmarkproperties"
|
||||
buttons="accept, cancel"
|
||||
buttoniconaccept="save"
|
||||
ondialogaccept="BookmarkPropertiesPanel.onDialogAccept();"
|
||||
ondialogcancel="BookmarkPropertiesPanel.onDialogCancel();"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="BookmarkPropertiesPanel.onDialogLoad();"
|
||||
onunload="BookmarkPropertiesPanel.onDialogUnload();"
|
||||
style="min-width: 30em;"
|
||||
persist="screenX screenY width">
|
||||
|
||||
<stringbundleset id="stringbundleset">
|
||||
<stringbundle id="stringBundle"
|
||||
src="chrome://browser/locale/places/bookmarkProperties.properties"/>
|
||||
</stringbundleset>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/places/editBookmarkOverlay.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/places/bookmarkProperties.js"/>
|
||||
|
||||
<vbox id="editBookmarkPanelContent"/>
|
||||
|
||||
</dialog>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function init() {
|
||||
document.getElementById("bookmarks-view").place =
|
||||
"place:queryType=1&folder=" + window.top.PlacesUIUtils.allBookmarksFolderId;
|
||||
}
|
||||
|
||||
function searchBookmarks(aSearchString) {
|
||||
var tree = document.getElementById('bookmarks-view');
|
||||
if (!aSearchString)
|
||||
tree.place = tree.place;
|
||||
else
|
||||
tree.applyFilter(aSearchString,
|
||||
[PlacesUtils.bookmarksMenuFolderId,
|
||||
PlacesUtils.unfiledBookmarksFolderId,
|
||||
PlacesUtils.toolbarFolderId]);
|
||||
}
|
||||
|
||||
window.addEventListener("SidebarFocused",
|
||||
() => document.getElementById("search-box").focus(),
|
||||
false);
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0"?> <!-- -*- Mode: SGML; indent-tabs-mode: nil; -*- -->
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
|
||||
<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
|
||||
|
||||
<!DOCTYPE page SYSTEM "chrome://browser/locale/places/places.dtd">
|
||||
|
||||
<page id="bookmarksPanel"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="init();"
|
||||
onunload="SidebarUtils.setMouseoverURL('');">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/bookmarks/sidebarUtils.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/bookmarks/bookmarksPanel.js"/>
|
||||
|
||||
<commandset id="placesCommands"/>
|
||||
<commandset id="editMenuCommands"/>
|
||||
<menupopup id="placesContext"/>
|
||||
|
||||
<!-- Bookmarks and history tooltip -->
|
||||
<tooltip id="bhTooltip"/>
|
||||
|
||||
<hbox id="sidebar-search-container" align="center">
|
||||
<label id="sidebar-search-label"
|
||||
value="&search.label;" accesskey="&search.accesskey;" control="search-box"/>
|
||||
<textbox id="search-box" flex="1" type="search" class="compact"
|
||||
aria-controls="bookmarks-view"
|
||||
oncommand="searchBookmarks(this.value);"/>
|
||||
</hbox>
|
||||
|
||||
<tree id="bookmarks-view" class="sidebar-placesTree" type="places"
|
||||
flex="1"
|
||||
hidecolumnpicker="true"
|
||||
context="placesContext"
|
||||
onkeypress="SidebarUtils.handleTreeKeyPress(event);"
|
||||
onclick="SidebarUtils.handleTreeClick(this, event, true);"
|
||||
onmousemove="SidebarUtils.handleTreeMouseMove(event);"
|
||||
onmouseout="SidebarUtils.setMouseoverURL('');">
|
||||
<treecols>
|
||||
<treecol id="title" flex="1" primary="true" hideheader="true"/>
|
||||
</treecols>
|
||||
<treechildren id="bookmarks-view-children" view="bookmarks-view"
|
||||
class="sidebar-placesTreechildren" flex="1" tooltip="bhTooltip"/>
|
||||
</tree>
|
||||
</page>
|
||||
1996
application/basilisk/components/places/content/browserPlacesViews.js
Normal file
1996
application/basilisk/components/places/content/browserPlacesViews.js
Normal file
File diff suppressed because it is too large
Load diff
1743
application/basilisk/components/places/content/controller.js
Normal file
1743
application/basilisk/components/places/content/controller.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,47 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<?xul-overlay href="chrome://browser/content/downloads/allDownloadsViewOverlay.xul"?>
|
||||
|
||||
<!DOCTYPE overlay [
|
||||
<!ENTITY % downloadsDTD SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
|
||||
%downloadsDTD;
|
||||
]>
|
||||
|
||||
<overlay id="downloadsViewOverlay"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript"><![CDATA[
|
||||
const DOWNLOADS_QUERY = "place:transition=" +
|
||||
Components.interfaces.nsINavHistoryService.TRANSITION_DOWNLOAD +
|
||||
"&sort=" +
|
||||
Components.interfaces.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING;
|
||||
|
||||
ContentArea.setContentViewForQueryString(DOWNLOADS_QUERY,
|
||||
() => new DownloadsPlacesView(document.getElementById("downloadsRichListBox"), false),
|
||||
{ showDetailsPane: false,
|
||||
toolbarSet: "back-button, forward-button, organizeButton, clearDownloadsButton, libraryToolbarSpacer, searchFilter" });
|
||||
]]></script>
|
||||
|
||||
<window id="places">
|
||||
<commandset id="downloadCommands"/>
|
||||
<menupopup id="downloadsContextMenu"/>
|
||||
</window>
|
||||
|
||||
<deck id="placesViewsDeck">
|
||||
<richlistbox id="downloadsRichListBox"/>
|
||||
</deck>
|
||||
|
||||
<toolbar id="placesToolbar">
|
||||
<toolbarbutton id="clearDownloadsButton"
|
||||
#ifdef XP_MACOSX
|
||||
class="tabbable"
|
||||
#endif
|
||||
insertbefore="libraryToolbarSpacer"
|
||||
label="&clearDownloadsButton.label;"
|
||||
command="downloadsCmd_clearDownloads"
|
||||
tooltiptext="&clearDownloadsButton.tooltip;"/>
|
||||
</toolbar>
|
||||
|
||||
</overlay>
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,188 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!DOCTYPE overlay [
|
||||
<!ENTITY % editBookmarkOverlayDTD SYSTEM "chrome://browser/locale/places/editBookmarkOverlay.dtd">
|
||||
%editBookmarkOverlayDTD;
|
||||
]>
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/editBookmarkOverlay.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
|
||||
<overlay id="editBookmarkOverlay"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<vbox id="editBookmarkPanelContent" flex="1">
|
||||
<hbox id="editBMPanel_selectionCount" pack="center">
|
||||
<label id="editBMPanel_itemsCountText"/>
|
||||
</hbox>
|
||||
|
||||
<grid id="editBookmarkPanelGrid" flex="1">
|
||||
<columns id="editBMPanel_columns">
|
||||
<column id="editBMPanel_labelColumn" />
|
||||
<column flex="1" id="editBMPanel_editColumn" />
|
||||
</columns>
|
||||
<rows id="editBMPanel_rows">
|
||||
<row id="editBMPanel_nameRow"
|
||||
align="center"
|
||||
collapsed="true">
|
||||
<label value="&editBookmarkOverlay.name.label;"
|
||||
class="editBMPanel_rowLabel"
|
||||
accesskey="&editBookmarkOverlay.name.accesskey;"
|
||||
control="editBMPanel_namePicker"/>
|
||||
<textbox id="editBMPanel_namePicker"
|
||||
onchange="gEditItemOverlay.onNamePickerChange();"/>
|
||||
</row>
|
||||
|
||||
<row id="editBMPanel_locationRow"
|
||||
align="center"
|
||||
collapsed="true">
|
||||
<label value="&editBookmarkOverlay.location.label;"
|
||||
class="editBMPanel_rowLabel"
|
||||
accesskey="&editBookmarkOverlay.location.accesskey;"
|
||||
control="editBMPanel_locationField"/>
|
||||
<textbox id="editBMPanel_locationField"
|
||||
class="uri-element"
|
||||
onchange="gEditItemOverlay.onLocationFieldChange();"/>
|
||||
</row>
|
||||
|
||||
<row id="editBMPanel_folderRow"
|
||||
align="center"
|
||||
collapsed="true">
|
||||
<label value="&editBookmarkOverlay.folder.label;"
|
||||
class="editBMPanel_rowLabel"
|
||||
control="editBMPanel_folderMenuList"/>
|
||||
<hbox flex="1" align="center">
|
||||
<menulist id="editBMPanel_folderMenuList"
|
||||
class="folder-icon"
|
||||
flex="1"
|
||||
oncommand="gEditItemOverlay.onFolderMenuListCommand(event);">
|
||||
<menupopup>
|
||||
<!-- Static item for special folders -->
|
||||
<menuitem id="editBMPanel_toolbarFolderItem"
|
||||
class="menuitem-iconic folder-icon"/>
|
||||
<menuitem id="editBMPanel_bmRootItem"
|
||||
class="menuitem-iconic folder-icon"/>
|
||||
<menuitem id="editBMPanel_unfiledRootItem"
|
||||
class="menuitem-iconic folder-icon"/>
|
||||
<menuseparator id="editBMPanel_chooseFolderSeparator"/>
|
||||
<menuitem id="editBMPanel_chooseFolderMenuItem"
|
||||
label="&editBookmarkOverlay.choose.label;"
|
||||
class="menuitem-iconic folder-icon"/>
|
||||
<menuseparator id="editBMPanel_foldersSeparator" hidden="true"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
<button id="editBMPanel_foldersExpander"
|
||||
class="expander-down"
|
||||
tooltiptext="&editBookmarkOverlay.foldersExpanderDown.tooltip;"
|
||||
tooltiptextdown="&editBookmarkOverlay.foldersExpanderDown.tooltip;"
|
||||
tooltiptextup="&editBookmarkOverlay.expanderUp.tooltip;"
|
||||
oncommand="gEditItemOverlay.toggleFolderTreeVisibility();"/>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<row id="editBMPanel_folderTreeRow"
|
||||
collapsed="true"
|
||||
flex="1">
|
||||
<spacer/>
|
||||
<vbox flex="1">
|
||||
<tree id="editBMPanel_folderTree"
|
||||
flex="1"
|
||||
class="placesTree"
|
||||
type="places"
|
||||
height="150"
|
||||
minheight="150"
|
||||
editable="true"
|
||||
onselect="gEditItemOverlay.onFolderTreeSelect();"
|
||||
hidecolumnpicker="true">
|
||||
<treecols>
|
||||
<treecol anonid="title" flex="1" primary="true" hideheader="true"/>
|
||||
</treecols>
|
||||
<treechildren flex="1"/>
|
||||
</tree>
|
||||
|
||||
<hbox id="editBMPanel_newFolderBox">
|
||||
<button label="&editBookmarkOverlay.newFolderButton.label;"
|
||||
id="editBMPanel_newFolderButton"
|
||||
accesskey="&editBookmarkOverlay.newFolderButton.accesskey;"
|
||||
oncommand="gEditItemOverlay.newFolder().catch(Components.utils.reportError);"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</row>
|
||||
|
||||
<row id="editBMPanel_tagsRow"
|
||||
align="center"
|
||||
collapsed="true">
|
||||
<label value="&editBookmarkOverlay.tags.label;"
|
||||
class="editBMPanel_rowLabel"
|
||||
accesskey="&editBookmarkOverlay.tags.accesskey;"
|
||||
control="editBMPanel_tagsField"/>
|
||||
<hbox flex="1" align="center">
|
||||
<textbox id="editBMPanel_tagsField"
|
||||
type="autocomplete"
|
||||
class="padded"
|
||||
flex="1"
|
||||
autocompletesearch="places-tag-autocomplete"
|
||||
completedefaultindex="true"
|
||||
tabscrolling="true"
|
||||
showcommentcolumn="true"
|
||||
placeholder="&editBookmarkOverlay.tagsEmptyDesc.label;"
|
||||
onchange="gEditItemOverlay.onTagsFieldChange();"/>
|
||||
<button id="editBMPanel_tagsSelectorExpander"
|
||||
class="expander-down"
|
||||
tooltiptext="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
|
||||
tooltiptextdown="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
|
||||
tooltiptextup="&editBookmarkOverlay.expanderUp.tooltip;"
|
||||
oncommand="gEditItemOverlay.toggleTagsSelector();"/>
|
||||
</hbox>
|
||||
</row>
|
||||
|
||||
<row id="editBMPanel_tagsSelectorRow"
|
||||
align="center"
|
||||
collapsed="true">
|
||||
<spacer/>
|
||||
<listbox id="editBMPanel_tagsSelector"
|
||||
height="150"/>
|
||||
</row>
|
||||
|
||||
<row id="editBMPanel_keywordRow"
|
||||
align="center"
|
||||
collapsed="true">
|
||||
<observes element="additionalInfoBroadcaster" attribute="hidden"/>
|
||||
<label value="&editBookmarkOverlay.keyword.label;"
|
||||
class="editBMPanel_rowLabel"
|
||||
accesskey="&editBookmarkOverlay.keyword.accesskey;"
|
||||
control="editBMPanel_keywordField"/>
|
||||
<textbox id="editBMPanel_keywordField"
|
||||
onchange="gEditItemOverlay.onKeywordFieldChange();"/>
|
||||
</row>
|
||||
|
||||
<row id="editBMPanel_descriptionRow"
|
||||
collapsed="true">
|
||||
<observes element="additionalInfoBroadcaster" attribute="hidden"/>
|
||||
<label value="&editBookmarkOverlay.description.label;"
|
||||
class="editBMPanel_rowLabel"
|
||||
accesskey="&editBookmarkOverlay.description.accesskey;"
|
||||
control="editBMPanel_descriptionField"/>
|
||||
<textbox id="editBMPanel_descriptionField"
|
||||
multiline="true"
|
||||
rows="4"
|
||||
onchange="gEditItemOverlay.onDescriptionFieldChange();"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
|
||||
<checkbox id="editBMPanel_loadInSidebarCheckbox"
|
||||
collapsed="true"
|
||||
label="&editBookmarkOverlay.loadInSidebar.label;"
|
||||
accesskey="&editBookmarkOverlay.loadInSidebar.accesskey;"
|
||||
oncommand="gEditItemOverlay.onLoadInSidebarCheckboxCommand();">
|
||||
<observes element="additionalInfoBroadcaster" attribute="hidden"/>
|
||||
</checkbox>
|
||||
|
||||
<!-- If the ids are changing or additional fields are being added, be sure
|
||||
to sync the values in places.js -->
|
||||
<broadcaster id="additionalInfoBroadcaster"/>
|
||||
</vbox>
|
||||
</overlay>
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/TelemetryStopwatch.jsm");
|
||||
|
||||
var gHistoryTree;
|
||||
var gSearchBox;
|
||||
var gHistoryGrouping = "";
|
||||
var gSearching = false;
|
||||
|
||||
function HistorySidebarInit()
|
||||
{
|
||||
gHistoryTree = document.getElementById("historyTree");
|
||||
gSearchBox = document.getElementById("search-box");
|
||||
|
||||
gHistoryGrouping = document.getElementById("viewButton").
|
||||
getAttribute("selectedsort");
|
||||
|
||||
if (gHistoryGrouping == "site")
|
||||
document.getElementById("bysite").setAttribute("checked", "true");
|
||||
else if (gHistoryGrouping == "visited")
|
||||
document.getElementById("byvisited").setAttribute("checked", "true");
|
||||
else if (gHistoryGrouping == "lastvisited")
|
||||
document.getElementById("bylastvisited").setAttribute("checked", "true");
|
||||
else if (gHistoryGrouping == "dayandsite")
|
||||
document.getElementById("bydayandsite").setAttribute("checked", "true");
|
||||
else
|
||||
document.getElementById("byday").setAttribute("checked", "true");
|
||||
|
||||
searchHistory("");
|
||||
}
|
||||
|
||||
function GroupBy(groupingType)
|
||||
{
|
||||
gHistoryGrouping = groupingType;
|
||||
searchHistory(gSearchBox.value);
|
||||
}
|
||||
|
||||
function searchHistory(aInput)
|
||||
{
|
||||
var query = PlacesUtils.history.getNewQuery();
|
||||
var options = PlacesUtils.history.getNewQueryOptions();
|
||||
|
||||
const NHQO = Ci.nsINavHistoryQueryOptions;
|
||||
var sortingMode;
|
||||
var resultType;
|
||||
|
||||
switch (gHistoryGrouping) {
|
||||
case "visited":
|
||||
resultType = NHQO.RESULTS_AS_URI;
|
||||
sortingMode = NHQO.SORT_BY_VISITCOUNT_DESCENDING;
|
||||
break;
|
||||
case "lastvisited":
|
||||
resultType = NHQO.RESULTS_AS_URI;
|
||||
sortingMode = NHQO.SORT_BY_DATE_DESCENDING;
|
||||
break;
|
||||
case "dayandsite":
|
||||
resultType = NHQO.RESULTS_AS_DATE_SITE_QUERY;
|
||||
break;
|
||||
case "site":
|
||||
resultType = NHQO.RESULTS_AS_SITE_QUERY;
|
||||
sortingMode = NHQO.SORT_BY_TITLE_ASCENDING;
|
||||
break;
|
||||
case "day":
|
||||
default:
|
||||
resultType = NHQO.RESULTS_AS_DATE_QUERY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (aInput) {
|
||||
query.searchTerms = aInput;
|
||||
if (gHistoryGrouping != "visited" && gHistoryGrouping != "lastvisited") {
|
||||
sortingMode = NHQO.SORT_BY_FRECENCY_DESCENDING;
|
||||
resultType = NHQO.RESULTS_AS_URI;
|
||||
}
|
||||
}
|
||||
|
||||
options.sortingMode = sortingMode;
|
||||
options.resultType = resultType;
|
||||
options.includeHidden = !!aInput;
|
||||
|
||||
if (gHistoryGrouping == "lastvisited")
|
||||
this.TelemetryStopwatch.start("HISTORY_LASTVISITED_TREE_QUERY_TIME_MS");
|
||||
|
||||
// call load() on the tree manually
|
||||
// instead of setting the place attribute in history-panel.xul
|
||||
// otherwise, we will end up calling load() twice
|
||||
gHistoryTree.load([query], options);
|
||||
|
||||
if (gHistoryGrouping == "lastvisited")
|
||||
this.TelemetryStopwatch.finish("HISTORY_LASTVISITED_TREE_QUERY_TIME_MS");
|
||||
}
|
||||
|
||||
window.addEventListener("SidebarFocused",
|
||||
() => gSearchBox.focus(),
|
||||
false);
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0"?> <!-- -*- Mode: xml; indent-tabs-mode: nil; -*- -->
|
||||
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
|
||||
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
|
||||
<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
|
||||
|
||||
<!DOCTYPE page [
|
||||
<!ENTITY % placesDTD SYSTEM "chrome://browser/locale/places/places.dtd">
|
||||
%placesDTD;
|
||||
]>
|
||||
|
||||
<!-- we need to keep id="history-panel" for upgrade and switching
|
||||
between versions of the browser -->
|
||||
|
||||
<page id="history-panel" orient="vertical"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="HistorySidebarInit();"
|
||||
onunload="SidebarUtils.setMouseoverURL('');">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/bookmarks/sidebarUtils.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/places/history-panel.js"/>
|
||||
|
||||
<commandset id="editMenuCommands"/>
|
||||
<commandset id="placesCommands"/>
|
||||
|
||||
<keyset id="editMenuKeys">
|
||||
#ifdef XP_MACOSX
|
||||
<key id="key_delete2" keycode="VK_BACK" command="cmd_delete"/>
|
||||
#endif
|
||||
</keyset>
|
||||
|
||||
<!-- required to overlay the context menu -->
|
||||
<menupopup id="placesContext"/>
|
||||
|
||||
<!-- Bookmarks and history tooltip -->
|
||||
<tooltip id="bhTooltip"/>
|
||||
|
||||
<hbox id="sidebar-search-container" align="center">
|
||||
<label id="sidebar-search-label"
|
||||
value="&find.label;" accesskey="&find.accesskey;"
|
||||
control="search-box"/>
|
||||
<textbox id="search-box" flex="1" type="search" class="compact"
|
||||
aria-controls="historyTree"
|
||||
oncommand="searchHistory(this.value);"/>
|
||||
<button id="viewButton" style="min-width:0px !important;" type="menu"
|
||||
label="&view.label;" accesskey="&view.accesskey;" selectedsort="day"
|
||||
persist="selectedsort">
|
||||
<menupopup>
|
||||
<menuitem id="bydayandsite" label="&byDayAndSite.label;"
|
||||
accesskey="&byDayAndSite.accesskey;" type="radio"
|
||||
oncommand="this.parentNode.parentNode.setAttribute('selectedsort', 'dayandsite'); GroupBy('dayandsite');"/>
|
||||
<menuitem id="bysite" label="&bySite.label;"
|
||||
accesskey="&bySite.accesskey;" type="radio"
|
||||
oncommand="this.parentNode.parentNode.setAttribute('selectedsort', 'site'); GroupBy('site');"/>
|
||||
<menuitem id="byday" label="&byDate.label;"
|
||||
accesskey="&byDate.accesskey;"
|
||||
type="radio"
|
||||
oncommand="this.parentNode.parentNode.setAttribute('selectedsort', 'day'); GroupBy('day');"/>
|
||||
<menuitem id="byvisited" label="&byMostVisited.label;"
|
||||
accesskey="&byMostVisited.accesskey;"
|
||||
type="radio"
|
||||
oncommand="this.parentNode.parentNode.setAttribute('selectedsort', 'visited'); GroupBy('visited');"/>
|
||||
<menuitem id="bylastvisited" label="&byLastVisited.label;"
|
||||
accesskey="&byLastVisited.accesskey;"
|
||||
type="radio"
|
||||
oncommand="this.parentNode.parentNode.setAttribute('selectedsort', 'lastvisited'); GroupBy('lastvisited');"/>
|
||||
</menupopup>
|
||||
</button>
|
||||
</hbox>
|
||||
|
||||
<tree id="historyTree"
|
||||
class="sidebar-placesTree"
|
||||
flex="1"
|
||||
type="places"
|
||||
context="placesContext"
|
||||
hidecolumnpicker="true"
|
||||
onkeypress="SidebarUtils.handleTreeKeyPress(event);"
|
||||
onclick="SidebarUtils.handleTreeClick(this, event, true);"
|
||||
onmousemove="SidebarUtils.handleTreeMouseMove(event);"
|
||||
onmouseout="SidebarUtils.setMouseoverURL('');">
|
||||
<treecols>
|
||||
<treecol id="title" flex="1" primary="true" hideheader="true"/>
|
||||
</treecols>
|
||||
<treechildren class="sidebar-placesTreechildren" flex="1" tooltip="bhTooltip"/>
|
||||
</tree>
|
||||
</page>
|
||||
633
application/basilisk/components/places/content/menu.xml
Normal file
633
application/basilisk/components/places/content/menu.xml
Normal file
|
|
@ -0,0 +1,633 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<bindings id="placesMenuBindings"
|
||||
xmlns="http://www.mozilla.org/xbl"
|
||||
xmlns:xbl="http://www.mozilla.org/xbl"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<binding id="places-popup-base"
|
||||
extends="chrome://global/content/bindings/popup.xml#popup">
|
||||
<content>
|
||||
<xul:hbox flex="1">
|
||||
<xul:vbox class="menupopup-drop-indicator-bar" hidden="true">
|
||||
<xul:image class="menupopup-drop-indicator" mousethrough="always"/>
|
||||
</xul:vbox>
|
||||
<xul:arrowscrollbox class="popup-internal-box" flex="1" orient="vertical"
|
||||
smoothscroll="false">
|
||||
<children/>
|
||||
</xul:arrowscrollbox>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
|
||||
<implementation>
|
||||
|
||||
<field name="AppConstants" readonly="true">
|
||||
(Components.utils.import("resource://gre/modules/AppConstants.jsm", {})).AppConstants;
|
||||
</field>
|
||||
|
||||
<field name="_indicatorBar">
|
||||
document.getAnonymousElementByAttribute(this, "class",
|
||||
"menupopup-drop-indicator-bar");
|
||||
</field>
|
||||
|
||||
<field name="_scrollBox">
|
||||
document.getAnonymousElementByAttribute(this, "class",
|
||||
"popup-internal-box");
|
||||
</field>
|
||||
|
||||
<!-- This is the view that manage the popup -->
|
||||
<field name="_rootView">PlacesUIUtils.getViewForNode(this);</field>
|
||||
|
||||
<!-- Check if we should hide the drop indicator for the target -->
|
||||
<method name="_hideDropIndicator">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
let target = aEvent.target;
|
||||
|
||||
// Don't draw the drop indicator outside of markers or if current
|
||||
// node is not a Places node.
|
||||
let betweenMarkers =
|
||||
(this._startMarker.compareDocumentPosition(target) & Node.DOCUMENT_POSITION_FOLLOWING) &&
|
||||
(this._endMarker.compareDocumentPosition(target) & Node.DOCUMENT_POSITION_PRECEDING);
|
||||
|
||||
// Hide the dropmarker if current node is not a Places node.
|
||||
return !(target && target._placesNode && betweenMarkers);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- This function returns information about where to drop when
|
||||
dragging over this popup insertion point -->
|
||||
<method name="_getDropPoint">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
// Can't drop if the menu isn't a folder
|
||||
let resultNode = this._placesNode;
|
||||
|
||||
if (!PlacesUtils.nodeIsFolder(resultNode) ||
|
||||
PlacesControllerDragHelper.disallowInsertion(resultNode)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var dropPoint = { ip: null, folderElt: null };
|
||||
|
||||
// The element we are dragging over
|
||||
let elt = aEvent.target;
|
||||
if (elt.localName == "menupopup")
|
||||
elt = elt.parentNode;
|
||||
|
||||
// Calculate positions taking care of arrowscrollbox
|
||||
let scrollbox = this._scrollBox;
|
||||
let eventY = aEvent.layerY + (scrollbox.boxObject.y - this.boxObject.y);
|
||||
let scrollboxOffset = scrollbox.scrollBoxObject.y -
|
||||
(scrollbox.boxObject.y - this.boxObject.y);
|
||||
let eltY = elt.boxObject.y - scrollboxOffset;
|
||||
let eltHeight = elt.boxObject.height;
|
||||
|
||||
if (!elt._placesNode) {
|
||||
// If we are dragging over a non places node drop at the end.
|
||||
dropPoint.ip = new InsertionPoint(
|
||||
PlacesUtils.getConcreteItemId(resultNode),
|
||||
-1,
|
||||
Ci.nsITreeView.DROP_ON);
|
||||
// We can set folderElt if we are dropping over a static menu that
|
||||
// has an internal placespopup.
|
||||
let isMenu = elt.localName == "menu" ||
|
||||
(elt.localName == "toolbarbutton" &&
|
||||
elt.getAttribute("type") == "menu");
|
||||
if (isMenu && elt.lastChild &&
|
||||
elt.lastChild.hasAttribute("placespopup"))
|
||||
dropPoint.folderElt = elt;
|
||||
return dropPoint;
|
||||
}
|
||||
|
||||
let tagName = PlacesUtils.nodeIsTagQuery(elt._placesNode) ?
|
||||
elt._placesNode.title : null;
|
||||
if ((PlacesUtils.nodeIsFolder(elt._placesNode) &&
|
||||
!PlacesUIUtils.isContentsReadOnly(elt._placesNode)) ||
|
||||
PlacesUtils.nodeIsTagQuery(elt._placesNode)) {
|
||||
// This is a folder or a tag container.
|
||||
if (eventY - eltY < eltHeight * 0.20) {
|
||||
// If mouse is in the top part of the element, drop above folder.
|
||||
dropPoint.ip = new InsertionPoint(
|
||||
PlacesUtils.getConcreteItemId(resultNode),
|
||||
-1,
|
||||
Ci.nsITreeView.DROP_BEFORE,
|
||||
tagName,
|
||||
elt._placesNode.itemId);
|
||||
return dropPoint;
|
||||
}
|
||||
else if (eventY - eltY < eltHeight * 0.80) {
|
||||
// If mouse is in the middle of the element, drop inside folder.
|
||||
dropPoint.ip = new InsertionPoint(
|
||||
PlacesUtils.getConcreteItemId(elt._placesNode),
|
||||
-1,
|
||||
Ci.nsITreeView.DROP_ON,
|
||||
tagName);
|
||||
dropPoint.folderElt = elt;
|
||||
return dropPoint;
|
||||
}
|
||||
}
|
||||
else if (eventY - eltY <= eltHeight / 2) {
|
||||
// This is a non-folder node or a readonly folder.
|
||||
// If the mouse is above the middle, drop above this item.
|
||||
dropPoint.ip = new InsertionPoint(
|
||||
PlacesUtils.getConcreteItemId(resultNode),
|
||||
-1,
|
||||
Ci.nsITreeView.DROP_BEFORE,
|
||||
tagName,
|
||||
elt._placesNode.itemId);
|
||||
return dropPoint;
|
||||
}
|
||||
|
||||
// Drop below the item.
|
||||
dropPoint.ip = new InsertionPoint(
|
||||
PlacesUtils.getConcreteItemId(resultNode),
|
||||
-1,
|
||||
Ci.nsITreeView.DROP_AFTER,
|
||||
tagName,
|
||||
elt._placesNode.itemId);
|
||||
return dropPoint;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- Sub-menus should be opened when the mouse drags over them, and closed
|
||||
when the mouse drags off. The overFolder object manages opening and
|
||||
closing of folders when the mouse hovers. -->
|
||||
<field name="_overFolder"><![CDATA[({
|
||||
_self: this,
|
||||
_folder: {elt: null,
|
||||
openTimer: null,
|
||||
hoverTime: 350,
|
||||
closeTimer: null},
|
||||
_closeMenuTimer: null,
|
||||
|
||||
get elt() {
|
||||
return this._folder.elt;
|
||||
},
|
||||
set elt(val) {
|
||||
return this._folder.elt = val;
|
||||
},
|
||||
|
||||
get openTimer() {
|
||||
return this._folder.openTimer;
|
||||
},
|
||||
set openTimer(val) {
|
||||
return this._folder.openTimer = val;
|
||||
},
|
||||
|
||||
get hoverTime() {
|
||||
return this._folder.hoverTime;
|
||||
},
|
||||
set hoverTime(val) {
|
||||
return this._folder.hoverTime = val;
|
||||
},
|
||||
|
||||
get closeTimer() {
|
||||
return this._folder.closeTimer;
|
||||
},
|
||||
set closeTimer(val) {
|
||||
return this._folder.closeTimer = val;
|
||||
},
|
||||
|
||||
get closeMenuTimer() {
|
||||
return this._closeMenuTimer;
|
||||
},
|
||||
set closeMenuTimer(val) {
|
||||
return this._closeMenuTimer = val;
|
||||
},
|
||||
|
||||
setTimer: function OF__setTimer(aTime) {
|
||||
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(this, aTime, timer.TYPE_ONE_SHOT);
|
||||
return timer;
|
||||
},
|
||||
|
||||
notify: function OF__notify(aTimer) {
|
||||
// Function to process all timer notifications.
|
||||
|
||||
if (aTimer == this._folder.openTimer) {
|
||||
// Timer to open a submenu that's being dragged over.
|
||||
this._folder.elt.lastChild.setAttribute("autoopened", "true");
|
||||
this._folder.elt.lastChild.showPopup(this._folder.elt);
|
||||
this._folder.openTimer = null;
|
||||
}
|
||||
|
||||
else if (aTimer == this._folder.closeTimer) {
|
||||
// Timer to close a submenu that's been dragged off of.
|
||||
// Only close the submenu if the mouse isn't being dragged over any
|
||||
// of its child menus.
|
||||
var draggingOverChild = PlacesControllerDragHelper
|
||||
.draggingOverChildNode(this._folder.elt);
|
||||
if (draggingOverChild)
|
||||
this._folder.elt = null;
|
||||
this.clear();
|
||||
|
||||
// Close any parent folders which aren't being dragged over.
|
||||
// (This is necessary because of the above code that keeps a folder
|
||||
// open while its children are being dragged over.)
|
||||
if (!draggingOverChild)
|
||||
this.closeParentMenus();
|
||||
}
|
||||
|
||||
else if (aTimer == this.closeMenuTimer) {
|
||||
// Timer to close this menu after the drag exit.
|
||||
var popup = this._self;
|
||||
// if we are no more dragging we can leave the menu open to allow
|
||||
// for better D&D bookmark organization
|
||||
if (PlacesControllerDragHelper.getSession() &&
|
||||
!PlacesControllerDragHelper.draggingOverChildNode(popup.parentNode)) {
|
||||
popup.hidePopup();
|
||||
// Close any parent menus that aren't being dragged over;
|
||||
// otherwise they'll stay open because they couldn't close
|
||||
// while this menu was being dragged over.
|
||||
this.closeParentMenus();
|
||||
}
|
||||
this._closeMenuTimer = null;
|
||||
}
|
||||
},
|
||||
|
||||
// Helper function to close all parent menus of this menu,
|
||||
// as long as none of the parent's children are currently being
|
||||
// dragged over.
|
||||
closeParentMenus: function OF__closeParentMenus() {
|
||||
var popup = this._self;
|
||||
var parent = popup.parentNode;
|
||||
while (parent) {
|
||||
if (parent.localName == "menupopup" && parent._placesNode) {
|
||||
if (PlacesControllerDragHelper.draggingOverChildNode(parent.parentNode))
|
||||
break;
|
||||
parent.hidePopup();
|
||||
}
|
||||
parent = parent.parentNode;
|
||||
}
|
||||
},
|
||||
|
||||
// The mouse is no longer dragging over the stored menubutton.
|
||||
// Close the menubutton, clear out drag styles, and clear all
|
||||
// timers for opening/closing it.
|
||||
clear: function OF__clear() {
|
||||
if (this._folder.elt && this._folder.elt.lastChild) {
|
||||
if (!this._folder.elt.lastChild.hasAttribute("dragover"))
|
||||
this._folder.elt.lastChild.hidePopup();
|
||||
// remove menuactive style
|
||||
this._folder.elt.removeAttribute("_moz-menuactive");
|
||||
this._folder.elt = null;
|
||||
}
|
||||
if (this._folder.openTimer) {
|
||||
this._folder.openTimer.cancel();
|
||||
this._folder.openTimer = null;
|
||||
}
|
||||
if (this._folder.closeTimer) {
|
||||
this._folder.closeTimer.cancel();
|
||||
this._folder.closeTimer = null;
|
||||
}
|
||||
}
|
||||
})]]></field>
|
||||
|
||||
<method name="_cleanupDragDetails">
|
||||
<body><![CDATA[
|
||||
// Called on dragend and drop.
|
||||
PlacesControllerDragHelper.currentDropTarget = null;
|
||||
this._rootView._draggedElt = null;
|
||||
this.removeAttribute("dragover");
|
||||
this.removeAttribute("dragstart");
|
||||
this._indicatorBar.hidden = true;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
</implementation>
|
||||
|
||||
<handlers>
|
||||
<handler event="DOMMenuItemActive"><![CDATA[
|
||||
let elt = event.target;
|
||||
if (elt.parentNode != this)
|
||||
return;
|
||||
|
||||
if (this.AppConstants.platform === "macosx") {
|
||||
// XXX: The following check is a temporary hack until bug 420033 is
|
||||
// resolved.
|
||||
let parentElt = elt.parent;
|
||||
while (parentElt) {
|
||||
if (parentElt.id == "bookmarksMenuPopup" ||
|
||||
parentElt.id == "goPopup")
|
||||
return;
|
||||
|
||||
parentElt = parentElt.parentNode;
|
||||
}
|
||||
}
|
||||
|
||||
if (window.XULBrowserWindow) {
|
||||
let elt = event.target;
|
||||
let placesNode = elt._placesNode;
|
||||
|
||||
var linkURI;
|
||||
if (placesNode && PlacesUtils.nodeIsURI(placesNode))
|
||||
linkURI = placesNode.uri;
|
||||
else if (elt.hasAttribute("targetURI"))
|
||||
linkURI = elt.getAttribute("targetURI");
|
||||
|
||||
if (linkURI)
|
||||
window.XULBrowserWindow.setOverLink(linkURI, null);
|
||||
}
|
||||
]]></handler>
|
||||
|
||||
<handler event="DOMMenuItemInactive"><![CDATA[
|
||||
let elt = event.target;
|
||||
if (elt.parentNode != this)
|
||||
return;
|
||||
|
||||
if (window.XULBrowserWindow)
|
||||
window.XULBrowserWindow.setOverLink("", null);
|
||||
]]></handler>
|
||||
|
||||
<handler event="dragstart"><![CDATA[
|
||||
let elt = event.target;
|
||||
if (!elt._placesNode)
|
||||
return;
|
||||
|
||||
let draggedElt = elt._placesNode;
|
||||
|
||||
// Force a copy action if parent node is a query or we are dragging a
|
||||
// not-removable node.
|
||||
if (!PlacesControllerDragHelper.canMoveNode(draggedElt, elt))
|
||||
event.dataTransfer.effectAllowed = "copyLink";
|
||||
|
||||
// Activate the view and cache the dragged element.
|
||||
this._rootView._draggedElt = draggedElt;
|
||||
this._rootView.controller.setDataTransfer(event);
|
||||
this.setAttribute("dragstart", "true");
|
||||
event.stopPropagation();
|
||||
]]></handler>
|
||||
|
||||
<handler event="drop"><![CDATA[
|
||||
PlacesControllerDragHelper.currentDropTarget = event.target;
|
||||
|
||||
let dropPoint = this._getDropPoint(event);
|
||||
if (dropPoint && dropPoint.ip) {
|
||||
PlacesControllerDragHelper.onDrop(dropPoint.ip, event.dataTransfer)
|
||||
.then(null, Components.utils.reportError);
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
this._cleanupDragDetails();
|
||||
event.stopPropagation();
|
||||
]]></handler>
|
||||
|
||||
<handler event="dragover"><![CDATA[
|
||||
PlacesControllerDragHelper.currentDropTarget = event.target;
|
||||
let dt = event.dataTransfer;
|
||||
|
||||
let dropPoint = this._getDropPoint(event);
|
||||
if (!dropPoint || !dropPoint.ip ||
|
||||
!PlacesControllerDragHelper.canDrop(dropPoint.ip, dt)) {
|
||||
this._indicatorBar.hidden = true;
|
||||
event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark this popup as being dragged over.
|
||||
this.setAttribute("dragover", "true");
|
||||
|
||||
if (dropPoint.folderElt) {
|
||||
// We are dragging over a folder.
|
||||
// _overFolder should take the care of opening it on a timer.
|
||||
if (this._overFolder.elt &&
|
||||
this._overFolder.elt != dropPoint.folderElt) {
|
||||
// We are dragging over a new folder, let's clear old values
|
||||
this._overFolder.clear();
|
||||
}
|
||||
if (!this._overFolder.elt) {
|
||||
this._overFolder.elt = dropPoint.folderElt;
|
||||
// Create the timer to open this folder.
|
||||
this._overFolder.openTimer = this._overFolder
|
||||
.setTimer(this._overFolder.hoverTime);
|
||||
}
|
||||
// Since we are dropping into a folder set the corresponding style.
|
||||
dropPoint.folderElt.setAttribute("_moz-menuactive", true);
|
||||
}
|
||||
else {
|
||||
// We are not dragging over a folder.
|
||||
// Clear out old _overFolder information.
|
||||
this._overFolder.clear();
|
||||
}
|
||||
|
||||
// Autoscroll the popup strip if we drag over the scroll buttons.
|
||||
let anonid = event.originalTarget.getAttribute('anonid');
|
||||
let scrollDir = 0;
|
||||
if (anonid == "scrollbutton-up") {
|
||||
scrollDir = -1;
|
||||
} else if (anonid == "scrollbutton-down") {
|
||||
scrollDir = 1;
|
||||
}
|
||||
if (scrollDir != 0) {
|
||||
this._scrollBox.scrollByIndex(scrollDir, false);
|
||||
}
|
||||
|
||||
// Check if we should hide the drop indicator for this target.
|
||||
if (dropPoint.folderElt || this._hideDropIndicator(event)) {
|
||||
this._indicatorBar.hidden = true;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
// We should display the drop indicator relative to the arrowscrollbox.
|
||||
let sbo = this._scrollBox.scrollBoxObject;
|
||||
let newMarginTop = 0;
|
||||
if (scrollDir == 0) {
|
||||
let elt = this.firstChild;
|
||||
while (elt && event.screenY > elt.boxObject.screenY +
|
||||
elt.boxObject.height / 2)
|
||||
elt = elt.nextSibling;
|
||||
newMarginTop = elt ? elt.boxObject.screenY - sbo.screenY :
|
||||
sbo.height;
|
||||
}
|
||||
else if (scrollDir == 1)
|
||||
newMarginTop = sbo.height;
|
||||
|
||||
// Set the new marginTop based on arrowscrollbox.
|
||||
newMarginTop += sbo.y - this._scrollBox.boxObject.y;
|
||||
this._indicatorBar.firstChild.style.marginTop = newMarginTop + "px";
|
||||
this._indicatorBar.hidden = false;
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
]]></handler>
|
||||
|
||||
<handler event="dragexit"><![CDATA[
|
||||
PlacesControllerDragHelper.currentDropTarget = null;
|
||||
this.removeAttribute("dragover");
|
||||
|
||||
// If we have not moved to a valid new target clear the drop indicator
|
||||
// this happens when moving out of the popup.
|
||||
let target = event.relatedTarget;
|
||||
if (!target || !this.contains(target))
|
||||
this._indicatorBar.hidden = true;
|
||||
|
||||
// Close any folder being hovered over
|
||||
if (this._overFolder.elt) {
|
||||
this._overFolder.closeTimer = this._overFolder
|
||||
.setTimer(this._overFolder.hoverTime);
|
||||
}
|
||||
|
||||
// The autoopened attribute is set when this folder was automatically
|
||||
// opened after the user dragged over it. If this attribute is set,
|
||||
// auto-close the folder on drag exit.
|
||||
// We should also try to close this popup if the drag has started
|
||||
// from here, the timer will check if we are dragging over a child.
|
||||
if (this.hasAttribute("autoopened") ||
|
||||
this.hasAttribute("dragstart")) {
|
||||
this._overFolder.closeMenuTimer = this._overFolder
|
||||
.setTimer(this._overFolder.hoverTime);
|
||||
}
|
||||
|
||||
event.stopPropagation();
|
||||
]]></handler>
|
||||
|
||||
<handler event="dragend"><![CDATA[
|
||||
this._cleanupDragDetails();
|
||||
]]></handler>
|
||||
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
<!-- Most of this is copied from the arrowpanel binding in popup.xml -->
|
||||
<binding id="places-popup-arrow"
|
||||
extends="chrome://browser/content/places/menu.xml#places-popup-base">
|
||||
<content flip="both" side="top" position="bottomcenter topright">
|
||||
<xul:vbox anonid="container" class="panel-arrowcontainer" flex="1"
|
||||
xbl:inherits="side,panelopen">
|
||||
<xul:box anonid="arrowbox" class="panel-arrowbox">
|
||||
<xul:image anonid="arrow" class="panel-arrow" xbl:inherits="side"/>
|
||||
</xul:box>
|
||||
<xul:box class="panel-arrowcontent" xbl:inherits="side,align,dir,orient,pack" flex="1">
|
||||
<xul:vbox class="menupopup-drop-indicator-bar" hidden="true">
|
||||
<xul:image class="menupopup-drop-indicator" mousethrough="always"/>
|
||||
</xul:vbox>
|
||||
<xul:arrowscrollbox class="popup-internal-box" flex="1" orient="vertical"
|
||||
smoothscroll="false">
|
||||
<children/>
|
||||
</xul:arrowscrollbox>
|
||||
</xul:box>
|
||||
</xul:vbox>
|
||||
</content>
|
||||
|
||||
<implementation>
|
||||
<constructor><![CDATA[
|
||||
this.style.pointerEvents = 'none';
|
||||
]]></constructor>
|
||||
<method name="adjustArrowPosition">
|
||||
<body><![CDATA[
|
||||
var arrow = document.getAnonymousElementByAttribute(this, "anonid", "arrow");
|
||||
|
||||
var anchor = this.anchorNode;
|
||||
if (!anchor) {
|
||||
arrow.hidden = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var container = document.getAnonymousElementByAttribute(this, "anonid", "container");
|
||||
var arrowbox = document.getAnonymousElementByAttribute(this, "anonid", "arrowbox");
|
||||
|
||||
var position = this.alignmentPosition;
|
||||
var offset = this.alignmentOffset;
|
||||
|
||||
this.setAttribute("arrowposition", position);
|
||||
|
||||
// if this panel has a "sliding" arrow, we may have previously set margins...
|
||||
arrowbox.style.removeProperty("transform");
|
||||
if (position.indexOf("start_") == 0 || position.indexOf("end_") == 0) {
|
||||
container.orient = "horizontal";
|
||||
arrowbox.orient = "vertical";
|
||||
if (position.indexOf("_after") > 0) {
|
||||
arrowbox.pack = "end";
|
||||
} else {
|
||||
arrowbox.pack = "start";
|
||||
}
|
||||
arrowbox.style.transform = "translate(0, " + -offset + "px)";
|
||||
|
||||
// The assigned side stays the same regardless of direction.
|
||||
var isRTL = (window.getComputedStyle(this).direction == "rtl");
|
||||
|
||||
if (position.indexOf("start_") == 0) {
|
||||
container.dir = "reverse";
|
||||
this.setAttribute("side", isRTL ? "left" : "right");
|
||||
}
|
||||
else {
|
||||
container.dir = "";
|
||||
this.setAttribute("side", isRTL ? "right" : "left");
|
||||
}
|
||||
}
|
||||
else if (position.indexOf("before_") == 0 || position.indexOf("after_") == 0) {
|
||||
container.orient = "";
|
||||
arrowbox.orient = "";
|
||||
if (position.indexOf("_end") > 0) {
|
||||
arrowbox.pack = "end";
|
||||
} else {
|
||||
arrowbox.pack = "start";
|
||||
}
|
||||
arrowbox.style.transform = "translate(" + -offset + "px, 0)";
|
||||
|
||||
if (position.indexOf("before_") == 0) {
|
||||
container.dir = "reverse";
|
||||
this.setAttribute("side", "bottom");
|
||||
}
|
||||
else {
|
||||
container.dir = "";
|
||||
this.setAttribute("side", "top");
|
||||
}
|
||||
}
|
||||
|
||||
arrow.hidden = false;
|
||||
]]></body>
|
||||
</method>
|
||||
</implementation>
|
||||
|
||||
<handlers>
|
||||
<handler event="popupshowing" phase="target"><![CDATA[
|
||||
this.adjustArrowPosition();
|
||||
this.setAttribute("animate", "open");
|
||||
]]></handler>
|
||||
<handler event="popupshown" phase="target"><![CDATA[
|
||||
this.setAttribute("panelopen", "true");
|
||||
let disablePointerEvents;
|
||||
if (!this.hasAttribute("disablepointereventsfortransition")) {
|
||||
let container = document.getAnonymousElementByAttribute(this, "anonid", "container");
|
||||
let cs = getComputedStyle(container);
|
||||
let transitionProp = cs.transitionProperty;
|
||||
let transitionTime = parseFloat(cs.transitionDuration);
|
||||
disablePointerEvents = (transitionProp.includes("transform") ||
|
||||
transitionProp == "all") &&
|
||||
transitionTime > 0;
|
||||
this.setAttribute("disablepointereventsfortransition", disablePointerEvents);
|
||||
} else {
|
||||
disablePointerEvents = this.getAttribute("disablepointereventsfortransition") == "true";
|
||||
}
|
||||
if (!disablePointerEvents) {
|
||||
this.style.removeProperty("pointer-events");
|
||||
}
|
||||
]]></handler>
|
||||
<handler event="transitionend"><![CDATA[
|
||||
if (event.originalTarget.getAttribute("anonid") == "container" &&
|
||||
event.propertyName == "transform") {
|
||||
this.style.removeProperty("pointer-events");
|
||||
}
|
||||
]]></handler>
|
||||
<handler event="popuphiding" phase="target"><![CDATA[
|
||||
this.setAttribute("animate", "cancel");
|
||||
]]></handler>
|
||||
<handler event="popuphidden" phase="target"><![CDATA[
|
||||
this.removeAttribute("panelopen");
|
||||
if (this.getAttribute("disablepointereventsfortransition") == "true") {
|
||||
this.style.pointerEvents = 'none';
|
||||
}
|
||||
this.removeAttribute("animate");
|
||||
]]></handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
</bindings>
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var gMoveBookmarksDialog = {
|
||||
_nodes: null,
|
||||
|
||||
_foldersTree: null,
|
||||
get foldersTree() {
|
||||
if (!this._foldersTree)
|
||||
this._foldersTree = document.getElementById("foldersTree");
|
||||
|
||||
return this._foldersTree;
|
||||
},
|
||||
|
||||
init: function() {
|
||||
this._nodes = window.arguments[0];
|
||||
|
||||
this.foldersTree.place =
|
||||
"place:excludeItems=1&excludeQueries=1&excludeReadOnlyFolders=1&folder=" +
|
||||
PlacesUIUtils.allBookmarksFolderId;
|
||||
},
|
||||
|
||||
onOK: function MBD_onOK(aEvent) {
|
||||
let selectedNode = this.foldersTree.selectedNode;
|
||||
let selectedFolderId = PlacesUtils.getConcreteItemId(selectedNode);
|
||||
|
||||
if (!PlacesUIUtils.useAsyncTransactions) {
|
||||
let transactions = [];
|
||||
for (var i=0; i < this._nodes.length; i++) {
|
||||
// Nothing to do if the node is already under the selected folder
|
||||
if (this._nodes[i].parent.itemId == selectedFolderId)
|
||||
continue;
|
||||
|
||||
let txn = new PlacesMoveItemTransaction(this._nodes[i].itemId,
|
||||
selectedFolderId,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX);
|
||||
transactions.push(txn);
|
||||
}
|
||||
if (transactions.length != 0) {
|
||||
let txn = new PlacesAggregatedTransaction("Move Items", transactions);
|
||||
PlacesUtils.transactionManager.doTransaction(txn);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
PlacesTransactions.batch(function* () {
|
||||
let newParentGuid = yield PlacesUtils.promiseItemGuid(selectedFolderId);
|
||||
for (let node of this._nodes) {
|
||||
// Nothing to do if the node is already under the selected folder.
|
||||
if (node.parent.itemId == selectedFolderId)
|
||||
continue;
|
||||
yield PlacesTransactions.Move({ guid: node.bookmarkGuid
|
||||
, newParentGuid }).transact();
|
||||
}
|
||||
}.bind(this)).then(null, Components.utils.reportError);
|
||||
},
|
||||
|
||||
newFolder: function MBD_newFolder() {
|
||||
// The command is disabled when the tree is not focused
|
||||
this.foldersTree.focus();
|
||||
goDoCommand("placesCmd_new:folder");
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
|
||||
<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
|
||||
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % moveBookmarksDTD SYSTEM "chrome://browser/locale/places/moveBookmarks.dtd">
|
||||
%moveBookmarksDTD;
|
||||
]>
|
||||
|
||||
<dialog id="moveBookmarkDialog"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
ondialogaccept="return gMoveBookmarksDialog.onOK(event);"
|
||||
title="&window.title;"
|
||||
onload="gMoveBookmarksDialog.init();"
|
||||
style="&window.style;"
|
||||
screenX="24"
|
||||
screenY="24"
|
||||
persist="screenX screenY width height">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/places/moveBookmarks.js"/>
|
||||
|
||||
<hbox flex="1">
|
||||
<label id="movetolabel" value="&moveTo.label;" control="foldersTree"/>
|
||||
<hbox flex="1">
|
||||
<tree id="foldersTree"
|
||||
class="placesTree"
|
||||
flex="1"
|
||||
type="places"
|
||||
seltype="single"
|
||||
hidecolumnpicker="true">
|
||||
<treecols>
|
||||
<treecol id="title" flex="1" primary="true" hideheader="true"/>
|
||||
</treecols>
|
||||
<treechildren id="placesListChildren" view="placesList" flex="1"/>
|
||||
</tree>
|
||||
<vbox>
|
||||
<button id="newFolderButton"
|
||||
label="&newFolderButton.label;"
|
||||
accesskey="&newFolderButton.accesskey;"
|
||||
oncommand="gMoveBookmarksDialog.newFolder();"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</hbox>
|
||||
</dialog>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#searchFilter {
|
||||
width: 23em;
|
||||
}
|
||||
25
application/basilisk/components/places/content/places.css
Normal file
25
application/basilisk/components/places/content/places.css
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
tree[type="places"] {
|
||||
-moz-binding: url("chrome://browser/content/places/tree.xml#places-tree");
|
||||
}
|
||||
|
||||
.toolbar-drop-indicator {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
menupopup[placespopup="true"] {
|
||||
-moz-binding: url("chrome://browser/content/places/menu.xml#places-popup-base");
|
||||
}
|
||||
|
||||
/* Apply crisp rendering for favicons at exactly 2dppx resolution */
|
||||
@media (resolution: 2dppx) {
|
||||
#bookmarksChildren,
|
||||
.sidebar-placesTreechildren,
|
||||
.placesTree > treechildren {
|
||||
image-rendering: -moz-crisp-edges;
|
||||
}
|
||||
}
|
||||
1405
application/basilisk/components/places/content/places.js
Normal file
1405
application/basilisk/components/places/content/places.js
Normal file
File diff suppressed because it is too large
Load diff
438
application/basilisk/components/places/content/places.xul
Normal file
438
application/basilisk/components/places/content/places.xul
Normal file
|
|
@ -0,0 +1,438 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/places/organizer.css"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/organizer.css"?>
|
||||
|
||||
<?xul-overlay href="chrome://browser/content/places/editBookmarkOverlay.xul"?>
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
<?xul-overlay href="chrome://browser/content/macBrowserOverlay.xul"?>
|
||||
#else
|
||||
<?xul-overlay href="chrome://browser/content/baseMenuOverlay.xul"?>
|
||||
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
|
||||
<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
|
||||
#endif
|
||||
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % placesDTD SYSTEM "chrome://browser/locale/places/places.dtd">
|
||||
%placesDTD;
|
||||
<!ENTITY % editMenuOverlayDTD SYSTEM "chrome://global/locale/editMenuOverlay.dtd">
|
||||
%editMenuOverlayDTD;
|
||||
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
|
||||
%browserDTD;
|
||||
]>
|
||||
|
||||
<window id="places"
|
||||
title="&places.library.title;"
|
||||
windowtype="Places:Organizer"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
onload="PlacesOrganizer.init();"
|
||||
onunload="PlacesOrganizer.destroy();"
|
||||
width="&places.library.width;" height="&places.library.height;"
|
||||
screenX="10" screenY="10"
|
||||
toggletoolbar="true"
|
||||
persist="width height screenX screenY sizemode">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/places/places.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/utilityOverlay.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/places/editBookmarkOverlay.js"/>
|
||||
|
||||
<stringbundleset id="placesStringSet">
|
||||
<stringbundle id="brandStrings" src="chrome://branding/locale/brand.properties"/>
|
||||
</stringbundleset>
|
||||
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include ../../../base/content/browserMountPoints.inc
|
||||
#else
|
||||
<commandset id="editMenuCommands"/>
|
||||
<commandset id="placesCommands"/>
|
||||
#endif
|
||||
|
||||
<commandset id="organizerCommandSet">
|
||||
<command id="OrganizerCommand_find:all"
|
||||
oncommand="PlacesSearchBox.findAll();"/>
|
||||
<command id="OrganizerCommand_export"
|
||||
oncommand="PlacesOrganizer.exportBookmarks();"/>
|
||||
<command id="OrganizerCommand_import"
|
||||
oncommand="PlacesOrganizer.importFromFile();"/>
|
||||
<command id="OrganizerCommand_browserImport"
|
||||
oncommand="PlacesOrganizer.importFromBrowser();"/>
|
||||
<command id="OrganizerCommand_backup"
|
||||
oncommand="PlacesOrganizer.backupBookmarks();"/>
|
||||
<command id="OrganizerCommand_restoreFromFile"
|
||||
oncommand="PlacesOrganizer.onRestoreBookmarksFromFile();"/>
|
||||
<command id="OrganizerCommand_search:save"
|
||||
oncommand="PlacesOrganizer.saveSearch();"/>
|
||||
<command id="OrganizerCommand_search:moreCriteria"
|
||||
oncommand="PlacesQueryBuilder.addRow();"/>
|
||||
<command id="OrganizerCommand:Back"
|
||||
oncommand="PlacesOrganizer.back();"/>
|
||||
<command id="OrganizerCommand:Forward"
|
||||
oncommand="PlacesOrganizer.forward();"/>
|
||||
</commandset>
|
||||
|
||||
|
||||
<keyset id="placesOrganizerKeyset">
|
||||
<!-- Instantiation Keys -->
|
||||
<key id="placesKey_close" key="&cmd.close.key;" modifiers="accel"
|
||||
oncommand="close();"/>
|
||||
|
||||
<!-- Command Keys -->
|
||||
<key id="placesKey_find:all"
|
||||
command="OrganizerCommand_find:all"
|
||||
key="&cmd.find.key;"
|
||||
modifiers="accel"/>
|
||||
|
||||
<!-- Back/Forward Keys Support -->
|
||||
#ifndef XP_MACOSX
|
||||
<key id="placesKey_goBackKb"
|
||||
keycode="VK_LEFT"
|
||||
command="OrganizerCommand:Back"
|
||||
modifiers="alt"/>
|
||||
<key id="placesKey_goForwardKb"
|
||||
keycode="VK_RIGHT"
|
||||
command="OrganizerCommand:Forward"
|
||||
modifiers="alt"/>
|
||||
#else
|
||||
<key id="placesKey_goBackKb"
|
||||
keycode="VK_LEFT"
|
||||
command="OrganizerCommand:Back"
|
||||
modifiers="accel"/>
|
||||
<key id="placesKey_goForwardKb"
|
||||
keycode="VK_RIGHT"
|
||||
command="OrganizerCommand:Forward"
|
||||
modifiers="accel"/>
|
||||
#endif
|
||||
#ifdef XP_UNIX
|
||||
<key id="placesKey_goBackKb2"
|
||||
key="&goBackCmd.commandKey;"
|
||||
command="OrganizerCommand:Back"
|
||||
modifiers="accel"/>
|
||||
<key id="placesKey_goForwardKb2"
|
||||
key="&goForwardCmd.commandKey;"
|
||||
command="OrganizerCommand:Forward"
|
||||
modifiers="accel"/>
|
||||
#endif
|
||||
</keyset>
|
||||
|
||||
<keyset id="editMenuKeys">
|
||||
#ifdef XP_MACOSX
|
||||
<key id="key_delete2" keycode="VK_BACK" command="cmd_delete"/>
|
||||
#endif
|
||||
</keyset>
|
||||
|
||||
<popupset id="placesPopupset">
|
||||
<menupopup id="placesContext"/>
|
||||
<menupopup id="placesColumnsContext"
|
||||
onpopupshowing="ViewMenu.fillWithColumns(event, null, null, 'checkbox', null);"
|
||||
oncommand="ViewMenu.showHideColumn(event.target); event.stopPropagation();"/>
|
||||
</popupset>
|
||||
|
||||
<toolbox id="placesToolbox">
|
||||
<toolbar class="chromeclass-toolbar" id="placesToolbar" align="center">
|
||||
<toolbarbutton id="back-button"
|
||||
command="OrganizerCommand:Back"
|
||||
tooltiptext="&backButton.tooltip;"
|
||||
disabled="true"/>
|
||||
|
||||
<toolbarbutton id="forward-button"
|
||||
command="OrganizerCommand:Forward"
|
||||
tooltiptext="&forwardButton.tooltip;"
|
||||
disabled="true"/>
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
<toolbarbutton type="menu" class="tabbable"
|
||||
onpopupshowing="document.getElementById('placeContent').focus()"
|
||||
#else
|
||||
<menubar id="placesMenu">
|
||||
<menu accesskey="&organize.accesskey;" class="menu-iconic"
|
||||
#endif
|
||||
id="organizeButton" label="&organize.label;"
|
||||
tooltiptext="&organize.tooltip;">
|
||||
<menupopup id="organizeButtonPopup">
|
||||
<menuitem id="newbookmark"
|
||||
command="placesCmd_new:bookmark"
|
||||
label="&cmd.new_bookmark.label;"
|
||||
accesskey="&cmd.new_bookmark.accesskey;"/>
|
||||
<menuitem id="newfolder"
|
||||
command="placesCmd_new:folder"
|
||||
label="&cmd.new_folder.label;"
|
||||
accesskey="&cmd.new_folder.accesskey;"/>
|
||||
<menuitem id="newseparator"
|
||||
command="placesCmd_new:separator"
|
||||
label="&cmd.new_separator.label;"
|
||||
accesskey="&cmd.new_separator.accesskey;"/>
|
||||
|
||||
#ifndef XP_MACOSX
|
||||
<menuseparator id="orgUndoSeparator"/>
|
||||
|
||||
<menuitem id="orgUndo"
|
||||
command="cmd_undo"
|
||||
label="&undoCmd.label;"
|
||||
key="key_undo"
|
||||
accesskey="&undoCmd.accesskey;"/>
|
||||
<menuitem id="orgRedo"
|
||||
command="cmd_redo"
|
||||
label="&redoCmd.label;"
|
||||
key="key_redo"
|
||||
accesskey="&redoCmd.accesskey;"/>
|
||||
|
||||
<menuseparator id="orgCutSeparator"/>
|
||||
|
||||
<menuitem id="orgCut"
|
||||
command="cmd_cut"
|
||||
label="&cutCmd.label;"
|
||||
key="key_cut"
|
||||
accesskey="&cutCmd.accesskey;"
|
||||
selection="separator|link|folder|mixed"/>
|
||||
<menuitem id="orgCopy"
|
||||
command="cmd_copy"
|
||||
label="©Cmd.label;"
|
||||
key="key_copy"
|
||||
accesskey="©Cmd.accesskey;"
|
||||
selection="separator|link|folder|mixed"/>
|
||||
<menuitem id="orgPaste"
|
||||
command="cmd_paste"
|
||||
label="&pasteCmd.label;"
|
||||
key="key_paste"
|
||||
accesskey="&pasteCmd.accesskey;"
|
||||
selection="mutable"/>
|
||||
<menuitem id="orgDelete"
|
||||
command="cmd_delete"
|
||||
label="&deleteCmd.label;"
|
||||
key="key_delete"
|
||||
accesskey="&deleteCmd.accesskey;"/>
|
||||
|
||||
<menuseparator id="selectAllSeparator"/>
|
||||
|
||||
<menuitem id="orgSelectAll"
|
||||
command="cmd_selectAll"
|
||||
label="&selectAllCmd.label;"
|
||||
key="key_selectAll"
|
||||
accesskey="&selectAllCmd.accesskey;"/>
|
||||
|
||||
#endif
|
||||
<menuseparator id="orgMoveSeparator"/>
|
||||
|
||||
<menuitem id="orgMoveBookmarks"
|
||||
command="placesCmd_moveBookmarks"
|
||||
label="&cmd.moveBookmarks.label;"
|
||||
accesskey="&cmd.moveBookmarks.accesskey;"/>
|
||||
#ifdef XP_MACOSX
|
||||
<menuitem id="orgDelete"
|
||||
command="cmd_delete"
|
||||
label="&deleteCmd.label;"
|
||||
key="key_delete"
|
||||
accesskey="&deleteCmd.accesskey;"/>
|
||||
#else
|
||||
<menuseparator id="orgCloseSeparator"/>
|
||||
|
||||
<menuitem id="orgClose"
|
||||
key="placesKey_close"
|
||||
label="&file.close.label;"
|
||||
accesskey="&file.close.accesskey;"
|
||||
oncommand="close();"/>
|
||||
#endif
|
||||
</menupopup>
|
||||
#ifdef XP_MACOSX
|
||||
</toolbarbutton>
|
||||
<toolbarbutton type="menu" class="tabbable"
|
||||
#else
|
||||
</menu>
|
||||
<menu accesskey="&views.accesskey;" class="menu-iconic"
|
||||
#endif
|
||||
id="viewMenu" label="&views.label;"
|
||||
tooltiptext="&views.tooltip;">
|
||||
<menupopup id="viewMenuPopup">
|
||||
|
||||
<menu id="viewColumns"
|
||||
label="&view.columns.label;" accesskey="&view.columns.accesskey;">
|
||||
<menupopup onpopupshowing="ViewMenu.fillWithColumns(event, null, null, 'checkbox', null);"
|
||||
oncommand="ViewMenu.showHideColumn(event.target); event.stopPropagation();"/>
|
||||
</menu>
|
||||
|
||||
<menu id="viewSort" label="&view.sort.label;"
|
||||
accesskey="&view.sort.accesskey;">
|
||||
<menupopup onpopupshowing="ViewMenu.populateSortMenu(event);"
|
||||
oncommand="ViewMenu.setSortColumn(event.target.column, null);">
|
||||
<menuitem id="viewUnsorted" type="radio" name="columns"
|
||||
label="&view.unsorted.label;" accesskey="&view.unsorted.accesskey;"
|
||||
oncommand="ViewMenu.setSortColumn(null, null);"/>
|
||||
<menuseparator id="directionSeparator"/>
|
||||
<menuitem id="viewSortAscending" type="radio" name="direction"
|
||||
label="&view.sortAscending.label;" accesskey="&view.sortAscending.accesskey;"
|
||||
oncommand="ViewMenu.setSortColumn(null, 'ascending'); event.stopPropagation();"/>
|
||||
<menuitem id="viewSortDescending" type="radio" name="direction"
|
||||
label="&view.sortDescending.label;" accesskey="&view.sortDescending.accesskey;"
|
||||
oncommand="ViewMenu.setSortColumn(null, 'descending'); event.stopPropagation();"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
</menupopup>
|
||||
#ifdef XP_MACOSX
|
||||
</toolbarbutton>
|
||||
<toolbarbutton type="menu" class="tabbable"
|
||||
#else
|
||||
</menu>
|
||||
<menu accesskey="&maintenance.accesskey;" class="menu-iconic"
|
||||
#endif
|
||||
id="maintenanceButton" label="&maintenance.label;"
|
||||
tooltiptext="&maintenance.tooltip;">
|
||||
<menupopup id="maintenanceButtonPopup">
|
||||
<menuitem id="backupBookmarks"
|
||||
command="OrganizerCommand_backup"
|
||||
label="&cmd.backup.label;"
|
||||
accesskey="&cmd.backup.accesskey;"/>
|
||||
<menu id="fileRestoreMenu" label="&cmd.restore2.label;"
|
||||
accesskey="&cmd.restore2.accesskey;">
|
||||
<menupopup id="fileRestorePopup" onpopupshowing="PlacesOrganizer.populateRestoreMenu();">
|
||||
<menuitem id="restoreFromFile"
|
||||
command="OrganizerCommand_restoreFromFile"
|
||||
label="&cmd.restoreFromFile.label;"
|
||||
accesskey="&cmd.restoreFromFile.accesskey;"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
<menuseparator/>
|
||||
<menuitem id="fileImport"
|
||||
command="OrganizerCommand_import"
|
||||
label="&importBookmarksFromHTML.label;"
|
||||
accesskey="&importBookmarksFromHTML.accesskey;"/>
|
||||
<menuitem id="fileExport"
|
||||
command="OrganizerCommand_export"
|
||||
label="&exportBookmarksToHTML.label;"
|
||||
accesskey="&exportBookmarksToHTML.accesskey;"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="browserImport"
|
||||
command="OrganizerCommand_browserImport"
|
||||
label="&importOtherBrowser.label;"
|
||||
accesskey="&importOtherBrowser.accesskey;"/>
|
||||
</menupopup>
|
||||
#ifdef XP_MACOSX
|
||||
</toolbarbutton>
|
||||
#else
|
||||
</menu>
|
||||
</menubar>
|
||||
#endif
|
||||
|
||||
<spacer id="libraryToolbarSpacer" flex="1"/>
|
||||
|
||||
<textbox id="searchFilter"
|
||||
clickSelectsAll="true"
|
||||
type="search"
|
||||
aria-controls="placeContent"
|
||||
oncommand="PlacesSearchBox.search(this.value);"
|
||||
collection="bookmarks">
|
||||
</textbox>
|
||||
</toolbar>
|
||||
</toolbox>
|
||||
|
||||
<hbox flex="1" id="placesView">
|
||||
<tree id="placesList"
|
||||
class="plain placesTree"
|
||||
type="places"
|
||||
hidecolumnpicker="true" context="placesContext"
|
||||
onselect="PlacesOrganizer.onPlaceSelected(true);"
|
||||
onclick="PlacesOrganizer.onPlacesListClick(event);"
|
||||
onfocus="PlacesOrganizer.updateDetailsPane(event);"
|
||||
seltype="single"
|
||||
persist="width"
|
||||
width="200"
|
||||
minwidth="100"
|
||||
maxwidth="400">
|
||||
<treecols>
|
||||
<treecol anonid="title" flex="1" primary="true" hideheader="true"/>
|
||||
</treecols>
|
||||
<treechildren flex="1"/>
|
||||
</tree>
|
||||
<splitter collapse="none" persist="state"></splitter>
|
||||
<vbox id="contentView" flex="4">
|
||||
<deck id="placesViewsDeck"
|
||||
selectedIndex="0"
|
||||
flex="1">
|
||||
<tree id="placeContent"
|
||||
class="plain placesTree"
|
||||
context="placesContext"
|
||||
hidecolumnpicker="true"
|
||||
flex="1"
|
||||
type="places"
|
||||
flatList="true"
|
||||
selectfirstnode="true"
|
||||
enableColumnDrag="true"
|
||||
onfocus="PlacesOrganizer.updateDetailsPane(event)"
|
||||
onselect="PlacesOrganizer.updateDetailsPane(event)"
|
||||
onkeypress="ContentTree.onKeyPress(event);"
|
||||
onopenflatcontainer="PlacesOrganizer.openFlatContainer(aContainer);">
|
||||
<treecols id="placeContentColumns" context="placesColumnsContext">
|
||||
<treecol label="&col.name.label;" id="placesContentTitle" anonid="title" flex="5" primary="true" ordinal="1"
|
||||
persist="width hidden ordinal sortActive sortDirection"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol label="&col.tags.label;" id="placesContentTags" anonid="tags" flex="2"
|
||||
persist="width hidden ordinal sortActive sortDirection"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol label="&col.url.label;" id="placesContentUrl" anonid="url" flex="5"
|
||||
persist="width hidden ordinal sortActive sortDirection"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol label="&col.mostrecentvisit.label;" id="placesContentDate" anonid="date" flex="1" hidden="true"
|
||||
persist="width hidden ordinal sortActive sortDirection"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol label="&col.visitcount.label;" id="placesContentVisitCount" anonid="visitCount" flex="1" hidden="true"
|
||||
persist="width hidden ordinal sortActive sortDirection"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol label="&col.description.label;" id="placesContentDescription" anonid="description" flex="1" hidden="true"
|
||||
persist="width hidden ordinal sortActive sortDirection"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol label="&col.dateadded.label;" id="placesContentDateAdded" anonid="dateAdded" flex="1" hidden="true"
|
||||
persist="width hidden ordinal sortActive sortDirection"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol label="&col.lastmodified.label;" id="placesContentLastModified" anonid="lastModified" flex="1" hidden="true"
|
||||
persist="width hidden ordinal sortActive sortDirection"/>
|
||||
</treecols>
|
||||
<treechildren flex="1" onclick="ContentTree.onClick(event);"/>
|
||||
</tree>
|
||||
</deck>
|
||||
<deck id="detailsDeck" style="height: 11em;">
|
||||
<vbox id="itemsCountBox" align="center">
|
||||
<spacer flex="3"/>
|
||||
<label id="itemsCountText"/>
|
||||
<spacer flex="1"/>
|
||||
<description id="selectItemDescription">
|
||||
&detailsPane.selectAnItemText.description;
|
||||
</description>
|
||||
<spacer flex="3"/>
|
||||
</vbox>
|
||||
<vbox id="infoBox" minimal="true">
|
||||
<vbox id="editBookmarkPanelContent" flex="1"/>
|
||||
<hbox id="infoBoxExpanderWrapper" align="center">
|
||||
|
||||
<button type="image" id="infoBoxExpander"
|
||||
class="expander-down"
|
||||
oncommand="PlacesOrganizer.toggleAdditionalInfoFields();"
|
||||
observes="paneElementsBroadcaster"/>
|
||||
|
||||
<label id="infoBoxExpanderLabel"
|
||||
lesslabel="&detailsPane.less.label;"
|
||||
lessaccesskey="&detailsPane.less.accesskey;"
|
||||
morelabel="&detailsPane.more.label;"
|
||||
moreaccesskey="&detailsPane.more.accesskey;"
|
||||
value="&detailsPane.more.label;"
|
||||
accesskey="&detailsPane.more.accesskey;"
|
||||
control="infoBoxExpander"/>
|
||||
|
||||
</hbox>
|
||||
</vbox>
|
||||
</deck>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</window>
|
||||
233
application/basilisk/components/places/content/placesOverlay.xul
Normal file
233
application/basilisk/components/places/content/placesOverlay.xul
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!DOCTYPE overlay [
|
||||
<!ENTITY % placesDTD SYSTEM "chrome://browser/locale/places/places.dtd">
|
||||
%placesDTD;
|
||||
<!ENTITY % editMenuOverlayDTD SYSTEM "chrome://global/locale/editMenuOverlay.dtd">
|
||||
%editMenuOverlayDTD;
|
||||
]>
|
||||
|
||||
<overlay id="placesOverlay"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://global/content/globalOverlay.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/utilityOverlay.js"/>
|
||||
<script type="application/javascript"><![CDATA[
|
||||
// TODO: Bug 406371.
|
||||
// A bunch of browser code depends on us defining these, sad but true :(
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cr = Components.results;
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(window,
|
||||
"PlacesUIUtils", "resource:///modules/PlacesUIUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(window,
|
||||
"PlacesTransactions", "resource://gre/modules/PlacesTransactions.jsm");
|
||||
]]></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/places/controller.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/places/treeView.js"/>
|
||||
|
||||
<!-- Bookmarks and history tooltip -->
|
||||
<tooltip id="bhTooltip" noautohide="true"
|
||||
onpopupshowing="return window.top.BookmarksEventHandler.fillInBHTooltip(document, event)">
|
||||
<vbox id="bhTooltipTextBox" flex="1">
|
||||
<label id="bhtTitleText" class="tooltip-label" />
|
||||
<label id="bhtUrlText" crop="center" class="tooltip-label" />
|
||||
</vbox>
|
||||
</tooltip>
|
||||
|
||||
<commandset id="placesCommands"
|
||||
commandupdater="true"
|
||||
events="focus,sort,places"
|
||||
oncommandupdate="goUpdatePlacesCommands();">
|
||||
<command id="placesCmd_open"
|
||||
oncommand="goDoPlacesCommand('placesCmd_open');"/>
|
||||
<command id="placesCmd_open:window"
|
||||
oncommand="goDoPlacesCommand('placesCmd_open:window');"/>
|
||||
<command id="placesCmd_open:privatewindow"
|
||||
oncommand="goDoPlacesCommand('placesCmd_open:privatewindow');"/>
|
||||
<command id="placesCmd_open:tab"
|
||||
oncommand="goDoPlacesCommand('placesCmd_open:tab');"/>
|
||||
|
||||
<command id="placesCmd_new:bookmark"
|
||||
oncommand="goDoPlacesCommand('placesCmd_new:bookmark');"/>
|
||||
<command id="placesCmd_new:folder"
|
||||
oncommand="goDoPlacesCommand('placesCmd_new:folder');"/>
|
||||
<command id="placesCmd_new:separator"
|
||||
oncommand="goDoPlacesCommand('placesCmd_new:separator');"/>
|
||||
<command id="placesCmd_show:info"
|
||||
oncommand="goDoPlacesCommand('placesCmd_show:info');"/>
|
||||
<command id="placesCmd_rename"
|
||||
oncommand="goDoPlacesCommand('placesCmd_show:info');"
|
||||
observes="placesCmd_show:info"/>
|
||||
<command id="placesCmd_reload"
|
||||
oncommand="goDoPlacesCommand('placesCmd_reload');"/>
|
||||
<command id="placesCmd_sortBy:name"
|
||||
oncommand="goDoPlacesCommand('placesCmd_sortBy:name');"/>
|
||||
<command id="placesCmd_moveBookmarks"
|
||||
oncommand="goDoPlacesCommand('placesCmd_moveBookmarks');"/>
|
||||
<command id="placesCmd_deleteDataHost"
|
||||
oncommand="goDoPlacesCommand('placesCmd_deleteDataHost');"/>
|
||||
<command id="placesCmd_createBookmark"
|
||||
oncommand="goDoPlacesCommand('placesCmd_createBookmark');"/>
|
||||
|
||||
<!-- Special versions of cut/copy/paste/delete which check for an open context menu. -->
|
||||
<command id="placesCmd_cut"
|
||||
oncommand="goDoPlacesCommand('placesCmd_cut');"/>
|
||||
<command id="placesCmd_copy"
|
||||
oncommand="goDoPlacesCommand('placesCmd_copy');"/>
|
||||
<command id="placesCmd_paste"
|
||||
oncommand="goDoPlacesCommand('placesCmd_paste');"/>
|
||||
<command id="placesCmd_delete"
|
||||
oncommand="goDoPlacesCommand('placesCmd_delete');"/>
|
||||
</commandset>
|
||||
|
||||
<menupopup id="placesContext"
|
||||
onpopupshowing="this._view = PlacesUIUtils.getViewForNode(document.popupNode);
|
||||
return this._view.buildContextMenu(this);"
|
||||
onpopuphiding="this._view.destroyContextMenu();">
|
||||
<menuitem id="placesContext_open"
|
||||
command="placesCmd_open"
|
||||
label="&cmd.open.label;"
|
||||
accesskey="&cmd.open.accesskey;"
|
||||
default="true"
|
||||
selectiontype="single"
|
||||
selection="link"/>
|
||||
<menuitem id="placesContext_open:newtab"
|
||||
command="placesCmd_open:tab"
|
||||
label="&cmd.open_tab.label;"
|
||||
accesskey="&cmd.open_tab.accesskey;"
|
||||
selectiontype="single"
|
||||
selection="link"/>
|
||||
<menuitem id="placesContext_openContainer:tabs"
|
||||
oncommand="var view = PlacesUIUtils.getViewForNode(document.popupNode);
|
||||
view.controller.openSelectionInTabs(event);"
|
||||
onclick="checkForMiddleClick(this, event);"
|
||||
label="&cmd.open_all_in_tabs.label;"
|
||||
accesskey="&cmd.open_all_in_tabs.accesskey;"
|
||||
selectiontype="single|none"
|
||||
selection="folder|host|query"/>
|
||||
<menuitem id="placesContext_openLinks:tabs"
|
||||
oncommand="var view = PlacesUIUtils.getViewForNode(document.popupNode);
|
||||
view.controller.openSelectionInTabs(event);"
|
||||
onclick="checkForMiddleClick(this, event);"
|
||||
label="&cmd.open_all_in_tabs.label;"
|
||||
accesskey="&cmd.open_all_in_tabs.accesskey;"
|
||||
selectiontype="multiple"
|
||||
selection="link"/>
|
||||
<menuitem id="placesContext_open:newwindow"
|
||||
command="placesCmd_open:window"
|
||||
label="&cmd.open_window.label;"
|
||||
accesskey="&cmd.open_window.accesskey;"
|
||||
selectiontype="single"
|
||||
selection="link"/>
|
||||
<menuitem id="placesContext_open:newprivatewindow"
|
||||
command="placesCmd_open:privatewindow"
|
||||
label="&cmd.open_private_window.label;"
|
||||
accesskey="&cmd.open_private_window.accesskey;"
|
||||
selectiontype="single"
|
||||
selection="link"
|
||||
hideifprivatebrowsing="true"/>
|
||||
<menuseparator id="placesContext_openSeparator"/>
|
||||
<menuitem id="placesContext_new:bookmark"
|
||||
command="placesCmd_new:bookmark"
|
||||
label="&cmd.new_bookmark.label;"
|
||||
accesskey="&cmd.new_bookmark.accesskey;"
|
||||
selectiontype="any"
|
||||
hideifnoinsertionpoint="true"/>
|
||||
<menuitem id="placesContext_new:folder"
|
||||
command="placesCmd_new:folder"
|
||||
label="&cmd.new_folder.label;"
|
||||
accesskey="&cmd.context_new_folder.accesskey;"
|
||||
selectiontype="any"
|
||||
hideifnoinsertionpoint="true"/>
|
||||
<menuitem id="placesContext_new:separator"
|
||||
command="placesCmd_new:separator"
|
||||
label="&cmd.new_separator.label;"
|
||||
accesskey="&cmd.new_separator.accesskey;"
|
||||
closemenu="single"
|
||||
selectiontype="any"
|
||||
hideifnoinsertionpoint="true"/>
|
||||
<menuseparator id="placesContext_newSeparator"/>
|
||||
<menuitem id="placesContext_createBookmark"
|
||||
command="placesCmd_createBookmark"
|
||||
label="&cmd.bookmarkLink.label;"
|
||||
accesskey="&cmd.bookmarkLink.accesskey;"
|
||||
selection="link"
|
||||
forcehideselection="bookmark|tagChild"/>
|
||||
<menuitem id="placesContext_cut"
|
||||
command="placesCmd_cut"
|
||||
label="&cutCmd.label;"
|
||||
accesskey="&cutCmd.accesskey;"
|
||||
closemenu="single"
|
||||
selection="bookmark|folder|separator|query"
|
||||
forcehideselection="tagChild|livemarkChild"/>
|
||||
<menuitem id="placesContext_copy"
|
||||
command="placesCmd_copy"
|
||||
label="©Cmd.label;"
|
||||
closemenu="single"
|
||||
accesskey="©Cmd.accesskey;"
|
||||
selection="any"/>
|
||||
<menuitem id="placesContext_paste"
|
||||
command="placesCmd_paste"
|
||||
label="&pasteCmd.label;"
|
||||
closemenu="single"
|
||||
accesskey="&pasteCmd.accesskey;"
|
||||
selectiontype="any"
|
||||
hideifnoinsertionpoint="true"/>
|
||||
<menuseparator id="placesContext_editSeparator"/>
|
||||
<menuitem id="placesContext_delete"
|
||||
command="placesCmd_delete"
|
||||
label="&deleteCmd.label;"
|
||||
accesskey="&deleteCmd.accesskey;"
|
||||
closemenu="single"
|
||||
selection="bookmark|tagChild|folder|query|dynamiccontainer|separator|host"/>
|
||||
<menuitem id="placesContext_delete_history"
|
||||
command="placesCmd_delete"
|
||||
label="&cmd.delete.label;"
|
||||
accesskey="&cmd.delete.accesskey;"
|
||||
closemenu="single"
|
||||
selection="link"
|
||||
forcehideselection="bookmark"/>
|
||||
<menuitem id="placesContext_deleteHost"
|
||||
command="placesCmd_deleteDataHost"
|
||||
label="&cmd.deleteDomainData.label;"
|
||||
accesskey="&cmd.deleteDomainData.accesskey;"
|
||||
closemenu="single"
|
||||
selection="link|host"
|
||||
selectiontype="single"
|
||||
hideifprivatebrowsing="true"
|
||||
forcehideselection="bookmark"/>
|
||||
<menuseparator id="placesContext_deleteSeparator"/>
|
||||
<menuitem id="placesContext_sortBy:name"
|
||||
command="placesCmd_sortBy:name"
|
||||
label="&cmd.sortby_name.label;"
|
||||
accesskey="&cmd.context_sortby_name.accesskey;"
|
||||
closemenu="single"
|
||||
selection="folder"/>
|
||||
<menuitem id="placesContext_reload"
|
||||
command="placesCmd_reload"
|
||||
label="&cmd.reloadLivebookmark.label;"
|
||||
accesskey="&cmd.reloadLivebookmark.accesskey;"
|
||||
closemenu="single"
|
||||
selection="livemark/feedURI"/>
|
||||
<menuseparator id="placesContext_sortSeparator"/>
|
||||
<menuitem id="placesContext_show:info"
|
||||
command="placesCmd_show:info"
|
||||
label="&cmd.properties.label;"
|
||||
accesskey="&cmd.properties.accesskey;"
|
||||
selection="bookmark|folder|query"
|
||||
forcehideselection="livemarkChild"/>
|
||||
</menupopup>
|
||||
|
||||
</overlay>
|
||||
106
application/basilisk/components/places/content/sidebarUtils.js
Normal file
106
application/basilisk/components/places/content/sidebarUtils.js
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
var SidebarUtils = {
|
||||
handleTreeClick: function SU_handleTreeClick(aTree, aEvent, aGutterSelect) {
|
||||
// right-clicks are not handled here
|
||||
if (aEvent.button == 2)
|
||||
return;
|
||||
|
||||
var tbo = aTree.treeBoxObject;
|
||||
var cell = tbo.getCellAt(aEvent.clientX, aEvent.clientY);
|
||||
|
||||
if (cell.row == -1 || cell.childElt == "twisty")
|
||||
return;
|
||||
|
||||
var mouseInGutter = false;
|
||||
if (aGutterSelect) {
|
||||
var rect = tbo.getCoordsForCellItem(cell.row, cell.col, "image");
|
||||
// getCoordsForCellItem returns the x coordinate in logical coordinates
|
||||
// (i.e., starting from the left and right sides in LTR and RTL modes,
|
||||
// respectively.) Therefore, we make sure to exclude the blank area
|
||||
// before the tree item icon (that is, to the left or right of it in
|
||||
// LTR and RTL modes, respectively) from the click target area.
|
||||
var isRTL = window.getComputedStyle(aTree, null).direction == "rtl";
|
||||
if (isRTL)
|
||||
mouseInGutter = aEvent.clientX > rect.x;
|
||||
else
|
||||
mouseInGutter = aEvent.clientX < rect.x;
|
||||
}
|
||||
|
||||
var metaKey = AppConstants.platform === "macosx" ? aEvent.metaKey
|
||||
: aEvent.ctrlKey;
|
||||
var modifKey = metaKey || aEvent.shiftKey;
|
||||
var isContainer = tbo.view.isContainer(cell.row);
|
||||
var openInTabs = isContainer &&
|
||||
(aEvent.button == 1 ||
|
||||
(aEvent.button == 0 && modifKey)) &&
|
||||
PlacesUtils.hasChildURIs(tbo.view.nodeForTreeIndex(cell.row));
|
||||
|
||||
if (aEvent.button == 0 && isContainer && !openInTabs) {
|
||||
tbo.view.toggleOpenState(cell.row);
|
||||
return;
|
||||
}
|
||||
else if (!mouseInGutter && openInTabs &&
|
||||
aEvent.originalTarget.localName == "treechildren") {
|
||||
tbo.view.selection.select(cell.row);
|
||||
PlacesUIUtils.openContainerNodeInTabs(aTree.selectedNode, aEvent, aTree);
|
||||
}
|
||||
else if (!mouseInGutter && !isContainer &&
|
||||
aEvent.originalTarget.localName == "treechildren") {
|
||||
// Clear all other selection since we're loading a link now. We must
|
||||
// do this *before* attempting to load the link since openURL uses
|
||||
// selection as an indication of which link to load.
|
||||
tbo.view.selection.select(cell.row);
|
||||
PlacesUIUtils.openNodeWithEvent(aTree.selectedNode, aEvent, aTree);
|
||||
}
|
||||
},
|
||||
|
||||
handleTreeKeyPress: function SU_handleTreeKeyPress(aEvent) {
|
||||
// XXX Bug 627901: Post Fx4, this method should take a tree parameter.
|
||||
let tree = aEvent.target;
|
||||
let node = tree.selectedNode;
|
||||
if (node) {
|
||||
if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN)
|
||||
PlacesUIUtils.openNodeWithEvent(node, aEvent, tree);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The following function displays the URL of a node that is being
|
||||
* hovered over.
|
||||
*/
|
||||
handleTreeMouseMove: function SU_handleTreeMouseMove(aEvent) {
|
||||
if (aEvent.target.localName != "treechildren")
|
||||
return;
|
||||
|
||||
var tree = aEvent.target.parentNode;
|
||||
var tbo = tree.treeBoxObject;
|
||||
var cell = tbo.getCellAt(aEvent.clientX, aEvent.clientY);
|
||||
|
||||
// cell.row is -1 when the mouse is hovering an empty area within the tree.
|
||||
// To avoid showing a URL from a previously hovered node for a currently
|
||||
// hovered non-url node, we must clear the moused-over URL in these cases.
|
||||
if (cell.row != -1) {
|
||||
var node = tree.view.nodeForTreeIndex(cell.row);
|
||||
if (PlacesUtils.nodeIsURI(node))
|
||||
this.setMouseoverURL(node.uri);
|
||||
else
|
||||
this.setMouseoverURL("");
|
||||
}
|
||||
else
|
||||
this.setMouseoverURL("");
|
||||
},
|
||||
|
||||
setMouseoverURL: function SU_setMouseoverURL(aURL) {
|
||||
// When the browser window is closed with an open sidebar, the sidebar
|
||||
// unload event happens after the browser's one. In this case
|
||||
// top.XULBrowserWindow has been nullified already.
|
||||
if (top.XULBrowserWindow) {
|
||||
top.XULBrowserWindow.setOverLink(aURL, null);
|
||||
}
|
||||
}
|
||||
};
|
||||
801
application/basilisk/components/places/content/tree.xml
Normal file
801
application/basilisk/components/places/content/tree.xml
Normal file
|
|
@ -0,0 +1,801 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<bindings id="placesTreeBindings"
|
||||
xmlns="http://www.mozilla.org/xbl"
|
||||
xmlns:xbl="http://www.mozilla.org/xbl"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<binding id="places-tree" extends="chrome://global/content/bindings/tree.xml#tree">
|
||||
<implementation>
|
||||
<constructor><![CDATA[
|
||||
// Force an initial build.
|
||||
if (this.place)
|
||||
this.place = this.place;
|
||||
]]></constructor>
|
||||
|
||||
<destructor><![CDATA[
|
||||
// Break the treeviewer->result->treeviewer cycle.
|
||||
// Note: unsetting the result's viewer also unsets
|
||||
// the viewer's reference to our treeBoxObject.
|
||||
var result = this.result;
|
||||
if (result) {
|
||||
result.root.containerOpen = false;
|
||||
}
|
||||
|
||||
// Unregister the controllber before unlinking the view, otherwise it
|
||||
// may still try to update commands on a view with a null result.
|
||||
if (this._controller) {
|
||||
this._controller.terminate();
|
||||
this.controllers.removeController(this._controller);
|
||||
}
|
||||
|
||||
this.view = null;
|
||||
]]></destructor>
|
||||
|
||||
<property name="controller"
|
||||
readonly="true"
|
||||
onget="return this._controller"/>
|
||||
|
||||
<!-- overriding -->
|
||||
<property name="view">
|
||||
<getter><![CDATA[
|
||||
try {
|
||||
return this.treeBoxObject.view.wrappedJSObject || null;
|
||||
}
|
||||
catch (e) {
|
||||
return null;
|
||||
}
|
||||
]]></getter>
|
||||
<setter><![CDATA[
|
||||
return this.treeBoxObject.view = val;
|
||||
]]></setter>
|
||||
</property>
|
||||
|
||||
<property name="associatedElement"
|
||||
readonly="true"
|
||||
onget="return this"/>
|
||||
|
||||
<method name="applyFilter">
|
||||
<parameter name="filterString"/>
|
||||
<parameter name="folderRestrict"/>
|
||||
<parameter name="includeHidden"/>
|
||||
<body><![CDATA[
|
||||
// preserve grouping
|
||||
var queryNode = PlacesUtils.asQuery(this.result.root);
|
||||
var options = queryNode.queryOptions.clone();
|
||||
|
||||
// Make sure we're getting uri results.
|
||||
// We do not yet support searching into grouped queries or into
|
||||
// tag containers, so we must fall to the default case.
|
||||
if (PlacesUtils.nodeIsHistoryContainer(queryNode) ||
|
||||
options.resultType == options.RESULTS_AS_TAG_QUERY ||
|
||||
options.resultType == options.RESULTS_AS_TAG_CONTENTS)
|
||||
options.resultType = options.RESULTS_AS_URI;
|
||||
|
||||
var query = PlacesUtils.history.getNewQuery();
|
||||
query.searchTerms = filterString;
|
||||
|
||||
if (folderRestrict) {
|
||||
query.setFolders(folderRestrict, folderRestrict.length);
|
||||
options.queryType = options.QUERY_TYPE_BOOKMARKS;
|
||||
}
|
||||
|
||||
options.includeHidden = !!includeHidden;
|
||||
|
||||
this.load([query], options);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="load">
|
||||
<parameter name="queries"/>
|
||||
<parameter name="options"/>
|
||||
<body><![CDATA[
|
||||
let result = PlacesUtils.history
|
||||
.executeQueries(queries, queries.length,
|
||||
options);
|
||||
let callback;
|
||||
if (this.flatList) {
|
||||
let onOpenFlatContainer = this.onOpenFlatContainer;
|
||||
if (onOpenFlatContainer)
|
||||
callback = new Function("aContainer", onOpenFlatContainer);
|
||||
}
|
||||
|
||||
if (!this._controller) {
|
||||
this._controller = new PlacesController(this);
|
||||
this.controllers.appendController(this._controller);
|
||||
}
|
||||
|
||||
let treeView = new PlacesTreeView(this.flatList, callback, this._controller);
|
||||
|
||||
// Observer removal is done within the view itself. When the tree
|
||||
// goes away, treeboxobject calls view.setTree(null), which then
|
||||
// calls removeObserver.
|
||||
result.addObserver(treeView, false);
|
||||
this.view = treeView;
|
||||
|
||||
if (this.getAttribute("selectfirstnode") == "true" && treeView.rowCount > 0) {
|
||||
treeView.selection.select(0);
|
||||
}
|
||||
|
||||
this._cachedInsertionPoint = undefined;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<property name="flatList">
|
||||
<getter><![CDATA[
|
||||
return this.getAttribute("flatList") == "true";
|
||||
]]></getter>
|
||||
<setter><![CDATA[
|
||||
if (this.flatList != val) {
|
||||
this.setAttribute("flatList", val);
|
||||
// reload with the last place set
|
||||
if (this.place)
|
||||
this.place = this.place;
|
||||
}
|
||||
return val;
|
||||
]]></setter>
|
||||
</property>
|
||||
|
||||
<property name="onOpenFlatContainer">
|
||||
<getter><![CDATA[
|
||||
return this.getAttribute("onopenflatcontainer");
|
||||
]]></getter>
|
||||
<setter><![CDATA[
|
||||
if (this.onOpenFlatContainer != val) {
|
||||
this.setAttribute("onopenflatcontainer", val);
|
||||
// reload with the last place set
|
||||
if (this.place)
|
||||
this.place = this.place;
|
||||
}
|
||||
return val;
|
||||
]]></setter>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
Causes a particular node represented by the specified placeURI to be
|
||||
selected in the tree. All containers above the node in the hierarchy
|
||||
will be opened, so that the node is visible.
|
||||
-->
|
||||
<method name="selectPlaceURI">
|
||||
<parameter name="placeURI"/>
|
||||
<body><![CDATA[
|
||||
// Do nothing if a node matching the given uri is already selected
|
||||
if (this.hasSelection && this.selectedNode.uri == placeURI)
|
||||
return;
|
||||
|
||||
function findNode(container, placeURI, nodesURIChecked) {
|
||||
var containerURI = container.uri;
|
||||
if (containerURI == placeURI)
|
||||
return container;
|
||||
if (nodesURIChecked.includes(containerURI))
|
||||
return null;
|
||||
|
||||
// never check the contents of the same query
|
||||
nodesURIChecked.push(containerURI);
|
||||
|
||||
var wasOpen = container.containerOpen;
|
||||
if (!wasOpen)
|
||||
container.containerOpen = true;
|
||||
for (var i = 0; i < container.childCount; ++i) {
|
||||
var child = container.getChild(i);
|
||||
var childURI = child.uri;
|
||||
if (childURI == placeURI)
|
||||
return child;
|
||||
else if (PlacesUtils.nodeIsContainer(child)) {
|
||||
var nested = findNode(PlacesUtils.asContainer(child), placeURI, nodesURIChecked);
|
||||
if (nested)
|
||||
return nested;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wasOpen)
|
||||
container.containerOpen = false;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var container = this.result.root;
|
||||
NS_ASSERT(container, "No result, cannot select place URI!");
|
||||
if (!container)
|
||||
return;
|
||||
|
||||
var child = findNode(container, placeURI, []);
|
||||
if (child)
|
||||
this.selectNode(child);
|
||||
else {
|
||||
// If the specified child could not be located, clear the selection
|
||||
var selection = this.view.selection;
|
||||
selection.clearSelection();
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
Causes a particular node to be selected in the tree, resulting in all
|
||||
containers above the node in the hierarchy to be opened, so that the
|
||||
node is visible.
|
||||
-->
|
||||
<method name="selectNode">
|
||||
<parameter name="node"/>
|
||||
<body><![CDATA[
|
||||
var view = this.view;
|
||||
|
||||
var parent = node.parent;
|
||||
if (parent && !parent.containerOpen) {
|
||||
// Build a list of all of the nodes that are the parent of this one
|
||||
// in the result.
|
||||
var parents = [];
|
||||
var root = this.result.root;
|
||||
while (parent && parent != root) {
|
||||
parents.push(parent);
|
||||
parent = parent.parent;
|
||||
}
|
||||
|
||||
// Walk the list backwards (opening from the root of the hierarchy)
|
||||
// opening each folder as we go.
|
||||
for (var i = parents.length - 1; i >= 0; --i) {
|
||||
let index = view.treeIndexForNode(parents[i]);
|
||||
if (index != Ci.nsINavHistoryResultTreeViewer.INDEX_INVISIBLE &&
|
||||
view.isContainer(index) && !view.isContainerOpen(index))
|
||||
view.toggleOpenState(index);
|
||||
}
|
||||
// Select the specified node...
|
||||
}
|
||||
|
||||
let index = view.treeIndexForNode(node);
|
||||
if (index == Ci.nsINavHistoryResultTreeViewer.INDEX_INVISIBLE)
|
||||
return;
|
||||
|
||||
view.selection.select(index);
|
||||
// ... and ensure it's visible, not scrolled off somewhere.
|
||||
this.treeBoxObject.ensureRowIsVisible(index);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- nsIPlacesView -->
|
||||
<property name="result">
|
||||
<getter><![CDATA[
|
||||
try {
|
||||
return this.view.QueryInterface(Ci.nsINavHistoryResultObserver).result;
|
||||
}
|
||||
catch (e) {
|
||||
return null;
|
||||
}
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<!-- nsIPlacesView -->
|
||||
<property name="place">
|
||||
<getter><![CDATA[
|
||||
return this.getAttribute("place");
|
||||
]]></getter>
|
||||
<setter><![CDATA[
|
||||
this.setAttribute("place", val);
|
||||
|
||||
var queriesRef = { };
|
||||
var queryCountRef = { };
|
||||
var optionsRef = { };
|
||||
PlacesUtils.history.queryStringToQueries(val, queriesRef, queryCountRef, optionsRef);
|
||||
if (queryCountRef.value == 0)
|
||||
queriesRef.value = [PlacesUtils.history.getNewQuery()];
|
||||
if (!optionsRef.value)
|
||||
optionsRef.value = PlacesUtils.history.getNewQueryOptions();
|
||||
|
||||
this.load(queriesRef.value, optionsRef.value);
|
||||
|
||||
return val;
|
||||
]]></setter>
|
||||
</property>
|
||||
|
||||
<!-- nsIPlacesView -->
|
||||
<property name="hasSelection">
|
||||
<getter><![CDATA[
|
||||
return this.view && this.view.selection.count >= 1;
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<!-- nsIPlacesView -->
|
||||
<property name="selectedNodes">
|
||||
<getter><![CDATA[
|
||||
let nodes = [];
|
||||
if (!this.hasSelection)
|
||||
return nodes;
|
||||
|
||||
let selection = this.view.selection;
|
||||
let rc = selection.getRangeCount();
|
||||
let resultview = this.view;
|
||||
for (let i = 0; i < rc; ++i) {
|
||||
let min = { }, max = { };
|
||||
selection.getRangeAt(i, min, max);
|
||||
for (let j = min.value; j <= max.value; ++j) {
|
||||
nodes.push(resultview.nodeForTreeIndex(j));
|
||||
}
|
||||
}
|
||||
return nodes;
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<method name="toggleCutNode">
|
||||
<parameter name="aNode"/>
|
||||
<parameter name="aValue"/>
|
||||
<body><![CDATA[
|
||||
this.view.toggleCutNode(aNode, aValue);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- nsIPlacesView -->
|
||||
<property name="removableSelectionRanges">
|
||||
<getter><![CDATA[
|
||||
// This property exists in addition to selectedNodes because it
|
||||
// encodes selection ranges (which only occur in list views) into
|
||||
// the return value. For each removed range, the index at which items
|
||||
// will be re-inserted upon the remove transaction being performed is
|
||||
// the first index of the range, so that the view updates correctly.
|
||||
//
|
||||
// For example, if we remove rows 2,3,4 and 7,8 from a list, when we
|
||||
// undo that operation, if we insert what was at row 3 at row 3 again,
|
||||
// it will show up _after_ the item that was at row 5. So we need to
|
||||
// insert all items at row 2, and the tree view will update correctly.
|
||||
//
|
||||
// Also, this function collapses the selection to remove redundant
|
||||
// data, e.g. when deleting this selection:
|
||||
//
|
||||
// http://www.foo.com/
|
||||
// (-) Some Folder
|
||||
// http://www.bar.com/
|
||||
//
|
||||
// ... returning http://www.bar.com/ as part of the selection is
|
||||
// redundant because it is implied by removing "Some Folder". We
|
||||
// filter out all such redundancies since some partial amount of
|
||||
// the folder's children may be selected.
|
||||
//
|
||||
let nodes = [];
|
||||
if (!this.hasSelection)
|
||||
return nodes;
|
||||
|
||||
var selection = this.view.selection;
|
||||
var rc = selection.getRangeCount();
|
||||
var resultview = this.view;
|
||||
// This list is kept independently of the range selected (i.e. OUTSIDE
|
||||
// the for loop) since the row index of a container is unique for the
|
||||
// entire view, and we could have some really wacky selection and we
|
||||
// don't want to blow up.
|
||||
var containers = { };
|
||||
for (var i = 0; i < rc; ++i) {
|
||||
var range = [];
|
||||
var min = { }, max = { };
|
||||
selection.getRangeAt(i, min, max);
|
||||
|
||||
for (var j = min.value; j <= max.value; ++j) {
|
||||
if (this.view.isContainer(j))
|
||||
containers[j] = true;
|
||||
if (!(this.view.getParentIndex(j) in containers))
|
||||
range.push(resultview.nodeForTreeIndex(j));
|
||||
}
|
||||
nodes.push(range);
|
||||
}
|
||||
return nodes;
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<!-- nsIPlacesView -->
|
||||
<property name="draggableSelection"
|
||||
onget="return this.selectedNodes"/>
|
||||
|
||||
<!-- nsIPlacesView -->
|
||||
<property name="selectedNode">
|
||||
<getter><![CDATA[
|
||||
var view = this.view;
|
||||
if (!view || view.selection.count != 1)
|
||||
return null;
|
||||
|
||||
var selection = view.selection;
|
||||
var min = { }, max = { };
|
||||
selection.getRangeAt(0, min, max);
|
||||
|
||||
return this.view.nodeForTreeIndex(min.value);
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<!-- nsIPlacesView -->
|
||||
<property name="insertionPoint">
|
||||
<getter><![CDATA[
|
||||
// invalidated on selection and focus changes
|
||||
if (this._cachedInsertionPoint !== undefined)
|
||||
return this._cachedInsertionPoint;
|
||||
|
||||
// there is no insertion point for history queries
|
||||
// so bail out now and save a lot of work when updating commands
|
||||
var resultNode = this.result.root;
|
||||
if (PlacesUtils.nodeIsQuery(resultNode) &&
|
||||
PlacesUtils.asQuery(resultNode).queryOptions.queryType ==
|
||||
Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY)
|
||||
return this._cachedInsertionPoint = null;
|
||||
|
||||
var orientation = Ci.nsITreeView.DROP_BEFORE;
|
||||
// If there is no selection, insert at the end of the container.
|
||||
if (!this.hasSelection) {
|
||||
var index = this.view.rowCount - 1;
|
||||
this._cachedInsertionPoint =
|
||||
this._getInsertionPoint(index, orientation);
|
||||
return this._cachedInsertionPoint;
|
||||
}
|
||||
|
||||
// This is a two-part process. The first part is determining the drop
|
||||
// orientation.
|
||||
// * The default orientation is to drop _before_ the selected item.
|
||||
// * If the selected item is a container, the default orientation
|
||||
// is to drop _into_ that container.
|
||||
//
|
||||
// Warning: It may be tempting to use tree indexes in this code, but
|
||||
// you must not, since the tree is nested and as your tree
|
||||
// index may change when folders before you are opened and
|
||||
// closed. You must convert your tree index to a node, and
|
||||
// then use getChildIndex to find your absolute index in
|
||||
// the parent container instead.
|
||||
//
|
||||
var resultView = this.view;
|
||||
var selection = resultView.selection;
|
||||
var rc = selection.getRangeCount();
|
||||
var min = { }, max = { };
|
||||
selection.getRangeAt(rc - 1, min, max);
|
||||
|
||||
// If the sole selection is a container, and we are not in
|
||||
// a flatlist, insert into it.
|
||||
// Note that this only applies to _single_ selections,
|
||||
// if the last element within a multi-selection is a
|
||||
// container, insert _adjacent_ to the selection.
|
||||
//
|
||||
// If the sole selection is the bookmarks toolbar folder, we insert
|
||||
// into it even if it is not opened
|
||||
if (selection.count == 1 && resultView.isContainer(max.value) &&
|
||||
!this.flatList)
|
||||
orientation = Ci.nsITreeView.DROP_ON;
|
||||
|
||||
this._cachedInsertionPoint =
|
||||
this._getInsertionPoint(max.value, orientation);
|
||||
return this._cachedInsertionPoint;
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<method name="_getInsertionPoint">
|
||||
<parameter name="index"/>
|
||||
<parameter name="orientation"/>
|
||||
<body><![CDATA[
|
||||
var result = this.result;
|
||||
var resultview = this.view;
|
||||
var container = result.root;
|
||||
var dropNearItemId = -1;
|
||||
NS_ASSERT(container, "null container");
|
||||
// When there's no selection, assume the container is the container
|
||||
// the view is populated from (i.e. the result's itemId).
|
||||
if (index != -1) {
|
||||
var lastSelected = resultview.nodeForTreeIndex(index);
|
||||
if (resultview.isContainer(index) && orientation == Ci.nsITreeView.DROP_ON) {
|
||||
// If the last selected item is an open container, append _into_
|
||||
// it, rather than insert adjacent to it.
|
||||
container = lastSelected;
|
||||
index = -1;
|
||||
}
|
||||
else if (lastSelected.containerOpen &&
|
||||
orientation == Ci.nsITreeView.DROP_AFTER &&
|
||||
lastSelected.hasChildren) {
|
||||
// If the last selected item is an open container and the user is
|
||||
// trying to drag into it as a first item, really insert into it.
|
||||
container = lastSelected;
|
||||
orientation = Ci.nsITreeView.DROP_ON;
|
||||
index = 0;
|
||||
}
|
||||
else {
|
||||
// Use the last-selected node's container.
|
||||
container = lastSelected.parent;
|
||||
|
||||
// See comment in the treeView.js's copy of this method
|
||||
if (!container || !container.containerOpen)
|
||||
return null;
|
||||
|
||||
// Avoid the potentially expensive call to getChildIndex
|
||||
// if we know this container doesn't allow insertion
|
||||
if (PlacesControllerDragHelper.disallowInsertion(container))
|
||||
return null;
|
||||
|
||||
var queryOptions = PlacesUtils.asQuery(result.root).queryOptions;
|
||||
if (queryOptions.sortingMode !=
|
||||
Ci.nsINavHistoryQueryOptions.SORT_BY_NONE) {
|
||||
// If we are within a sorted view, insert at the end
|
||||
index = -1;
|
||||
}
|
||||
else if (queryOptions.excludeItems ||
|
||||
queryOptions.excludeQueries ||
|
||||
queryOptions.excludeReadOnlyFolders) {
|
||||
// Some item may be invisible, insert near last selected one.
|
||||
// We don't replace index here to avoid requests to the db,
|
||||
// instead it will be calculated later by the controller.
|
||||
index = -1;
|
||||
dropNearItemId = lastSelected.itemId;
|
||||
}
|
||||
else {
|
||||
var lsi = container.getChildIndex(lastSelected);
|
||||
index = orientation == Ci.nsITreeView.DROP_BEFORE ? lsi : lsi + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PlacesControllerDragHelper.disallowInsertion(container))
|
||||
return null;
|
||||
|
||||
// TODO (Bug 1160193): properly support dropping on a tag root.
|
||||
let tagName = null;
|
||||
if (PlacesUtils.nodeIsTagQuery(container)) {
|
||||
tagName = container.title;
|
||||
if (!tagName)
|
||||
return null;
|
||||
}
|
||||
|
||||
return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
|
||||
index, orientation,
|
||||
tagName,
|
||||
dropNearItemId);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- nsIPlacesView -->
|
||||
<method name="selectAll">
|
||||
<body><![CDATA[
|
||||
this.view.selection.selectAll();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- This method will select the first node in the tree that matches
|
||||
each given item id. It will open any folder nodes that it needs
|
||||
to in order to show the selected items.
|
||||
-->
|
||||
<method name="selectItems">
|
||||
<parameter name="aIDs"/>
|
||||
<parameter name="aOpenContainers"/>
|
||||
<body><![CDATA[
|
||||
// Never open containers in flat lists.
|
||||
if (this.flatList)
|
||||
aOpenContainers = false;
|
||||
// By default, we do search and select within containers which were
|
||||
// closed (note that containers in which nodes were not found are
|
||||
// closed).
|
||||
if (aOpenContainers === undefined)
|
||||
aOpenContainers = true;
|
||||
|
||||
var ids = aIDs; // don't manipulate the caller's array
|
||||
|
||||
// Array of nodes found by findNodes which are to be selected
|
||||
var nodes = [];
|
||||
|
||||
// Array of nodes found by findNodes which should be opened
|
||||
var nodesToOpen = [];
|
||||
|
||||
// A set of GUIDs of container-nodes that were previously searched,
|
||||
// and thus shouldn't be searched again. This is empty at the initial
|
||||
// start of the recursion and gets filled in as the recursion
|
||||
// progresses.
|
||||
var checkedGuidsSet = new Set();
|
||||
|
||||
/**
|
||||
* Recursively search through a node's children for items
|
||||
* with the given IDs. When a matching item is found, remove its ID
|
||||
* from the IDs array, and add the found node to the nodes dictionary.
|
||||
*
|
||||
* NOTE: This method will leave open any node that had matching items
|
||||
* in its subtree.
|
||||
*/
|
||||
function findNodes(node) {
|
||||
var foundOne = false;
|
||||
// See if node matches an ID we wanted; add to results.
|
||||
// For simple folder queries, check both itemId and the concrete
|
||||
// item id.
|
||||
var index = ids.indexOf(node.itemId);
|
||||
if (index == -1 &&
|
||||
node.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT)
|
||||
index = ids.indexOf(PlacesUtils.asQuery(node).folderItemId);
|
||||
|
||||
if (index != -1) {
|
||||
nodes.push(node);
|
||||
foundOne = true;
|
||||
ids.splice(index, 1);
|
||||
}
|
||||
|
||||
var concreteGuid = PlacesUtils.getConcreteItemGuid(node);
|
||||
if (ids.length == 0 || !PlacesUtils.nodeIsContainer(node) ||
|
||||
checkedGuidsSet.has(concreteGuid))
|
||||
return foundOne;
|
||||
|
||||
// Only follow a query if it has been been explicitly opened by the caller.
|
||||
let shouldOpen = aOpenContainers && PlacesUtils.nodeIsFolder(node);
|
||||
PlacesUtils.asContainer(node);
|
||||
if (!node.containerOpen && !shouldOpen)
|
||||
return foundOne;
|
||||
|
||||
checkedGuidsSet.add(concreteGuid);
|
||||
|
||||
// Remember the beginning state so that we can re-close
|
||||
// this node if we don't find any additional results here.
|
||||
var previousOpenness = node.containerOpen;
|
||||
node.containerOpen = true;
|
||||
for (var child = 0; child < node.childCount && ids.length > 0;
|
||||
child++) {
|
||||
var childNode = node.getChild(child);
|
||||
var found = findNodes(childNode);
|
||||
if (!foundOne)
|
||||
foundOne = found;
|
||||
}
|
||||
|
||||
// If we didn't find any additional matches in this node's
|
||||
// subtree, revert the node to its previous openness.
|
||||
if (foundOne)
|
||||
nodesToOpen.unshift(node);
|
||||
node.containerOpen = previousOpenness;
|
||||
return foundOne;
|
||||
}
|
||||
|
||||
// Disable notifications while looking for nodes.
|
||||
let result = this.result;
|
||||
let didSuppressNotifications = result.suppressNotifications;
|
||||
if (!didSuppressNotifications)
|
||||
result.suppressNotifications = true
|
||||
try {
|
||||
findNodes(this.result.root);
|
||||
}
|
||||
finally {
|
||||
if (!didSuppressNotifications)
|
||||
result.suppressNotifications = false;
|
||||
}
|
||||
|
||||
// For all the nodes we've found, highlight the corresponding
|
||||
// index in the tree.
|
||||
var resultview = this.view;
|
||||
var selection = this.view.selection;
|
||||
selection.selectEventsSuppressed = true;
|
||||
selection.clearSelection();
|
||||
// Open nodes containing found items
|
||||
for (let i = 0; i < nodesToOpen.length; i++) {
|
||||
nodesToOpen[i].containerOpen = true;
|
||||
}
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
var index = resultview.treeIndexForNode(nodes[i]);
|
||||
if (index == Ci.nsINavHistoryResultTreeViewer.INDEX_INVISIBLE)
|
||||
continue;
|
||||
selection.rangedSelect(index, index, true);
|
||||
}
|
||||
selection.selectEventsSuppressed = false;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<field name="_contextMenuShown">false</field>
|
||||
|
||||
<method name="buildContextMenu">
|
||||
<parameter name="aPopup"/>
|
||||
<body><![CDATA[
|
||||
this._contextMenuShown = true;
|
||||
return this.controller.buildContextMenu(aPopup);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="destroyContextMenu">
|
||||
<parameter name="aPopup"/>
|
||||
this._contextMenuShown = false;
|
||||
<body/>
|
||||
</method>
|
||||
|
||||
<property name="ownerWindow"
|
||||
readonly="true"
|
||||
onget="return window;"/>
|
||||
|
||||
<field name="_active">true</field>
|
||||
<property name="active"
|
||||
onget="return this._active"
|
||||
onset="return this._active = val"/>
|
||||
|
||||
</implementation>
|
||||
<handlers>
|
||||
<handler event="focus"><![CDATA[
|
||||
this._cachedInsertionPoint = undefined;
|
||||
|
||||
// See select handler. We need the sidebar's places commandset to be
|
||||
// updated as well
|
||||
document.commandDispatcher.updateCommands("focus");
|
||||
]]></handler>
|
||||
<handler event="select"><![CDATA[
|
||||
this._cachedInsertionPoint = undefined;
|
||||
|
||||
// This additional complexity is here for the sidebars
|
||||
var win = window;
|
||||
while (true) {
|
||||
win.document.commandDispatcher.updateCommands("focus");
|
||||
if (win == window.top)
|
||||
break;
|
||||
|
||||
win = win.parent;
|
||||
}
|
||||
]]></handler>
|
||||
|
||||
<handler event="dragstart"><![CDATA[
|
||||
if (event.target.localName != "treechildren")
|
||||
return;
|
||||
|
||||
let nodes = this.selectedNodes;
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
let node = nodes[i];
|
||||
|
||||
// Disallow dragging the root node of a tree.
|
||||
if (!node.parent) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
// If this node is child of a readonly container (e.g. a livemark)
|
||||
// or cannot be moved, we must force a copy.
|
||||
if (!PlacesControllerDragHelper.canMoveNode(node)) {
|
||||
event.dataTransfer.effectAllowed = "copyLink";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this._controller.setDataTransfer(event);
|
||||
event.stopPropagation();
|
||||
]]></handler>
|
||||
|
||||
<handler event="dragover"><![CDATA[
|
||||
if (event.target.localName != "treechildren")
|
||||
return;
|
||||
|
||||
let cell = this.treeBoxObject.getCellAt(event.clientX, event.clientY);
|
||||
let node = cell.row != -1 ?
|
||||
this.view.nodeForTreeIndex(cell.row) :
|
||||
this.result.root;
|
||||
// cache the dropTarget for the view
|
||||
PlacesControllerDragHelper.currentDropTarget = node;
|
||||
|
||||
// We have to calculate the orientation since view.canDrop will use
|
||||
// it and we want to be consistent with the dropfeedback.
|
||||
let tbo = this.treeBoxObject;
|
||||
let rowHeight = tbo.rowHeight;
|
||||
let eventY = event.clientY - tbo.treeBody.boxObject.y -
|
||||
rowHeight * (cell.row - tbo.getFirstVisibleRow());
|
||||
|
||||
let orientation = Ci.nsITreeView.DROP_BEFORE;
|
||||
|
||||
if (cell.row == -1) {
|
||||
// If the row is not valid we try to insert inside the resultNode.
|
||||
orientation = Ci.nsITreeView.DROP_ON;
|
||||
}
|
||||
else if (PlacesUtils.nodeIsContainer(node) &&
|
||||
eventY > rowHeight * 0.75) {
|
||||
// If we are below the 75% of a container the treeview we try
|
||||
// to drop after the node.
|
||||
orientation = Ci.nsITreeView.DROP_AFTER;
|
||||
}
|
||||
else if (PlacesUtils.nodeIsContainer(node) &&
|
||||
eventY > rowHeight * 0.25) {
|
||||
// If we are below the 25% of a container the treeview we try
|
||||
// to drop inside the node.
|
||||
orientation = Ci.nsITreeView.DROP_ON;
|
||||
}
|
||||
|
||||
if (!this.view.canDrop(cell.row, orientation, event.dataTransfer))
|
||||
return;
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
]]></handler>
|
||||
|
||||
<handler event="dragend"><![CDATA[
|
||||
PlacesControllerDragHelper.currentDropTarget = null;
|
||||
]]></handler>
|
||||
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
</bindings>
|
||||
1728
application/basilisk/components/places/content/treeView.js
Normal file
1728
application/basilisk/components/places/content/treeView.js
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue