[Pkg-mozext-commits] [tree-style-tab] 01/04: Imported Upstream version 0.16.2016021602

Ximin Luo infinity0 at debian.org
Sat Feb 20 23:28:44 UTC 2016


This is an automated email from the git hooks/post-receive script.

infinity0 pushed a commit to branch master
in repository tree-style-tab.

commit 0c2052b93a816b197a1af7024c0f1afe39527deb
Author: Ximin Luo <infinity0 at debian.org>
Date:   Sat Feb 20 22:45:32 2016 +0100

    Imported Upstream version 0.16.2016021602
---
 META-INF/manifest.mf                               | 203 +++++----
 META-INF/mozilla.rsa                               | Bin 4189 -> 4189 bytes
 META-INF/mozilla.sf                                |   4 +-
 content/treestyletab/bookmarksOverlay.js           | 488 +-------------------
 content/treestyletab/bookmarksOverlayEditable.js   | 123 +++--
 content/treestyletab/config.xul                    |   1 +
 content/treestyletab/license.txt                   |   2 +-
 content/treestyletab/treestyletab.css              |  12 +
 content/treestyletab/treestyletab.js               |   8 +-
 content/treestyletab/treestyletab.xul              |   4 +-
 content/treestyletab/windowHelper.js               | 147 +++---
 content/treestyletab/windowHelperHacks.js          |   2 +-
 defaults/preferences/treestyletab.js               |  21 +-
 install.rdf                                        |   7 +-
 locale/cs/treestyletab/treestyletab.dtd            |   4 +-
 locale/da-DK/treestyletab/treestyletab.dtd         |   4 +-
 locale/de-DE/treestyletab/license.txt              |   5 +-
 locale/de-DE/treestyletab/treestyletab.dtd         | 274 ++++++-----
 locale/en-US/treestyletab/treestyletab.dtd         |   3 +-
 locale/es-ES/treestyletab/treestyletab.dtd         |   4 +-
 locale/fr-FR/treestyletab/treestyletab.dtd         |   4 +-
 locale/it-IT/treestyletab/treestyletab.dtd         |   4 +-
 locale/ja/treestyletab/treestyletab.dtd            |   3 +-
 locale/pl/treestyletab/treestyletab.dtd            |   4 +-
 locale/ru/treestyletab/treestyletab.dtd            |  12 +-
 locale/sv-SE/treestyletab/treestyletab.dtd         |   4 +-
 locale/zh-CN/treestyletab/treestyletab.dtd         |   4 +-
 locale/zh-TW/treestyletab/treestyletab.dtd         |   4 +-
 modules/autoHide.js                                |  90 +++-
 modules/base.js                                    | 395 ++++------------
 modules/bookmark.js                                | 504 +++++++++++++++++++++
 modules/browser.js                                 | 326 +++++++++----
 modules/browserUIShowHideObserver.js               |  57 ++-
 modules/constants.js                               |  18 +
 modules/contentBridge.js                           |  15 +-
 modules/fullTooltip.js                             |  71 ++-
 modules/fullscreenObserver.js                      |  10 +-
 modules/groupTab.js                                |  32 +-
 modules/pseudoTreeBuilder.js                       |  66 ++-
 modules/tabAttributesObserver.js                   |  11 +-
 ...ttributesObserver.js => tabContentsObserver.js} |  96 ++--
 modules/tabbarDNDObserver.js                       |  96 ++--
 modules/utils.js                                   | 370 ++++++++++++++-
 modules/window.js                                  | 141 +++++-
 skin/classic/treestyletab/group.css                |  13 +-
 skin/classic/treestyletab/license.txt              |   2 +-
 skin/classic/treestyletab/metal/base.css           |  68 ++-
 skin/classic/treestyletab/pseudo-tree.css          |  30 +-
 skin/classic/treestyletab/sidebar/sidebar.css      |  48 +-
 skin/classic/treestyletab/square/base.css          |  17 +
 skin/classic/treestyletab/square/vertigo.css       |  18 +
 skin/classic/treestyletab/ui-base.css              |  10 +
 treestyletab.update.rdf                            |  30 ++
 53 files changed, 2426 insertions(+), 1463 deletions(-)

diff --git a/META-INF/manifest.mf b/META-INF/manifest.mf
index d30ab74..9e2f63f 100644
--- a/META-INF/manifest.mf
+++ b/META-INF/manifest.mf
@@ -2,8 +2,8 @@ Manifest-Version: 1.0
 
 Name: install.rdf
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: CAt8kfQijgwV0VrebcRR4g==
-SHA1-Digest: taJHxkigk8GxKRBvwYWA7GbI25k=
+MD5-Digest: GhhEUrydTwg3fyzdRVE7Hw==
+SHA1-Digest: IA2smyD8Ao/QqmYTFfcSGOwW370=
 
 Name: chrome.manifest
 Digest-Algorithms: MD5 SHA1
@@ -15,6 +15,11 @@ Digest-Algorithms: MD5 SHA1
 MD5-Digest: b26p1vuhLB2vYtkJ0EpFZg==
 SHA1-Digest: T9f7i8A7iAz/ElpA361lLRpnbWc=
 
+Name: treestyletab.update.rdf
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: P0m8CTDmPTu3ahll/DOucQ==
+SHA1-Digest: Fj8WbLoHt0uNXjyC/5Nt63948rA=
+
 Name: components/AboutGroup.js
 Digest-Algorithms: MD5 SHA1
 MD5-Digest: D+AXOvn4yNMXf8GhIKbFrA==
@@ -22,8 +27,8 @@ SHA1-Digest: XLM7zjvCkIi09SoAGOVOZdeQofY=
 
 Name: content/treestyletab/bookmarksOverlay.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: sLs6Xz86OV6NK6RJVHgEvA==
-SHA1-Digest: pmX3AWu0z9RzIeDgImy8NfP1UIA=
+MD5-Digest: w3yRAETKAdZTGAbBG3Em7Q==
+SHA1-Digest: wihCEtZ16DVkz+waXI6bdMxzAdI=
 
 Name: content/treestyletab/bookmarksOverlay.xul
 Digest-Algorithms: MD5 SHA1
@@ -37,8 +42,8 @@ SHA1-Digest: /V6d117O8c9Qgt7NoCuVRN2bOF0=
 
 Name: content/treestyletab/bookmarksOverlayEditable.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: aRKA2Ooi+mTYX9yfoZnEqg==
-SHA1-Digest: DtU1d+Is7rWbs3c/rzdEje7a8Tk=
+MD5-Digest: u6u3KPfJJdx4eWOpykXXAA==
+SHA1-Digest: zh1Sx8pycIsT2yk/kjw3eBA9cTk=
 
 Name: content/treestyletab/bookmarksOverlayEditable.xul
 Digest-Algorithms: MD5 SHA1
@@ -57,8 +62,8 @@ SHA1-Digest: LSm4XQfNAqRWieDG2oKRk54Rrh8=
 
 Name: content/treestyletab/config.xul
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: QaUI+njq/1aPa0LBOt69hw==
-SHA1-Digest: RikaDXmgEw6M/cVHItWilEShkAA=
+MD5-Digest: NZY8ITSUeWciGsIYiwKgaA==
+SHA1-Digest: n3WFwTJN9dYOliz5YDpjd13YJh4=
 
 Name: content/treestyletab/content-utils-autohide.js
 Digest-Algorithms: MD5 SHA1
@@ -82,8 +87,8 @@ SHA1-Digest: dVIKETt9CnpIKynmf5iCpf1jDNo=
 
 Name: content/treestyletab/license.txt
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: ks0H9N1HwtHOGFBceqqXLA==
-SHA1-Digest: EeTFV+ifwWkwaWvQiix88l8YDtw=
+MD5-Digest: LPKF3jz0aUCOORAZxF3CBw==
+SHA1-Digest: 9pCMihCjV7sRiu2H4IKuovx68LM=
 
 Name: content/treestyletab/multipletabConfigOverlay.xul
 Digest-Algorithms: MD5 SHA1
@@ -97,13 +102,13 @@ SHA1-Digest: dUnh9cVls70LC0cO+AzOTyJ+7Bc=
 
 Name: content/treestyletab/treestyletab.css
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: Mm0SnlWa87xf7i6PZskaSA==
-SHA1-Digest: V8ChvaXQTQoL7PWPnqUSUybFakY=
+MD5-Digest: Y+LtIloCWi9BRp0tIr38/Q==
+SHA1-Digest: hY2iyFgCqbULOeYkM7FS3NnkQMc=
 
 Name: content/treestyletab/treestyletab.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: rAQdu8NF3MYvlInTA/rnZA==
-SHA1-Digest: mdGLj3IkGat9NH80/KPUwZIx3zc=
+MD5-Digest: 6E9tmEesiujXo1RfuXj+tw==
+SHA1-Digest: NWhDnh0jSiQ+8Yn2qWWKZl+smqA=
 
 Name: content/treestyletab/treestyletab.xml
 Digest-Algorithms: MD5 SHA1
@@ -112,18 +117,18 @@ SHA1-Digest: yI4r2a9JmBDqDI8qcvvn6R1wG4M=
 
 Name: content/treestyletab/treestyletab.xul
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: a1axHz8ImoVUaGIhA0wOzA==
-SHA1-Digest: xdVcooRj2CkN5RnELJyfUbvKzZ0=
+MD5-Digest: gzxBjw2xe+IkDHQVK1ojcA==
+SHA1-Digest: 9lVQdUME2zPBCECRLZrK2fGxEFY=
 
 Name: content/treestyletab/windowHelper.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: JOMK+8toiBUS/M03riElHw==
-SHA1-Digest: cyjdZyq02U3zrD87OG+gxvTnJZM=
+MD5-Digest: r4uLpCypKvERzfkcDWZU0A==
+SHA1-Digest: 2eJCf+fAYOKLzjm/CMJlBLS73Oc=
 
 Name: content/treestyletab/windowHelperHacks.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: vVo8T1auXVrfm43DVwFlQQ==
-SHA1-Digest: NGxQoWrIDKS8RhPZk6DbEXVcDbY=
+MD5-Digest: tIusMKnymHkV00GpE4vqNg==
+SHA1-Digest: 7ALqU8yWobS7ys5FjKr+tlBz+VY=
 
 Name: content/treestyletab/res/bookmarkMultipleTabs.xul
 Digest-Algorithms: MD5 SHA1
@@ -203,8 +208,8 @@ SHA1-Digest: q0mYa40sk7KoHzdmK6voR/OuGF8=
 
 Name: defaults/preferences/treestyletab.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: lPwzD9NItQEv3PUa7RZRJQ==
-SHA1-Digest: soqONodaywdE4m2JsBSw7OW91Pw=
+MD5-Digest: vXg0XUNA6dpDy6LBjdxO8g==
+SHA1-Digest: b9nv5QEmT1sZj/o8+K7DnzAHGqg=
 
 Name: locale/cs/treestyletab/license.txt
 Digest-Algorithms: MD5 SHA1
@@ -213,8 +218,8 @@ SHA1-Digest: AmPIaBSAXJtd03ZD/LGrxu3FN3Y=
 
 Name: locale/cs/treestyletab/treestyletab.dtd
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: GFjhguaDXqBoU6EmEPralw==
-SHA1-Digest: 6Bnzxn4B1BUNCsB4R1/jkfcDiqw=
+MD5-Digest: S1c7sGxI5L45WTemrDpN2Q==
+SHA1-Digest: r5pt9I98GQbtwLsN9lrvKzVaIWU=
 
 Name: locale/cs/treestyletab/treestyletab.properties
 Digest-Algorithms: MD5 SHA1
@@ -228,8 +233,8 @@ SHA1-Digest: vjay7k00E2Dhmo0XsTlEeFTRPXI=
 
 Name: locale/da-DK/treestyletab/treestyletab.dtd
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: 2qQbuzytrLI3gR1RShTh3g==
-SHA1-Digest: Wq4dH3SqSOEhXLAI4XjO8ovAGLc=
+MD5-Digest: MGcs5SmhA0RFaLZ+jMuBpg==
+SHA1-Digest: E1K4ntc3dnYJnNyyqCGIFgZn59c=
 
 Name: locale/da-DK/treestyletab/treestyletab.properties
 Digest-Algorithms: MD5 SHA1
@@ -238,13 +243,13 @@ SHA1-Digest: ST1q6G8rHvDj78R+2ob8U7WMBdo=
 
 Name: locale/de-DE/treestyletab/license.txt
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: P1OFa2/VTsD9tBpI1qCeSA==
-SHA1-Digest: CQr1mkH//MpqNCWbLou/CJX2aDk=
+MD5-Digest: Bl+6HAZa3Dp3iHyhd2VYIg==
+SHA1-Digest: JdQfP7XjmROHYlyQEMxiYImBB38=
 
 Name: locale/de-DE/treestyletab/treestyletab.dtd
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: 8k+CsLwHHSe1I54khQTQ9w==
-SHA1-Digest: vfifHgKnlz1ZfkGFHQWClnbOnlg=
+MD5-Digest: g5xm6kv8MCM9UpFM67F6EA==
+SHA1-Digest: uFn6iFBt/WujKnMH1Txp8N810NY=
 
 Name: locale/de-DE/treestyletab/treestyletab.properties
 Digest-Algorithms: MD5 SHA1
@@ -258,8 +263,8 @@ SHA1-Digest: /vNGGzRR58QK5AOQjlorkE5GCAI=
 
 Name: locale/en-US/treestyletab/treestyletab.dtd
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: iDLxSpuoKKNs699XnahdWA==
-SHA1-Digest: 4VWXkPnDg6Y/as5jndUQ2Crv3Eo=
+MD5-Digest: 79tbzrCYB/x0bdBOiDfs7w==
+SHA1-Digest: Ll5LFDQhfOdJg8EMWUO/QAZdG78=
 
 Name: locale/en-US/treestyletab/treestyletab.properties
 Digest-Algorithms: MD5 SHA1
@@ -273,8 +278,8 @@ SHA1-Digest: OeORv30Cbr8ylQKVbM0O9Y5n+4Y=
 
 Name: locale/es-ES/treestyletab/treestyletab.dtd
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: OUTcy4zd5Vxuzcu5FXhgGA==
-SHA1-Digest: dq3ViTmc3yQeagUUn6jn1AJqh5g=
+MD5-Digest: FZ8qygxK89diULrqTjwkUA==
+SHA1-Digest: /ALFGxPRT17mrwhASIWhTTVggq8=
 
 Name: locale/es-ES/treestyletab/treestyletab.properties
 Digest-Algorithms: MD5 SHA1
@@ -288,8 +293,8 @@ SHA1-Digest: eSqlFr5OnT5gIpY1PF7f/E3bHas=
 
 Name: locale/fr-FR/treestyletab/treestyletab.dtd
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: Xv5frYQruWKmsjywNOTj9A==
-SHA1-Digest: SNvJsrIA10cSSO0a+nb2zs3i9Ck=
+MD5-Digest: N6bDJ3SzgVZe1UlTgRFwsg==
+SHA1-Digest: PXpG4+Xyjn3jjJJDZemJaFQeQNA=
 
 Name: locale/fr-FR/treestyletab/treestyletab.properties
 Digest-Algorithms: MD5 SHA1
@@ -303,8 +308,8 @@ SHA1-Digest: DqBJQrV8f3tss7fKSnCdeXNIxYs=
 
 Name: locale/it-IT/treestyletab/treestyletab.dtd
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: +EEwXCEjVyEwhfddMukiTQ==
-SHA1-Digest: 3z666pwEzH6Tee/hDX1shLrntFE=
+MD5-Digest: lQk7kY4EANS4K8T/ikjJLQ==
+SHA1-Digest: L5MogwLPip1K4gUGbiazhgzLKhg=
 
 Name: locale/it-IT/treestyletab/treestyletab.properties
 Digest-Algorithms: MD5 SHA1
@@ -318,8 +323,8 @@ SHA1-Digest: /vNGGzRR58QK5AOQjlorkE5GCAI=
 
 Name: locale/ja/treestyletab/treestyletab.dtd
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: mkOJ40PDsuMqvNxtpJJjOA==
-SHA1-Digest: FfRIjSw0qEiGxdFlwQ//fQkptg4=
+MD5-Digest: FkeegJj5UPAbmhnKhVcf3A==
+SHA1-Digest: FdMi4A/WAXHC4XUZ+xyzLSPg0hs=
 
 Name: locale/ja/treestyletab/treestyletab.properties
 Digest-Algorithms: MD5 SHA1
@@ -333,8 +338,8 @@ SHA1-Digest: JwRGjnhAsrasY46ktL+EtP3fxDI=
 
 Name: locale/pl/treestyletab/treestyletab.dtd
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: KFVWmQdcJ9pGREtXLoODOg==
-SHA1-Digest: i5B0DPl6SfjGK6eXQY2b9QIAFOc=
+MD5-Digest: H9KOrshnfLwdtj7W5L+61g==
+SHA1-Digest: eqB5I2Nq/aUMmXlWRW2lU+ZKVTo=
 
 Name: locale/pl/treestyletab/treestyletab.properties
 Digest-Algorithms: MD5 SHA1
@@ -348,8 +353,8 @@ SHA1-Digest: Ewz5/CWtInQDfBCQoje+iGZbjEE=
 
 Name: locale/ru/treestyletab/treestyletab.dtd
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: PfBvTn8K+gNIHmvd/dGkDg==
-SHA1-Digest: fsTj+hUNX9NzIOCW4Z15gFW0Dik=
+MD5-Digest: dWGYPSeZ5341VaTF1/MdXA==
+SHA1-Digest: pK3SDZcLZCbCfqnVARH8M+RP84c=
 
 Name: locale/ru/treestyletab/treestyletab.properties
 Digest-Algorithms: MD5 SHA1
@@ -363,8 +368,8 @@ SHA1-Digest: Zfn4AKRpBe4E44Sg1HIuoxFmif0=
 
 Name: locale/sv-SE/treestyletab/treestyletab.dtd
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: sAP3Nk44J3lDruqer4GpDQ==
-SHA1-Digest: V/BXP1zzBS4VWaFmWr67FUKcQ4w=
+MD5-Digest: V6/Vd3aktzj4JZvOwOdXsw==
+SHA1-Digest: ngGCi/Hn1Kgd+plJuY2vZmD4ZdA=
 
 Name: locale/sv-SE/treestyletab/treestyletab.properties
 Digest-Algorithms: MD5 SHA1
@@ -378,8 +383,8 @@ SHA1-Digest: CxdX2iIT5cw2WR+1eMh9AA78n+U=
 
 Name: locale/zh-CN/treestyletab/treestyletab.dtd
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: p/wDbKOmcTNUKMPVJJ6m0w==
-SHA1-Digest: hRTFekXYZAHKfuy0jZMKnwMjwg4=
+MD5-Digest: KnhHB+1luU5RevlomI6QFw==
+SHA1-Digest: 8bj+cDEDY+yjEXy7IO/5PnxL9js=
 
 Name: locale/zh-CN/treestyletab/treestyletab.properties
 Digest-Algorithms: MD5 SHA1
@@ -393,8 +398,8 @@ SHA1-Digest: XVqJMKhADCM73LtM7OFthNdECYo=
 
 Name: locale/zh-TW/treestyletab/treestyletab.dtd
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: wOiKXRdEV9+7hWwqWu7suQ==
-SHA1-Digest: QsZ16EOh4Nq8UKRGsln0l3WiX8Q=
+MD5-Digest: sYDn/nP1GsBXhSJ7A+lIQA==
+SHA1-Digest: 693d8xo1yzJWXJEr3aJvNW/1kRI=
 
 Name: locale/zh-TW/treestyletab/treestyletab.properties
 Digest-Algorithms: MD5 SHA1
@@ -403,53 +408,58 @@ SHA1-Digest: 820CmLC9fE1O0AAZaeKrzW0ER0g=
 
 Name: modules/autoHide.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: WSRRLknoma7O3S9aJkSOKw==
-SHA1-Digest: lGdnY8ofd14V1AMwdEOp8dKjAPc=
+MD5-Digest: 9qFptUgYah+iSy44QE8Naw==
+SHA1-Digest: OHvqXa79X2rOIFUeOsIEN78zno4=
 
 Name: modules/base.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: VOevY6uJ0ZCSWIiIZmzO2Q==
-SHA1-Digest: +L7wNk9LzQHZUw9OPQZSEg1NilY=
+MD5-Digest: 1TiyG9rY3cIybESDkUrR5g==
+SHA1-Digest: 1S8UA0ZVJI817ysQG2J4cT9Qoy0=
+
+Name: modules/bookmark.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: +NLpHc0+GiT0lSzGiJtlNA==
+SHA1-Digest: GYZNPm63Yrhqkide8fT3TyXFJvw=
 
 Name: modules/browser.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: QGVmf085jGnv2mcc5Hq06A==
-SHA1-Digest: 2QUA4g3DDsXPc/PmD9FT42CGRac=
+MD5-Digest: mGAY2Pmq1BEh2fg63QWAaA==
+SHA1-Digest: RyyoaY7u1toldesei3wwQ9hQkoM=
 
 Name: modules/browserUIShowHideObserver.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: 1jGa2nmHU/8r438jcy8bxA==
-SHA1-Digest: 0ye5nfvkIj6pI35yGQAEL7xtJ+k=
+MD5-Digest: dNk/UnlE0F8L4dJZICP6Nw==
+SHA1-Digest: D84Jbg20wtUqqgG4pWCgF9ZdVaw=
 
 Name: modules/constants.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: EHGxOf4hgnxhSn5EG9Q3ig==
-SHA1-Digest: uk+B7UWHZ+SGcCrBuSYDEi+lwBE=
+MD5-Digest: BZIM6ulqOhpQxI0KmT/J4Q==
+SHA1-Digest: ZQ/tn2EH7qOR5Pmaez8DZaeyVXo=
 
 Name: modules/contentBridge.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: 8EkTrdJ8nAxYO+81/mRYig==
-SHA1-Digest: PjTvEP1WjiDk/FgiOz5XVHKr/+E=
+MD5-Digest: AxdjgF9qLoOy1Dwpm94DKQ==
+SHA1-Digest: F+2KHUcbSxqlW4FbdoKCOM9Viyo=
 
 Name: modules/fullscreenObserver.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: dA4uF/PyD4eIAjQaZ1RIIQ==
-SHA1-Digest: ENKlU1ETpeEMx47y4xvTsSltvtw=
+MD5-Digest: TKVwSD0v1bAX/oWKo8OerA==
+SHA1-Digest: cc6D7hos4bGfa5ReVduq0YkLnWI=
 
 Name: modules/fullTooltip.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: OTHa0q1gsOZFgz5uOQOE0Q==
-SHA1-Digest: SAU4UbMLDt9SVI9lrj/dfSoXe4k=
+MD5-Digest: FoqOnzIGy6E7x19QU0hQFQ==
+SHA1-Digest: 90q+tMYpgfjZ5gI8NgtY/zurn8E=
 
 Name: modules/groupTab.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: NL5i97YRH+b+XpG22i8tIA==
-SHA1-Digest: qefrneMChMj4kmaCaq19QCg/BqM=
+MD5-Digest: mLv7QoeDW18xj5Qr0oFy3Q==
+SHA1-Digest: Q5YR/wKCEBtik8DUl+kY7AFfd8c=
 
 Name: modules/pseudoTreeBuilder.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: KsauIXOH18MRG4mEplXZfw==
-SHA1-Digest: 7EaG3t5WJWOobr8LTS9nX/ulAoI=
+MD5-Digest: lOXZb5hQEp7AKAt5nQPr8A==
+SHA1-Digest: jFpw99/71Tjjz9Yg81LVDPqWJPM=
 
 Name: modules/ReferenceCounter.js
 Digest-Algorithms: MD5 SHA1
@@ -458,13 +468,18 @@ SHA1-Digest: KwYUQNA0W5ensPrOgCQeR2NRGm4=
 
 Name: modules/tabAttributesObserver.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: ASIvZ3RBvp7ujNIxUhHjhA==
-SHA1-Digest: E3qycu7EJPrhOGIYeCcsiHlDq/A=
+MD5-Digest: GnqU1In8Jw/2jscAyXXGyg==
+SHA1-Digest: a4KpeD2z5f3xYaa//UQGtAA5+j0=
 
 Name: modules/tabbarDNDObserver.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: Af1MrXXUChYdrEcE83+ljA==
-SHA1-Digest: jzjPtaYbneiJQrIL86DEi8H0qCQ=
+MD5-Digest: SVM/EuTv3Ybu8nxvHnuC2Q==
+SHA1-Digest: jKHCxKjOpz2CQJK2gzwifuh+Uec=
+
+Name: modules/tabContentsObserver.js
+Digest-Algorithms: MD5 SHA1
+MD5-Digest: Mx8Cw+iPLWSjkNjv10xCXg==
+SHA1-Digest: XZJFvYTu9pPIFV+zY9hH2IJsTKM=
 
 Name: modules/tabpanelDNDObserver.js
 Digest-Algorithms: MD5 SHA1
@@ -478,13 +493,13 @@ SHA1-Digest: QRODHmwaRkX+b/zrhPVckxz7kf4=
 
 Name: modules/utils.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: Evsu0Jey/gxHQtysi3qW9w==
-SHA1-Digest: z+FPUT6tjjGfA52pyzkH0LPYwB0=
+MD5-Digest: MPLBmR6Rg3wF6+6R5yAEZw==
+SHA1-Digest: 1jMd3iV7CwXwLgjmhzjCJ2Sd5BM=
 
 Name: modules/window.js
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: 2YhxOObDBT3JeYp0wn4Y9Q==
-SHA1-Digest: VhNri9EbLd5snZIeuxlX5G5CuIM=
+MD5-Digest: /T5G3EZnKKl1v+Gs2/xLsg==
+SHA1-Digest: mjDJSrMcZLOjZk+pWIxl91kXSw4=
 
 Name: modules/lib/animationManager.js
 Digest-Algorithms: MD5 SHA1
@@ -573,13 +588,13 @@ SHA1-Digest: DvaxcjAmPsnt7a1LFCcI+kZ8O4U=
 
 Name: skin/classic/treestyletab/group.css
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: 90uxLtKKwShXcpxAlDs44A==
-SHA1-Digest: z7qNzCAhtrmIXtkGllbGhDnXKDg=
+MD5-Digest: BjIr5GS7yRoBH6Ki7jcDzg==
+SHA1-Digest: 5BZvSzT495FHylk38Y/+5t82t5E=
 
 Name: skin/classic/treestyletab/license.txt
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: YNMSU+FEmPbD4l7BlE+1eg==
-SHA1-Digest: SkZhMKbeatV48RFx9AROoyuLalc=
+MD5-Digest: Tc+NDhBc7EP4cr5OqQGQyQ==
+SHA1-Digest: TLhlpxf44EXADPU56xRsRroxdo4=
 
 Name: skin/classic/treestyletab/Linux-base.css
 Digest-Algorithms: MD5 SHA1
@@ -598,8 +613,8 @@ SHA1-Digest: qeeZLagzbORE5b8b1TAxnZVS998=
 
 Name: skin/classic/treestyletab/pseudo-tree.css
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: vladq5shyYibE7GNT5fh0Q==
-SHA1-Digest: oS++SxHpJBVwPdVbO7VHkoGDom4=
+MD5-Digest: YpzbGadA5uvjsoP1UfTk1g==
+SHA1-Digest: lRJLbWJTt07wa9FVOvoH+717+po=
 
 Name: skin/classic/treestyletab/tmp.css
 Digest-Algorithms: MD5 SHA1
@@ -613,8 +628,8 @@ SHA1-Digest: /CcGFdIzQT8ebf8twW9s6P1rRRI=
 
 Name: skin/classic/treestyletab/ui-base.css
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: f7hWW6ka4HhJp2x4iDlIrw==
-SHA1-Digest: SBpgkKqiRMt63i0rHc+TUMJoo1o=
+MD5-Digest: 4J55NfuxfInmG+yrwyWLXg==
+SHA1-Digest: 3R9fRWUS30aMN2OlqohDOhKrTnY=
 
 Name: skin/classic/treestyletab/WINNT-base.css
 Digest-Algorithms: MD5 SHA1
@@ -633,8 +648,8 @@ SHA1-Digest: OeNgpLNuSgMsZsZ2yp1YXdy3Fg8=
 
 Name: skin/classic/treestyletab/metal/base.css
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: VOvt6P5FBvR/oN9iUdQxtQ==
-SHA1-Digest: i2FdF8PL0OCo1dgAI9S+zJmcKn8=
+MD5-Digest: TNk9iR8Q3ipTt8YGmNsffQ==
+SHA1-Digest: 1PFGo316AmQuindR0mhEfcHIq2I=
 
 Name: skin/classic/treestyletab/metal/Darwin.css
 Digest-Algorithms: MD5 SHA1
@@ -738,13 +753,13 @@ SHA1-Digest: VNJPj9nckqPyRb2Ff3HWiGPQE58=
 
 Name: skin/classic/treestyletab/sidebar/sidebar.css
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: xgizmjMioe0U8jjR60gvCA==
-SHA1-Digest: cb+98YrSrq/rVbSDoYhKTVwMKQw=
+MD5-Digest: KDhvyIF+hdzOv2Y+0HhMyg==
+SHA1-Digest: Hat43VvEtekC4PdBU3rxCdoK6hE=
 
 Name: skin/classic/treestyletab/square/base.css
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: 7elXQXx/AV+21AEq+84dAw==
-SHA1-Digest: T7j8PUzg8peCmHWYmY26cyrDi2w=
+MD5-Digest: 86fdJZscRoUZHtV5iyvicw==
+SHA1-Digest: Le6rdBYbmghJePZWLTxtaPwFTqk=
 
 Name: skin/classic/treestyletab/square/Darwin.css
 Digest-Algorithms: MD5 SHA1
@@ -803,8 +818,8 @@ SHA1-Digest: uJCYdd6cnRl0V0Vt+sFUFWmD4oE=
 
 Name: skin/classic/treestyletab/square/vertigo.css
 Digest-Algorithms: MD5 SHA1
-MD5-Digest: x5bWTAcM++UPB3EJFA3J3A==
-SHA1-Digest: 08KztOOzgQ0M+D/3ayVlOxnPaw4=
+MD5-Digest: YLJ7vvT+Tx9/UICfK4wVJQ==
+SHA1-Digest: kb6KoccqQfUIWkC1Dt3Ma3P7jAQ=
 
 Name: skin/classic/treestyletab/twisty/twisty-modern-b-l.png
 Digest-Algorithms: MD5 SHA1
diff --git a/META-INF/mozilla.rsa b/META-INF/mozilla.rsa
index 8a26cc4..3979352 100644
Binary files a/META-INF/mozilla.rsa and b/META-INF/mozilla.rsa differ
diff --git a/META-INF/mozilla.sf b/META-INF/mozilla.sf
index 36df67f..ad31b7f 100644
--- a/META-INF/mozilla.sf
+++ b/META-INF/mozilla.sf
@@ -1,4 +1,4 @@
 Signature-Version: 1.0
-MD5-Digest-Manifest: T08tnhNEZ1g5FL/L2ZxHZg==
-SHA1-Digest-Manifest: iNKONgCoicdK/P5/AHA1K9bV7zQ=
+MD5-Digest-Manifest: oVOnv2S1lDvsplClJaljyQ==
+SHA1-Digest-Manifest: qt6nGW08/CsBc6g0DFWFIZjhT2s=
 
diff --git a/content/treestyletab/bookmarksOverlay.js b/content/treestyletab/bookmarksOverlay.js
index 91e51d0..bedc225 100644
--- a/content/treestyletab/bookmarksOverlay.js
+++ b/content/treestyletab/bookmarksOverlay.js
@@ -1,221 +1,14 @@
 Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
+Components.utils.import('resource://treestyletab-modules/bookmark.js', {});
 XPCOMUtils.defineLazyModuleGetter(this,
   'TreeStyleTabUtils', 'resource://treestyletab-modules/utils.js');
 
 (function() {
 let { ReferenceCounter } = Components.utils.import('resource://treestyletab-modules/ReferenceCounter.js', {});
 let { inherit } = Components.utils.import('resource://treestyletab-modules/lib/inherit.jsm', {});
-var TreeStyleTabBookmarksService = inherit(TreeStyleTabService, {
-
-	get BookmarksService() {
-		if (!this._BookmarksService) {
-			this._BookmarksService = Components
-					.classes['@mozilla.org/browser/nav-bookmarks-service;1']
-					.getService(Components.interfaces.nsINavBookmarksService);
-		}
-		return this._BookmarksService;
-	},
-	_BookmarksService : null,
-
-
-	beginAddBookmarksFromTabs : function TSTBMService_beginAddBookmarksFromTabs(aTabs) /* PUBLIC API */ 
-	{
-		if (this._observing) return;
-		this._observing = true;
-
-		aTabs = this.cleanUpTabsArray(aTabs);
-
-		this._addingBookmarks = [];
-		this._addingBookmarkTreeStructure = aTabs.map(function(aTab) {
-			var parent = this.getParentTab(aTab);
-			return aTabs.indexOf(parent);
-		}, this);
-
-		this.BookmarksService.addObserver(this, false);
-	},
- 
-	endAddBookmarksFromTabs : function TSTBMService_endAddBookmarksFromTabs() /* PUBLIC API */ 
-	{
-		if (!this._observing) return;
-		this._observing = false;
-
-		this.BookmarksService.removeObserver(this);
-		this.handleNewBookmarksFromTabs(this._addingBookmarks, this._addingBookmarkTreeStructure);
-		this._addingBookmarks = [];
-		this._addingBookmarkTreeStructure = [];
-	},
- 
-	handleNewBookmarksFromTabs : function TSTBMService_handleNewBookmarksFromTabs(aBookarmks, aTreeStructure) 
-	{
-		// this is adding bookmark folder from tabs, so ignroe the first item!
-		if (
-			aBookarmks.length == aTreeStructure.length+1 &&
-			this.BookmarksService.getItemType(aBookarmks[0].id) == this.BookmarksService.TYPE_FOLDER
-			) {
-			aBookarmks.shift();
-		}
-		else if (aBookarmks.length != aTreeStructure.length) {
-			return;
-		}
-
-		for (let i = 0, maxi = aBookarmks.length; i < maxi; i++)
-		{
-			let item = aBookarmks[i];
-			item.position = this.BookmarksService.getItemIndex(item.id);
-		}
-		aBookarmks.sort(function(aA, aB) {
-			return aA.position - aB.position;
-		});
-
-		for (let i = 0, maxi = aBookarmks.length; i < maxi; i++)
-		{
-			let item = aBookarmks[i];
-			if (this.BookmarksService.getItemType(item.id) != this.BookmarksService.TYPE_BOOKMARK)
-				continue;
-
-			let uri = this.BookmarksService.getBookmarkURI(item.id);
-			if (/^about:treestyletab-group\b/.test(uri.spec)) {
-				let title = this.BookmarksService.getItemTitle(item.id);
-				let folderId = this.BookmarksService.createFolder(item.parent, title, item.position);
-				this.BookmarksService.removeItem(item.id);
-				item.id = folderId;
-				item.isFolder = true;
-			}
-
-			let index = aTreeStructure[i];
-			let parent = index > -1 ? aBookarmks[index] : null ;
-			if (parent && (parent.folder || parent).isFolder) {
-				let folder = parent.isFolder ? parent : parent.folder ;
-				this.BookmarksService.moveItem(item.id, folder.id, -1);
-				item.folder = folder;
-			}
-			if (parent && !parent.isFolder) {
-				PlacesUtils.setAnnotationsForItem(item.id, [{
-					name    : this.kPARENT,
-					value   : parent ? parent.id : -1,
-					expires : PlacesUtils.annotations.EXPIRE_NEVER
-				}]);
-			}
-		}
-	},
- 
-	bookmarkTabSubtree : function TSTBMService_bookmarkTabSubtree(aTabOrTabs) 
-	{
-		var tabs = aTabOrTabs;
-		if (!Array.isArray(tabs)) {
-			tabs = [aTabOrTabs];
-		}
-
-		var folderName = (this.isGroupTab(tabs[0], true) || tabs.length == 1) ?
-						tabs[0].label :
-						null ;
-
-		var b = this.getTabBrowserFromChild(tabs[0]);
-		var bookmarkedTabs = [];
-		for (let i = 0, maxi = tabs.length; i < maxi; i++)
-		{
-			let tab = tabs[i];
-			if (!this.isGroupTab(tab, i == 0)) bookmarkedTabs.push(tab);
-			bookmarkedTabs = bookmarkedTabs.concat(b.treeStyleTab.getDescendantTabs(tab));
-		}
-
-		this.beginAddBookmarksFromTabs(bookmarkedTabs);
-		try {
-			window['piro.sakura.ne.jp'].bookmarkMultipleTabs.addBookmarkFor(bookmarkedTabs, folderName);
-		}
-		catch(e) {
-		}
-		this.endAddBookmarksFromTabs();
-	},
-	bookmarkTabSubTree : function() { return this.bookmarkTabSubtree.apply(this, arguments); }, // obsolete, for backward compatibility
- 
-	getParentItem : function TSTBMService_getParentItem(aId) 
-	{
-		if (aId < 0) return -1;
-		var annotations = PlacesUtils.getAnnotationsForItem(aId);
-		for (let i in annotations)
-		{
-			if (annotations[i].name != this.kPARENT) continue;
-			return parseInt(annotations[i].value);
-		}
-		return -1;
-	},
- 
-	getTreeStructureFromItems : function TSTBMService_getTreeStructureFromItems(aIDs, aDefaultParentID) 
-	{
-		/* this returns a result same to getTreeStructureFromTabs().
-		  [A]     => -1 (parent is not in this tree)
-		    [B]   => 0 (parent is 1st item in this tree)
-		    [C]   => 0 (parent is 1st item in this tree)
-		      [D] => 2 (parent is 2nd in this tree)
-		  [E]     => -1 (parent is not in this tree, and this creates another tree)
-		    [F]   => 0 (parent is 1st item in this another tree)
-		*/
-		if (aDefaultParentID === void(0))
-			aDefaultParentID = -1;
-
-		/* Get array of parents. The index becomes to -1,
-		   if there is NO PARENT or the parent is THE TAB ITSELF. */
-		var treeStructure = aIDs.map(function(aId, aIndex) {
-				let id = this.getParentItem(aId);
-				let index = aIDs.indexOf(id);
-				return index >= aIndex ? aDefaultParentID : index ;
-			}, this);
-
-		/* Correct patterns like:
-		     [TabA]
-		     [TabB] - this has no parent
-		       [TabC] - TabA's child
-		   to:
-		     [TabA]
-		       [TabB]
-		       [TabC]
-		*/
-		treeStructure = treeStructure.reverse();
-		treeStructure = treeStructure.map(function(aPosition, aIndex) {
-				if (aIndex > 0 &&
-					aIndex < treeStructure.length-1 &&
-					aPosition < 0) {
-					aPosition = treeStructure[aIndex-1];
-				}
-				return aPosition;
-			});
-		treeStructure = treeStructure.reverse();
-
-		return this.cleanUpTreeStructureArray(treeStructure, aDefaultParentID);
-	},
- 
-	// based on PlacesUtils.getURLsForContainerNode()
-	getItemIdsForContainerNode : function TSTBMService_getItemIdsForContainerNode(aNode) 
-	{
-		var ids = [];
-		if (!aNode || !PlacesUtils.nodeIsContainer(aNode)) return ids;
-
-		var root = aNode;
-		if ('getContainerNodeWithOptions' in PlacesUtils) {
-			root = PlacesUtils.getContainerNodeWithOptions(root, false, true);
-		}
-		var oldViewer = root.parentResult.viewer;
-		var wasOpen = root.containerOpen;
-		if (!wasOpen) {
-			if (oldViewer)
-				root.parentResult.viewer = null;
-			root.containerOpen = true;
-		}
-		for (let i = 0, maxi = root.childCount; i < maxi; ++i)
-		{
-			let child = root.getChild(i);
-			if (PlacesUtils.nodeIsURI(child)) ids.push(child.itemId || -1);
-		}
-		if (!wasOpen) {
-			root.containerOpen = false;
-			if (oldViewer)
-				root.parentResult.viewer = oldViewer;
-		}
-		return ids;
-	},
 
 
+var TreeStyleTabBookmarksUIService = inherit(TreeStyleTabService, {
 	preInit : function TSTBMService_preInit()
 	{
 		window.addEventListener('load', this, false);
@@ -231,250 +24,35 @@ var TreeStyleTabBookmarksService = inherit(TreeStyleTabService, {
 		window.addEventListener('unload', this, false);
 		ReferenceCounter.add('window,unload,TSTBMService,false');
 
-		if (!('PlacesUIUtils' in window)) return;
-
-		if (!PlacesUIUtils.__treestyletab__done) {
-			var ns = Components.utils.import('resource:///modules/PlacesUIUtils.jsm', {});
-			var sv = this;
-			with (ns) {
-
-			{
-				let method = (TreeStyleTabUtils.getTreePref('compatibility.TabUtilities') && PlacesUIUtils.TU__openTabset) ?
-							'TU__openTabset' :
-							'_openTabset';
-				TreeStyleTabUtils.doPatching(PlacesUIUtils[method], 'PlacesUIUtils.'+method, function(aName, aSource) {
-					var patched = eval(aName+' = '+aSource.replace(
-						/(function[^\(]*\([^\)]+)(\))/,
-						'$1, aFolderTitle$2'
-					).replace(
-						'{',
-						'{ var TSTTreeStructure = null, TSTPreviousTabs, TSTTreeStructureApplied = true, TSTOpenGroupBookmarkBehavior;'
-					).replace(
-						'var urls = [];',
-						'$& var ids = [];'
-					).replace(
-						'urls.push(item.uri);',
-						'if (item.uri) { $& ids.push(item.id); }'
-					).replace(
-						'this.markPageAsTyped(item.uri);',
-						'if (item.uri) { $& }'
-					).replace(
-						/(browserWindow\.(?:getBrowser\(\)|gBrowser)\.loadTabs\([^;]+\);)/,
-						'var TSTResult = browserWindow.TreeStyleTabBookmarksService.handleTabsOpenProcess(where, aEvent, browserWindow, ids, urls, aFolderTitle);\n' +
-						'TSTTreeStructure = TSTResult.treeStructure;\n' +
-						'TSTPreviousTabs = TSTResult.previousTabs;\n' +
-						'TSTTreeStructureApplied = TSTResult.treeStructureApplied;\n' +
-						'TSTOpenGroupBookmarkBehavior = TSTResult.behavior;\n' +
-						'if (typeof replaceCurrentTab != "undefined")\n' +
-						'  replaceCurrentTab = TSTResult.replaceCurrentTab;\n' +
-						'$1'
-					).replace(
-						/(\}\)?)$/,
-						'  if (TSTTreeStructure && TSTPreviousTabs) {\n' +
-						'    let tabs = browserWindow.TreeStyleTabService.getNewTabsFromPreviousTabsInfo(browserWindow.gBrowser, TSTPreviousTabs);\n' +
-						'    if (!TSTTreeStructureApplied)\n' +
-						'      browserWindow.TreeStyleTabService.applyTreeStructureToTabs(tabs, TSTTreeStructure, TSTOpenGroupBookmarkBehavior & browserWindow.TreeStyleTabBookmarksService.kGROUP_BOOKMARK_EXPAND_ALL_TREE);\n' +
-						'    if (!loadInBackground) {\n' +
-						'      browserWindow.setTimeout(function() {\n' +
-						'        browserWindow.gBrowser.treeStyleTab.scrollToTabs(tabs);\n' +
-						'      }, browserWindow.gBrowser.treeStyleTab.collapseDuration); // start scroll after expanding animation is finished\n' +
-						'    }\n' +
-						'  }\n' +
-						'$1'
-					));
-					if (TreeStyleTabUtils.getTreePref('compatibility.TabUtilities') && method.indexOf('TU_') > -1)
-						window[method] = patched;
-					return patched;
-				}, 'TreeStyleTab');
-			}
-
-			{
-				let method = (TreeStyleTabUtils.getTreePref('compatibility.TabUtilities') && PlacesUIUtils.TU_openContainerNodeInTabs) ?
-							'TU_openContainerNodeInTabs' :
-							'openContainerNodeInTabs';
-				TreeStyleTabUtils.doPatching(PlacesUIUtils[method], 'PlacesUIUtils.'+method, function(aName, aSource) {
-					var patched = eval(aName+' = '+aSource.replace(
-						/(this\._openTabset\([^\)]+)(\))/,
-						'{\n' +
-						'  let w = "_getTopBrowserWin" in this ?\n' +
-						'      this._getTopBrowserWin() :\n' +
-						'    "_getCurrentActiveWin" in this ?\n' +
-						'      this._getCurrentActiveWin() :\n' +
-						'      window;\n' +
-						'  let nodes = w.TreeStyleTabBookmarksService.getItemIdsForContainerNode(aNode);\n' +
-						'  for (let i in nodes) {\n' +
-						'    urlsToOpen[i].id = nodes[i];\n' +
-						'  }\n' +
-						'}\n' +
-						'$1, aNode.title$2'
-					));
-					if (TreeStyleTabUtils.getTreePref('compatibility.TabUtilities') && method.indexOf('TU_') > -1)
-						window[method] = patched;
-					return patched;
-				}, 'TreeStyleTab');
-			}
-
-			{
-				let method = (TreeStyleTabUtils.getTreePref('compatibility.TabUtilities') && PlacesUIUtils.TU_openURINodesInTabs) ?
-							'TU_openURINodesInTabs' :
-							'openURINodesInTabs';
-				TreeStyleTabUtils.doPatching(PlacesUIUtils[method], 'PlacesUIUtils.'+method, function(aName, aSource) {
-					var patched = eval(aName+' = '+aSource.replace(
-						'{',
-						'{\n' +
-						'  var TSTBS, TSTUtils;\n' +
-						'  {\n'+
-						'    let w = "_getTopBrowserWin" in this ?\n' +
-						'        this._getTopBrowserWin() :\n' +
-						'      "_getCurrentActiveWin" in this ?\n' +
-						'        this._getCurrentActiveWin() :\n' +
-						'        window;\n' +
-						'    TSTBS = w.TreeStyleTabBookmarksService;\n' +
-						'    TSTUtils = w.TreeStyleTabUtils;\n' +
-						'    PlacesUtils = w.PlacesUtils;\n' +
-						'  }'
-					).replace(
-						'uri: aNodes[i].uri,',
-						'id: aNodes[i].itemId, $&'
-					).replace(
-						/(this\._openTabset\([^\)]+)(\))/,
-						'$1,\n' +
-						'  TSTUtils.treeBundle\n' +
-						'    .getFormattedString(\n' +
-						'      PlacesUtils.nodeIsBookmark(aNodes[0]) ?\n' +
-						'        "openSelectedPlaces.bookmarks" :\n' +
-						'        "openSelectedPlaces.history",\n' +
-						'      [aNodes[0].title, aNodes.length]\n' +
-						'    )\n' +
-						'$2'
-					));
-					if (TreeStyleTabUtils.getTreePref('compatibility.TabUtilities') && method.indexOf('TU_') > -1)
-						window[method] = patched;
-					return patched;
-				}, 'TreeStyleTab');
-			}
-
-			PlacesUIUtils.__treestyletab__done = true;
-
-			} // end of with
-		}
-
 		if ('PlacesCommandHook' in window && 'bookmarkCurrentPages' in PlacesCommandHook) {
 			// Bookmark All Tabs
-			TreeStyleTabUtils.doPatching(PlacesCommandHook.bookmarkCurrentPages, 'PlacesCommandHook.bookmarkCurrentPages', function(aName, aSource) {
-				return eval(aName+' = '+aSource.replace(
-					'{',
-					'{\n' +
-					'  TreeStyleTabBookmarksService.beginAddBookmarksFromTabs((function() {\n' +
-					'    var tabs = [];\n' +
-					'    var seen = {};\n' +
-					'    var allTabs = getBrowser().mTabContainer.childNodes;\n' +
-					'    for (let i = 0, maxi = allTabs.length; i < maxi; i++)\n' +
-					'    {\n' +
-					'      let tab = allTabs[i];\n' +
-					'      let uri = tab.linkedBrowser.currentURI.spec;\n' +
-					'      if (uri in seen) continue;\n' +
-					'      seen[uri] = true;\n' +
-					'      tabs.push(tab);\n' +
-					'    }\n' +
-					'    return tabs;\n' +
-					'  })());\n' +
-					'  try {'
-				).replace(
-					/(\}\)?)$/,
-					'  }\n' +
-					'  catch(e) {\n' +
-					'  }\n' +
-					'  TreeStyleTabBookmarksService.endAddBookmarksFromTabs();\n' +
-					'$1'
-				));
-			}, 'TreeStyleTab');
-		}
-	},
-	handleTabsOpenProcess : function TSTBMService_handleTabsOpenProcess(aWhere, aEvent, aBrowserWindow, aIDs, aURLs, aFolderTitle)
-	{
-		var result = {
-				behavior      : undefined,
-				treeStructure : undefined,
-				previousTabs  : undefined,
-				treeStructureApplied : false
-			};
-		if (
-			aEvent.type != 'drop' &&
-			aWhere.indexOf('tab') != 0 &&
-			aEvent.target.id != 'placesContext_openContainer:tabs' &&
-			aEvent.target.id != 'placesContext_openLinks:tabs' &&
-			aEvent.target != aEvent.target.parentNode._endOptOpenAllInTabs &&
-			aEvent.target.getAttribute('openInTabs') != 'true'
-			)
-			return result;
-
-		var sv = aBrowserWindow.TreeStyleTabBookmarksService;
-		result.behavior = sv.openGroupBookmarkBehavior();
-		if (result.behavior & sv.kGROUP_BOOKMARK_SUBTREE) {
-			let treeStructure = result.behavior & sv.kGROUP_BOOKMARK_DONT_RESTORE_TREE_STRUCTURE ?
-						null :
-						sv.getTreeStructureFromItems(aIDs) ;
-			if (treeStructure) {
-				let parentTabs = treeStructure.filter(function(aParent) {
-						return aParent < 0;
-					});
-				let haveMultipleTrees = parentTabs.length != treeStructure.length;
-				if (result.behavior & sv.kGROUP_BOOKMARK_USE_DUMMY) {
-					let parentCount = 0;
-					let childCount = 0;
-					for (let i in treeStructure) {
-						if (treeStructure[i] == -1)
-							parentCount++;
-						else
-							childCount++;
-					}
-					if (
-						parentCount > 1 &&
-						(
-							result.behavior & sv.kGROUP_BOOKMARK_USE_DUMMY_FORCE ||
-							// when there is any orphan, then all of parents and orphans should be grouped under a dummy tab.
-							childCount < parentCount
-						)
-						) {
-						aIDs.unshift(-1);
-						treeStructure = sv.getTreeStructureFromItems(aIDs, 0);
-						aURLs.unshift(sv.getGroupTabURI({
-							title:     aFolderTitle,
-							temporary: TreeStyleTabUtils.getTreePref('openGroupBookmark.temporaryGroup')
-						}));
+			PlacesCommandHook.__treestyletab__bookmarkCurrentPages = PlacesCommandHook.bookmarkCurrentPages;
+			PlacesCommandHook.bookmarkCurrentPages = function(...aArgs) {
+				TreeStyleTabBookmarksService.beginAddBookmarksFromTabs((function() {
+					var tabs = [];
+					var seen = {};
+					var allTabs = gBrowser.mTabContainer.childNodes;
+					for (let i = 0, maxi = allTabs.length; i < maxi; i++)
+					{
+						let tab = allTabs[i];
+						let uri = tab.linkedBrowser.currentURI.spec;
+						if (uri in seen)
+							continue;
+						seen[uri] = true;
+						tabs.push(tab);
 					}
+					return tabs;
+				})());
+				try {
+					return this.__treestyletab__bookmarkCurrentPages.apply(this, aArgs);
 				}
-				else if (!haveMultipleTrees) {
-					// make the first item parent.
-					treeStructure = treeStructure.map(function(aParent, aIndex) {
-						if (aIndex == 0)
-							return aParent;
-						if (aParent < 0)
-							return 0;
-						return aParent;
-					});
+				finally {
+					TreeStyleTabBookmarksService.endAddBookmarksFromTabs();
 				}
-			}
-
-			result.treeStructure = treeStructure;
-			result.previousTabs = aBrowserWindow.TreeStyleTabService.getTabsInfo(aBrowserWindow.gBrowser);
-
-			if (TreeStyleTabUtils.getTreePref('compatibility.TMP') &&
-				'TMP_Places' in aBrowserWindow &&
-				'openGroup' in aBrowserWindow.TMP_Places) {
-				result.treeStructureApplied = false;
-			}
-			else {
-				sv.readyToOpenNewTabGroup(null, treeStructure, result.behavior & sv.kGROUP_BOOKMARK_EXPAND_ALL_TREE);
-				result.treeStructureApplied = true;
-			}
+			};
 		}
-		return result;
 	},
 
-
-
 	destroy : function TSTBMService_destroy()
 	{
 		window.removeEventListener('unload', this, false);
@@ -483,22 +61,6 @@ var TreeStyleTabBookmarksService = inherit(TreeStyleTabService, {
 		ReferenceCounter.remove('window,EVENT_TYPE_TABS_DROP,TSTBMService,false');
 	},
 
-	// observer for nsINavBookmarksService 
-	onItemAdded : function TSTBMService_onItemAdded(aID, aFolderID, aPosition)
-	{
-		this._addingBookmarks.push({
-			id     : aID,
-			parent : aFolderID
-		});
-	},
-	onItemRemoved : function TSTBMService_onItemRemoved(aID, aFolderID, aPosition) {},
-	onItemMoved : function TSTBMService_onItemMoved(aID, aFolderID, aPosition) {},
-	onItemChanged : function TSTBMService_onItemChanged(aID, aChange, aIsAnnotation, aNewValue) {},
-	onItemVisited : function TSTBMService_onItemVisited(aID, aHistoryID, aDate) {},
-	onBeginUpdateBatch : function TSTBMService_onBeginUpdateBatch() {},
-	onEndUpdateBatch : function TSTBMService_onEndUpdateBatch() {},
-
-
 	_onTabsDrop : function TSTBMService_onTabsDrop(aEvent)
 	{
 		var tabs = aEvent.detail.tabs;
@@ -533,7 +95,7 @@ var TreeStyleTabBookmarksService = inherit(TreeStyleTabService, {
 
 });
 
-TreeStyleTabBookmarksService.preInit();
+TreeStyleTabBookmarksUIService.preInit();
 
-window.TreeStyleTabBookmarksService = TreeStyleTabBookmarksService;
+window.TreeStyleTabBookmarksUIService = TreeStyleTabBookmarksUIService;
 })();
diff --git a/content/treestyletab/bookmarksOverlayEditable.js b/content/treestyletab/bookmarksOverlayEditable.js
index aa5b429..38f89f0 100644
--- a/content/treestyletab/bookmarksOverlayEditable.js
+++ b/content/treestyletab/bookmarksOverlayEditable.js
@@ -1,11 +1,21 @@
 Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this,
   'TreeStyleTabUtils', 'resource://treestyletab-modules/utils.js');
+XPCOMUtils.defineLazyModuleGetter(this,
+  'TreeStyleTabBookmarksService', 'resource://treestyletab-modules/bookmark.js');
 
 (function() {
 let { ReferenceCounter } = Components.utils.import('resource://treestyletab-modules/ReferenceCounter.js', {});
 let { inherit } = Components.utils.import('resource://treestyletab-modules/lib/inherit.jsm', {});
-var TreeStyleTabBookmarksServiceEditable = inherit(TreeStyleTabBookmarksService, {
+
+function log(...aArgs) {
+	TreeStyleTabUtils.log.apply(TreeStyleTabUtils, ['bookmark'].concat(aArgs));
+}
+function logWithStackTrace(...aArgs) {
+	TreeStyleTabUtils.logWithStackTrace.apply(TreeStyleTabUtils, ['bookmark'].concat(aArgs));
+}
+
+var TreeStyleTabBookmarksServiceEditable = inherit(TreeStyleTabBookmarksUIService, {
 
 	instantApply : false,
 	canceled : false,
@@ -44,7 +54,8 @@ var TreeStyleTabBookmarksServiceEditable = inherit(TreeStyleTabBookmarksService,
 
 	init : function TSTBMEditable_init()
 	{
-		if (this.isCreatingMultipleBookmarksInFolder) return;
+		if (this.isCreatingMultipleBookmarksInFolder)
+			return;
 
 		// main browser window
 		if ('StarUI' in window) {
@@ -56,7 +67,7 @@ var TreeStyleTabBookmarksServiceEditable = inherit(TreeStyleTabBookmarksService,
 
 			StarUI.__treestyletab__quitEditMode = StarUI.__treestyletab__quitEditMode || StarUI.quitEditMode;
 			StarUI.quitEditMode = function(...args) {
-				TreeStyleTabBookmarksServiceEditable.saveParentFor(this._itemId);
+				TreeStyleTabBookmarksServiceEditable.saveParentFor(gEditItemOverlay.itemId);
 				return this.__treestyletab__quitEditMode.apply(this, args);
 			};
 
@@ -69,12 +80,37 @@ var TreeStyleTabBookmarksServiceEditable = inherit(TreeStyleTabBookmarksService,
 
 		// Bookmarks Property dialog
 		if ('BookmarkPropertiesPanel' in window) {
-			TreeStyleTabUtils.doPatching(BookmarkPropertiesPanel._endBatch, 'BookmarkPropertiesPanel._endBatch', function(aName, aSource) {
-				return eval(aName+' = '+aSource.replace(
-					/(PlacesUtils\.transactionManager\.endBatch\([^)]*\);)/,
-					'$1 TreeStyleTabBookmarksServiceEditable.saveParentFor(this._itemId, true);'
-				));
-			}, 'TreeStyleTab');
+			BookmarkPropertiesPanel.__treestyletab__onDialogAccept = BookmarkPropertiesPanel.onDialogAccept;
+			BookmarkPropertiesPanel.onDialogAccept = function(...aArgs) {
+				try {
+					TreeStyleTabBookmarksServiceEditable.saveParentFor(gEditItemOverlay.itemId, true);
+				}
+				catch(e) {
+					log(e);
+				}
+				return this.__treestyletab__onDialogAccept.apply(this, aArgs);
+			};
+
+			BookmarkPropertiesPanel.__treestyletab__endBatch = BookmarkPropertiesPanel._endBatch;
+			BookmarkPropertiesPanel._endBatch = function(...aArgs) {
+				var id = this.__treestyletab__itemId || gEditItemOverlay.itemId;
+				log('BookmarkPropertiesPanel._endBatch for '+id);
+				var batching = this._batching;
+				var result = this.__treestyletab__endBatch.apply(this, aArgs);
+				if (id >= 0 && !batching && !this._batching) {
+					this._batching = true;
+					try {
+						TreeStyleTabBookmarksServiceEditable.saveParentFor(id, true);
+					}
+					catch(e) {
+						log(e);
+					}
+					finally {
+						this._batching = false;
+					}
+				}
+				return result;
+			};
 		}
 
 		// Places Organizer (Library)
@@ -119,42 +155,24 @@ var TreeStyleTabBookmarksServiceEditable = inherit(TreeStyleTabBookmarksService,
 		document.getElementById('treestyletab-parent-label').setAttribute('value', TreeStyleTabUtils.treeBundle.getString('bookmarkProperty.parent.label'));
 		this.blankItem.setAttribute('label', TreeStyleTabUtils.treeBundle.getString('bookmarkProperty.parent.blank.label'));
 
-		if (Services.vc.compare(Services.appinfo.platformVersion, '40') >= 0) {
-			// for Firefox 40 and later, after Bug 951651
-			TreeStyleTabUtils.doPatching(gEditItemOverlay.initPanel, 'gEditItemOverlay.initPanel', function(aName, aSource) {
-				return eval(aName+' = '+aSource.replace(
-					/(\}\)?)$/,
-					'  TreeStyleTabBookmarksServiceEditable.parentRow.collapsed = this._element("keywordRow").collapsed && this._element("folderRow").collapsed;\n' +
-					'  if (!TreeStyleTabBookmarksServiceEditable.parentRow.collapsed)\n' +
-					'    TreeStyleTabBookmarksServiceEditable.initParentMenuList();\n' +
-					'$1'
-				));
-			}, 'TreeStyleTab');
-		}
-		else {
-			// 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');
-
-			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');
-		}
-
-		TreeStyleTabUtils.doPatching(gEditItemOverlay.onItemMoved, 'gEditItemOverlay.onItemMoved', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'{',
-				'$& if (aNewParent == this._getFolderIdFromMenuList()) TreeStyleTabBookmarksServiceEditable.initParentMenuList();'
-			));
-		}, 'TreeStyleTab');
+		gEditItemOverlay.__treestyletab__initPanel = gEditItemOverlay.initPanel;
+		gEditItemOverlay.initPanel = function(...aArgs) {
+			var result = this.__treestyletab__initPanel.apply(this, aArgs);
+			TreeStyleTabBookmarksServiceEditable.parentRow.collapsed = (
+				this._element('keywordRow').collapsed &&
+				this._element('folderRow').collapsed
+			);
+			if (!TreeStyleTabBookmarksServiceEditable.parentRow.collapsed)
+				TreeStyleTabBookmarksServiceEditable.initParentMenuList();
+			return result;
+		};
+
+		gEditItemOverlay.__treestyletab__onItemMoved = gEditItemOverlay.onItemMoved;
+		gEditItemOverlay.onItemMoved = function(aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex, aItemType, ...aArgs) {
+			if (aNewParent == this._getFolderIdFromMenuList())
+				TreeStyleTabBookmarksServiceEditable.initParentMenuList();
+			return this.__treestyletab__onItemMoved.apply(this, [aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex, aItemType].concat(aArgs));
+		};
 
 		this.editUIInitialized = true;
 	},
@@ -255,7 +273,7 @@ var TreeStyleTabBookmarksServiceEditable = inherit(TreeStyleTabBookmarksService,
 	},
 	_createSiblingsFragmentInternal : function TSTBMEditable_createSiblingsFragmentInternal(aCurrentItem, aItems, aCallback)
 	{
-		var treeStructure = this.getTreeStructureFromItems(aItems);
+		var treeStructure = TreeStyleTabBookmarksService.getTreeStructureFromItems(aItems);
 
 		var currentIndex = aItems.indexOf(aCurrentItem);
 		var selected = treeStructure[currentIndex];
@@ -327,13 +345,20 @@ var TreeStyleTabBookmarksServiceEditable = inherit(TreeStyleTabBookmarksService,
 	},
 	_getSiblingItemsIterator : function TSTBMEditable_getSiblingItemsIterator(aId)
 	{
-		return this._getItemsInFolderIterator(PlacesUtils.bookmarks.getFolderIdForItem(aId));
+		var folderId = -1;
+		try {
+			folderId = PlacesUtils.bookmarks.getFolderIdForItem(aId);
+		}
+		catch(e) {
+		}
+		return this._getItemsInFolderIterator(folderId);
 	},
 
 	saveParentFor : function TSTBMEditable_saveParentFor(aId, aJustNow)
 	{
 		var newParentId = parseInt(this.menulist.value || -1);
-		if (this.canceled || newParentId == this.getParentItem(aId)) return;
+		if (this.canceled || newParentId == TreeStyleTabBookmarksService.getParentItem(aId))
+			return;
 
 		var itemsIterator = this._getSiblingItemsIterator(aId);
 		var items = [];
@@ -350,7 +375,7 @@ var TreeStyleTabBookmarksServiceEditable = inherit(TreeStyleTabBookmarksService,
 	},
 	_saveParentForInternal : function TSTBMEditable_saveParentForInternal(aId, aNewParentId, aItems)
 	{
-		var treeStructure = this.getTreeStructureFromItems(aItems);
+		var treeStructure = TreeStyleTabBookmarksService.getTreeStructureFromItems(aItems);
 
 		var parentIndex = aItems.indexOf(aNewParentId);
 		var newIndex;
diff --git a/content/treestyletab/config.xul b/content/treestyletab/config.xul
index 7c06f7c..c85a27d 100644
--- a/content/treestyletab/config.xul
+++ b/content/treestyletab/config.xul
@@ -750,6 +750,7 @@
 			oncommand="syncEnabledState(this, this.value == 0);"
 			sync-enabled-state-targets="extensions.treestyletab.closeRootBehavior-check">
 			<radio value="2" label="&config.closeParentBehavior.close;"/>
+			<radio value="5" label="&config.closeParentBehavior.replaceWithGroupTab;"/>
 			<radio value="3" label="&config.closeParentBehavior.promoteFirst;"/>
 			<radio value="0" label="&config.closeParentBehavior.promoteAll;"/>
 			<hbox align="center">
diff --git a/content/treestyletab/license.txt b/content/treestyletab/license.txt
index 62dcd4b..c35e8f1 100644
--- a/content/treestyletab/license.txt
+++ b/content/treestyletab/license.txt
@@ -14,7 +14,7 @@ License.
 The Original Code is the Tree Style Tab.
 
 The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
-Portions created by the Initial Developer are Copyright (C) 2007-2014
+Portions created by the Initial Developer are Copyright (C) 2007-2016
 the Initial Developer. All Rights Reserved.
 
 Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
diff --git a/content/treestyletab/treestyletab.css b/content/treestyletab/treestyletab.css
index bae0f28..ecf5c54 100644
--- a/content/treestyletab/treestyletab.css
+++ b/content/treestyletab/treestyletab.css
@@ -447,6 +447,7 @@ toolbar.treestyletab-tabbar-toolbar-ready:not([nowindowdrag="true"]),
 	                 margin-right 0.2s ease-out,
 	                 margin-top 0.15s ease-out,
 	                 opacity 0.15s ease-out,
+	                 outline-color 0.5s ease-out,
 	                 min-height 0.15s ease-out,
 	                 max-height 0.15s ease-out,
 	                 min-width 0.15s ease-out /* for Firefox itself */,
@@ -455,6 +456,7 @@ toolbar.treestyletab-tabbar-toolbar-ready:not([nowindowdrag="true"]),
 	            margin-right 0.2s ease-out,
 	            margin-top 0.15s ease-out,
 	            opacity 0.15s ease-out,
+                outline-color 0.5s ease-out,
 	            min-height 0.15s ease-out,
 	            max-height 0.15s ease-out,
 	            min-width 0.15s ease-out /* for Firefox itself */,
@@ -466,6 +468,7 @@ toolbar.treestyletab-tabbar-toolbar-ready:not([nowindowdrag="true"]),
 	                 margin-right 0.2s ease-out,
 	                 margin-top 0.15s ease-out,
 	                 opacity 0.15s ease-out,
+	                 outline-color 0.5s ease-out,
 	                 min-height 0.15s ease-out,
 	                 max-height 0.15s ease-out,
 	                 min-width 0.15s ease-out /* for Firefox itself */,
@@ -475,6 +478,7 @@ toolbar.treestyletab-tabbar-toolbar-ready:not([nowindowdrag="true"]),
 	            margin-right 0.2s ease-out,
 	            margin-top 0.15s ease-out,
 	            opacity 0.15s ease-out,
+	            outline-color 0.5s ease-out,
 	            min-height 0.15s ease-out,
 	            max-height 0.15s ease-out,
 	            min-width 0.15s ease-out /* for Firefox itself */,
@@ -486,6 +490,7 @@ toolbar.treestyletab-tabbar-toolbar-ready:not([nowindowdrag="true"]),
   .tabbrowser-tab:not([treestyletab-collapsed-done="true"]) {
 	-moz-transition: margin-left 0.15s ease-out,
 	                 opacity 0.15s ease-out,
+	                 outline-color 0.5s ease-out,
 	                 margin-top 0.2s ease-out,
 	                 min-height 0.15s ease-out,
 	                 max-height 0.15s ease-out,
@@ -493,6 +498,7 @@ toolbar.treestyletab-tabbar-toolbar-ready:not([nowindowdrag="true"]),
 	                 max-width 0.15s ease-out /* for Firefox itself */;
 	transition: margin-left 0.15s ease-out,
 	            opacity 0.15s ease-out,
+                outline-color 0.5s ease-out,
 	            margin-top 0.2s ease-out,
 	            min-height 0.15s ease-out,
 	            max-height 0.15s ease-out,
@@ -503,6 +509,7 @@ toolbar.treestyletab-tabbar-toolbar-ready:not([nowindowdrag="true"]),
   .tabbrowser-tab:not([treestyletab-collapsed-done="true"]) {
 	-moz-transition: margin-left 0.15s ease-out,
 	                 opacity 0.15s ease-out,
+	                 outline-color 0.5s ease-out,
 	                 margin-top 0.2s ease-out,
 	                 min-height 0.15s ease-out,
 	                 max-height 0.15s ease-out,
@@ -511,6 +518,7 @@ toolbar.treestyletab-tabbar-toolbar-ready:not([nowindowdrag="true"]),
 	                 transform 0.2s ease-out /* for Firefox itself */;
 	transition: margin-left 0.15s ease-out,
 	            opacity 0.15s ease-out,
+                outline-color 0.5s ease-out,
 	            margin-top 0.2s ease-out,
 	            min-height 0.15s ease-out,
 	            max-height 0.15s ease-out,
@@ -523,6 +531,7 @@ toolbar.treestyletab-tabbar-toolbar-ready:not([nowindowdrag="true"]),
   .tabbrowser-tab:not([treestyletab-collapsed-done="true"]) {
 	-moz-transition: margin-left 0.15s ease-out,
 	                 opacity 0.15s ease-out,
+	                 outline-color 0.5s ease-out,
 	                 margin-bottom 0.2s ease-out,
 	                 min-height 0.15s ease-out,
 	                 max-height 0.15s ease-out,
@@ -530,6 +539,7 @@ toolbar.treestyletab-tabbar-toolbar-ready:not([nowindowdrag="true"]),
 	                 max-width 0.15s ease-out /* for Firefox itself */;
 	transition: margin-left 0.15s ease-out,
 	            opacity 0.15s ease-out,
+                outline-color 0.5s ease-out,
 	            margin-bottom 0.2s ease-out,
 	            min-height 0.15s ease-out,
 	            max-height 0.15s ease-out,
@@ -540,6 +550,7 @@ toolbar.treestyletab-tabbar-toolbar-ready:not([nowindowdrag="true"]),
   .tabbrowser-tab:not([treestyletab-collapsed-done="true"]) {
 	-moz-transition: margin-left 0.15s ease-out,
 	                 opacity 0.15s ease-out,
+	                 outline-color 0.5s ease-out,
 	                 margin-bottom 0.2s ease-out,
 	                 min-height 0.15s ease-out,
 	                 max-height 0.15s ease-out,
@@ -548,6 +559,7 @@ toolbar.treestyletab-tabbar-toolbar-ready:not([nowindowdrag="true"]),
 	                 transform 0.2s ease-out /* for Firefox itself */;
 	transition: margin-left 0.15s ease-out,
 	            opacity 0.15s ease-out,
+                outline-color 0.5s ease-out,
 	            margin-bottom 0.2s ease-out,
 	            min-height 0.15s ease-out,
 	            max-height 0.15s ease-out,
diff --git a/content/treestyletab/treestyletab.js b/content/treestyletab/treestyletab.js
index 4b63e06..4dc1cfc 100644
--- a/content/treestyletab/treestyletab.js
+++ b/content/treestyletab/treestyletab.js
@@ -23,7 +23,9 @@
 	}, false);
 	ReferenceCounter.add('window,aEvent.type,onDOMContentLoaded,false');
 
-	var ns = {};
-	Components.utils.import('resource://treestyletab-modules/window.js', ns);
-	new ns.TreeStyleTabWindow(window);
+	var { TreeStyleTabUtils } = Components.utils.import('resource://treestyletab-modules/utils.js', {});
+	window.TreeStyleTabUtils = TreeStyleTabUtils;
+
+	var { TreeStyleTabWindow } = Components.utils.import('resource://treestyletab-modules/window.js', {});
+	new TreeStyleTabWindow(window);
 })();
diff --git a/content/treestyletab/treestyletab.xul b/content/treestyletab/treestyletab.xul
index 5b7d51d..6065ef6 100644
--- a/content/treestyletab/treestyletab.xul
+++ b/content/treestyletab/treestyletab.xul
@@ -84,7 +84,7 @@
 				event.stopPropagation();
 				this.parentNode.hidePopup();
 			}"
-			multipletab-insertbefore="TreeStyleTabService.evaluateXPath(
+			multipletab-insertbefore="TreeStyleTabUtils.evaluateXPath(
 				"(descendant::*[starts-with(@id, 'multipletab-context-removeAll') | starts-with(@id, 'context_closeTab')][1] | child::xul:menuitem[last()])/preceding-sibling::xul:menuseparator[1]"
 			, tabContextMenu, XPathResult.FIRST_ORDERED_NODE_TYPE).singleNodeValue"/>
 		<menuitem id="context-item-removeDescendantTabs"
@@ -107,7 +107,7 @@
 			label="&context.bookmarkTabSubtree.label;"
 			accesskey="&context.bookmarkTabSubtree.accesskey;"
 			oncommand="TreeStyleTabBookmarksService.bookmarkTabSubtree(TreeStyleTabService.getTabBrowserFromChild(this).mContextTab);"
-			multipletab-insertafter="TreeStyleTabService.evaluateXPath(
+			multipletab-insertafter="TreeStyleTabUtils.evaluateXPath(
 				"descendant::*[starts-with(@id, 'context_bookmarkTab')][1] | descendant::*[@command='Browser:BookmarkAllTabs']/preceding-sibling[1]"
 			, tabContextMenu, XPathResult.FIRST_ORDERED_NODE_TYPE).singleNodeValue"/>
 
diff --git a/content/treestyletab/windowHelper.js b/content/treestyletab/windowHelper.js
index 1b35e03..1d2e301 100644
--- a/content/treestyletab/windowHelper.js
+++ b/content/treestyletab/windowHelper.js
@@ -31,7 +31,7 @@ var TreeStyleTabWindowHelper = {
 				else
 					where = TreeStyleTabUtils.prefs.getPref('browser.link.open_newwindow');
 			}
-			TreeStyleTabService.onBeforeBrowserAccessOpenURI(aOpener, where, aContext);
+			TreeStyleTabService.onBeforeBrowserAccessOpenURI(aOpener, where);
 			return nsBrowserAccess.prototype.__treestyletab__openURI.call(this, aURI, aOpener, aWhere, aContext);
 		};
 
@@ -69,25 +69,34 @@ var TreeStyleTabWindowHelper = {
 			return tab;
 		};
 
-		[
-			'window.duplicateTab.handleLinkClick',
-			'window.duplicatethistab.handleLinkClick',
-			'window.__treestyletab__highlander__origHandleLinkClick',
-			'window.__splitbrowser__handleLinkClick',
-			'window.__ctxextensions__handleLinkClick',
-			'window.handleLinkClick'
-		].some(function(aName) {
-			let func = this._getFunction(aName);
-			if (!func || !/^\(?function handleLinkClick/.test(func.toString()))
-				return false;
-			TreeStyleTabUtils.doPatching(func, aName, function(aName, aSource) {
-				return eval(aName+' = '+aSource.replace(
-					/(charset\s*:\s*doc\.characterSet\s*)/,
-					'$1, event : event, linkNode : linkNode'
-				));
-			}, 'event : event, linkNode : linkNode');
-			return true;
-		}, this);
+		window.__treestyletab__openLinkIn = window.openLinkIn;
+		window.openLinkIn = function(aUrl, aWhere, aParams, ...aArgs) {
+			if (window.__treestyletab__openLinkIn_extraParams)
+				Object.keys(window.__treestyletab__openLinkIn_extraParams).forEach(function(aKey) {
+					aParams[aKey] = window.__treestyletab__openLinkIn_extraParams[aKey];
+				});
+			try {
+				TreeStyleTabService.onBeforeOpenLinkWithTab(gBrowser.selectedTab, aParams);
+				return window.__treestyletab__openLinkIn.apply(this, [aUrl, aWhere, aParams].concat(aArgs));
+			}
+			finally {
+				delete window.__treestyletab__openLinkIn_extraParams;
+			}
+		};
+
+		window.__treestyletab__handleLinkClick = window.handleLinkClick;
+		window.handleLinkClick = function(aEvent, aHref, aLinkNode, ...aArgs) {
+			window.__treestyletab__openLinkIn_extraParams = {
+				event    : aEvent,
+				linkNode : aLinkNode
+			};
+			try {
+				return window.__treestyletab__handleLinkClick.apply(this, [aEvent, aHref, aLinkNode].concat(aArgs));
+			}
+			finally {
+				delete window.__treestyletab__openLinkIn_extraParams;
+			}
+		};
 
 		this.overrideExtensionsPreInit(); // windowHelperHacks.js
 	},
@@ -223,12 +232,6 @@ var TreeStyleTabWindowHelper = {
 			return BrowserSearch.__treestyletab__loadSearch.call(this, aSearchText, aUseNewTab, aPurpose);
 		};
 
-		window.__treestyletab__openLinkIn = window.openLinkIn;
-		window.openLinkIn = function(aUrl, aWhere, aParams) {
-			TreeStyleTabService.onBeforeOpenLinkWithTab(gBrowser.selectedTab, aParams.fromChrome);
-			return window.__treestyletab__openLinkIn.call(this, aUrl, aWhere, aParams);
-		};
-
 		[
 			{ owner: window.permaTabs && window.permaTabs.utils && window.permaTabs.utils.wrappedFunctions,
 			  name:  'window.contentAreaClick' },
@@ -263,21 +266,11 @@ var TreeStyleTabWindowHelper = {
 			return window.__treestyletab__duplicateTabIn.call(this, aTab, where, delta);
 		};
 
-		[
-			'permaTabs.utils.wrappedFunctions["window.BrowserHomeClick"]',
-			'window.BrowserHomeClick',
-			'window.BrowserGoHome'
-		].forEach(function(aName) {
-			let func = this._getFunction(aName);
-			if (!func || !/^\(?function (BrowserHomeClick|BrowserGoHome)/.test(func.toString()))
-				return;
-			TreeStyleTabUtils.doPatching(func, aName, function(aName, aSource) {
-				return eval(aName+' = '+aSource.replace(
-					'gBrowser.loadTabs(',
-					'TreeStyleTabService.readyToOpenNewTabGroup(gBrowser); $&'
-				));
-			}, 'TreeStyleTab');
-		}, this);
+		window.__treestyletab__BrowserGoHome = window.BrowserGoHome;
+		window.BrowserGoHome = function(aEvent) {
+			TreeStyleTabService.onBeforeGoHome(aEvent, gBrowser);
+			return window.__treestyletab__BrowserGoHome.call(this, aEvent);
+		};
 
 		FeedHandler.__treestyletab__loadFeed = FeedHandler.loadFeed;
 		FeedHandler.loadFeed = function(aHref, aEvent) {
@@ -455,23 +448,17 @@ var TreeStyleTabWindowHelper = {
 			return eval(aName+' = '+aSource.replace(
 				'if (nextTab)',
 				'(function() {\n' +
-				'  if (this.treeStyleTab.hasChildTabs(this.mCurrentTab)) {\n' +
-				'    let descendant = this.treeStyleTab.getDescendantTabs(this.mCurrentTab);\n' +
-				'    if (descendant.length)\n' +
-				'      nextTab = this.treeStyleTab.getNextTab(descendant[descendant.length-1]);\n' +
+				'  let descendants = this.treeStyleTab.getDescendantTabs(this.mCurrentTab);\n' +
+				'  if (descendants.indexOf(nextTab) > -1) {\n' +
+				'    let lastDescendant = this.treeStyleTab.getLastDescendantTab(this.mCurrentTab);\n' +
+				'    nextTab = this.treeStyleTab.getNextVisibleTab(lastDescendant || this.mCurrentTab);\n' +
+				'  }\n' +
+				'  if (this.treeStyleTab.hasChildTabs(nextTab) && this.treeStyleTab.isSubtreeCollapsed(nextTab)) {\n' +
+				'    nextTab = this.treeStyleTab.getLastDescendantTab(nextTab);\n' +
 				'  }\n' +
 				'}).call(this);' +
 				'$&'
 			).replace(
-				/(this.moveTabTo\([^;]+\);)/,
-				'(function() {\n' +
-				'  let descendant = this.treeStyleTab.getDescendantTabs(nextTab);\n' +
-				'  if (descendant.length) {\n' +
-				'    nextTab = descendant[descendant.length-1];\n' +
-				'  }\n' +
-				'  $1\n' +
-				'}).call(this);'
-			).replace(
 				'this.moveTabToStart();',
 				'(function() {\n' +
 				'  this.treeStyleTab.internallyTabMovingCount++;\n' +
@@ -490,6 +477,12 @@ var TreeStyleTabWindowHelper = {
 
 		TreeStyleTabUtils.doPatching(b.moveTabBackward, 'b.moveTabBackward', function(aName, aSource) {
 			return eval(aName+' = '+aSource.replace(
+				'if (previousTab)',
+				'(function() {\n' +
+				'  previousTab = this.treeStyleTab.getPreviousVisibleTab(this.mCurrentTab);\n' +
+				'}).call(this);' +
+				'$&'
+			).replace(
 				'this.moveTabToEnd();',
 				'(function() {\n' +
 				'  this.treeStyleTab.internallyTabMovingCount++;\n' +
@@ -506,24 +499,34 @@ var TreeStyleTabWindowHelper = {
 			));
 		}, 'treeStyleTab');
 
-		TreeStyleTabUtils.doPatching(b.loadTabs, 'b.loadTabs', function(aName, aSource) {
-			return eval(aName+' = '+aSource.replace(
-				'var tabNum = ',
-				'if (this.treeStyleTab.readiedToAttachNewTabGroup)\n' +
-				'  TreeStyleTabService.readyToOpenChildTab(firstTabAdded || this.selectedTab, true);\n' +
-				'$&'
-			).replace(
-				'if (!aLoadInBackground)',
-				'if (TreeStyleTabService.checkToOpenChildTab(this))\n' +
-				'  TreeStyleTabService.stopToOpenChildTab(this);\n' +
-				'$&'
-			).replace(
-				'this.selectedTab = firstTabAdded;',
-				'this.selectedTab = aURIs[0].indexOf("about:treestyletab-group") < 0 ? \n' +
-				'  firstTabAdded :\n' +
-				'  TreeStyleTabService.getNextTab(firstTabAdded) ;'
-			));
-		}, 'TreeStyleTab');
+		b.__treestyletab__loadTabs = b.loadTabs;
+		b.loadTabs = function(aURIs, aLoadInBackground, aReplace, ...aArgs) {
+			if (aReplace)
+				this.treeStyleTab.readyToOpenChildTab(this.selectedTab, true);
+			else if (typeof this.treeStyleTab.nextOpenedTabToBeParent == 'undefined')
+				this.treeStyleTab.nextOpenedTabToBeParent = true;
+
+			var result;
+			var tabs = [];
+			var firstTabAdded;
+			try {
+				tabs = this.treeStyleTab.doAndGetNewTabs((function() {
+						result = this.__treestyletab__loadTabs.apply(this, [aURIs, aLoadInBackground, aReplace].concat(aArgs));
+					}).bind(this));
+				firstTabAdded = tabs[0];
+			}
+			finally {
+				if (!aReplace && firstTabAdded) {
+					this.selectedTab = aURIs[0].indexOf('about:treestyletab-group') == 0 ?
+						TreeStyleTabService.getNextTab(firstTabAdded) :
+						firstTabAdded;
+				}
+				if (this.treeStyleTab.checkToOpenChildTab(this))
+					this.treeStyleTab.stopToOpenChildTab(this);
+				delete this.treeStyleTab.nextOpenedTabToBeParent;
+			}
+			return result;
+		};
 
 		TreeStyleTabUtils.doPatching(b._beginRemoveTab, 'b._beginRemoveTab', function(aName, aSource) {
 			return eval(aName+' = '+aSource.replace(
diff --git a/content/treestyletab/windowHelperHacks.js b/content/treestyletab/windowHelperHacks.js
index af5fbb2..5892849 100644
--- a/content/treestyletab/windowHelperHacks.js
+++ b/content/treestyletab/windowHelperHacks.js
@@ -1122,7 +1122,7 @@ TreeStyleTabWindowHelper.overrideExtensionsAfterBrowserInit = function TSTWH_ove
 						return;
 
 					case 'click':
-						if (sv.evaluateXPath(
+						if (TreeStyleTabUtils.evaluateXPath(
 								'ancestor-or-self::*['
 									+'contains(concat(" ", normalize-space(@class), " "), " textbox-presentation-segment ")'
 								+']',
diff --git a/defaults/preferences/treestyletab.js b/defaults/preferences/treestyletab.js
index 3c2a2ba..70390fd 100644
--- a/defaults/preferences/treestyletab.js
+++ b/defaults/preferences/treestyletab.js
@@ -68,7 +68,7 @@ pref("extensions.treestyletab.tabbar.invertScrollbar", true);
  * This option works only for vertical tab bar.
  */
 pref("extensions.treestyletab.tabbar.narrowScrollbar", true);
-pref("extensions.treestyletab.tabbar.narrowScrollbar.size", "10px");
+pref("extensions.treestyletab.tabbar.narrowScrollbar.width", 10);
 
 /**
  * On some environments (ex. GNOME3 on Linux), "narrow scrollbar" cannot get
@@ -136,6 +136,11 @@ pref("extensions.treestyletab.tabbar.autoShow.accelKeyDown", true);
 pref("extensions.treestyletab.tabbar.autoShow.accelKeyDown.delay", 800);
 pref("extensions.treestyletab.tabbar.autoShow.tabSwitch", true);
 pref("extensions.treestyletab.tabbar.autoShow.feedback", false);
+pref("extensions.treestyletab.tabbar.autoShow.feedback.opened", true);
+pref("extensions.treestyletab.tabbar.autoShow.feedback.closed", true);
+pref("extensions.treestyletab.tabbar.autoShow.feedback.moved", true);
+pref("extensions.treestyletab.tabbar.autoShow.feedback.selected", true);
+pref("extensions.treestyletab.tabbar.autoShow.feedback.titleChanged", true);
 pref("extensions.treestyletab.tabbar.autoShow.feedback.delay", 3000);
 /**
  * Size of the placeholder for "hidden tab bar".
@@ -343,6 +348,10 @@ pref("extensions.treestyletab.tooltip.maxCount", 10);
  * Negative value means "do not show full tooltip".
  */
 pref("extensions.treestyletab.tooltip.fullTooltipDelay", 2000);
+/**
+ * If true, too many items are shown in multiple columns.
+ */
+pref("extensions.treestyletab.tooltip.columnize", true);
 
 /**
  * Visibility of extra menu items for the context menu on tabs, inserted by TST.
@@ -629,8 +638,6 @@ pref("extensions.treestyletab.restoreTree.level", 1);
  * conflict with TST features. They will be rolled back when TST is uninstalled.
  */
 pref("browser.link.open_newwindow.restriction.override", 0);
-pref("browser.tabs.insertRelatedAfterCurrent.override", false);
-pref("browser.tabs.insertRelatedAfterCurrent.override.force", true);
 
 /**
  * Extra commands for selected tabs (Multiple Tab Handler)
@@ -658,6 +665,11 @@ pref("extensions.treestyletab.createSubtree.underParent.temporaryGroup", true);
 pref("extensions.treestyletab.pinnedTab.faviconized", true);
 
 /**
+ * If true, too many items are shown in multiple columns in a dummy (group) tab.
+ */
+pref("extensions.treestyletab.groupTab.columnize", true);
+
+/**
  * Compatibility hack flags for other addons. They can be disabled by each
  * addon, when the addon become working with TST without dirty hacks.
  * In other words, add-on authros can disable TST's dirty hack if it is
@@ -728,7 +740,10 @@ pref("extensions.treestyletab.prefsVersion", 0);
 pref("extensions.treestyletab.debug.all", false);
 pref("extensions.treestyletab.debug.autoHide", false);
 pref("extensions.treestyletab.debug.base", false);
+pref("extensions.treestyletab.debug.bookmark", false);
 pref("extensions.treestyletab.debug.browser", false);
 pref("extensions.treestyletab.debug.browserUIShowHideObserver", false);
 pref("extensions.treestyletab.debug.contentBridge", false);
+pref("extensions.treestyletab.debug.fullscreenObserver", false);
 pref("extensions.treestyletab.debug.tabbarDNDObserver", false);
+pref("extensions.treestyletab.debug.window", false);
diff --git a/install.rdf b/install.rdf
index c377fc1..03ac69f 100644
--- a/install.rdf
+++ b/install.rdf
@@ -5,7 +5,7 @@
   <RDF:Description RDF:about="urn:mozilla:install-manifest"
                    em:id="treestyletab at piro.sakura.ne.jp"
                    em:name="Tree Style Tab"
-                   em:version="0.16.2015122501"
+                   em:version="0.16.2016021602"
                    em:creator="YUKI "Piro" Hiroshi"
                    em:description="Show tabs like a tree."
                    em:homepageURL="http://piro.sakura.ne.jp/xul/_treestyletab.html.en"
@@ -84,7 +84,7 @@
     </em:localized>
     <em:localized>
       <RDF:Description em:locale="es-ES"
-                       em:name="Tree Style Tab (Pestañas estilo árbol)"
+                       em:name="Pestañas estilo árbol"
                        em:description="Muestra las pestañas en vista de árbol"
                        em:homepageURL="http://piro.sakura.ne.jp/xul/_treestyletab.html.en"
                        em:creator="YUKI "Piro" Hiroshi">
@@ -112,6 +112,7 @@
           <em:contributor>mnoorenberghe (Firefox 36 support)</em:contributor>
           <em:contributor>Xidorn Quan (Firefox 40+ support)</em:contributor>
           <em:translator>Andy Pillip (de-DE locale)</em:translator>
+          <em:translator>Björn Kautler (de-DE locale)</em:translator>
       </RDF:Description>
     </em:localized>
     <em:localized>
@@ -134,7 +135,7 @@
     </em:localized>
     <em:localized>
       <RDF:Description em:locale="ru"
-                       em:name="Tree Style Tab (Древовидный стиль вкладок)"
+                       em:name="Древовидный стиль вкладок"
                        em:description="Отображение вкладок в виде дерева"
                        em:homepageURL="http://piro.sakura.ne.jp/xul/_treestyletab.html.en"
                        em:creator="YUKI "Piro" Hiroshi">
diff --git a/locale/cs/treestyletab/treestyletab.dtd b/locale/cs/treestyletab/treestyletab.dtd
index c57e86d..422f7c2 100644
--- a/locale/cs/treestyletab/treestyletab.dtd
+++ b/locale/cs/treestyletab/treestyletab.dtd
@@ -113,7 +113,8 @@
 <!ENTITY config.autoShow.accelKeyDown.delay.before "Zobrazit lištu po">
 <!ENTITY config.autoShow.accelKeyDown.delay.after  "ms">
 <!ENTITY config.autoShow.tabSwitch   "Panel je přepnut kombinací kláves Ctrl-Tab">
-<!ENTITY config.autoShow.feedback    "Panel je otevřen nebo zavřen">
+<!ENTITY config.autoShow.feedback    "Something happen on tabs (new tab, closed tab, focus changing, title changing)">
+<!--ENTITY config.autoShow.feedback    "Panel je otevřen nebo zavřen"-->
 <!ENTITY config.autoShow.feedback.delay.before "Opět zmenšit nebo schovat lištu po">
 <!ENTITY config.autoShow.feedback.delay.after  "ms">
 
@@ -131,6 +132,7 @@
 <!ENTITY config.closeParentBehavior.promoteFirst "Povýšit prvního potomka na rodičovský panel">
 <!ENTITY config.closeParentBehavior.promoteAll   "Povýšit všechny potomky na úroveň rodičovského panelu">
 <!ENTITY config.closeParentBehavior.detach       "Osvobodit potomky z celého stromu">
+<!ENTITY config.closeParentBehavior.replaceWithGroupTab "Replace closed parent with a dummy tab and keep the tree">
 <!ENTITY config.closeRootBehavior.promoteFirst   "Povýšit prvního potomka na rodičovský panel, pokud původní rodič sám neměl rodiče">
 
 <!ENTITY config.focusMode "Přepnout na následující/předchozí panel pomocí Ctrl-Tab i přesto, že není vidět">
diff --git a/locale/da-DK/treestyletab/treestyletab.dtd b/locale/da-DK/treestyletab/treestyletab.dtd
index 29da501..c03a1db 100644
--- a/locale/da-DK/treestyletab/treestyletab.dtd
+++ b/locale/da-DK/treestyletab/treestyletab.dtd
@@ -127,7 +127,8 @@
 <!ENTITY config.autoShow.accelKeyDown.delay.before "Vis efter">
 <!ENTITY config.autoShow.accelKeyDown.delay.after "msec.">
 <!ENTITY config.autoShow.tabSwitch "Ctrl-Tab skifter faner">
-<!ENTITY config.autoShow.feedback "Ved åbning eller lukning af faner">
+<!ENTITY config.autoShow.feedback    "Something happen on tabs (new tab, closed tab, focus changing, title changing)">
+<!--ENTITY config.autoShow.feedback "Ved åbning eller lukning af faner"-->
 <!ENTITY config.autoShow.feedback.delay.before "Skjul efter">
 <!ENTITY config.autoShow.feedback.delay.after "msec.">
 
@@ -145,6 +146,7 @@
 <!ENTITY config.closeParentBehavior.promoteFirst "Gør første underfane til hovedfane">
 <!ENTITY config.closeParentBehavior.promoteAll "Gør alle underfaner til hovedfaner">
 <!ENTITY config.closeParentBehavior.detach "Frigør underfaner fra træet">
+<!ENTITY config.closeParentBehavior.replaceWithGroupTab "Replace closed parent with a dummy tab and keep the tree">
 <!ENTITY config.closeRootBehavior.promoteFirst "Gør første underfane til hovedfane, hvis den lukkede fane er den første">
 
 <!ENTITY config.focusMode "Flyt fokus til næste/forrige fane, selv om den ikke er synlig, med Ctrl-Tab">
diff --git a/locale/de-DE/treestyletab/license.txt b/locale/de-DE/treestyletab/license.txt
index 6b66e3f..b4ce9e5 100644
--- a/locale/de-DE/treestyletab/license.txt
+++ b/locale/de-DE/treestyletab/license.txt
@@ -14,10 +14,11 @@ License.
 The Original Code is the Tree Style Tab.
 
 The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
-Portions created by the Initial Developer are Copyright (C) 2007-2009
+Portions created by the Initial Developer are Copyright (C) 2007-2016
 the Initial Developer. All Rights Reserved.
 
-Contributor(s): Andy Pillip <andy at pillip.eu>
+Contributor(s): Andy Pillip <andy at pillip.eu>
+                Björn Kautler <https://github.com/Vampire>
                 YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
 
 Alternatively, the contents of these files may be used under the terms of
diff --git a/locale/de-DE/treestyletab/treestyletab.dtd b/locale/de-DE/treestyletab/treestyletab.dtd
index 226d710..dae26df 100644
--- a/locale/de-DE/treestyletab/treestyletab.dtd
+++ b/locale/de-DE/treestyletab/treestyletab.dtd
@@ -6,164 +6,153 @@
 
 <!ENTITY config.tabs.appearance "Darstellung">
 
-<!ENTITY config.tabbar.position.caption "Position der Tableiste">
-<!ENTITY config.tabbar.position.left    "Links">
-<!ENTITY config.tabbar.position.right   "Rechts">
-<!ENTITY config.tabbar.position.top     "Oben (Firefox Standard)">
-<!ENTITY config.tabbar.position.bottom  "Unten">
-<!ENTITY config.tabbar.invertClosebox.left  "Schließen-Button in jedem Tab links anzeigen">
-<!ENTITY config.tabbar.invertClosebox.right "Schließen-Button in jedem Tab rechts anzeigen">
-<!ENTITY config.tabbar.invertTab            "Tabs von rechts einrücken">
-<!ENTITY config.tabbar.invertTabContents    "Symbol und Text in den Tabs vertauschen">
-<!ENTITY config.tabbar.narrowScrollbar      "Narrow scrollbar">
-<!ENTITY config.enableSubtreeIndent         "Tabs einrücken">
-<!ENTITY config.maxTreeLevel.before "bis">
-<!ENTITY config.maxTreeLevel.after  "Level">
-<!ENTITY config.allowSubtreeCollapseExpand  "Auf- und Einklappen von Zweigen erlauben">
+<!ENTITY config.tabbar.position.caption      "Position der Tableiste">
+<!ENTITY config.tabbar.position.left         "Links">
+<!ENTITY config.tabbar.position.right        "Rechts">
+<!ENTITY config.tabbar.position.top          "Oben (Firefox Standard)">
+<!ENTITY config.tabbar.position.bottom       "Unten">
+<!ENTITY config.tabbar.invertClosebox.left   "Schließen-Knopf in jedem Tab links anzeigen">
+<!ENTITY config.tabbar.invertClosebox.right  "Schließen-Knopf in jedem Tab rechts anzeigen">
+<!ENTITY config.tabbar.invertTab             "Tabs von rechts einrücken">
+<!ENTITY config.tabbar.invertTabContents     "Symbol und Text in den Tabs vertauschen">
+<!ENTITY config.tabbar.narrowScrollbar       "Schmale Bildlaufleiste">
+<!ENTITY config.enableSubtreeIndent          "Tabs einrücken">
+<!ENTITY config.maxTreeLevel.before          "bis">
+<!ENTITY config.maxTreeLevel.after           "Level">
+<!ENTITY config.allowSubtreeCollapseExpand   "Auf- und Einklappen von Zweigen erlauben">
 <!ENTITY config.tabbarSize.before-horizontal ":">
-<!ENTITY config.tabbarSize.after-horizontal  "px height">
+<!ENTITY config.tabbarSize.after-horizontal  "px Höhe">
 <!ENTITY config.tabbarSize.before-vertical   ":">
-<!ENTITY config.tabbarSize.after-vertical    "px width">
+<!ENTITY config.tabbarSize.after-vertical    "px Breite">
 
 
-<!ENTITY config.tabs.style "Style">
+<!ENTITY config.tabs.style "Aussehen">
 
 <!ENTITY config.tabbar.style.caption "Aussehen der Tableiste">
-<!ENTITY config.tabbar.style.plain   "Plain">
-<!ENTITY config.tabbar.style.flat    "Flat">
+<!ENTITY config.tabbar.style.plain   "Pur">
+<!ENTITY config.tabbar.style.flat    "Flach">
 <!ENTITY config.tabbar.style.mixed   "Gemischt">
 <!ENTITY config.tabbar.style.vertigo "Vertigo">
 <!ENTITY config.tabbar.style.metal   "Metal">
-<!ENTITY config.tabbar.style.sidebar "Sidebar">
+<!ENTITY config.tabbar.style.sidebar "Seitenleiste">
 <!ENTITY config.tabbar.style.none    "Standard (durch Theme festgelegt)">
 
-<!ENTITY config.twisty.style.caption "Aufklappsymbole">
-<!ENTITY config.twisty.style.auto    "Auto">
-<!ENTITY config.twisty.style.none    "Keine">
-<!ENTITY config.twisty.style.retro   "Retro">
+<!ENTITY config.twisty.style.caption      "Aufklappsymbole">
+<!ENTITY config.twisty.style.auto         "Auto">
+<!ENTITY config.twisty.style.none         "Keine">
+<!ENTITY config.twisty.style.retro        "Retro">
 <!ENTITY config.twisty.style.modern.black "Schwarz Modern">
 <!ENTITY config.twisty.style.modern.white "Weiß Modern">
-<!ENTITY config.twisty.style.osx     "OS X">
+<!ENTITY config.twisty.style.osx          "OS X">
 
 
 <!ENTITY config.tabs.menu "Menü">
 
 <!ENTITY config.show.tabContextMenu.caption "Folgende Zeilen im Kontextmenü der Tabs anzeigen">
-<!ENTITY config.show.openSelectionLinks ""Links im markierten Webseitentext in Tabs öffnen" im Kontextmenü der Markierung anbieten">
-
 
 <!ENTITY config.tabs.tab "Tabs Öffnen">
 
-<!--
-<!ENTITY config.autoAttach.newTabCommand.caption     "Neuen Tab öffnen:">
-<!ENTITY config.autoAttach.newTabCommand.independent "Auf oberster Ebene">
-<!ENTITY config.autoAttach.newTabCommand.child       "Dem aktuellen Tab unterordnen">
-<!ENTITY config.autoAttach.newTabCommand.sibling     "Auf Ebene des aktuellen Tabs öffnen">
-<!ENTITY config.autoAttach.newTabCommand.nextSibling "Open as the next sibling of the current tab">
-
-<!ENTITY config.autoAttach.duplicateTabCommand.caption     "When a tab is duplicated by middle click on the "Reload" button:">
-<!ENTITY config.autoAttach.duplicateTabCommand.independent "Auf oberster Ebene">
-<!ENTITY config.autoAttach.duplicateTabCommand.child       "Dem aktuellen Tab unterordnen">
-<!ENTITY config.autoAttach.duplicateTabCommand.sibling     "Auf Ebene des aktuellen Tabs öffnen">
-<!ENTITY config.autoAttach.duplicateTabCommand.nextSibling "Open as the next sibling of the source tab">
--->
-<!ENTITY config.autoAttach.newTabCommand.label_before "Open new blank tab as">
-<!ENTITY config.autoAttach.newTabCommand.independent "an independent tab">
-<!ENTITY config.autoAttach.newTabCommand.child       "a child of the current tab">
-<!ENTITY config.autoAttach.newTabCommand.sibling     "a sibling of the current tab">
-<!ENTITY config.autoAttach.newTabCommand.nextSibling "the next sibling of the current tab">
-<!ENTITY config.autoAttach.newTabCommand.label_after "">
-
-<!ENTITY config.autoAttach.newTabButton.label_before "For middle click on the "New Tab" button, open new blank tab as">
-<!ENTITY config.autoAttach.newTabButton.independent "an independent tab">
-<!ENTITY config.autoAttach.newTabButton.child       "a child of the current tab">
-<!ENTITY config.autoAttach.newTabButton.sibling     "a sibling of the current tab">
-<!ENTITY config.autoAttach.newTabButton.nextSibling "the next sibling of the current tab">
-<!ENTITY config.autoAttach.newTabButton.label_after "">
-
-<!ENTITY config.autoAttach.duplicateTabCommand.label_before "For middle click on the "Reload" button, duplicate the tab as">
-<!ENTITY config.autoAttach.duplicateTabCommand.independent "an independent tab">
-<!ENTITY config.autoAttach.duplicateTabCommand.child       "a child of the source tab">
-<!ENTITY config.autoAttach.duplicateTabCommand.sibling     "a sibling of the source tab">
-<!ENTITY config.autoAttach.duplicateTabCommand.nextSibling "the next sibling of the source tab">
-<!ENTITY config.autoAttach.duplicateTabCommand.label_after "">
-
-<!ENTITY config.autoAttach.goButton.label_before "For middle click on the "Go" button, open new tab as">
-<!ENTITY config.autoAttach.goButton.independent "an independent tab">
-<!ENTITY config.autoAttach.goButton.child       "a child of the current tab">
-<!ENTITY config.autoAttach.goButton.sibling     "a sibling of the current tab">
-<!ENTITY config.autoAttach.goButton.nextSibling "the next sibling of the current tab">
-<!ENTITY config.autoAttach.goButton.label_after "">
-
-<!ENTITY config.openGroupBookmark.caption     "Verhalten von "Alle in Tabs öffnen" für Seiten in einem Lesezeichenordner">
-<!ENTITY config.openGroupBookmark.ask         "Jedes Mal nachfragen">
-<!ENTITY config.openGroupBookmark.subtree     "Als Zweig öffnen (Empfohlen)">
-<!ENTITY config.openGroupBookmark.subtree.type.before  "">
-<!ENTITY config.openGroupBookmark.subtree.type.restore "Speichere">
-<!ENTITY config.openGroupBookmark.subtree.type.flat    "Ignoriere">
-<!ENTITY config.openGroupBookmark.subtree.type.after   "Anordnung der Tabs im Zweig beim Speichern als Lesezeichen">
-<!ENTITY config.openGroupBookmark.flat        "Als eigenständige Tabs öffnen (Firefox Standard)">
-<!ENTITY config.openGroupBookmark.underParent "Seiten zur Gruppierung einem Dummytab unterordnen">
-
-<!ENTITY config.dropLinksOnTab.caption "Verhalten für Drag & Drop auf Tabs">
+<!ENTITY config.autoAttach.newTabCommand.label_before "Neuen leeren Tab als">
+<!ENTITY config.autoAttach.newTabCommand.independent  "eigenständigen Tab">
+<!ENTITY config.autoAttach.newTabCommand.child        "untergeordneten Tab des aktiven Tab">
+<!ENTITY config.autoAttach.newTabCommand.sibling      "Tab auf der Ebene des aktiven Tab">
+<!ENTITY config.autoAttach.newTabCommand.nextSibling  "direkten Nachbar auf der Ebene des aktiven Tab">
+<!ENTITY config.autoAttach.newTabCommand.label_after  "öffnen">
+
+<!ENTITY config.autoAttach.newTabButton.label_before "Bei Mittelklick auf den "Neuer Tab" Knopf, neuen leeren Tab als">
+<!ENTITY config.autoAttach.newTabButton.independent  "eigenständigen Tab">
+<!ENTITY config.autoAttach.newTabButton.child        "untergeordneten Tab des aktiven Tab">
+<!ENTITY config.autoAttach.newTabButton.sibling      "Tab auf der Ebene des aktiven Tab">
+<!ENTITY config.autoAttach.newTabButton.nextSibling  "direkten Nachbar auf der Ebene des aktiven Tab">
+<!ENTITY config.autoAttach.newTabButton.label_after  "öffnen">
+
+<!ENTITY config.autoAttach.duplicateTabCommand.label_before "Bei Mittelklick auf den "Neu Laden" Knopf, den aktiven Tab als">
+<!ENTITY config.autoAttach.duplicateTabCommand.independent  "eigenständigen Tab">
+<!ENTITY config.autoAttach.duplicateTabCommand.child        "untergeordneten Tab des aktiven Tab">
+<!ENTITY config.autoAttach.duplicateTabCommand.sibling      "Tab auf der Ebene des aktiven Tab">
+<!ENTITY config.autoAttach.duplicateTabCommand.nextSibling  "direkten Nachbar auf der Ebene des aktiven Tab">
+<!ENTITY config.autoAttach.duplicateTabCommand.label_after  "kopieren">
+
+<!ENTITY config.autoAttach.goButton.label_before "Bei Mittelklick auf den "Laden" Knopf, neuen Tab als">
+<!ENTITY config.autoAttach.goButton.independent  "eigenständigen Tab">
+<!ENTITY config.autoAttach.goButton.child        "untergeordneten Tab des aktiven Tab">
+<!ENTITY config.autoAttach.goButton.sibling      "Tab auf der Ebene des aktiven Tab">
+<!ENTITY config.autoAttach.goButton.nextSibling  "direkten Nachbar auf der Ebene des aktiven Tab">
+<!ENTITY config.autoAttach.goButton.label_after  "öffnen">
+
+<!ENTITY config.openGroupBookmark.caption              "Verhalten von "Alle in Tabs öffnen" in einem Lesezeichenordner">
+<!ENTITY config.openGroupBookmark.ask                  "Jedes Mal nachfragen">
+<!ENTITY config.openGroupBookmark.subtree              "Als Zweig öffnen (Empfohlen)">
+<!ENTITY config.openGroupBookmark.subtree.type.before  "Die Zweigstruktur von als Tabs gespeicherten Lesezeichen">
+<!ENTITY config.openGroupBookmark.subtree.type.restore "wiederherstellen">
+<!ENTITY config.openGroupBookmark.subtree.type.flat    "ignorieren">
+<!ENTITY config.openGroupBookmark.subtree.type.after   "">
+<!ENTITY config.openGroupBookmark.flat                 "Als eigenständige Tabs öffnen (Firefox Standard)">
+<!ENTITY config.openGroupBookmark.underParent          "Seiten zur Gruppierung einem Pseudotab unterordnen">
+
+<!ENTITY config.dropLinksOnTab.caption "Verhalten für Drag & Drop von Link, URL, Bookmark oder Datei auf existierenden Tab">
 <!ENTITY config.dropLinksOnTab.ask     "Immer nachfragen">
 <!ENTITY config.dropLinksOnTab.load    "Seite im Tab laden (Firefox default)">
 <!ENTITY config.dropLinksOnTab.newTab  "Seite in einem neuen untergeordneten Tab laden">
 
-<!ENTITY config.tabs.autohide "Platz sparen">
-
-<!ENTITY config.autoHide.mode.normal.caption     "Bei normaler Fenstergröße">
-<!ENTITY config.autoHide.mode.fullscreen.caption "Im Vollbildmodus">
-<!ENTITY config.autoHide.mode.0 "Tableiste immer voll anzeigen">
-<!ENTITY config.autoHide.mode.1 "Inaktive Tableiste verstecken">
-<!ENTITY config.autoHide.mode.2 "Inaktive Tableiste verkleinert anzeigen">
-<!ENTITY config.autoShow.caption      "Tableiste aktivieren">
-<!ENTITY config.autoShow.mousemove    "Wenn der Mauszeiger die Fensterecken berührt">
-<!ENTITY config.autoHide.area.before "Empfindlicher Bereich:">
-<!ENTITY config.autoHide.area.after "Pixel rund um die Fensterecken / Kante der Tableiste">
-<!ENTITY config.autoHide.delay.before "Verzögerung:">
-<!ENTITY config.autoHide.delay.after "msec.">
-<!ENTITY config.autoShow.accelKeyDown "Wenn die Strg-Taste eine Zeit lang gedrückt wird">
+
+<!ENTITY config.tabs.autohide "Automatisches Ausblenden">
+
+<!ENTITY config.autoHide.mode.normal.caption       "Im Normalmodus">
+<!ENTITY config.autoHide.mode.fullscreen.caption   "Im Vollbildmodus">
+<!ENTITY config.autoHide.mode.0                    "Tableiste immer anzeigen">
+<!ENTITY config.autoHide.mode.1                    "Tableiste automatisch verstecken">
+<!ENTITY config.autoHide.mode.2                    "Tableiste automatisch verkleinern">
+<!ENTITY config.autoShow.caption                   "Tableiste anzeigen">
+<!ENTITY config.autoShow.mousemove                 "Wenn sich der Mauszeiger der Fenster- oder Tableistenkante annähert">
+<!ENTITY config.autoHide.area.before               "Empfindlicher Bereich:">
+<!ENTITY config.autoHide.area.after                "Pixel rund um die Fenster- oder Tableistenkante">
+<!ENTITY config.autoHide.delay.before              "Verzögerung:">
+<!ENTITY config.autoHide.delay.after               "Millisekunden">
+<!ENTITY config.autoShow.accelKeyDown              "Wenn die Strg-Taste eine Zeit lang gedrückt wird">
 <!ENTITY config.autoShow.accelKeyDown.delay.before "Nach">
-<!ENTITY config.autoShow.accelKeyDown.delay.after  "msec. aktivieren">
-<!ENTITY config.autoShow.tabSwitch    "Wenn Strg+Tab (wechselt zwischen Tabs) gedrückt wird">
-<!ENTITY config.autoShow.feedback     "Wenn neue Tabs geöffnet oder alte geschlossen werden">
-<!ENTITY config.autoShow.feedback.delay.before "Nach">
-<!ENTITY config.autoShow.feedback.delay.after  "msec. wieder deaktivieren">
+<!ENTITY config.autoShow.accelKeyDown.delay.after  "Millisekunden anzeigen">
+<!ENTITY config.autoShow.tabSwitch                 "Wenn Strg+Tab gedrückt wird um zwischen Tabs zu wechseln">
+<!ENTITY config.autoShow.feedback    "Something happen on tabs (new tab, closed tab, focus changing, title changing)">
+<!--ENTITY config.autoShow.feedback                  "Wenn Tabs geöffnet oder geschlossen werden"-->
+<!ENTITY config.autoShow.feedback.delay.before     "Nach">
+<!ENTITY config.autoShow.feedback.delay.after      "Millisekunden wieder ausblenden">
 
 
-<!ENTITY config.tabs.tree "Verhalten">
+<!ENTITY config.tabs.tree "Zweig">
 
-<!ENTITY config.autoCollapseExpandSubtreeOnAttach "When a new tree appears, collapse others automatically">
-<!ENTITY config.autoCollapseExpandSubtreeOnSelect "Nicht aktive Zweige zuklappen">
-<!ENTITY config.autoCollapseExpandSubtreeOnSelect.onCurrentTabRemove "Keine Fokusänderung beim Schließen des aktiven Tabs">
-<!ENTITY config.collapseExpandSubtree.dblclick "Bei Doppelklick auf Tab untergeordneten Zweig auf- oder zuklappen">
-<!ENTITY config.autoExpandSubtreeOnAppendChild "Zweig automatisch aufklappen, wenn ein Tab in den Zweig eingefügt wird">
+<!ENTITY config.autoCollapseExpandSubtreeOnAttach                    "Wenn ein neuer Zweig erscheint, andere Zweige automatisch zuklappen">
+<!ENTITY config.autoCollapseExpandSubtreeOnSelect                    "Wenn ein Tab ausgewählt wird, untergeordneten Zweig automatisch auf- und andere Zweige zuklappen">
+<!ENTITY config.autoCollapseExpandSubtreeOnSelect.onCurrentTabRemove "Nicht durch Schließen des aktiven Tabs auslösen">
+<!ENTITY config.collapseExpandSubtree.dblclick                       "Bei Doppelklick auf Tab untergeordneten Zweig auf- oder zuklappen">
+<!ENTITY config.autoExpandSubtreeOnAppendChild                       "Zweig automatisch aufklappen, wenn ein Tab in den Zweig eingefügt wird">
 
-<!ENTITY config.closeParentBehavior.caption "Wenn ein Tab geschlossen wird">
-<!ENTITY config.closeParentBehavior.close   "Untergeordnete Tabs auch schließen">
-<!ENTITY config.closeParentBehavior.promoteFirst "Das geschlossene Tab durch das erste untergeordnete ersetzen">
-<!ENTITY config.closeParentBehavior.promoteAll   "Untergeordnete Tabs auf die Ebene des geschlossenen Tabs verschieben">
-<!ENTITY config.closeParentBehavior.detach        "Untergeordnete Tabs ganz aus dem Zweig ausgliedern">
-<!ENTITY config.closeRootBehavior.promoteFirst   "Das geschlossene Tab durch das erste untergeordnete ersetzen, wenn das geschlossene Tab kein übergordnetes hatte">
+<!ENTITY config.closeParentBehavior.caption             "Wenn ein Tab geschlossen wird">
+<!ENTITY config.closeParentBehavior.close               "Untergeordnete Tabs auch schließen">
+<!ENTITY config.closeParentBehavior.promoteFirst        "Das geschlossene Tab durch das erste untergeordnete ersetzen">
+<!ENTITY config.closeParentBehavior.promoteAll          "Untergeordnete Tabs auf die Ebene des geschlossenen Tabs verschieben">
+<!ENTITY config.closeParentBehavior.detach              "Untergeordnete Tabs ganz aus dem Zweig ausgliedern">
+<!ENTITY config.closeParentBehavior.replaceWithGroupTab "Das geschlossene Tab durch ein Pseudotab ersetzen">
+<!ENTITY config.closeRootBehavior.promoteFirst          "Das geschlossene Tab durch das erste untergeordnete ersetzen, wenn das geschlossene Tab kein übergeordnetes hatte">
 
-<!ENTITY config.focusMode "Strg+Tab selektiert auch nicht sichtbare Tabs">
+<!ENTITY config.focusMode "Bei Strg+Tab auch zu nicht sichtbaren Tabs wechseln">
 
 <!ENTITY config.insertNewChildAt.caption "Einfügeposition neuer untergeordneter Tabs">
-<!ENTITY config.insertNewChildAt.first "Oben im Zweig einfügen">
-<!ENTITY config.insertNewChildAt.last "Unten im Zweig einfügen">
+<!ENTITY config.insertNewChildAt.first   "Als erstes Tab einfügen">
+<!ENTITY config.insertNewChildAt.last    "Als letztes Tab anfügen">
 
-<!ENTITY config.undoCloseTabSet.caption  "Wenn ein Element eines Zweiges durch "Tab wieder öffnen" wiederhergestellt wird.">
+<!ENTITY config.undoCloseTabSet.caption  "Wenn ein Element eines Zweiges durch "Tab wiederherstellen" geöffnet wird">
 <!ENTITY config.undoCloseTabSet.ask      "Immer nachfragen">
-<!ENTITY config.undoCloseTabSet.set      "Den ganzen Zweig wieder herstellen">
-<!ENTITY config.undoCloseTabSet.separate "Nur das eine Tab wieder herstellen (Firefox Standard)">
+<!ENTITY config.undoCloseTabSet.set      "Den ganzen Zweig wiederherstellen">
+<!ENTITY config.undoCloseTabSet.separate "Nur das eine Tab wiederherstellen (Firefox Standard)">
+
 
 
 <!ENTITY config.tabs.advanced "Erweitert">
 
-<!ENTITY config.tooltip.includeChildren        "Titel der untergeordneten Tabs im Tooltip geschlossener Tabs anzeigen">
+<!ENTITY config.tooltip.includeChildren     "Titel der untergeordneten Tabs im Tooltip des Tabs anzeigen">
 
-<!ENTITY config.bookmarkDroppedTabs.caption "Verhalten für Drag & Drop von Tab-Zweigen auf das Lesezeichenverzeichnis">
+<!ENTITY config.bookmarkDroppedTabs.caption "Verhalten für Drag & Drop von Tab-Zweigen auf den Lesezeichenbaum">
 <!ENTITY config.bookmarkDroppedTabs.ask     "Immer nachfragen">
 <!ENTITY config.bookmarkDroppedTabs.all     "Alle Tabs im Zweig als Lesezeichen speichern">
 <!ENTITY config.bookmarkDroppedTabs.parent  "Nur das gezogene Tab als Lesezeichen speichern">
@@ -171,34 +160,35 @@
 
 
 
-<!ENTITY selection.removeTabSubtree.label     "Ausgewählte Zweige schließen">
-<!ENTITY selection.removeTabSubtree.accesskey "s">
-<!ENTITY selection.createSubtree.label          "Zweig auf oberste Ebene verschieben">
+
+<!ENTITY selection.createSubtree.label          "Zu neuem Zweig zusammenfügen">
 <!ENTITY selection.createSubtree.accesskey      "g">
 
-<!ENTITY context.reloadTabSubtree.label     "Diesen Zweig neu laden">
-<!ENTITY context.reloadTabSubtree.accesskey "r">
+<!ENTITY selection.removeTabSubtree.label       "Ausgewählte Zweige schließen">
+<!ENTITY selection.removeTabSubtree.accesskey   "s">
+<!ENTITY context.reloadTabSubtree.label         "Diesen Zweig neu laden">
+<!ENTITY context.reloadTabSubtree.accesskey     "r">
 <!ENTITY context.reloadDescendantTabs.label     "Untergeordnete Tabs neu laden">
 <!ENTITY context.reloadDescendantTabs.accesskey "r">
-<!ENTITY context.removeTabSubtree.label     "Diesen Zweig schließen">
-<!ENTITY context.removeTabSubtree.accesskey "s">
+<!ENTITY context.removeTabSubtree.label         "Diesen Zweig schließen">
+<!ENTITY context.removeTabSubtree.accesskey     "s">
 <!ENTITY context.removeDescendantTabs.label     "Untergeordnete Tabs schließen">
 <!ENTITY context.removeDescendantTabs.accesskey "d">
-<!ENTITY context.removeAllTabsBut.label         "Andere Zweige schließen">
+<!ENTITY context.removeAllTabsBut.label         "Andere Tabs außer diesem Zweig schließen">
 <!ENTITY context.removeAllTabsBut.accesskey     "a">
-<!ENTITY context.collapseAllSubtree.label     "Alle Zweige zuklappen">
-<!ENTITY context.collapseAllSubtree.accesskey "c">
-<!ENTITY context.expandAllSubtree.label     "Alle Zweige aufklappen">
-<!ENTITY context.expandAllSubtree.accesskey "e">
-<!ENTITY context.toggleAutoHide.label.hide      "Tableiste verstecken">
-<!ENTITY context.toggleAutoHide.label.shrink    "Tableiste verkleinert anzeigen">
-<!ENTITY context.toggleAutoHide.accesskey "h">
-<!ENTITY context.toggleFixed.label            "Feste Position und Größe der Tableiste">
-<!ENTITY context.toggleFixed.label.horizontal "Feste Position und Höhe der Tableiste">
-<!ENTITY context.toggleFixed.label.vertical   "Feste Position und Breite der Tableiste">
-<!ENTITY context.toggleFixed.accesskey "f">
-<!ENTITY context.bookmarkTabSubtree.label     "Zweig als Lesezeichen speichern">
-<!ENTITY context.bookmarkTabSubtree.accesskey "t">
-
-<!ENTITY group.default "Neue Gruppe">
-<!ENTITY group.temporary "Temporary Group">
+<!ENTITY context.collapseAllSubtree.label       "Alle Zweige zuklappen">
+<!ENTITY context.collapseAllSubtree.accesskey   "c">
+<!ENTITY context.expandAllSubtree.label         "Alle Zweige aufklappen">
+<!ENTITY context.expandAllSubtree.accesskey     "e">
+<!ENTITY context.toggleAutoHide.label.hide      "Tableiste automatisch verstecken">
+<!ENTITY context.toggleAutoHide.label.shrink    "Tableiste automatisch verkleinern">
+<!ENTITY context.toggleAutoHide.accesskey       "h">
+<!ENTITY context.toggleFixed.label              "Feste Position und Größe der Tableiste">
+<!ENTITY context.toggleFixed.label.horizontal   "Feste Position und Höhe der Tableiste">
+<!ENTITY context.toggleFixed.label.vertical     "Feste Position und Breite der Tableiste">
+<!ENTITY context.toggleFixed.accesskey          "f">
+<!ENTITY context.bookmarkTabSubtree.label       "Zweig als Lesezeichen speichern">
+<!ENTITY context.bookmarkTabSubtree.accesskey   "t">
+
+<!ENTITY group.default   "Neue Gruppe">
+<!ENTITY group.temporary "Temporäre Gruppe">
diff --git a/locale/en-US/treestyletab/treestyletab.dtd b/locale/en-US/treestyletab/treestyletab.dtd
index a780985..504090d 100644
--- a/locale/en-US/treestyletab/treestyletab.dtd
+++ b/locale/en-US/treestyletab/treestyletab.dtd
@@ -113,7 +113,7 @@
 <!ENTITY config.autoShow.accelKeyDown.delay.before "Show after">
 <!ENTITY config.autoShow.accelKeyDown.delay.after  "msec.">
 <!ENTITY config.autoShow.tabSwitch   "Control-Tab to switch tabs">
-<!ENTITY config.autoShow.feedback    "New tabs are opened or some tabs are closed">
+<!ENTITY config.autoShow.feedback    "Something happen on tabs (new tab, closed tab, focus changing, title changing)">
 <!ENTITY config.autoShow.feedback.delay.before "Hide after">
 <!ENTITY config.autoShow.feedback.delay.after  "msec.">
 
@@ -131,6 +131,7 @@
 <!ENTITY config.closeParentBehavior.promoteFirst "Promote the first child tab as the new parent">
 <!ENTITY config.closeParentBehavior.promoteAll   "Promote all child tabs as the level of the closed parent tab">
 <!ENTITY config.closeParentBehavior.detach       "Liberate child tabs from the tree">
+<!ENTITY config.closeParentBehavior.replaceWithGroupTab "Replace closed parent with a dummy tab and keep the tree">
 <!ENTITY config.closeRootBehavior.promoteFirst   "Promote the first child tab as the new parent, if the closed parent has no parent">
 
 <!ENTITY config.focusMode "Focus to the next/previous tab even if it is invisible, by Control-Tab">
diff --git a/locale/es-ES/treestyletab/treestyletab.dtd b/locale/es-ES/treestyletab/treestyletab.dtd
index 8e3de37..4fb2642 100644
--- a/locale/es-ES/treestyletab/treestyletab.dtd
+++ b/locale/es-ES/treestyletab/treestyletab.dtd
@@ -122,7 +122,8 @@
 <!ENTITY config.autoShow.accelKeyDown.delay.before "Mostrar después">
 <!ENTITY config.autoShow.accelKeyDown.delay.after  "mseg.">
 <!ENTITY config.autoShow.tabSwitch   "Control-Tab para cambiar pestañas">
-<!ENTITY config.autoShow.feedback    "Nuevas pestañas son abiertas o algunas pestañas son cerradas">
+<!ENTITY config.autoShow.feedback    "Something happen on tabs (new tab, closed tab, focus changing, title changing)">
+<!--ENTITY config.autoShow.feedback    "Nuevas pestañas son abiertas o algunas pestañas son cerradas"-->
 <!ENTITY config.autoShow.feedback.delay.before "Ocultar después">
 <!ENTITY config.autoShow.feedback.delay.after  "mseg.">
 
@@ -141,6 +142,7 @@
 <!ENTITY config.closeParentBehavior.promoteFirst "Promover la primer pestañas como madre">
 <!ENTITY config.closeParentBehavior.promoteAll   "Promover todas las pestañas hijas al nivel de la pestaña cerrada">
 <!ENTITY config.closeParentBehavior.detach        "Liberar las hijas del árbol">
+<!ENTITY config.closeParentBehavior.replaceWithGroupTab "Replace closed parent with a dummy tab and keep the tree">
 <!ENTITY config.closeRootBehavior.promoteFirst   "Promover la primer hija como la nueva madre, si la madre cerrada no tiene madres">
 <!--ENTITY config.attachChildrenToGrandParentOnRemoveTab "Liberar las pestañas hijas del árbol cuando el árbol es cerrado"-->
 
diff --git a/locale/fr-FR/treestyletab/treestyletab.dtd b/locale/fr-FR/treestyletab/treestyletab.dtd
index 6f7fad5..5e67997 100644
--- a/locale/fr-FR/treestyletab/treestyletab.dtd
+++ b/locale/fr-FR/treestyletab/treestyletab.dtd
@@ -114,7 +114,8 @@
 <!ENTITY config.autoShow.accelKeyDown.delay.before "Afficher après">
 <!ENTITY config.autoShow.accelKeyDown.delay.after  "msec.">
 <!ENTITY config.autoShow.tabSwitch   "Control-Tab pour passer à l'onglet suivant">
-<!ENTITY config.autoShow.feedback    "De nouveaux onglets sont ouverts ou d'autres sont fermés">
+<!ENTITY config.autoShow.feedback    "Something happen on tabs (new tab, closed tab, focus changing, title changing)">
+<!--ENTITY config.autoShow.feedback    "De nouveaux onglets sont ouverts ou d'autres sont fermés"-->
 <!ENTITY config.autoShow.feedback.delay.before "Masquer après">
 <!ENTITY config.autoShow.feedback.delay.after  "msec.">
 
@@ -132,6 +133,7 @@
 <!ENTITY config.closeParentBehavior.promoteFirst "Promouvoir le premier onglet enfant en nouveau parent">
 <!ENTITY config.closeParentBehavior.promoteAll   "Promouvoir tous les onglets enfants au même niveau que l'onglet parent fermé">
 <!ENTITY config.closeParentBehavior.detach       "Sortir les onglets enfants de l'arborescence">
+<!ENTITY config.closeParentBehavior.replaceWithGroupTab "Replace closed parent with a dummy tab and keep the tree">
 <!ENTITY config.closeRootBehavior.promoteFirst   "Promouvoir le premier onglet enfant en nouveau parent, si le parent fermé n'a pas de parent">
 
 <!ENTITY config.focusMode "Activer l'onglet suivant/précédent même s'il n'est pas visible par Control-Tab">
diff --git a/locale/it-IT/treestyletab/treestyletab.dtd b/locale/it-IT/treestyletab/treestyletab.dtd
index a11fdb7..b8949cd 100644
--- a/locale/it-IT/treestyletab/treestyletab.dtd
+++ b/locale/it-IT/treestyletab/treestyletab.dtd
@@ -122,7 +122,8 @@
 <!ENTITY config.autoShow.accelKeyDown.delay.before "Visualizza dopo">
 <!ENTITY config.autoShow.accelKeyDown.delay.after  "msec.">
 <!ENTITY config.autoShow.tabSwitch   "Viene utilizzata la scorciatoia Control+Tab per passare da una scheda all'altra">
-<!ENTITY config.autoShow.feedback    "Viene aperta o chiusa una scheda">
+<!ENTITY config.autoShow.feedback    "Something happen on tabs (new tab, closed tab, focus changing, title changing)">
+<!--ENTITY config.autoShow.feedback    "Viene aperta o chiusa una scheda"-->
 <!ENTITY config.autoShow.feedback.delay.before "Nascondi dopo">
 <!ENTITY config.autoShow.feedback.delay.after  "msec.">
 
@@ -141,6 +142,7 @@
 <!ENTITY config.closeParentBehavior.promoteFirst "Promote the first child tab as the new parent">
 <!ENTITY config.closeParentBehavior.promoteAll   "porta le sottoschede al livello della scheda principale">
 <!ENTITY config.closeParentBehavior.detach        "elimina le sottoschede dall'albero">
+<!ENTITY config.closeParentBehavior.replaceWithGroupTab "Replace closed parent with a dummy tab and keep the tree">
 <!ENTITY config.closeRootBehavior.promoteFirst   "Promote the first child tab as the new parent, if the closed parent has no parent">
 <!--ENTITY config.attachChildrenToGrandParentOnRemoveTab "Elimina le sottoschede dall'albero alla chiusura della scheda principale"-->
 
diff --git a/locale/ja/treestyletab/treestyletab.dtd b/locale/ja/treestyletab/treestyletab.dtd
index 45f3534..90626b2 100644
--- a/locale/ja/treestyletab/treestyletab.dtd
+++ b/locale/ja/treestyletab/treestyletab.dtd
@@ -114,7 +114,7 @@
 <!ENTITY config.autoShow.accelKeyDown.delay.before "">
 <!ENTITY config.autoShow.accelKeyDown.delay.after  "ミリ秒以上で反応">
 <!ENTITY config.autoShow.tabSwitch   "Control-Tabでタブを切り替える時">
-<!ENTITY config.autoShow.feedback    "新しいタブが開かれたりタブが閉じられたりした時">
+<!ENTITY config.autoShow.feedback    "タブに何かが起こった時(開く、閉じる、フォーカス移動、タイトルの変化)">
 <!ENTITY config.autoShow.feedback.delay.before "">
 <!ENTITY config.autoShow.feedback.delay.after  "ミリ秒後に自動で隠す">
 
@@ -135,6 +135,7 @@
 <!ENTITY config.closeParentBehavior.promoteFirst "最初の子タブを新しい親にする">
 <!ENTITY config.closeParentBehavior.promoteAll   "閉じた親タブの階層に子孫のタブを移動する">
 <!ENTITY config.closeParentBehavior.detach       "子孫のタブをツリーから解放する">
+<!ENTITY config.closeParentBehavior.replaceWithGroupTab "代わりにグループ化用のダミーのタブを開いてツリーを維持する">
 <!ENTITY config.closeRootBehavior.promoteFirst   "最上位の親タブを閉じた時だけは、最初の子タブを新しい親にする">
 
 <!ENTITY config.insertNewChildAt.caption "新しい子タブを開く位置">
diff --git a/locale/pl/treestyletab/treestyletab.dtd b/locale/pl/treestyletab/treestyletab.dtd
index a08be90..27d47dd 100644
--- a/locale/pl/treestyletab/treestyletab.dtd
+++ b/locale/pl/treestyletab/treestyletab.dtd
@@ -122,7 +122,8 @@
 <!ENTITY config.autoShow.accelKeyDown.delay.before "Opóźnienie:">
 <!ENTITY config.autoShow.accelKeyDown.delay.after  "ms">
 <!ENTITY config.autoShow.tabSwitch   "Podczas przełączania kart za pomocą skrótu [Ctrl+Tab]">
-<!ENTITY config.autoShow.feedback    "Podczas otwierania nowych/zamykania kart">
+<!ENTITY config.autoShow.feedback    "Something happen on tabs (new tab, closed tab, focus changing, title changing)">
+<!--ENTITY config.autoShow.feedback    "Podczas otwierania nowych/zamykania kart"-->
 <!ENTITY config.autoShow.feedback.delay.before "Ukrywaj po">
 <!ENTITY config.autoShow.feedback.delay.after  "ms">
 
@@ -140,6 +141,7 @@
 <!ENTITY config.closeParentBehavior.promoteFirst "promuj pierwszą kartę potomną na kartę macierzystą">
 <!ENTITY config.closeParentBehavior.promoteAll   "promuj wszystkie potomne karty na poziom zamkniętej karty macierzystej">
 <!ENTITY config.closeParentBehavior.detach        "odłączaj karty potomne od drzewa">
+<!ENTITY config.closeParentBehavior.replaceWithGroupTab "Replace closed parent with a dummy tab and keep the tree">
 <!ENTITY config.closeRootBehavior.promoteFirst   "promuj pierwszą potomną, jeśli zamykana karta nie ma macierzystej">
 
 <!ENTITY config.focusMode "Skrót [Ctrl+Tab] uaktywnia następną/poprzednią kartę nawet jeśli jest niewidoczna">
diff --git a/locale/ru/treestyletab/treestyletab.dtd b/locale/ru/treestyletab/treestyletab.dtd
index 6005e15..ed5bbb5 100755
--- a/locale/ru/treestyletab/treestyletab.dtd
+++ b/locale/ru/treestyletab/treestyletab.dtd
@@ -21,14 +21,14 @@
 <!ENTITY config.maxTreeLevel.after  "">
 <!ENTITY config.allowSubtreeCollapseExpand  "Разрешить сворачивать/разворачивать поддеревья вкладок">
 <!ENTITY config.tabbarSize.before-horizontal ":">
-<!ENTITY config.tabbarSize.after-horizontal  "px height">
+<!ENTITY config.tabbarSize.after-horizontal  "пикселей в высоту">
 <!ENTITY config.tabbarSize.before-vertical   ":">
-<!ENTITY config.tabbarSize.after-vertical    "px width">
+<!ENTITY config.tabbarSize.after-vertical    "пикселей в ширину">
 
 
 <!ENTITY config.tabs.style "Стиль">
 
-<!ENTITY config.tabbar.style.caption "Стиль вкладок на панели">
+<!ENTITY config.tabbar.style.caption "Стиль панели вкладок">
 <!ENTITY config.tabbar.style.plain   "Plain">
 <!ENTITY config.tabbar.style.flat    "Flat">
 <!ENTITY config.tabbar.style.mixed   "Mixed">
@@ -113,14 +113,15 @@
 <!ENTITY config.autoShow.caption "Автоматически показывать панель вкладок при">
 <!ENTITY config.autoShow.mousemove "Перемещении мышки к краю окна или панели вкладок">
 <!ENTITY config.autoHide.area.before "Область срабатывания:">
-<!ENTITY config.autoHide.area.after "пикселов от края окна или панели вкладок">
+<!ENTITY config.autoHide.area.after "пикселей от края окна или панели вкладок">
 <!ENTITY config.autoHide.delay.before "Задержка:">
 <!ENTITY config.autoHide.delay.after "мсек.">
 <!ENTITY config.autoShow.accelKeyDown "При удерживании клавиши Ctrl">
 <!ENTITY config.autoShow.accelKeyDown.delay.before "Показывать после">
 <!ENTITY config.autoShow.accelKeyDown.delay.after  "мсек.">
 <!ENTITY config.autoShow.tabSwitch   "Переключении вкладок через Ctrl+Tab">
-<!ENTITY config.autoShow.feedback    "Закрытии вкладок или открытии новых">
+<!ENTITY config.autoShow.feedback    "Изменении вкладок (новая вкладка, закрытие вкладки, изменение фокуса, изменение заголовка)">
+<!--ENTITY config.autoShow.feedback    "Закрытии вкладок или открытии новых"-->
 <!ENTITY config.autoShow.feedback.delay.before "Скрыть после">
 <!ENTITY config.autoShow.feedback.delay.after  "мсек.">
 
@@ -138,6 +139,7 @@
 <!ENTITY config.closeParentBehavior.promoteFirst "Сделать первую дочернюю вкладку новой родительской">
 <!ENTITY config.closeParentBehavior.promoteAll   "Переместить все дочерние вкладки на уровень закрытой родительской вкладки">
 <!ENTITY config.closeParentBehavior.detach        "Переместить дочерние вкладки из дерева">
+<!ENTITY config.closeParentBehavior.replaceWithGroupTab "Заменить закрытую родительскую вкладку пустышкой и сохранить дерево">
 <!ENTITY config.closeRootBehavior.promoteFirst   "Сделать первую дочернюю вкладку новой родительской, если закрытая родительская вкладка не имела родителя">
 
 <!ENTITY config.focusMode "Переходить по Ctrl+Tab на следующую/предыдущую вкладку даже если она скрыта">
diff --git a/locale/sv-SE/treestyletab/treestyletab.dtd b/locale/sv-SE/treestyletab/treestyletab.dtd
index b153eb2..4f16fd6 100644
--- a/locale/sv-SE/treestyletab/treestyletab.dtd
+++ b/locale/sv-SE/treestyletab/treestyletab.dtd
@@ -126,7 +126,8 @@
 <!ENTITY config.autoShow.accelKeyDown.delay.before "Visa efter">
 <!ENTITY config.autoShow.accelKeyDown.delay.after  "ms">
 <!ENTITY config.autoShow.tabSwitch   "Ctrl+Tabb för att byta mellan flikar">
-<!ENTITY config.autoShow.feedback    "Nya flikar öppnas eller några flikar stängs">
+<!ENTITY config.autoShow.feedback    "Something happen on tabs (new tab, closed tab, focus changing, title changing)">
+<!--ENTITY config.autoShow.feedback    "Nya flikar öppnas eller några flikar stängs"-->
 <!ENTITY config.autoShow.feedback.delay.before "Dölj efter">
 <!ENTITY config.autoShow.feedback.delay.after  "ms">
 
@@ -144,6 +145,7 @@
 <!ENTITY config.closeParentBehavior.promoteFirst "Befordra den första underordnade fliken till ny överordnad flik">
 <!ENTITY config.closeParentBehavior.promoteAll   "Befordra alla underordnade flikar till nivån för den stängda överordnade fliken">
 <!ENTITY config.closeParentBehavior.detach       "Frigör underordnade flikar från trädet">
+<!ENTITY config.closeParentBehavior.replaceWithGroupTab "Replace closed parent with a dummy tab and keep the tree">
 <!ENTITY config.closeRootBehavior.promoteFirst   "Befordra den första underordnade fliken till ny överordnad, om den stängda fliken var högsta överordnade flik">
 
 <!ENTITY config.focusMode "Fokusera på nästa/föregående flik även om den är osynlig, m.h.a. Ctrl+Tabb">
diff --git a/locale/zh-CN/treestyletab/treestyletab.dtd b/locale/zh-CN/treestyletab/treestyletab.dtd
index 527fcdf..9cdd922 100644
--- a/locale/zh-CN/treestyletab/treestyletab.dtd
+++ b/locale/zh-CN/treestyletab/treestyletab.dtd
@@ -126,7 +126,8 @@
 <!ENTITY config.autoShow.accelKeyDown.delay.before "等待">
 <!ENTITY config.autoShow.accelKeyDown.delay.after  "毫秒再显示">
 <!ENTITY config.autoShow.tabSwitch   "用Ctrl-Tab切换标签时">
-<!ENTITY config.autoShow.feedback    "新建或关闭标签之后">
+<!ENTITY config.autoShow.feedback    "Something happen on tabs (new tab, closed tab, focus changing, title changing)">
+<!--ENTITY config.autoShow.feedback    "新建或关闭标签之后"-->
 <!ENTITY config.autoShow.feedback.delay.before "等待">
 <!ENTITY config.autoShow.feedback.delay.after  "毫秒再自动隐藏">
 
@@ -144,6 +145,7 @@
 <!ENTITY config.closeParentBehavior.promoteFirst "提升首个子标签为父标签">
 <!ENTITY config.closeParentBehavior.promoteAll   "提升所有子标签到父标签的级别">
 <!ENTITY config.closeParentBehavior.detach       "让子标签脱离树状关系">
+<!ENTITY config.closeParentBehavior.replaceWithGroupTab "Replace closed parent with a dummy tab and keep the tree">
 <!ENTITY config.closeRootBehavior.promoteFirst   "若父标签之上无父标签,则提升首个子标签为父标签">
 
 <!ENTITY config.focusMode "通过“Ctrl-Tab”切换标签时可切换到折叠起来的标签上。">
diff --git a/locale/zh-TW/treestyletab/treestyletab.dtd b/locale/zh-TW/treestyletab/treestyletab.dtd
index 5102cd5..bd15c9e 100644
--- a/locale/zh-TW/treestyletab/treestyletab.dtd
+++ b/locale/zh-TW/treestyletab/treestyletab.dtd
@@ -114,7 +114,8 @@
 <!ENTITY config.autoShow.accelKeyDown.delay.before "">
 <!ENTITY config.autoShow.accelKeyDown.delay.after  "毫秒以上才顯示">
 <!ENTITY config.autoShow.tabSwitch   "用 Ctrl-Tab 切換分頁時">
-<!ENTITY config.autoShow.feedback    "開新分頁或關閉分頁時">
+<!ENTITY config.autoShow.feedback    "Something happen on tabs (new tab, closed tab, focus changing, title changing)">
+<!--ENTITY config.autoShow.feedback    "開新分頁或關閉分頁時"-->
 <!ENTITY config.autoShow.feedback.delay.before "">
 <!ENTITY config.autoShow.feedback.delay.after  "毫秒後自動隱藏">
 
@@ -135,6 +136,7 @@
 <!ENTITY config.closeParentBehavior.promoteFirst "提升第一個子分頁到父分頁所在階層">
 <!ENTITY config.closeParentBehavior.promoteAll   "所有子分頁都提升到父分頁所在階層">
 <!ENTITY config.closeParentBehavior.detach  "從該樹釋放所屬子分頁">
+<!ENTITY config.closeParentBehavior.replaceWithGroupTab "Replace closed parent with a dummy tab and keep the tree">
 <!ENTITY config.closeRootBehavior.promoteFirst   "只有關閉最頂層的父分頁時,才提升第一子分頁為父分頁">
 
 
diff --git a/modules/autoHide.js b/modules/autoHide.js
index 782d504..65712e1 100644
--- a/modules/autoHide.js
+++ b/modules/autoHide.js
@@ -14,7 +14,7 @@
  * The Original Code is the Tree Style Tab.
  *
  * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2010-2015
+ * Portions created by the Initial Developer are Copyright (C) 2010-2016
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
@@ -47,6 +47,7 @@ Cu.import('resource://treestyletab-modules/constants.js');
 Cu.import('resource://treestyletab-modules/ReferenceCounter.js');
 
 XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
+XPCOMUtils.defineLazyModuleGetter(this, 'TabAttributesObserver', 'resource://treestyletab-modules/tabAttributesObserver.js');
 
 XPCOMUtils.defineLazyGetter(this, 'window', function() {
 	Cu.import('resource://treestyletab-modules/lib/namespace.jsm');
@@ -57,6 +58,12 @@ XPCOMUtils.defineLazyGetter(this, 'prefs', function() {
 	return window['piro.sakura.ne.jp'].prefs;
 });
 
+function log(...aArgs) {
+	utils.log.apply(utils, ['autoHide'].concat(aArgs));
+}
+function logWithStackTrace(...aArgs) {
+	utils.logWithStackTrace.apply(utils, ['autoHide'].concat(aArgs));
+}
 
 var AutoHideConstants = Object.freeze(inherit(TreeStyleTabConstants, {
 	kMODE : 'treestyletab-tabbar-autohide-mode', 
@@ -75,6 +82,7 @@ var AutoHideConstants = Object.freeze(inherit(TreeStyleTabConstants, {
 	kSHOWN_BY_SHORTCUT  : 1 << 0,
 	kSHOWN_BY_MOUSEMOVE : 1 << 1,
 	kSHOWN_BY_FEEDBACK  : 1 << 2,
+	kSHOWN_AUTOMATICALLY : (1 << 0) | (1 << 1),
 	kSHOWN_BY_ANY_REASON : (1 << 0) | (1 << 1) | (1 << 2),
 	kSHOWHIDE_BY_START  : 1 << 3,
 	kSHOWHIDE_BY_END    : 1 << 4,
@@ -361,6 +369,8 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 		sv.setTabbrowserAttribute(this.kSTATE, this.kSTATE_EXPANDED);
 
 		if (!(aReason & this.kSHOWHIDE_BY_API)) {
+			w.addEventListener('blur', this, true);
+			ReferenceCounter.add('w,blur,AHW,true');
 			b.addEventListener('dragover', this, true);
 			ReferenceCounter.add('b,dragover,AHW,true');
 			b.addEventListener('dragleave', this, true);
@@ -412,6 +422,8 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 		this.screen.hidePopup();
 
 		if (this.userActionListening) {
+			w.removeEventListener('blur', this, true);
+			ReferenceCounter.remove('w,blur,AHW,true');
 			b.removeEventListener('dragover', this, true);
 			ReferenceCounter.remove('b,dragover,AHW,true');
 			b.removeEventListener('dragleave', this, true);
@@ -570,11 +582,10 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 				extraInfo.push('expanded-by-unknown');
 			if (this.lastMouseDownTarget)
 				extraInfo.push('mousedown');
-			dump('showHideOnMouseMove: ' +
+			log('showHideOnMouseMove: ' +
 			       '('+aCoordinates.screenX + ', ' + aCoordinates.screenY + ') => ' +
 			       humanReadablePosition.join(', ') +
-			       (extraInfo.length ? ('[' + extraInfo.join(', ') + ']') : '') +
-			       '\n');
+			       (extraInfo.length ? ('[' + extraInfo.join(', ') + ']') : ''));
 		}
 
 		if (sv.isPopupShown() ||
@@ -754,7 +765,7 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
   
 	// feedback 
 	
-	showForFeedback : function AHB_showForFeedback() 
+	showForFeedback : function AHB_showForFeedback(aTab) 
 	{
 		if (!this.enabled ||
 			!utils.getTreePref('tabbar.autoShow.feedback'))
@@ -769,19 +780,21 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 		this.delayedShowForFeedbackTimer = w.setTimeout(
 			function(aSelf) {
 				aSelf.delayedShowForFeedbackTimer = null;
-				aSelf.delayedShowForFeedback();
+				aSelf.delayedShowForFeedback(aTab);
 			},
 			100,
 			this
 		);
 	},
  
-	delayedShowForFeedback : function AHB_delayedShowForFeedback() 
+	delayedShowForFeedback : function AHB_delayedShowForFeedback(aTab) 
 	{
+		this.treeStyleTab.highlightTab(aTab);
 		this.show(this.kSHOWN_BY_FEEDBACK);
 		this.cancelHideForFeedback();
 		this.delayedHideTabbarForFeedbackTimer = this.window.setTimeout(
 			function(aSelf) {
+				// TODO: we do something to highlight the given tab.
 				aSelf.delayedHideTabbarForFeedbackTimer = null;
 				aSelf.hide(aSelf.kSHOWN_BY_FEEDBACK);
 			},
@@ -905,10 +918,9 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 			let givenReason = this._getHumanReadableReason(aReason);
 			let unifiedReason = this._getHumanReadableReason(this.showHideReason);
 			if (this.expanded)
-				dump('autoHide: show by ' + aReason + '(' + givenReason + ' / ' + unifiedReason + ')\n');
+				logWithStackTrace('autoHide: show by ' + aReason + '(' + givenReason + ' / ' + unifiedReason + ')');
 			else
-				dump('autoHide: hide by ' + aReason + '(' + givenReason + ' / ' + unifiedReason + ')\n');
-			dump((new Error()).stack.replace(/^/gm, '  ').replace(/\s+$/, '') + '\n');
+				logWithStackTrace('autoHide: hide by ' + aReason + '(' + givenReason + ' / ' + unifiedReason + ')');
 		}
 
 		this.fireStateChangingEvent();
@@ -1216,6 +1228,16 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 	{
 		switch (aEvent.type)
 		{
+			case 'blur':
+				let activeWindow = Cc['@mozilla.org/focus-manager;1']
+									.getService(Ci.nsIFocusManager)
+									.activeWindow;
+				var inactive = !activeWindow || activeWindow != this.window;
+				if (inactive &&
+					this.showHideReason & this.kSHOWN_AUTOMATICALLY)
+					this.hide(this.kSHOWN_BY_ANY_REASON);
+				return;
+
 			case 'mousedown':
 				return this.onMouseDown(aEvent);
 
@@ -1234,17 +1256,26 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 				return this.notifyStatusToAllTabs(aEvent.target);
 
 			case 'TabOpen':
+				if (utils.getTreePref('tabbar.autoShow.feedback.opened'))
+					this.showForFeedback(aEvent.originalTarget);
+				return;
+
 			case 'TabClose':
-				return this.showForFeedback();
+				if (utils.getTreePref('tabbar.autoShow.feedback.closed'))
+					this.showForFeedback(aEvent.originalTarget);
+				return;
 
 			case 'TabMove':
-				if (!this.treeStyleTab.subTreeMovingCount && !this.treeStyleTab.internallyTabMovingCount)
-					this.showForFeedback();
+				if (utils.getTreePref('tabbar.autoShow.feedback.moved') &&
+					!this.treeStyleTab.subTreeMovingCount &&
+					!this.treeStyleTab.isTabInternallyMoving(aEvent.originalTarget))
+					this.showForFeedback(aEvent.originalTarget);
 				return;
 
 			case 'select':
-				if (!this.window.TreeStyleTabService.accelKeyPressed)
-					this.showForFeedback();
+				if (utils.getTreePref('tabbar.autoShow.feedback.selected') &&
+					!this.window.TreeStyleTabService.accelKeyPressed)
+					this.showForFeedback(aEvent.originalTarget);
 				return;
 
 			case 'dragover':
@@ -1310,7 +1341,7 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 		if (
 			aEvent.target &&
 			!this.isResizing &&
-			sv.evaluateXPath(
+			utils.evaluateXPath(
 				'ancestor-or-self::*[@class="'+sv.kSPLITTER+'"]',
 				aEvent.originalTarget || aEvent.target,
 				Ci.nsIDOMXPathResult.BOOLEAN_TYPE
@@ -1342,7 +1373,7 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 		var sv = this.treeStyleTab;
 		if (this.isResizing &&
 			aEvent.originalTarget &&
-			sv.evaluateXPath(
+			utils.evaluateXPath(
 				'ancestor-or-self::*[@class="'+sv.kSPLITTER+'"]',
 				aEvent.originalTarget,
 				Ci.nsIDOMXPathResult.BOOLEAN_TYPE
@@ -1454,6 +1485,12 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
  
 	delayedShowForShortcutTimer : null, 
 	delayedShowForShortcutDone : true,
+ 
+	onTabTitleChanged : function AHB_onTabTitleChanged(aTab)
+	{
+		if (utils.getTreePref('tabbar.autoShow.feedback.titleChanged'))
+			this.showForFeedback(aTab);
+	},
     
 	init : function AHB_init(aTabBrowser) 
 	{
@@ -1500,6 +1537,15 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 		ReferenceCounter.add('b,kEVENT_TYPE_TAB_FOCUS_SWITCHING_START,AHW,false');
 		b.addEventListener(sv.kEVENT_TYPE_TAB_FOCUS_SWITCHING_END, this, false);
 		ReferenceCounter.add('b,kEVENT_TYPE_TAB_FOCUS_SWITCHING_END,AHW,false');
+
+		this.tabsAttributeObserver = new TabAttributesObserver({
+			container  : b.mTabContainer,
+			attributes : 'titlechanged',
+			callback   : (function(aTab) {
+				if (aTab.getAttribute('titlechanged') == 'true')
+					this.onTabTitleChanged(aTab);
+			}).bind(this)
+		});
 	},
  
 	destroy : function AHB_destroy() 
@@ -1507,6 +1553,9 @@ AutoHideBrowser.prototype = inherit(AutoHideBase.prototype, {
 		this.end();
 		prefs.removePrefListener(this);
 
+		this.tabsAttributeObserver.destroy();
+		delete this.tabsAttributeObserver;
+
 		var sv = this.treeStyleTab;
 		var b  = this.browser;
 		b.mTabContainer.removeEventListener('TabOpen', this, false);
@@ -1636,8 +1685,7 @@ AutoHideWindow.prototype = inherit(AutoHideBase.prototype, {
 	
 	get shouldListenKeyEvents() 
 	{
-		return !this.treeStyleTab.ctrlTabPreviewsEnabled &&
-				(
+		return (
 					utils.getTreePref('tabbar.autoShow.accelKeyDown') ||
 					utils.getTreePref('tabbar.autoShow.tabSwitch') ||
 					utils.getTreePref('tabbar.autoShow.feedback')
@@ -1706,8 +1754,7 @@ AutoHideWindow.prototype = inherit(AutoHideBase.prototype, {
 	},
  
 	domains : [ 
-		'extensions.treestyletab.',
-		'browser.ctrlTab.previews'
+		'extensions.treestyletab.'
 	],
 
 	onPrefChange : function AHW_onPrefChange(aPrefName) 
@@ -1719,7 +1766,6 @@ AutoHideWindow.prototype = inherit(AutoHideBase.prototype, {
 			case 'extensions.treestyletab.tabbar.autoShow.accelKeyDown':
 			case 'extensions.treestyletab.tabbar.autoShow.tabSwitch':
 			case 'extensions.treestyletab.tabbar.autoShow.feedback':
-			case 'browser.ctrlTab.previews':
 				this.updateKeyListeners(this.window);
 
 			default:
diff --git a/modules/base.js b/modules/base.js
index 3a4452f..75093cc 100644
--- a/modules/base.js
+++ b/modules/base.js
@@ -14,7 +14,7 @@
  * The Original Code is the Tree Style Tab.
  *
  * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2010-2014
+ * Portions created by the Initial Developer are Copyright (C) 2010-2016
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
@@ -81,6 +81,13 @@ if (Services.appinfo.OS === 'WINNT') {
 else {
 	this.AeroPeek = null;
 }
+
+function log(...aArgs) {
+	utils.log.apply(utils, ['base'].concat(aArgs));
+}
+function logWithStackTrace(...aArgs) {
+	utils.logWithStackTrace.apply(utils, ['base'].concat(aArgs));
+}
  
 var TreeStyleTabBase = inherit(TreeStyleTabConstants, { 
 	
@@ -132,12 +139,10 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 		this.onPrefChange('extensions.treestyletab.indent.vertical');
 		this.onPrefChange('extensions.treestyletab.indent.horizontal');
 		this.onPrefChange('extensions.treestyletab.clickOnIndentSpaces.enabled');
-		this.onPrefChange('browser.tabs.insertRelatedAfterCurrent.override');
 		this.onPrefChange('extensions.stm.tabBarMultiRows.override'); // Super Tab Mode
 		this.onPrefChange('extensions.treestyletab.tabbar.scroll.smooth');
 		this.onPrefChange('extensions.treestyletab.tabbar.scroll.duration');
 		this.onPrefChange('extensions.treestyletab.tabbar.scrollToNewTab.mode');
-		this.onPrefChange('extensions.treestyletab.tabbar.narrowScrollbar.size');
 		this.onPrefChange('browser.tabs.animate');
 		this.onPrefChange('extensions.treestyletab.animation.indent.duration');
 		this.onPrefChange('extensions.treestyletab.animation.collapse.duration');
@@ -149,8 +154,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 			this.overrideExtensions();
 		}
 		catch(e) {
-			if (utils.isDebugging('base'))
-				dump(e+'\n');
+			log(e);
 		}
 	},
 	_initialized : false,
@@ -184,7 +188,6 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 			prefs.removePrefListener(this);
 
 			let restorePrefs = [
-				'browser.tabs.insertRelatedAfterCurrent',
 				'extensions.stm.tabBarMultiRows' // Super Tab Mode
 			];
 			for (let i = 0, maxi = restorePrefs.length; i < maxi; i++)
@@ -230,69 +233,6 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 		}
 	},
  
-	updateNarrowScrollbarStyle : function TSTBase_updateNarrowScrollbarStyle() 
-	{
-		const SSS = Cc['@mozilla.org/content/style-sheet-service;1']
-					.getService(Ci.nsIStyleSheetService);
-
-		if (this.lastAgentSheet &&
-			SSS.sheetRegistered(this.lastAgentSheet, SSS.AGENT_SHEET))
-			SSS.unregisterSheet(this.lastAgentSheet, SSS.AGENT_SHEET);
-
-		const style = 'data:text/css,'+encodeURIComponent(
-			('@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");' +
-
-			'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
-			'  .tabbrowser-arrowscrollbox' +
-			'  > scrollbox' +
-			'  > scrollbar[orient="vertical"],' +
-			'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
-			'  .tabbrowser-arrowscrollbox' +
-			'  > scrollbox' +
-			'  > scrollbar[orient="vertical"] * {' +
-			'  max-width: %SIZE%;' +
-			'  min-width: %SIZE%;' +
-			'}' +
-
-			'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
-			'  .tabbrowser-arrowscrollbox' +
-			'  > scrollbox' +
-			'  > scrollbar[orient="vertical"] {' +
-			'  font-size: %SIZE%;' +
-			'}' +
-
-			'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
-			'  .tabbrowser-arrowscrollbox' +
-			'  > scrollbox' +
-			'  > scrollbar[orient="vertical"] * {' +
-			'  padding-left: 0;' +
-			'  padding-right: 0;' +
-			'  margin-left: 0;' +
-			'  margin-right: 0;' +
-			'}' +
-
-			'%FORCE_NARROW_SCROLLBAR%')
-				.replace(/%FORCE_NARROW_SCROLLBAR%/g,
-					utils.getTreePref('tabbar.narrowScrollbar.overrideSystemAppearance') ?
-						this.kOVERRIDE_SYSTEM_SCROLLBAR_APPEARANCE : '' )
-				.replace(/%MODE%/g, this.kMODE)
-				.replace(/%NARROW%/g, this.kNARROW_SCROLLBAR)
-				.replace(/%SIZE%/g, utils.getTreePref('tabbar.narrowScrollbar.size'))
-			);
-		this.lastAgentSheet = this.makeURIFromSpec(style);
-		SSS.loadAndRegisterSheet(this.lastAgentSheet, SSS.AGENT_SHEET);
-	},
-	kOVERRIDE_SYSTEM_SCROLLBAR_APPEARANCE :
-		'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
-		'  .tabbrowser-arrowscrollbox' +
-		'  > scrollbox' +
-		'  > scrollbar[orient="vertical"] {' +
-		'  appearance: none;' +
-		'  -moz-appearance: none;' +
-		'  background: ThreeDFace;' +
-		'  border: 1px solid ThreeDShadow;' +
-		'}',
-	lastAgentSheet : null,
   
 /* references to the owner */ 
 	
@@ -372,10 +312,6 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 
 		return behavior
 	},
-	kDROPLINK_ASK    : 0,
-	kDROPLINK_FIXED  : 1 + 2,
-	kDROPLINK_LOAD   : 1,
-	kDROPLINK_NEWTAB : 2,
  
 	openGroupBookmarkBehavior : function TSTBase_openGroupBookmarkBehavior() 
 	{
@@ -411,14 +347,6 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 		}
 		return behavior;
 	},
-	kGROUP_BOOKMARK_ASK       : 0,
-	kGROUP_BOOKMARK_FIXED     : 1 + 2 + 4,
-	kGROUP_BOOKMARK_SUBTREE   : 1,
-	kGROUP_BOOKMARK_SEPARATE  : 2,
-	kGROUP_BOOKMARK_USE_DUMMY                   : 256,
-	kGROUP_BOOKMARK_USE_DUMMY_FORCE             : 1024,
-	kGROUP_BOOKMARK_DONT_RESTORE_TREE_STRUCTURE : 512,
-	kGROUP_BOOKMARK_EXPAND_ALL_TREE             : 2048,
  
 	bookmarkDroppedTabsBehavior : function TSTBase_bookmarkDroppedTabsBehavior() 
 	{
@@ -519,8 +447,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 
 		var message = 'ERROR: accessed after destruction!';
 		var error = new Error(message);
-		if (utils.isDebugging('base'))
-			dump(message+'\n'+error.stack.replace(/^/gm, '  ')+'\n');
+		logWithStackTrace(message);
 		throw error;
 	},
   
@@ -560,7 +487,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
  
 	isEventFiredOnClosebox : function TSTBase_isEventFiredOnClosebox(aEvent) 
 	{
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 				'ancestor-or-self::*[contains(concat(" ", normalize-space(@class), " "), " tab-close-button ")]',
 				aEvent.originalTarget || aEvent.target,
 				Ci.nsIDOMXPathResult.BOOLEAN_TYPE
@@ -569,7 +496,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
  
 	isEventFiredOnClickable : function TSTBase_isEventFiredOnClickable(aEvent) 
 	{
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 				'ancestor-or-self::*[contains(" button toolbarbutton scrollbar nativescrollbar popup menupopup panel tooltip splitter textbox ", concat(" ", local-name(), " "))]',
 				aEvent.originalTarget,
 				Ci.nsIDOMXPathResult.BOOLEAN_TYPE
@@ -578,7 +505,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
  
 	isEventFiredOnScrollbar : function TSTBase_isEventFiredOnScrollbar(aEvent) 
 	{
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 				'ancestor-or-self::*[local-name()="scrollbar" or local-name()="nativescrollbar"]',
 				aEvent.originalTarget,
 				Ci.nsIDOMXPathResult.BOOLEAN_TYPE
@@ -715,92 +642,6 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 	{
 		return 'tabs-closed-set-<'+Date.now()+'-'+parseInt(Math.random() * 65000)+'>';
 	},
- 
-	makeURIFromSpec : function TSTBase_makeURIFromSpec(aURI) 
-	{
-		var newURI;
-		aURI = aURI || '';
-		if (aURI && String(aURI).indexOf('file:') == 0) {
-			var fileHandler = Services.io.getProtocolHandler('file').QueryInterface(Ci.nsIFileProtocolHandler);
-			var tempLocalFile = fileHandler.getFileFromURLSpec(aURI);
-			newURI = Services.io.newFileURI(tempLocalFile);
-		}
-		else {
-			if (!/^\w+\:/.test(aURI))
-				aURI = 'http://'+aURI;
-			newURI = Services.io.newURI(aURI, null, null);
-		}
-		return newURI;
-	},
- 
-	getGroupTabURI : function TSTBase_getGroupTabURI(aOptions) 
-	{
-		aOptions = aOptions || {};
-		var parameters = [];
-		parameters.push('title=' + encodeURIComponent(aOptions.title || ''));
-		parameters.push('temporary=' + !!aOptions.temporary);
-		return 'about:treestyletab-group?' + parameters.join('&');
-	},
-  
-// xpath 
-	
-	NSResolver : { 
-		lookupNamespaceURI : function(aPrefix)
-		{
-			switch (aPrefix)
-			{
-				case 'xul':
-					return 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
-				case 'html':
-				case 'xhtml':
-					return 'http://www.w3.org/1999/xhtml';
-				case 'xlink':
-					return 'http://www.w3.org/1999/xlink';
-				default:
-					return '';
-			}
-		}
-	},
- 
-	evaluateXPath : function TSTBase_evaluateXPath(aExpression, aContext, aType) 
-	{
-		if (!aType)
-			aType = Ci.nsIDOMXPathResult.ORDERED_NODE_SNAPSHOT_TYPE;
-		try {
-			var XPathResult = (aContext.ownerDocument || aContext).evaluate(
-					aExpression,
-					(aContext || document),
-					this.NSResolver,
-					aType,
-					null
-				);
-		}
-		catch(e) {
-			return {
-				singleNodeValue : null,
-				snapshotLength  : 0,
-				snapshotItem    : function() {
-					return null
-				}
-			};
-		}
-		return XPathResult;
-	},
- 
-	getArrayFromXPathResult : function TSTBase_getArrayFromXPathResult(aXPathResult) 
-	{
-		var max = aXPathResult.snapshotLength;
-		var array = new Array(max);
-		if (!max)
-			return array;
-
-		for (var i = 0; i < max; i++)
-		{
-			array[i] = aXPathResult.snapshotItem(i);
-		}
-
-		return array;
-	},
   
 /* Session Store API */ 
 	
@@ -903,7 +744,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 		var strip = aTabBrowser.mStrip;
 		return (strip && strip instanceof this.window.Element) ?
 				strip :
-				this.evaluateXPath(
+				utils.evaluateXPath(
 					'ancestor::xul:toolbar[1]',
 					aTabBrowser.tabContainer,
 					Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
@@ -951,10 +792,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 	{
 		var strip = this.tabStrip;
 		if (!strip) {
-			if (utils.isDebugging('base')) {
-				dump('FAILED TO SET TABSTRIP ATTRIBUTE ' + aAttr + '=' + aValue + '\n');
-				dump((new Error()).stack.replace(/^/gm, '  ') + '\n');
-			}
+			logWithStackTrace('FAILED TO SET TABSTRIP ATTRIBUTE ' + aAttr + '=' + aValue);
 			return;
 		}
 		var isFeatureAttribute = aAttr.indexOf('treestyletab-') == 0;
@@ -995,7 +833,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
  
 	getTabFromChild : function TSTBase_getTabFromChild(aTab) 
 	{
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 				'ancestor-or-self::xul:tab',
 				aTab,
 				Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
@@ -1009,7 +847,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
  
 	getNewTabButtonFromEvent : function TSTBase_getNewTabButtonFromEvent(aEvent) 
 	{
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 				'ancestor-or-self::*['
 					+'@id="new-tab-button" or '
 					+'contains(concat(" ", normalize-space(@class), " "), " tabs-newtab-button ")'
@@ -1021,7 +859,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
  
 	getSplitterFromEvent : function TSTBase_getSplitterFromEvent(aEvent) 
 	{
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 				'ancestor-or-self::xul:splitter[contains(concat(" ", normalize-space(@class), " "), " '+this.kSPLITTER+' ")]',
 				aEvent.originalTarget,
 				Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
@@ -1030,7 +868,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
  
 	isEventFiredOnGrippy : function TSTBase_isEventFiredOnGrippy(aEvent) 
 	{
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 				'ancestor-or-self::xul:grippy',
 				aEvent.originalTarget,
 				Ci.nsIDOMXPathResult.BOOLEAN_TYPE
@@ -1070,7 +908,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
  
 	getTabbarFromChild : function TSTBase_getTabbarFromChild(aNode) 
 	{
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 				'ancestor-or-self::*[contains(concat(" ", normalize-space(@class), " "), " tabbrowser-strip ")] | ' +
 				'ancestor-or-self::xul:tabs[@tabbrowser] | ' +
 				'ancestor-or-self::xul:toolbar/child::xul:tabs[@tabbrowser]',
@@ -1080,7 +918,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 	},
 	getAncestorTabbarFromChild : function TSTBase_getAncestorTabbarFromChild(aNode)
 	{
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 				'ancestor-or-self::*[contains(concat(" ", normalize-space(@class), " "), " tabbrowser-strip ")] | ' +
 				'ancestor-or-self::xul:tabs[@tabbrowser]',
 				aNode,
@@ -1162,38 +1000,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 	
 	getTabBrowserFromChild : function TSTBase_getTabBrowserFromChild(aTabBrowserChild) 
 	{
-		if (!aTabBrowserChild)
-			return null;
-
-		if (aTabBrowserChild.__treestyletab__linkedTabBrowser) // tab
-			return aTabBrowserChild.__treestyletab__linkedTabBrowser;
-
-		if (aTabBrowserChild.localName == 'tabbrowser') // itself
-			return aTabBrowserChild;
-
-		if (aTabBrowserChild.tabbrowser) // tabs
-			return aTabBrowserChild.tabbrowser;
-
-		if (aTabBrowserChild.localName == 'toolbar') // tabs toolbar
-			return aTabBrowserChild.getElementsByTagName('tabs')[0].tabbrowser;
-
-		// tab context menu
-		var popup = this.evaluateXPath(
-				'ancestor-or-self::xul:menupopup[@id="tabContextMenu"]',
-				aTabBrowserChild,
-				Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
-			).singleNodeValue;
-		if (popup && 'TabContextMenu' in aTabBrowserChild.ownerDocument.defaultView)
-			return this.getTabBrowserFromChild(aTabBrowserChild.ownerDocument.defaultView.TabContextMenu.contextTab);
-
-		var b = this.evaluateXPath(
-				'ancestor::xul:tabbrowser | '+
-				'ancestor::xul:tabs[@tabbrowser] |'+
-				'ancestor::xul:toolbar/descendant::xul:tabs',
-				aTabBrowserChild,
-				Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
-			).singleNodeValue;
-		return (b && b.tabbrowser) || b;
+		return utils.getTabBrowserFromChild(aTabBrowserChild);
 	},
  
 	getTabBrowserFromFrame : function TSTBase_getTabBrowserFromFrame(aFrame) 
@@ -1464,6 +1271,20 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 	},
  
 	/**
+	 * Returns tabs which are newly opened from the given task.
+	 */
+	doAndGetNewTabs : function TSTBase_doAndGetNewTabs(aTask, aTabBrowser) 
+	{
+		var previousTabs = this.getTabsInfo(aTabBrowser);
+		try {
+			aTask();
+		}
+		catch(e) {
+			Components.utils.reportError(e);
+		}
+		return this.getNewTabsFromPreviousTabsInfo(aTabBrowser, previousTabs);
+	},
+	/**
 	 * Returns tabs which are newly opened. This requires the "previous state".
 	 */
 	getNewTabsFromPreviousTabsInfo : function TSTBase_getNewTabsFromPreviousTabsInfo(aTabBrowser, aTabsInfo) 
@@ -1510,9 +1331,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 			refId = aInsertBefore.getAttribute(this.kID);
 		}
 
-		if (utils.isDebugging('base'))
-			dump('Tree Style Tab: new child tab is requested.\n'+
-			     new Error().stack.replace(/^/gm, '  ')+'\n');
+		logWithStackTrace('new child tab is requested.');
 
 		ownerBrowser.treeStyleTab.readiedToAttachNewTab   = true;
 		ownerBrowser.treeStyleTab.readiedToAttachMultiple = aMultiple || false ;
@@ -1543,6 +1362,41 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 		return false;
 	},
  
+	readyToOpenOrphanTab : function TSTBase_readyToOpenOrphanTab(aTabOrSomething) /* PUBLIC API */ 
+	{
+		var browser = this.getBrowserFromTabBrowserElements(aTabOrSomething);
+		if (!browser)
+			return false;
+
+		var ownerBrowser = this.getTabBrowserFromChild(browser);
+
+		logWithStackTrace('new orphan tab is requested.');
+
+		ownerBrowser.treeStyleTab.readiedToAttachNewTab   = false;
+
+		return true;
+	},
+	/**
+	 * Extended version. If you don't know whether a new tab will be actually
+	 * opened or not (by the command called after TST's API), then use this.
+	 * This version automatically cancels the "ready" state with delay.
+	 */
+	readyToOpenOrphanTabNow : function TSTBase_readyToOpenOrphanTabNow(...aArgs) /* PUBLIC API */
+	{
+		if (this.readyToOpenOrphanTab.apply(this, aArgs)) {
+			setTimeout((function() {
+				try {
+					this.stopToOpenChildTab(aArgs[0]);
+				}
+				catch(e) {
+					this.defaultErrorHandler(e);
+				}
+			}).bind(this), 0);
+			return true;
+		}
+		return false;
+	},
+ 
 	readyToOpenNextSiblingTab : function TSTBase_readyToOpenNextSiblingTab(aTabOrSomething) /* PUBLIC API */ 
 	{
 		var browser = this.getBrowserFromTabBrowserElements(aTabOrSomething);
@@ -1611,6 +1465,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 		this.stopToOpenChildTab(browser);
 
 		var ownerBrowser = this.getTabBrowserFromChild(browser);
+		ownerBrowser.treeStyleTab.readiedToAttachNewTab      = false;
 		ownerBrowser.treeStyleTab.readiedToAttachNewTabGroup = true;
 		ownerBrowser.treeStyleTab.readiedToAttachMultiple    = true;
 		ownerBrowser.treeStyleTab.multipleCount              = 0;
@@ -1649,18 +1504,17 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 
 		var ownerBrowser = this.getTabBrowserFromChild(browser);
 
-		if (ownerBrowser.treeStyleTab.readiedToAttachNewTab && utils.isDebugging('base'))
-			dump('Tree Style Tab: new child tab is canceled.\n'+
-			     new Error().stack.replace(/^/gm, '  ')+'\n');
+		if (ownerBrowser.treeStyleTab.readiedToAttachNewTab)
+			logWithStackTrace('new child tab is canceled.');
 
-		ownerBrowser.treeStyleTab.readiedToAttachNewTab      = false;
-		ownerBrowser.treeStyleTab.readiedToAttachNewTabGroup = false;
-		ownerBrowser.treeStyleTab.readiedToAttachMultiple    = false;
-		ownerBrowser.treeStyleTab.multipleCount              = -1;
-		ownerBrowser.treeStyleTab.parentTab                  = null;
-		ownerBrowser.treeStyleTab.insertBefore               = null;
-		ownerBrowser.treeStyleTab.treeStructure              = null;
-		ownerBrowser.treeStyleTab.shouldExpandAllTree        = false;
+		delete ownerBrowser.treeStyleTab.readiedToAttachNewTab;
+		delete ownerBrowser.treeStyleTab.readiedToAttachNewTabGroup;
+		delete ownerBrowser.treeStyleTab.readiedToAttachMultiple;
+		delete ownerBrowser.treeStyleTab.multipleCount;
+		delete ownerBrowser.treeStyleTab.parentTab;
+		delete ownerBrowser.treeStyleTab.insertBefore;
+		delete ownerBrowser.treeStyleTab.treeStructure;
+		delete ownerBrowser.treeStyleTab.shouldExpandAllTree;
 
 		return true;
 	},
@@ -1693,6 +1547,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 			case this.kNEWTAB_OPEN_AS_ORPHAN:
 			case this.kNEWTAB_DO_NOTHING:
 			default:
+				this.readyToOpenOrphanTabNow(aBaseTab);
 				break;
 			case this.kNEWTAB_OPEN_AS_CHILD:
 				this.readyToOpenChildTabNow(aBaseTab);
@@ -1820,7 +1675,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 			}
 		}
 		else {
-			parent =  this.evaluateXPath(
+			parent = utils.evaluateXPath(
 				'preceding-sibling::xul:tab[@'+this.kID+'="'+id+'"][1]',
 				aTab,
 				Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
@@ -1843,8 +1698,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 								aTab.label+'\n     '+
 								aTab.getAttribute(this.kID);
 					}, this).join('\n');
-				if (utils.isDebugging('base'))
-					dump(message+'\n');
+				log(message);
 				break;
 			}
 
@@ -1856,8 +1710,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 								aTab.label+'\n     '+
 								aTab.getAttribute(this.kID);
 					}, this).join('\n');
-				if (utils.isDebugging('base'))
-					dump(message+'\n');
+				log(message);
 			}
 
 			tabs.push(parentTab);
@@ -1876,7 +1729,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 			return ancestors.length ? ancestors[ancestors.length-1] : aTab ;
 		}
 
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 			'(self::*[not(@'+this.kPARENT+')] | preceding-sibling::xul:tab[not(@'+this.kPARENT+')])[last()]',
 			aTab,
 			Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
@@ -1917,7 +1770,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 		}
 
 		var parent = aTab.getAttribute(this.kPARENT);
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 			'following-sibling::xul:tab['+
 				(parent ? '@'+this.kPARENT+'="'+parent+'"' : 'not(@'+this.kPARENT+')' )+
 			'][1]',
@@ -1959,7 +1812,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 		}
 
 		var parent = aTab.getAttribute(this.kPARENT);
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 			'preceding-sibling::xul:tab['+
 				(parent ? '@'+this.kPARENT+'="'+parent+'"' : 'not(@'+this.kPARENT+')' )+
 			'][1]',
@@ -2004,8 +1857,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 								aTab.label+'\n     '+
 								aTab.getAttribute(this.kID);
 					}, this).join('\n');
-				if (utils.isDebugging('base'))
-					dump(message+'\n');
+				log(message);
 				continue;
 			}
 			tabs.push(tab);
@@ -2050,7 +1902,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 			return firstChild;
 		}
 
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 			'following-sibling::xul:tab[@'+this.kPARENT+'="'+aTab.getAttribute(this.kID)+'"][1]',
 			aTab,
 			Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
@@ -2077,7 +1929,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 			return lastChild;
 		}
 
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 			'following-sibling::xul:tab[@'+this.kPARENT+'="'+aTab.getAttribute(this.kID)+'"][last()]',
 			aTab,
 			Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
@@ -2146,7 +1998,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 								'[not(@'+this.kCOLLAPSED+'="true")]' :
 								'' ;
 
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 			'sum((self::* | preceding-sibling::xul:tab[not(@hidden="true")]'+extraCondition+')'+
 				'/attribute::'+this.kX_OFFSET+')',
 			aTab,
@@ -2159,7 +2011,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 								'[not(@'+this.kCOLLAPSED+'="true")]' :
 								'';
 
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 			'sum((self::* | preceding-sibling::xul:tab[not(@hidden="true")]'+extraCondition+')'+
 				'/attribute::'+this.kY_OFFSET+')',
 			aTab,
@@ -2213,16 +2065,13 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
  
 	isGroupTab : function TSTBase_isGroupTab(aTab, aLazyCheck) 
 	{
-		return (
-			(aLazyCheck || aTab.linkedBrowser.sessionHistory.count == 1) &&
-			aTab.linkedBrowser.currentURI.spec.indexOf('about:treestyletab-group') == 0
-		);
+		return aTab.linkedBrowser.currentURI.spec.indexOf('about:treestyletab-group') == 0;
 	},
  
 	isTemporaryGroupTab : function TSTBase_isTemporaryGroupTab(aTab) 
 	{
 		return (
-			this.isGroupTab(aTab, true) &&
+			this.isGroupTab(aTab) &&
 			/.*[\?&;]temporary=(?:1|yes|true)/i.test(aTab.linkedBrowser.currentURI.spec)
 		);
 	},
@@ -2246,48 +2095,6 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 		return collapsedStates;
 	},
  
-	getTreeStructureFromTabs : function TSTBase_getTreeStructureFromTabs(aTabs) 
-	{
-		/* this returns...
-		  [A]     => -1 (parent is not in this tree)
-		    [B]   => 0 (parent is 1st item in this tree)
-		    [C]   => 0 (parent is 1st item in this tree)
-		      [D] => 2 (parent is 2nd in this tree)
-		  [E]     => -1 (parent is not in this tree, and this creates another tree)
-		    [F]   => 0 (parent is 1st item in this another tree)
-		*/
-		return this.cleanUpTreeStructureArray(
-				aTabs.map(function(aTab, aIndex) {
-					let tab = this.getParentTab(aTab);
-					let index = tab ? aTabs.indexOf(tab) : -1 ;
-					return index >= aIndex ? -1 : index ;
-				}, this),
-				-1
-			);
-	},
-	cleanUpTreeStructureArray : function TSTBase_cleanUpTreeStructureArray(aTreeStructure, aDefaultParent)
-	{
-		var offset = 0;
-		aTreeStructure = aTreeStructure
-			.map(function(aPosition, aIndex) {
-				return (aPosition == aIndex) ? -1 : aPosition ;
-			})
-			.map(function(aPosition, aIndex) {
-				if (aPosition == -1) {
-					offset = aIndex;
-					return aPosition;
-				}
-				return aPosition - offset;
-			});
-
-		/* The final step, this validates all of values.
-		   Smaller than -1 is invalid, so it becomes to -1. */
-		aTreeStructure = aTreeStructure.map(function(aIndex) {
-				return aIndex < -1 ? aDefaultParent : aIndex ;
-			}, this);
-		return aTreeStructure;
-	},
- 
 	applyTreeStructureToTabs : function TSTBase_applyTreeStructureToTabs(aTabs, aTreeStructure, aExpandStates) 
 	{
 		var b = this.getTabBrowserFromChild(aTabs[0]);
@@ -2339,7 +2146,7 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
  
 	getTreeStructureFromTabBrowser : function TSTBase_getTreeStructureFromTabBrowser(aTabBrowser) 
 	{
-		return this.getTreeStructureFromTabs(this.getAllTabs(aTabBrowser));
+		return utils.getTreeStructureFromTabs(this.getAllTabs(aTabBrowser));
 	},
  
 	applyTreeStructureToTabBrowser : function TSTBase_applyTreeStructureToTabBrowser(aTabBrowser, aTreeStructure, aExpandAllTree) 
@@ -2403,7 +2210,6 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 	domains : [ 
 		'extensions.treestyletab.',
 		'browser.tabs.animate',
-		'browser.tabs.insertRelatedAfterCurrent',
 		'extensions.stm.tabBarMultiRows' // Super Tab Mode
 	],
  
@@ -2435,13 +2241,11 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 			case 'extensions.treestyletab.tabbar.shrunkenWidth':
 				return this.correctMismatchedTabWidthPrefs(aPrefName);
 
-			case 'browser.tabs.insertRelatedAfterCurrent':
 			case 'extensions.stm.tabBarMultiRows': // Super Tab Mode
 				if (this.prefOverriding)
 					return;
 				aPrefName += '.override';
 				prefs.setPref(aPrefName, value);
-			case 'browser.tabs.insertRelatedAfterCurrent.override':
 			case 'extensions.stm.tabBarMultiRows.override': // Super Tab Mode
 				if (prefs.getPref(aPrefName+'.force')) {
 					let defaultValue = prefs.getDefaultPref(aPrefName);
@@ -2472,9 +2276,6 @@ var TreeStyleTabBase = inherit(TreeStyleTabConstants, {
 			case 'extensions.treestyletab.tabbar.scrollToNewTab.mode':
 				return this.scrollToNewTabMode = value;
 
-			case 'extensions.treestyletab.tabbar.narrowScrollbar.size':
-				return this.updateNarrowScrollbarStyle();
-
 			case 'browser.tabs.animate':
 				return this.animationEnabled = value;
 			case 'extensions.treestyletab.animation.indent.duration':
diff --git a/modules/bookmark.js b/modules/bookmark.js
new file mode 100644
index 0000000..943d25c
--- /dev/null
+++ b/modules/bookmark.js
@@ -0,0 +1,504 @@
+/* ***** BEGIN LICENSE BLOCK ***** 
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Tree Style Tab.
+ *
+ * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
+ * Portions created by the Initial Developer are Copyright (C) 2016
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ******/
+ 
+var EXPORTED_SYMBOLS = ['TreeStyleTabBookmarksService']; 
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+
+Cu.import('resource:///modules/PlacesUIUtils.jsm');
+Cu.import('resource://gre/modules/PlacesUtils.jsm');
+
+Cu.import('resource://treestyletab-modules/lib/inherit.jsm');
+Cu.import('resource://treestyletab-modules/constants.js');
+
+XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
+
+function log(...aArgs) {
+	utils.log.apply(utils, ['bookmark'].concat(aArgs));
+}
+function logWithStackTrace(...aArgs) {
+	utils.logWithStackTrace.apply(utils, ['bookmark'].concat(aArgs));
+}
+
+var TreeStyleTabBookmarksService = inherit(TreeStyleTabConstants, {
+	get BookmarksService() {
+		if (!this._BookmarksService) {
+			this._BookmarksService = Cc['@mozilla.org/browser/nav-bookmarks-service;1']
+										.getService(Ci.nsINavBookmarksService);
+		}
+		return this._BookmarksService;
+	},
+	_BookmarksService : null,
+
+
+	beginAddBookmarksFromTabs : function TSTBMService_beginAddBookmarksFromTabs(aTabs) /* PUBLIC API */ 
+	{
+		if (this._observing ||
+			!aTabs ||
+			aTabs.length <= 0)
+			return;
+
+		this._observing = true;
+
+		var TST = aTabs[0].ownerDocument.defaultView.TreeStyleTabService;
+		aTabs = TST.cleanUpTabsArray(aTabs);
+
+		this._addingBookmarks = [];
+		this._addingBookmarkTreeStructure = aTabs.map(function(aTab) {
+			var parent = TST.getParentTab(aTab);
+			return aTabs.indexOf(parent);
+		}, this);
+
+		this.BookmarksService.addObserver(this, false);
+	},
+ 
+	endAddBookmarksFromTabs : function TSTBMService_endAddBookmarksFromTabs() /* PUBLIC API */ 
+	{
+		if (!this._observing)
+			return;
+
+		this._observing = false;
+
+		this.BookmarksService.removeObserver(this);
+		this.handleNewBookmarksFromTabs(this._addingBookmarks, this._addingBookmarkTreeStructure);
+		this._addingBookmarks = [];
+		this._addingBookmarkTreeStructure = [];
+	},
+ 
+	handleNewBookmarksFromTabs : function TSTBMService_handleNewBookmarksFromTabs(aBookarmks, aTreeStructure) 
+	{
+		// this is adding bookmark folder from tabs, so ignroe the first item!
+		if (
+			aBookarmks.length == aTreeStructure.length+1 &&
+			this.BookmarksService.getItemType(aBookarmks[0].id) == this.BookmarksService.TYPE_FOLDER
+			) {
+			aBookarmks.shift();
+		}
+		else if (aBookarmks.length != aTreeStructure.length) {
+			return;
+		}
+
+		for (let i = 0, maxi = aBookarmks.length; i < maxi; i++)
+		{
+			let item = aBookarmks[i];
+			item.position = this.BookmarksService.getItemIndex(item.id);
+		}
+		aBookarmks.sort(function(aA, aB) {
+			return aA.position - aB.position;
+		});
+
+		for (let i = 0, maxi = aBookarmks.length; i < maxi; i++)
+		{
+			let item = aBookarmks[i];
+			if (this.BookmarksService.getItemType(item.id) != this.BookmarksService.TYPE_BOOKMARK)
+				continue;
+
+			let uri = this.BookmarksService.getBookmarkURI(item.id);
+			if (/^about:treestyletab-group\b/.test(uri.spec)) {
+				let title = this.BookmarksService.getItemTitle(item.id);
+				let folderId = this.BookmarksService.createFolder(item.parent, title, item.position);
+				this.BookmarksService.removeItem(item.id);
+				item.id = folderId;
+				item.isFolder = true;
+			}
+
+			let index = aTreeStructure[i];
+			let parent = index > -1 ? aBookarmks[index] : null ;
+			if (parent && (parent.folder || parent).isFolder) {
+				let folder = parent.isFolder ? parent : parent.folder ;
+				this.BookmarksService.moveItem(item.id, folder.id, -1);
+				item.folder = folder;
+			}
+			if (parent && !parent.isFolder) {
+				PlacesUtils.setAnnotationsForItem(item.id, [{
+					name    : this.kPARENT,
+					value   : parent ? parent.id : -1,
+					expires : PlacesUtils.annotations.EXPIRE_NEVER
+				}]);
+			}
+		}
+	},
+
+	bookmarkTabSubtree : function TSTBMService_bookmarkTabSubtree(aTabOrTabs) 
+	{
+		var tabs = aTabOrTabs;
+		if (!Array.isArray(tabs)) {
+			tabs = [aTabOrTabs];
+		}
+		if (tabs.length <= 0)
+			return;
+
+		var window = tabs[0].ownerDocument.defaultView;
+		var TST = window.TreeStyleTabService;
+
+		var folderName = (TST.isGroupTab(tabs[0]) || tabs.length == 1) ?
+						tabs[0].label :
+						null ;
+
+		var b = TST.getTabBrowserFromChild(tabs[0]);
+		var bookmarkedTabs = [];
+		for (let i = 0, maxi = tabs.length; i < maxi; i++)
+		{
+			let tab = tabs[i];
+			if (!TST.isGroupTab(tab))
+				bookmarkedTabs.push(tab);
+			bookmarkedTabs = bookmarkedTabs.concat(b.treeStyleTab.getDescendantTabs(tab));
+		}
+
+		this.beginAddBookmarksFromTabs(bookmarkedTabs);
+		try {
+			window['piro.sakura.ne.jp'].bookmarkMultipleTabs.addBookmarkFor(bookmarkedTabs, folderName);
+		}
+		catch(e) {
+		}
+		this.endAddBookmarksFromTabs();
+	},
+	bookmarkTabSubTree : function() { return this.bookmarkTabSubtree.apply(this, arguments); }, // obsolete, for backward compatibility
+
+	getParentItem : function TSTBMService_getParentItem(aId) 
+	{
+		if (aId < 0) return -1;
+		var annotations = PlacesUtils.getAnnotationsForItem(aId);
+		for (let i in annotations)
+		{
+			if (annotations[i].name != this.kPARENT) continue;
+			return parseInt(annotations[i].value);
+		}
+		return -1;
+	},
+
+	getTreeStructureFromItems : function TSTBMService_getTreeStructureFromItems(aIDs, aDefaultParentID) 
+	{
+		/* this returns a result same to utils.getTreeStructureFromTabs().
+		  [A]     => -1 (parent is not in this tree)
+		    [B]   => 0 (parent is 1st item in this tree)
+		    [C]   => 0 (parent is 1st item in this tree)
+		      [D] => 2 (parent is 2nd in this tree)
+		  [E]     => -1 (parent is not in this tree, and this creates another tree)
+		    [F]   => 0 (parent is 1st item in this another tree)
+		*/
+		if (aDefaultParentID === void(0))
+			aDefaultParentID = -1;
+
+		/* Get array of parents. The index becomes to -1,
+		   if there is NO PARENT or the parent is THE TAB ITSELF. */
+		var treeStructure = aIDs.map(function(aId, aIndex) {
+				let id = this.getParentItem(aId);
+				let index = aIDs.indexOf(id);
+				return index >= aIndex ? aDefaultParentID : index ;
+			}, this);
+
+		/* Correct patterns like:
+		     [TabA]
+		     [TabB] - this has no parent
+		       [TabC] - TabA's child
+		   to:
+		     [TabA]
+		       [TabB]
+		       [TabC]
+		*/
+		treeStructure = treeStructure.reverse();
+		treeStructure = treeStructure.map(function(aPosition, aIndex) {
+				if (aIndex > 0 &&
+					aIndex < treeStructure.length-1 &&
+					aPosition < 0) {
+					aPosition = treeStructure[aIndex-1];
+				}
+				return aPosition;
+			});
+		treeStructure = treeStructure.reverse();
+
+		return utils.cleanUpTreeStructureArray(treeStructure, aDefaultParentID);
+	},
+ 
+	// based on PlacesUtils.getURLsForContainerNode()
+	getItemIdsForContainerNode : function TSTBMService_getItemIdsForContainerNode(aNode) 
+	{
+		var ids = [];
+		if (!aNode || !PlacesUtils.nodeIsContainer(aNode)) return ids;
+
+		var root = aNode;
+		if ('getContainerNodeWithOptions' in PlacesUtils) {
+			root = PlacesUtils.getContainerNodeWithOptions(root, false, true);
+		}
+		var oldViewer = root.parentResult.viewer;
+		var wasOpen = root.containerOpen;
+		if (!wasOpen) {
+			if (oldViewer)
+				root.parentResult.viewer = null;
+			root.containerOpen = true;
+		}
+		for (let i = 0, maxi = root.childCount; i < maxi; ++i)
+		{
+			let child = root.getChild(i);
+			if (PlacesUtils.nodeIsURI(child)) ids.push(child.itemId || -1);
+		}
+		if (!wasOpen) {
+			root.containerOpen = false;
+			if (oldViewer)
+				root.parentResult.viewer = oldViewer;
+		}
+		return ids;
+	},
+
+	handleTabsOpenProcess : function TSTBMService_handleTabsOpenProcess(aWhere, aEvent, aBrowserWindow, aIDs, aURLs, aItemsToOpen, aFolderTitle)
+	{
+		var result = {
+				behavior      : undefined,
+				treeStructure : undefined,
+				treeStructureApplied : false
+			};
+		if (
+			aEvent.type != 'drop' &&
+			aWhere.indexOf('tab') != 0 &&
+			aEvent.target.id != 'placesContext_openContainer:tabs' &&
+			aEvent.target.id != 'placesContext_openLinks:tabs' &&
+			aEvent.target != aEvent.target.parentNode._endOptOpenAllInTabs &&
+			aEvent.target.getAttribute('openInTabs') != 'true'
+			)
+			return result;
+
+		var TST = aBrowserWindow.TreeStyleTabService;
+
+		result.behavior = TST.openGroupBookmarkBehavior();
+		if (result.behavior & this.kGROUP_BOOKMARK_SUBTREE) {
+			log('handleTabsOpenProcess: open as a group');
+			let treeStructure = result.behavior & this.kGROUP_BOOKMARK_DONT_RESTORE_TREE_STRUCTURE ?
+						null :
+						this.getTreeStructureFromItems(aIDs) ;
+			log('  treeStructure => ', treeStructure);
+			if (treeStructure) {
+				let parentTabs = treeStructure.filter(function(aParent) {
+						return aParent < 0;
+					});
+				let haveMultipleTrees = parentTabs.length != treeStructure.length;
+				if (result.behavior & this.kGROUP_BOOKMARK_USE_DUMMY) {
+					log('  trying to use dummy group tab');
+					let parentCount = 0;
+					let childCount = 0;
+					for (let i in treeStructure) {
+						if (treeStructure[i] == -1)
+							parentCount++;
+						else
+							childCount++;
+					}
+					log('  parentCount: '+parentCount);
+					log('  childCount: '+childCount);
+					if (
+						parentCount > 1 &&
+						(
+							result.behavior & this.kGROUP_BOOKMARK_USE_DUMMY_FORCE ||
+							// when there is any orphan, then all of parents and orphans should be grouped under a dummy tab.
+							childCount < parentCount
+						)
+						) {
+						aIDs.unshift(-1);
+						treeStructure = this.getTreeStructureFromItems(aIDs, 0);
+						let uri = utils.getGroupTabURI({
+							title:     aFolderTitle,
+							temporary: utils.getTreePref('openGroupBookmark.temporaryGroup')
+						});
+						aURLs.unshift(uri);
+						aItemsToOpen.unshift({
+							itemId: -1,
+							title:  aFolderTitle,
+							uri:    uri
+						})
+						log('  updated treeStructure => ', treeStructure);
+					}
+				}
+				else if (!haveMultipleTrees) {
+					// make the first item parent.
+					treeStructure = treeStructure.map(function(aParent, aIndex) {
+						if (aIndex == 0)
+							return aParent;
+						if (aParent < 0)
+							return 0;
+						return aParent;
+					});
+				}
+			}
+
+			result.treeStructure = treeStructure;
+
+			if (utils.getTreePref('compatibility.TMP') &&
+				'TMP_Places' in aBrowserWindow &&
+				'openGroup' in aBrowserWindow.TMP_Places) {
+				result.treeStructureApplied = false;
+			}
+			else {
+				TST.readyToOpenNewTabGroup(null, treeStructure, result.behavior & this.kGROUP_BOOKMARK_EXPAND_ALL_TREE);
+				result.treeStructureApplied = true;
+			}
+		}
+		else {
+			TST.browser.treeStyleTab.nextOpenedTabToBeParent = false;
+		}
+		return result;
+	},
+
+
+	// observer for nsINavBookmarksService 
+	onItemAdded : function TSTBMService_onItemAdded(aID, aFolderID, aPosition)
+	{
+		this._addingBookmarks.push({
+			id     : aID,
+			parent : aFolderID
+		});
+	},
+	onItemRemoved : function TSTBMService_onItemRemoved(aID, aFolderID, aPosition) {},
+	onItemMoved : function TSTBMService_onItemMoved(aID, aFolderID, aPosition) {},
+	onItemChanged : function TSTBMService_onItemChanged(aID, aChange, aIsAnnotation, aNewValue) {},
+	onItemVisited : function TSTBMService_onItemVisited(aID, aHistoryID, aDate) {},
+	onBeginUpdateBatch : function TSTBMService_onBeginUpdateBatch() {},
+	onEndUpdateBatch : function TSTBMService_onEndUpdateBatch() {}
+});
+
+
+PlacesUIUtils.__treestyletab__openTabset = PlacesUIUtils._openTabset;
+PlacesUIUtils._openTabset = function(aItemsToOpen, aEvent, aWindow, ...aArgs) {
+	log('TSTBookmarks_openTabset');
+
+	var uris = [];
+	var ids = [];
+	var nodes = this.__treestyletab__openTabset_rawNodes || [];
+	aItemsToOpen = aItemsToOpen.filter(function(aItem, aIndex) {
+		if (aItem.uri) {
+			uris.push(aItem.uri);
+			let id = aItem.id;
+			if (!id && aIndex in nodes)
+				id = nodes[aIndex].itemId;
+			ids.push(id);
+			log('  '+aIndex+': '+id+' / '+aItem.uri);
+			return true;
+		}
+		return false;
+	});
+	log('  items => '+aItemsToOpen.length);
+
+	var allArgs = [aItemsToOpen, aEvent, aWindow].concat(aArgs);
+	if (aItemsToOpen.length <= 0)
+		return this.__treestyletab__openTabset.apply(this, allArgs);
+
+	var w = aWindow && aWindow.document.documentElement.getAttribute('windowtype') == 'navigator:browser' ?
+			aWindow :
+			this._getTopBrowserWin() ;
+	var TST = w.TreeStyleTabService;
+	var BS = TreeStyleTabBookmarksService;
+
+	var where = w && w.whereToOpenLink(aEvent, false, true) || 'window';
+	log('  where: '+where);
+	if (where === 'window')
+		return this.__treestyletab__openTabset.apply(this, allArgs);
+
+	var result = BS.handleTabsOpenProcess(where, aEvent, w, ids, uris, aItemsToOpen, this.__treestyletab__folderName);
+	log('  result: ', result);
+
+	var tabs = TST.doAndGetNewTabs((function() {
+			this.__treestyletab__openTabset.apply(this, allArgs);
+		}).bind(this), w.gBrowser);
+	log('  tabs: '+tabs.length);
+
+	if (!result.treeStructure)
+		tabs = [];
+
+	if (!result.treeStructureApplied)
+		TST.applyTreeStructureToTabs(
+			tabs,
+			result.treeStructure,
+			result.behavior & BS.kGROUP_BOOKMARK_EXPAND_ALL_TREE
+		);
+
+	var loadInBackground = where == 'tabshifted';
+	if (!loadInBackground) {
+		// start scroll after expanding animation is finished
+		w.setTimeout(function() {
+			w.gBrowser.treeStyleTab.scrollToTabs(tabs);
+		}, w.gBrowser.treeStyleTab.collapseDuration);
+	}
+};
+
+PlacesUtils.__treestyletab__getURLsForContainerNode = PlacesUtils.getURLsForContainerNode;
+PlacesUtils.getURLsForContainerNode = function(aNode, ...aArgs) {
+	var uris = this.__treestyletab__getURLsForContainerNode.apply(this, [aNode].concat(aArgs));
+	var nodes = TreeStyleTabBookmarksService.getItemIdsForContainerNode(aNode);
+	for (let i in nodes) {
+		uris[i].id = nodes[i];
+	}
+	return uris;
+};
+
+PlacesUIUtils.__treestyletab__openContainerNodeInTabs = PlacesUIUtils.openContainerNodeInTabs;
+PlacesUIUtils.openContainerNodeInTabs = function(aNode, ...aArgs) {
+	this.__treestyletab__folderName = aNode.title;
+	try {
+		return this.__treestyletab__openContainerNodeInTabs.apply(this, [aNode].concat(aArgs));
+	}
+	finally {
+		delete this.__treestyletab__folderName;
+	}
+};
+
+PlacesUIUtils.__treestyletab__openURINodesInTabs = PlacesUIUtils.openURINodesInTabs;
+PlacesUIUtils.openURINodesInTabs = function(aNode, ...aArgs) {
+	try {
+		this.__treestyletab__openTabset_rawNodes = aNodes;
+		this.__treestyletab__folderName = utils.treeBundle.getFormattedString(
+			PlacesUtils.nodeIsBookmark(aNodes[0]) ?
+				'openSelectedPlaces.bookmarks' :
+				'openSelectedPlaces.history',
+			[aNodes[0].title, aNodes.length]
+		);
+		return this.__treestyletab__openURINodesInTabs.apply(this, [aNode].concat(aArgs));
+	}
+	finally {
+		delete this.__treestyletab__openTabset_rawNodes;
+		delete this.__treestyletab__folderName;
+	}
+};
+
+PlacesUIUtils.__treestyletab__openNodeWithEvent = PlacesUIUtils.openNodeWithEvent;
+PlacesUIUtils.openNodeWithEvent = function(aNode, aEvent, aView, ...aArgs) {
+	var window = aView.ownerWindow;
+	if (!window.gBrowser)
+		window = PlacesUIUtils._getTopBrowserWin();
+	if (window && window.gBrowser)
+		window.gBrowser.treeStyleTab.readyToOpenOrphanTabNow();
+	return PlacesUIUtils.__treestyletab__openNodeWithEvent.apply(this, [aNode, aEvent, aView].concat(aArgs));
+};
diff --git a/modules/browser.js b/modules/browser.js
index e6e59e0..01b8a7d 100644
--- a/modules/browser.js
+++ b/modules/browser.js
@@ -14,7 +14,7 @@
  * The Original Code is the Tree Style Tab.
  *
  * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2011-2015
+ * Portions created by the Initial Developer are Copyright (C) 2011-2016
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
@@ -56,6 +56,7 @@ XPCOMUtils.defineLazyModuleGetter(this, 'TabpanelDNDObserver', 'resource://trees
 XPCOMUtils.defineLazyModuleGetter(this, 'AutoHideBrowser', 'resource://treestyletab-modules/autoHide.js');
 XPCOMUtils.defineLazyModuleGetter(this, 'ContentBridge', 'resource://treestyletab-modules/contentBridge.js');
 XPCOMUtils.defineLazyModuleGetter(this, 'BrowserUIShowHideObserver', 'resource://treestyletab-modules/browserUIShowHideObserver.js');
+XPCOMUtils.defineLazyModuleGetter(this, 'TabContentsObserver', 'resource://treestyletab-modules/tabContentsObserver.js');
 XPCOMUtils.defineLazyModuleGetter(this, 'visuallyselectedTabs', 'resource://treestyletab-modules/lib/visuallyselectedTabs.jsm');
 
 XPCOMUtils.defineLazyGetter(this, 'window', function() {
@@ -75,9 +76,11 @@ function wait(aMilliSeconds) {
 	});
 }
 
-function mydump(aString) {
-	if (utils.isDebugging('browser'))
-		dump(aString);
+function log(...aArgs) {
+	utils.log.apply(utils, ['browser'].concat(aArgs));
+}
+function logWithStackTrace(...aArgs) {
+	utils.logWithStackTrace.apply(utils, ['browser'].concat(aArgs));
 }
 
 Cu.import('resource://treestyletab-modules/window.js');
@@ -433,7 +436,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
  
 	get ownerToolbar() 
 	{
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 				'ancestor-or-self::xul:toolbar[1]',
 				this.mTabBrowser.tabContainer,
 				Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
@@ -588,6 +591,14 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			);
 	},
  
+	isTabInternallyMoving : function TSTBrowser_isTabInternallyMoving(aTab)
+	{
+		if (aTab &&
+			aTab.__treestyletab__internallyTabMovingCount)
+			return true;
+		return Boolean(this.internallyTabMovingCount);
+	},
+ 
 	isMultiRow : function TSTBrowser_isMultiRow() 
 	{
 		var w = this.window;
@@ -920,6 +931,8 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 
 		if (this.tabStripPlaceHolder)
 			this.tabStripPlaceHolderBoxObserver = new BrowserUIShowHideObserver(this, this.tabStripPlaceHolder.parentNode);
+
+		this.tabContentsObserver = new TabContentsObserver(this, this.tabStrip);
 	},
  
 	_initTabbrowserContextMenu : function TSTBrowser_initTabbrowserContextMenu() 
@@ -1072,6 +1085,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 
 		aTab.__treestyletab__linkedTabBrowser = this.mTabBrowser;
 		aTab.__treestyletab__restoreState = this.RESTORE_STATE_INITIAL;
+		aTab.__treestyletab__internallyTabMovingCount = 0;
 
 		if (utils.isTabNotRestoredYet(aTab))
 			aTab.linkedBrowser.__treestyletab__toBeRestored = true;
@@ -1174,52 +1188,61 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
  
 	initTabContentsOrder : function TSTBrowser_initTabContentsOrder(aTab, aForce) 
 	{
-		if (!aTab.parentNode) // do nothing for closed tab!
+		if (
+			!aTab.parentNode || // do nothing for closed tab!
+			aTab.__treestyletab__initializingContentsOrder
+			)
 			return;
 
-		var d = this.document;
+		aTab.__treestyletab__initializingContentsOrder = true;
 
-		var namedNodes = {
-				label        : this.getTabLabel(aTab),
-				sound        : this.getTabSoundButton(aTab),
-				close        : this.getTabClosebox(aTab),
-				twistyAnchor : this.getTabTwistyAnchorNode(aTab),
-				twisty       : this.getTabTwisty(aTab),
-				counter      : d.getAnonymousElementByAttribute(aTab, 'class', this.kCOUNTER_CONTAINER)
-			};
+		try {
+			var d = this.document;
+			var namedNodes = {
+					label        : this.getTabLabel(aTab),
+					sound        : this.getTabSoundButton(aTab),
+					close        : this.getTabClosebox(aTab),
+					twistyAnchor : this.getTabTwistyAnchorNode(aTab),
+					twisty       : this.getTabTwisty(aTab),
+					counter      : d.getAnonymousElementByAttribute(aTab, 'class', this.kCOUNTER_CONTAINER)
+				};
 
-		namedNodes.closeAnchor = namedNodes.label;
-		if (namedNodes.closeAnchor.parentNode != namedNodes.close.parentNode) {
-			let containerFinder = d.createRange();
-			containerFinder.selectNode(namedNodes.closeAnchor);
-			containerFinder.setEndAfter(namedNodes.close);
-			let container = containerFinder.commonAncestorContainer;
-			while (namedNodes.closeAnchor.parentNode != container)
-			{
-				namedNodes.closeAnchor = namedNodes.closeAnchor.parentNode;
+			namedNodes.closeAnchor = namedNodes.label;
+			if (namedNodes.closeAnchor.parentNode != namedNodes.close.parentNode) {
+				let containerFinder = d.createRange();
+				containerFinder.selectNode(namedNodes.closeAnchor);
+				containerFinder.setEndAfter(namedNodes.close);
+				let container = containerFinder.commonAncestorContainer;
+				while (namedNodes.closeAnchor.parentNode != container)
+				{
+					namedNodes.closeAnchor = namedNodes.closeAnchor.parentNode;
+				}
+				while (namedNodes.close.parentNode != container)
+				{
+					namedNodes.close = namedNodes.close.parentNode;
+				}
 			}
-			while (namedNodes.close.parentNode != container)
+
+			namedNodes.counterAnchor = namedNodes.label;
+
+			var foundContainers = [];
+			var containers = [
+					namedNodes.twistyAnchor.parentNode,
+					namedNodes.label.parentNode,
+					namedNodes.counter.parentNode,
+					namedNodes.closeAnchor.parentNode
+				];
+			for (let i = 0, maxi = containers.length; i < maxi; i++)
 			{
-				namedNodes.close = namedNodes.close.parentNode;
+				let container = containers[i];
+				if (foundContainers.indexOf(container) > -1)
+					continue;
+				this.initTabContentsOrderInternal(container, namedNodes, aForce);
+				foundContainers.push(container);
 			}
 		}
-
-		namedNodes.counterAnchor = namedNodes.label;
-
-		var foundContainers = [];
-		var containers = [
-				namedNodes.twistyAnchor.parentNode,
-				namedNodes.label.parentNode,
-				namedNodes.counter.parentNode,
-				namedNodes.closeAnchor.parentNode
-			];
-		for (let i = 0, maxi = containers.length; i < maxi; i++)
-		{
-			let container = containers[i];
-			if (foundContainers.indexOf(container) > -1)
-				continue;
-			this.initTabContentsOrderInternal(container, namedNodes, aForce);
-			foundContainers.push(container);
+		finally {
+			delete aTab.__treestyletab__initializingContentsOrder;
 		}
 	},
 	initTabContentsOrderInternal : function TSTBrowser_initTabContentsOrderInternal(aContainer, aNamedNodes, aForce) 
@@ -1246,7 +1269,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			if (this.mTabBrowser.getAttribute(this.kCLOSEBOX_INVERTED) == 'true')
 				nodes.splice(nodes.indexOf(aNamedNodes.closeAnchor), 0, aNamedNodes.close);
 			else
-				nodes.splice(nodes.indexOf(aNamedNodes.closeAnchor)+1, 0, aNamedNodes.close);
+				nodes.push(aNamedNodes.close);
 		}
 
 		index = nodes.indexOf(aNamedNodes.sound);
@@ -1738,7 +1761,9 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			// So, we have to turn the actual tab bar visible manually
 			// when the grippy is clicked.
 			let tabContainer = this.mTabBrowser.tabContainer;
-			grippy.grippyOnClick = function() {
+			grippy.grippyOnClick = function(aEvent) {
+				if (aEvent.button != 0)
+					return;
 				tabContainer.ownerDocument.defaultView.setTimeout(function() {
 					var visible = grippy.getAttribute('state') != 'collapsed';
 					if (visible != tabContainer.visible)
@@ -1760,6 +1785,8 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		ReferenceCounter.add('splitter,mouseup,windowService,false');
 		splitter.addEventListener('dblclick', this.windowService, false);
 		ReferenceCounter.add('splitter,dblclick,windowService,false');
+		splitter.addEventListener('click', this.windowService, false);
+		ReferenceCounter.add('splitter,click,windowService,false');
 
 		var ref = this.mTabBrowser.mPanelContainer;
 		ref.parentNode.insertBefore(splitter, ref);
@@ -1779,6 +1806,8 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			ReferenceCounter.remove('splitter,mouseup,windowService,false');
 			splitter.removeEventListener('dblclick', this.windowService, false);
 			ReferenceCounter.remove('splitter,dblclick,windowService,false');
+			splitter.removeEventListener('click', this.windowService, false);
+			ReferenceCounter.remove('splitter,click,windowService,false');
 			var grippy = splitter.firstChild;
 			grippy.removeEventListener('click', grippy.grippyOnClick, true);
 			ReferenceCounter.remove('grippy,click,grippy.grippyOnClick,true');
@@ -1965,7 +1994,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 				(aReason & this.kTABBAR_UPDATE_BY_AUTOHIDE ? 'autohide ' : '' ) +
 				(aReason & this.kTABBAR_UPDATE_BY_INITIALIZE ? 'initialize ' : '' ) +
 				(aReason & this.kTABBAR_UPDATE_BY_TOGGLE_SIDEBAR ? 'toggle-sidebar ' : '' );
-			mydump('TSTBrowser_updateFloatingTabbarInternal: ' + humanReadableReason + '\n');
+			log('updateFloatingTabbarInternal: ' + humanReadableReason);
 		}
 
 		var d = this.document;
@@ -2140,6 +2169,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			splitter.setAttribute('onmousedown', 'TreeStyleTabService.handleEvent(event);');
 			splitter.setAttribute('onmouseup', 'TreeStyleTabService.handleEvent(event);');
 			splitter.setAttribute('ondblclick', 'TreeStyleTabService.handleEvent(event);');
+			splitter.setAttribute('onclick', 'TreeStyleTabService.handleEvent(event);');
 			box.appendChild(splitter);
 			this.tabStrip.appendChild(box);
 		}
@@ -2303,6 +2333,11 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			delete this.tabStripPlaceHolderBoxObserver;
 		}
 
+		if (this.tabContentsObserver) {
+			this.tabContentsObserver.destroy();
+			delete this.tabContentsObserver;
+		}
+
 		this._destroyOldSplitter();
 
 		var w = this.window;
@@ -2760,6 +2795,12 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			case 'extensions.treestyletab.tabbar.narrowScrollbar':
 				return this.setTabbrowserAttribute(this.kNARROW_SCROLLBAR, value);
 
+			case 'extensions.treestyletab.tabbar.narrowScrollbar.width':
+				if (this.isVertical &&
+					this.mTabBrowser.mTabContainer.getAttribute('overflow') == 'true')
+					utils.updateNarrowScrollbarStyle(this.browser);
+				return;
+
 			case 'extensions.treestyletab.maxTreeLevel.physical':
 				if (this.maxTreeLevelPhysical = value)
 					this.promoteTooDeepLevelTabs();
@@ -3159,12 +3200,26 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		var pareintIndexInTree = hasStructure ? this.treeStructure.shift() : 0 ;
 		var lastRelatedTab = b._lastRelatedTab;
 
-		mydump('TSTBrowser_onTabOpen\n  ' + [
+		log('onTabOpen\n  ' + [
 		  'readiedToAttachNewTab: '+this.readiedToAttachNewTab,
 		  'parentTab: '+this.parentTab + ' (' + this.getTabById(this.parentTab) + ')',
 		  'insertBefore: '+this.insertBefore,
 		  'treeStructure: '+this.treeStructure
-		].join('\n  ') + '\n');
+		].join('\n  '));
+
+		if (utils.getTreePref('autoAttach') &&
+			typeof this.readiedToAttachNewTab !== 'boolean') {
+			this.window.setTimeout((function() {
+				if (!tab.owner || tab != b._lastRelatedTab)
+					return;
+				log('onTabOpen: new child tab opened by browser.tabs.insertRelatedAfterCurrent=true');
+				var nextTab = this.findNextTabForNewChild(tab, tab.owner);
+				log('  next tab: '+(nextTab && nextTab._tPos));
+				this.attachTabTo(tab, tab.owner, {
+					insertBefore: nextTab
+				});
+			}).bind(this), 0);
+		}
 
 		if (this.readiedToAttachNewTab) {
 			if (pareintIndexInTree < 0) { // there is no parent, so this is a new parent!
@@ -3193,7 +3248,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			else if (
 				parent &&
 				utils.getTreePref('insertNewChildAt') == this.kINSERT_FISRT &&
-				(this.multipleCount <= 0 || this._addedCountInThisLoop <= 0)
+				(typeof this.multipleCount !== 'number' || this._addedCountInThisLoop <= 0)
 				) {
 				/* 複数の子タブを一気に開く場合、最初に開いたタブだけを
 				   子タブの最初の位置に挿入し、続くタブは「最初の開いたタブ」と
@@ -3202,13 +3257,18 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 				if (refTab = this.getFirstChildTab(parent))
 					this.insertBefore = refTab.getAttribute(this.kID);
 			}
+			else {
+				refTab = this.findNextTabForNewChild(tab, parent);
+				if (refTab)
+					nextIndex = refTab._tPos;
+			}
 
 			if (newIndex > -1) {
 				if (newIndex > tab._tPos)
 					newIndex--;
-				this.internallyTabMovingCount++;
+				tab.__treestyletab__internallyTabMovingCount++;
 				b.moveTabTo(tab, newIndex);
-				this.internallyTabMovingCount--;
+				tab.__treestyletab__internallyTabMovingCount--;
 			}
 
 			if (this.shouldExpandAllTree)
@@ -3217,10 +3277,10 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 
 		this._addedCountInThisLoop++;
 		if (!this._addedCountClearTimer) {
-			this._addedCountClearTimer = this.window.setTimeout(function(aSelf) {
-				aSelf._addedCountInThisLoop = 0;
-				aSelf._addedCountClearTimer = null;
-			}, 0, this);
+			this._addedCountClearTimer = this.window.setTimeout((function() {
+				this._addedCountInThisLoop = 0;
+				this._addedCountClearTimer = null;
+			}).bind(this), 0);
 		}
 
 		if (!this.readiedToAttachMultiple) {
@@ -3269,12 +3329,41 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		 */
 		b._lastRelatedTab = lastRelatedTab;
 
+		// this is the first tab of loading group.
+		if (this.nextOpenedTabToBeParent) {
+			this.readyToOpenChildTab(tab, true);
+		}
+		delete this.nextOpenedTabToBeParent;
+
+		tab.__treestyletab__isOpening = true;
+		this.window.setTimeout((function() {
+			tab.__treestyletab__isOpening = false;
+		}).bind(this), 0);
+
 		return true;
 	},
+	loadingMultipleTabs : false,
 	_addedCountInThisLoop : 0,
 	_addedCountClearTimer : null,
 	_checkRestoringWindowTimerOnTabAdded : null,
 	
+	findNextTabForNewChild : function TSTBrowser_findNextTabForNewChild(aTab, aParent) 
+	{
+		if (!aParent)
+			return this.getNextTab(aTab);
+
+		var nextTab;
+		if (utils.getTreePref('insertNewChildAt') === this.kINSERT_FISRT)
+			nextTab = this.getFirstChildTab(aParent);
+		else
+			nextTab = this.getNextSiblingTab(aParent) || this.getNextTab(this.getLastDescendantTab(aParent));
+
+		if (nextTab == aTab)
+			nextTab = this.getNextTab(nextTab);
+
+		return nextTab;
+	},
+ 
 	scrollToNewTab : function TSTBrowser_scrollToNewTab(aTab) 
 	{
 		if (!aTab.parentNode) // do nothing for closed tab!
@@ -3347,7 +3436,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		var closeParentBehavior = this.getCloseParentBehaviorForTab(tab);
 
 		var backupAttributes = this._collectBackupAttributes(tab);
-		mydump('onTabClose: backupAttributes = '+JSON.stringify(backupAttributes)+'\n');
+		log('onTabClose: backupAttributes = ', backupAttributes);
 
 		if (closeParentBehavior == this.kCLOSE_PARENT_BEHAVIOR_CLOSE_ALL_CHILDREN ||
 			this.isSubtreeCollapsed(tab))
@@ -3574,7 +3663,16 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		var b   = this.mTabBrowser;
 
 		var prevPosition = aEvent.detail;
+		if (tab.__treestyletab__isOpening && !this.isTabInternallyMoving(tab)) {
+			log('onTabMove for new child tab: move back '+tab._tPos+' => '+prevPosition);
+			tab.__treestyletab__internallyTabMovingCount++;
+			b.moveTabTo(tab, prevPosition);
+			tab.__treestyletab__internallyTabMovingCount--;
+			return;
+		}
+
 		tab.__treestyletab__previousPosition = prevPosition;
+		logWithStackTrace('onTabMove '+prevPosition+' => '+tab._tPos+' (internal moving count='+tab.__treestyletab__internallyTabMovingCount+', owner='+String(tab.owner)+')');
 
 		// When the tab was moved before TabOpen event is fired, we have to update manually.
 		var newlyOpened = !this.isTabInitialized(tab) && this.onTabOpen(null, tab);
@@ -3597,8 +3695,11 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			if (storedId && tab.getAttribute(this.kID) != storedId)
 				restored = this.onTabRestoring(aEvent);
 		}
+		log('  newlyOpened: '+newlyOpened);
+		log('  restored:    '+restored);
 
 		if (this.hasChildTabs(tab) && !this.subTreeMovingCount) {
+			log('  => move sub tree');
 			this.moveTabSubtreeTo(tab, tab._tPos);
 		}
 
@@ -3634,6 +3735,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			if (!this.subTreeChildrenMovingCount)
 				this.updateChildrenArray(parentTab);
 		}
+		log('  tabsToBeUpdated: '+tabsToBeUpdated.map(function(aTab) { return aTab._tPos; }));
 
 		var updatedTabs = new WeakMap();
 		tabsToBeUpdated.forEach(function(aTab) {
@@ -3651,7 +3753,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 
 		if (
 			this.subTreeMovingCount ||
-			this.internallyTabMovingCount ||
+			this.isTabInternallyMoving(tab) ||
 			// We don't have to fixup tree structure for a NEW TAB
 			// which has already been structured.
 			(newlyOpened && this.getParentTab(tab))
@@ -3666,15 +3768,18 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 	
 	attachTabFromPosition : function TSTBrowser_attachTabFromPosition(aTab, aOldPosition) 
 	{
+		log('attachTabFromPosition '+aOldPosition+' => '+aTab._tPos);
 		var parent = this.getParentTab(aTab);
 
 		if (aOldPosition === void(0))
 			aOldPosition = aTab._tPos;
 
 		var pos = this.getChildIndex(aTab, parent);
-		var oldPos = this.getChildIndex(this.getAllTabs(this.mTabBrowser)[aOldPosition], parent);
+		var oldPositionTab = this.getAllTabs(this.mTabBrowser)[aOldPosition];
+		var oldPos = this.getChildIndex(oldPositionTab, parent);
 		var delta;
-		if (pos == oldPos) { // no move?
+		if (oldPositionTab == aTab && pos == oldPos) { // no move?
+			log('  => no move');
 			return;
 		}
 		else if (pos < 0 || oldPos < 0) {
@@ -3684,51 +3789,54 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			delta = Math.abs(pos - oldPos);
 		}
 
-		mydump('attachTabFromPosition '+aTab._tPos+' / '+aOldPosition+'\n');
-		mydump((new Error()).stack.replace(/^/gm, '  ')+'\n');
+		logWithStackTrace('  moving');
 
-		var prevTab = this.getPreviousTab(aTab);
-		var nextTab = this.getNextTab(aTab);
+		var prevTab = this.getPreviousVisibleTab(aTab);
+		var nextTab = this.getNextVisibleTab(aTab);
 
 		var tabs = this.getDescendantTabs(aTab);
 		if (tabs.length) {
 			nextTab = this.getNextTab(tabs[tabs.length-1]);
 		}
+		log('  prevTab: '+(prevTab&&(prevTab._tPos+'('+prevTab.linkedBrowser.currentURI.spec+')')));
+		log('  nextTab: '+(nextTab&&(nextTab._tPos+'('+nextTab.linkedBrowser.currentURI.spec+')')));
 
 		var prevParent = this.getParentTab(prevTab);
 		var nextParent = this.getParentTab(nextTab);
 
 		var prevLevel  = prevTab ? Number(prevTab.getAttribute(this.kNEST)) : -1 ;
 		var nextLevel  = nextTab ? Number(nextTab.getAttribute(this.kNEST)) : -1 ;
+		log('  prevLevel: '+prevLevel);
+		log('  nextLevel: '+nextLevel);
 
 		var newParent;
 
 		if (!prevTab) {
-			mydump(' => moved to topmost position\n');
+			log(' => moved to topmost position');
 			newParent = null;
 		}
 		else if (!nextTab) {
-			mydump(' => movedmoved to last position\n');
+			log(' => movedmoved to last position');
 			newParent = (delta > 1) ? prevParent : parent ;
 		}
 		else if (prevParent == nextParent) {
-			mydump(' => moved into existing tree\n');
+			log(' => moved into existing tree');
 			newParent = prevParent;
 		}
 		else if (prevLevel > nextLevel) {
-			mydump(' => moved to end of existing tree\n');
+			log(' => moved to end of existing tree');
 			if (this.mTabBrowser.selectedTab != aTab) { 
-				mydump('    => maybe newly opened tab\n');
+				log('    => maybe newly opened tab');
 				newParent = prevParent;
 			}
 			else {
-				mydump('    => maybe drag and drop\n');
+				log('    => maybe drag and drop');
 				var realDelta = Math.abs(aTab._tPos - aOldPosition);
 				newParent = realDelta < 2 ? prevParent : (parent || nextParent) ;
 			}
 		}
 		else if (prevLevel < nextLevel) {
-			mydump(' => moved to first child position of existing tree\n');
+			log(' => moved to first child position of existing tree');
 			newParent = prevTab || parent || nextParent;
 		}
 
@@ -4043,7 +4151,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 	handleRestoredTab : function TSTBrowser_handleRestoredTab(aTab) 
 	{
 		if (aTab.__treestyletab__restoreState === undefined) {
-			mydump('handleRestoredTab: ' + aTab._tPos + ' is already restored!\n');
+			log('handleRestoredTab: ' + aTab._tPos + ' is already restored!');
 			return false;
 		}
 
@@ -4271,7 +4379,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		var restoringMultipleTabs = this.windowService.restoringTree;
 		var position = this._prepareInsertionPosition(aTab, aMayBeDuplicated);
 		var parent = position.parent;
-		mydump('handleRestoredTab: found parent = ' + parent+'\n');
+		log('handleRestoredTab: found parent = ' + parent);
 		if (parent) {
 			aTab.removeAttribute(this.kPARENT);
 			parent = this.getTabById(parent);
@@ -4317,7 +4425,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		}
 
 		var ancestors = (this.getTabValue(aTab, this.kANCESTORS) || this.getTabValue(aTab, this.kPARENT)).split('|');
-		mydump('handleRestoredTab: ancestors = ' + ancestors+'\n');
+		log('handleRestoredTab: ancestors = ' + ancestors);
 		var parent = null;
 		for (let i in ancestors)
 		{
@@ -4339,7 +4447,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		 */
 		if (!parent) {
 			parent = aTab.getAttribute(this.kPARENT);
-			mydump('handleRestoredTab: parent = ' + parent+'\n');
+			log('handleRestoredTab: parent = ' + parent);
 			if (parent && !next)
 				next = this.getNextSiblingTab(aTab);
 		}
@@ -5044,6 +5152,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			if (aEvent.type == 'overflow') {
 				tabs.setAttribute('overflow', 'true');
 				this.scrollBoxObject.ensureElementIsVisible(tabs.selectedItem);
+				utils.updateNarrowScrollbarStyle(this.browser);
 			}
 			else {
 				tabs.removeAttribute('overflow');
@@ -5095,9 +5204,9 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 		}
 
 		if (isContentResize || isChromeResize) {
-			mydump('TSTBrowser_onResize\n');
-			mydump('  isContentResize = '+isContentResize+'\n');
-			mydump('  isChromeResize = '+isChromeResize+'\n');
+			log('TSTBrowser_onResize');
+			log('  isContentResize = '+isContentResize);
+			log('  isChromeResize = '+isChromeResize);
 			this.updateFloatingTabbar(this.kTABBAR_UPDATE_BY_WINDOW_RESIZE);
 			this.updateInvertedTabContentsOrder(true);
 			this.mTabBrowser.mTabContainer.adjustTabstrip();
@@ -5259,10 +5368,10 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
   
 	onBeforeFullScreenToggle : function TSTBrowser_onBeforeFullScreenToggle(aEnterFS)
 	{
-		mydump('onBeforeFullScreenToggle / ' + this.position + '\n');
+		log('onBeforeFullScreenToggle / ' + this.position);
 		if (this.position != 'top') {
-			mydump('  this.document.mozFullScreen => ' + this.document.mozFullScreen + '\n');
-			mydump('  aEnterFS => ' + aEnterFS + '\n');
+			log('  this.document.mozFullScreen => ' + this.document.mozFullScreen);
+			log('  aEnterFS => ' + aEnterFS);
 			// ignore entering to the DOM-fullscreen (ex. YouTube Player)
 			if (!this.document.mozFullScreen) {
 				if (aEnterFS)
@@ -5667,6 +5776,29 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			!utils.getTreePref('closeParentBehavior.moveDetachedTabsToBottom')) {
 			insertBefore = this.getNextSiblingTab(this.getRootTab(aTab));
 		}
+
+		if (aInfo.behavior == this.kCLOSE_PARENT_BEHAVIOR_REPLACE_WITH_GROUP_TAB) {
+			let uri = utils.getGroupTabURI({
+				title:     aTab.label,
+				temporary: true
+			});
+			let groupTab = b.addTab(uri);
+			if (parentTab) {
+				this.attachTabTo(groupTab, parentTab, {
+					insertBefore : aTab,
+					dontAnimate  : true
+				});
+			}
+			else {
+				this.moveTabSubtreeTo(groupTab, aTab._tPos);
+			}
+			this.attachTabTo(aTab, groupTab, {
+				dontAnimate : true
+			});
+			parentTab = groupTab;
+			aInfo.behavior = this.kCLOSE_PARENT_BEHAVIOR_PROMOTE_ALL_CHILDREN;
+		}
+
 		for (let i = 0, maxi = children.length; i < maxi; i++)
 		{
 			let tab = children[i];
@@ -6220,7 +6352,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 				sourceService.getAllTabs(sourceBrowser).length == aTabs.length
 			);
 		var newTabs = [];
-		var treeStructure = sourceService.getTreeStructureFromTabs(aTabs);
+		var treeStructure = utils.getTreeStructureFromTabs(aTabs);
 
 		// Firefox fails to "move" collapsed tabs. So, expand them first
 		// and collapse them after they are moved.
@@ -6395,7 +6527,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 				var id = this.getTabValue(aTab, this.kID);
 				aTab.__treestyletab__checkTabsIndentOverflowOnMouseLeave = function checkTabsIndentOverflowOnMouseLeave(aEvent, aDelayed) {
 					if (aEvent.type == 'mouseover') {
-						if (self.evaluateXPath(
+						if (utils.evaluateXPath(
 								'ancestor-or-self::*[@' + self.kID + '="' + id + '"]',
 								aEvent.originalTarget || aEvent.target,
 								Ci.nsIDOMXPathResult.BOOLEAN_TYPE
@@ -6682,7 +6814,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 				}, this)
 				.join('|');
 
-		var xpathResult = this.evaluateXPath(
+		var xpathResult = utils.evaluateXPath(
 				'child::xul:tab[@'+this.kCHILDREN+' and not(@'+this.kCOLLAPSED+'="true") and not(@'+this.kSUBTREE_COLLAPSED+'="true") and @'+this.kID+' and not(contains("'+expandedAncestors+'", @'+this.kID+')) and not(@hidden="true")]',
 				b.mTabContainer
 			);
@@ -6925,7 +7057,8 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 	scrollToTabs : function TSTBrowser_scrollToTabs(aTabs) 
 	{
 		var firstTab = aTabs[0];
-		if (!firstTab.parentNode) // do nothing for closed tab!
+		if (!firstTab ||
+			!firstTab.parentNode) // do nothing for closed tab!
 			return;
 
 		var b            = this.mTabBrowser;
@@ -7013,6 +7146,23 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 				}).bind(this));
 		}).bind(this), 0);
 	},
+
+	highlightTab : function TSTBrowser_highlightTab(aTab)
+	{
+		aTab.setAttribute(this.kHIGHLIGHTED, 'ready');
+		wait(0)
+			.then((function() {
+				aTab.setAttribute(this.kHIGHLIGHTED, 'notifying');
+				return wait(500);
+			}).bind(this))
+			.then((function() {
+				aTab.setAttribute(this.kHIGHLIGHTED, 'finish');
+				return wait(1000);
+			}).bind(this))
+			.then((function() {
+				aTab.removeAttribute(this.kHIGHLIGHTED);
+			}).bind(this));
+	},
  
 	restoreTree : function TSTBrowser_restoreTree() 
 	{
@@ -7039,9 +7189,9 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			Components.utils.reportError(new Error('There is no property named "_browserEpochs"!!'));
 		}
 
-		mydump('TSTBrowser::restoreTree\n');
-		mydump('  level = '+level+'\n');
-		mydump('  tabsToRestore = '+tabsToRestore+'\n');
+		log('TSTBrowser::restoreTree');
+		log('  level = '+level);
+		log('  tabsToRestore = '+tabsToRestore);
 
 		if (
 			level <= this.kRESTORE_TREE_LEVEL_NONE ||
@@ -7064,7 +7214,7 @@ TreeStyleTabBrowser.prototype = inherit(TreeStyleTabWindow.prototype, {
 			);
 		});
 
-		mydump('  restoring member tabs = '+tabs.length+' ('+tabs.map(function(aTab) { return aTab._tPos; })+')\n');
+		log('  restoring member tabs = '+tabs.length+' ('+tabs.map(function(aTab) { return aTab._tPos; })+')');
 
 		if (tabs.length <= 1)
 			return;
diff --git a/modules/browserUIShowHideObserver.js b/modules/browserUIShowHideObserver.js
index ac5b391..9932f82 100644
--- a/modules/browserUIShowHideObserver.js
+++ b/modules/browserUIShowHideObserver.js
@@ -14,7 +14,7 @@
  * The Original Code is the Tree Style Tab.
  *
  * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2014-2015
+ * Portions created by the Initial Developer are Copyright (C) 2014-2016
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
@@ -42,6 +42,13 @@ Components.utils.import('resource://treestyletab-modules/constants.js');
 
 XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
 
+function log(...aArgs) {
+	utils.log.apply(utils, ['browserUIShowHideObserver'].concat(aArgs));
+}
+function logWithStackTrace(...aArgs) {
+	utils.logWithStackTrace.apply(utils, ['browserUIShowHideObserver'].concat(aArgs));
+}
+
 function BrowserUIShowHideObserver(aOwner, aBox, aOptions) {
 	this.owner = aOwner;
 	this.box = aBox;
@@ -91,7 +98,7 @@ BrowserUIShowHideObserver.prototype = {
 				{
 					case 'childList':
 						if (aMutation.target == this.box) {
-							this.dumpMutation(aMutation, 'BrowserUIShowHideObserver_onMutation/childList');
+							this.logMutation(aMutation, 'onMutation/childList');
 							this.owner.browser.treeStyleTab.updateFloatingTabbar(TreeStyleTabConstants.kTABBAR_UPDATE_BY_WINDOW_RESIZE);
 						}
 						return;
@@ -102,7 +109,7 @@ BrowserUIShowHideObserver.prototype = {
 				}
 			}
 			catch(error) {
-				this.dumpMutation(aMutation, 'BrowserUIShowHideObserver_onMutation(error)');
+				this.logMutation(aMutation, 'onMutation(error)');
 				Components.utils.reportError(error);
 			}
 		}, this);
@@ -118,7 +125,7 @@ BrowserUIShowHideObserver.prototype = {
 		delete this.owner;
 	},
 
-	dumpMutation : function BrowserUIShowHideObserver_dumpMutation(aMutation, aDescription)
+	logMutation : function BrowserUIShowHideObserver_logMutation(aMutation, aDescription)
 	{
 		if (!utils.isDebugging('browserUIShowHideObserver'))
 			return;
@@ -132,10 +139,10 @@ BrowserUIShowHideObserver.prototype = {
 					aMutation.attributeName + ', ' +
 					aMutation.oldValue + ' => ' +
 					target.getAttribute(aMutation.attributeName);
-		dump(aDescription + ' ' +
+		log(aDescription + ' ' +
 			ownerInformation + ' / ' +
 			targetInformation +
-			attributeInformation + '\n');
+			attributeInformation);
 	},
 
 	onAttributeModified : function BrowserUIShowHideObserver_onAttributeModified(aMutation, aObserver) 
@@ -146,22 +153,35 @@ BrowserUIShowHideObserver.prototype = {
 			return;
 
 		var target = aMutation.target;
-		var state = this.serializeBoxState(target);
-		if (target.__treestyletab_mutationObserver_lastState == state)
-			return;
-
 		if (
 			// ignore modifications of each tab
 			TST.getTabFromChild(target) ||
-			// ignore modifications in the location bar (ex. identity icon)
-			TST.evaluateXPath(
-				'ancestor-or-self::xul:textbox',
+			utils.evaluateXPath(
+				// ignore modifications in the location bar (ex. identity icon)
+				'ancestor-or-self::xul:textbox |' +
+				// or menu items
+				'ancestor-or-self::xul:menupopup |' +
+				// or scrollable indicator in the vertical tab bar
+				'ancestor-or-self::xul:spacer[' +
+					'contains(@class, "arrowscrollbox-overflow-start-indicator") or ' +
+					'contains(@class, "arrowscrollbox-overflow-end-indicator")' +
+				'][ancestor::xul:tabs[@' + TreeStyleTabConstants.kMODE + ' = "vertical"]]',
 				target,
 				Components.interfaces.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
-			).singleNodeValue
+			).singleNodeValue ||
+			// value is not changed
+			aMutation.oldValue == target.getAttribute(aMutation.attributeName)
 			)
 			return;
 
+		this.logMutation(aMutation, 'onAttributeModified');
+
+		var state = this.serializeBoxState(target);
+		if (target.__treestyletab_mutationObserver_lastState == state) {
+			log(' => skip modification with no state change');
+			return;
+		}
+
 		var tabbar = this.owner.browser.tabContainer;
 		var placeHolder = TST.tabStripPlaceHolder;
 
@@ -198,7 +218,7 @@ BrowserUIShowHideObserver.prototype = {
 		if (
 			// I must ignore show/hide of elements managed by TST,
 			// to avoid infinity loop.
-			TST.evaluateXPath(
+			utils.evaluateXPath(
 				'ancestor-or-self::xul:*[@' + TreeStyleTabConstants.kTAB_STRIP_ELEMENT + '="true"]',
 				target,
 				Components.interfaces.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
@@ -210,13 +230,14 @@ BrowserUIShowHideObserver.prototype = {
 			// (Pale Moon, Tab Mix Plus, etc.)
 			!tabbarVisibilityMismatching &&
 			!tabbarMatrixMismatching
-			)
+			) {
+			log(' => skip modifications around controlled element');
 			return;
-
-		this.dumpMutation(aMutation, 'BrowserUIShowHideObserver_onAttributeModified');
+		}
 
 		this.handlingAttrChange = true;
 
+		log(' => update floating tab bar');
 		TST.updateFloatingTabbar(TreeStyleTabConstants.kTABBAR_UPDATE_BY_WINDOW_RESIZE);
 
 		var w = this.box.ownerDocument.defaultView;
diff --git a/modules/constants.js b/modules/constants.js
index 9cc4c25..7405919 100644
--- a/modules/constants.js
+++ b/modules/constants.js
@@ -82,6 +82,7 @@ var TreeStyleTabConstants = Object.freeze({
 	kINVERT_SCROLLBAR   : 'treestyletab-invert-scrollbar',
 	kNARROW_SCROLLBAR   : 'treestyletab-narrow-scrollbar',
 	kFAVICONIZED        : 'treestyletab-faviconized',
+	kHIGHLIGHTED        : 'treestyletab-highlighted',
 	kBG_NOTIFY_PHASE    : 'treestyletab-notifybgtab-phase',
 	kIGNORE_POPUP_STATE : 'treestyletab-ignore-state',
 
@@ -198,6 +199,7 @@ var TreeStyleTabConstants = Object.freeze({
 	kCLOSE_PARENT_BEHAVIOR_DETACH_ALL_CHILDREN        : 1,
 	kCLOSE_PARENT_BEHAVIOR_SIMPLY_DETACH_ALL_CHILDREN : 4,
 	kCLOSE_PARENT_BEHAVIOR_CLOSE_ALL_CHILDREN         : 2, // onTabRemoved only
+	kCLOSE_PARENT_BEHAVIOR_REPLACE_WITH_GROUP_TAB     : 5,
 
 	kRESTORE_TREE_LEVEL_NONE   : 0,
 	kRESTORE_TREE_ONLY_VISIBLE : 1,
@@ -220,6 +222,22 @@ var TreeStyleTabConstants = Object.freeze({
 	RESTORE_STATE_STRUCTURE_RESTORED  : 2,
 
 
+	kDROPLINK_ASK    : 0,
+	kDROPLINK_FIXED  : 1 + 2,
+	kDROPLINK_LOAD   : 1,
+	kDROPLINK_NEWTAB : 2,
+
+
+	kGROUP_BOOKMARK_ASK       : 0,
+	kGROUP_BOOKMARK_FIXED     : 1 + 2 + 4,
+	kGROUP_BOOKMARK_SUBTREE   : 1,
+	kGROUP_BOOKMARK_SEPARATE  : 2,
+	kGROUP_BOOKMARK_USE_DUMMY                   : 256,
+	kGROUP_BOOKMARK_USE_DUMMY_FORCE             : 1024,
+	kGROUP_BOOKMARK_DONT_RESTORE_TREE_STRUCTURE : 512,
+	kGROUP_BOOKMARK_EXPAND_ALL_TREE             : 2048,
+
+
 	CONTENT_SCRIPT          : 'chrome://treestyletab/content/content-utils.js',
 	CONTENT_SCRIPT_AUTOHIDE : 'chrome://treestyletab/content/content-utils-autohide.js',
 	MESSAGE_TYPE            : 'treestyletab',
diff --git a/modules/contentBridge.js b/modules/contentBridge.js
index d7f34a4..d40246b 100644
--- a/modules/contentBridge.js
+++ b/modules/contentBridge.js
@@ -46,6 +46,13 @@ Cu.import('resource://gre/modules/Promise.jsm');
 
 XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
 
+function log(...aArgs) {
+	utils.log.apply(utils, ['contentBridge'].concat(aArgs));
+}
+function logWithStackTrace(...aArgs) {
+	utils.logWithStackTrace.apply(utils, ['contentBridge'].concat(aArgs));
+}
+
 function ContentBridge(aTab, aTabBrowser) 
 {
 	this.init(aTab, aTabBrowser);
@@ -107,11 +114,9 @@ ContentBridge.prototype = inherit(TreeStyleTabConstants, {
 	},
 	handleMessage : function CB_handleMessage(aMessage)
 	{
-		if (utils.isDebugging('contentBridge')) {
-			dump('*********************handleMessage*******************\n');
-			dump('TARGET IS: '+aMessage.target.localName+'\n');
-			dump(JSON.stringify(aMessage.json)+'\n');
-		}
+		log('*********************handleMessage*******************');
+		log('TARGET IS: '+aMessage.target.localName);
+		log(JSON.stringify(aMessage.json));
 
 		if (aMessage.target != this.mTab.linkedBrowser)
 		  return;
diff --git a/modules/fullTooltip.js b/modules/fullTooltip.js
index 9457d87..7529688 100644
--- a/modules/fullTooltip.js
+++ b/modules/fullTooltip.js
@@ -14,7 +14,7 @@
  * The Original Code is the Tree Style Tab.
  *
  * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2011-2014
+ * Portions created by the Initial Developer are Copyright (C) 2011-2016
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
@@ -148,7 +148,7 @@ FullTooltipManager.prototype = inherit(TreeStyleTabBase, {
 
 	getFullTooltipFromEvent : function FTM_getFullTooltipFromEvent(aEvent)
 	{
-		return this.evaluateXPath(
+		return utils.evaluateXPath(
 				'ancestor-or-self::xul:tooltip[@id="'+this.tabFullTooltip.id+'"]',
 				aEvent.target,
 				Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
@@ -188,10 +188,46 @@ FullTooltipManager.prototype = inherit(TreeStyleTabBase, {
 		this.cancel();
 	},
 
+	getCurrentScreen : function FTM_getCurrentScreen(aBox)
+	{
+		var currentScreen = Cc['@mozilla.org/gfx/screenmanager;1']
+							.getService(Ci.nsIScreenManager)
+							.screenForRect(aBox.screenX, aBox.screenY, aBox.width, aBox.height);
+		var screenLeft   = {},
+			screenTop    = {},
+			screenWidth  = {},
+			screenHeight = {};
+		currentScreen.GetRect(screenLeft, screenTop, screenWidth, screenHeight);
+		return {
+			left   : screenLeft.value,
+			top    : screenTop.value,
+			width  : screenWidth.value,
+			height : screenHeight.value,
+			allowedWidth  : Math.ceil(screenWidth.value * 0.8),
+			allowedHeight : Math.ceil(screenHeight.value * 0.7)
+		};
+	},
+
 	onShown : function FTM_onShown(aEvent) 
 	{
 		this.startListenTooltipEvents();
 
+		if (utils.getTreePref('tooltip.columnize')) {
+			let tooltip = this.tabFullTooltip;
+			let currentScreen = this.getCurrentScreen(tooltip.boxObject);
+			let tree = tooltip.lastChild.lastChild.lastChild;
+			PseudoTreeBuilder.columnizeTree(tree, {
+				width  : currentScreen.allowedWidth,
+				height : currentScreen.allowedHeight
+			});
+			this.window.setTimeout(this.resizeTooltip.bind(this), 0);
+		}
+		else {
+			this.resizeTooltip();
+		}
+	},
+	resizeTooltip : function FTM_resizeTooltip() 
+	{
 		var tooltip = this.tabFullTooltip;
 		tooltip.setAttribute('popup-shown', true);
 
@@ -205,24 +241,17 @@ FullTooltipManager.prototype = inherit(TreeStyleTabBase, {
 		var currentX = box.screenX;
 		var currentY = box.screenY;
 
-		var currentScreen = Cc['@mozilla.org/gfx/screenmanager;1']
-							.getService(Ci.nsIScreenManager)
-							.screenForRect(box.screenX, box.screenY, box.width, box.height);
-		var screenLeft   = {},
-			screenTop    = {},
-			screenWidth  = {},
-			screenHeight = {};
-		currentScreen.GetRect(screenLeft, screenTop, screenWidth, screenHeight);
+		var currentScreen = this.getCurrentScreen(box);
 
 		var style = tooltip.style;
-		style.maxWidth = screenWidth.value+'px';
-		style.maxHeight = screenHeight.value+'px';
+		style.maxWidth = currentScreen.allowedWidth+'px';
+		style.maxHeight = currentScreen.allowedHeight+'px';
 		style.minWidth = 0;
 		style.minHeight = 0;
-		if (currentX + currentW + screenLeft.value >= screenWidth.value)
-			style.marginLeft = (Math.max(screenLeft.value, screenWidth.value - currentW) - this.window.screenX)+'px';
-		if (currentY + currentH + screenTop.value >= screenHeight.value)
-			style.marginTop = (Math.max(screenTop.value, screenHeight.value - currentH) - this.window.screenY)+'px';
+		if (currentX + currentW + currentScreen.left >= currentScreen.allowedWidth)
+			style.marginLeft = (Math.max(currentScreen.left, currentScreen.allowedWidth - currentW) - this.window.screenX)+'px';
+		if (currentY + currentH + currentScreen.top >= currentScreen.allowedHeight)
+			style.marginTop = (Math.max(currentScreen.top, currentScreen.allowedHeight - currentH) - this.window.screenY)+'px';
 	},
 
 	onHidden : function FTM_onHidden(aEvent) 
@@ -449,9 +478,12 @@ FullTooltipManager.prototype = inherit(TreeStyleTabBase, {
 
 		var tree = PseudoTreeBuilder.build(aTab);
 		var root = this.document.createElement('arrowscrollbox');
-		root.setAttribute('orient', 'vertical');
+		var orient = utils.getTreePref('tooltip.columnize') ? 'horizontal' : 'vertical' ;
+		root.setAttribute('orient', orient);
 		root.setAttribute('flex', 1);
 
+		var container = root.appendChild(this.document.createElement('vbox'));
+
 		if (aExtraLabels) {
 			if (typeof aExtraLabels == 'string')
 				aExtraLabels = [aExtraLabels];
@@ -461,12 +493,13 @@ FullTooltipManager.prototype = inherit(TreeStyleTabBase, {
 				label = label.trim();
 				if (!label)
 					continue;
-				root.appendChild(this.document.createElement('description'))
+				container.appendChild(this.document.createElement('description'))
 					.appendChild(this.document.createTextNode(label));
 			}
 		}
 
-		root.insertBefore(tree, root.firstChild && root.firstChild.nextSibling);
+		container.insertBefore(tree, container.firstChild && container.firstChild.nextSibling);
+		root.appendChild(container);
 
 		this.tabFullTooltip.appendChild(root);
 	},
diff --git a/modules/fullscreenObserver.js b/modules/fullscreenObserver.js
index 6dcd7de..54210dc 100644
--- a/modules/fullscreenObserver.js
+++ b/modules/fullscreenObserver.js
@@ -14,7 +14,7 @@
  * The Original Code is the Tree Style Tab.
  *
  * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2013-2015
+ * Portions created by the Initial Developer are Copyright (C) 2013-2016
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
@@ -39,6 +39,13 @@ Components.utils.import('resource://treestyletab-modules/constants.js');
 
 Components.utils.import('resource://treestyletab-modules/utils.js');
 
+function log(...aArgs) {
+	TreeStyleTabUtils.log.apply(TreeStyleTabUtils, ['fullscreenObserver'].concat(aArgs));
+}
+function logWithStackTrace(...aArgs) {
+	TreeStyleTabUtils.logWithStackTrace.apply(TreeStyleTabUtils, ['fullscreenObserver'].concat(aArgs));
+}
+
 function FullscreenObserver(aWindow) {
 	this.window = aWindow;
 	this.init();
@@ -90,6 +97,7 @@ FullscreenObserver.prototype = {
 
 	onSizeModeChange : function FullscreenObserver_onSizeModeChange()
 	{
+		log('onSizeModeChange: ', this.window.document.documentElement.getAttribute('sizemode'));
 		this.updateToolboxPosition();
 		if (!this.window.gBrowser.treeStyleTab.notifyingRenderedEvent)
 			this.window.gBrowser.treeStyleTab.updateFloatingTabbar(TreeStyleTabConstants.kTABBAR_UPDATE_BY_WINDOW_RESIZE);
diff --git a/modules/groupTab.js b/modules/groupTab.js
index 080f1b4..fba531f 100644
--- a/modules/groupTab.js
+++ b/modules/groupTab.js
@@ -14,7 +14,7 @@
  * The Original Code is the Tree Style Tab.
  *
  * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2010-2014
+ * Portions created by the Initial Developer are Copyright (C) 2010-2016
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
@@ -39,11 +39,15 @@ var EXPORTED_SYMBOLS = ['GroupTab'];
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
+Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
+
 Components.utils.import('resource://treestyletab-modules/lib/inherit.jsm');
 Components.utils.import('resource://treestyletab-modules/base.js');
 Components.utils.import('resource://treestyletab-modules/pseudoTreeBuilder.js');
 Components.utils.import('resource://treestyletab-modules/tabAttributesObserver.js');
 
+XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
+
 function GroupTab(aWindow)
 {
 	this.window = aWindow;
@@ -234,6 +238,8 @@ GroupTab.prototype = inherit(TreeStyleTabBase, {
 		var contents = PseudoTreeBuilder.build(this.getOwnerTab());
 		if (contents)
 			tree.appendChild(contents);
+
+		this.onResize();
 	},
 
 	checkUpdateTreeNow : function GT_checkUpdateTreeNow()
@@ -272,6 +278,9 @@ GroupTab.prototype = inherit(TreeStyleTabBase, {
 			case 'TabSelect':
 				return this.onTabSelect(aEvent);
 
+			case 'resize':
+				return this.onResize();
+
 			case this.kEVENT_TYPE_ATTACHED:
 				return this.onTabAttached(aEvent);
 			case this.kEVENT_TYPE_DETACHED:
@@ -293,15 +302,20 @@ GroupTab.prototype = inherit(TreeStyleTabBase, {
 		this.window.addEventListener('unload', this, false);
 		this.window.addEventListener('click', this, false);
 		this.window.addEventListener('dblclick', this, false);
+		this.window.addEventListener('resize', this, false);
 
 		tab.addEventListener('TabSelect', this, false);
 		tab.addEventListener('TabClose', this, false);
 		tab.parentNode.addEventListener(this.kEVENT_TYPE_ATTACHED, this, false);
 		tab.parentNode.addEventListener(this.kEVENT_TYPE_DETACHED, this, false);
 
-		this.tabsObserver = new TabAttributesObserver(this.browser.tabContainer, (function(aTab) {
-			this.onTabModified(aTab);
-		}).bind(this));
+		this.tabsObserver = new TabAttributesObserver({
+			container  : this.browser.tabContainer,
+			attributes : 'label,visibleLabel,image',
+			callback   : (function(aTab) {
+				this.onTabModified(aTab);
+			}).bind(this)
+		});
 
 		this.editor.addEventListener('keypress', this, false);
 
@@ -320,6 +334,7 @@ GroupTab.prototype = inherit(TreeStyleTabBase, {
 		this.window.removeEventListener('unload', this, false);
 		this.window.removeEventListener('click', this, false);
 		this.window.removeEventListener('dblclick', this, false);
+		this.window.removeEventListener('resize', this, false);
 
 		tab.removeEventListener('TabSelect', this, false);
 		tab.removeEventListener('TabClose', this, false);
@@ -390,6 +405,15 @@ GroupTab.prototype = inherit(TreeStyleTabBase, {
 		this.shouldUpdate = false;
 	},
 
+	onResize : function GT_onResize()
+	{
+		if (!utils.getTreePref('groupTab.columnize'))
+			return;
+		var container = this.document.getElementById('tree');
+		var tree = container.firstChild;
+		PseudoTreeBuilder.columnizeTree(tree);
+	},
+
 	onTabAttached : function GT_onTabAttached(aEvent)
 	{
 		var tab = aEvent.detail.parentTab;
diff --git a/modules/pseudoTreeBuilder.js b/modules/pseudoTreeBuilder.js
index 5907d54..018becf 100644
--- a/modules/pseudoTreeBuilder.js
+++ b/modules/pseudoTreeBuilder.js
@@ -14,7 +14,7 @@
  * The Original Code is the Tree Style Tab.
  *
  * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2011-2015
+ * Portions created by the Initial Developer are Copyright (C) 2011-2016
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
@@ -44,8 +44,10 @@ Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'TreeStyleTabBase', 'resource://treestyletab-modules/base.js');
 
 var PseudoTreeBuilder = {
+	XHTMLNS : 'http://www.w3.org/1999/xhtml',
 
 	kFAVICON      : 'treestyletab-pseudo-tree-favicon',
+	kROOT         : 'treestyletab-pseudo-tree-root',
 	kROOTITEM     : 'treestyletab-pseudo-tree-root-item',
 	kTREEITEM     : 'treestyletab-pseudo-tree-item',
 	kTREEROW      : 'treestyletab-pseudo-tree-row',
@@ -59,8 +61,9 @@ var PseudoTreeBuilder = {
 			return null;
 
 		var tree = this.createTabItem(aTab);
+		tree.className = this.kROOT;
 
-		var row = tree.querySelector("."+this.kTREEROW);
+		var row = tree.querySelector("*|*."+this.kTREEROW);
 		if (!row)
 			return;
 
@@ -95,31 +98,36 @@ var PseudoTreeBuilder = {
 		var doc = aTab.ownerDocument;
 		var w = doc.defaultView;
 
-		var item = doc.createElement('hbox');
-		item.setAttribute('class', this.kTREEROW);
+		var item = doc.createElementNS(this.XHTMLNS, 'div');
+		item.setAttribute('class', this.kTREEITEM);
 
-		var favicon = item.appendChild(doc.createElement('image'));
+		var favicon = item.appendChild(doc.createElementNS(this.XHTMLNS, 'img'));
 		favicon.setAttribute('src', aTab.getAttribute('image') || 'chrome://mozapps/skin/places/defaultFavicon.png');
 		favicon.setAttribute('class', this.kFAVICON);
 
 		var label = item.appendChild(doc.createElement('label'));
-		label.setAttribute('value', aTab.label);
+		label.setAttribute('flex', 1);
+		label.textContent = aTab.label;
 		var tooltip = aTab.label;
 		var uri = aTab.linkedBrowser.currentURI.spec;
 		if (w.isBlankPageURL ? !w.isBlankPageURL(uri) : (uri != 'about:blank')) tooltip += '\n' + uri;
 		label.setAttribute('tooltiptext', tooltip);
-		label.setAttribute('class', 'text-link '+this.kTREEITEM);
+		label.setAttribute('class', 'text-link');
 		label.setAttribute('tab-id', TreeStyleTabBase.getTabValue(aTab, TreeStyleTabBase.kID));
 
+		var row = doc.createElementNS(this.XHTMLNS, 'div');
+		row.setAttribute('class', this.kTREEROW);
+		row.appendChild(item);
+
 		var children = this.createTabChildren(aTab);
 		if (children) {
-			let container = doc.createElement('vbox');
-			container.appendChild(item);
+			let container = doc.createElementNS(this.XHTMLNS, 'div');
+			container.appendChild(row);
 			container.appendChild(children);
 			return container;
 		}
 		else {
-			return item;
+			return row;
 		}
 	},
 
@@ -131,12 +139,46 @@ var PseudoTreeBuilder = {
 		if (!children.length)
 			return null;
 
-		var container = doc.createElement('vbox');
+		var container = doc.createElementNS(this.XHTMLNS, 'div');
+		container.setAttribute('class', this.kTREECHILDREN);
 		for (let i = 0, maxi = children.length; i < maxi; i++)
 		{
 			container.appendChild(this.createTabItem(children[i]));
 		}
-		container.setAttribute('class', this.kTREECHILDREN);
 		return container;
+	},
+
+	columnizeTree : function TB_columnizeTree(aTree, aContainerBox)
+	{
+		aContainerBox = aContainerBox || aTree.parentNode.boxObject;
+
+		var style = aTree.style;
+		var height = aTree.clientHeight * (aTree.columnCount || 1);
+		if (height > aContainerBox.height &&
+			aContainerBox.height < aContainerBox.width) {
+			let maxWidth = aContainerBox.width;
+			aTree.columnWidth = Math.floor(maxWidth * 0.9 / 2.5);
+			let count = Math.ceil(
+				(aTree.clientWidth * aTree.clientHeight) /
+				(aTree.columnWidth * aTree.clientHeight)
+			);
+			aTree.columnCount = style.columnCount = style.MozColumnCount = count;
+			style.columnWidth = style.MozColumnWidth = aTree.columnWidth+'px';
+			style.columnGap = style.MozColumnGap = '0';
+		}
+		else {
+			aTree.columnCount = 1;
+			style.columnCount = style.MozColumnCount =
+				style.columnWidth = style.MozColumnWidth =
+				style.columnGap = style.MozColumnGap = '';
+		}
+
+		if (aTree.columnCount > 1) {
+			style.height = style.maxHeight =
+				Math.floor(aContainerBox.height * 0.9) + 'px';
+		}
+		else {
+			style.height = style.maxHeight = '';
+		}
 	}
 };
diff --git a/modules/tabAttributesObserver.js b/modules/tabAttributesObserver.js
index 8a62231..f03a79e 100644
--- a/modules/tabAttributesObserver.js
+++ b/modules/tabAttributesObserver.js
@@ -14,7 +14,7 @@
  * The Original Code is the Tree Style Tab.
  *
  * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2014
+ * Portions created by the Initial Developer are Copyright (C) 2014-2016
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
@@ -37,9 +37,12 @@ var EXPORTED_SYMBOLS = ['TabAttributesObserver'];
 
 Components.utils.import('resource://treestyletab-modules/constants.js');
 
-function TabAttributesObserver(aContainer, aCallback) {
-	this.container = aContainer;
-	this.callback = aCallback;
+function TabAttributesObserver(aParams) {
+	this.container = aParams.container;
+	this.attributes = aParams.attributes;
+	if (typeof this.attributes == 'string')
+		this.attributes = this.attributes.split(',');
+	this.callback = aParams.callback;
 	this.init();
 }
 TabAttributesObserver.prototype = {
diff --git a/modules/tabAttributesObserver.js b/modules/tabContentsObserver.js
similarity index 54%
copy from modules/tabAttributesObserver.js
copy to modules/tabContentsObserver.js
index 8a62231..8592f91 100644
--- a/modules/tabAttributesObserver.js
+++ b/modules/tabContentsObserver.js
@@ -14,7 +14,7 @@
  * The Original Code is the Tree Style Tab.
  *
  * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2014
+ * Portions created by the Initial Developer are Copyright (C) 2016
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
@@ -33,74 +33,102 @@
  *
  * ***** END LICENSE BLOCK ******/
 
-var EXPORTED_SYMBOLS = ['TabAttributesObserver']; 
+var EXPORTED_SYMBOLS = ['TabContentsObserver']; 
+
+Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
 
 Components.utils.import('resource://treestyletab-modules/constants.js');
 
-function TabAttributesObserver(aContainer, aCallback) {
-	this.container = aContainer;
-	this.callback = aCallback;
-	this.init();
+XPCOMUtils.defineLazyModuleGetter(this, 'utils', 'resource://treestyletab-modules/utils.js', 'TreeStyleTabUtils');
+
+function log(...aArgs) {
+	utils.log.apply(utils, ['tabContentsObserver'].concat(aArgs));
+}
+function logWithStackTrace(...aArgs) {
+	utils.logWithStackTrace.apply(utils, ['tabContentsObserver'].concat(aArgs));
+}
+
+function TabContentsObserver(aOwner, aBox, aOptions) {
+	this.owner = aOwner;
+	this.box = aBox;
+	this.init(aOptions);
 }
-TabAttributesObserver.prototype = {
+TabContentsObserver.prototype = {
 	get MutationObserver()
 	{
-		var w = this.container.ownerDocument.defaultView;
+		var w = this.box.ownerDocument.defaultView;
 		return w.MutationObserver || w.MozMutationObserver;
 	},
 
-	init : function TabAttributesObserver_onInit() 
+	init : function TabContentsObserver_onInit(aOptions) 
 	{
 		if (!this.MutationObserver)
 			return;
 		this.observer = new this.MutationObserver((function(aMutations, aObserver) {
 			this.onMutation(aMutations, aObserver);
 		}).bind(this));
-		this.observer.observe(this.container, {
-			childList       : false,
-			attributes      : true,
-			subtree         : true,
-			attributeFilter : [
-				'label',
-				'visibleLabel',
-				'image'
-			]
-		});
+		var options = {
+			childList  : true,
+			attributes : false,
+			subtree    : true
+		};
+		if (aOptions) {
+			Object.keys(options).forEach(function(aKey) {
+				if (aKey in aOptions)
+					options[aKey] = aOptions[aKey];
+			});
+		}
+		this.observer.observe(this.box, options);
 	},
-	onMutation : function TabAttributesObserver_onMutation(aMutations, aObserver) 
+	onMutation : function TabContentsObserver_onMutation(aMutations, aObserver) 
 	{
 		aMutations.forEach(function(aMutation) {
-			switch (aMutation.type)
-			{
-				case 'attributes':
-					this.onAttributeModified(aMutation, aObserver);
-					return;
+			try {
+				switch (aMutation.type)
+				{
+					case 'childList':
+						this.onTabContentsModified(aMutation, aObserver);
+						return;
+				}
+			}
+			catch(error) {
+				this.logMutation(aMutation, 'onMutation(error)');
+				Components.utils.reportError(error);
 			}
 		}, this);
 	},
 
-	destroy : function TabAttributesObserver_destroy()
+	destroy : function TabContentsObserver_destroy()
 	{
 		if (this.observer) {
 			this.observer.disconnect();
 			delete this.observer;
 		}
-		delete this.container;
+		delete this.box;
+		delete this.owner;
 	},
 
-	onAttributeModified : function TabAttributesObserver_onAttributeModified(aMutation, aObserver) 
+	onTabContentsModified : function TabContentsObserver_onTabContentsModified(aMutation, aObserver) 
 	{
-		if (this.handlingAttrChange ||
-			aMutation.target.localName != 'tab')
+		var TST = this.owner.browser.treeStyleTab;
+		if (this.handlingChange ||
+			TST.notifyingRenderedEvent)
 			return;
 
-		this.handlingAttrChange = true;
+		var target = aMutation.target;
+		var tab = TST.getTabFromChild(target);
+		if (!tab)
+			return;
+
+		log('onTabContentsModified on the tab '+tab._tPos);
+
+		this.handlingChange = true;
 
-		this.callback(aMutation.target);
+		TST.initTabContentsOrder(tab, true);
 
-		var w = this.container.ownerDocument.defaultView;
+		var w = this.box.ownerDocument.defaultView;
 		w.setTimeout((function() {
-			this.handlingAttrChange = false;
+			this.handlingChange = false;
 		}).bind(this), 10);
 	}
 };
diff --git a/modules/tabbarDNDObserver.js b/modules/tabbarDNDObserver.js
index e45033e..da0b61d 100644
--- a/modules/tabbarDNDObserver.js
+++ b/modules/tabbarDNDObserver.js
@@ -14,7 +14,7 @@
  * The Original Code is the Tree Style Tab.
  *
  * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2010-2015
+ * Portions created by the Initial Developer are Copyright (C) 2010-2016
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
@@ -63,6 +63,13 @@ const SSS = Cc['@mozilla.org/content/style-sheet-service;1']
 const SecMan = Cc['@mozilla.org/scriptsecuritymanager;1']
 				.getService(Ci.nsIScriptSecurityManager);
 
+function log(...aArgs) {
+	utils.log.apply(utils, ['tabbarDNDObserver'].concat(aArgs));
+}
+function logWithStackTrace(...aArgs) {
+	utils.logWithStackTrace.apply(utils, ['tabbarDNDObserver'].concat(aArgs));
+}
+
 function TabbarDNDObserver(aTabBrowser) 
 {
 	this.init(aTabBrowser);
@@ -72,14 +79,14 @@ TabbarDNDObserver.prototype = {
 	
 	readyToStartTabbarDrag : function TabbarDND_readyToStartTabbarDrag() 
 	{
-		var sheet = this.treeStyleTab.makeURIFromSpec('chrome://treestyletab/content/hide-embed.css');
+		var sheet = utils.makeURIFromSpec('chrome://treestyletab/content/hide-embed.css');
 		if (!SSS.sheetRegistered(sheet, SSS.AGENT_SHEET))
 			SSS.loadAndRegisterSheet(sheet, SSS.AGENT_SHEET);
 	},
  
 	readyToEndTabbarDrag : function TabbarDND_readyToEndTabbarDrag() 
 	{
-		var sheet = this.treeStyleTab.makeURIFromSpec('chrome://treestyletab/content/hide-embed.css');
+		var sheet = utils.makeURIFromSpec('chrome://treestyletab/content/hide-embed.css');
 		if (SSS.sheetRegistered(sheet, SSS.AGENT_SHEET))
 			SSS.unregisterSheet(sheet, SSS.AGENT_SHEET);
 	},
@@ -89,7 +96,7 @@ TabbarDNDObserver.prototype = {
 		var sv = this.treeStyleTab;
 
 		if (
-			sv.evaluateXPath(
+			utils.evaluateXPath(
 				'ancestor-or-self::*[' +
 					'contains(" scrollbar popup menupopup panel tooltip ", concat(" ", local-name(), " ")) or' +
 					'(local-name()="toolbarbutton" and @type="menu")' +
@@ -187,8 +194,7 @@ try{
 		return info.canDrop;
 }
 catch(e) {
-		if (utils.isDebugging('tabbarDNDObserver'))
-			dump('TabbarDND::canDrop\n'+e+'\n');
+		log('canDrop', e);
 		return false;
 }
 	},
@@ -262,8 +268,7 @@ catch(e) {
 	
 	getDropActionInternal : function TabbarDND_getDropActionInternal(aEvent, aSourceTab) 
 	{
-		if (utils.isDebugging('tabbarDNDObserver'))
-			dump('getDropActionInternal: start\n');
+		log('getDropActionInternal: start');
 		var sv = this.treeStyleTab;
 		var b  = this.browser;
 		var d  = this.document;
@@ -304,21 +309,18 @@ catch(e) {
 		var isNewTabAction = !aSourceTab || aSourceTab.ownerDocument != d;
 
 		if (!tab || tab.localName != 'tab') {
-			if (utils.isDebugging('tabbarDNDObserver'))
-				dump('  not on a tab\n');
+			log('  not on a tab');
 			let action = isTabMoveFromOtherWindow ? sv.kACTION_STAY : (sv.kACTION_MOVE | sv.kACTION_PART) ;
 			if (isNewTabAction) action |= sv.kACTION_NEWTAB;
 			if (aEvent[sv.screenPositionProp] < sv.getTabActualScreenPosition(firstTab)) {
-				if (utils.isDebugging('tabbarDNDObserver'))
-					dump('  above the first tab\n');
+				log('  above the first tab');
 				info.target   = info.parent = info.insertBefore = firstTab;
 				info.position = isInverted ? sv.kDROP_AFTER : sv.kDROP_BEFORE ;
 				info.action   = action;
 				return info;
 			}
 			else if (aEvent[sv.screenPositionProp] > sv.getTabActualScreenPosition(tabs[lastTabIndex]) + tabs[lastTabIndex].boxObject[sv.sizeProp]) {
-				if (utils.isDebugging('tabbarDNDObserver'))
-					dump('  below the last tab\n');
+				log('  below the last tab');
 				info.target   = info.parent = tabs[lastTabIndex];
 				info.position = isInverted ? sv.kDROP_BEFORE : sv.kDROP_AFTER ;
 				info.action   = action;
@@ -328,30 +330,25 @@ catch(e) {
 				let index = b.getNewIndex ?
 								b.getNewIndex(aEvent) :
 								b.tabContainer._getDropIndex(aEvent) ;
-				if (utils.isDebugging('tabbarDNDObserver'))
-					dump('  on the tab '+index+'\n');
+				log('  on the tab '+index);
 				index = Math.min(index, lastTabIndex);
 				info.target = tab = tabs[index];
 				if (index == tabs[lastTabIndex]._tPos) {
 					if (index > 0)
 						info.target = tab = tabs[index - 1];
 					info.position = sv.kDROP_AFTER;
-					if (utils.isDebugging('tabbarDNDObserver'))
-						dump('  => after the last tab\n');
+					log('  => after the last tab');
 				} else if (index == firstTab._tPos) {
 					if (index < lastTabIndex - 1)
 						info.target = tab = tabs[index + 1];
 					info.position = sv.kDROP_BEFORE;
-					if (utils.isDebugging('tabbarDNDObserver'))
-						dump('  => before the first tab\n');
+					log('  => before the first tab');
 				}
-				if (utils.isDebugging('tabbarDNDObserver'))
-					dump('  info.target = ' + info.target._tPos + '\n');
+				log('  info.target = ' + info.target._tPos);
 			}
 		}
 		else {
-			if (utils.isDebugging('tabbarDNDObserver'))
-				dump('  on the tab '+tab._tPos+'\n');
+			log('  on the tab '+tab._tPos);
 			sv.ensureTabInitialized(tab);
 			info.target = tab;
 		}
@@ -387,21 +384,19 @@ catch(e) {
 		switch (info.position)
 		{
 			case sv.kDROP_ON:
-				if (utils.isDebugging('tabbarDNDObserver'))
-					dump('  position = on the tab\n');
+				log('  position = on the tab');
 				var visible = sv.getNextVisibleTab(tab);
 				info.action       = sv.kACTION_STAY | sv.kACTION_ATTACH;
 				info.parent       = tab;
 				info.insertBefore = utils.getTreePref('insertNewChildAt') == sv.kINSERT_FISRT ?
 						(sv.getFirstChildTab(tab) || visible) :
 						(sv.getNextSiblingTab(tab) || sv.getNextTab(sv.getLastDescendantTab(tab) || tab));
-				if (utils.isDebugging('tabbarDNDObserver') && info.insertBefore)
-					dump('  insertBefore = '+info.insertBefore._tPos+'\n');
+				if (info.insertBefore)
+					log('  insertBefore = '+info.insertBefore._tPos);
 				break;
 
 			case sv.kDROP_BEFORE:
-				if (utils.isDebugging('tabbarDNDObserver'))
-					dump('  position = before the tab\n');
+				log('  position = before the tab');
 /*
 	     <= detach from parent, and move
 	[TARGET  ]
@@ -437,13 +432,12 @@ catch(e) {
 					info.action       = sv.kACTION_MOVE | (info.parent ? sv.kACTION_ATTACH : sv.kACTION_PART );
 					info.insertBefore = tab;
 				}
-				if (utils.isDebugging('tabbarDNDObserver') && info.insertBefore)
-					dump('  insertBefore = '+info.insertBefore._tPos+'\n');
+				if (info.insertBefore)
+					log('  insertBefore = '+info.insertBefore._tPos);
 				break;
 
 			case sv.kDROP_AFTER:
-				if (utils.isDebugging('tabbarDNDObserver'))
-					dump('  position = after the tab\n');
+				log('  position = after the tab');
 /*
 	[TARGET  ]
 	     <= if the target has a parent, attach to it and and move
@@ -487,8 +481,8 @@ catch(e) {
 						}
 					}
 				}
-				if (utils.isDebugging('tabbarDNDObserver') && info.insertBefore)
-					dump('  insertBefore = '+info.insertBefore._tPos+'\n');
+				if (info.insertBefore)
+					log('  insertBefore = '+info.insertBefore._tPos);
 				break;
 		}
 
@@ -499,16 +493,14 @@ catch(e) {
   
 	performDrop : function TabbarDND_performDrop(aInfo, aDraggedTab) 
 	{
-		if (utils.isDebugging('tabbarDNDObserver'))
-			dump('performDrop: start\n');
+		log('performDrop: start');
 		var sv = this.treeStyleTab;
 		var b  = this.browser;
 		var w  = this.window;
 
 		var tabsInfo = this.getDraggedTabsInfoFromOneTab(aDraggedTab, aInfo);
 		if (!tabsInfo.draggedTab) {
-			if (utils.isDebugging('tabbarDNDObserver'))
-				dump(' => no dragged tab\n');
+			log(' => no dragged tab');
 			return false;
 		}
 
@@ -565,14 +557,13 @@ catch(e) {
 				sourceBrowser == targetBrowser &&
 				sourceService.getNextVisibleTab(draggedTabs[draggedTabs.length-1]) == aInfo.insertBefore
 				) {
-				if (utils.isDebugging('tabbarDNDObserver'))
-					dump(' => no change\n');
+				log(' => no change');
 				// then, do nothing
 				return true;
 			}
 		}
 
-		var treeStructure = sourceService.getTreeStructureFromTabs(draggedTabs);
+		var treeStructure = utils.getTreeStructureFromTabs(draggedTabs);
 
 		var newTabs = sv.moveTabsInternal(draggedTabs, {
 				duplicate    : aInfo.action & sv.kACTION_DUPLICATE,
@@ -1053,8 +1044,7 @@ try{
 		return (info.position == sv.kDROP_ON || sv.position != 'top')
 }
 catch(e) {
-		if (utils.isDebugging('tabbarDNDObserver'))
-			dump('TabbarDND::onDragOver\n'+e+'\n');
+		log('onDragOver', e);
 }
 	},
   
@@ -1100,10 +1090,9 @@ catch(e) {
 
 		var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
 
-		if (utils.isDebugging('tabbarDNDObserver'))
-			dump('TabbarDND::onDrop\n' +
-				'  dt.dropEffect: ' + dt.dropEffect + '\n' +
-				'  draggedTab:    ' + draggedTab + '\n');
+		log('TabbarDND::onDrop',
+			'  dt.dropEffect: ' + dt.dropEffect,
+			'  draggedTab:    ' + draggedTab);
 
 		if (dt.dropEffect != 'link' &&
 			dt.dropEffect != 'move' &&
@@ -1173,9 +1162,8 @@ catch(e) {
 				if (aURI.indexOf(this.BOOKMARK_FOLDER) == 0) {
 					let newTabs = sv.getNewTabsWithOperation(function() {
 									var data = aURI.replace(self.BOOKMARK_FOLDER, '');
-									if (utils.isDebugging('tabbarDNDObserver'))
-										dump('TabbarDND::handleLinksOrBookmarks\n' +
-											'  bookmark folder data: ' + data + '\n');
+									log('TabbarDND::handleLinksOrBookmarks' +
+										'  bookmark folder data: ' + data);
 									data = JSON.parse(data);
 									w.PlacesUIUtils._openTabset(data.children, { type : 'drop' }, w, data.title);
 								}, b);
@@ -1231,7 +1219,7 @@ catch(e) {
 		}
 		let normalizedURI;
 		try {
-			normalizedURI = this.treeStyleTab.makeURIFromSpec(aURI);
+			normalizedURI = utils.makeURIFromSpec(aURI);
 		}
 		catch(e) {
 		}
@@ -1303,7 +1291,7 @@ catch(e) {
 						}
 						// When a blank folder is dropped, just open a dummy tab with the folder name.
 						if (children && children.length == 0) {
-							let uri = this.treeStyleTab.getGroupTabURI({ title: item.title });
+							let uri = utils.getGroupTabURI({ title: item.title });
 							return [uri];
 						}
 					}
diff --git a/modules/utils.js b/modules/utils.js
index 240602f..368318b 100644
--- a/modules/utils.js
+++ b/modules/utils.js
@@ -14,7 +14,7 @@
  * The Original Code is the Tree Style Tab.
  *
  * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2010-2015
+ * Portions created by the Initial Developer are Copyright (C) 2010-2016
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
@@ -63,11 +63,13 @@ XPCOMUtils.defineLazyModuleGetter(this, 'Task',
 	'resource://gre/modules/Task.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Promise',
 	'resource://gre/modules/Promise.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Services',
+	'resource://gre/modules/Services.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'TreeStyleTabConstants',
   'resource://treestyletab-modules/constants.js', 'TreeStyleTabConstants');
 
 const TST_PREF_PREFIX = 'extensions.treestyletab.';
-const TST_PREF_VERSION = 11;
+const TST_PREF_VERSION = 12;
 
 
 var TreeStyleTabUtils = {
@@ -221,6 +223,13 @@ var TreeStyleTabUtils = {
 					this.setTreePref('maxTreeLevel.physical', physical);
 					this.clearTreePref('maxTreeLevel.phisical');
 				}
+			case 11:
+				{
+					prefs.clearPref('browser.tabs.insertRelatedAfterCurrent');
+					let backupValue = prefs.getPref('browser.tabs.insertRelatedAfterCurrent.backup');
+					if (backupValue !== null)
+						prefs.setPref('browser.tabs.insertRelatedAfterCurrent', backupValue);
+				}
 			default:
 				for (let i = 0, maxi = orientalPrefs.length; i < maxi; i++)
 				{
@@ -243,6 +252,81 @@ var TreeStyleTabUtils = {
 		return this.getTreePref('debug.' + aModule) || this.getTreePref('debug.all');
 	},
 
+	log : function utils_log(aModule, ...aArgs)
+	{
+		if (!this.isDebugging(aModule))
+			return;
+
+		var logString = '[treestyletab:' + aModule+'] '+ aArgs.map(this.objectToLogString, this).join('');
+		Services.console.logStringMessage(logString);
+		dump(logString+'\n');
+	},
+	logWithStackTrace : function utils_logWithStackTrace(aModule, ...aArgs)
+	{
+		var stack = (new Error()).stack.replace(/^/gm, '  ');
+		return this.log.apply(this, [aModule].concat(aArgs).concat([stack]));
+	},
+	objectToLogString : function utils_objectToLogString(aObject)
+	{
+		if (!aObject)
+			return JSON.stringify(aObject);
+
+		if (/^(string|number|boolean)$/.test(typeof aObject))
+			return aObject;
+
+		return this.objectToString(aObject);
+	},
+	objectToString : function utils_objectToString(aObject)
+	{
+		try {
+			if (!aObject ||
+				/^(string|number|boolean)$/.test(typeof aObject))
+				return JSON.stringify(aObject);
+
+			if (Array.isArray(aObject))
+				return '['+aObject.map(this.objectToString, this).join(', ')+']';
+
+			var constructor = String(aObject.constructor).match(/^function ([^\(]+)/);
+			if (constructor) {
+				constructor = constructor[1];
+				switch (constructor)
+				{
+					case 'String':
+					case 'Number':
+					case 'Boolean':
+						return JSON.stringify(aObject);
+
+					case 'Object':
+						return '{' + Object.keys(aObject).map(function(aKey) {
+							return '"' + aKey + '":' + this.objectToString(aObject[aKey]);
+						}, this).join(', ') + '}';
+
+					default:
+						break;
+				}
+
+				if (/Element$/.test(constructor)) {
+					let id = '';
+					if (aObject.hasAttribute('id'))
+						id = '#' + aObject.getAttribute('id');
+
+					let classes = '';
+					if (aObject.className)
+						classes = '.' + aObject.className.replace(/\s+/g, '.');
+
+					return '<' + aObject.localName + id + classes + '>';
+				}
+
+				return '<object '+constructor+'>';
+			}
+
+			return String(aObject);
+		}
+		catch(e) {
+			return String(e);
+		}
+	},
+
 /* string bundle */
 	get treeBundle () {
 		return stringBundle.get('chrome://treestyletab/locale/treestyletab.properties');
@@ -328,6 +412,288 @@ var TreeStyleTabUtils = {
 				this.isPrefChanging(aKey);
 	},
 
+
+// xpath 
+	
+	NSResolver : { 
+		lookupNamespaceURI : function(aPrefix)
+		{
+			switch (aPrefix)
+			{
+				case 'xul':
+					return 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
+				case 'html':
+				case 'xhtml':
+					return 'http://www.w3.org/1999/xhtml';
+				case 'xlink':
+					return 'http://www.w3.org/1999/xlink';
+				default:
+					return '';
+			}
+		}
+	},
+ 
+	evaluateXPath : function utils_evaluateXPath(aExpression, aContext, aType) 
+	{
+		if (!aType)
+			aType = Ci.nsIDOMXPathResult.ORDERED_NODE_SNAPSHOT_TYPE;
+		try {
+			var XPathResult = (aContext.ownerDocument || aContext).evaluate(
+					aExpression,
+					(aContext || document),
+					this.NSResolver,
+					aType,
+					null
+				);
+		}
+		catch(e) {
+			return {
+				singleNodeValue : null,
+				snapshotLength  : 0,
+				snapshotItem    : function() {
+					return null
+				}
+			};
+		}
+		return XPathResult;
+	},
+ 
+	getArrayFromXPathResult : function utils_getArrayFromXPathResult(aXPathResult) 
+	{
+		var max = aXPathResult.snapshotLength;
+		var array = new Array(max);
+		if (!max)
+			return array;
+
+		for (var i = 0; i < max; i++)
+		{
+			array[i] = aXPathResult.snapshotItem(i);
+		}
+
+		return array;
+	},
+
+
+	getTabBrowserFromChild : function utils_getTabBrowserFromChild(aTabBrowserChild) 
+	{
+		if (!aTabBrowserChild)
+			return null;
+
+		if (aTabBrowserChild.__treestyletab__linkedTabBrowser) // tab
+			return aTabBrowserChild.__treestyletab__linkedTabBrowser;
+
+		if (aTabBrowserChild.localName == 'tabbrowser') // itself
+			return aTabBrowserChild;
+
+		if (aTabBrowserChild.tabbrowser) // tabs
+			return aTabBrowserChild.tabbrowser;
+
+		if (aTabBrowserChild.localName == 'toolbar') // tabs toolbar
+			return aTabBrowserChild.getElementsByTagName('tabs')[0].tabbrowser;
+
+		// tab context menu
+		var popup = this.evaluateXPath(
+				'ancestor-or-self::xul:menupopup[@id="tabContextMenu"]',
+				aTabBrowserChild,
+				Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+			).singleNodeValue;
+		if (popup && 'TabContextMenu' in aTabBrowserChild.ownerDocument.defaultView)
+			return this.getTabBrowserFromChild(aTabBrowserChild.ownerDocument.defaultView.TabContextMenu.contextTab);
+
+		var b = this.evaluateXPath(
+				'ancestor::xul:tabbrowser | '+
+				'ancestor::xul:tabs[@tabbrowser] |'+
+				'ancestor::xul:toolbar/descendant::xul:tabs',
+				aTabBrowserChild,
+				Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE
+			).singleNodeValue;
+		return (b && b.tabbrowser) || b;
+	},
+
+
+ 
+	getTreeStructureFromTabs : function TSTUtils_getTreeStructureFromTabs(aTabs) 
+	{
+		if (!aTabs || !aTabs.length)
+			return [];
+
+		/* this returns...
+		  [A]     => -1 (parent is not in this tree)
+		    [B]   => 0 (parent is 1st item in this tree)
+		    [C]   => 0 (parent is 1st item in this tree)
+		      [D] => 2 (parent is 2nd in this tree)
+		  [E]     => -1 (parent is not in this tree, and this creates another tree)
+		    [F]   => 0 (parent is 1st item in this another tree)
+		*/
+		var browser = this.getTabBrowserFromChild(aTabs[0]);
+		return this.cleanUpTreeStructureArray(
+				aTabs.map(function(aTab, aIndex) {
+					let tab = browser.treeStyleTab.getParentTab(aTab);
+					let index = tab ? aTabs.indexOf(tab) : -1 ;
+					return index >= aIndex ? -1 : index ;
+				}, this),
+				-1
+			);
+	},
+	cleanUpTreeStructureArray : function TSTUtils_cleanUpTreeStructureArray(aTreeStructure, aDefaultParent)
+	{
+		var offset = 0;
+		aTreeStructure = aTreeStructure
+			.map(function(aPosition, aIndex) {
+				return (aPosition == aIndex) ? -1 : aPosition ;
+			})
+			.map(function(aPosition, aIndex) {
+				if (aPosition == -1) {
+					offset = aIndex;
+					return aPosition;
+				}
+				return aPosition - offset;
+			});
+
+		/* The final step, this validates all of values.
+		   Smaller than -1 is invalid, so it becomes to -1. */
+		aTreeStructure = aTreeStructure.map(function(aIndex) {
+				return aIndex < -1 ? aDefaultParent : aIndex ;
+			}, this);
+		return aTreeStructure;
+	},
+
+
+	updateNarrowScrollbarStyle : function utils_updateNarrowScrollbarStyle(aTabBrowser) 
+	{
+		if (this.updatingNarrowScrollbarStyle)
+			return;
+
+		this.updatingNarrowScrollbarStyle = true;
+		setTimeout((function() {
+			this.updatingNarrowScrollbarStyle = false;
+		}).bind(this), 100);
+
+		const SSS = Cc['@mozilla.org/content/style-sheet-service;1']
+					.getService(Ci.nsIStyleSheetService);
+
+		if (this.lastAgentSheetForNarrowScrollbar &&
+			SSS.sheetRegistered(this.lastAgentSheetForNarrowScrollbar, SSS.AGENT_SHEET))
+			SSS.unregisterSheet(this.lastAgentSheetForNarrowScrollbar, SSS.AGENT_SHEET);
+
+		var scrollbox = aTabBrowser.tabContainer.mTabstrip._scrollbox;
+		var d = scrollbox.ownerDocument;
+
+		// We have to calculate the width of the scroll bar indirectly
+		// based on the width of the container and the scrollable contents,
+		// because the scrollbar is not accessible via public APIs.
+		var scrollbarSize = this.lastOriginalScrollbarSize;
+		if (scrollbarSize == 0) {
+			let nodes = d.getAnonymousNodes(scrollbox);
+			if (nodes) {
+				for (let i = 0, maxi = nodes.length; i < maxi; i++)
+				{
+					if (nodes[i].localName != 'box')
+						continue;
+					scrollbarSize = scrollbox.boxObject.width - nodes[i].boxObject.width;
+					break;
+				}
+			}
+		}
+
+		var size = this.getTreePref('tabbar.narrowScrollbar.width');
+		var rulesToSizeScrollbar;
+		var rulesToSizeScrollbarContents;
+		if (scrollbarSize) {
+			let overWidth = size - scrollbarSize;
+			let leftMargin = Math.floor(overWidth / 2);
+			let rightMargin = overWidth - leftMargin;
+			rulesToSizeScrollbar = 'margin-left: '+leftMargin+'px;' +
+									'margin-right: '+rightMargin+'px;';
+		}
+		else {
+			rulesToSizeScrollbar = 'font-size: '+size+'px;';
+			rulesToSizeScrollbarContents = 'max-width: '+size+'px;' +
+											'min-width: '+size+'px;';
+		}
+
+		const style = 'data:text/css,'+encodeURIComponent(
+			('@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");' +
+
+			(rulesToSizeScrollbarContents ?
+			'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
+			'  .tabbrowser-arrowscrollbox' +
+			'  > scrollbox' +
+			'  > scrollbar[orient="vertical"],' +
+			'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
+			'  .tabbrowser-arrowscrollbox' +
+			'  > scrollbox' +
+			'  > scrollbar[orient="vertical"] * {' + rulesToSizeScrollbarContents + '}' : '' ) +
+
+			'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
+			'  .tabbrowser-arrowscrollbox' +
+			'  > scrollbox' +
+			'  > scrollbar[orient="vertical"] {' + rulesToSizeScrollbar + '}' +
+
+			'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
+			'  .tabbrowser-arrowscrollbox' +
+			'  > scrollbox' +
+			'  > scrollbar[orient="vertical"] * {' +
+			'  padding-left: 0;' +
+			'  padding-right: 0;' +
+			'  margin-left: 0;' +
+			'  margin-right: 0;' +
+			'}' +
+
+			'%FORCE_NARROW_SCROLLBAR%')
+				.replace(/%FORCE_NARROW_SCROLLBAR%/g,
+					this.getTreePref('tabbar.narrowScrollbar.overrideSystemAppearance') ?
+						TreeStyleTabConstants.kOVERRIDE_SYSTEM_SCROLLBAR_APPEARANCE : '' )
+				.replace(/%MODE%/g, TreeStyleTabConstants.kMODE)
+				.replace(/%NARROW%/g, TreeStyleTabConstants.kNARROW_SCROLLBAR)
+				.replace(/%SIZE%/g, size)
+			);
+		this.lastAgentSheetForNarrowScrollbar = this.makeURIFromSpec(style);
+		SSS.loadAndRegisterSheet(this.lastAgentSheetForNarrowScrollbar, SSS.AGENT_SHEET);
+	},
+	kOVERRIDE_SYSTEM_SCROLLBAR_APPEARANCE :
+		'tabs.tabbrowser-tabs[%MODE%="vertical"][%NARROW%="true"]' +
+		'  .tabbrowser-arrowscrollbox' +
+		'  > scrollbox' +
+		'  > scrollbar[orient="vertical"] {' +
+		'  appearance: none;' +
+		'  -moz-appearance: none;' +
+		'  background: ThreeDFace;' +
+		'  border: 1px solid ThreeDShadow;' +
+		'}',
+	lastAgentSheetForNarrowScrollbar : null,
+	lastOriginalScrollbarSize : 0,
+
+
+
+
+	makeURIFromSpec : function utils_makeURIFromSpec(aURI) 
+	{
+		var newURI;
+		aURI = aURI || '';
+		if (aURI && String(aURI).indexOf('file:') == 0) {
+			var fileHandler = Services.io.getProtocolHandler('file').QueryInterface(Ci.nsIFileProtocolHandler);
+			var tempLocalFile = fileHandler.getFileFromURLSpec(aURI);
+			newURI = Services.io.newFileURI(tempLocalFile);
+		}
+		else {
+			if (!/^\w+\:/.test(aURI))
+				aURI = 'http://'+aURI;
+			newURI = Services.io.newURI(aURI, null, null);
+		}
+		return newURI;
+	},
+ 
+	getGroupTabURI : function utils_getGroupTabURI(aOptions) 
+	{
+		aOptions = aOptions || {};
+		var parameters = [];
+		parameters.push('title=' + encodeURIComponent(aOptions.title || ''));
+		parameters.push('temporary=' + !!aOptions.temporary);
+		return 'about:treestyletab-group?' + parameters.join('&');
+	},
+
+
 /* Pref Listener */ 
 	domains : [ 
 		'extensions.treestyletab.'
diff --git a/modules/window.js b/modules/window.js
index d9b15dd..5624ac5 100644
--- a/modules/window.js
+++ b/modules/window.js
@@ -14,7 +14,7 @@
  * The Original Code is the Tree Style Tab.
  *
  * The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
- * Portions created by the Initial Developer are Copyright (C) 2012-2015
+ * Portions created by the Initial Developer are Copyright (C) 2012-2016
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
@@ -71,6 +71,13 @@ XPCOMUtils.defineLazyModuleGetter(this, 'ContentBridge', 'resource://treestyleta
 XPCOMUtils.defineLazyServiceGetter(this, 'SessionStore',
   '@mozilla.org/browser/sessionstore;1', 'nsISessionStore');
 
+function log(...aArgs) {
+	utils.log.apply(utils, ['window'].concat(aArgs));
+}
+function logWithStackTrace(...aArgs) {
+	utils.logWithStackTrace.apply(utils, ['window'].concat(aArgs));
+}
+
 function TreeStyleTabWindow(aWindow)
 {
 	this.window = aWindow;
@@ -714,7 +721,12 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 				return this.onKeyRelease(aEvent);
 
 			case 'blur':
-				return this.simulateKeyRelease();
+				let activeWindow = Cc['@mozilla.org/focus-manager;1']
+									.getService(Ci.nsIFocusManager)
+									.activeWindow;
+				if (!activeWindow || activeWindow != this.window)
+					this.simulateKeyRelease();
+				return;
 
 			case 'mousedown':
 				return this.onTabbarResizeStart(aEvent);
@@ -729,7 +741,11 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 				return this.onTabbarReset(aEvent);
 
 			case 'click':
-				return this.handleNewTabActionOnButton(aEvent);
+				if (aEvent.currentTarget.localName == 'splitter')
+					this.onTabbarSplitterClick(aEvent);
+				else
+					this.handleNewTabActionOnButton(aEvent);
+				return;
 
 
 			case 'beforecustomization':
@@ -964,18 +980,11 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
  
 	get shouldListenKeyEventsForAutoExpandByFocusChange() 
 	{
-		return !this.ctrlTabPreviewsEnabled &&
-				(
+		return (
 					utils.getTreePref('autoExpandSubtreeOnSelect.whileFocusMovingByShortcut') ||
 					utils.getTreePref('autoCollapseExpandSubtreeOnSelect')
 				);
 	},
- 
-	get ctrlTabPreviewsEnabled() 
-	{
-		return 'allTabs' in this.window &&
-				prefs.getPref('browser.ctrlTab.previews');
-	},
    
 	receiveMessage : function TSTWindow_receiveMessage(aMessage) 
 	{
@@ -1104,6 +1113,44 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 		}
 	},
  
+	onTabbarSplitterClick : function TSTWindow_onTabbarSplitterClick(aEvent) 
+	{
+		if (
+			aEvent.button != 1 ||
+			(aEvent.button == 0 && !isAccelKeyPressed(aEvent))
+			)
+			return;
+
+		var grippy = utils.evaluateXPath(
+			'ancestor-or-self::*[local-name()="grippy"]',
+			aEvent.originalTarget || aEvent.target,
+			Ci.nsIDOMXPathResult.BOOLEAN_TYPE
+		).booleanValue;
+		if (grippy && aEvent.button == 0)
+			return;
+
+		this.onTabbarToggleCollapsed(aEvent.currentTarget);
+	},
+	onTabbarToggleCollapsed : function TSTWindow_onTabbarToggleCollapsed(aTarget) 
+	{
+		var b = this.getTabBrowserFromChild(aTarget);
+		var splitter = b.treeStyleTab.splitter;
+
+		var state = splitter.getAttribute('state');
+		var newState = state == 'collapsed' ? 'open' : 'collapsed';
+		splitter.setAttribute('state', newState);
+
+		// Workaround for bugs:
+		//  * https://github.com/piroor/treestyletab/issues/593
+		//  * https://github.com/piroor/treestyletab/issues/783
+		b.ownerDocument.defaultView.setTimeout(function() {
+			var visible = splitter.getAttribute('state') != 'collapsed';
+			var tabContainer = b.tabContainer;
+			if (visible != tabContainer.visible)
+				tabContainer.visible = visible;
+		}, 0);
+	},
+ 
 	onFocusNextTab : function TSTWindow_onFocusNextTab(aEvent) 
 	{
 		var tab = aEvent.originalTarget;
@@ -1238,7 +1285,7 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 	onPopupShown : function TSTWindow_onPopupShown(aPopup) 
 	{
 		if (!aPopup.boxObject ||
-			this.evaluateXPath(
+			utils.evaluateXPath(
 				'parent::*/ancestor-or-self::*[local-name()="tooltip" or local-name()="panel" or local-name()="popup" or local-name()="menupopup"]',
 				aPopup,
 				Ci.nsIDOMXPathResult.BOOLEAN_TYPE
@@ -1333,29 +1380,44 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 			this.handleNewTabFromCurrent(aOwner);
 	},
  
-	onBeforeOpenLinkWithTab : function TSTWindow_onBeforeOpenLinkWithTab(aTab, aFromChrome) 
+	onBeforeOpenLinkWithTab : function TSTWindow_onBeforeOpenLinkWithTab(aTab, aParams) 
 	{
-		if (!aFromChrome && aTab && !this.checkToOpenChildTab(aTab))
-			this.handleNewTabFromCurrent(aTab);
+		if (!aTab)
+			return;
+
+		log('onBeforeOpenLinkWithTab: ', [aTab, aParams, this.checkToOpenChildTab(aTab)]);
+
+		if (!this.checkToOpenChildTab(aTab)) {
+			if (!aParams.fromChrome)
+				this.handleNewTabFromCurrent(aTab);
+			else if (!aParams.relatedToCurrent && !aParams.referrerURI)
+				this.readyToOpenOrphanTabNow(aTab);
+		}
 	},
  
 	onBeforeOpenNewTabByThirdParty : function TSTWindow_onBeforeOpenNewTabByThirdParty(aOwner) 
 	{
-		if (!this.checkToOpenChildTab(aOwner))
+		log('onBeforeOpenNewTabByThirdParty: ', [aOwner, this.checkToOpenChildTab(aTab)]);
+
+		if (!this.checkToOpenChildTab(aOwner)) {
 			this.handleNewTabFromCurrent(aOwner);
+		}
 	},
  
-	onBeforeBrowserAccessOpenURI : function TSTWindow_onBeforeBrowserAccessOpenURI(aOpener, aWhere, aContext) 
+	onBeforeBrowserAccessOpenURI : function TSTWindow_onBeforeBrowserAccessOpenURI(aOpener, aWhere) 
 	{
 		var hasOwnerTab = false;
 		var opener = null;
 		if (aOpener) {
 			if (aOpener instanceof Ci.nsIDOMWindow) {
+				log('onBeforeBrowserAccessOpenURI: opener is DOMWindow');
 				opener = aOpener;
 				hasOwnerTab = this.getTabFromFrame(opener.top);
+				log('  opener =>', [opener, hasOwnerTab]);
 			}
 			else if (Ci.nsIOpenURIInFrameParams &&
 					aOpener instanceof Ci.nsIOpenURIInFrameParams) {
+				log('TSTWindow_onBeforeBrowserAccessOpenURI: opener is nsIOpenURIInFrameParams');
 				// from remote contents, we have to detect its opener from the URI.
 				let referrer = aOpener.referrer;
 				if (referrer) {
@@ -1370,25 +1432,53 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 						break;
 					}
 				}
+				log('  opener =>', [opener, hasOwnerTab]);
 			}
 		}
-		var internalOpen = aContext != Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL;
-		if ((hasOwnerTab || internalOpen) &&
+		if (aOpener &&
+			hasOwnerTab &&
 			aWhere == Ci.nsIBrowserDOMWindow.OPEN_NEWTAB)
 			this.handleNewTabFromCurrent(opener);
+		else
+			this.readyToOpenOrphanTabNow(opener);
+	},
+ 
+	onBeforeGoHome : function TSTWindow_onBeforeGoHome(aEvent, aTabBrowser) 
+	{
+		if (!aEvent || aEvent.button === 2 || !aTabBrowser)
+			return;
+
+		var where = this.window.whereToOpenLink(aEvent, false, true);
+		if (where == 'current' && aTabBrowser.selectedTab.pinned)
+			where = 'tab';
+
+		if (where.indexOf('tab') === 0)
+			this.readyToOpenNewTabGroupNow(aTabBrowser);
+		else
+			this.readyToOpenOrphanTabNow(aTabBrowser);
 	},
  
 	onBeforeViewMedia : function TSTWindow_onBeforeViewMedia(aEvent, aOwner) 
 	{
-		if (String(this.window.whereToOpenLink(aEvent, false, true)).indexOf('tab') == 0)
+		var where = String(this.window.whereToOpenLink(aEvent, false, true));
+
+		log('onBeforeViewMedia: ', [aEvent, aOwner, where]);
+
+		if (where.indexOf('tab') == 0)
 			this.handleNewTabFromCurrent(aOwner);
+		else
+			this.readyToOpenOrphanTabNow(aOwner);
 	},
  
 	onBeforeBrowserSearch : function TSTWindow_onBeforeBrowserSearch(aTerm, aForceNewTab) 
 	{
+		log('onBeforeBrowserSearch: ', [aTerm, aForceNewTab, this.shouldOpenSearchResultAsChild(aTerm)]);
+
 		if ((arguments.length == 1 || aForceNewTab) &&
 			this.shouldOpenSearchResultAsChild(aTerm))
 			this.handleNewTabFromCurrent();
+		else
+			this.readyToOpenOrphanTabNow();
 	},
   
 /* Tree Style Tabの初期化が行われる前に復元されたセッションについてツリー構造を復元 */ 
@@ -1575,6 +1665,10 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
  
 	createSubtree : function TSTWindow_createSubtree(aTabs) 
 	{
+		log('TSTWindow_createSubtree\n'+aTabs.map(function(aTab) {
+			return '  '+aTab._tPos+': '+aTab.linkedBrowser.currentURI.spec;
+		}).join('\n'));
+
 		var rootTabs = this.getRootTabs(aTabs);
 
 		var parent = this.getParentTab(aTabs[0]);
@@ -1594,6 +1688,7 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 				var parentInTargets = aTabs.indexOf(this.getParentTab(aDescendantTab)) > -1;
 				if (inTargets || (inTargets == parentInTargets))
 					return;
+				log('  detaching unselected descendant: '+aDescendantTab._tPos+': '+aDescendantTab.linkedBrowser.currentURI.spec);
 				if (parentTab)
 					b.treeStyleTab.attachTabTo(aDescendantTab, parentTab, {
 						dontExpand   : true,
@@ -1609,7 +1704,7 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 
 		var shouldCreateGroup = aTabs.length > 1 && utils.getTreePref('createSubtree.underParent');
 		var root = shouldCreateGroup ?
-					b.addTab(this.getGroupTabURI({
+					b.addTab(utils.getGroupTabURI({
 						temporary: utils.getTreePref('createSubtree.underParent.temporaryGroup')
 					})) :
 					aTabs.shift() ;
@@ -1880,8 +1975,7 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 /* Pref Listener */ 
 	
 	domains : [ 
-		'extensions.treestyletab',
-		'browser.ctrlTab.previews'
+		'extensions.treestyletab'
 	],
  
 	onPrefChange : function TSTWindow_onPrefChange(aPrefName) 
@@ -1894,7 +1988,6 @@ TreeStyleTabWindow.prototype = inherit(TreeStyleTabBase, {
 				this.themeManager.set(prefs.getPref('extensions.treestyletab.tabbar.style'), this.position);
 				break;
 
-			case 'browser.ctrlTab.previews':
 			case 'extensions.treestyletab.autoCollapseExpandSubtreeOnSelect.whileFocusMovingByShortcut':
 			case 'extensions.treestyletab.autoCollapseExpandSubtreeOnSelect':
 				if (this.shouldListenKeyEventsForAutoExpandByFocusChange)
diff --git a/skin/classic/treestyletab/group.css b/skin/classic/treestyletab/group.css
index eb4457d..14d1d8d 100644
--- a/skin/classic/treestyletab/group.css
+++ b/skin/classic/treestyletab/group.css
@@ -1,3 +1,6 @@
+ at namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+ at namespace xhtml url("http://www.w3.org/1999/xhtml");
+
 :root {
 	appearance: window;
 	-moz-appearance: window;
@@ -57,12 +60,16 @@
 
 
 #tree {
-	margin-top: 1em;
+	margin: 1em 0 0 0.5em;
 	overflow: auto;
 	box-flex: 1;
 	-moz-box-flex: 1;
 }
 
-.treestyletab-pseudo-tree-root-item {
-	display: none;
+*|*.treestyletab-pseudo-tree-root-item {
+	display: none !important;
+}
+*|*.treestyletab-pseudo-tree-root-item +
+  *|*.treestyletab-pseudo-tree-children > *|* {
+	margin-left: 0 !important;
 }
diff --git a/skin/classic/treestyletab/license.txt b/skin/classic/treestyletab/license.txt
index 6f14a29..023b08a 100644
--- a/skin/classic/treestyletab/license.txt
+++ b/skin/classic/treestyletab/license.txt
@@ -14,7 +14,7 @@ License.
 The Original Code is the Tree Style Tab.
 
 The Initial Developer of the Original Code is YUKI "Piro" Hiroshi.
-Portions created by the Initial Developer are Copyright (C) 2007-2013
+Portions created by the Initial Developer are Copyright (C) 2007-2016
 the Initial Developer. All Rights Reserved.
 
 Contributor(s): YUKI "Piro" Hiroshi <piro.outsider.reflex at gmail.com>
diff --git a/skin/classic/treestyletab/metal/base.css b/skin/classic/treestyletab/metal/base.css
index d38fe58..5977ab5 100644
--- a/skin/classic/treestyletab/metal/base.css
+++ b/skin/classic/treestyletab/metal/base.css
@@ -40,6 +40,23 @@
 	border-width: 1px 0 0 !important;
 	padding: 0 !important;
 }
+/* these styles are required to cover narrow scrollbars. */
+.tabbrowser-tabs[treestyletab-mode="vertical"]
+  .scrollbox-innerbox {
+	background: linear-gradient(to left,
+	                            rgba(121,121,121,1) 0%,
+	                            rgba(121,121,121,1) 10%,
+	                            rgba(121,121,121,0) 11%,
+	                            rgba(121,121,121,0) 100%) !important;
+}
+.tabbrowser-tabs[treestyletab-tabbar-position="left"][treestyletab-invert-scrollbar="true"]
+  .scrollbox-innerbox {
+	background: linear-gradient(to right,
+	                            rgba(121,121,121,1) 0%,
+	                            rgba(121,121,121,1) 10%,
+	                            rgba(121,121,121,0) 11%,
+	                            rgba(121,121,121,0) 100%) !important;
+}
 
 .tabbrowser-tabs[treestyletab-mode="vertical"] {
 	appearance: none !important;
@@ -51,14 +68,20 @@
 .tabbrowser-tabs[treestyletab-mode="vertical"]:not([overflow="true"])
   .tabbrowser-arrowscrollbox,
 .tabbrowser-tabs[treestyletab-mode="vertical"][overflow="true"]
-  .tabbrowser-arrowscrollbox .scrollbox-innerbox {
-	background: url("shadow-active-l.png") repeat-y top right !important;
+  .tabbrowser-arrowscrollbox
+  scrollbox {
+	background-image: url("shadow-active-l.png") !important;
+	background-repeat: repeat-y !important;
+	background-position: top right !important;
 }
 .tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-tab-inverted="true"]:not([overflow="true"])
   .tabbrowser-arrowscrollbox,
 .tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-tab-inverted="true"][overflow="true"]
-  .tabbrowser-arrowscrollbox .scrollbox-innerbox {
-	background: url("shadow-active-r.png") repeat-y top left !important;
+  .tabbrowser-arrowscrollbox
+  scrollbox {
+	background-image: url("shadow-active-r.png") !important;
+	background-repeat: repeat-y !important;
+	background-position: top left !important;
 }
 
 .tabbrowser-tabs[treestyletab-mode="vertical"]
@@ -100,8 +123,30 @@ tabbrowser[treestyletab-tabbar-position="right"]
 	background: #acacac !important;
 	border-color: #797979 !important;
 }
+/* these styles are required to cover narrow scrollbars. */
 :root:-moz-window-inactive
-  .tabbrowser-strip[treestyletab-mode="vertical"][treestyletab-style~="aero"] {
+  .tabbrowser-tabs[treestyletab-mode="vertical"]
+  .scrollbox-innerbox {
+	background: linear-gradient(to left,
+	                            rgba(172,172,172,1) 0%,
+	                            rgba(172,172,172,1) 10%,
+	                            rgba(172,172,172,0) 11%,
+	                            rgba(172,172,172,0) 100%) !important;
+}
+:root:-moz-window-inactive
+  .tabbrowser-tabs[treestyletab-tabbar-position="left"][treestyletab-invert-scrollbar="true"]
+  .scrollbox-innerbox {
+	background: linear-gradient(to right,
+	                            rgba(172,172,172,1) 0%,
+	                            rgba(172,172,172,1) 10%,
+	                            rgba(172,172,172,0) 11%,
+	                            rgba(172,172,172,0) 100%) !important;
+}
+:root:-moz-window-inactive
+  .tabbrowser-strip[treestyletab-mode="vertical"][treestyletab-style~="aero"],
+:root:-moz-window-inactive
+  .tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-style~="aero"]
+  .scrollbox-innerbox {
 	background: transparent !important;
 }
 
@@ -110,8 +155,11 @@ tabbrowser[treestyletab-tabbar-position="right"]
   .tabbrowser-arrowscrollbox,
 :root:-moz-window-inactive
   .tabbrowser-tabs[treestyletab-mode="vertical"][overflow="true"]
-  .tabbrowser-arrowscrollbox .scrollbox-innerbox {
-	background: url("shadow-inactive-l.png") repeat-y top right !important;
+  .tabbrowser-arrowscrollbox
+  scrollbox {
+	background-image: url("shadow-inactive-l.png") !important;
+	background-repeat: repeat-y !important;
+	background-position: top right !important;
 }
 :root:-moz-window-inactive
   .tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-tab-inverted="true"]:not([overflow="true"])
@@ -119,8 +167,10 @@ tabbrowser[treestyletab-tabbar-position="right"]
 :root:-moz-window-inactive
   .tabbrowser-tabs[treestyletab-mode="vertical"][treestyletab-tab-inverted="true"][overflow="true"]
   .tabbrowser-arrowscrollbox
-  .scrollbox-innerbox {
-	background: url("shadow-inactive-r.png") repeat-y top left !important;
+  scrollbox {
+	background-image: url("shadow-inactive-r.png") !important;
+	background-repeat: repeat-y !important;
+	background-position: top left !important;
 }
 
 :root:-moz-window-inactive
diff --git a/skin/classic/treestyletab/pseudo-tree.css b/skin/classic/treestyletab/pseudo-tree.css
index 311bf76..73ae9a8 100644
--- a/skin/classic/treestyletab/pseudo-tree.css
+++ b/skin/classic/treestyletab/pseudo-tree.css
@@ -1,25 +1,35 @@
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+ at namespace xhtml url("http://www.w3.org/1999/xhtml");
 
-.treestyletab-pseudo-tree-favicon {
+*|*.treestyletab-pseudo-tree-favicon {
 	height: 16px;
 	max-width: 16px;
 	max-height: 16px;
+	position: relative;
+	top: 0.25em;
 	width: 16px;
 }
 
-.treestyletab-pseudo-tree-row {
-	box-align: center;
-	-moz-box-align: center;
+*|*.treestyletab-pseudo-tree-item {
+	display: block;
+	line-height: 1.5;
+	margin-bottom: 0.15em;
+	white-space: pre;
 }
 
-.treestyletab-pseudo-tree-row label.text-link {
-	box-crop: end;
-	-moz-box-crop: end;
+*|*.treestyletab-pseudo-tree-row {
+	display: block;
 }
 
-.treestyletab-pseudo-tree-children {
+*|*.treestyletab-pseudo-tree-row label.text-link {
+	display: inline-block;
+	margin: 0;
+	padding: 0 0 0 0.25em;
+	vertical-align: text-top;
+	white-space: pre-wrap;
+}
+
+*|*.treestyletab-pseudo-tree-children > *|* {
 	margin-left: 1.5em;
-	box-align: stretch;
-	-moz-box-align: stretch;
 }
 
diff --git a/skin/classic/treestyletab/sidebar/sidebar.css b/skin/classic/treestyletab/sidebar/sidebar.css
index 16189a8..4ef8ba6 100644
--- a/skin/classic/treestyletab/sidebar/sidebar.css
+++ b/skin/classic/treestyletab/sidebar/sidebar.css
@@ -18,12 +18,54 @@
 /* Background colour for the tree sidebar (light blue when window is
    active, grey otherwise) */
 .tabbrowser-strip[treestyletab-mode="vertical"] {
-	background: transparent !important;
-	background-color: #d4dde5 !important;
+	background: #d4dde5 !important;
+}
+/* these styles are required to cover narrow scrollbars. */
+.tabbrowser-tabs[treestyletab-mode="vertical"]
+  .scrollbox-innerbox {
+	background: linear-gradient(to left,
+	                            rgba(212,221,229,1) 0%,
+	                            rgba(212,221,229,1) 10%,
+	                            rgba(212,221,229,0) 11%,
+	                            rgba(212,221,229,0) 100%) !important;
+}
+.tabbrowser-tabs[treestyletab-tabbar-position="left"][treestyletab-invert-scrollbar="true"]
+  .scrollbox-innerbox {
+	background: linear-gradient(to right,
+	                            rgba(212,221,229,1) 0%,
+	                            rgba(212,221,229,1) 10%,
+	                            rgba(212,221,229,0) 11%,
+	                            rgba(212,221,229,0) 100%) !important;
+}
+.tabbrowser-tabs[treestyletab-mode="vertical"]
+  .scrollbox-innerbox {
+	background: linear-gradient(to left,
+	                            rgba(212,221,229,1) 0%,
+	                            rgba(212,221,229,1) 10%,
+	                            rgba(212,221,229,0) 11%,
+	                            rgba(212,221,229,0) 100%) !important;
+}
+.tabbrowser-tabs[treestyletab-tabbar-position="left"][treestyletab-invert-scrollbar="true"]
+  .scrollbox-innerbox {
+	background: linear-gradient(to right,
+	                            rgba(212,221,229,1) 0%,
+	                            rgba(212,221,229,1) 10%,
+	                            rgba(212,221,229,0) 11%,
+	                            rgba(212,221,229,0) 100%) !important;
 }
+
 #main-window:-moz-window-inactive
   .tabbrowser-strip:not([treestyletab-style~="aero"])[treestyletab-mode="vertical"] {
-	background-color: #e8e8e8 !important;
+	background: #e8e8e8 !important;
+}
+#main-window:-moz-window-inactive
+  .tabbrowser-tabs:not([treestyletab-style~="aero"])[treestyletab-mode="vertical"]
+  .scrollbox-innerbox {
+	background: linear-gradient(to right,
+	                            rgba(232,232,232,1) 0%,
+	                            rgba(232,232,232,1) 10%,
+	                            rgba(232,232,232,0) 11%,
+	                            rgba(232,232,232,0) 100%) !important;
 }
 /* autohide */
 .treestyletab-tabbar-toolbar[treestyletab-tabbar-autohide][treestyletab-mode="vertical"]
diff --git a/skin/classic/treestyletab/square/base.css b/skin/classic/treestyletab/square/base.css
index 6d1adb2..3d1487d 100644
--- a/skin/classic/treestyletab/square/base.css
+++ b/skin/classic/treestyletab/square/base.css
@@ -17,6 +17,23 @@
 	-moz-appearance: none;
 	background: darkgray !important;
 }
+/* these styles are required to cover narrow scrollbars. */
+.tabbrowser-tabs[treestyletab-style~="border"][treestyletab-mode="vertical"]
+  .scrollbox-innerbox {
+	background: linear-gradient(to left,
+	                            rgba(169,169,169,1) 0%,
+	                            rgba(169,169,169,1) 10%,
+	                            rgba(169,169,169,0) 11%,
+	                            rgba(169,169,169,0) 100%) !important;
+}
+.tabbrowser-tabs[treestyletab-style~="border"][treestyletab-tabbar-position="left"][treestyletab-invert-scrollbar="true"]
+  .scrollbox-innerbox {
+	background: linear-gradient(to right,
+	                            rgba(169,169,169,1) 0%,
+	                            rgba(169,169,169,1) 10%,
+	                            rgba(169,169,169,0) 11%,
+	                            rgba(169,169,169,0) 100%) !important;
+}
 
 .tabbrowser-strip[treestyletab-mode="vertical"],
 .treestyletab-tabbar-toolbar[treestyletab-mode="vertical"],
diff --git a/skin/classic/treestyletab/square/vertigo.css b/skin/classic/treestyletab/square/vertigo.css
index 68bd86b..2d8ecb9 100644
--- a/skin/classic/treestyletab/square/vertigo.css
+++ b/skin/classic/treestyletab/square/vertigo.css
@@ -1,5 +1,23 @@
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 
+/* these styles are required to cover narrow scrollbars. */
+.tabbrowser-tabs[treestyletab-mode="vertical"]
+  .scrollbox-innerbox {
+	background: linear-gradient(to left,
+	                            -moz-dialog 0%,
+	                            -moz-dialog 10%,
+	                            transparent 11%,
+	                            transparent 100%) !important;
+}
+.tabbrowser-tabs[treestyletab-tabbar-position="left"][treestyletab-invert-scrollbar="true"]
+  .scrollbox-innerbox {
+	background: linear-gradient(to right,
+	                            -moz-dialog 0%,
+	                            -moz-dialog 10%,
+	                            transparent 11%,
+	                            transparent 100%) !important;
+}
+
 .tabbrowser-tabs:not([treestyletab-tabbar-position="top"]),
 .tabbrowser-tabs:not([treestyletab-tabbar-position="top"])
   .tabbrowser-tab:not([pinned]),
diff --git a/skin/classic/treestyletab/ui-base.css b/skin/classic/treestyletab/ui-base.css
index 600a32b..3a31d5f 100644
--- a/skin/classic/treestyletab/ui-base.css
+++ b/skin/classic/treestyletab/ui-base.css
@@ -419,3 +419,13 @@ tabbrowser[treestyletab-tabbar-position="bottom"]
   > .scrollbutton-down > * {
 	display: none;
 }
+
+.tabbrowser-tab[treestyletab-highlighted] {
+	outline: transparent solid 0.2em;
+	outline-offset: -0.2em;
+	-moz-outline-radius: 0.25em;
+	outline-radius: 0.25em;
+}
+.tabbrowser-tab[treestyletab-highlighted='notifying'] {
+	outline: Highlight solid 0.2em;
+}
diff --git a/treestyletab.update.rdf b/treestyletab.update.rdf
new file mode 100644
index 0000000..161072f
--- /dev/null
+++ b/treestyletab.update.rdf
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+        xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+    <rdf:Description rdf:about="urn:mozilla:extension:treestyletab at piro.sakura.ne.jp">
+        <em:updates>
+            <rdf:Seq>
+                <rdf:li>
+                    <rdf:Description>
+                        <em:version>0.16.2016021602</em:version>
+                        <em:targetApplication>
+                            <rdf:Description>
+                                <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+                                <em:minVersion>38.0</em:minVersion>
+                                <em:maxVersion>46.0a1</em:maxVersion>
+                                <em:updateLink>http://piro.sakura.ne.jp/xul/xpi/treestyletab.xpi?version=0.16.2016021602</em:updateLink>
+                                <em:updateHash>sha1:7fb200bbf69bc1f103df2630234183f9310511f2</em:updateHash>
+                            </rdf:Description>
+                        </em:targetApplication>
+                    </rdf:Description>
+                </rdf:li>
+            </rdf:Seq>
+        </em:updates>
+        <em:signature>
+            MIGRMAsGCSqGSIb3DQEBDQOBgQB/n6kVPTDADsmj0/gvaPxVLLLuUCYKmEiTOzMG
+            ujOVtb86gl7U7yRRkV71LVPAjxSmOc6oKhAVO5wcIua2DlmNsO1wg9xXGnVa4/ub
+            zFxNi1+bPAJtLn3rebkx0aoTSPSy42WLz7zr5YbpQqEyfb+RbHY7oWI5qierVCFD
+            U5iJ4g==
+        </em:signature>
+    </rdf:Description>
+</rdf:RDF>

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/tree-style-tab.git



More information about the Pkg-mozext-commits mailing list