2014-09-30 07:09:27 -04:00
|
|
|
Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this,
|
|
|
|
'TreeStyleTabUtils', 'resource://treestyletab-modules/utils.js');
|
|
|
|
|
|
|
|
(function() {
|
2015-11-09 13:00:43 -05:00
|
|
|
let { ReferenceCounter } = Components.utils.import('resource://treestyletab-modules/ReferenceCounter.js', {});
|
2014-09-30 07:09:27 -04:00
|
|
|
let { inherit } = Components.utils.import('resource://treestyletab-modules/lib/inherit.jsm', {});
|
|
|
|
var TreeStyleTabBookmarksServiceEditable = inherit(TreeStyleTabBookmarksService, {
|
|
|
|
|
|
|
|
instantApply : false,
|
|
|
|
canceled : false,
|
|
|
|
|
|
|
|
get parentRow()
|
|
|
|
{
|
|
|
|
return document.getElementById('treestyletab-parent-row');
|
|
|
|
},
|
|
|
|
|
|
|
|
get menulist()
|
|
|
|
{
|
|
|
|
return document.getElementById('treestyletab-parent-menulist');
|
|
|
|
},
|
|
|
|
get popup()
|
|
|
|
{
|
|
|
|
return document.getElementById('treestyletab-parent-popup');
|
|
|
|
},
|
|
|
|
|
|
|
|
get separator()
|
|
|
|
{
|
|
|
|
return document.getElementById('treestyletab-parent-blank-item-separator');
|
|
|
|
},
|
|
|
|
get blankItem()
|
|
|
|
{
|
|
|
|
return document.getElementById('treestyletab-parent-blank-item');
|
|
|
|
},
|
|
|
|
|
|
|
|
get isCreatingMultipleBookmarksInFolder()
|
|
|
|
{
|
|
|
|
return (
|
|
|
|
window.arguments.length &&
|
|
|
|
window.arguments[0] &&
|
|
|
|
window.arguments[0].type == 'folder'
|
|
|
|
);
|
|
|
|
},
|
|
|
|
|
|
|
|
init : function TSTBMEditable_init()
|
|
|
|
{
|
|
|
|
if (this.isCreatingMultipleBookmarksInFolder) return;
|
|
|
|
|
|
|
|
// main browser window
|
|
|
|
if ('StarUI' in window) {
|
Replace functions entirely instead of partial patching.
This should fix #887 partially. However, when I click the star button twice, there still be another error like:
~~~
treestyletab: doPatching: gEditItemOverlay._showHideRows is missing! utils.js:319:0
treestyletab: Failed to patch to gEditItemOverlay.initPanel: function initPanel(aInfo) {
if (typeof(aInfo) != "object" || aInfo === null)
throw new Error("aInfo must be an object.");
// For sanity ensure that the implementer has uninited the panel before
// trying to init it again, or we could end up leaking due to observers.
if (this.initialized)
this.uninitPanel(false);
let { itemId, itemGuid, isItem,
isURI, uri, title,
isBookmark, bulkTagging, uris,
visibleRows } = this._setPaneInfo(aInfo);
let showOrCollapse =
(rowId, isAppropriateForInput, nameInHiddenRows = null) => {
let visible = isAppropriateForInput;
if (visible && "hiddenRows" in aInfo && nameInHiddenRows)
visible &= aInfo.hiddenRows.indexOf(nameInHiddenRows) == -1;
if (visible)
visibleRows.add(rowId);
return !(this._element(rowId).collapsed = !visible);
};
if (showOrCollapse("nameRow", !bulkTagging, "name")) {
this._initNamePicker();
this._namePicker.readOnly = this.readOnly;
}
// In some cases we want to hide the location field, since it's not
// human-readable, but we still want to initialize it.
showOrCollapse("locationRow", isURI, "location");
if (isURI) {
this._initLocationField();
this._locationField.readOnly = this.readOnly;
}
// hide the description field for
if (showOrCollapse("descriptionRow", isItem && !this.readOnly,
"description")) {
this._initDescriptionField();
this._descriptionField.readOnly = this.readOnly;
}
if (showOrCollapse("keywordRow", isBookmark, "keyword")) {
this._initKeywordField();
this._keywordField.readOnly = this.readOnly;
}
// Collapse the tag selector if the item does not accept tags.
if (showOrCollapse("tagsRow", isURI || bulkTagging, "tags"))
this._initTagsField().catch(Components.utils.reportError);
else if (!this._element("tagsSelectorRow").collapsed)
this.toggleTagsSelector().catch(Components.utils.reportError);
// Load in sidebar.
if (showOrCollapse("loadInSidebarCheckbox", isBookmark, "loadInSidebar")) {
this._initLoadInSidebar();
}
// Folder picker.
// Technically we should check that the item is not moveable, but that's
// not cheap (we don't always have the parent), and there's no use case for
// this (it's only the Star UI that shows the folderPicker)
if (showOrCollapse("folderRow", isItem, "folderPicker")) {
let containerId = PlacesUtils.bookmarks.getFolderIdForItem(itemId);
this._initFolderMenuList(containerId);
}
// Selection count.
if (showOrCollapse("selectionCount", bulkTagging)) {
this._element("itemsCountText").value =
PlacesUIUtils.getPluralString("detailsPane.itemsCountLabel",
uris.length,
[uris.length]);
}
// Observe changes.
if (!this._observersAdded) {
PlacesUtils.bookmarks.addObserver(this, false);
window.addEventListener("unload", this, false);
this._observersAdded = true;
}
}
~~~
2015-08-18 11:25:47 -04:00
|
|
|
StarUI.__treestyletab___doShowEditBookmarkPanel = StarUI.__treestyletab___doShowEditBookmarkPanel || StarUI._doShowEditBookmarkPanel;
|
|
|
|
StarUI._doShowEditBookmarkPanel = function(...args) {
|
|
|
|
TreeStyleTabBookmarksServiceEditable.initEditUI();
|
|
|
|
return this.__treestyletab___doShowEditBookmarkPanel.apply(this, args);
|
|
|
|
};
|
2014-11-12 12:13:23 -05:00
|
|
|
|
Replace functions entirely instead of partial patching.
This should fix #887 partially. However, when I click the star button twice, there still be another error like:
~~~
treestyletab: doPatching: gEditItemOverlay._showHideRows is missing! utils.js:319:0
treestyletab: Failed to patch to gEditItemOverlay.initPanel: function initPanel(aInfo) {
if (typeof(aInfo) != "object" || aInfo === null)
throw new Error("aInfo must be an object.");
// For sanity ensure that the implementer has uninited the panel before
// trying to init it again, or we could end up leaking due to observers.
if (this.initialized)
this.uninitPanel(false);
let { itemId, itemGuid, isItem,
isURI, uri, title,
isBookmark, bulkTagging, uris,
visibleRows } = this._setPaneInfo(aInfo);
let showOrCollapse =
(rowId, isAppropriateForInput, nameInHiddenRows = null) => {
let visible = isAppropriateForInput;
if (visible && "hiddenRows" in aInfo && nameInHiddenRows)
visible &= aInfo.hiddenRows.indexOf(nameInHiddenRows) == -1;
if (visible)
visibleRows.add(rowId);
return !(this._element(rowId).collapsed = !visible);
};
if (showOrCollapse("nameRow", !bulkTagging, "name")) {
this._initNamePicker();
this._namePicker.readOnly = this.readOnly;
}
// In some cases we want to hide the location field, since it's not
// human-readable, but we still want to initialize it.
showOrCollapse("locationRow", isURI, "location");
if (isURI) {
this._initLocationField();
this._locationField.readOnly = this.readOnly;
}
// hide the description field for
if (showOrCollapse("descriptionRow", isItem && !this.readOnly,
"description")) {
this._initDescriptionField();
this._descriptionField.readOnly = this.readOnly;
}
if (showOrCollapse("keywordRow", isBookmark, "keyword")) {
this._initKeywordField();
this._keywordField.readOnly = this.readOnly;
}
// Collapse the tag selector if the item does not accept tags.
if (showOrCollapse("tagsRow", isURI || bulkTagging, "tags"))
this._initTagsField().catch(Components.utils.reportError);
else if (!this._element("tagsSelectorRow").collapsed)
this.toggleTagsSelector().catch(Components.utils.reportError);
// Load in sidebar.
if (showOrCollapse("loadInSidebarCheckbox", isBookmark, "loadInSidebar")) {
this._initLoadInSidebar();
}
// Folder picker.
// Technically we should check that the item is not moveable, but that's
// not cheap (we don't always have the parent), and there's no use case for
// this (it's only the Star UI that shows the folderPicker)
if (showOrCollapse("folderRow", isItem, "folderPicker")) {
let containerId = PlacesUtils.bookmarks.getFolderIdForItem(itemId);
this._initFolderMenuList(containerId);
}
// Selection count.
if (showOrCollapse("selectionCount", bulkTagging)) {
this._element("itemsCountText").value =
PlacesUIUtils.getPluralString("detailsPane.itemsCountLabel",
uris.length,
[uris.length]);
}
// Observe changes.
if (!this._observersAdded) {
PlacesUtils.bookmarks.addObserver(this, false);
window.addEventListener("unload", this, false);
this._observersAdded = true;
}
}
~~~
2015-08-18 11:25:47 -04:00
|
|
|
StarUI.__treestyletab__quitEditMode = StarUI.__treestyletab__quitEditMode || StarUI.quitEditMode;
|
|
|
|
StarUI.quitEditMode = function(...args) {
|
2015-08-18 11:27:45 -04:00
|
|
|
TreeStyleTabBookmarksServiceEditable.saveParentFor(this._itemId);
|
Replace functions entirely instead of partial patching.
This should fix #887 partially. However, when I click the star button twice, there still be another error like:
~~~
treestyletab: doPatching: gEditItemOverlay._showHideRows is missing! utils.js:319:0
treestyletab: Failed to patch to gEditItemOverlay.initPanel: function initPanel(aInfo) {
if (typeof(aInfo) != "object" || aInfo === null)
throw new Error("aInfo must be an object.");
// For sanity ensure that the implementer has uninited the panel before
// trying to init it again, or we could end up leaking due to observers.
if (this.initialized)
this.uninitPanel(false);
let { itemId, itemGuid, isItem,
isURI, uri, title,
isBookmark, bulkTagging, uris,
visibleRows } = this._setPaneInfo(aInfo);
let showOrCollapse =
(rowId, isAppropriateForInput, nameInHiddenRows = null) => {
let visible = isAppropriateForInput;
if (visible && "hiddenRows" in aInfo && nameInHiddenRows)
visible &= aInfo.hiddenRows.indexOf(nameInHiddenRows) == -1;
if (visible)
visibleRows.add(rowId);
return !(this._element(rowId).collapsed = !visible);
};
if (showOrCollapse("nameRow", !bulkTagging, "name")) {
this._initNamePicker();
this._namePicker.readOnly = this.readOnly;
}
// In some cases we want to hide the location field, since it's not
// human-readable, but we still want to initialize it.
showOrCollapse("locationRow", isURI, "location");
if (isURI) {
this._initLocationField();
this._locationField.readOnly = this.readOnly;
}
// hide the description field for
if (showOrCollapse("descriptionRow", isItem && !this.readOnly,
"description")) {
this._initDescriptionField();
this._descriptionField.readOnly = this.readOnly;
}
if (showOrCollapse("keywordRow", isBookmark, "keyword")) {
this._initKeywordField();
this._keywordField.readOnly = this.readOnly;
}
// Collapse the tag selector if the item does not accept tags.
if (showOrCollapse("tagsRow", isURI || bulkTagging, "tags"))
this._initTagsField().catch(Components.utils.reportError);
else if (!this._element("tagsSelectorRow").collapsed)
this.toggleTagsSelector().catch(Components.utils.reportError);
// Load in sidebar.
if (showOrCollapse("loadInSidebarCheckbox", isBookmark, "loadInSidebar")) {
this._initLoadInSidebar();
}
// Folder picker.
// Technically we should check that the item is not moveable, but that's
// not cheap (we don't always have the parent), and there's no use case for
// this (it's only the Star UI that shows the folderPicker)
if (showOrCollapse("folderRow", isItem, "folderPicker")) {
let containerId = PlacesUtils.bookmarks.getFolderIdForItem(itemId);
this._initFolderMenuList(containerId);
}
// Selection count.
if (showOrCollapse("selectionCount", bulkTagging)) {
this._element("itemsCountText").value =
PlacesUIUtils.getPluralString("detailsPane.itemsCountLabel",
uris.length,
[uris.length]);
}
// Observe changes.
if (!this._observersAdded) {
PlacesUtils.bookmarks.addObserver(this, false);
window.addEventListener("unload", this, false);
this._observersAdded = true;
}
}
~~~
2015-08-18 11:25:47 -04:00
|
|
|
return this.__treestyletab__quitEditMode.apply(this, args);
|
|
|
|
};
|
2014-11-12 12:13:23 -05:00
|
|
|
|
Replace functions entirely instead of partial patching.
This should fix #887 partially. However, when I click the star button twice, there still be another error like:
~~~
treestyletab: doPatching: gEditItemOverlay._showHideRows is missing! utils.js:319:0
treestyletab: Failed to patch to gEditItemOverlay.initPanel: function initPanel(aInfo) {
if (typeof(aInfo) != "object" || aInfo === null)
throw new Error("aInfo must be an object.");
// For sanity ensure that the implementer has uninited the panel before
// trying to init it again, or we could end up leaking due to observers.
if (this.initialized)
this.uninitPanel(false);
let { itemId, itemGuid, isItem,
isURI, uri, title,
isBookmark, bulkTagging, uris,
visibleRows } = this._setPaneInfo(aInfo);
let showOrCollapse =
(rowId, isAppropriateForInput, nameInHiddenRows = null) => {
let visible = isAppropriateForInput;
if (visible && "hiddenRows" in aInfo && nameInHiddenRows)
visible &= aInfo.hiddenRows.indexOf(nameInHiddenRows) == -1;
if (visible)
visibleRows.add(rowId);
return !(this._element(rowId).collapsed = !visible);
};
if (showOrCollapse("nameRow", !bulkTagging, "name")) {
this._initNamePicker();
this._namePicker.readOnly = this.readOnly;
}
// In some cases we want to hide the location field, since it's not
// human-readable, but we still want to initialize it.
showOrCollapse("locationRow", isURI, "location");
if (isURI) {
this._initLocationField();
this._locationField.readOnly = this.readOnly;
}
// hide the description field for
if (showOrCollapse("descriptionRow", isItem && !this.readOnly,
"description")) {
this._initDescriptionField();
this._descriptionField.readOnly = this.readOnly;
}
if (showOrCollapse("keywordRow", isBookmark, "keyword")) {
this._initKeywordField();
this._keywordField.readOnly = this.readOnly;
}
// Collapse the tag selector if the item does not accept tags.
if (showOrCollapse("tagsRow", isURI || bulkTagging, "tags"))
this._initTagsField().catch(Components.utils.reportError);
else if (!this._element("tagsSelectorRow").collapsed)
this.toggleTagsSelector().catch(Components.utils.reportError);
// Load in sidebar.
if (showOrCollapse("loadInSidebarCheckbox", isBookmark, "loadInSidebar")) {
this._initLoadInSidebar();
}
// Folder picker.
// Technically we should check that the item is not moveable, but that's
// not cheap (we don't always have the parent), and there's no use case for
// this (it's only the Star UI that shows the folderPicker)
if (showOrCollapse("folderRow", isItem, "folderPicker")) {
let containerId = PlacesUtils.bookmarks.getFolderIdForItem(itemId);
this._initFolderMenuList(containerId);
}
// Selection count.
if (showOrCollapse("selectionCount", bulkTagging)) {
this._element("itemsCountText").value =
PlacesUIUtils.getPluralString("detailsPane.itemsCountLabel",
uris.length,
[uris.length]);
}
// Observe changes.
if (!this._observersAdded) {
PlacesUtils.bookmarks.addObserver(this, false);
window.addEventListener("unload", this, false);
this._observersAdded = true;
}
}
~~~
2015-08-18 11:25:47 -04:00
|
|
|
StarUI.__treestyletab__cancelButtonOnCommand = StarUI.__treestyletab__cancelButtonOnCommand || StarUI.cancelButtonOnCommand;
|
|
|
|
StarUI.cancelButtonOnCommand = function(...args) {
|
|
|
|
TreeStyleTabBookmarksServiceEditable.canceled = true;
|
|
|
|
return this.__treestyletab__cancelButtonOnCommand.apply(this, args);
|
|
|
|
};
|
2014-09-30 07:09:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Bookmarks Property dialog
|
|
|
|
if ('BookmarkPropertiesPanel' in window) {
|
2014-11-12 12:13:23 -05:00
|
|
|
TreeStyleTabUtils.doPatching(BookmarkPropertiesPanel._endBatch, 'BookmarkPropertiesPanel._endBatch', function(aName, aSource) {
|
|
|
|
return eval(aName+' = '+aSource.replace(
|
|
|
|
/(PlacesUtils\.transactionManager\.endBatch\([^)]*\);)/,
|
2014-11-12 12:25:05 -05:00
|
|
|
'$1 TreeStyleTabBookmarksServiceEditable.saveParentFor(this._itemId, true);'
|
2014-11-12 12:13:23 -05:00
|
|
|
));
|
|
|
|
}, 'TreeStyleTab');
|
2014-09-30 07:09:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Places Organizer (Library)
|
|
|
|
if ('PlacesOrganizer' in window) {
|
|
|
|
this.instantApply = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.initEditUI();
|
|
|
|
},
|
|
|
|
|
|
|
|
initEditUI : function TSTBMEditable_initEditUI()
|
|
|
|
{
|
|
|
|
if (
|
|
|
|
this.editUIInitialized ||
|
|
|
|
!('gEditItemOverlay' in window) ||
|
|
|
|
this.isCreatingMultipleBookmarksInFolder
|
|
|
|
)
|
|
|
|
return;
|
|
|
|
|
|
|
|
var container = document.getElementById('editBookmarkPanelGrid');
|
|
|
|
if (!container) return;
|
|
|
|
|
|
|
|
container = container.getElementsByTagName('rows')[0];
|
|
|
|
var range = document.createRange();
|
|
|
|
range.selectNodeContents(container);
|
|
|
|
range.collapse(false);
|
|
|
|
range.insertNode(range.createContextualFragment(
|
|
|
|
('<row align="center" id="treestyletab-parent-row">' +
|
|
|
|
' <label id="treestyletab-parent-label"' +
|
|
|
|
' control="treestyletab-parent-menulist"/>' +
|
|
|
|
' <menulist id="treestyletab-parent-menulist"' +
|
|
|
|
' flex="1"' +
|
|
|
|
' oncommand="TreeStyleTabBookmarksServiceEditable.onParentChange();">' +
|
|
|
|
' <menupopup id="treestyletab-parent-popup">' +
|
|
|
|
' <menuseparator id="treestyletab-parent-blank-item-separator"/>' +
|
|
|
|
' <menuitem id="treestyletab-parent-blank-item"' +
|
|
|
|
' value=""/>' +
|
|
|
|
' </menupopup>' +
|
|
|
|
' </menulist>' +
|
|
|
|
'</row>').trim().replace(/>\s+</g, '><')));
|
|
|
|
range.detach();
|
|
|
|
document.getElementById('treestyletab-parent-label').setAttribute('value', TreeStyleTabUtils.treeBundle.getString('bookmarkProperty.parent.label'));
|
|
|
|
this.blankItem.setAttribute('label', TreeStyleTabUtils.treeBundle.getString('bookmarkProperty.parent.blank.label'));
|
|
|
|
|
2015-08-18 11:59:16 -04:00
|
|
|
if (Services.vc.compare(Services.appinfo.platformVersion, '40') >= 0) {
|
2015-08-18 12:03:01 -04:00
|
|
|
// for Firefox 40 and later, after Bug 951651
|
|
|
|
TreeStyleTabUtils.doPatching(gEditItemOverlay.initPanel, 'gEditItemOverlay.initPanel', function(aName, aSource) {
|
|
|
|
return eval(aName+' = '+aSource.replace(
|
2015-08-18 12:12:07 -04:00
|
|
|
/(\}\)?)$/,
|
|
|
|
' TreeStyleTabBookmarksServiceEditable.parentRow.collapsed = this._element("keywordRow").collapsed && this._element("folderRow").collapsed;\n' +
|
2015-08-18 12:24:54 -04:00
|
|
|
' if (!TreeStyleTabBookmarksServiceEditable.parentRow.collapsed)\n' +
|
|
|
|
' TreeStyleTabBookmarksServiceEditable.initParentMenuList();\n' +
|
2015-08-18 12:12:07 -04:00
|
|
|
'$1'
|
2015-08-18 12:03:01 -04:00
|
|
|
));
|
|
|
|
}, 'TreeStyleTab');
|
2015-08-18 11:59:16 -04:00
|
|
|
}
|
|
|
|
else {
|
2015-08-18 12:03:01 -04:00
|
|
|
// for Firefox 39 and olders
|
|
|
|
TreeStyleTabUtils.doPatching(gEditItemOverlay.initPanel, 'gEditItemOverlay.initPanel', function(aName, aSource) {
|
|
|
|
return eval(aName+' = '+aSource.replace(
|
|
|
|
'if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK) {',
|
|
|
|
'$& TreeStyleTabBookmarksServiceEditable.initParentMenuList();'
|
|
|
|
));
|
|
|
|
}, 'TreeStyleTab');
|
2015-08-18 12:12:07 -04:00
|
|
|
|
|
|
|
TreeStyleTabUtils.doPatching(gEditItemOverlay._showHideRows, 'gEditItemOverlay._showHideRows', function(aName, aSource) {
|
|
|
|
return eval(aName+' = '+aSource.replace(
|
|
|
|
/(\}\)?)$/,
|
|
|
|
' TreeStyleTabBookmarksServiceEditable.parentRow.collapsed = this._element("keywordRow").collapsed && this._element("folderRow").collapsed;\n' +
|
|
|
|
'$1'
|
|
|
|
));
|
|
|
|
}, 'TreeStyleTab');
|
2015-08-18 11:59:16 -04:00
|
|
|
}
|
2014-09-30 07:09:27 -04:00
|
|
|
|
2014-11-12 12:13:23 -05:00
|
|
|
TreeStyleTabUtils.doPatching(gEditItemOverlay.onItemMoved, 'gEditItemOverlay.onItemMoved', function(aName, aSource) {
|
|
|
|
return eval(aName+' = '+aSource.replace(
|
|
|
|
'{',
|
|
|
|
'$& if (aNewParent == this._getFolderIdFromMenuList()) TreeStyleTabBookmarksServiceEditable.initParentMenuList();'
|
|
|
|
));
|
|
|
|
}, 'TreeStyleTab');
|
2014-09-30 07:09:27 -04:00
|
|
|
|
|
|
|
this.editUIInitialized = true;
|
|
|
|
},
|
|
|
|
editUIInitialized : false,
|
|
|
|
|
|
|
|
initParentMenuList : function TSTBMEditable_initParentMenuList()
|
|
|
|
{
|
|
|
|
var id = gEditItemOverlay.itemId;
|
|
|
|
|
|
|
|
this.menulist.disabled = true;
|
|
|
|
this.menulist.setAttribute('label', '...');
|
|
|
|
|
|
|
|
var popup = this.popup;
|
|
|
|
var range = document.createRange();
|
|
|
|
range.selectNodeContents(popup);
|
|
|
|
range.setEndBefore(this.separator);
|
|
|
|
range.deleteContents();
|
|
|
|
range.detach();
|
|
|
|
|
|
|
|
this.canceled = false;
|
|
|
|
|
|
|
|
// Ignore bookmark in the "unsorted bookmarks" folder, because
|
|
|
|
// there can be very large number of bookmarks and they won't be
|
|
|
|
// opened as a tree.
|
|
|
|
if (PlacesUtils.bookmarks.getFolderIdForItem(id) == PlacesUtils.unfiledBookmarksFolderId)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._createSiblingsFragment(id, (function(aSiblingsFragment) {
|
|
|
|
var range = document.createRange();
|
|
|
|
range.selectNodeContents(popup);
|
|
|
|
range.setEndBefore(this.separator);
|
|
|
|
range.insertNode(aSiblingsFragment);
|
|
|
|
range.detach();
|
|
|
|
|
|
|
|
var selected = popup.getElementsByAttribute('selected', 'true')[0];
|
|
|
|
this.menulist.disabled = false;
|
|
|
|
this.menulist.value = (selected || this.blankItem).getAttribute('value');
|
|
|
|
}).bind(this))
|
|
|
|
},
|
|
|
|
_doProgressively : function TSTBMEditable__doProgressively(aParams)
|
|
|
|
{
|
|
|
|
var name = aParams.name;
|
|
|
|
if (this._doProgressivelyTimers[name])
|
|
|
|
window.clearTimeout(this._doProgressivelyTimers[name]);
|
|
|
|
|
|
|
|
var interval = 100;
|
|
|
|
var step = 10;
|
|
|
|
var progressiveIteration = (function() {
|
|
|
|
try {
|
2014-11-12 12:25:05 -05:00
|
|
|
if (aParams.justNow) {
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
aParams.onProgress();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (let i = 0; i < step; i++)
|
|
|
|
{
|
|
|
|
aParams.onProgress();
|
|
|
|
}
|
|
|
|
this._doProgressivelyTimers[name] = window.setTimeout(progressiveIteration, interval);
|
2014-09-30 07:09:27 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(e if e instanceof StopIteration) {
|
|
|
|
aParams.onComplete();
|
|
|
|
}
|
|
|
|
catch(e) {
|
|
|
|
Components.utils.reportError(e);
|
|
|
|
}
|
|
|
|
finally {
|
|
|
|
this._doProgressivelyTimers[name] = null;
|
|
|
|
}
|
|
|
|
}).bind(this);
|
2014-11-12 12:25:05 -05:00
|
|
|
|
|
|
|
if (aParams.justNow)
|
|
|
|
progressiveIteration();
|
|
|
|
else
|
|
|
|
this._doProgressivelyTimers[name] = window.setTimeout(progressiveIteration, interval);
|
2014-09-30 07:09:27 -04:00
|
|
|
},
|
|
|
|
_doProgressivelyTimers : {},
|
|
|
|
_createSiblingsFragment : function TSTBMEditable__createSiblingsFragment(aCurrentItem, aCallback)
|
|
|
|
{
|
|
|
|
var itemsIterator = this._getSiblingItemsIterator(aCurrentItem);
|
|
|
|
var items = [];
|
|
|
|
this._doProgressively({
|
|
|
|
name : '_createSiblingsFragment',
|
|
|
|
onProgress : function() {
|
|
|
|
items.push(itemsIterator.next());
|
|
|
|
},
|
|
|
|
onComplete : (function() {
|
|
|
|
this._createSiblingsFragmentInternal(aCurrentItem, items, function(aSiblingsFragment) {
|
|
|
|
aCallback(aSiblingsFragment);
|
|
|
|
});
|
|
|
|
}).bind(this)
|
|
|
|
});
|
|
|
|
},
|
|
|
|
_createSiblingsFragmentInternal : function TSTBMEditable_createSiblingsFragmentInternal(aCurrentItem, aItems, aCallback)
|
|
|
|
{
|
|
|
|
var treeStructure = this.getTreeStructureFromItems(aItems);
|
|
|
|
|
|
|
|
var currentIndex = aItems.indexOf(aCurrentItem);
|
|
|
|
var selected = treeStructure[currentIndex];
|
|
|
|
if (selected > -1) {
|
|
|
|
let offset = treeStructure.lastIndexOf(-1, currentIndex);
|
|
|
|
let subStructure = treeStructure.slice(offset);
|
|
|
|
selected = aItems[selected + offset];
|
|
|
|
}
|
|
|
|
|
|
|
|
var fragment = document.createDocumentFragment();
|
|
|
|
|
|
|
|
var itemsIterator = Iterator(aItems);
|
|
|
|
this._doProgressively({
|
|
|
|
name : '_createSiblingsFragment',
|
|
|
|
onProgress : (function() {
|
|
|
|
let [index, id] = itemsIterator.next();
|
|
|
|
|
|
|
|
let label = PlacesUtils.bookmarks.getItemTitle(id);
|
|
|
|
let menuitem = document.createElement('menuitem');
|
|
|
|
menuitem.setAttribute('value', id);
|
|
|
|
|
|
|
|
let parent = index;
|
|
|
|
let nest = 0;
|
|
|
|
let disabled = false;
|
|
|
|
while ((parent = treeStructure[parent]) != -1)
|
|
|
|
{
|
|
|
|
nest++;
|
|
|
|
if (parent == currentIndex) disabled = true;
|
|
|
|
}
|
|
|
|
if (nest)
|
|
|
|
menuitem.setAttribute('style', 'padding-left:'+nest+'em');
|
|
|
|
|
|
|
|
if (disabled || id == aCurrentItem) {
|
|
|
|
menuitem.setAttribute('disabled', true);
|
|
|
|
if (id == aCurrentItem)
|
|
|
|
label = TreeStyleTabUtils.treeBundle.getFormattedString('bookmarkProperty.parent.current.label', [label]);
|
|
|
|
}
|
|
|
|
if (id == selected)
|
|
|
|
menuitem.setAttribute('selected', true);
|
|
|
|
|
|
|
|
menuitem.setAttribute('label', label);
|
|
|
|
|
|
|
|
fragment.appendChild(menuitem);
|
|
|
|
}).bind(this),
|
|
|
|
onComplete : function() {
|
|
|
|
aCallback(fragment);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
_getItemsInFolderIterator : function TSTBMEditable_getItemsInFolderIterator(aId)
|
|
|
|
{
|
|
|
|
var count = 0;
|
|
|
|
var item;
|
|
|
|
try {
|
|
|
|
while((item = PlacesUtils.bookmarks.getIdForItemAt(aId, count++)) != -1)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
let uri = PlacesUtils.bookmarks.getBookmarkURI(item);
|
|
|
|
if (uri.spec.indexOf('place:') != 0)
|
|
|
|
yield item;
|
|
|
|
}
|
|
|
|
catch(e) {
|
|
|
|
// this is not a normal bookmark.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(e) {
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_getSiblingItemsIterator : function TSTBMEditable_getSiblingItemsIterator(aId)
|
|
|
|
{
|
|
|
|
return this._getItemsInFolderIterator(PlacesUtils.bookmarks.getFolderIdForItem(aId));
|
|
|
|
},
|
|
|
|
|
2014-11-12 12:25:05 -05:00
|
|
|
saveParentFor : function TSTBMEditable_saveParentFor(aId, aJustNow)
|
2014-09-30 07:09:27 -04:00
|
|
|
{
|
|
|
|
var newParentId = parseInt(this.menulist.value || -1);
|
|
|
|
if (this.canceled || newParentId == this.getParentItem(aId)) return;
|
|
|
|
|
|
|
|
var itemsIterator = this._getSiblingItemsIterator(aId);
|
|
|
|
var items = [];
|
|
|
|
this._doProgressively({
|
|
|
|
name : '_createSiblingsFragment',
|
|
|
|
onProgress : function() {
|
|
|
|
items.push(itemsIterator.next());
|
|
|
|
},
|
|
|
|
onComplete : (function() {
|
|
|
|
this._saveParentForInternal(aId, newParentId, items);
|
2014-11-12 12:25:05 -05:00
|
|
|
}).bind(this),
|
|
|
|
justNow : aJustNow
|
2014-09-30 07:09:27 -04:00
|
|
|
});
|
|
|
|
},
|
|
|
|
_saveParentForInternal : function TSTBMEditable_saveParentForInternal(aId, aNewParentId, aItems)
|
|
|
|
{
|
|
|
|
var treeStructure = this.getTreeStructureFromItems(aItems);
|
|
|
|
|
|
|
|
var parentIndex = aItems.indexOf(aNewParentId);
|
|
|
|
var newIndex;
|
|
|
|
if (TreeStyleTabUtils.getTreePref('insertNewChildAt') == this.kINSERT_FISRT) {
|
|
|
|
newIndex = treeStructure.indexOf(parentIndex);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
do {
|
|
|
|
newIndex = parentIndex;
|
|
|
|
parentIndex = treeStructure.lastIndexOf(parentIndex);
|
|
|
|
}
|
|
|
|
while (parentIndex > -1);
|
|
|
|
newIndex++;
|
|
|
|
}
|
|
|
|
|
|
|
|
PlacesUtils.setAnnotationsForItem(aId, [{
|
|
|
|
name : this.kPARENT,
|
|
|
|
value : aNewParentId,
|
|
|
|
expires : PlacesUtils.annotations.EXPIRE_NEVER
|
|
|
|
}]);
|
|
|
|
|
|
|
|
PlacesUtils.bookmarks.moveItem(aId, PlacesUtils.bookmarks.getFolderIdForItem(aId), newIndex);
|
|
|
|
|
|
|
|
if (this.instantApply) this.initParentMenuList();
|
|
|
|
},
|
|
|
|
|
|
|
|
onParentChange : function TSTBMEditable_onParentChange()
|
|
|
|
{
|
|
|
|
if (!this.instantApply) return;
|
|
|
|
this.saveParentFor(gEditItemOverlay.itemId);
|
|
|
|
},
|
|
|
|
|
|
|
|
handleEvent : function TSTBMEditable_handleEvent(aEvent)
|
|
|
|
{
|
|
|
|
switch (aEvent.type)
|
|
|
|
{
|
|
|
|
case 'DOMContentLoaded':
|
|
|
|
window.removeEventListener('DOMContentLoaded', this, false);
|
2015-11-09 13:00:43 -05:00
|
|
|
ReferenceCounter.remove('window,DOMContentLoaded,TreeStyleTabBookmarksServiceEditable,false');
|
2014-09-30 07:09:27 -04:00
|
|
|
this.init();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
window.addEventListener('DOMContentLoaded', TreeStyleTabBookmarksServiceEditable, false);
|
2015-11-09 13:00:43 -05:00
|
|
|
ReferenceCounter.add('window,DOMContentLoaded,TreeStyleTabBookmarksServiceEditable,false');
|
2014-09-30 07:09:27 -04:00
|
|
|
|
|
|
|
window.TreeStyleTabBookmarksServiceEditable = TreeStyleTabBookmarksServiceEditable;
|
|
|
|
})();
|