addons/firefox-addons/tab-mover

changeset 0:480f8e4f4500

Initial revision
author Guido Berhoerster <guido+tab-mover@berhoerster.name>
date Sun Feb 19 00:20:26 2017 +0100 (2017-02-19)
parents
children 68114ae7d8b7
files COPYING Makefile NEWS README _locales/en/messages.json background.js icons/tab-mover.svg manifest.json
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/COPYING	Sun Feb 19 00:20:26 2017 +0100
     1.3 @@ -0,0 +1,373 @@
     1.4 +Mozilla Public License Version 2.0
     1.5 +==================================
     1.6 +
     1.7 +1. Definitions
     1.8 +--------------
     1.9 +
    1.10 +1.1. "Contributor"
    1.11 +    means each individual or legal entity that creates, contributes to
    1.12 +    the creation of, or owns Covered Software.
    1.13 +
    1.14 +1.2. "Contributor Version"
    1.15 +    means the combination of the Contributions of others (if any) used
    1.16 +    by a Contributor and that particular Contributor's Contribution.
    1.17 +
    1.18 +1.3. "Contribution"
    1.19 +    means Covered Software of a particular Contributor.
    1.20 +
    1.21 +1.4. "Covered Software"
    1.22 +    means Source Code Form to which the initial Contributor has attached
    1.23 +    the notice in Exhibit A, the Executable Form of such Source Code
    1.24 +    Form, and Modifications of such Source Code Form, in each case
    1.25 +    including portions thereof.
    1.26 +
    1.27 +1.5. "Incompatible With Secondary Licenses"
    1.28 +    means
    1.29 +
    1.30 +    (a) that the initial Contributor has attached the notice described
    1.31 +        in Exhibit B to the Covered Software; or
    1.32 +
    1.33 +    (b) that the Covered Software was made available under the terms of
    1.34 +        version 1.1 or earlier of the License, but not also under the
    1.35 +        terms of a Secondary License.
    1.36 +
    1.37 +1.6. "Executable Form"
    1.38 +    means any form of the work other than Source Code Form.
    1.39 +
    1.40 +1.7. "Larger Work"
    1.41 +    means a work that combines Covered Software with other material, in 
    1.42 +    a separate file or files, that is not Covered Software.
    1.43 +
    1.44 +1.8. "License"
    1.45 +    means this document.
    1.46 +
    1.47 +1.9. "Licensable"
    1.48 +    means having the right to grant, to the maximum extent possible,
    1.49 +    whether at the time of the initial grant or subsequently, any and
    1.50 +    all of the rights conveyed by this License.
    1.51 +
    1.52 +1.10. "Modifications"
    1.53 +    means any of the following:
    1.54 +
    1.55 +    (a) any file in Source Code Form that results from an addition to,
    1.56 +        deletion from, or modification of the contents of Covered
    1.57 +        Software; or
    1.58 +
    1.59 +    (b) any new file in Source Code Form that contains any Covered
    1.60 +        Software.
    1.61 +
    1.62 +1.11. "Patent Claims" of a Contributor
    1.63 +    means any patent claim(s), including without limitation, method,
    1.64 +    process, and apparatus claims, in any patent Licensable by such
    1.65 +    Contributor that would be infringed, but for the grant of the
    1.66 +    License, by the making, using, selling, offering for sale, having
    1.67 +    made, import, or transfer of either its Contributions or its
    1.68 +    Contributor Version.
    1.69 +
    1.70 +1.12. "Secondary License"
    1.71 +    means either the GNU General Public License, Version 2.0, the GNU
    1.72 +    Lesser General Public License, Version 2.1, the GNU Affero General
    1.73 +    Public License, Version 3.0, or any later versions of those
    1.74 +    licenses.
    1.75 +
    1.76 +1.13. "Source Code Form"
    1.77 +    means the form of the work preferred for making modifications.
    1.78 +
    1.79 +1.14. "You" (or "Your")
    1.80 +    means an individual or a legal entity exercising rights under this
    1.81 +    License. For legal entities, "You" includes any entity that
    1.82 +    controls, is controlled by, or is under common control with You. For
    1.83 +    purposes of this definition, "control" means (a) the power, direct
    1.84 +    or indirect, to cause the direction or management of such entity,
    1.85 +    whether by contract or otherwise, or (b) ownership of more than
    1.86 +    fifty percent (50%) of the outstanding shares or beneficial
    1.87 +    ownership of such entity.
    1.88 +
    1.89 +2. License Grants and Conditions
    1.90 +--------------------------------
    1.91 +
    1.92 +2.1. Grants
    1.93 +
    1.94 +Each Contributor hereby grants You a world-wide, royalty-free,
    1.95 +non-exclusive license:
    1.96 +
    1.97 +(a) under intellectual property rights (other than patent or trademark)
    1.98 +    Licensable by such Contributor to use, reproduce, make available,
    1.99 +    modify, display, perform, distribute, and otherwise exploit its
   1.100 +    Contributions, either on an unmodified basis, with Modifications, or
   1.101 +    as part of a Larger Work; and
   1.102 +
   1.103 +(b) under Patent Claims of such Contributor to make, use, sell, offer
   1.104 +    for sale, have made, import, and otherwise transfer either its
   1.105 +    Contributions or its Contributor Version.
   1.106 +
   1.107 +2.2. Effective Date
   1.108 +
   1.109 +The licenses granted in Section 2.1 with respect to any Contribution
   1.110 +become effective for each Contribution on the date the Contributor first
   1.111 +distributes such Contribution.
   1.112 +
   1.113 +2.3. Limitations on Grant Scope
   1.114 +
   1.115 +The licenses granted in this Section 2 are the only rights granted under
   1.116 +this License. No additional rights or licenses will be implied from the
   1.117 +distribution or licensing of Covered Software under this License.
   1.118 +Notwithstanding Section 2.1(b) above, no patent license is granted by a
   1.119 +Contributor:
   1.120 +
   1.121 +(a) for any code that a Contributor has removed from Covered Software;
   1.122 +    or
   1.123 +
   1.124 +(b) for infringements caused by: (i) Your and any other third party's
   1.125 +    modifications of Covered Software, or (ii) the combination of its
   1.126 +    Contributions with other software (except as part of its Contributor
   1.127 +    Version); or
   1.128 +
   1.129 +(c) under Patent Claims infringed by Covered Software in the absence of
   1.130 +    its Contributions.
   1.131 +
   1.132 +This License does not grant any rights in the trademarks, service marks,
   1.133 +or logos of any Contributor (except as may be necessary to comply with
   1.134 +the notice requirements in Section 3.4).
   1.135 +
   1.136 +2.4. Subsequent Licenses
   1.137 +
   1.138 +No Contributor makes additional grants as a result of Your choice to
   1.139 +distribute the Covered Software under a subsequent version of this
   1.140 +License (see Section 10.2) or under the terms of a Secondary License (if
   1.141 +permitted under the terms of Section 3.3).
   1.142 +
   1.143 +2.5. Representation
   1.144 +
   1.145 +Each Contributor represents that the Contributor believes its
   1.146 +Contributions are its original creation(s) or it has sufficient rights
   1.147 +to grant the rights to its Contributions conveyed by this License.
   1.148 +
   1.149 +2.6. Fair Use
   1.150 +
   1.151 +This License is not intended to limit any rights You have under
   1.152 +applicable copyright doctrines of fair use, fair dealing, or other
   1.153 +equivalents.
   1.154 +
   1.155 +2.7. Conditions
   1.156 +
   1.157 +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
   1.158 +in Section 2.1.
   1.159 +
   1.160 +3. Responsibilities
   1.161 +-------------------
   1.162 +
   1.163 +3.1. Distribution of Source Form
   1.164 +
   1.165 +All distribution of Covered Software in Source Code Form, including any
   1.166 +Modifications that You create or to which You contribute, must be under
   1.167 +the terms of this License. You must inform recipients that the Source
   1.168 +Code Form of the Covered Software is governed by the terms of this
   1.169 +License, and how they can obtain a copy of this License. You may not
   1.170 +attempt to alter or restrict the recipients' rights in the Source Code
   1.171 +Form.
   1.172 +
   1.173 +3.2. Distribution of Executable Form
   1.174 +
   1.175 +If You distribute Covered Software in Executable Form then:
   1.176 +
   1.177 +(a) such Covered Software must also be made available in Source Code
   1.178 +    Form, as described in Section 3.1, and You must inform recipients of
   1.179 +    the Executable Form how they can obtain a copy of such Source Code
   1.180 +    Form by reasonable means in a timely manner, at a charge no more
   1.181 +    than the cost of distribution to the recipient; and
   1.182 +
   1.183 +(b) You may distribute such Executable Form under the terms of this
   1.184 +    License, or sublicense it under different terms, provided that the
   1.185 +    license for the Executable Form does not attempt to limit or alter
   1.186 +    the recipients' rights in the Source Code Form under this License.
   1.187 +
   1.188 +3.3. Distribution of a Larger Work
   1.189 +
   1.190 +You may create and distribute a Larger Work under terms of Your choice,
   1.191 +provided that You also comply with the requirements of this License for
   1.192 +the Covered Software. If the Larger Work is a combination of Covered
   1.193 +Software with a work governed by one or more Secondary Licenses, and the
   1.194 +Covered Software is not Incompatible With Secondary Licenses, this
   1.195 +License permits You to additionally distribute such Covered Software
   1.196 +under the terms of such Secondary License(s), so that the recipient of
   1.197 +the Larger Work may, at their option, further distribute the Covered
   1.198 +Software under the terms of either this License or such Secondary
   1.199 +License(s).
   1.200 +
   1.201 +3.4. Notices
   1.202 +
   1.203 +You may not remove or alter the substance of any license notices
   1.204 +(including copyright notices, patent notices, disclaimers of warranty,
   1.205 +or limitations of liability) contained within the Source Code Form of
   1.206 +the Covered Software, except that You may alter any license notices to
   1.207 +the extent required to remedy known factual inaccuracies.
   1.208 +
   1.209 +3.5. Application of Additional Terms
   1.210 +
   1.211 +You may choose to offer, and to charge a fee for, warranty, support,
   1.212 +indemnity or liability obligations to one or more recipients of Covered
   1.213 +Software. However, You may do so only on Your own behalf, and not on
   1.214 +behalf of any Contributor. You must make it absolutely clear that any
   1.215 +such warranty, support, indemnity, or liability obligation is offered by
   1.216 +You alone, and You hereby agree to indemnify every Contributor for any
   1.217 +liability incurred by such Contributor as a result of warranty, support,
   1.218 +indemnity or liability terms You offer. You may include additional
   1.219 +disclaimers of warranty and limitations of liability specific to any
   1.220 +jurisdiction.
   1.221 +
   1.222 +4. Inability to Comply Due to Statute or Regulation
   1.223 +---------------------------------------------------
   1.224 +
   1.225 +If it is impossible for You to comply with any of the terms of this
   1.226 +License with respect to some or all of the Covered Software due to
   1.227 +statute, judicial order, or regulation then You must: (a) comply with
   1.228 +the terms of this License to the maximum extent possible; and (b)
   1.229 +describe the limitations and the code they affect. Such description must
   1.230 +be placed in a text file included with all distributions of the Covered
   1.231 +Software under this License. Except to the extent prohibited by statute
   1.232 +or regulation, such description must be sufficiently detailed for a
   1.233 +recipient of ordinary skill to be able to understand it.
   1.234 +
   1.235 +5. Termination
   1.236 +--------------
   1.237 +
   1.238 +5.1. The rights granted under this License will terminate automatically
   1.239 +if You fail to comply with any of its terms. However, if You become
   1.240 +compliant, then the rights granted under this License from a particular
   1.241 +Contributor are reinstated (a) provisionally, unless and until such
   1.242 +Contributor explicitly and finally terminates Your grants, and (b) on an
   1.243 +ongoing basis, if such Contributor fails to notify You of the
   1.244 +non-compliance by some reasonable means prior to 60 days after You have
   1.245 +come back into compliance. Moreover, Your grants from a particular
   1.246 +Contributor are reinstated on an ongoing basis if such Contributor
   1.247 +notifies You of the non-compliance by some reasonable means, this is the
   1.248 +first time You have received notice of non-compliance with this License
   1.249 +from such Contributor, and You become compliant prior to 30 days after
   1.250 +Your receipt of the notice.
   1.251 +
   1.252 +5.2. If You initiate litigation against any entity by asserting a patent
   1.253 +infringement claim (excluding declaratory judgment actions,
   1.254 +counter-claims, and cross-claims) alleging that a Contributor Version
   1.255 +directly or indirectly infringes any patent, then the rights granted to
   1.256 +You by any and all Contributors for the Covered Software under Section
   1.257 +2.1 of this License shall terminate.
   1.258 +
   1.259 +5.3. In the event of termination under Sections 5.1 or 5.2 above, all
   1.260 +end user license agreements (excluding distributors and resellers) which
   1.261 +have been validly granted by You or Your distributors under this License
   1.262 +prior to termination shall survive termination.
   1.263 +
   1.264 +************************************************************************
   1.265 +*                                                                      *
   1.266 +*  6. Disclaimer of Warranty                                           *
   1.267 +*  -------------------------                                           *
   1.268 +*                                                                      *
   1.269 +*  Covered Software is provided under this License on an "as is"       *
   1.270 +*  basis, without warranty of any kind, either expressed, implied, or  *
   1.271 +*  statutory, including, without limitation, warranties that the       *
   1.272 +*  Covered Software is free of defects, merchantable, fit for a        *
   1.273 +*  particular purpose or non-infringing. The entire risk as to the     *
   1.274 +*  quality and performance of the Covered Software is with You.        *
   1.275 +*  Should any Covered Software prove defective in any respect, You     *
   1.276 +*  (not any Contributor) assume the cost of any necessary servicing,   *
   1.277 +*  repair, or correction. This disclaimer of warranty constitutes an   *
   1.278 +*  essential part of this License. No use of any Covered Software is   *
   1.279 +*  authorized under this License except under this disclaimer.         *
   1.280 +*                                                                      *
   1.281 +************************************************************************
   1.282 +
   1.283 +************************************************************************
   1.284 +*                                                                      *
   1.285 +*  7. Limitation of Liability                                          *
   1.286 +*  --------------------------                                          *
   1.287 +*                                                                      *
   1.288 +*  Under no circumstances and under no legal theory, whether tort      *
   1.289 +*  (including negligence), contract, or otherwise, shall any           *
   1.290 +*  Contributor, or anyone who distributes Covered Software as          *
   1.291 +*  permitted above, be liable to You for any direct, indirect,         *
   1.292 +*  special, incidental, or consequential damages of any character      *
   1.293 +*  including, without limitation, damages for lost profits, loss of    *
   1.294 +*  goodwill, work stoppage, computer failure or malfunction, or any    *
   1.295 +*  and all other commercial damages or losses, even if such party      *
   1.296 +*  shall have been informed of the possibility of such damages. This   *
   1.297 +*  limitation of liability shall not apply to liability for death or   *
   1.298 +*  personal injury resulting from such party's negligence to the       *
   1.299 +*  extent applicable law prohibits such limitation. Some               *
   1.300 +*  jurisdictions do not allow the exclusion or limitation of           *
   1.301 +*  incidental or consequential damages, so this exclusion and          *
   1.302 +*  limitation may not apply to You.                                    *
   1.303 +*                                                                      *
   1.304 +************************************************************************
   1.305 +
   1.306 +8. Litigation
   1.307 +-------------
   1.308 +
   1.309 +Any litigation relating to this License may be brought only in the
   1.310 +courts of a jurisdiction where the defendant maintains its principal
   1.311 +place of business and such litigation shall be governed by laws of that
   1.312 +jurisdiction, without reference to its conflict-of-law provisions.
   1.313 +Nothing in this Section shall prevent a party's ability to bring
   1.314 +cross-claims or counter-claims.
   1.315 +
   1.316 +9. Miscellaneous
   1.317 +----------------
   1.318 +
   1.319 +This License represents the complete agreement concerning the subject
   1.320 +matter hereof. If any provision of this License is held to be
   1.321 +unenforceable, such provision shall be reformed only to the extent
   1.322 +necessary to make it enforceable. Any law or regulation which provides
   1.323 +that the language of a contract shall be construed against the drafter
   1.324 +shall not be used to construe this License against a Contributor.
   1.325 +
   1.326 +10. Versions of the License
   1.327 +---------------------------
   1.328 +
   1.329 +10.1. New Versions
   1.330 +
   1.331 +Mozilla Foundation is the license steward. Except as provided in Section
   1.332 +10.3, no one other than the license steward has the right to modify or
   1.333 +publish new versions of this License. Each version will be given a
   1.334 +distinguishing version number.
   1.335 +
   1.336 +10.2. Effect of New Versions
   1.337 +
   1.338 +You may distribute the Covered Software under the terms of the version
   1.339 +of the License under which You originally received the Covered Software,
   1.340 +or under the terms of any subsequent version published by the license
   1.341 +steward.
   1.342 +
   1.343 +10.3. Modified Versions
   1.344 +
   1.345 +If you create software not governed by this License, and you want to
   1.346 +create a new license for such software, you may create and use a
   1.347 +modified version of this License if you rename the license and remove
   1.348 +any references to the name of the license steward (except to note that
   1.349 +such modified license differs from this License).
   1.350 +
   1.351 +10.4. Distributing Source Code Form that is Incompatible With Secondary
   1.352 +Licenses
   1.353 +
   1.354 +If You choose to distribute Source Code Form that is Incompatible With
   1.355 +Secondary Licenses under the terms of this version of the License, the
   1.356 +notice described in Exhibit B of this License must be attached.
   1.357 +
   1.358 +Exhibit A - Source Code Form License Notice
   1.359 +-------------------------------------------
   1.360 +
   1.361 +  This Source Code Form is subject to the terms of the Mozilla Public
   1.362 +  License, v. 2.0. If a copy of the MPL was not distributed with this
   1.363 +  file, You can obtain one at http://mozilla.org/MPL/2.0/.
   1.364 +
   1.365 +If it is not possible or desirable to put the notice in a particular
   1.366 +file, then You may include the notice in a location (such as a LICENSE
   1.367 +file in a relevant directory) where a recipient would be likely to look
   1.368 +for such a notice.
   1.369 +
   1.370 +You may add additional accurate notices of copyright ownership.
   1.371 +
   1.372 +Exhibit B - "Incompatible With Secondary Licenses" Notice
   1.373 +---------------------------------------------------------
   1.374 +
   1.375 +  This Source Code Form is "Incompatible With Secondary Licenses", as
   1.376 +  defined by the Mozilla Public License, v. 2.0.
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Makefile	Sun Feb 19 00:20:26 2017 +0100
     2.3 @@ -0,0 +1,63 @@
     2.4 +#
     2.5 +# Copyright (C) 2017 Guido Berhoerster <guido+tab-mover@berhoerster.name>
     2.6 +#
     2.7 +# Permission is hereby granted, free of charge, to any person obtaining
     2.8 +# a copy of this software and associated documentation files (the
     2.9 +# "Software"), to deal in the Software without restriction, including
    2.10 +# without limitation the rights to use, copy, modify, merge, publish,
    2.11 +# distribute, sublicense, and/or sell copies of the Software, and to
    2.12 +# permit persons to whom the Software is furnished to do so, subject to
    2.13 +# the following conditions:
    2.14 +#
    2.15 +# The above copyright notice and this permission notice shall be included
    2.16 +# in all copies or substantial portions of the Software.
    2.17 +#
    2.18 +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    2.19 +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    2.20 +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    2.21 +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    2.22 +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    2.23 +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    2.24 +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    2.25 +#
    2.26 +
    2.27 +NAME =		tab-mover
    2.28 +VERSION =	1
    2.29 +EXT_NAME =	$(subst -,_,$(NAME))-$(VERSION)
    2.30 +
    2.31 +INKSCAPE := inkscape
    2.32 +INFOZIP := zip
    2.33 +
    2.34 +BITMAP_ICONS =	icons/tab-mover-48.png \
    2.35 +		icons/tab-mover-96.png
    2.36 +DIST_FILES =	manifest.json \
    2.37 +		background.js \
    2.38 +		COPYING \
    2.39 +		NEWS \
    2.40 +		README \
    2.41 +		$(wildcard _locales/*/messages.json) \
    2.42 +		$(BITMAP_ICONS)
    2.43 +
    2.44 +.DEFAULT_TARGET = all
    2.45 +
    2.46 +.PHONY: all extension clean clobber
    2.47 +
    2.48 +all: extension
    2.49 +
    2.50 +extension: $(EXT_NAME).zip
    2.51 +
    2.52 +$(EXT_NAME).zip: $(DIST_FILES)
    2.53 +	$(INFOZIP) $@ $^
    2.54 +
    2.55 +define generate-icon-rule
    2.56 +$1: $(1:%-$(lastword $(subst -, ,$1))=%.svg)
    2.57 +	size=$(lastword $(subst -, ,$(basename $1))); \
    2.58 +	    $(INKSCAPE) -w $$$${size} -h $$$${size} -e $$@ $$<
    2.59 +endef
    2.60 +
    2.61 +$(foreach icon,$(BITMAP_ICONS),$(eval $(call generate-icon-rule,$(icon))))
    2.62 +
    2.63 +clean:
    2.64 +	-rm -f $(BITMAP_ICONS)
    2.65 +
    2.66 +clobber: clean
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/NEWS	Sun Feb 19 00:20:26 2017 +0100
     3.3 @@ -0,0 +1,2 @@
     3.4 +News
     3.5 +====
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/README	Sun Feb 19 00:20:26 2017 +0100
     4.3 @@ -0,0 +1,48 @@
     4.4 +Tab Mover
     4.5 +=========
     4.6 +
     4.7 +Tab Mover is a Firefox Addon for quickly moving tabs between windows via the
     4.8 +page context menu.
     4.9 +
    4.10 +Usage
    4.11 +-----
    4.12 +
    4.13 +In order to move a tab between windows, open the tab context menu by clicking
    4.14 +on the tab using the right mouse button, then open the submenu named
    4.15 +"Tab Mover", and finally select a window from the submenu named "Move to
    4.16 +Window".
    4.17 +
    4.18 +In order to reopen a tab from a window in incognito mode in a normal window,
    4.19 +open the tab context menu by clicking the tab using the right mouse button,
    4.20 +then open the submenu named "Tab Mover", and finally select a window from the
    4.21 +submenu named "Reopen in Window".
    4.22 +
    4.23 +When using Firefox version 52 or earlier the "Tab Mover" submenu is in the
    4.24 +page context menu which can be opened by clicking anywhere on a page using the
    4.25 +right mouse button.
    4.26 +
    4.27 +Contact
    4.28 +-------
    4.29 +
    4.30 +Please send any feedback, translations or bug reports via email to
    4.31 +<guido+tab-mover@berhoerster.name>
    4.32 +
    4.33 +Bug Reports
    4.34 +-----------
    4.35 +
    4.36 +When sending bug reports, please always mention the exact version of the script
    4.37 +with which the issue occurs as well as the version of vim and the operating
    4.38 +system you are using and make sure that you provide sufficient information to
    4.39 +reproduce the issue and include any input, output, and any error messages.
    4.40 +
    4.41 +License
    4.42 +-------
    4.43 +
    4.44 +Except otherwise noted, all files are Copyright (C) 2017 Guido Berhoerster and
    4.45 +distributed under the following license terms:
    4.46 +
    4.47 +Copyright (C) 2017 Guido Berhoerster <guido+tab-mover@berhoerster.name>
    4.48 +
    4.49 +This Source Code Form is subject to the terms of the Mozilla Public
    4.50 +License, v. 2.0. If a copy of the MPL was not distributed with this
    4.51 +file, You can obtain one at http://mozilla.org/MPL/2.0/.
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/_locales/en/messages.json	Sun Feb 19 00:20:26 2017 +0100
     5.3 @@ -0,0 +1,58 @@
     5.4 +{
     5.5 +    "extensionName": {
     5.6 +        "message": "Tab Mover",
     5.7 +        "description": "Name of the extension."
     5.8 +    },
     5.9 +    "extensionDescription": {
    5.10 +        "message": "Move tabs between windows via context menu.",
    5.11 +        "description": "Description of the extension."
    5.12 +    },
    5.13 +    "moveToWindowMenu": {
    5.14 +        "message": "Move to Window",
    5.15 +        "description": "Label of the submenu for selecting a window to which the current tab should be moved to."
    5.16 +    },
    5.17 +    "reopenInWindowMenu": {
    5.18 +        "message": "Reopen in Window",
    5.19 +        "description": "Label of the submenu for selecting a window in which the current tab should be reopened in."
    5.20 +    },
    5.21 +    "defaultWindowTitle": {
    5.22 +        "message": "Window $id$",
    5.23 +        "description": "Default title for windows.",
    5.24 +        "placeholders": {
    5.25 +            "id": {
    5.26 +                "content": "$1",
    5.27 +                "example": "0"
    5.28 +            }
    5.29 +        }
    5.30 +    },
    5.31 +    "defaultIncognitoWindowTitle": {
    5.32 +        "message": "Window $id$ (Private Browsing)",
    5.33 +        "description": "Default title for windows in incognito-mode.",
    5.34 +        "placeholders": {
    5.35 +            "id": {
    5.36 +                "content": "$1",
    5.37 +                "example": "0"
    5.38 +            }
    5.39 +        }
    5.40 +    },
    5.41 +    "windowTitle": {
    5.42 +        "message": "$title$",
    5.43 +        "description": "Title for windows.",
    5.44 +        "placeholders": {
    5.45 +            "title": {
    5.46 +                "content": "$1",
    5.47 +                "example": "Download Firefox — Free Web Browser — Mozilla"
    5.48 +            }
    5.49 +        }
    5.50 +    },
    5.51 +    "incognitoWindowTitle": {
    5.52 +        "message": "$title$ (Private Browsing)",
    5.53 +        "description": "Title for windows in incognito-mode.",
    5.54 +        "placeholders": {
    5.55 +            "title": {
    5.56 +                "content": "$1",
    5.57 +                "example": "Download Firefox — Free Web Browser — Mozilla"
    5.58 +            }
    5.59 +        }
    5.60 +    }
    5.61 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/background.js	Sun Feb 19 00:20:26 2017 +0100
     6.3 @@ -0,0 +1,398 @@
     6.4 +/*
     6.5 + * Copyright (C) 2017 Guido Berhoerster <guido+tab-mover@berhoerster.name>
     6.6 + *
     6.7 + * This Source Code Form is subject to the terms of the Mozilla Public
     6.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     6.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    6.10 + */
    6.11 +
    6.12 +'use strict';
    6.13 +
    6.14 +function createContextMenuItem(createProperties) {
    6.15 +    return new Promise((resolve, reject) => {
    6.16 +        browser.contextMenus.create(createProperties, () => {
    6.17 +            if (browser.runtime.lastError) {
    6.18 +                reject(browser.runtime.lastError);
    6.19 +            } else {
    6.20 +                resolve();
    6.21 +            }
    6.22 +        });
    6.23 +    });
    6.24 +}
    6.25 +
    6.26 +const Observable = (superclass) => class extends superclass {
    6.27 +    constructor(...args) {
    6.28 +        super(...args);
    6.29 +
    6.30 +        this._observers = new Map();
    6.31 +    }
    6.32 +
    6.33 +    addObserver(eventName, observer, thisArg) {
    6.34 +        if (!this._observers.has(eventName)) {
    6.35 +            this._observers.set(eventName, new Set());
    6.36 +        }
    6.37 +
    6.38 +        this._observers.get(eventName).add(observer);
    6.39 +    }
    6.40 +
    6.41 +    deleteObserver(eventName, observer) {
    6.42 +        if (this._observers.has(eventName)) {
    6.43 +            this._observers.get(eventName).delete(observer);
    6.44 +        }
    6.45 +    }
    6.46 +
    6.47 +    notifyObservers(eventName, ...args) {
    6.48 +        if (!this._observers.has(eventName)) {
    6.49 +            return;
    6.50 +        }
    6.51 +
    6.52 +        for (let observer of this._observers.get(eventName)) {
    6.53 +            observer(eventName, ...args);
    6.54 +        }
    6.55 +    }
    6.56 +}
    6.57 +
    6.58 +class WindowsModel extends Observable(Object) {
    6.59 +    constructor() {
    6.60 +        super();
    6.61 +
    6.62 +        this.windows = new Map();
    6.63 +        this.focusedWindowId = browser.windows.WINDOW_ID_NONE;
    6.64 +    }
    6.65 +
    6.66 +    hasWindow(id) {
    6.67 +        return this.windows.has(id);
    6.68 +    }
    6.69 +
    6.70 +    getWindow(id) {
    6.71 +        return this.windows.get(id);
    6.72 +    }
    6.73 +
    6.74 +    getAllWindows() {
    6.75 +        return this.windows.values();
    6.76 +    }
    6.77 +
    6.78 +    getfocusedWindowId() {
    6.79 +        return this.focusedWindowId;
    6.80 +    }
    6.81 +
    6.82 +    openWindow(id, incognito = false) {
    6.83 +        this.windows.set(id, {
    6.84 +            id,
    6.85 +            title: browser.i18n.getMessage(incognito ?
    6.86 +                'defaultIncognitoWindowTitle' : 'defaultWindowTitle', id),
    6.87 +            incognito
    6.88 +        });
    6.89 +
    6.90 +        this.notifyObservers('window-opened', id);
    6.91 +    }
    6.92 +
    6.93 +    updateWindowTitle(id, title) {
    6.94 +        if (!this.windows.has(id)) {
    6.95 +            return;
    6.96 +        }
    6.97 +
    6.98 +        let windowInfo = this.windows.get(id)
    6.99 +        windowInfo.title = browser.i18n.getMessage(windowInfo.incognito ?
   6.100 +            'incognitoWindowTitle' : 'windowTitle', title);
   6.101 +
   6.102 +        this.notifyObservers('window-title-updated', id, title);
   6.103 +    }
   6.104 +
   6.105 +    focusWindow(id) {
   6.106 +        let oldId = this.focusedWindowId;
   6.107 +        this.focusedWindowId = this.windows.has(id) ? id :
   6.108 +            browser.windows.WINDOW_ID_NONE;
   6.109 +
   6.110 +        this.notifyObservers('window-focus-changed', oldId, id);
   6.111 +    }
   6.112 +
   6.113 +    closeWindow(id) {
   6.114 +        if (!this.windows.has(id)) {
   6.115 +            return;
   6.116 +        }
   6.117 +
   6.118 +        this.windows.delete(id);
   6.119 +
   6.120 +        if (id === this.focusedWindowId) {
   6.121 +            this.focusedWindowId = browser.windows.WINDOW_ID_NONE;
   6.122 +        }
   6.123 +
   6.124 +        this.notifyObservers('window-closed', id);
   6.125 +    }
   6.126 +}
   6.127 +
   6.128 +class MenuView {
   6.129 +    constructor(model) {
   6.130 +        this.model = model;
   6.131 +        this.moveMenuIds = new Set();
   6.132 +        this.reopenMenuIds = new Set();
   6.133 +        this.menuContexts = ['tab'];
   6.134 +
   6.135 +        browser.runtime.getBrowserInfo().then(browserInfo => {
   6.136 +            // Firefox before version 53 does not support tab context menus
   6.137 +            let majorVersion = browserInfo.version.match(/^\d+/);
   6.138 +            if (majorVersion !== null && majorVersion < 53) {
   6.139 +                this.menuContexts = ['all'];
   6.140 +            }
   6.141 +
   6.142 +            return Promise.all([
   6.143 +                // create submenus
   6.144 +                createContextMenuItem({
   6.145 +                    id: 'move-menu',
   6.146 +                    title: browser.i18n.getMessage('moveToWindowMenu'),
   6.147 +                    enabled: false,
   6.148 +                    contexts: this.menuContexts
   6.149 +                }),
   6.150 +                createContextMenuItem({
   6.151 +                    id: 'reopen-menu',
   6.152 +                    title: browser.i18n.getMessage('reopenInWindowMenu'),
   6.153 +                    enabled: false,
   6.154 +                    contexts: this.menuContexts
   6.155 +                })
   6.156 +            ]);
   6.157 +        }).then(values => {
   6.158 +            this.model.addObserver('window-opened',
   6.159 +                this.onWindowOpened.bind(this));
   6.160 +            this.model.addObserver('window-title-updated',
   6.161 +                this.onWindowTitleUpdated.bind(this));
   6.162 +            this.model.addObserver('window-focus-changed',
   6.163 +                this.onWindowFocusChanged.bind(this));
   6.164 +            this.model.addObserver('window-closed',
   6.165 +                this.onWindowClosed.bind(this));
   6.166 +        }).catch(error => {
   6.167 +            console.log('Error:', error);
   6.168 +        });
   6.169 +    }
   6.170 +
   6.171 +    enableMenus() {
   6.172 +        return Promise.all([
   6.173 +            browser.contextMenus.update('move-menu', {
   6.174 +                enabled: this.moveMenuIds.size > 0
   6.175 +            }),
   6.176 +            browser.contextMenus.update('reopen-menu', {
   6.177 +                enabled: this.reopenMenuIds.size > 0
   6.178 +            })
   6.179 +        ]);
   6.180 +    }
   6.181 +
   6.182 +    onWindowOpened(eventName, windowId) {
   6.183 +        let focusedWindowId = this.model.getfocusedWindowId();
   6.184 +        if (focusedWindowId === browser.windows.WINDOW_ID_NONE) {
   6.185 +            return;
   6.186 +        }
   6.187 +
   6.188 +        let menuId = String(windowId);
   6.189 +        let windowInfo = this.model.getWindow(windowId);
   6.190 +        let incognito = this.model.getWindow(focusedWindowId).incognito;
   6.191 +
   6.192 +        if (incognito && !windowInfo.incognito) {
   6.193 +            this.reopenMenuIds.add(menuId);
   6.194 +        } else {
   6.195 +            this.moveMenuIds.add(menuId);
   6.196 +        }
   6.197 +
   6.198 +        createContextMenuItem({
   6.199 +            id: menuId,
   6.200 +            title: windowInfo.title,
   6.201 +            contexts: this.menuContexts,
   6.202 +            parentId: (incognito && !windowInfo.incognito) ?
   6.203 +                'reopen-menu' : 'move-menu'
   6.204 +        }).then(() => {
   6.205 +            return this.enableMenus();
   6.206 +        }).catch(error => {
   6.207 +            console.log('Error:', error);
   6.208 +        });
   6.209 +    }
   6.210 +
   6.211 +    onWindowTitleUpdated(eventName, windowId, title) {
   6.212 +        if (this.model.getfocusedWindowId() ===
   6.213 +            browser.windows.WINDOW_ID_NONE) {
   6.214 +            return;
   6.215 +        }
   6.216 +
   6.217 +        browser.contextMenus.update(String(windowId), {title}).catch(error => {
   6.218 +            console.log('Error:', error);
   6.219 +        });
   6.220 +    }
   6.221 +
   6.222 +    onWindowFocusChanged(eventName, oldWindowId, newWindowId) {
   6.223 +        let promises = [
   6.224 +            // disable submenus
   6.225 +            browser.contextMenus.update('move-menu', {
   6.226 +                enabled: false
   6.227 +            }),
   6.228 +            browser.contextMenus.update('reopen-menu', {
   6.229 +                enabled: false
   6.230 +            })
   6.231 +        ];
   6.232 +
   6.233 +        if (newWindowId === browser.windows.WINDOW_ID_NONE) {
   6.234 +            // just disable the submenus if focus moved to a window not tracked
   6.235 +            Promise.all(promises).catch(error => {
   6.236 +                console.log('Error:', error);
   6.237 +            });
   6.238 +            return;
   6.239 +        }
   6.240 +
   6.241 +        Promise.all(promises).then(values => {
   6.242 +            // remove all submenu items
   6.243 +            let promises = new Array(...this.moveMenuIds,
   6.244 +                ...this.reopenMenuIds).map(menuId => {
   6.245 +                this.moveMenuIds.delete(menuId) ||
   6.246 +                    this.reopenMenuIds.delete(menuId);
   6.247 +
   6.248 +                return browser.contextMenus.remove(menuId);
   6.249 +            });
   6.250 +
   6.251 +            return Promise.all(promises);
   6.252 +        }).then(values => {
   6.253 +            let incognito = this.model.getWindow(newWindowId).incognito;
   6.254 +
   6.255 +            // rebuild submenus
   6.256 +            let promises = [];
   6.257 +            for (let windowInfo of this.model.getAllWindows()) {
   6.258 +                if (windowInfo.id === newWindowId) {
   6.259 +                    // skip the currently focused window
   6.260 +                    continue;
   6.261 +                }
   6.262 +
   6.263 +                let menuId = String(windowInfo.id);
   6.264 +                if (incognito && !windowInfo.incognito) {
   6.265 +                    this.reopenMenuIds.add(menuId);
   6.266 +                } else {
   6.267 +                    this.moveMenuIds.add(menuId);
   6.268 +                }
   6.269 +
   6.270 +                // create menu item
   6.271 +                promises.push(createContextMenuItem({
   6.272 +                    id: menuId,
   6.273 +                    title: windowInfo.title,
   6.274 +                    contexts: this.menuContexts,
   6.275 +                    parentId: (incognito && !windowInfo.incognito) ?
   6.276 +                        'reopen-menu' : 'move-menu'
   6.277 +                }));
   6.278 +            }
   6.279 +
   6.280 +            return Promise.all(promises);
   6.281 +        }).then(values => {
   6.282 +            return this.enableMenus();
   6.283 +        }).catch(error => {
   6.284 +            console.log('Error:', error);
   6.285 +        });
   6.286 +    }
   6.287 +
   6.288 +    onWindowClosed(eventName, windowId) {
   6.289 +        if (this.model.getfocusedWindowId() ===
   6.290 +            browser.windows.WINDOW_ID_NONE) {
   6.291 +            return;
   6.292 +        }
   6.293 +
   6.294 +        let menuId = String(windowId);
   6.295 +
   6.296 +        this.moveMenuIds.delete(menuId) || this.reopenMenuIds.delete(menuId);
   6.297 +
   6.298 +        browser.contextMenus.remove(menuId).then(() => {
   6.299 +            return this.enableMenus();
   6.300 +        }).catch(error => {
   6.301 +            console.log('Error:', error);
   6.302 +        });
   6.303 +    }
   6.304 +}
   6.305 +
   6.306 +class Presenter {
   6.307 +    constructor(model, view) {
   6.308 +        this.model = model;
   6.309 +        this.view = view;
   6.310 +
   6.311 +        browser.windows.getAll({windowTypes: ['normal']}).then(windows => {
   6.312 +            // populate model with existing windows
   6.313 +            for (let windowInfo of windows) {
   6.314 +                this.onWindowCreated(windowInfo);
   6.315 +
   6.316 +                if (windowInfo.focused) {
   6.317 +                    this.onWindowFocusChanged(windowInfo.id);
   6.318 +                }
   6.319 +            }
   6.320 +
   6.321 +            browser.windows.onCreated
   6.322 +                .addListener(this.onWindowCreated.bind(this));
   6.323 +            browser.windows.onRemoved
   6.324 +                .addListener(this.onWindowRemoved.bind(this));
   6.325 +            browser.windows.onFocusChanged
   6.326 +                .addListener(this.onWindowFocusChanged.bind(this));
   6.327 +            browser.contextMenus.onClicked
   6.328 +                .addListener(this.onMenuItemClicked.bind(this));
   6.329 +        }).catch(error => {
   6.330 +            console.log('Error:', error);
   6.331 +        });
   6.332 +    }
   6.333 +
   6.334 +    onWindowCreated(windowInfo) {
   6.335 +        // only track normal windows
   6.336 +        if (windowInfo.type !== 'normal') {
   6.337 +            return;
   6.338 +        }
   6.339 +
   6.340 +        this.model.openWindow(windowInfo.id, windowInfo.incognito);
   6.341 +
   6.342 +        // get the window title and update the model
   6.343 +        browser.tabs.query({
   6.344 +            active: true,
   6.345 +            windowId: windowInfo.id
   6.346 +        }).then(tabs => {
   6.347 +            this.model.updateWindowTitle(tabs[0].windowId, tabs[0].title)
   6.348 +        }).catch(error => {
   6.349 +            console.log('Error:', error);
   6.350 +        });
   6.351 +    }
   6.352 +
   6.353 +    onWindowRemoved(windowId) {
   6.354 +        this.model.closeWindow(windowId);
   6.355 +    }
   6.356 +
   6.357 +    onWindowFocusChanged(windowId) {
   6.358 +        let prevFocusedWindowId = this.model.getfocusedWindowId();
   6.359 +        if (prevFocusedWindowId !== browser.windows.WINDOW_ID_NONE) {
   6.360 +            // get title of the previously focused window and update the model
   6.361 +            browser.tabs.query({
   6.362 +                active: true,
   6.363 +                windowId: prevFocusedWindowId
   6.364 +            }).then(tabs => {
   6.365 +                this.model.updateWindowTitle(tabs[0].windowId, tabs[0].title)
   6.366 +            }).catch(error => {
   6.367 +                console.log('Error:', error);
   6.368 +            });
   6.369 +        }
   6.370 +
   6.371 +        this.model.focusWindow(windowId);
   6.372 +    }
   6.373 +
   6.374 +    onMenuItemClicked(info, tab) {
   6.375 +        if (info.parentMenuItemId === 'move-menu') {
   6.376 +            // move tab from the current window to the selected window
   6.377 +            browser.tabs.move(tab.id, {
   6.378 +                windowId: parseInt(info.menuItemId),
   6.379 +                index: -1
   6.380 +            }).catch(error => {
   6.381 +                console.log('Error:', error);
   6.382 +            });
   6.383 +        } else {
   6.384 +            // open the URL of the current tab in the selected window and close
   6.385 +            // the current tab
   6.386 +            browser.tabs.create({
   6.387 +                url: tab.url,
   6.388 +                windowId: parseInt(info.menuItemId),
   6.389 +                index: -1
   6.390 +            }).then(newTab => {
   6.391 +                return browser.tabs.remove(tab.id);
   6.392 +            }).catch(error => {
   6.393 +                console.log('Error:', error);
   6.394 +            });
   6.395 +        }
   6.396 +    }
   6.397 +}
   6.398 +
   6.399 +let windowsModel = new WindowsModel();
   6.400 +let menuView = new MenuView(windowsModel);
   6.401 +let presenter = new Presenter(windowsModel, menuView);
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/icons/tab-mover.svg	Sun Feb 19 00:20:26 2017 +0100
     7.3 @@ -0,0 +1,243 @@
     7.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
     7.5 +<!-- Created with Inkscape (http://www.inkscape.org/) -->
     7.6 +
     7.7 +<svg
     7.8 +   xmlns:dc="http://purl.org/dc/elements/1.1/"
     7.9 +   xmlns:cc="http://creativecommons.org/ns#"
    7.10 +   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    7.11 +   xmlns:svg="http://www.w3.org/2000/svg"
    7.12 +   xmlns="http://www.w3.org/2000/svg"
    7.13 +   xmlns:xlink="http://www.w3.org/1999/xlink"
    7.14 +   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    7.15 +   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
    7.16 +   width="48"
    7.17 +   height="48"
    7.18 +   viewBox="0 0 48 48.000001"
    7.19 +   id="svg4199"
    7.20 +   version="1.1"
    7.21 +   inkscape:version="0.91 r13725"
    7.22 +   sodipodi:docname="tab-mover.svg">
    7.23 +  <title
    7.24 +     id="title6440">Tab Mover</title>
    7.25 +  <defs
    7.26 +     id="defs4201">
    7.27 +    <linearGradient
    7.28 +       inkscape:collect="always"
    7.29 +       id="linearGradient5694">
    7.30 +      <stop
    7.31 +         style="stop-color:#3465a4;stop-opacity:0"
    7.32 +         offset="0"
    7.33 +         id="stop5696" />
    7.34 +      <stop
    7.35 +         id="stop5702"
    7.36 +         offset="0.24956821"
    7.37 +         style="stop-color:#3465a4;stop-opacity:1" />
    7.38 +      <stop
    7.39 +         style="stop-color:#3465a4;stop-opacity:1"
    7.40 +         offset="1"
    7.41 +         id="stop5698" />
    7.42 +    </linearGradient>
    7.43 +    <linearGradient
    7.44 +       inkscape:collect="always"
    7.45 +       id="linearGradient5684">
    7.46 +      <stop
    7.47 +         style="stop-color:#eeeeec;stop-opacity:0"
    7.48 +         offset="0"
    7.49 +         id="stop5686" />
    7.50 +      <stop
    7.51 +         id="stop5692"
    7.52 +         offset="0.25649694"
    7.53 +         style="stop-color:#eeeeec;stop-opacity:1" />
    7.54 +      <stop
    7.55 +         style="stop-color:#eeeeec;stop-opacity:1"
    7.56 +         offset="1"
    7.57 +         id="stop5688" />
    7.58 +    </linearGradient>
    7.59 +    <linearGradient
    7.60 +       inkscape:collect="always"
    7.61 +       id="linearGradient5674">
    7.62 +      <stop
    7.63 +         style="stop-color:#204a87;stop-opacity:0"
    7.64 +         offset="0"
    7.65 +         id="stop5676" />
    7.66 +      <stop
    7.67 +         id="stop5682"
    7.68 +         offset="0.24120744"
    7.69 +         style="stop-color:#204a87;stop-opacity:1" />
    7.70 +      <stop
    7.71 +         style="stop-color:#204a87;stop-opacity:1"
    7.72 +         offset="1"
    7.73 +         id="stop5678" />
    7.74 +    </linearGradient>
    7.75 +    <linearGradient
    7.76 +       inkscape:collect="always"
    7.77 +       xlink:href="#linearGradient5694"
    7.78 +       id="linearGradient5731"
    7.79 +       gradientUnits="userSpaceOnUse"
    7.80 +       x1="8"
    7.81 +       y1="1059.3622"
    7.82 +       x2="32.041523"
    7.83 +       y2="1059.3622" />
    7.84 +    <linearGradient
    7.85 +       inkscape:collect="always"
    7.86 +       xlink:href="#linearGradient5684"
    7.87 +       id="linearGradient5733"
    7.88 +       gradientUnits="userSpaceOnUse"
    7.89 +       x1="8"
    7.90 +       y1="1059.3622"
    7.91 +       x2="31.392092"
    7.92 +       y2="1059.3622" />
    7.93 +    <linearGradient
    7.94 +       inkscape:collect="always"
    7.95 +       xlink:href="#linearGradient5674"
    7.96 +       id="linearGradient5735"
    7.97 +       gradientUnits="userSpaceOnUse"
    7.98 +       x1="8"
    7.99 +       y1="1059.3622"
   7.100 +       x2="32.874856"
   7.101 +       y2="1059.3622" />
   7.102 +  </defs>
   7.103 +  <sodipodi:namedview
   7.104 +     id="base"
   7.105 +     pagecolor="#ffffff"
   7.106 +     bordercolor="#666666"
   7.107 +     borderopacity="1.0"
   7.108 +     inkscape:pageopacity="0.0"
   7.109 +     inkscape:pageshadow="2"
   7.110 +     inkscape:zoom="16"
   7.111 +     inkscape:cx="22.032573"
   7.112 +     inkscape:cy="21.805001"
   7.113 +     inkscape:document-units="px"
   7.114 +     inkscape:current-layer="layer1"
   7.115 +     showgrid="true"
   7.116 +     units="px"
   7.117 +     inkscape:window-width="1920"
   7.118 +     inkscape:window-height="1021"
   7.119 +     inkscape:window-x="0"
   7.120 +     inkscape:window-y="0"
   7.121 +     inkscape:window-maximized="1"
   7.122 +     showguides="false">
   7.123 +    <inkscape:grid
   7.124 +       type="xygrid"
   7.125 +       id="grid4747" />
   7.126 +  </sodipodi:namedview>
   7.127 +  <metadata
   7.128 +     id="metadata4204">
   7.129 +    <rdf:RDF>
   7.130 +      <cc:Work
   7.131 +         rdf:about="">
   7.132 +        <dc:format>image/svg+xml</dc:format>
   7.133 +        <dc:type
   7.134 +           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
   7.135 +        <dc:title>Tab Mover</dc:title>
   7.136 +        <cc:license
   7.137 +           rdf:resource="http://mozilla.org/MPL/2.0/" />
   7.138 +        <dc:creator>
   7.139 +          <cc:Agent>
   7.140 +            <dc:title>Guido Berhoerster</dc:title>
   7.141 +          </cc:Agent>
   7.142 +        </dc:creator>
   7.143 +      </cc:Work>
   7.144 +    </rdf:RDF>
   7.145 +  </metadata>
   7.146 +  <g
   7.147 +     inkscape:label="Layer 1"
   7.148 +     inkscape:groupmode="layer"
   7.149 +     id="layer1"
   7.150 +     transform="translate(0,-1004.3622)">
   7.151 +    <g
   7.152 +       id="g4828"
   7.153 +       transform="translate(2,0)">
   7.154 +      <rect
   7.155 +         ry="2"
   7.156 +         rx="2"
   7.157 +         y="1008.8622"
   7.158 +         x="11.5"
   7.159 +         height="32"
   7.160 +         width="32"
   7.161 +         id="rect4821"
   7.162 +         style="opacity:1;fill:#d3d7cf;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.2;stroke-opacity:1" />
   7.163 +      <rect
   7.164 +         y="1009.1122"
   7.165 +         x="11.75"
   7.166 +         height="7.25"
   7.167 +         width="31.5"
   7.168 +         id="rect4819"
   7.169 +         style="opacity:1;fill:#204a87;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.2;stroke-opacity:1" />
   7.170 +      <rect
   7.171 +         style="opacity:1;fill:none;fill-opacity:1;stroke:#555753;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.2;stroke-opacity:1"
   7.172 +         id="rect4808"
   7.173 +         width="32"
   7.174 +         height="32"
   7.175 +         x="11.5"
   7.176 +         y="1008.8622"
   7.177 +         rx="2"
   7.178 +         ry="2" />
   7.179 +      <path
   7.180 +         d="m 13.5,1009.7988 c -0.604856,0 -1.0625,0.4577 -1.0625,1.0625 l 0,28 c 0,0.6049 0.457644,1.0625 1.0625,1.0625 l 28,0 c 0.604856,0 1.0625,-0.4576 1.0625,-1.0625 l 0,-28 c 0,-0.6048 -0.457644,-1.0625 -1.0625,-1.0625 l -28,0 z"
   7.181 +         id="path5503"
   7.182 +         style="opacity:1;fill:none;fill-opacity:1;stroke:#e7e7e5;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.2;stroke-opacity:1"
   7.183 +         inkscape:original="M 13.5 1008.8613 C 12.392 1008.8613 11.5 1009.7533 11.5 1010.8613 L 11.5 1038.8613 C 11.5 1039.9693 12.392 1040.8613 13.5 1040.8613 L 41.5 1040.8613 C 42.608 1040.8613 43.5 1039.9693 43.5 1038.8613 L 43.5 1010.8613 C 43.5 1009.7533 42.608 1008.8613 41.5 1008.8613 L 13.5 1008.8613 z "
   7.184 +         inkscape:radius="-0.93747187"
   7.185 +         sodipodi:type="inkscape:offset" />
   7.186 +      <rect
   7.187 +         ry="2"
   7.188 +         rx="2"
   7.189 +         y="1008.8622"
   7.190 +         x="11.5"
   7.191 +         height="32"
   7.192 +         width="32"
   7.193 +         id="rect5497"
   7.194 +         style="opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.2;stroke-opacity:1" />
   7.195 +    </g>
   7.196 +    <g
   7.197 +       id="g5737">
   7.198 +      <path
   7.199 +         style="opacity:1;fill:#d3d7cf;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.2;stroke-opacity:1"
   7.200 +         d="m 8.5,1023.8622 6,0 c 1,0 2,1 2,2 l 0,2 10,0 c 1.108,0 2,0.892 2,2 l 0,16 c 0,1.108 -0.892,2 -2,2 l -22,0 c -1.108,0 -2,-0.892 -2,-2 l 0,-16 c 0,-0.9428 1,-2 2,-2 l 2,0 0,-2 c 0,-1.108 0.892,-2 2,-2 z"
   7.201 +         id="path5469"
   7.202 +         inkscape:connector-curvature="0"
   7.203 +         sodipodi:nodetypes="ssscsssssssccss" />
   7.204 +      <path
   7.205 +         transform="translate(0.5,-0.5)"
   7.206 +         d="m 8,1025.3613 c -0.5713123,0 -1,0.4287 -1,1 l 0,2 a 1.0000719,1.0000719 0 0 1 -1,1 l -2,0 c -0.1476099,0 -0.4368983,0.1182 -0.6621094,0.3477 C 3.1126795,1029.9385 3,1030.2435 3,1030.3613 l 0,16 c 0,0.5713 0.4286877,1 1,1 l 22,0 c 0.571312,0 1,-0.4287 1,-1 l 0,-16 c 0,-0.5713 -0.428688,-1 -1,-1 l -10,0 a 1.0000719,1.0000719 0 0 1 -1,-1 l 0,-2 c 0,-0.1666 -0.114162,-0.4501 -0.332031,-0.6679 -0.21787,-0.2179 -0.501293,-0.3321 -0.667969,-0.3321 l -6,0 z"
   7.207 +         id="path5507"
   7.208 +         style="opacity:1;fill:none;fill-opacity:1;stroke:#e7e7e5;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.2;stroke-opacity:1"
   7.209 +         inkscape:original="M 8 1024.3613 C 6.892 1024.3613 6 1025.2533 6 1026.3613 L 6 1028.3613 L 4 1028.3613 C 3 1028.3613 2 1029.4185 2 1030.3613 L 2 1046.3613 C 2 1047.4693 2.892 1048.3613 4 1048.3613 L 26 1048.3613 C 27.108 1048.3613 28 1047.4693 28 1046.3613 L 28 1030.3613 C 28 1029.2533 27.108 1028.3613 26 1028.3613 L 16 1028.3613 L 16 1026.3613 C 16 1025.3613 15 1024.3613 14 1024.3613 L 8 1024.3613 z "
   7.210 +         inkscape:radius="-0.99997187"
   7.211 +         sodipodi:type="inkscape:offset" />
   7.212 +      <path
   7.213 +         sodipodi:nodetypes="ssscsssssssccss"
   7.214 +         inkscape:connector-curvature="0"
   7.215 +         id="rect4806"
   7.216 +         d="m 8.5,1023.8622 6,0 c 1,0 2,1 2,2 l 0,2 10,0 c 1.108,0 2,0.892 2,2 l 0,16 c 0,1.108 -0.892,2 -2,2 l -22,0 c -1.108,0 -2,-0.892 -2,-2 l 0,-16 c 0,-0.9428 1,-2 2,-2 l 2,0 0,-2 c 0,-1.108 0.892,-2 2,-2 z"
   7.217 +         style="opacity:1;fill:none;fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.2;stroke-opacity:1" />
   7.218 +    </g>
   7.219 +    <g
   7.220 +       transform="translate(24.6875,14.25)"
   7.221 +       id="g5536" />
   7.222 +    <g
   7.223 +       id="g5723"
   7.224 +       transform="matrix(0.76604444,-0.64278761,0.64278761,0.76604444,-668.92461,230.46198)"
   7.225 +       style="opacity:0.9">
   7.226 +      <path
   7.227 +         sodipodi:nodetypes="ccccccc"
   7.228 +         inkscape:connector-curvature="0"
   7.229 +         id="path5725"
   7.230 +         d="m 0.041523,1059.3622 24,2 0,4 8,-6 -8,-6 0,4 z"
   7.231 +         style="fill:url(#linearGradient5731);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
   7.232 +      <path
   7.233 +         sodipodi:nodetypes="ccccccc"
   7.234 +         inkscape:connector-curvature="0"
   7.235 +         id="path5727"
   7.236 +         d="m 3.042,1059.3622 22,1 0,3 5.5,-4 -5.5,-4 0,3 z"
   7.237 +         style="opacity:0.25;fill:none;fill-rule:evenodd;stroke:url(#linearGradient5733);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
   7.238 +      <path
   7.239 +         style="fill:none;fill-rule:evenodd;stroke:url(#linearGradient5735);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
   7.240 +         d="m 0.041523,1059.3622 24,2 0,4 8,-6 -8,-6 0,4 z"
   7.241 +         id="path5729"
   7.242 +         inkscape:connector-curvature="0"
   7.243 +         sodipodi:nodetypes="ccccccc" />
   7.244 +    </g>
   7.245 +  </g>
   7.246 +</svg>
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/manifest.json	Sun Feb 19 00:20:26 2017 +0100
     8.3 @@ -0,0 +1,28 @@
     8.4 +{
     8.5 +  "manifest_version": 2,
     8.6 +  "name": "__MSG_extensionName__",
     8.7 +  "version": "1",
     8.8 +  "description": "__MSG_extensionDescription__",
     8.9 +  "author": "Guido Berhoerster",
    8.10 +  "homepage_url": "https://code.guido-berhoerster.org/addons/firefox-addons/tab-mover/",
    8.11 +  "applications": {
    8.12 +      "gecko": {
    8.13 +          "id": "tab-mover@code.guido-berhoerster.org",
    8.14 +          "strict_min_version": "51.0"
    8.15 +      }
    8.16 +  },
    8.17 +  "icons": {
    8.18 +      "48": "icons/tab-mover-48.png",
    8.19 +      "96": "icons/tab-mover-96.png"
    8.20 +  },
    8.21 +  "default_locale": "en",
    8.22 +  "permissions": [
    8.23 +    "contextMenus",
    8.24 +    "tabs"
    8.25 +  ],
    8.26 +  "background": {
    8.27 +    "scripts": [
    8.28 +        "background.js"
    8.29 +    ]
    8.30 +  }
    8.31 +}