選択範囲のリンクを子タブとして開く機能を追加

git-svn-id: http://www.cozmixng.org/repos/piro/treestyletab/trunk@1284 599a83e7-65a4-db11-8015-0010dcdd6dc2
This commit is contained in:
piro 2007-10-22 09:59:43 +00:00
parent 9a8fe69208
commit 1542562437
6 changed files with 193 additions and 10 deletions

View File

@ -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;"

View File

@ -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',

View File

@ -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"

View File

@ -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);

View File

@ -15,6 +15,8 @@
<!ENTITY config.tabbar.style.vertigo "Vertigo">
<!ENTITY config.tabbar.style.mixed "Mixed">
<!ENTITY config.show.openSelectionLinks "Add &quot;Open Selection Links in Tabs&quot; 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">

View File

@ -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 "このサブツリーを閉じる">