選択範囲のリンクを子タブとして開く機能を追加
git-svn-id: http://www.cozmixng.org/repos/piro/treestyletab/trunk@1284 599a83e7-65a4-db11-8015-0010dcdd6dc2
This commit is contained in:
parent
9a8fe69208
commit
1542562437
@ -25,6 +25,9 @@
|
||||
<preference id="extensions.treestyletab.tabbar.invertUI"
|
||||
name="extensions.treestyletab.tabbar.invertUI"
|
||||
type="bool"/>
|
||||
<preference id="extensions.treestyletab.show.openSelectionLinks"
|
||||
name="extensions.treestyletab.show.openSelectionLinks"
|
||||
type="bool"/>
|
||||
</preferences>
|
||||
|
||||
<checkbox id="extensions.treestyletab.tabbar.scroll.smooth-check"
|
||||
@ -64,6 +67,9 @@
|
||||
src="chrome://treestyletab/content/res/style-mixed.png"/>
|
||||
</radiogroup>
|
||||
</groupbox>
|
||||
<checkbox id="extensions.treestyletab.show.openSelectionLinks-check"
|
||||
preference="extensions.treestyletab.show.openSelectionLinks"
|
||||
label="&config.show.openSelectionLinks;"/>
|
||||
</prefpane>
|
||||
|
||||
<prefpane id="prefpane-tab" label="&config.tabs.tab;"
|
||||
|
@ -83,9 +83,17 @@ var TreeStyleTabService = {
|
||||
return this._ObserverService;
|
||||
},
|
||||
_ObserverService : null,
|
||||
|
||||
get IOService() {
|
||||
if (!this._IOService) {
|
||||
this._IOService = Components.classes['@mozilla.org/network/io-service;1'].getService(Components.interfaces.nsIIOService);
|
||||
}
|
||||
return this._IOService;
|
||||
},
|
||||
_IOService : null,
|
||||
|
||||
/* API */
|
||||
|
||||
|
||||
readyToOpenChildTab : function(aFrameOrTabBrowser, aMultiple)
|
||||
{
|
||||
var frame = this.getFrameFromTabBrowserElements(aFrameOrTabBrowser);
|
||||
@ -299,15 +307,32 @@ var TreeStyleTabService = {
|
||||
}
|
||||
return aTabs;
|
||||
},
|
||||
|
||||
makeURIFromSpec : function(aURI)
|
||||
{
|
||||
var newURI;
|
||||
aURI = aURI || '';
|
||||
if (aURI && String(aURI).indexOf('file:') == 0) {
|
||||
var fileHandler = this.IOService.getProtocolHandler('file').QueryInterface(Components.interfaces.nsIFileProtocolHandler);
|
||||
var tempLocalFile = fileHandler.getFileFromURLSpec(aURI);
|
||||
newURI = this.IOService.newFileURI(tempLocalFile);
|
||||
}
|
||||
else {
|
||||
newURI = this.IOService.newURI(aURI, null, null);
|
||||
}
|
||||
return newURI;
|
||||
},
|
||||
|
||||
/* Initializing */
|
||||
|
||||
|
||||
init : function()
|
||||
{
|
||||
if (!('gBrowser' in window)) return;
|
||||
|
||||
window.removeEventListener('load', this, false);
|
||||
|
||||
document.getElementById('contentAreaContextMenu').addEventListener('popupshowing', this, false);
|
||||
|
||||
if (this.getPref('extensions.treestyletab.inSubbrowsers.enabled')) {
|
||||
var appcontent = document.getElementById('appcontent');
|
||||
appcontent.addEventListener('SubBrowserAdded', this, false);
|
||||
@ -322,7 +347,7 @@ var TreeStyleTabService = {
|
||||
|
||||
this.initTabBrowser(gBrowser);
|
||||
},
|
||||
|
||||
|
||||
initTabBrowser : function(aTabBrowser)
|
||||
{
|
||||
this.initTabbar(aTabBrowser);
|
||||
@ -825,13 +850,15 @@ catch(e) {
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
destroy : function()
|
||||
{
|
||||
this.destroyTabBrowser(gBrowser);
|
||||
|
||||
window.removeEventListener('unload', this, false);
|
||||
|
||||
document.getElementById('contentAreaContextMenu').removeEventListener('popupshowing', this, false);
|
||||
|
||||
if (this.getPref('extensions.treestyletab.inSubbrowsers.enabled')) {
|
||||
var appcontent = document.getElementById('appcontent');
|
||||
appcontent.removeEventListener('SubBrowserAdded', this, false);
|
||||
@ -846,7 +873,7 @@ catch(e) {
|
||||
this.destroyTab(tabs[i]);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
destroyTabBrowser : function(aTabBrowser)
|
||||
{
|
||||
aTabBrowser.__treestyletab__observer.destroy();
|
||||
@ -878,7 +905,7 @@ catch(e) {
|
||||
},
|
||||
|
||||
/* Event Handling */
|
||||
|
||||
|
||||
handleEvent : function(aEvent)
|
||||
{
|
||||
switch (aEvent.type)
|
||||
@ -949,7 +976,8 @@ catch(e) {
|
||||
return;
|
||||
|
||||
case 'popupshowing':
|
||||
// this.showHideMenuItems(aEvent.target);
|
||||
if (aEvent.target != aEvent.currentTarget) return;
|
||||
this.initContextMenu();
|
||||
return;
|
||||
|
||||
case 'SubBrowserAdded':
|
||||
@ -1197,7 +1225,21 @@ catch(e) {
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
|
||||
initContextMenu : function()
|
||||
{
|
||||
var item = document.getElementById('context-treestyletab-openSelectionLinks');
|
||||
var sep = document.getElementById('context-treestyletab-openSelectionLinks-separator');
|
||||
if (this.getPref('extensions.treestyletab.show.openSelectionLinks') && this.getSelectionLinks().length) {
|
||||
item.removeAttribute('hidden');
|
||||
sep.removeAttribute('hidden');
|
||||
}
|
||||
else {
|
||||
item.setAttribute('hidden', true);
|
||||
sep.setAttribute('hidden', true);
|
||||
}
|
||||
},
|
||||
|
||||
/* Tab Utilities */
|
||||
|
||||
getTabValue : function(aTab, aKey)
|
||||
@ -1550,7 +1592,7 @@ catch(e) {
|
||||
},
|
||||
|
||||
/* Commands */
|
||||
|
||||
|
||||
initTabbar : function(aTabBrowser, aPosition)
|
||||
{
|
||||
if (!aPosition) aPosition = this.getPref('extensions.treestyletab.tabbar.position');
|
||||
@ -2177,7 +2219,120 @@ catch(e) {
|
||||
b.removeTab(tabs[i]);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
openSelectionLinks : function()
|
||||
{
|
||||
var links = this.getSelectionLinks();
|
||||
if (!links.length) return;
|
||||
|
||||
var b = this.browser;
|
||||
var targetWindow = document.commandDispatcher.focusedWindow;
|
||||
if (!targetWindow || targetWindow.top == window)
|
||||
targetWindow = b.contentWindow;
|
||||
|
||||
var referrer = this.makeURIFromSpec(targetWindow.location.href);
|
||||
|
||||
this.readyToOpenChildTab(targetWindow, true);
|
||||
var self = this;
|
||||
links.forEach(function(aItem, aIndex) {
|
||||
var tab = b.addTab(aItem.uri, referrer);
|
||||
if (aIndex == 0 && !self.getPref('browser.tabs.loadInBackground'))
|
||||
b.selectedTab = tab;
|
||||
});
|
||||
this.stopToOpenChildTab(targetWindow);
|
||||
},
|
||||
|
||||
getSelectionLinks : function()
|
||||
{
|
||||
var links = [];
|
||||
|
||||
var targetWindow = document.commandDispatcher.focusedWindow;
|
||||
if (!targetWindow || targetWindow.top == window)
|
||||
targetWindow = this.browser.contentWindow;
|
||||
|
||||
var selection = targetWindow.getSelection();
|
||||
if (!selection || !selection.rangeCount)
|
||||
return links;
|
||||
|
||||
const count = selection.rangeCount;
|
||||
var range,
|
||||
node,
|
||||
link,
|
||||
uri,
|
||||
nodeRange = targetWindow.document.createRange();
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
range = selection.getRangeAt(0);
|
||||
node = range.startContainer;
|
||||
|
||||
traceTree:
|
||||
while (true)
|
||||
{
|
||||
nodeRange.selectNode(node);
|
||||
|
||||
// 「ノードの終端が、選択範囲の先端より後にあるかどうか」をチェック。
|
||||
// 後にあるならば、そのノードは選択範囲内にあると考えられる。
|
||||
if (nodeRange.compareBoundaryPoints(Range.START_TO_END, range) > -1) {
|
||||
// 「ノードの先端が、選択範囲の終端より後にあるかどうか」をチェック。
|
||||
// 後にあるならば、そのノードは選択範囲外にあると考えられる。
|
||||
if (nodeRange.compareBoundaryPoints(Range.END_TO_START, range) > 0) {
|
||||
// 「リンクテキストが実際には選択されていないリンク」については除外する
|
||||
if (
|
||||
links.length &&
|
||||
range.startContainer.nodeType != Node.ELEMENT_NODE &&
|
||||
range.startOffset == range.startContainer.nodeValue.length &&
|
||||
links[0].node == this.getParentLink(range.startContainer)
|
||||
)
|
||||
links.splice(0, 1);
|
||||
|
||||
if (
|
||||
links.length &&
|
||||
range.endContainer.nodeType != Node.ELEMENT_NODE &&
|
||||
range.endOffset == 0 &&
|
||||
links[links.length-1].node == this.getParentLink(range.endContainer)
|
||||
)
|
||||
links.splice(links.length-1, 1);
|
||||
break;
|
||||
}
|
||||
else if (link = this.getParentLink(node)) {
|
||||
try {
|
||||
uri = link.href;
|
||||
if (uri && uri.indexOf('mailto:') < 0)
|
||||
links.push({ node : link, uri : uri });
|
||||
}
|
||||
catch(e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node.hasChildNodes() && !link) {
|
||||
node = node.firstChild;
|
||||
}
|
||||
else {
|
||||
while (!node.nextSibling)
|
||||
{
|
||||
node = node.parentNode;
|
||||
if (!node) break traceTree;
|
||||
}
|
||||
node = node.nextSibling;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nodeRange.detach();
|
||||
|
||||
return links;
|
||||
},
|
||||
|
||||
getParentLink : function(aNode)
|
||||
{
|
||||
var node = aNode;
|
||||
while (!node.href && node.parentNode)
|
||||
node = node.parentNode;
|
||||
|
||||
return node.href ? node : null ;
|
||||
},
|
||||
|
||||
/* Pref Listener */
|
||||
|
||||
domain : 'extensions.treestyletab',
|
||||
|
@ -10,6 +10,16 @@
|
||||
<script src="hacks.js" type="application/x-javascript"/>
|
||||
|
||||
|
||||
<popup id="contentAreaContextMenu">
|
||||
<menuseparator id="context-treestyletab-openSelectionLinks-separator"
|
||||
insertafter="context-sep-open"/>
|
||||
<menuitem id="context-treestyletab-openSelectionLinks"
|
||||
insertafter="context-sep-open"
|
||||
label="&context.openSelectionLinks.label;"
|
||||
accesskey="&context.openSelectionLinks.accesskey;"
|
||||
oncommand="TreeStyleTabService.openSelectionLinks();"/>
|
||||
</popup>
|
||||
|
||||
<menupopup id="multipletab-selection-menu">
|
||||
<menuitem id="multipletab-selection-item-removeTabSubTree"
|
||||
insertafter="multipletab-selection-removeTabs"
|
||||
|
@ -6,6 +6,8 @@ pref("extensions.treestyletab.tabbar.scroll.timeout", 250);
|
||||
pref("extensions.treestyletab.tabbar.style", "mixed");
|
||||
pref("extensions.treestyletab.levelMargin", 12);
|
||||
|
||||
pref("extensions.treestyletab.show.openSelectionLinks", true);
|
||||
|
||||
pref("extensions.treestyletab.openGroupBookmarkAsTabSubTree", true);
|
||||
pref("extensions.treestyletab.loadDroppedLinkToNewChildTab", false);
|
||||
|
||||
|
@ -15,6 +15,8 @@
|
||||
<!ENTITY config.tabbar.style.vertigo "Vertigo">
|
||||
<!ENTITY config.tabbar.style.mixed "Mixed">
|
||||
|
||||
<!ENTITY config.show.openSelectionLinks "Add "Open Selection Links in Tabs" to the context menu">
|
||||
|
||||
|
||||
<!ENTITY config.tabs.tab "Tab Operations">
|
||||
|
||||
@ -51,6 +53,9 @@
|
||||
|
||||
|
||||
|
||||
<!ENTITY context.openSelectionLinks.label "Open Selection Links in Tabs">
|
||||
<!ENTITY context.openSelectionLinks.accesskey "l">
|
||||
|
||||
<!ENTITY selection.removeTabSubTree.label "Close Selected Sub Trees">
|
||||
<!ENTITY selection.removeTabSubTree.accesskey "s">
|
||||
<!ENTITY context.removeTabSubTree.label "Close this Sub Tree">
|
||||
|
@ -15,6 +15,8 @@
|
||||
<!ENTITY config.tabbar.style.vertigo "Vertigo">
|
||||
<!ENTITY config.tabbar.style.mixed "Mixed">
|
||||
|
||||
<!ENTITY config.show.openSelectionLinks "コンテキストメニューに「選択したリンクをすべてタブで開く」を加える">
|
||||
|
||||
|
||||
<!ENTITY config.tabs.tab "タブの開き方">
|
||||
|
||||
@ -50,6 +52,9 @@
|
||||
|
||||
|
||||
|
||||
<!ENTITY context.openSelectionLinks.label "選択したリンクをすべてタブで開く">
|
||||
<!ENTITY context.openSelectionLinks.accesskey "l">
|
||||
|
||||
<!ENTITY selection.removeTabSubTree.label "すべてのサブツリーを閉じる">
|
||||
<!ENTITY selection.removeTabSubTree.accesskey "s">
|
||||
<!ENTITY context.removeTabSubTree.label "このサブツリーを閉じる">
|
||||
|
Loading…
Reference in New Issue
Block a user