├── .gitignore
├── .jshintrc
├── CONTRIBUTING.md
├── LICENSE
├── LICENSE.txt
├── Readme.md
├── _locales
├── de
│ └── messages.json
└── en
│ └── messages.json
├── build.py
├── content-script.js
├── icon.png
├── icon.svg
├── icon32.png
├── icon64.png
├── main.js
├── manifest.json
├── options.html
└── options.js
/.gitignore:
--------------------------------------------------------------------------------
1 | *.xpi
2 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "browser": true,
3 | "curly": true,
4 | "esnext": true,
5 | "freeze": true,
6 | "globalstrict": true,
7 | "moz": true,
8 | "noarg": true,
9 | "nonbsp": true,
10 | "strict": true,
11 | "undef": true,
12 | "unused": true,
13 | "validthis": true,
14 | "maxlen": 80,
15 | "predef": ["Components", "Cc", "Ci", "Cr", "Cu", "require", "log",
16 | "LOG_DEBUG", "LOG_ERROR", "LOG_INFO", "prefs", "lazyRequire",
17 | "lazy", "Services", "Instances", "XPCOMUtils", "exports",
18 | "reportError", "ADDON", "unload", "BASE_PATH", "Iterator",
19 | "globalPrefs", "weak"]
20 | }
21 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | First of all, thanks for considering contributing code or other resources.
4 | Much appreciated!
5 |
6 | ## Submitting issues
7 |
8 | Please try to keep your texts short, but still include enough detail for other
9 | people to understand and **reproduce** your issue.
10 | E.g. if a bug affects a particular version, mention the version number. It might
11 | be also helpful to talk a bit about your environment, like operating system and
12 | platform (x86, x86_64, arm).
13 |
14 | For bugs or feature requests provide:
15 |
16 | - Sensible, but short summary/title.
17 | - Description of the actual behavior, preferably with detailed steps to
18 | reproduce the issue.
19 | - Description of the expected behavior.
20 | - If you know about older versions that worked correctly, mention that as well.
21 |
22 | Be polite, even if your issue does not (initially) get a lot of attention,
23 | or project maintainers close it as invalid/wontfix/etc.
24 |
25 | If you already diagnosed an issue and found the root cause, and feel like
26 | spending some extra time coding up a fix, then please don't hesitate to file a
27 | pull request instead of an issue. Project maintainers will love you.
28 |
29 | ### Bad
30 |
31 | > There is a bug in your software. When I click the button, it crashes.
32 |
33 | ### Better
34 |
35 | > Crash in version 1.0 when clicking Print button
36 | >
37 | > Hey, I'm using your software in version 1.0 on a Windows 7 (64-bit) system
38 | > along with FooBar Browser version 13.0. Unfortunately, it crashes when I
39 | > click on the Print button. This didn't happen in version 0.9.
40 | >
41 | > 1. Open document xyz
42 | > 2. Click Print button
43 | > 3. The application becomes unresponsive and has to be killed manually.
44 | >
45 | > I expect the application to print the document and then to continue working
46 | > normally.
47 |
48 | ## Submitting code and/or documentation
49 |
50 | - Your code should look and feel like the other code in the project, e.g. it
51 | should try to mimic/abide by the existing code formatting style and API
52 | design decisions.
53 | - If you plan to implement or revise a major feature/major API, or
54 | *break things* (for the better) in general, then please file an issue or
55 | pull request early. That way the project maintainers might suggest changes
56 | early and/or refine/reject ideas before you spend a lot time writing code that
57 | won't be merged in the current form.
58 | - Please provide (unit) tests, where appropriate and feasible.
59 | - Please use pull requests and avoid *plain* patches, etc.
60 | - Your commits should include at the very least an exploratory in plain English.
61 | Feel free to make use additional long messages current version control systems
62 | support, in particular if your commit is anything more than a simple bugfix.
63 | - Try to use gender-neutral language. Why? For four good reasons:
64 | - It is more inclusive and should work well-enough for all people.
65 | - It doesn't cost you anything, really, and no, it does not infringe upon your
66 | rights. It is easy enough to do, at least, in the English language.
67 | - Most importantly: because this file tells you to ;)
68 |
69 | ## Copyrights and License
70 |
71 | Any new code you submit **must be licensed** under the same license as the
72 | project license.
73 | Exception to this rule are only third-party libraries, which have to be
74 | licensed under a compatible license nonetheless and may **not** make the whole
75 | project less permissive.
76 | E.g. you may **not** submit code that uses plain GPL in a derivative way in a
77 | project otherwise licensed under a more permissive license such as the
78 | BSD/MIT/GPL licenses.
79 |
80 | You retain your copyright, or may assign it to the project/project maintainer.
81 | However, you must of course own the copyright or have the permission from the
82 | owners before submitting code. Work-for-hire-laws can be complicated.
83 |
84 | ## Enforcement
85 |
86 | The points outlined in this document are more guidelines than
87 | rules-set-in-stone.
88 |
89 | If in doubt, **the project maintainer(s) make the final decision**.
90 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Mozilla Public License Version 2.0
2 | ==================================
3 |
4 | 1. Definitions
5 | --------------
6 |
7 | 1.1. "Contributor"
8 | means each individual or legal entity that creates, contributes to
9 | the creation of, or owns Covered Software.
10 |
11 | 1.2. "Contributor Version"
12 | means the combination of the Contributions of others (if any) used
13 | by a Contributor and that particular Contributor's Contribution.
14 |
15 | 1.3. "Contribution"
16 | means Covered Software of a particular Contributor.
17 |
18 | 1.4. "Covered Software"
19 | means Source Code Form to which the initial Contributor has attached
20 | the notice in Exhibit A, the Executable Form of such Source Code
21 | Form, and Modifications of such Source Code Form, in each case
22 | including portions thereof.
23 |
24 | 1.5. "Incompatible With Secondary Licenses"
25 | means
26 |
27 | (a) that the initial Contributor has attached the notice described
28 | in Exhibit B to the Covered Software; or
29 |
30 | (b) that the Covered Software was made available under the terms of
31 | version 1.1 or earlier of the License, but not also under the
32 | terms of a Secondary License.
33 |
34 | 1.6. "Executable Form"
35 | means any form of the work other than Source Code Form.
36 |
37 | 1.7. "Larger Work"
38 | means a work that combines Covered Software with other material, in
39 | a separate file or files, that is not Covered Software.
40 |
41 | 1.8. "License"
42 | means this document.
43 |
44 | 1.9. "Licensable"
45 | means having the right to grant, to the maximum extent possible,
46 | whether at the time of the initial grant or subsequently, any and
47 | all of the rights conveyed by this License.
48 |
49 | 1.10. "Modifications"
50 | means any of the following:
51 |
52 | (a) any file in Source Code Form that results from an addition to,
53 | deletion from, or modification of the contents of Covered
54 | Software; or
55 |
56 | (b) any new file in Source Code Form that contains any Covered
57 | Software.
58 |
59 | 1.11. "Patent Claims" of a Contributor
60 | means any patent claim(s), including without limitation, method,
61 | process, and apparatus claims, in any patent Licensable by such
62 | Contributor that would be infringed, but for the grant of the
63 | License, by the making, using, selling, offering for sale, having
64 | made, import, or transfer of either its Contributions or its
65 | Contributor Version.
66 |
67 | 1.12. "Secondary License"
68 | means either the GNU General Public License, Version 2.0, the GNU
69 | Lesser General Public License, Version 2.1, the GNU Affero General
70 | Public License, Version 3.0, or any later versions of those
71 | licenses.
72 |
73 | 1.13. "Source Code Form"
74 | means the form of the work preferred for making modifications.
75 |
76 | 1.14. "You" (or "Your")
77 | means an individual or a legal entity exercising rights under this
78 | License. For legal entities, "You" includes any entity that
79 | controls, is controlled by, or is under common control with You. For
80 | purposes of this definition, "control" means (a) the power, direct
81 | or indirect, to cause the direction or management of such entity,
82 | whether by contract or otherwise, or (b) ownership of more than
83 | fifty percent (50%) of the outstanding shares or beneficial
84 | ownership of such entity.
85 |
86 | 2. License Grants and Conditions
87 | --------------------------------
88 |
89 | 2.1. Grants
90 |
91 | Each Contributor hereby grants You a world-wide, royalty-free,
92 | non-exclusive license:
93 |
94 | (a) under intellectual property rights (other than patent or trademark)
95 | Licensable by such Contributor to use, reproduce, make available,
96 | modify, display, perform, distribute, and otherwise exploit its
97 | Contributions, either on an unmodified basis, with Modifications, or
98 | as part of a Larger Work; and
99 |
100 | (b) under Patent Claims of such Contributor to make, use, sell, offer
101 | for sale, have made, import, and otherwise transfer either its
102 | Contributions or its Contributor Version.
103 |
104 | 2.2. Effective Date
105 |
106 | The licenses granted in Section 2.1 with respect to any Contribution
107 | become effective for each Contribution on the date the Contributor first
108 | distributes such Contribution.
109 |
110 | 2.3. Limitations on Grant Scope
111 |
112 | The licenses granted in this Section 2 are the only rights granted under
113 | this License. No additional rights or licenses will be implied from the
114 | distribution or licensing of Covered Software under this License.
115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a
116 | Contributor:
117 |
118 | (a) for any code that a Contributor has removed from Covered Software;
119 | or
120 |
121 | (b) for infringements caused by: (i) Your and any other third party's
122 | modifications of Covered Software, or (ii) the combination of its
123 | Contributions with other software (except as part of its Contributor
124 | Version); or
125 |
126 | (c) under Patent Claims infringed by Covered Software in the absence of
127 | its Contributions.
128 |
129 | This License does not grant any rights in the trademarks, service marks,
130 | or logos of any Contributor (except as may be necessary to comply with
131 | the notice requirements in Section 3.4).
132 |
133 | 2.4. Subsequent Licenses
134 |
135 | No Contributor makes additional grants as a result of Your choice to
136 | distribute the Covered Software under a subsequent version of this
137 | License (see Section 10.2) or under the terms of a Secondary License (if
138 | permitted under the terms of Section 3.3).
139 |
140 | 2.5. Representation
141 |
142 | Each Contributor represents that the Contributor believes its
143 | Contributions are its original creation(s) or it has sufficient rights
144 | to grant the rights to its Contributions conveyed by this License.
145 |
146 | 2.6. Fair Use
147 |
148 | This License is not intended to limit any rights You have under
149 | applicable copyright doctrines of fair use, fair dealing, or other
150 | equivalents.
151 |
152 | 2.7. Conditions
153 |
154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
155 | in Section 2.1.
156 |
157 | 3. Responsibilities
158 | -------------------
159 |
160 | 3.1. Distribution of Source Form
161 |
162 | All distribution of Covered Software in Source Code Form, including any
163 | Modifications that You create or to which You contribute, must be under
164 | the terms of this License. You must inform recipients that the Source
165 | Code Form of the Covered Software is governed by the terms of this
166 | License, and how they can obtain a copy of this License. You may not
167 | attempt to alter or restrict the recipients' rights in the Source Code
168 | Form.
169 |
170 | 3.2. Distribution of Executable Form
171 |
172 | If You distribute Covered Software in Executable Form then:
173 |
174 | (a) such Covered Software must also be made available in Source Code
175 | Form, as described in Section 3.1, and You must inform recipients of
176 | the Executable Form how they can obtain a copy of such Source Code
177 | Form by reasonable means in a timely manner, at a charge no more
178 | than the cost of distribution to the recipient; and
179 |
180 | (b) You may distribute such Executable Form under the terms of this
181 | License, or sublicense it under different terms, provided that the
182 | license for the Executable Form does not attempt to limit or alter
183 | the recipients' rights in the Source Code Form under this License.
184 |
185 | 3.3. Distribution of a Larger Work
186 |
187 | You may create and distribute a Larger Work under terms of Your choice,
188 | provided that You also comply with the requirements of this License for
189 | the Covered Software. If the Larger Work is a combination of Covered
190 | Software with a work governed by one or more Secondary Licenses, and the
191 | Covered Software is not Incompatible With Secondary Licenses, this
192 | License permits You to additionally distribute such Covered Software
193 | under the terms of such Secondary License(s), so that the recipient of
194 | the Larger Work may, at their option, further distribute the Covered
195 | Software under the terms of either this License or such Secondary
196 | License(s).
197 |
198 | 3.4. Notices
199 |
200 | You may not remove or alter the substance of any license notices
201 | (including copyright notices, patent notices, disclaimers of warranty,
202 | or limitations of liability) contained within the Source Code Form of
203 | the Covered Software, except that You may alter any license notices to
204 | the extent required to remedy known factual inaccuracies.
205 |
206 | 3.5. Application of Additional Terms
207 |
208 | You may choose to offer, and to charge a fee for, warranty, support,
209 | indemnity or liability obligations to one or more recipients of Covered
210 | Software. However, You may do so only on Your own behalf, and not on
211 | behalf of any Contributor. You must make it absolutely clear that any
212 | such warranty, support, indemnity, or liability obligation is offered by
213 | You alone, and You hereby agree to indemnify every Contributor for any
214 | liability incurred by such Contributor as a result of warranty, support,
215 | indemnity or liability terms You offer. You may include additional
216 | disclaimers of warranty and limitations of liability specific to any
217 | jurisdiction.
218 |
219 | 4. Inability to Comply Due to Statute or Regulation
220 | ---------------------------------------------------
221 |
222 | If it is impossible for You to comply with any of the terms of this
223 | License with respect to some or all of the Covered Software due to
224 | statute, judicial order, or regulation then You must: (a) comply with
225 | the terms of this License to the maximum extent possible; and (b)
226 | describe the limitations and the code they affect. Such description must
227 | be placed in a text file included with all distributions of the Covered
228 | Software under this License. Except to the extent prohibited by statute
229 | or regulation, such description must be sufficiently detailed for a
230 | recipient of ordinary skill to be able to understand it.
231 |
232 | 5. Termination
233 | --------------
234 |
235 | 5.1. The rights granted under this License will terminate automatically
236 | if You fail to comply with any of its terms. However, if You become
237 | compliant, then the rights granted under this License from a particular
238 | Contributor are reinstated (a) provisionally, unless and until such
239 | Contributor explicitly and finally terminates Your grants, and (b) on an
240 | ongoing basis, if such Contributor fails to notify You of the
241 | non-compliance by some reasonable means prior to 60 days after You have
242 | come back into compliance. Moreover, Your grants from a particular
243 | Contributor are reinstated on an ongoing basis if such Contributor
244 | notifies You of the non-compliance by some reasonable means, this is the
245 | first time You have received notice of non-compliance with this License
246 | from such Contributor, and You become compliant prior to 30 days after
247 | Your receipt of the notice.
248 |
249 | 5.2. If You initiate litigation against any entity by asserting a patent
250 | infringement claim (excluding declaratory judgment actions,
251 | counter-claims, and cross-claims) alleging that a Contributor Version
252 | directly or indirectly infringes any patent, then the rights granted to
253 | You by any and all Contributors for the Covered Software under Section
254 | 2.1 of this License shall terminate.
255 |
256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all
257 | end user license agreements (excluding distributors and resellers) which
258 | have been validly granted by You or Your distributors under this License
259 | prior to termination shall survive termination.
260 |
261 | ************************************************************************
262 | * *
263 | * 6. Disclaimer of Warranty *
264 | * ------------------------- *
265 | * *
266 | * Covered Software is provided under this License on an "as is" *
267 | * basis, without warranty of any kind, either expressed, implied, or *
268 | * statutory, including, without limitation, warranties that the *
269 | * Covered Software is free of defects, merchantable, fit for a *
270 | * particular purpose or non-infringing. The entire risk as to the *
271 | * quality and performance of the Covered Software is with You. *
272 | * Should any Covered Software prove defective in any respect, You *
273 | * (not any Contributor) assume the cost of any necessary servicing, *
274 | * repair, or correction. This disclaimer of warranty constitutes an *
275 | * essential part of this License. No use of any Covered Software is *
276 | * authorized under this License except under this disclaimer. *
277 | * *
278 | ************************************************************************
279 |
280 | ************************************************************************
281 | * *
282 | * 7. Limitation of Liability *
283 | * -------------------------- *
284 | * *
285 | * Under no circumstances and under no legal theory, whether tort *
286 | * (including negligence), contract, or otherwise, shall any *
287 | * Contributor, or anyone who distributes Covered Software as *
288 | * permitted above, be liable to You for any direct, indirect, *
289 | * special, incidental, or consequential damages of any character *
290 | * including, without limitation, damages for lost profits, loss of *
291 | * goodwill, work stoppage, computer failure or malfunction, or any *
292 | * and all other commercial damages or losses, even if such party *
293 | * shall have been informed of the possibility of such damages. This *
294 | * limitation of liability shall not apply to liability for death or *
295 | * personal injury resulting from such party's negligence to the *
296 | * extent applicable law prohibits such limitation. Some *
297 | * jurisdictions do not allow the exclusion or limitation of *
298 | * incidental or consequential damages, so this exclusion and *
299 | * limitation may not apply to You. *
300 | * *
301 | ************************************************************************
302 |
303 | 8. Litigation
304 | -------------
305 |
306 | Any litigation relating to this License may be brought only in the
307 | courts of a jurisdiction where the defendant maintains its principal
308 | place of business and such litigation shall be governed by laws of that
309 | jurisdiction, without reference to its conflict-of-law provisions.
310 | Nothing in this Section shall prevent a party's ability to bring
311 | cross-claims or counter-claims.
312 |
313 | 9. Miscellaneous
314 | ----------------
315 |
316 | This License represents the complete agreement concerning the subject
317 | matter hereof. If any provision of this License is held to be
318 | unenforceable, such provision shall be reformed only to the extent
319 | necessary to make it enforceable. Any law or regulation which provides
320 | that the language of a contract shall be construed against the drafter
321 | shall not be used to construe this License against a Contributor.
322 |
323 | 10. Versions of the License
324 | ---------------------------
325 |
326 | 10.1. New Versions
327 |
328 | Mozilla Foundation is the license steward. Except as provided in Section
329 | 10.3, no one other than the license steward has the right to modify or
330 | publish new versions of this License. Each version will be given a
331 | distinguishing version number.
332 |
333 | 10.2. Effect of New Versions
334 |
335 | You may distribute the Covered Software under the terms of the version
336 | of the License under which You originally received the Covered Software,
337 | or under the terms of any subsequent version published by the license
338 | steward.
339 |
340 | 10.3. Modified Versions
341 |
342 | If you create software not governed by this License, and you want to
343 | create a new license for such software, you may create and use a
344 | modified version of this License if you rename the license and remove
345 | any references to the name of the license steward (except to note that
346 | such modified license differs from this License).
347 |
348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary
349 | Licenses
350 |
351 | If You choose to distribute Source Code Form that is Incompatible With
352 | Secondary Licenses under the terms of this version of the License, the
353 | notice described in Exhibit B of this License must be attached.
354 |
355 | Exhibit A - Source Code Form License Notice
356 | -------------------------------------------
357 |
358 | This Source Code Form is subject to the terms of the Mozilla Public
359 | License, v. 2.0. If a copy of the MPL was not distributed with this
360 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
361 |
362 | If it is not possible or desirable to put the notice in a particular
363 | file, then You may include the notice in a location (such as a LICENSE
364 | file in a relevant directory) where a recipient would be likely to look
365 | for such a notice.
366 |
367 | You may add additional accurate notices of copyright ownership.
368 |
369 | Exhibit B - "Incompatible With Secondary Licenses" Notice
370 | ---------------------------------------------------------
371 |
372 | This Source Code Form is "Incompatible With Secondary Licenses", as
373 | defined by the Mozilla Public License, v. 2.0.
374 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Mozilla Public License Version 2.0
2 | ==================================
3 |
4 | See: http://www.mozilla.org/MPL/2.0/index.txt
5 | Or see: LICENSE file in the repository
6 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | Re-Pagination
2 | ===
3 |
4 | This add-on is an update of the old re-pagination/antipagination extension for Firefox 57+.
5 | Nils Maier has not assigned ownership over to this project, so this is still a fork.
6 |
7 | Features
8 | ===
9 |
10 | * WebExtension compatible with Firefox Quantum
11 | * Compatible with more sites
12 | * All, limited and slideshow
13 |
--------------------------------------------------------------------------------
/_locales/de/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "displaySubmenu_label": {
3 | "message": "Untermenü anzeigen"
4 | },
5 | "displaySubmenu_desc": {
6 | "message": "Wenn diese Option aktiviert ist (Standard), dann wird Re-Pagination als Untermenü angezeigt anstatt die verschiedenen Aktionen direkt im Kontextmenü anzuzeigen."
7 | },
8 | "showslideshow_label": {
9 | "message": "'Slide-Show' Menüeintrag anzeigen"
10 | },
11 | "showalldomain_label": {
12 | "message": "'Alle Tabs der aktuellen Domain' Menüeintrag anzeigen"
13 | },
14 | "loglevel_label": {
15 | "message": "Protokoll Stufe"
16 | },
17 | "loglevel_desc": {
18 | "message": "Die Nachrichten werden in der Fehlerkonsole protokolliert. Man sollte diese Einstellung auf 'Keine Protokollierung' belassen, wenn nicht anders angewiesen."
19 | },
20 | "loglevel_none_label": {
21 | "message": "Keine Protokollierung"
22 | },
23 | "loglevel_error_label": {
24 | "message": "Fehler protokollieren"
25 | },
26 | "loglevel_info_label": {
27 | "message": "Fehler und Infos protokollieren"
28 | },
29 | "loglevel_debug_label": {
30 | "message": "Alles protokollieren!"
31 | },
32 | "menu_label": {
33 | "message": "Re-Pagination"
34 | },
35 | "repagination_nolimit": {
36 | "message": "Alle laden"
37 | },
38 | "repagination_nolimit_domain": {
39 | "message": "'Alle Tabs der aktuellen Domain'"
40 | },
41 | "repagination_limit": {
42 | "message": "Begrenzt"
43 | },
44 | "repagination_slide": {
45 | "message": "Slide-Show"
46 | },
47 | "repagination_slide_0": {
48 | "message": "Sofort"
49 | },
50 | "repagination_slide_1": {
51 | "message": "1 Sekunde"
52 | },
53 | "repagination_slide_60": {
54 | "message": "1 Minute"
55 | },
56 | "repagination_stop": {
57 | "message": "Stoppen!"
58 | },
59 | "repagination_limit_x": {
60 | "message": "$1 Seiten"
61 | },
62 | "repagination_slide_120": {
63 | "message": "2 Minuten"
64 | },
65 | "repagination_slide_x": {
66 | "message": "$1 Sekunden"
67 | },
68 |
69 | "repagination_limited": {
70 | "message": "($1 of $2) Re-Pagination arbeitet..."
71 | },
72 | "repagination_unlimited": {
73 | "message": "($1) Re-Pagination arbeitet..."
74 | },
75 | "repagination_running": {
76 | "message": "Re-Pagination arbeitet..."
77 | },
78 |
79 | "extensionName": {
80 | "message": "Re-Pagination"
81 | },
82 | "extensionDescription": {
83 | "message": "Alle fortlaufenden Seiten in einem einzigem Tab auf einmal laden"
84 | }
85 | }
--------------------------------------------------------------------------------
/_locales/en/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "displaySubmenu_label": {
3 | "message": "Display submenu"
4 | },
5 | "displaySubmenu_desc": {
6 | "message": "When this option is enabled (default), then Re-Pagination will be displayed as a submenu instead of displaying the various actions directly within the context menu."
7 | },
8 | "showslideshow_label": {
9 | "message": "Show 'Slideshow' menu item"
10 | },
11 | "showalldomain_label": {
12 | "message": "Show 'All tabs for current domain' menu item"
13 | },
14 | "loglevel_label": {
15 | "message": "Log level"
16 | },
17 | "loglevel_desc": {
18 | "message": "The messages will be logged to the Error Console. You should leave this at 'No Logging' unless instructed otherwise"
19 | },
20 | "loglevel_none_label": {
21 | "message": "No Logging"
22 | },
23 | "loglevel_error_label": {
24 | "message": "Log Errors"
25 | },
26 | "loglevel_info_label": {
27 | "message": "Log Errors and Infos"
28 | },
29 | "loglevel_debug_label": {
30 | "message": "Log Everything!"
31 | },
32 | "menu_label": {
33 | "message": "Re-Pagination"
34 | },
35 | "repagination_nolimit": {
36 | "message": "Load all"
37 | },
38 | "repagination_nolimit_domain": {
39 | "message": "All tabs for current domain"
40 | },
41 | "repagination_limit": {
42 | "message": "Limited"
43 | },
44 | "repagination_limit_x": {
45 | "message": "$1 pages"
46 | },
47 | "repagination_slide": {
48 | "message": "Slideshow"
49 | },
50 | "repagination_slide_0": {
51 | "message": "Immediately"
52 | },
53 | "repagination_slide_1": {
54 | "message": "1 second"
55 | },
56 | "repagination_slide_x": {
57 | "message": "$1 seconds"
58 | },
59 | "repagination_slide_60": {
60 | "message": "1 minute"
61 | },
62 | "repagination_slide_120": {
63 | "message": "2 minutes"
64 | },
65 | "repagination_stop": {
66 | "message": "Stop!"
67 | },
68 | "repagination_limited": {
69 | "message": "($1 of $2) Re-Pagination is running..."
70 | },
71 | "repagination_unlimited": {
72 | "message": "($1) Re-Pagination is running..."
73 | },
74 | "repagination_running": {
75 | "message": "Re-Pagination is running..."
76 | },
77 | "extensionName": {
78 | "message": "Re-Pagination"
79 | },
80 | "extensionDescription": {
81 | "message": "Load all consecutive pages in a single tab at once."
82 | }
83 | }
--------------------------------------------------------------------------------
/build.py:
--------------------------------------------------------------------------------
1 | # vim: set nosmartindent et ts=4 sw=4 :
2 |
3 | import os
4 | import re
5 | import sys
6 |
7 | from contextlib import contextmanager as ctx
8 | from glob import glob
9 |
10 | from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED
11 |
12 | resources = [
13 | "manifest.json",
14 | "_locales/*/messages.json",
15 | "icon.png", "icon32.png", "icon64.png",
16 | "LICENSE.txt",
17 | "*.js", "options.html"
18 | ]
19 | destination = "repagination.xpi"
20 |
21 |
22 | try:
23 | from xpisign.context import ZipFileMinorCompression as Minor
24 | except ImportError:
25 | from warnings import warn
26 | warn("No optimal compression available; install xpisign")
27 |
28 | @ctx
29 | def Minor():
30 | yield
31 |
32 |
33 | def get_files(resources):
34 | for r in resources:
35 | if os.path.isfile(r):
36 | yield r
37 | continue
38 | for g in glob(r):
39 | yield g
40 |
41 |
42 | class ZipOutFile(ZipFile):
43 | def __init__(self, zfile):
44 | ZipFile.__init__(self, zfile, "w", ZIP_DEFLATED)
45 |
46 | def __enter__(self):
47 | return self
48 |
49 | def __exit__(self, type, value, traceback):
50 | self.close()
51 |
52 |
53 | # if os.path.exists(destination):
54 | # print >>sys.stderr, destination, "is in the way"
55 | # sys.exit(1)
56 |
57 | with Minor(), ZipOutFile(destination) as zp:
58 | for f in sorted(get_files(resources), key=str.lower):
59 | compress_type = ZIP_STORED if f.endswith(".png") else ZIP_DEFLATED
60 | zp.write(f, compress_type=compress_type)
61 |
--------------------------------------------------------------------------------
/content-script.js:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 | "use strict";
5 |
6 | {
7 | console.log("Framescript loaded!");
8 | let port = browser.runtime.connect();
9 |
10 | var focusElement = null;
11 |
12 | let _ = function () {
13 | let args = Array.from(arguments).map(e => e.toString());
14 | return browser.i18n.getMessage(args[0], args.slice(1));
15 | }
16 |
17 | let equalLinks = (left, right) =>
18 | left.pathname === right.pathname &&
19 | left.search === right.search &&
20 | left.host === right.host &&
21 | left.protocol === right.protocol;
22 |
23 | let getFirstSnapshot = (doc, node, query) =>
24 | doc.evaluate(query, node, null, 7, null).snapshotItem(0);
25 |
26 | let createPageRequest = (srcurl, allowScripts, loadFun) => {
27 | let errorCount = 0;
28 | function sendRequest() {
29 | var xhr = new XMLHttpRequest();
30 | xhr.onload = function() {
31 | if (xhr.status == 200) {
32 | console.info("XHR loaded, going to process");
33 | try {
34 | loadFun(xhr.responseXML);
35 | }
36 | catch (ex) {
37 | console.error("failed to invoke callback on XHR", ex);
38 | }
39 | } else if (++errorCount <= 5) {
40 | console.info("XHR err'ed out, retrying");
41 | setTimeout(function(){ sendRequest(); }, 500 * (2**errorCount));
42 | } else {
43 | console.error("XHR err'ed out, giving up");
44 | }
45 | }
46 | xhr.open('GET', srcurl);
47 | xhr.responseType = "document";
48 | xhr.send();
49 | }
50 | sendRequest();
51 | };
52 |
53 | let Repaginator = function Repaginator(count, allowScripts, yielding) {
54 | this.pageLimit = count || 0;
55 | this.allowScripts = allowScripts;
56 | this.yielding = yielding;
57 | this.init();
58 | };
59 | Repaginator.prototype = {
60 | slideshow: false,
61 | pageLimit: 0,
62 | seconds: 0,
63 | pageCount: 0,
64 | attemptToIncrement: true,
65 |
66 | init: function R_init() {
67 | // find anchor
68 | (function findInitialAnchor() {
69 | for (let parent = focusElement; parent; parent = parent.parentNode) {
70 | if (parent.localName == "a") {
71 | focusElement = parent;
72 | return;
73 | }
74 | }
75 | throw new Error("No focus element");
76 | })();
77 | },
78 | buildQuery: function R_buildQuery(el) {
79 | function escapeXStr(mystr) {
80 | return mystr.replace(/'/g, "\\'");
81 | }
82 |
83 | this.query = "";
84 |
85 | (function buildQuery() {
86 | // Homestuck hack
87 | if(el.href && el.href.includes("mspaintadventures.com")) {
88 | this.query = "//center[position() = 1]/table[position() = 1]/tbody[position() = 1]/tr[position() = 2]/td[position() = 1]/table[position() = 1]/tbody[position() = 1]/tr[position() = 1]/td[position() = 1]/table[position() = 1]/tbody[position() = 1]/tr[position() = 2]/td[position() = 1]/center[position() = 1]/table[position() = 1]/tbody[position() = 1]/tr[position() = 6]/td[position() = 1]/table[position() = 1]/tbody[position() = 1]/tr[position() = 1]/td[position() = 1]/font[position() = 1]/a[position() = 1]";
89 | this.numberToken = /(\[@href='.*)(\d+)(.*?'\])/;
90 | return;
91 | }
92 |
93 | // See if the anchor has an ID
94 | // Note: cannot use the id() xpath function here, as there might
95 | // be duplicate ids
96 | if (el.id) {
97 | this.query = "//a[@id='" + escapeXStr(el.id) + "']";
98 | this.numberToken = /(\[@id='.*?)(\d+)(.*?'\])/;
99 | return;
100 | }
101 |
102 | // See if the document has a link rel="..." pointing to the same place
103 | let linkEl = getFirstSnapshot(el.ownerDocument, el.ownerDocument,
104 | "//head//link[@href='" +
105 | escapeXStr(el.href) + "']");
106 | if (linkEl) {
107 | let rel = linkEl.getAttribute("rel") || "";
108 | if (rel.trim()) {
109 | this.query = "/html/head//link[@rel='" + escapeXStr(rel) + "']";
110 | // no point in checking for numbers
111 | this.attemptToIncrement = false;
112 | console.log("using link[@rel]");
113 | return;
114 | }
115 | }
116 |
117 | // Find an id in the ancestor chain, or alternatively a class
118 | // that we may operate on
119 | (function findPathPrefix() {
120 | let pieces = [];
121 | for (let pn = el.parentNode; pn; pn = pn.parentNode) {
122 | if (pn.localName == "body") {
123 | break;
124 | }
125 | if (pn.id) {
126 | console.log("got id: " + pn.id);
127 | pieces.unshift("//" + pn.localName + "[@id='" +
128 | escapeXStr(pn.id) + "']");
129 | break; // one id is enough
130 | }
131 | if (pn.className) {
132 | console.log("got class: " + pn.className);
133 | pieces.unshift("//" + pn.localName + "[@class='" +
134 | escapeXStr(pn.className) + "']");
135 | break;
136 | }
137 | }
138 | this.query = pieces.join("");
139 | console.log("findPathPrefix result: " + this.query);
140 | }).call(this);
141 |
142 | // find the anchor
143 | (function findAnchor() {
144 | let text = el.textContent;
145 |
146 | // See if there is rel=next or rel=prev
147 | let rel = (el.getAttribute("rel") || "").trim();
148 | if (rel && (rel.includes("next") || rel.includes("prev"))) {
149 | this.query += "//a[@rel='" + escapeXStr(rel) + "']";
150 | // no point in checking for numbers
151 | this.attemptToIncrement = false;
152 | console.log("using a[@rel]");
153 | return;
154 | }
155 |
156 | // Try the node text
157 | if (text.trim()) {
158 | this.query += "//a[.='" + escapeXStr(text) + "']";
159 | this.numberToken = /(a\[.='.*?)(\d+)(.*?\])/;
160 | console.log("using text");
161 | return;
162 | }
163 |
164 | // See if it has a descendant with a @src we may use
165 | let srcEl = getFirstSnapshot(el.ownerDocument, el, "descendant::*[@src]");
166 | if (srcEl) {
167 | let src = srcEl.getAttribute("src") || "";
168 | if (src.trim()) {
169 | this.query += "//" + srcEl.localName + "[@src='" + escapeXStr(src) +
170 | "']/ancestor::a";
171 | this.numberToken = /(\[@src='.*?)(\d+)(.*?'\])/;
172 | console.log("using @src");
173 | return;
174 | }
175 | }
176 |
177 | // See if there is a descendant with a @value we may use
178 | srcEl = getFirstSnapshot(el.ownerDocument, el, "descendant::*[@value]");
179 | if (srcEl) {
180 | let val = srcEl.getAttribute("value") || "";
181 | if (val.trim()) {
182 | this.query += "//" + srcEl.localName + "[@value='" +
183 | escapeXStr(val) + "']/ancestor::a";
184 | this.numberToken = /(\[@value='.*?)(\d+)(.*?'\])/;
185 | console.log("using @value");
186 | return;
187 | }
188 | }
189 |
190 | // See if there is a class we may use
191 | if (el.className) {
192 | this.query += "//a[@class='" + escapeXStr(el.className) + "']";
193 | this.numberToken = /(\[@class='.*?)(\d+)(.*?'\])/;
194 | console.log("using a[@class]");
195 | return;
196 | }
197 |
198 | // See if there is a descendant with an id we may use
199 | srcEl = getFirstSnapshot(el.ownerDocument, el, "descendant::*[@id]");
200 | if (srcEl) {
201 | let val = srcEl.getAttribute("id") || "";
202 | if (val.trim()) {
203 | this.query += "//" + srcEl.localName + "[@id='" +
204 | escapeXStr(val) + "']/ancestor::a";
205 | this.numberToken = /(\[@value='.*?)(\d+)(.*?'\])/;
206 | console.log("using descendant class");
207 | return;
208 | }
209 | }
210 |
211 | throw new Error("No anchor expression found!");
212 | }).call(this);
213 | }).call(this);
214 |
215 |
216 | // We're after the last result
217 | this.query = "(" + this.query + ")[last()]";
218 | console.info("query: " + this.query);
219 | },
220 | setTitle: function R_setTitle() {
221 | if (this.pageLimit) {
222 | document.title =
223 | _("repagination_limited", this.pageCount, this.pageLimit);
224 | }
225 | else if (this.pageCount > 0) {
226 | document.title = _("repagination_unlimited", this.pageCount);
227 | }
228 | else {
229 | document.title = _("repagination_running");
230 | }
231 | },
232 | finished: function R_finished() {
233 | port.postMessage({msg: "finished"});
234 | stop();
235 | // restore title
236 | if("_title" in this) {
237 | document.title = this._title;
238 | delete this._title;
239 | }
240 | },
241 | repaginate: function R_repaginate() {
242 | this._title = document.title;
243 | this.setTitle();
244 | try {
245 | let node = document.evaluate(
246 | this.query, document, null, 9, null).singleNodeValue;
247 | if (!node) {
248 | throw new Error("no node");
249 | }
250 | document.body.setAttribute("repagination", "true");
251 | createPageRequest(node.href, this.allowScripts, frame => {
252 | this.loadNext(node.href, frame, 0);
253 | });
254 | } catch (ex) {
255 | this.finished();
256 | console.error("repaginate failed", ex);
257 | }
258 | },
259 | incrementQuery: function R_incrementQuery() {
260 | return this.query.replace(this.numberToken, function(g, pre, num, post) {
261 | return pre + (parseInt(num, 10) + 1) + post;
262 | });
263 | },
264 | loadNext: function R_loadNext(src, element, delay) {
265 | if (delay > 0) {
266 | console.log("delaying (sto) " + delay);
267 | setTimeout(() => this.loadNext(src, element, 0), delay);
268 | return;
269 | }
270 |
271 | try {
272 | this._loadNext_gen.bind(this, src, element)();
273 | } catch (ex) {
274 | console.error("failed to process loadNext (non-yielding)", ex);
275 | this.finished();
276 | }
277 | return;
278 | },
279 | _loadNext_gen: function R__loadNext_gen(src, element) {
280 | let ownerDoc = document;
281 |
282 | try {
283 | if (!ownerDoc.body.hasAttribute("repagination")) {
284 | throw new Error("not running");
285 | }
286 |
287 | var doc = element;
288 | this.pageCount++;
289 |
290 | // Remove scripts from frame
291 | // The scripts should already be present in the parent (first page)
292 | // Duplicate scripts would cause more havoc (performance-wise) than
293 | // behaviour failures due to missing scripts
294 | // Note: This is NOT a security mechanism, but a performance thing.
295 | doc.querySelectorAll("script").forEach(s => s.parentNode.removeChild(s));
296 | doc.querySelectorAll("style").forEach(s => s.parentNode.removeChild(s));
297 |
298 | // Do the dirty deed
299 | if (this.slideshow) {
300 | console.info("replacing content (slideshow)");
301 | // this should be safe since innerHTML returns serialized HTML
302 | ownerDoc.body.innerHTML = doc.body.innerHTML;
303 | ownerDoc.body.setAttribute("repagination", "true");
304 | }
305 | else {
306 | console.info("inserting content (normal)");
307 | // Remove non-same-origin iframes, such as ad iframes
308 | // Otherwise we might create a shitload of (nearly) identical frames
309 | // which might even kill the browser
310 | if (!this.pageLimit || this.pageLimit > 10) {
311 | console.info("removing non-same-origin iframes to avoid dupes");
312 | let host = ownerDoc.defaultView.location.hostName;
313 | doc.querySelectorAll("iframe").forEach(function(f) {
314 | var url = new URL(f.src, ownerDoc.defaultView.location.href);
315 | if (url.hostname != host) {
316 | f.parentNode.removeChild(f);
317 | }
318 | });
319 | }
320 | for (let c = doc.body.firstChild; c; c = c.nextSibling) {
321 | ownerDoc.body.appendChild(ownerDoc.importNode(c, true));
322 | }
323 | }
324 |
325 | if (this.pageLimit && this.pageCount >= this.pageLimit) {
326 | throw new Error("done");
327 | }
328 |
329 | let savedQuery;
330 | if (this.attemptToIncrement) {
331 | console.log("attempting to increment query");
332 | let nq = this.incrementQuery();
333 | if (nq == this.query) {
334 | console.log("query did not increment");
335 | this.attemptToIncrement = false;
336 | }
337 | else {
338 | console.log("query did increment");
339 | savedQuery = this.query;
340 | this.query = nq;
341 | }
342 | }
343 | let node = doc.evaluate(this.query, doc, null, 9, null).singleNodeValue;
344 | let loc = src || null;
345 | if (this.attemptToIncrement && (!node || node.href == loc)) {
346 | console.log("no result after incrementing; restoring");
347 | console.log("inc:" + this.query + " orig:" + savedQuery);
348 | this.query = savedQuery;
349 | node = doc.evaluate(this.query, doc, null, 9, null).singleNodeValue;
350 | this.attemptToIncrement = false;
351 | }
352 | if (!node) {
353 | throw new Error("no next node found for query: " + this.query);
354 | }
355 | let nexturl = node.href.toString();
356 | if (loc && loc == nexturl) {
357 | throw new Error("location did not change for query" + this.query);
358 | }
359 | if (equalLinks(node,window.location)) {
360 | throw new Error("loop back to first item");
361 | }
362 |
363 | this.setTitle();
364 | console.info("next please: " + nexturl);
365 | createPageRequest(nexturl, this.allowScripts, frame => {
366 | if (this.slideshow && this.seconds) {
367 | console.info("slideshow; delay: " + this.seconds * 1000);
368 | this.loadNext(nexturl, frame, this.seconds * 1000);
369 | }
370 | else {
371 | console.info("regular; no-delay");
372 | this.loadNext(nexturl, frame, 0);
373 | }
374 | });
375 | }
376 | catch (ex) {
377 | console.log(ex);
378 | console.info("loadNext complete");
379 | this.finished();
380 | }
381 | }
382 | };
383 | Object.seal(Repaginator.prototype);
384 |
385 | let Slideshow = function Slideshow(seconds, allowScripts, yielding) {
386 | this.seconds = seconds || 0;
387 | this.slideshow = true;
388 | this.allowScripts = allowScripts;
389 | this.yielding = yielding;
390 | this.init();
391 | };
392 | Slideshow.prototype = Repaginator.prototype;
393 |
394 | let repaginate = (target, num, slideshow, allowScripts, yielding) => {
395 | try {
396 | let Ctor = slideshow ? Slideshow : Repaginator;
397 | let rep;
398 | focusElement = browser.menus.getTargetElement(target);
399 | rep = new Ctor(num, allowScripts, yielding);
400 | rep.buildQuery(focusElement);
401 | rep.repaginate();
402 | } catch (ex) {
403 | console.error("Failed to run repaginate", ex);
404 | }
405 | };
406 |
407 | let stop = () => {
408 | try {
409 | let body = document.body;
410 | if (body) {
411 | body.removeAttribute("repagination");
412 | }
413 | } catch (ex) {
414 | console.error("failed to stop repagination", ex);
415 | }
416 | };
417 |
418 | port.onMessage.addListener(msg => {
419 | switch (msg.msg) {
420 | case "normal": repaginate(msg.target, msg.num, msg.slideshow, msg.allowScripts, msg.yielding); break;
421 | case "stop" : stop(); break;
422 | }
423 | });
424 |
425 | // https://bugzilla.mozilla.org/show_bug.cgi?id=1370368
426 | window.addEventListener('pagehide', function(event) {
427 | stop();
428 | try {
429 | port.disconnect();
430 | } catch (ex) {
431 | console.log(ex)
432 | }
433 | });
434 |
435 | }
436 | /* vim: set et ts=2 sw=2 : */
437 |
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mathnerd314/repagination/b0214aa1e6b5d4b7df1b546a6b82db91a848ae8b/icon.png
--------------------------------------------------------------------------------
/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
111 |
--------------------------------------------------------------------------------
/icon32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mathnerd314/repagination/b0214aa1e6b5d4b7df1b546a6b82db91a848ae8b/icon32.png
--------------------------------------------------------------------------------
/icon64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mathnerd314/repagination/b0214aa1e6b5d4b7df1b546a6b82db91a848ae8b/icon64.png
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | /* This Source Code Form is subject to the terms of the Mozilla Public
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 | "use strict";
5 |
6 | const PORTS = {};
7 | const PENDING = {};
8 | const RUNNING = new Set();
9 |
10 | function onError(error) {
11 | console.error(error);
12 | }
13 |
14 | const MENU = {
15 | NOLIMIT: 'REPAGINATION_NOLIMIT',
16 | LIMIT: 'REPAGINATION_LIMIT',
17 | SLIDE: 'REPAGINATION_SLIDE',
18 | STOP: 'REPAGINATION_STOP'
19 | }
20 |
21 | function onCreated(n) {
22 | if (browser.runtime.lastError) {
23 | console.error("Error creating menu item: %o", browser.runtime.lastError);
24 | }
25 | }
26 |
27 | function createMenu(prefs) {
28 | let c = ["link"]; // ContextTypes for most menu items
29 |
30 | browser.menus.create({
31 | id: MENU.NOLIMIT,
32 | title: browser.i18n.getMessage("repagination_nolimit"),
33 | contexts: c
34 | }, onCreated);
35 |
36 | let limits = [5,10,25,50,100];
37 |
38 | for(let j in limits) {
39 | let i = limits[j];
40 | browser.menus.create({
41 | id: MENU.LIMIT + "_" + i,
42 | title: browser.i18n.getMessage("repagination_limit_x",[i]),
43 | contexts: c
44 | }, onCreated);
45 |
46 | }
47 |
48 | if(prefs.slideshows) {
49 | browser.menus.create({
50 | id: MENU.SLIDE,
51 | title: browser.i18n.getMessage("repagination_slide"),
52 | contexts: c
53 | }, onCreated);
54 |
55 | let slides = [0,1,2,4,5,10,15,30,60,120];
56 |
57 | for(let j in slides) {
58 | let i = slides[j];
59 | browser.menus.create({
60 | id: MENU.SLIDE + "_" + i,
61 | parentId: MENU.SLIDE,
62 | title: ([0,1,60,120].indexOf(i) != -1) ? browser.i18n.getMessage("repagination_slide_" + i) : browser.i18n.getMessage("repagination_slide_x",[i]),
63 | contexts: c
64 | }, onCreated);
65 | }
66 | }
67 |
68 | updStop();
69 | }
70 |
71 | var added = false;
72 |
73 | function updStop() {
74 | if(RUNNING.size > 0 && !added) {
75 | browser.menus.create({
76 | id: MENU.STOP,
77 | title: browser.i18n.getMessage("repagination_stop"),
78 | contexts: ["all"]
79 | }, onCreated);
80 | added = true;
81 | } else if(added) {
82 | browser.menus.remove(MENU.STOP);
83 | added = false;
84 | }
85 | }
86 |
87 | var defaultSettings = {
88 | slideshows: false,
89 | exists: true // special pref to restore defaults
90 | };
91 |
92 | function prefReset(newSettings, areaName) {
93 | console.log("prefs changed")
94 | if (areaName == "local" && ("exists" in newSettings)) {
95 | browser.menus.removeAll();
96 | console.log("recreating menu")
97 | browser.storage.local.get().then(initSettings, onError);
98 | }
99 | }
100 |
101 | function initSettings(prefs) {
102 | if (!("exists" in prefs) || !prefs.exists) {
103 | browser.storage.onChanged.removeListener(prefReset);
104 | browser.storage.local.set(defaultSettings);
105 | browser.storage.onChanged.addListener(prefReset);
106 | prefs = defaultSettings;
107 | }
108 |
109 | createMenu(prefs);
110 | }
111 |
112 | function myinit(prefs) {
113 | initSettings(prefs);
114 |
115 | function process(info, tab) {
116 | let str = info.menuItemId;
117 |
118 | if(str == MENU.STOP) {
119 | console.info("stop");
120 | PORTS[tab].postMessage({
121 | msg: "stop"
122 | });
123 | return;
124 | }
125 |
126 | let num, slideshow;
127 | if(str == MENU.NOLIMIT) {
128 | num = 0;
129 | slideshow = false;
130 | } else if(str.startsWith(MENU.LIMIT)) {
131 | // https://stackoverflow.com/questions/5555518/split-variable-from-last-slash-jquery
132 | num = parseInt(str.substring(str.lastIndexOf("_") + 1, str.length), 10);
133 | slideshow = false;
134 | } else if(str.startsWith(MENU.SLIDE)) {
135 | num = parseInt(str.substring(str.lastIndexOf("_") + 1, str.length), 10);
136 | slideshow = true;
137 | }
138 |
139 | console.info("repaginate: " + num + "/" + slideshow);
140 | try {
141 | PORTS[tab].postMessage({
142 | msg: "normal",
143 | target: info.targetElementId,
144 | num: num,
145 | slideshow: slideshow,
146 | allowScripts: prefs.allowScripts,
147 | yielding: prefs.yielding
148 | });
149 | RUNNING.add(tab);
150 | updStop();
151 | } catch (ex) {
152 | console.log(ex);
153 | console.error("failed to run repaginate");
154 | delete PORTS[tabid];
155 | delete PENDING[tabid];
156 | RUNNING.delete(tabid);
157 | }
158 | }
159 |
160 | // We lazily inject the main content script in a vague hope for efficiency
161 | // We use ports for messaging but have to store the messages until the port is opened.
162 |
163 | browser.menus.onClicked.addListener((info, tab) => {
164 | console.log(info, tab);
165 | if(tab.id in PORTS) {
166 | process(info, tab.id);
167 | } else {
168 | console.log("injecting " + tab.id);
169 | browser.tabs.executeScript(tab.id, { file: "content-script.js" } );
170 | PENDING[tab.id] = info;
171 | }
172 | });
173 |
174 |
175 | browser.runtime.onConnect.addListener(function(port) {
176 | let tabid = port.sender.tab.id;
177 | PORTS[tabid] = port;
178 | port.onDisconnect.addListener((p) => {
179 | delete PORTS[tabid];
180 | delete PENDING[tabid];
181 | RUNNING.delete(tabid);
182 | updStop();
183 | });
184 | port.onMessage.addListener(msg => {
185 | switch (msg.msg) {
186 | case "finished":
187 | RUNNING.delete(tabid);
188 | updStop();
189 | break;
190 | }
191 | });
192 |
193 | if (port.sender.tab.id in PENDING) {
194 | var info = PENDING[port.sender.tab.id];
195 | delete PENDING[port.sender.tab.id];
196 | process(info, port.sender.tab.id);
197 | }
198 | });
199 | }
200 |
201 | browser.storage.local.get().then(myinit, onError);
202 |
203 | browser.storage.onChanged.addListener(prefReset);
204 |
205 | console.info("all good!");
206 |
207 | /* vim: set et ts=2 sw=2 : */
208 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 2,
3 | "name": "__MSG_extensionName__",
4 | "version": "2020.5.27",
5 | "description": "__MSG_extensionDescription__",
6 | "homepage_url": "https://github.com/Mathnerd314/repagination/",
7 |
8 | "default_locale": "en",
9 | "options_ui": {
10 | "page": "options.html",
11 | "browser_style": true
12 | },
13 | "icons": { "32": "icon32.png",
14 | "48": "icon.png",
15 | "64": "icon64.png"},
16 |
17 | "applications": {
18 | "gecko": {
19 | "id": "repagination-fork-mathnerd314@github.com",
20 | "strict_min_version": "63.0"
21 | }
22 | },
23 |
24 | "background": {
25 | "scripts": ["main.js"]
26 | },
27 |
28 | "permissions": [
29 | "activeTab",
30 | "storage",
31 | "menus",
32 | ""
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
36 |
37 |
38 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
Credits
48 |
49 |
Original developer: Omar Lev
50 |
Developer, translator: Nils Maier
51 |
Current maintainer: Mathnerd314
52 |
53 |
--------------------------------------------------------------------------------
/options.js:
--------------------------------------------------------------------------------
1 | /* see also main.js */
2 |
3 | /*
4 | Update the options UI with the settings values retrieved from storage,
5 | or the default settings if the stored settings are empty.
6 | */
7 | function updateUI(restoredSettings) {
8 | document.getElementById("slideshows").checked = restoredSettings.slideshows || false;
9 | }
10 |
11 | function onError(e) {
12 | console.error(e);
13 | }
14 |
15 | browser.storage.local.get().then(updateUI, onError);
16 |
17 | document.getElementById("slideshows").onchange = function setSlideshows() {
18 | browser.storage.local.set({ exists: true, slideshows: document.getElementById("slideshows").checked});
19 | };
20 |
--------------------------------------------------------------------------------