pax_global_header00006660000000000000000000000064147737071310014524gustar00rootroot0000000000000052 comment=b2a0fc9441f9dd42640d6aed1f437ed54c7a2249 quicktext-6.3.2/000077500000000000000000000000001477370713100135555ustar00rootroot00000000000000quicktext-6.3.2/CONTRIBUTORS.md000066400000000000000000000005331477370713100160350ustar00rootroot00000000000000## Original Creator * Emil Hesslow ## Current Maintainer * John Bieling ## Contributors * John Bieling * Sebastian Haberey * Emil Hesslow * R Kent James * Philippe Lieser * Christian Schneider * Janning Vygen * bgeiring * drakulis * Peñalara Software S.L. * Samuel Plentz ## Translators * Alexey Sinitsyn (ru) * Óvári (hu) * Ryota Murai (ja)quicktext-6.3.2/LICENSE000066400000000000000000000405261477370713100145710ustar00rootroot00000000000000Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. quicktext-6.3.2/NEXT.md000066400000000000000000000031371477370713100146610ustar00rootroot00000000000000[x] load content of template and script files from background via Experiment [x] parse templates and script files from background [x] swap in compose script code and make it use files loaded from background [x] make settings window update/reparse templates [x] eliminate template setter [x] replace and properly implement file picker [x] replace most of utils.mjs and email-addresses.mjs with messengerUtilities API [x] implement choice via popover [x] migrate templates to local storage (keep XML files as backup) and decouple XUL settings dialog from Experiment usage as much as possible [x] properly implement startup imports [x] rename group to groups everywhere [x] find a preliminary solution for scripts, looks like this will not work without breaking existing scripts :-( (they have to use WebExtension code) [x] replace popover by popup, composer gets into an invalid state and many other issues [x] change composer toolbar Experiment to use templates from storage [x] change composer toolbar Experiment to use notifytools to trigger actions [x] implement toolbar reload on template change and time change [x] replace compose action button by menu typed action button [x] remove as much legacy Quicktext code as possible [ ] move composer toolbar Experiment into a separate add-on [x] make template manager use files loaded from background [ ] replace XUL template manager with HTML template manager [ ] add gallery for attachments, images and text files, which are currently references via file system paths, which will not work as a pure webextension [x] keyword + special seems to eat the leading spacequicktext-6.3.2/README.md000066400000000000000000000026061477370713100150400ustar00rootroot00000000000000[Quicktext](https://addons.thunderbird.net/addon/quicktext/) is a [Thunderbird](https://www.thunderbird.net/) extension, which has been created by Emil Hesslow. However, he was no longer able to update Quicktext or provide any kind of support. Thankfully he changed the license of Quicktext to MPL 2.0, so I could continue to update the extension and make it work with the most recent version of Thunderbird. I will try to keep Quicktext going, but support will be limited. You may use the [issue section](https://github.com/jobisoft/quicktext/issues) of this repository to report bugs. You may also discuss Quicktext related issues with other users at https://discourse.mozilla.org/c/thunderbird. **Note**: Emil maintained two versions of Quicktext, a free “Standard” version and a paid “Pro” version with additional features. Since he released both versions under MPL 2.0, the [official version of Quicktext](https://addons.thunderbird.net/addon/quicktext/) is based on the “Pro” version. However, the name of the extension remains just “Quicktext”. There is no longer a seperate Quicktext Pro version. More information and usage descriptions can be found in the [wiki](https://github.com/jobisoft/quicktext/wiki) of this repository. **The latest release and a change log can be found on [addons.thunderbird.net](https://addons.thunderbird.net/en-US/thunderbird/addon/quicktext/versions/)**. quicktext-6.3.2/_locales/000077500000000000000000000000001477370713100153365ustar00rootroot00000000000000quicktext-6.3.2/_locales/cs/000077500000000000000000000000001477370713100157435ustar00rootroot00000000000000quicktext-6.3.2/_locales/cs/messages.json000066400000000000000000000252401477370713100204500ustar00rootroot00000000000000{ "altKey": { "message": "Alt" }, "attachmentFile": { "message": "Vyberte soubor, který se má přidat do příloh" }, "controlKey": { "message": "Ctrl" }, "date": { "message": "Datum ($P1$)", "placeholders": { "P1": { "content": "$1" } } }, "exportFile": { "message": "Vyberte pro exportování (UTF-8)" }, "extensionDescription": { "message": "Přidá panel nástrojů do okna pro úpravy e-mailu, takže přidání standardního textu je rychlé a snadné. Je také možné použít proměnné jako [[TO=firstname]]." }, "fileNotUTF8": { "message": "Vybraný soubor zřejmě není kódovaný v UTF-8 a nebude správně načten. Vyberte prosím jiný soubor." }, "group": { "message": "Skupina" }, "importFile": { "message": "Vybarte soubor k importování (UTF-8)" }, "inputText": { "message": "Zadejte hodnotu $P1$", "placeholders": { "P1": { "content": "$1" } } }, "inputTitle": { "message": "Hodnota proměnné" }, "insertFile": { "message": "Vyberte soubor k vložení (UTF-8)" }, "insertImage": { "message": "Vyberte soubor obrázku ke vložení" }, "metaKey": { "message": "Meta" }, "newGroup": { "message": "Nová skupina" }, "newScript": { "message": "Nový skript" }, "newTemplate": { "message": "Nová šablona" }, "quicktext.HTML.label": { "message": "HTML" }, "quicktext.accesskey.addGroup": { "message": "p" }, "quicktext.accesskey.addScript": { "message": "t" }, "quicktext.accesskey.addTemplate": { "message": "l" }, "quicktext.accesskey.close": { "message": "z" }, "quicktext.accesskey.communityScripts": { "message": "s" }, "quicktext.accesskey.export": { "message": "o" }, "quicktext.accesskey.file": { "message": "b" }, "quicktext.accesskey.general": { "message": "g" }, "quicktext.accesskey.goToHomepage": { "message": "w" }, "quicktext.accesskey.help": { "message": "p" }, "quicktext.accesskey.import": { "message": "r" }, "quicktext.accesskey.remove": { "message": "v" }, "quicktext.accesskey.resetCounter": { "message": "u" }, "quicktext.accesskey.save": { "message": "s" }, "quicktext.accesskey.scripts": { "message": "s" }, "quicktext.accesskey.settings": { "message": "n" }, "quicktext.accesskey.templates": { "message": "y" }, "quicktext.accesskeyScripts.export": { "message": "x" }, "quicktext.accesskeyScripts.import": { "message": "m" }, "quicktext.accesskeyTemplate.export": { "message": "e" }, "quicktext.accesskeyTemplate.import": { "message": "i" }, "quicktext.addGroup.label": { "message": "Přidat skupinu" }, "quicktext.addScript.label": { "message": "Přidat skript" }, "quicktext.addTemplate.label": { "message": "Přidat šablonu" }, "quicktext.altKey.label": { "message": "Alt" }, "quicktext.attachments.label": { "message": "Přílohy" }, "quicktext.browse.label": { "message": "Procházet" }, "quicktext.cellularnumber.label": { "message": "Mobilní telefon" }, "quicktext.clipboard.label": { "message": "Schránka" }, "quicktext.close.label": { "message": "Zavřít" }, "quicktext.collapseSetting.label": { "message": "Skrývat názvy skupin, pokud obsahují jen jednu šablonu" }, "quicktext.controlKey.label": { "message": "Ctrl" }, "quicktext.counter.label": { "message": "Počítadlo" }, "quicktext.cursor.label": { "message": "Nastavit pozici kurzoru" }, "quicktext.custom1.label": { "message": "Vlastní 1" }, "quicktext.custom2.label": { "message": "Vlastní 2" }, "quicktext.custom3.label": { "message": "Vlastní 3" }, "quicktext.custom4.label": { "message": "Vlastní 4" }, "quicktext.dateTime.label": { "message": "Datum/čas" }, "quicktext.defaultImport.label": { "message": "Importovat po spuštění" }, "quicktext.displayname.label": { "message": "Zobrazované jméno" }, "quicktext.email.label": { "message": "E-mail" }, "quicktext.enterKey.label": { "message": "Enter" }, "quicktext.export.label": { "message": "Exportovat" }, "quicktext.f11Key.label": { "message": "F11" }, "quicktext.f12Key.label": { "message": "F12" }, "quicktext.f2Key.label": { "message": "F2" }, "quicktext.f4Key.label": { "message": "F4" }, "quicktext.f5Key.label": { "message": "F5" }, "quicktext.f8Key.label": { "message": "F8" }, "quicktext.faxnumber.label": { "message": "Fax" }, "quicktext.file.label": { "message": "Soubor" }, "quicktext.filename.label": { "message": "Název souboru" }, "quicktext.filenameAndSize.label": { "message": "Název souboru a velikost" }, "quicktext.firstname.label": { "message": "Jméno" }, "quicktext.from.label": { "message": "Od" }, "quicktext.fullname.label": { "message": "Celé jméno" }, "quicktext.general.label": { "message": "Obecné" }, "quicktext.getScript.label": { "message": "Komunitní skripty" }, "quicktext.goToHomepage.label": { "message": "Přejít na webové stránky" }, "quicktext.group.label": { "message": "Skupina" }, "quicktext.header.label": { "message": "Přidat záhlaví (komu, kopie, skrytá kopie)" }, "quicktext.help.label": { "message": "Nápověda" }, "quicktext.homenumber.label": { "message": "Telefon domů" }, "quicktext.image.label": { "message": "Vložený HTML obrázek" }, "quicktext.import.label": { "message": "Importovat" }, "quicktext.input.label": { "message": "Vstupní hodnota zadaná uživatelem" }, "quicktext.insertAs.label": { "message": "Vložit jako" }, "quicktext.insertTextFromFileAsHTML.label": { "message": "Vložit soubor jako HTML" }, "quicktext.insertTextFromFileAsText.label": { "message": "Vložit soubor jako text" }, "quicktext.insertfile.label": { "message": "Obsah ze souboru (Quicktext proměnné budou nahrazeny)" }, "quicktext.jobtitle.label": { "message": "Pozice" }, "quicktext.keyword.label": { "message": "Klíčové slovo" }, "quicktext.keywordKeySetting.label": { "message": "je klávesa, kterou chci aktivovat klíčové slovo" }, "quicktext.label": { "message": "Quicktext" }, "quicktext.lastname.label": { "message": "Příjmení" }, "quicktext.metaKey.label": { "message": "Meta" }, "quicktext.modifierSetting.label": { "message": "je modifikátor, který chci používat pro klávesové zkratky" }, "quicktext.nickname.label": { "message": "Přezdívka" }, "quicktext.none.label": { "message": "Žádná" }, "quicktext.orgatt.label": { "message": "Informace o původní příloze" }, "quicktext.orgheader.label": { "message": "Informace o původním záhlaví" }, "quicktext.other.label": { "message": "Ostatní" }, "quicktext.remove.label": { "message": "Odstranit" }, "quicktext.resetcounter.label": { "message": "Vynulovat počítadlo" }, "quicktext.showContextMenu.label": { "message": "Zobrazovat Quicktext v nabídce pod pravým tlačítkem myši" }, "quicktext.save.label": { "message": "Uložit" }, "quicktext.script.label": { "message": "Skript" }, "quicktext.scripts.label": { "message": "Skripty" }, "quicktext.selection.label": { "message": "Výběr" }, "quicktext.settings.label": { "message": "Nastavení" }, "quicktext.settings.title": { "message": "Nastavení Quicktext" }, "quicktext.sharingScripts.label": { "message": "Sdílení skriptů" }, "quicktext.sharingTemplates.label": { "message": "Sdílení šablon" }, "quicktext.shortcut.label": { "message": "Zkratka" }, "quicktext.shortcutTypeAdv.label": { "message": "Používat pokročilý režim zkratek" }, "quicktext.shortname.label": { "message": "Quicktext" }, "quicktext.spaceKey.label": { "message": "Mezera" }, "quicktext.subject.label": { "message": "Předmět" }, "quicktext.tabKey.label": { "message": "Tab" }, "quicktext.template.label": { "message": "Šablona" }, "quicktext.templates.label": { "message": "Šablony" }, "quicktext.text.label": { "message": "Text" }, "quicktext.title.label": { "message": "Název" }, "quicktext.to.label": { "message": "Komu" }, "quicktext.url.label": { "message": "Odpověď z URL" }, "quicktext.variables.label": { "message": "Proměnné" }, "quicktext.version.label": { "message": "Verze Thunderbirdu" }, "quicktext.workphone.label": { "message": "Telefon do zaměstnání" }, "remove": { "message": "Opravdu chcete odstranit “$P1$”?", "placeholders": { "P1": { "content": "$1" } } }, "saveMessage": { "message": "Vaše změny nebyly uloženy. Chcete je uložit?" }, "saveMessageTitle": { "message": "Uložit nastavení" }, "scriptError": { "message": "Ve vašem Quicktext skriptu se objevila chyba:" }, "scriptLine": { "message": "Řádek" }, "scriptNotFound": { "message": "Quicktext script “$P1$” not found!", "placeholders": { "P1": { "content": "$1" } } }, "template": { "message": "Šablona" }, "time": { "message": "Čas ($P1$)", "placeholders": { "P1": { "content": "$1" } } } } quicktext-6.3.2/_locales/de/000077500000000000000000000000001477370713100157265ustar00rootroot00000000000000quicktext-6.3.2/_locales/de/messages.json000066400000000000000000000252731477370713100204410ustar00rootroot00000000000000{ "altKey": { "message": "Alt" }, "attachmentFile": { "message": "Datei zum Anhängen auswählen" }, "controlKey": { "message": "Strg" }, "date": { "message": "Datum ($P1$)", "placeholders": { "P1": { "content": "$1" } } }, "exportFile": { "message": "Datei zum Exportieren auswählen (UTF-8)" }, "extensionDescription": { "message": "Fügt eine Symbolleiste zum E-Mail-Bearbeitenfenster hinzu, sodass Textbausteine einfach und schnell hinzugefügt werden können. Es ist auch möglich, Variablen wie [[TO=firstname]] zu verwenden." }, "fileNotUTF8": { "message": "Die ausgewählte Datei scheint nicht UTF-8-codiert zu sein und kann nicht korrekt geladen werden. Bitte wählen Sie eine andere Datei." }, "group": { "message": "Gruppe" }, "importFile": { "message": "Datei zum Importieren auswählen (UTF-8)" }, "inputText": { "message": "Wert für $P1$ eingeben", "placeholders": { "P1": { "content": "$1" } } }, "inputTitle": { "message": "Variablenwert" }, "insertFile": { "message": "Datei zum Einfügen auswählen (UTF-8)" }, "insertImage": { "message": "Bilddatei zum Einfügen auswählen" }, "metaKey": { "message": "Meta" }, "newGroup": { "message": "Neue Gruppe" }, "newScript": { "message": "Neues Skript" }, "newTemplate": { "message": "Neue Vorlage" }, "quicktext.HTML.label": { "message": "HTML" }, "quicktext.accesskey.addGroup": { "message": "p" }, "quicktext.accesskey.addScript": { "message": "t" }, "quicktext.accesskey.addTemplate": { "message": "l" }, "quicktext.accesskey.close": { "message": "c" }, "quicktext.accesskey.communityScripts": { "message": "r" }, "quicktext.accesskey.export": { "message": "o" }, "quicktext.accesskey.file": { "message": "d" }, "quicktext.accesskey.general": { "message": "a" }, "quicktext.accesskey.goToHomepage": { "message": "w" }, "quicktext.accesskey.help": { "message": "h" }, "quicktext.accesskey.import": { "message": "r" }, "quicktext.accesskey.remove": { "message": "f" }, "quicktext.accesskey.resetCounter": { "message": "u" }, "quicktext.accesskey.save": { "message": "s" }, "quicktext.accesskey.scripts": { "message": "k" }, "quicktext.accesskey.settings": { "message": "n" }, "quicktext.accesskey.templates": { "message": "v" }, "quicktext.accesskeyScripts.export": { "message": "x" }, "quicktext.accesskeyScripts.import": { "message": "m" }, "quicktext.accesskeyTemplate.export": { "message": "e" }, "quicktext.accesskeyTemplate.import": { "message": "i" }, "quicktext.addGroup.label": { "message": "Gruppe hinzufügen" }, "quicktext.addScript.label": { "message": "Skript hinzufügen" }, "quicktext.addTemplate.label": { "message": "Vorlage hinzufügen" }, "quicktext.altKey.label": { "message": "Alt" }, "quicktext.attachments.label": { "message": "Anhang" }, "quicktext.browse.label": { "message": "Suchen" }, "quicktext.cellularnumber.label": { "message": "Mobil" }, "quicktext.clipboard.label": { "message": "Zwischenablage" }, "quicktext.close.label": { "message": "Schließen" }, "quicktext.collapseSetting.label": { "message": "Zusammenklappen, wenn die Gruppe nur eine Vorlage enthält" }, "quicktext.controlKey.label": { "message": "Strg" }, "quicktext.counter.label": { "message": "Zähler" }, "quicktext.cursor.label": { "message": "Eingabemarke positionieren" }, "quicktext.custom1.label": { "message": "Benutzerdef. 1" }, "quicktext.custom2.label": { "message": "Benutzerdef. 2" }, "quicktext.custom3.label": { "message": "Benutzerdef. 3" }, "quicktext.custom4.label": { "message": "Benutzerdef. 4" }, "quicktext.dateTime.label": { "message": "Datum/Zeit" }, "quicktext.defaultImport.label": { "message": "Beim Start importieren" }, "quicktext.displayname.label": { "message": "Anzeigename" }, "quicktext.email.label": { "message": "E-Mail" }, "quicktext.enterKey.label": { "message": "Eingabe" }, "quicktext.export.label": { "message": "Exportieren" }, "quicktext.f11Key.label": { "message": "F11" }, "quicktext.f12Key.label": { "message": "F12" }, "quicktext.f2Key.label": { "message": "F2" }, "quicktext.f4Key.label": { "message": "F4" }, "quicktext.f5Key.label": { "message": "F5" }, "quicktext.f8Key.label": { "message": "F8" }, "quicktext.faxnumber.label": { "message": "Fax" }, "quicktext.file.label": { "message": "Datei" }, "quicktext.filename.label": { "message": "Dateiname" }, "quicktext.filenameAndSize.label": { "message": "Dateiname und -größe" }, "quicktext.firstname.label": { "message": "Vorname" }, "quicktext.from.label": { "message": "Von" }, "quicktext.fullname.label": { "message": "vollständiger Name" }, "quicktext.general.label": { "message": "Allgemein" }, "quicktext.getScript.label": { "message": "Gemeinsame Skripte" }, "quicktext.goToHomepage.label": { "message": "Zur Website" }, "quicktext.group.label": { "message": "Gruppe" }, "quicktext.header.label": { "message": "Kopfzeile (To, Cc, Bcc) hinzufügen" }, "quicktext.help.label": { "message": "Hilfe" }, "quicktext.homenumber.label": { "message": "Tel. Privat" }, "quicktext.image.label": { "message": "Eingebettetes HTML-Bild" }, "quicktext.import.label": { "message": "Importieren" }, "quicktext.input.label": { "message": "Eingabewert von einer Eingabeaufforderung" }, "quicktext.insertAs.label": { "message": "Einfügen als" }, "quicktext.insertTextFromFileAsHTML.label": { "message": "Datei als HTML einfügen" }, "quicktext.insertTextFromFileAsText.label": { "message": "Datei als Text einfügen" }, "quicktext.insertfile.label": { "message": "Inhalt einer Datei (Quicktext-Variablen werden ersetzt)" }, "quicktext.jobtitle.label": { "message": "Titel (dienstlich)" }, "quicktext.keyword.label": { "message": "Schlüsselwort" }, "quicktext.keywordKeySetting.label": { "message": "zum Aktivieren eines Schlüsselwortes verwenden" }, "quicktext.label": { "message": "Quicktext" }, "quicktext.lastname.label": { "message": "Name" }, "quicktext.metaKey.label": { "message": "Meta" }, "quicktext.modifierSetting.label": { "message": "für Tastenkürzel verwenden" }, "quicktext.nickname.label": { "message": "Spitzname" }, "quicktext.none.label": { "message": "Keine" }, "quicktext.orgatt.label": { "message": "Ursprüngliche Anhanginformationen" }, "quicktext.orgheader.label": { "message": "Ursprüngliche Kopfzeileninformationen" }, "quicktext.other.label": { "message": "Andere" }, "quicktext.remove.label": { "message": "Entfernen" }, "quicktext.resetcounter.label": { "message": "Zähler zurücksetzen" }, "quicktext.showContextMenu.label": { "message": "Quicktext-Menü bei Rechtsklick anzeigen" }, "quicktext.save.label": { "message": "Speichern" }, "quicktext.script.label": { "message": "Skript" }, "quicktext.scripts.label": { "message": "Skripte" }, "quicktext.selection.label": { "message": "Markierter Text" }, "quicktext.settings.label": { "message": "Einstellungen" }, "quicktext.settings.title": { "message": "Quicktext-Einstellungen" }, "quicktext.sharingScripts.label": { "message": "Skripte" }, "quicktext.sharingTemplates.label": { "message": "Vorlagen" }, "quicktext.shortcut.label": { "message": "Tastenkürzel" }, "quicktext.shortcutTypeAdv.label": { "message": "Erweiterten Modus für Tastaturkürzel verwenden" }, "quicktext.shortname.label": { "message": "Quicktext" }, "quicktext.spaceKey.label": { "message": "Leertaste" }, "quicktext.subject.label": { "message": "Betreff" }, "quicktext.tabKey.label": { "message": "Tab" }, "quicktext.template.label": { "message": "Vorlage" }, "quicktext.templates.label": { "message": "Vorlagen" }, "quicktext.text.label": { "message": "Text" }, "quicktext.title.label": { "message": "Titel" }, "quicktext.to.label": { "message": "An" }, "quicktext.url.label": { "message": "Rückgabewert einer URL-Anfrage" }, "quicktext.variables.label": { "message": "Variablen" }, "quicktext.version.label": { "message": "Thunderbird-Version" }, "quicktext.workphone.label": { "message": "Tel. dienstlich" }, "remove": { "message": "Sind Sie sicher, dass „$P1$“ entfernt werden soll?", "placeholders": { "P1": { "content": "$1" } } }, "saveMessage": { "message": "Ihre Änderungen wurden noch nicht gespeichert. Jetzt speichern?" }, "saveMessageTitle": { "message": "Einstellungen speichern" }, "scriptError": { "message": "In Ihrem Quicktext-Skript ist ein Fehler aufgetreten:" }, "scriptLine": { "message": "Zeile" }, "scriptNotFound": { "message": "Quicktext-Skript „$P1$“ nicht gefunden!", "placeholders": { "P1": { "content": "$1" } } }, "template": { "message": "Vorlage" }, "time": { "message": "Uhrzeit ($P1$)", "placeholders": { "P1": { "content": "$1" } } } } quicktext-6.3.2/_locales/en-US/000077500000000000000000000000001477370713100162655ustar00rootroot00000000000000quicktext-6.3.2/_locales/en-US/messages.json000066400000000000000000000245311477370713100207740ustar00rootroot00000000000000{ "altKey": { "message": "Alt" }, "attachmentFile": { "message": "Choose file to add to attachments" }, "controlKey": { "message": "Ctrl" }, "date": { "message": "Date ($P1$)", "placeholders": { "P1": { "content": "$1" } } }, "exportFile": { "message": "Choose file to export to (UTF-8)" }, "extensionDescription": { "message": "Adds a toolbar with unlimited number of text to quickly insert. It is also possible to use variables like [[TO=firstname]]. With settings for everything." }, "fileNotUTF8": { "message": "The selected file does not seem to be UTF-8 encoded and will not loaded correctly. Please select a different file." }, "group": { "message": "Group" }, "importFile": { "message": "Choose file to import (UTF-8)" }, "inputText": { "message": "Input the value of $P1$", "placeholders": { "P1": { "content": "$1" } } }, "inputTitle": { "message": "Variable value" }, "insertFile": { "message": "Choose file to insert (UTF-8)" }, "insertImage": { "message": "Choose image file to insert" }, "metaKey": { "message": "Meta" }, "newGroup": { "message": "New group" }, "newScript": { "message": "New script" }, "newTemplate": { "message": "New template" }, "quicktext.HTML.label": { "message": "HTML" }, "quicktext.accesskey.addGroup": { "message": "p" }, "quicktext.accesskey.addScript": { "message": "t" }, "quicktext.accesskey.addTemplate": { "message": "l" }, "quicktext.accesskey.close": { "message": "c" }, "quicktext.accesskey.communityScripts": { "message": "s" }, "quicktext.accesskey.export": { "message": "o" }, "quicktext.accesskey.file": { "message": "f" }, "quicktext.accesskey.general": { "message": "g" }, "quicktext.accesskey.goToHomepage": { "message": "h" }, "quicktext.accesskey.help": { "message": "p" }, "quicktext.accesskey.import": { "message": "r" }, "quicktext.accesskey.remove": { "message": "v" }, "quicktext.accesskey.resetCounter": { "message": "u" }, "quicktext.accesskey.save": { "message": "s" }, "quicktext.accesskey.scripts": { "message": "s" }, "quicktext.accesskey.settings": { "message": "n" }, "quicktext.accesskey.templates": { "message": "t" }, "quicktext.accesskeyScripts.export": { "message": "x" }, "quicktext.accesskeyScripts.import": { "message": "m" }, "quicktext.accesskeyTemplate.export": { "message": "e" }, "quicktext.accesskeyTemplate.import": { "message": "i" }, "quicktext.addGroup.label": { "message": "Add group" }, "quicktext.addScript.label": { "message": "Add script" }, "quicktext.addTemplate.label": { "message": "Add template" }, "quicktext.altKey.label": { "message": "Alt" }, "quicktext.attachments.label": { "message": "Attachments" }, "quicktext.browse.label": { "message": "Browse" }, "quicktext.cellularnumber.label": { "message": "Cellularnumber" }, "quicktext.clipboard.label": { "message": "Clipboard" }, "quicktext.close.label": { "message": "Close" }, "quicktext.collapseSetting.label": { "message": "Collapse group when it only contains one template" }, "quicktext.controlKey.label": { "message": "Ctrl" }, "quicktext.counter.label": { "message": "Counter" }, "quicktext.cursor.label": { "message": "Set cursor position" }, "quicktext.custom1.label": { "message": "Custom 1" }, "quicktext.custom2.label": { "message": "Custom 2" }, "quicktext.custom3.label": { "message": "Custom 3" }, "quicktext.custom4.label": { "message": "Custom 4" }, "quicktext.dateTime.label": { "message": "Date/Time" }, "quicktext.defaultImport.label": { "message": "Import on startup" }, "quicktext.displayname.label": { "message": "Displayname" }, "quicktext.email.label": { "message": "Email" }, "quicktext.enterKey.label": { "message": "Enter" }, "quicktext.export.label": { "message": "Export" }, "quicktext.f11Key.label": { "message": "F11" }, "quicktext.f12Key.label": { "message": "F12" }, "quicktext.f2Key.label": { "message": "F2" }, "quicktext.f4Key.label": { "message": "F4" }, "quicktext.f5Key.label": { "message": "F5" }, "quicktext.f8Key.label": { "message": "F8" }, "quicktext.faxnumber.label": { "message": "Faxnumber" }, "quicktext.file.label": { "message": "File" }, "quicktext.filename.label": { "message": "Filename" }, "quicktext.filenameAndSize.label": { "message": "Filename and size" }, "quicktext.firstname.label": { "message": "Firstname" }, "quicktext.from.label": { "message": "From" }, "quicktext.fullname.label": { "message": "Fullname" }, "quicktext.general.label": { "message": "General" }, "quicktext.getScript.label": { "message": "Community scripts" }, "quicktext.goToHomepage.label": { "message": "Go to homepage" }, "quicktext.group.label": { "message": "Group" }, "quicktext.header.label": { "message": "Add header (To, Cc, Bcc)" }, "quicktext.help.label": { "message": "Help" }, "quicktext.homenumber.label": { "message": "Homenumber" }, "quicktext.image.label": { "message": "Embedded HTML image" }, "quicktext.import.label": { "message": "Import" }, "quicktext.input.label": { "message": "Input value from user prompt" }, "quicktext.insertAs.label": { "message": "Insert as" }, "quicktext.insertTextFromFileAsHTML.label": { "message": "Insert file as HTML" }, "quicktext.insertTextFromFileAsText.label": { "message": "Insert file as text" }, "quicktext.insertfile.label": { "message": "Content from file (quicktext variables will be replaced)" }, "quicktext.jobtitle.label": { "message": "Jobtitle" }, "quicktext.keyword.label": { "message": "Keyword" }, "quicktext.keywordKeySetting.label": { "message": "is the key I want to use for activating a keyword" }, "quicktext.label": { "message": "Quicktext" }, "quicktext.lastname.label": { "message": "Lastname" }, "quicktext.metaKey.label": { "message": "Meta" }, "quicktext.modifierSetting.label": { "message": "is the modifier I want to use for the keyboard shortcuts" }, "quicktext.nickname.label": { "message": "Nickname" }, "quicktext.none.label": { "message": "None" }, "quicktext.orgatt.label": { "message": "Original attachment info" }, "quicktext.orgheader.label": { "message": "Original header info" }, "quicktext.other.label": { "message": "Other" }, "quicktext.remove.label": { "message": "Remove" }, "quicktext.resetcounter.label": { "message": "Reset counter" }, "quicktext.showContextMenu.label": { "message": "Show Quicktext-menu on right-click" }, "quicktext.save.label": { "message": "Save" }, "quicktext.script.label": { "message": "Script" }, "quicktext.scripts.label": { "message": "Scripts" }, "quicktext.selection.label": { "message": "Selection" }, "quicktext.settings.label": { "message": "Settings" }, "quicktext.settings.title": { "message": "Quicktext Settings" }, "quicktext.sharingScripts.label": { "message": "Sharing scripts" }, "quicktext.sharingTemplates.label": { "message": "Sharing templates" }, "quicktext.shortcut.label": { "message": "Shortcut" }, "quicktext.shortcutTypeAdv.label": { "message": "Use advanced mode for shortcuts" }, "quicktext.shortname.label": { "message": "Quicktext" }, "quicktext.spaceKey.label": { "message": "Space" }, "quicktext.subject.label": { "message": "Subject" }, "quicktext.tabKey.label": { "message": "Tab" }, "quicktext.template.label": { "message": "Template" }, "quicktext.templates.label": { "message": "Templates" }, "quicktext.text.label": { "message": "Text" }, "quicktext.title.label": { "message": "Title" }, "quicktext.to.label": { "message": "To" }, "quicktext.url.label": { "message": "Response from URL" }, "quicktext.variables.label": { "message": "Variables" }, "quicktext.version.label": { "message": "Thunderbird version" }, "quicktext.workphone.label": { "message": "Worknumber" }, "remove": { "message": "Are you sure you want to remove “$P1$”?", "placeholders": { "P1": { "content": "$1" } } }, "saveMessage": { "message": "Your changes has not been saved. Do you want to save them?" }, "saveMessageTitle": { "message": "Save settings" }, "scriptError": { "message": "There was an error in your Quicktext script:" }, "scriptLine": { "message": "Line" }, "scriptNotFound": { "message": "Quicktext script “$P1$” not found!", "placeholders": { "P1": { "content": "$1" } } }, "template": { "message": "Template" }, "time": { "message": "Time ($P1$)", "placeholders": { "P1": { "content": "$1" } } } } quicktext-6.3.2/_locales/es/000077500000000000000000000000001477370713100157455ustar00rootroot00000000000000quicktext-6.3.2/_locales/es/messages.json000066400000000000000000000252641477370713100204600ustar00rootroot00000000000000{ "altKey": { "message": "Alt" }, "attachmentFile": { "message": "Elegir archivo para añadir a los adjuntos" }, "controlKey": { "message": "Ctrl" }, "date": { "message": "Fecha ($P1$)", "placeholders": { "P1": { "content": "$1" } } }, "exportFile": { "message": "Elegir archivo para exportar a (UTF-8)" }, "extensionDescription": { "message": "Agrega una barra de herramientas con un número ilimitado de texto para insertar rápidamente. También es posible usar variables como [[TO=firstname]]. Con ajustes para todo." }, "fileNotUTF8": { "message": "El archivo seleccionado paraece no estar codificado en UTF-8 y no se ha cargado correctamente. Por favor, selecciona nuevo archivo." }, "group": { "message": "Grupo" }, "importFile": { "message": "Elegir archivo a importar (UTF-8)" }, "inputText": { "message": "Introducir el valor de $P1$", "placeholders": { "P1": { "content": "$1" } } }, "inputTitle": { "message": "Valor variable" }, "insertFile": { "message": "Elegir archivo a insertar (UTF-8)" }, "insertImage": { "message": "Elegir archivo de imagen a insertar" }, "metaKey": { "message": "Meta" }, "newGroup": { "message": "Nuevo grupo" }, "newScript": { "message": "Nuevo script" }, "newTemplate": { "message": "Nueva plantilla" }, "quicktext.HTML.label": { "message": "HTML" }, "quicktext.accesskey.addGroup": { "message": "p" }, "quicktext.accesskey.addScript": { "message": "t" }, "quicktext.accesskey.addTemplate": { "message": "l" }, "quicktext.accesskey.close": { "message": "c" }, "quicktext.accesskey.communityScripts": { "message": "s" }, "quicktext.accesskey.export": { "message": "o" }, "quicktext.accesskey.file": { "message": "a" }, "quicktext.accesskey.general": { "message": "g" }, "quicktext.accesskey.goToHomepage": { "message": "h" }, "quicktext.accesskey.help": { "message": "y" }, "quicktext.accesskey.import": { "message": "r" }, "quicktext.accesskey.remove": { "message": "v" }, "quicktext.accesskey.resetCounter": { "message": "d" }, "quicktext.accesskey.save": { "message": "u" }, "quicktext.accesskey.scripts": { "message": "s" }, "quicktext.accesskey.settings": { "message": "n" }, "quicktext.accesskey.templates": { "message": "t" }, "quicktext.accesskeyScripts.export": { "message": "x" }, "quicktext.accesskeyScripts.import": { "message": "m" }, "quicktext.accesskeyTemplate.export": { "message": "e" }, "quicktext.accesskeyTemplate.import": { "message": "i" }, "quicktext.addGroup.label": { "message": "Agregar grupo" }, "quicktext.addScript.label": { "message": "Agregar script" }, "quicktext.addTemplate.label": { "message": "Agregar plantilla" }, "quicktext.altKey.label": { "message": "Alt" }, "quicktext.attachments.label": { "message": "Adjuntos" }, "quicktext.browse.label": { "message": "Navegar" }, "quicktext.cellularnumber.label": { "message": "Número de móvil" }, "quicktext.clipboard.label": { "message": "Portapapeles" }, "quicktext.close.label": { "message": "Cerrar" }, "quicktext.collapseSetting.label": { "message": "Colapsar grupos cuando solo contengan una plantilla" }, "quicktext.controlKey.label": { "message": "Ctrl" }, "quicktext.counter.label": { "message": "Counter" }, "quicktext.cursor.label": { "message": "Posición del cursos" }, "quicktext.custom1.label": { "message": "Personalizado 1" }, "quicktext.custom2.label": { "message": "Personalizado 2" }, "quicktext.custom3.label": { "message": "Personalizado 3" }, "quicktext.custom4.label": { "message": "Personalizado 4" }, "quicktext.dateTime.label": { "message": "Fecha/Hora" }, "quicktext.defaultImport.label": { "message": "Importar al arrancar" }, "quicktext.displayname.label": { "message": "Nombre mostrado" }, "quicktext.email.label": { "message": "Email" }, "quicktext.enterKey.label": { "message": "Intro" }, "quicktext.export.label": { "message": "Exportar" }, "quicktext.f11Key.label": { "message": "F11" }, "quicktext.f12Key.label": { "message": "F12" }, "quicktext.f2Key.label": { "message": "F2" }, "quicktext.f4Key.label": { "message": "F4" }, "quicktext.f5Key.label": { "message": "F5" }, "quicktext.f8Key.label": { "message": "F8" }, "quicktext.faxnumber.label": { "message": "Número de fax" }, "quicktext.file.label": { "message": "Archivo" }, "quicktext.filename.label": { "message": "Nombre del fichero" }, "quicktext.filenameAndSize.label": { "message": "Nombre del fichero y tamaño" }, "quicktext.firstname.label": { "message": "Nombre" }, "quicktext.from.label": { "message": "De" }, "quicktext.fullname.label": { "message": "Nombre completo" }, "quicktext.general.label": { "message": "General" }, "quicktext.getScript.label": { "message": "Community Scripts" }, "quicktext.goToHomepage.label": { "message": "Ir a la página de inicio" }, "quicktext.group.label": { "message": "Grupo" }, "quicktext.header.label": { "message": "Cabecera (A, Cc, Bcc)" }, "quicktext.help.label": { "message": "Ayuda" }, "quicktext.homenumber.label": { "message": "Número de casa" }, "quicktext.image.label": { "message": "Embedded HTML image" }, "quicktext.import.label": { "message": "Importar" }, "quicktext.input.label": { "message": "Input value from user prompt" }, "quicktext.insertAs.label": { "message": "Insertar como" }, "quicktext.insertTextFromFileAsHTML.label": { "message": "Insertar archivo como HTML" }, "quicktext.insertTextFromFileAsText.label": { "message": "Insertar archivo como texto" }, "quicktext.insertfile.label": { "message": "Content from file (quicktext variables will be replaced)" }, "quicktext.jobtitle.label": { "message": "Trabajo" }, "quicktext.keyword.label": { "message": "Palabra clave" }, "quicktext.keywordKeySetting.label": { "message": "es la tecla que quiero usar para activar una palabra clave" }, "quicktext.label": { "message": "Quicktext" }, "quicktext.lastname.label": { "message": "Apellidos" }, "quicktext.metaKey.label": { "message": "Meta" }, "quicktext.modifierSetting.label": { "message": "es el modificador que quiero usar para el acceso directo del teclado" }, "quicktext.nickname.label": { "message": "Apodo" }, "quicktext.none.label": { "message": "Ninguno" }, "quicktext.orgatt.label": { "message": "Original attachment info" }, "quicktext.orgheader.label": { "message": "Original header info" }, "quicktext.other.label": { "message": "Otro" }, "quicktext.remove.label": { "message": "Eliminar" }, "quicktext.resetcounter.label": { "message": "Reiniciar contador" }, "quicktext.showContextMenu.label": { "message": "Ver menu-Quicktext con la pulsación del botón derecho del ratón" }, "quicktext.save.label": { "message": "Guardar" }, "quicktext.script.label": { "message": "Script" }, "quicktext.scripts.label": { "message": "Scripts" }, "quicktext.selection.label": { "message": "Selección" }, "quicktext.settings.label": { "message": "Opciones" }, "quicktext.settings.title": { "message": "Opciones de Quicktext" }, "quicktext.sharingScripts.label": { "message": "Compartiendo scripts" }, "quicktext.sharingTemplates.label": { "message": "Compartiendo plantillas" }, "quicktext.shortcut.label": { "message": "Acceso directo" }, "quicktext.shortcutTypeAdv.label": { "message": "Usar el modo avanzado para los accesos directos" }, "quicktext.shortname.label": { "message": "Quicktext" }, "quicktext.spaceKey.label": { "message": "Espacio" }, "quicktext.subject.label": { "message": "Asunto" }, "quicktext.tabKey.label": { "message": "Tab" }, "quicktext.template.label": { "message": "Plantilla" }, "quicktext.templates.label": { "message": "Plantillas" }, "quicktext.text.label": { "message": "Texto" }, "quicktext.title.label": { "message": "Título" }, "quicktext.to.label": { "message": "A" }, "quicktext.url.label": { "message": "Response from URL" }, "quicktext.variables.label": { "message": "Variables" }, "quicktext.version.label": { "message": "Versión del Thunderbird" }, "quicktext.workphone.label": { "message": "Número de trabajo" }, "remove": { "message": "¿Estas seguro que quieres eliminar “$P1$”?", "placeholders": { "P1": { "content": "$1" } } }, "saveMessage": { "message": "Tus cambios no se han guardado. ¿Quieres guardar los cambios?" }, "saveMessageTitle": { "message": "Guardar opciones" }, "scriptError": { "message": "Existe un error en tu script Quicktext:" }, "scriptLine": { "message": "Linea" }, "scriptNotFound": { "message": "¡Script de Quicktext “$P1$” no encontrado!", "placeholders": { "P1": { "content": "$1" } } }, "template": { "message": "Plantilla" }, "time": { "message": "Hora ($P1$)", "placeholders": { "P1": { "content": "$1" } } } } quicktext-6.3.2/_locales/fr/000077500000000000000000000000001477370713100157455ustar00rootroot00000000000000quicktext-6.3.2/_locales/fr/messages.json000066400000000000000000000254541477370713100204610ustar00rootroot00000000000000{ "altKey": { "message": "Alt" }, "attachmentFile": { "message": "Choisir le fichier à ajouter aux pièces jointes" }, "controlKey": { "message": "Ctrl" }, "date": { "message": "Date ($P1$)", "placeholders": { "P1": { "content": "$1" } } }, "exportFile": { "message": "Choisir le fichier de destination (UTF-8)" }, "extensionDescription": { "message": "Ajoute une barre d’outils à la fenêtre de composition de message afin d'insérer rapidement des modèles de texte. Il est également possible d'utiliser des variables telles que [[TO=firstname]]." }, "fileNotUTF8": { "message": "Le fichier sélectionné ne semble pas encodé UTF-8 et ne chargera pas correctement. Choisissez un autre fichier." }, "group": { "message": "Groupe" }, "importFile": { "message": "Choisir le fichier à importer (UTF-8)" }, "inputText": { "message": "Entrez la valeur de $P1$", "placeholders": { "P1": { "content": "$1" } } }, "inputTitle": { "message": "Valeur de la variable" }, "insertFile": { "message": "Choisir le fichier à insérer (UTF-8)" }, "insertImage": { "message": "Choisir le fichier d'image à insérer" }, "metaKey": { "message": "Meta" }, "newGroup": { "message": "Nouveau groupe" }, "newScript": { "message": "Nouveau script" }, "newTemplate": { "message": "Nouveau modèle" }, "quicktext.HTML.label": { "message": "HTML" }, "quicktext.accesskey.addGroup": { "message": "p" }, "quicktext.accesskey.addScript": { "message": "t" }, "quicktext.accesskey.addTemplate": { "message": "l" }, "quicktext.accesskey.close": { "message": "e" }, "quicktext.accesskey.communityScripts": { "message": "s" }, "quicktext.accesskey.export": { "message": "o" }, "quicktext.accesskey.file": { "message": "f" }, "quicktext.accesskey.general": { "message": "g" }, "quicktext.accesskey.goToHomepage": { "message": "w" }, "quicktext.accesskey.help": { "message": "d" }, "quicktext.accesskey.import": { "message": "r" }, "quicktext.accesskey.remove": { "message": "p" }, "quicktext.accesskey.resetCounter": { "message": "u" }, "quicktext.accesskey.save": { "message": "e" }, "quicktext.accesskey.scripts": { "message": "s" }, "quicktext.accesskey.settings": { "message": "s" }, "quicktext.accesskey.templates": { "message": "l" }, "quicktext.accesskeyScripts.export": { "message": "x" }, "quicktext.accesskeyScripts.import": { "message": "m" }, "quicktext.accesskeyTemplate.export": { "message": "x" }, "quicktext.accesskeyTemplate.import": { "message": "i" }, "quicktext.addGroup.label": { "message": "Ajouter un groupe" }, "quicktext.addScript.label": { "message": "Ajouter un script" }, "quicktext.addTemplate.label": { "message": "Ajouter un modèle" }, "quicktext.altKey.label": { "message": "Alt" }, "quicktext.attachments.label": { "message": "Pièces jointes" }, "quicktext.browse.label": { "message": "Parcourir" }, "quicktext.cellularnumber.label": { "message": "Portable" }, "quicktext.clipboard.label": { "message": "Presse-papiers" }, "quicktext.close.label": { "message": "Fermer" }, "quicktext.collapseSetting.label": { "message": "Masquer le groupe lorsqu'il ne contient qu'un seul modèle" }, "quicktext.controlKey.label": { "message": "Ctrl" }, "quicktext.counter.label": { "message": "Compteur" }, "quicktext.cursor.label": { "message": "Position du curseur" }, "quicktext.custom1.label": { "message": "Personnalisé-1" }, "quicktext.custom2.label": { "message": "Personnalisé-2" }, "quicktext.custom3.label": { "message": "Personnalisé-3" }, "quicktext.custom4.label": { "message": "Personnalisé-4" }, "quicktext.dateTime.label": { "message": "Date/Heure" }, "quicktext.defaultImport.label": { "message": "Importé au démarrage" }, "quicktext.displayname.label": { "message": "Nom à afficher" }, "quicktext.email.label": { "message": "Courriel" }, "quicktext.enterKey.label": { "message": "Entrée" }, "quicktext.export.label": { "message": "Exporter" }, "quicktext.f11Key.label": { "message": "F11" }, "quicktext.f12Key.label": { "message": "F12" }, "quicktext.f2Key.label": { "message": "F2" }, "quicktext.f4Key.label": { "message": "F4" }, "quicktext.f5Key.label": { "message": "F5" }, "quicktext.f8Key.label": { "message": "F8" }, "quicktext.faxnumber.label": { "message": "Télécopieur" }, "quicktext.file.label": { "message": "Fichier" }, "quicktext.filename.label": { "message": "Nom du fichier" }, "quicktext.filenameAndSize.label": { "message": "Nom et taille du fichier" }, "quicktext.firstname.label": { "message": "Prénom" }, "quicktext.from.label": { "message": "De" }, "quicktext.fullname.label": { "message": "Nom complet" }, "quicktext.general.label": { "message": "Général" }, "quicktext.getScript.label": { "message": "Scripts partagés" }, "quicktext.goToHomepage.label": { "message": "Visiter le site Web" }, "quicktext.group.label": { "message": "Groupe" }, "quicktext.header.label": { "message": "En-têtes (Pour, Cc, Cci)" }, "quicktext.help.label": { "message": "Aide" }, "quicktext.homenumber.label": { "message": "Tél. domicile" }, "quicktext.image.label": { "message": "Image HTML intégrée" }, "quicktext.import.label": { "message": "Importer" }, "quicktext.input.label": { "message": "Entrez le texte à insérer" }, "quicktext.insertAs.label": { "message": "Insérer en" }, "quicktext.insertTextFromFileAsHTML.label": { "message": "Insérer un fichier en HTML" }, "quicktext.insertTextFromFileAsText.label": { "message": "Insérer un fichier en texte" }, "quicktext.insertfile.label": { "message": "Contenu à partir d'un fichier (les variables Quicktext seront remplacées)" }, "quicktext.jobtitle.label": { "message": "Profession" }, "quicktext.keyword.label": { "message": "Mot-clé" }, "quicktext.keywordKeySetting.label": { "message": "est la touche que je veux utiliser pour activer un mot-clé" }, "quicktext.label": { "message": "Quicktext" }, "quicktext.lastname.label": { "message": "Nom" }, "quicktext.metaKey.label": { "message": "Meta" }, "quicktext.modifierSetting.label": { "message": "est la touche que je veux utiliser pour les raccourcis clavier" }, "quicktext.nickname.label": { "message": "Surnom" }, "quicktext.none.label": { "message": "Aucun" }, "quicktext.orgatt.label": { "message": "Infos des pièces jointes d'origine" }, "quicktext.orgheader.label": { "message": "Infos des en-têtes d'origine" }, "quicktext.other.label": { "message": "Autres" }, "quicktext.remove.label": { "message": "Supprimer" }, "quicktext.resetcounter.label": { "message": "Réinitialiser le compteur" }, "quicktext.showContextMenu.label": { "message": "Afficher le menu de Quicktext dans le menu contextuel (clic droit)" }, "quicktext.save.label": { "message": "Enregistrer" }, "quicktext.script.label": { "message": "Script" }, "quicktext.scripts.label": { "message": "Scripts" }, "quicktext.selection.label": { "message": "Sélection" }, "quicktext.settings.label": { "message": "Paramètres" }, "quicktext.settings.title": { "message": "Paramètres de Quicktext" }, "quicktext.sharingScripts.label": { "message": "Partage de scripts" }, "quicktext.sharingTemplates.label": { "message": "Partage de modèles" }, "quicktext.shortcut.label": { "message": "Raccourci" }, "quicktext.shortcutTypeAdv.label": { "message": "Utiliser le mode avancé pour les raccourcis clavier" }, "quicktext.shortname.label": { "message": "Quicktext" }, "quicktext.spaceKey.label": { "message": "Espace" }, "quicktext.subject.label": { "message": "Sujet" }, "quicktext.tabKey.label": { "message": "Tab" }, "quicktext.template.label": { "message": "Modèle" }, "quicktext.templates.label": { "message": "Modèles" }, "quicktext.text.label": { "message": "Texte" }, "quicktext.title.label": { "message": "Titre" }, "quicktext.to.label": { "message": "Pour" }, "quicktext.url.label": { "message": "Réponse à partir d'une URL" }, "quicktext.variables.label": { "message": "Variables" }, "quicktext.version.label": { "message": "Version de Thunderbird" }, "quicktext.workphone.label": { "message": "Tél. travail" }, "remove": { "message": "Voulez-vous vraiment supprimer « $P1$ » ?", "placeholders": { "P1": { "content": "$1" } } }, "saveMessage": { "message": "Vos modifications n'ont pas été enregistrées. Souhaitez-vous les enregistrer ?" }, "saveMessageTitle": { "message": "Enregistrement des paramètres" }, "scriptError": { "message": "Il y a une erreur dans votre script Quicktext:" }, "scriptLine": { "message": "Ligne" }, "scriptNotFound": { "message": "Script Quicktext “$P1$” introuvable!", "placeholders": { "P1": { "content": "$1" } } }, "template": { "message": "Modèle" }, "time": { "message": "Heure ($P1$)", "placeholders": { "P1": { "content": "$1" } } } } quicktext-6.3.2/_locales/hu/000077500000000000000000000000001477370713100157525ustar00rootroot00000000000000quicktext-6.3.2/_locales/hu/messages.json000066400000000000000000000256241477370713100204650ustar00rootroot00000000000000{ "altKey": { "message": "Alt" }, "attachmentFile": { "message": "Fájl kiválasztása mellékletek hozzáadása" }, "controlKey": { "message": "Ctrl" }, "date": { "message": "Dátum ($P1$)", "placeholders": { "P1": { "content": "$1" } } }, "exportFile": { "message": "Fájl kiválasztás exportálása (UTF-8)" }, "extensionDescription": { "message": "Eszköztár, parancsfájlok és sablonok korlátlan lehetoségekkel, beleértve a [[TO=firstname]] változókat, a gyors szövegbeillesztéshez" }, "extensionName": { "message": "Gyorsszöveg" }, "fileNotUTF8": { "message": "Nem töltődik be a fájl megfelelően, mert úgy tűnik, hogy a kijelölt fájl nem UTF-8 kódolású. Jelöljön ki egy másik fájlt." }, "group": { "message": "Csoport" }, "importFile": { "message": "Fájl kiválasztás importálása (UTF-8)" }, "inputText": { "message": "A(z) $P1$ érték bevitele", "placeholders": { "P1": { "content": "$1" } } }, "inputTitle": { "message": "Változó érték" }, "insertFile": { "message": "Fájl kiválasztás beszúrása (UTF-8)" }, "insertImage": { "message": "Beillesztendő képfájl kiválasztása" }, "metaKey": { "message": "Meta" }, "newGroup": { "message": "Új csoport" }, "newScript": { "message": "Új parancsfájl" }, "newTemplate": { "message": "Új sablon" }, "quicktext.HTML.label": { "message": "HTML" }, "quicktext.accesskey.addGroup": { "message": "p" }, "quicktext.accesskey.addScript": { "message": "t" }, "quicktext.accesskey.addTemplate": { "message": "l" }, "quicktext.accesskey.close": { "message": "z" }, "quicktext.accesskey.communityScripts": { "message": "s" }, "quicktext.accesskey.export": { "message": "t" }, "quicktext.accesskey.file": { "message": "f" }, "quicktext.accesskey.general": { "message": "n" }, "quicktext.accesskey.goToHomepage": { "message": "h" }, "quicktext.accesskey.help": { "message": "g" }, "quicktext.accesskey.import": { "message": "r" }, "quicktext.accesskey.remove": { "message": "v" }, "quicktext.accesskey.resetCounter": { "message": "i" }, "quicktext.accesskey.save": { "message": "c" }, "quicktext.accesskey.scripts": { "message": "p" }, "quicktext.accesskey.settings": { "message": "b" }, "quicktext.accesskey.templates": { "message": "o" }, "quicktext.accesskeyScripts.export": { "message": "x" }, "quicktext.accesskeyScripts.import": { "message": "m" }, "quicktext.accesskeyTemplate.export": { "message": "e" }, "quicktext.accesskeyTemplate.import": { "message": "i" }, "quicktext.addGroup.label": { "message": "Csoport hozzáadása" }, "quicktext.addScript.label": { "message": "Parancsfájl hozzáadása" }, "quicktext.addTemplate.label": { "message": "Sablon hozzáadása" }, "quicktext.altKey.label": { "message": "Alt" }, "quicktext.attachments.label": { "message": "Mellékletek" }, "quicktext.browse.label": { "message": "Tallózás…" }, "quicktext.cellularnumber.label": { "message": "Mobiltelefonszám" }, "quicktext.clipboard.label": { "message": "Vágólap" }, "quicktext.close.label": { "message": "Bezárás" }, "quicktext.collapseSetting.label": { "message": "Csoport összecsukása amikor egy sablont tartalmaz" }, "quicktext.controlKey.label": { "message": "Ctrl" }, "quicktext.counter.label": { "message": "Számláló" }, "quicktext.cursor.label": { "message": "Kurzor helyezkedő" }, "quicktext.custom1.label": { "message": "1. egyéni" }, "quicktext.custom2.label": { "message": "2. egyéni" }, "quicktext.custom3.label": { "message": "3. egyéni" }, "quicktext.custom4.label": { "message": "4. egyéni" }, "quicktext.dateTime.label": { "message": "Dátum/idő" }, "quicktext.defaultImport.label": { "message": "Importálás indításkor" }, "quicktext.displayname.label": { "message": "Megjelenítendő név" }, "quicktext.email.label": { "message": "E-mail" }, "quicktext.enterKey.label": { "message": "Enter" }, "quicktext.export.label": { "message": "Exportálása" }, "quicktext.f11Key.label": { "message": "F11" }, "quicktext.f12Key.label": { "message": "F12" }, "quicktext.f2Key.label": { "message": "F2" }, "quicktext.f4Key.label": { "message": "F4" }, "quicktext.f5Key.label": { "message": "F5" }, "quicktext.f8Key.label": { "message": "F8" }, "quicktext.faxnumber.label": { "message": "Fax szám" }, "quicktext.file.label": { "message": "Fájl" }, "quicktext.filename.label": { "message": "Fájlnév" }, "quicktext.filenameAndSize.label": { "message": "Fájlnév és fájlméret" }, "quicktext.firstname.label": { "message": "Keresztnév" }, "quicktext.from.label": { "message": "Feladó" }, "quicktext.fullname.label": { "message": "Teljes név" }, "quicktext.general.label": { "message": "Általános" }, "quicktext.getScript.label": { "message": "Közösségi parancsfájlok" }, "quicktext.goToHomepage.label": { "message": "Ugrás a honlapra" }, "quicktext.group.label": { "message": "Csoport" }, "quicktext.header.label": { "message": "Fejléc (Címzett [To], Másolat [Cc], Rejtett másolat [Bcc])" }, "quicktext.help.label": { "message": "Súgó" }, "quicktext.homenumber.label": { "message": "Otthoni szám" }, "quicktext.image.label": { "message": "Beágyazott HTML-kép" }, "quicktext.import.label": { "message": "Importálása" }, "quicktext.input.label": { "message": "Bemeneti érték a parancssorból" }, "quicktext.insertAs.label": { "message": "Irányított beszúrása…" }, "quicktext.insertTextFromFileAsHTML.label": { "message": "Fájl beszúrása mint HTML formátum" }, "quicktext.insertTextFromFileAsText.label": { "message": "Fájl beszúrása mint szöveg formátum" }, "quicktext.insertfile.label": { "message": "Tartalom a fájlból (gyorsszöveg változók lecseréli)" }, "quicktext.jobtitle.label": { "message": "Munka megnevezése" }, "quicktext.keyword.label": { "message": "Kulcsszó" }, "quicktext.keywordKeySetting.label": { "message": "billentyű a kulcsszó aktiválásához" }, "quicktext.label": { "message": "Gyorsszöveg" }, "quicktext.lastname.label": { "message": "Vezetéknév" }, "quicktext.metaKey.label": { "message": "Meta" }, "quicktext.modifierSetting.label": { "message": "billentyű módosít a billentyűparancsot" }, "quicktext.nickname.label": { "message": "Becenév" }, "quicktext.none.label": { "message": "Nincs" }, "quicktext.orgatt.label": { "message": "Eredeti melléklet adatai" }, "quicktext.orgheader.label": { "message": "Eredeti fejléc adatai" }, "quicktext.other.label": { "message": "Más" }, "quicktext.remove.label": { "message": "Eltávolítás" }, "quicktext.resetcounter.label": { "message": "Számláló visszaállítása" }, "quicktext.showContextMenu.label": { "message": "Jobb kattintással a gyorsszöveg menü megnyitása" }, "quicktext.save.label": { "message": "Mentés" }, "quicktext.script.label": { "message": "Parancsfájl" }, "quicktext.scripts.label": { "message": "Parancsfájlok" }, "quicktext.selection.label": { "message": "Kijelölés" }, "quicktext.settings.label": { "message": "Beállítások" }, "quicktext.settings.title": { "message": "Gyorsszöveg beállításai" }, "quicktext.sharingScripts.label": { "message": "Parancsfájlok megosztása" }, "quicktext.sharingTemplates.label": { "message": "Sablonok megosztása" }, "quicktext.shortcut.label": { "message": "Gyorsbillentyű" }, "quicktext.shortcutTypeAdv.label": { "message": "Használja a speciális módot a gyorsbillentyűkhöz" }, "quicktext.shortname.label": { "message": "Gyorsszöveg" }, "quicktext.spaceKey.label": { "message": "Szóköz" }, "quicktext.subject.label": { "message": "Tárgy" }, "quicktext.tabKey.label": { "message": "Fül" }, "quicktext.template.label": { "message": "Sablon" }, "quicktext.templates.label": { "message": "Sablonok" }, "quicktext.text.label": { "message": "Szöveg" }, "quicktext.title.label": { "message": "Cím" }, "quicktext.to.label": { "message": "Címzett" }, "quicktext.url.label": { "message": "Válasz az URL-címtől" }, "quicktext.variables.label": { "message": "Változók" }, "quicktext.version.label": { "message": "Thunderbird verzió" }, "quicktext.workphone.label": { "message": "Munkahelyi szám" }, "remove": { "message": "Biztos benne, hogy el akarja távolítani a(z) „$P1$”-t?", "placeholders": { "P1": { "content": "$1" } } }, "saveMessage": { "message": "A módosításokat nincs elmentve. Szeretné menteni azokat?" }, "saveMessageTitle": { "message": "Beállítások mentése" }, "scriptError": { "message": "Hiba történt a gyorsszöveg parancsfájlban:" }, "scriptLine": { "message": "Sor" }, "scriptNotFound": { "message": "Gyorsszöveg „$P1$”-parancsfájl nem található!", "placeholders": { "P1": { "content": "$1" } } }, "template": { "message": "Sablon" }, "time": { "message": "Idő ($P1$)", "placeholders": { "P1": { "content": "$1" } } } } quicktext-6.3.2/_locales/ja/000077500000000000000000000000001477370713100157305ustar00rootroot00000000000000quicktext-6.3.2/_locales/ja/messages.json000066400000000000000000000262071477370713100204410ustar00rootroot00000000000000{ "altKey": { "message": "Alt" }, "attachmentFile": { "message": "添付するファイルを選択してください" }, "controlKey": { "message": "Ctrl" }, "date": { "message": "日付 ($P1$)", "placeholders": { "P1": { "content": "$1" } } }, "exportFile": { "message": "ファイルのエクスポート先を選択 (UTF-8)" }, "extensionDescription": { "message": "定型文を素早く挿入できるツールバーをメール編集画面に追加します。[[TO=firstname]]のような変数も使用できます。" }, "fileNotUTF8": { "message": "選択されたファイルはUTF-8でないため正しく読み込まれません。別のファイルを選択してください。" }, "group": { "message": "グループ" }, "importFile": { "message": "インポートするファイルの選択 (UTF-8)" }, "inputText": { "message": "$P1$ の値を入力してください", "placeholders": { "P1": { "content": "$1" } } }, "inputTitle": { "message": "タグの値" }, "insertFile": { "message": "挿入するファイルの選択 (UTF-8)" }, "insertImage": { "message": "挿入する画像を選択" }, "metaKey": { "message": "Meta" }, "newGroup": { "message": "新しいグループ" }, "newScript": { "message": "新しいスクリプト" }, "newTemplate": { "message": "新しいテンプレート" }, "quicktext.HTML.label": { "message": "HTML" }, "quicktext.accesskey.addGroup": { "message": "p" }, "quicktext.accesskey.addScript": { "message": "a" }, "quicktext.accesskey.addTemplate": { "message": "l" }, "quicktext.accesskey.close": { "message": "c" }, "quicktext.accesskey.communityScripts": { "message": "c" }, "quicktext.accesskey.export": { "message": "e" }, "quicktext.accesskey.file": { "message": "f" }, "quicktext.accesskey.general": { "message": "g" }, "quicktext.accesskey.goToHomepage": { "message": "h" }, "quicktext.accesskey.help": { "message": "p" }, "quicktext.accesskey.import": { "message": "i" }, "quicktext.accesskey.remove": { "message": "d" }, "quicktext.accesskey.resetCounter": { "message": "r" }, "quicktext.accesskey.save": { "message": "s" }, "quicktext.accesskey.scripts": { "message": "s" }, "quicktext.accesskey.settings": { "message": "n" }, "quicktext.accesskey.templates": { "message": "t" }, "quicktext.accesskeyScripts.export": { "message": "x" }, "quicktext.accesskeyScripts.import": { "message": "m" }, "quicktext.accesskeyTemplate.export": { "message": "e" }, "quicktext.accesskeyTemplate.import": { "message": "i" }, "quicktext.addGroup.label": { "message": "グループを追加" }, "quicktext.addScript.label": { "message": "スクリプトを追加" }, "quicktext.addTemplate.label": { "message": "テンプレートを追加" }, "quicktext.altKey.label": { "message": "Alt" }, "quicktext.attachments.label": { "message": "添付ファイル" }, "quicktext.browse.label": { "message": "参照" }, "quicktext.cellularnumber.label": { "message": "携帯電話の番号" }, "quicktext.clipboard.label": { "message": "クリップボード" }, "quicktext.close.label": { "message": "閉じる" }, "quicktext.collapseSetting.label": { "message": "グループにテンプレートが1つしか含まれていない時は、グループとして表示しない" }, "quicktext.controlKey.label": { "message": "Ctrl" }, "quicktext.counter.label": { "message": "カウンター" }, "quicktext.cursor.label": { "message": "カーソルの位置" }, "quicktext.custom1.label": { "message": "カスタム 1" }, "quicktext.custom2.label": { "message": "カスタム 2" }, "quicktext.custom3.label": { "message": "カスタム 3" }, "quicktext.custom4.label": { "message": "カスタム 4" }, "quicktext.dateTime.label": { "message": "日付と時間" }, "quicktext.defaultImport.label": { "message": "起動時にインポート" }, "quicktext.displayname.label": { "message": "表示名" }, "quicktext.email.label": { "message": "メール" }, "quicktext.enterKey.label": { "message": "Enter" }, "quicktext.export.label": { "message": "エクスポート" }, "quicktext.f11Key.label": { "message": "F11" }, "quicktext.f12Key.label": { "message": "F12" }, "quicktext.f2Key.label": { "message": "F2" }, "quicktext.f4Key.label": { "message": "F4" }, "quicktext.f5Key.label": { "message": "F5" }, "quicktext.f8Key.label": { "message": "F8" }, "quicktext.faxnumber.label": { "message": "FAX 番号" }, "quicktext.file.label": { "message": "ファイル" }, "quicktext.filename.label": { "message": "ファイルの名前" }, "quicktext.filenameAndSize.label": { "message": "ファイルの名前と容量" }, "quicktext.firstname.label": { "message": "名" }, "quicktext.from.label": { "message": "差出人" }, "quicktext.fullname.label": { "message": "名前" }, "quicktext.general.label": { "message": "全般" }, "quicktext.getScript.label": { "message": "コミュニティスクリプト" }, "quicktext.goToHomepage.label": { "message": "ホームページへ移動" }, "quicktext.group.label": { "message": "グループ" }, "quicktext.header.label": { "message": "ヘッダー (To, Cc, Bcc)" }, "quicktext.help.label": { "message": "ヘルプ" }, "quicktext.homenumber.label": { "message": "自宅の電話番号" }, "quicktext.image.label": { "message": "埋め込みHTML画像" }, "quicktext.import.label": { "message": "インポート" }, "quicktext.input.label": { "message": "ユーザープロンプトからの入力値" }, "quicktext.insertAs.label": { "message": "挿入形式" }, "quicktext.insertTextFromFileAsHTML.label": { "message": "ファイルを HTML として挿入" }, "quicktext.insertTextFromFileAsText.label": { "message": "ファイルをテキストとして挿入" }, "quicktext.insertfile.label": { "message": "ファイルの内容(quicktext変数が置き換えられます)" }, "quicktext.jobtitle.label": { "message": "肩書き" }, "quicktext.keyword.label": { "message": "キーワード" }, "quicktext.keywordKeySetting.label": { "message": "をキーワードの起動に使用する" }, "quicktext.label": { "message": "Quicktext" }, "quicktext.lastname.label": { "message": "姓" }, "quicktext.metaKey.label": { "message": "Meta" }, "quicktext.modifierSetting.label": { "message": "をキーボードショートカットの修飾キーとして使用する" }, "quicktext.nickname.label": { "message": "ニックネーム" }, "quicktext.none.label": { "message": "なし" }, "quicktext.orgatt.label": { "message": "オリジナル添付ファイル情報" }, "quicktext.orgheader.label": { "message": "オリジナルヘッダー情報" }, "quicktext.other.label": { "message": "その他" }, "quicktext.remove.label": { "message": "削除" }, "quicktext.resetcounter.label": { "message": "カウンターをリセット" }, "quicktext.showContextMenu.label": { "message": "コンテキストメニューに Quicktext を表示する" }, "quicktext.save.label": { "message": "保存" }, "quicktext.script.label": { "message": "スクリプト" }, "quicktext.scripts.label": { "message": "スクリプト" }, "quicktext.selection.label": { "message": "選択" }, "quicktext.settings.label": { "message": "設定" }, "quicktext.settings.title": { "message": "Quicktext の設定" }, "quicktext.sharingScripts.label": { "message": "共有スクリプト" }, "quicktext.sharingTemplates.label": { "message": "共有テンプレート" }, "quicktext.shortcut.label": { "message": "ショートカット" }, "quicktext.shortcutTypeAdv.label": { "message": "アドバンスモードでショートカットを使用" }, "quicktext.shortname.label": { "message": "Quicktext" }, "quicktext.spaceKey.label": { "message": "Space" }, "quicktext.subject.label": { "message": "件名" }, "quicktext.tabKey.label": { "message": "Tab" }, "quicktext.template.label": { "message": "テンプレート" }, "quicktext.templates.label": { "message": "テンプレート" }, "quicktext.text.label": { "message": "テキスト" }, "quicktext.title.label": { "message": "タイトル" }, "quicktext.to.label": { "message": "宛先" }, "quicktext.url.label": { "message": "URLからの応答" }, "quicktext.variables.label": { "message": "タグ" }, "quicktext.version.label": { "message": "Thunderbird のバージョン" }, "quicktext.workphone.label": { "message": "勤務先の電話番号" }, "remove": { "message": "「$P1$」 を削除してもよろしいですか?", "placeholders": { "P1": { "content": "$1" } } }, "saveMessage": { "message": "設定が変更されています。保存して終了しますか?" }, "saveMessageTitle": { "message": "設定の保存" }, "scriptError": { "message": "Quicktextスクリプトにエラーがあります:" }, "scriptLine": { "message": "行" }, "scriptNotFound": { "message": "Quicktextスクリプト 「$P1$」 が見つかりません!", "placeholders": { "P1": { "content": "$1" } } }, "template": { "message": "テンプレート" }, "time": { "message": "時間 ($P1$)", "placeholders": { "P1": { "content": "$1" } } } } quicktext-6.3.2/_locales/pt_BR/000077500000000000000000000000001477370713100163445ustar00rootroot00000000000000quicktext-6.3.2/_locales/pt_BR/messages.json000066400000000000000000000253641477370713100210600ustar00rootroot00000000000000{ "altKey": { "message": "Alt" }, "attachmentFile": { "message": "Escolha o arquivo para adicionar aos anexos" }, "controlKey": { "message": "Ctrl" }, "date": { "message": "Data ($P1$)", "placeholders": { "P1": { "content": "$1" } } }, "exportFile": { "message": "Escolha o arquivo para exportar (UTF-8)" }, "extensionDescription": { "message": "Adiciona uma barra de ferramentas com um número ilimitado de texto para inserir rapidamente. Também é possível usar variáveis como [[TO=firstname]]. Com configurações para tudo." }, "fileNotUTF8": { "message": "The selected file does not seem to be UTF-8 encoded and will not loaded correctly. Please select a different file." }, "group": { "message": "Grupo" }, "importFile": { "message": "Escolha o arquivo para importar (UTF-8)" }, "inputText": { "message": "Insira o valor de $P1$", "placeholders": { "P1": { "content": "$1" } } }, "inputTitle": { "message": "Valor variável" }, "insertFile": { "message": "Escolha o arquivo para inserir (UTF-8)" }, "insertImage": { "message": "Escolha o arquivo de imagem para inserir" }, "metaKey": { "message": "Meta" }, "newGroup": { "message": "Novo grupo" }, "newScript": { "message": "Novo script" }, "newTemplate": { "message": "Novo modelo" }, "quicktext.HTML.label": { "message": "HTML" }, "quicktext.accesskey.addGroup": { "message": "p" }, "quicktext.accesskey.addScript": { "message": "t" }, "quicktext.accesskey.addTemplate": { "message": "l" }, "quicktext.accesskey.close": { "message": "c" }, "quicktext.accesskey.communityScripts": { "message": "a" }, "quicktext.accesskey.export": { "message": "o" }, "quicktext.accesskey.file": { "message": "q" }, "quicktext.accesskey.general": { "message": "g" }, "quicktext.accesskey.goToHomepage": { "message": "r" }, "quicktext.accesskey.help": { "message": "u" }, "quicktext.accesskey.import": { "message": "r" }, "quicktext.accesskey.remove": { "message": "v" }, "quicktext.accesskey.resetCounter": { "message": "i" }, "quicktext.accesskey.save": { "message": "s" }, "quicktext.accesskey.scripts": { "message": "s" }, "quicktext.accesskey.settings": { "message": "n" }, "quicktext.accesskey.templates": { "message": "d" }, "quicktext.accesskeyScripts.export": { "message": "x" }, "quicktext.accesskeyScripts.import": { "message": "m" }, "quicktext.accesskeyTemplate.export": { "message": "e" }, "quicktext.accesskeyTemplate.import": { "message": "i" }, "quicktext.addGroup.label": { "message": "Adicionar grupo" }, "quicktext.addScript.label": { "message": "Adicionar script" }, "quicktext.addTemplate.label": { "message": "Adicionar modelo" }, "quicktext.altKey.label": { "message": "Alt" }, "quicktext.attachments.label": { "message": "Anexos" }, "quicktext.browse.label": { "message": "Procurar" }, "quicktext.cellularnumber.label": { "message": "Número de Celular" }, "quicktext.clipboard.label": { "message": "Área de transferência" }, "quicktext.close.label": { "message": "Fechar" }, "quicktext.collapseSetting.label": { "message": "Recolher o grupo quando ele contém apenas um modelo" }, "quicktext.controlKey.label": { "message": "Ctrl" }, "quicktext.counter.label": { "message": "Contador" }, "quicktext.cursor.label": { "message": "Posição do Cursor" }, "quicktext.custom1.label": { "message": "Personalizado 1" }, "quicktext.custom2.label": { "message": "Personalizado 2" }, "quicktext.custom3.label": { "message": "Personalizado 3" }, "quicktext.custom4.label": { "message": "Personalizado 4" }, "quicktext.dateTime.label": { "message": "Data/Tempo" }, "quicktext.defaultImport.label": { "message": "Importar na inicialização" }, "quicktext.displayname.label": { "message": "Nome em Exibição" }, "quicktext.email.label": { "message": "E-mail" }, "quicktext.enterKey.label": { "message": "Enter" }, "quicktext.export.label": { "message": "Exportar" }, "quicktext.f11Key.label": { "message": "F11" }, "quicktext.f12Key.label": { "message": "F12" }, "quicktext.f2Key.label": { "message": "F2" }, "quicktext.f4Key.label": { "message": "F4" }, "quicktext.f5Key.label": { "message": "F5" }, "quicktext.f8Key.label": { "message": "F8" }, "quicktext.faxnumber.label": { "message": "Número de fax" }, "quicktext.file.label": { "message": "Arquivo" }, "quicktext.filename.label": { "message": "Nome do arquivo" }, "quicktext.filenameAndSize.label": { "message": "Nome do arquivo e tamanho" }, "quicktext.firstname.label": { "message": "Primeiro nome" }, "quicktext.from.label": { "message": "De" }, "quicktext.fullname.label": { "message": "Nome completo" }, "quicktext.general.label": { "message": "Geral" }, "quicktext.getScript.label": { "message": "Scripts da comunidade" }, "quicktext.goToHomepage.label": { "message": "Ir para a página inicial" }, "quicktext.group.label": { "message": "Grupo" }, "quicktext.header.label": { "message": "Cabeçalho (To, Cc, Bcc)" }, "quicktext.help.label": { "message": "Ajuda" }, "quicktext.homenumber.label": { "message": "Número Residencial" }, "quicktext.image.label": { "message": "Embedded HTML image" }, "quicktext.import.label": { "message": "Importar" }, "quicktext.input.label": { "message": "Valor de entrada do prompt do usuário" }, "quicktext.insertAs.label": { "message": "Inserir como" }, "quicktext.insertTextFromFileAsHTML.label": { "message": "Inserir arquivo como HTML" }, "quicktext.insertTextFromFileAsText.label": { "message": "Inserir arquivo como texto" }, "quicktext.insertfile.label": { "message": "Conteúdo do arquivo (as variáveis do quicktext serão substituídas)" }, "quicktext.jobtitle.label": { "message": "Titulo no trabalho" }, "quicktext.keyword.label": { "message": "Palavra-chave" }, "quicktext.keywordKeySetting.label": { "message": "é a chave que eu quero usar para ativar uma palavra-chave" }, "quicktext.label": { "message": "Quicktext" }, "quicktext.lastname.label": { "message": "Último nome" }, "quicktext.metaKey.label": { "message": "Meta" }, "quicktext.modifierSetting.label": { "message": "é o modificador que eu quero usar para os atalhos do teclado" }, "quicktext.nickname.label": { "message": "Apelido" }, "quicktext.none.label": { "message": "Nenhum" }, "quicktext.orgatt.label": { "message": "Informações do anexo original" }, "quicktext.orgheader.label": { "message": "Informações do cabeçalho original" }, "quicktext.other.label": { "message": "Outros" }, "quicktext.remove.label": { "message": "Remover" }, "quicktext.resetcounter.label": { "message": "Reiniciar contador" }, "quicktext.showContextMenu.label": { "message": "Exibir menu de texto rápido com o botão direito do mouse" }, "quicktext.save.label": { "message": "Salvar" }, "quicktext.script.label": { "message": "Script" }, "quicktext.scripts.label": { "message": "Scripts" }, "quicktext.selection.label": { "message": "Seleção" }, "quicktext.settings.label": { "message": "Configurações" }, "quicktext.settings.title": { "message": "Configurações do Quicktext" }, "quicktext.sharingScripts.label": { "message": "Scripts compartilhandos" }, "quicktext.sharingTemplates.label": { "message": "Modelos compartilhandos" }, "quicktext.shortcut.label": { "message": "Atalho" }, "quicktext.shortcutTypeAdv.label": { "message": "Use o modo avançado para atalhos" }, "quicktext.shortname.label": { "message": "Quicktext" }, "quicktext.spaceKey.label": { "message": "Espaço" }, "quicktext.subject.label": { "message": "Assunto" }, "quicktext.tabKey.label": { "message": "Tab" }, "quicktext.template.label": { "message": "Modelo" }, "quicktext.templates.label": { "message": "Modelos" }, "quicktext.text.label": { "message": "Texto simples" }, "quicktext.title.label": { "message": "Títlo" }, "quicktext.to.label": { "message": "Para" }, "quicktext.url.label": { "message": "Resposta da URL" }, "quicktext.variables.label": { "message": "Variáveis" }, "quicktext.version.label": { "message": "Versão do Thunderbird" }, "quicktext.workphone.label": { "message": "Número de Trabalho" }, "remove": { "message": "Tem certeza de que deseja remover “$P1$”?", "placeholders": { "P1": { "content": "$1" } } }, "saveMessage": { "message": "Suas alterações não foram salvas. Deseja salvá-las?" }, "saveMessageTitle": { "message": "Salvar configurações" }, "scriptError": { "message": "There was an error in your Quicktext script:" }, "scriptLine": { "message": "Line" }, "scriptNotFound": { "message": "Quicktext script “$P1$” not found!", "placeholders": { "P1": { "content": "$1" } } }, "template": { "message": "Modelo" }, "time": { "message": "Tempo ($P1$)", "placeholders": { "P1": { "content": "$1" } } } } quicktext-6.3.2/_locales/ru/000077500000000000000000000000001477370713100157645ustar00rootroot00000000000000quicktext-6.3.2/_locales/ru/messages.json000066400000000000000000000276141477370713100205000ustar00rootroot00000000000000{ "altKey": { "message": "Alt" }, "attachmentFile": { "message": "Выберите файл для добавления во вложения" }, "controlKey": { "message": "Ctrl" }, "date": { "message": "Дата ($P1$)", "placeholders": { "P1": { "content": "$1" } } }, "exportFile": { "message": "Выберите файл для экспорта в (UTF-8)" }, "extensionDescription": { "message": "Добавляет панель инструментов с неограниченным количеством текста для быстрой вставки. Также можно использовать такие переменные, как [[TO=firstname]]. С настройками для всего." }, "fileNotUTF8": { "message": "Выбранный файл не похож UTF-8 кодированный и загружен некорректно. Выберите другой файл." }, "group": { "message": "Группа" }, "importFile": { "message": "Выберите файл для импорта (UTF-8)" }, "inputText": { "message": "Введите значение $P1$", "placeholders": { "P1": { "content": "$1" } } }, "inputTitle": { "message": "Значение переменной" }, "insertFile": { "message": "Выберите файл для вставки (UTF-8)" }, "insertImage": { "message": "Выберите изображение для вставки" }, "metaKey": { "message": "Meta" }, "newGroup": { "message": "Новая группа" }, "newScript": { "message": "Новый скрипт" }, "newTemplate": { "message": "Новый шаблон" }, "quicktext.HTML.label": { "message": "HTML" }, "quicktext.accesskey.addGroup": { "message": "Д" }, "quicktext.accesskey.addScript": { "message": "б" }, "quicktext.accesskey.addTemplate": { "message": "б" }, "quicktext.accesskey.close": { "message": "З" }, "quicktext.accesskey.communityScripts": { "message": "щ" }, "quicktext.accesskey.export": { "message": "Э" }, "quicktext.accesskey.file": { "message": "Ф" }, "quicktext.accesskey.general": { "message": "Г" }, "quicktext.accesskey.goToHomepage": { "message": "д" }, "quicktext.accesskey.help": { "message": "П" }, "quicktext.accesskey.import": { "message": "И" }, "quicktext.accesskey.remove": { "message": "У" }, "quicktext.accesskey.resetCounter": { "message": "С" }, "quicktext.accesskey.save": { "message": "р" }, "quicktext.accesskey.scripts": { "message": "к" }, "quicktext.accesskey.settings": { "message": "Н" }, "quicktext.accesskey.templates": { "message": "Ш" }, "quicktext.accesskeyScripts.export": { "message": "о" }, "quicktext.accesskeyScripts.import": { "message": "т" }, "quicktext.accesskeyTemplate.export": { "message": "к" }, "quicktext.accesskeyTemplate.import": { "message": "м" }, "quicktext.addGroup.label": { "message": "Добавить группу" }, "quicktext.addScript.label": { "message": "Добавить скрипт" }, "quicktext.addTemplate.label": { "message": "Добавить шаблон" }, "quicktext.altKey.label": { "message": "Alt" }, "quicktext.attachments.label": { "message": "Вложения" }, "quicktext.browse.label": { "message": "Просмотр" }, "quicktext.cellularnumber.label": { "message": "Мобильный телефон" }, "quicktext.clipboard.label": { "message": "Буфер обмена" }, "quicktext.close.label": { "message": "Закрыть" }, "quicktext.collapseSetting.label": { "message": "Свернуть группу, если она содержит только один шаблон" }, "quicktext.controlKey.label": { "message": "Ctrl" }, "quicktext.counter.label": { "message": "Счётчик" }, "quicktext.cursor.label": { "message": "Позиция курсора" }, "quicktext.custom1.label": { "message": "Прочее 1" }, "quicktext.custom2.label": { "message": "Прочее 2" }, "quicktext.custom3.label": { "message": "Прочее 3" }, "quicktext.custom4.label": { "message": "Прочее 4" }, "quicktext.dateTime.label": { "message": "Дата/Время" }, "quicktext.defaultImport.label": { "message": "Импорт при запуске" }, "quicktext.displayname.label": { "message": "Отображаемое имя" }, "quicktext.email.label": { "message": "E-mail" }, "quicktext.enterKey.label": { "message": "Enter" }, "quicktext.export.label": { "message": "Экспорт" }, "quicktext.f11Key.label": { "message": "F11" }, "quicktext.f12Key.label": { "message": "F12" }, "quicktext.f2Key.label": { "message": "F2" }, "quicktext.f4Key.label": { "message": "F4" }, "quicktext.f5Key.label": { "message": "F5" }, "quicktext.f8Key.label": { "message": "F8" }, "quicktext.faxnumber.label": { "message": "Факс" }, "quicktext.file.label": { "message": "Файл" }, "quicktext.filename.label": { "message": "Имя файла" }, "quicktext.filenameAndSize.label": { "message": "Имя файла и размер" }, "quicktext.firstname.label": { "message": "Имя" }, "quicktext.from.label": { "message": "От" }, "quicktext.fullname.label": { "message": "ФИО" }, "quicktext.general.label": { "message": "Главное" }, "quicktext.getScript.label": { "message": "Скрипты сообщества" }, "quicktext.goToHomepage.label": { "message": "На домашнюю страницу" }, "quicktext.group.label": { "message": "Группа" }, "quicktext.header.label": { "message": "Header (To, Cc, Bcc)" }, "quicktext.help.label": { "message": "Помощь" }, "quicktext.homenumber.label": { "message": "Домашний телефон" }, "quicktext.image.label": { "message": "Внедрённое HTML изображение" }, "quicktext.import.label": { "message": "Импорт" }, "quicktext.input.label": { "message": "Входящее значение из приглашения пользователя" }, "quicktext.insertAs.label": { "message": "Вставить как" }, "quicktext.insertTextFromFileAsHTML.label": { "message": "Вставить файл как HTML" }, "quicktext.insertTextFromFileAsText.label": { "message": "Вставить файл как текст" }, "quicktext.insertfile.label": { "message": "Содержимое из файла (переменные quicktext будут заменены)" }, "quicktext.jobtitle.label": { "message": "Должность" }, "quicktext.keyword.label": { "message": "Kлючевое слово" }, "quicktext.keywordKeySetting.label": { "message": "клавиша для активации ключевого слова" }, "quicktext.label": { "message": "Quicktext" }, "quicktext.lastname.label": { "message": "Фамилия" }, "quicktext.metaKey.label": { "message": "Meta" }, "quicktext.modifierSetting.label": { "message": "модификатор для сочетаний клавиш" }, "quicktext.nickname.label": { "message": "Псевдоним" }, "quicktext.none.label": { "message": "Пусто" }, "quicktext.orgatt.label": { "message": "Информация оригинального вложения" }, "quicktext.orgheader.label": { "message": "Информация оригинального заголовка" }, "quicktext.other.label": { "message": "Прочее" }, "quicktext.remove.label": { "message": "Удалить" }, "quicktext.resetcounter.label": { "message": "Сбросить счетчик" }, "quicktext.showContextMenu.label": { "message": "Просмотр Quicktext-меню по правому клику" }, "quicktext.save.label": { "message": "Сохранить" }, "quicktext.script.label": { "message": "Скрипт" }, "quicktext.scripts.label": { "message": "Скрипты" }, "quicktext.selection.label": { "message": "Выделение" }, "quicktext.settings.label": { "message": "Настройки" }, "quicktext.settings.title": { "message": "Настройки Quicktext" }, "quicktext.sharingScripts.label": { "message": "Обмен скриптами" }, "quicktext.sharingTemplates.label": { "message": "Обмен шаблонами" }, "quicktext.shortcut.label": { "message": "Сочетание" }, "quicktext.shortcutTypeAdv.label": { "message": "Использовать расширенный режим для ярлыков" }, "quicktext.shortname.label": { "message": "Quicktext" }, "quicktext.spaceKey.label": { "message": "Пробел" }, "quicktext.subject.label": { "message": "Тема" }, "quicktext.tabKey.label": { "message": "Tab" }, "quicktext.template.label": { "message": "Шаблон" }, "quicktext.templates.label": { "message": "Шаблоны" }, "quicktext.text.label": { "message": "Текст" }, "quicktext.title.label": { "message": "Название" }, "quicktext.to.label": { "message": "Кому" }, "quicktext.url.label": { "message": "Ответ из URL" }, "quicktext.variables.label": { "message": "Переменные" }, "quicktext.version.label": { "message": "Версия Thunderbird" }, "quicktext.workphone.label": { "message": "Рабочий телефон" }, "remove": { "message": "Вы уверены, что хотите удалить “$P1$”?", "placeholders": { "P1": { "content": "$1" } } }, "saveMessage": { "message": "Ваши изменения не были сохранены. Вы хотите сохранить их?" }, "saveMessageTitle": { "message": "Сохранить настройки" }, "scriptError": { "message": "Ошибка в Quicktext скрипте:" }, "scriptLine": { "message": "Строка" }, "scriptNotFound": { "message": "Quicktext скрипт “$P1$” не найден!", "placeholders": { "P1": { "content": "$1" } } }, "template": { "message": "Шаблон" }, "time": { "message": "Время ($P1$)", "placeholders": { "P1": { "content": "$1" } } } } quicktext-6.3.2/_locales/sv-SE/000077500000000000000000000000001477370713100162735ustar00rootroot00000000000000quicktext-6.3.2/_locales/sv-SE/messages.json000066400000000000000000000246761477370713100210140ustar00rootroot00000000000000{ "altKey": { "message": "Alt" }, "attachmentFile": { "message": "Välj fil att lägga till i bifogade filer" }, "controlKey": { "message": "Ctrl" }, "date": { "message": "Datum ($P1$)", "placeholders": { "P1": { "content": "$1" } } }, "exportFile": { "message": "Välj fil att exportera till (UTF-8)" }, "extensionDescription": { "message": "Adds a toolbar with unlimited number of text to quickly insert. It is also possible to use variables like [[TO=firstname]]. With settings for everything." }, "fileNotUTF8": { "message": "The selected file does not seem to be UTF-8 encoded and will not loaded correctly. Please select a different file." }, "group": { "message": "Grupp" }, "importFile": { "message": "Välj fil att importera (UTF-8)" }, "inputText": { "message": "Ange värdet på $P1$", "placeholders": { "P1": { "content": "$1" } } }, "inputTitle": { "message": "Variabel värde" }, "insertFile": { "message": "Välj fil att infoga (UTF-8)" }, "insertImage": { "message": "Choose image file to insert" }, "metaKey": { "message": "Meta" }, "newGroup": { "message": "Ny grupp" }, "newScript": { "message": "Nytt skript" }, "newTemplate": { "message": "Ny mall" }, "quicktext.HTML.label": { "message": "HTML" }, "quicktext.accesskey.addGroup": { "message": "g" }, "quicktext.accesskey.addScript": { "message": "t" }, "quicktext.accesskey.addTemplate": { "message": "l" }, "quicktext.accesskey.close": { "message": "ä" }, "quicktext.accesskey.communityScripts": { "message": "s" }, "quicktext.accesskey.export": { "message": "o" }, "quicktext.accesskey.file": { "message": "k" }, "quicktext.accesskey.general": { "message": "w" }, "quicktext.accesskey.goToHomepage": { "message": "h" }, "quicktext.accesskey.help": { "message": "p" }, "quicktext.accesskey.import": { "message": "r" }, "quicktext.accesskey.remove": { "message": "v" }, "quicktext.accesskey.resetCounter": { "message": "l" }, "quicktext.accesskey.save": { "message": "a" }, "quicktext.accesskey.scripts": { "message": "s" }, "quicktext.accesskey.settings": { "message": "n" }, "quicktext.accesskey.templates": { "message": "q" }, "quicktext.accesskeyScripts.export": { "message": "x" }, "quicktext.accesskeyScripts.import": { "message": "m" }, "quicktext.accesskeyTemplate.export": { "message": "e" }, "quicktext.accesskeyTemplate.import": { "message": "i" }, "quicktext.addGroup.label": { "message": "Lägg till grupp" }, "quicktext.addScript.label": { "message": "Lägg till skript" }, "quicktext.addTemplate.label": { "message": "Lägg till mall" }, "quicktext.altKey.label": { "message": "Alt" }, "quicktext.attachments.label": { "message": "Bifogade filer" }, "quicktext.browse.label": { "message": "Bläddra" }, "quicktext.cellularnumber.label": { "message": "Mobilnummer" }, "quicktext.clipboard.label": { "message": "Urklipp" }, "quicktext.close.label": { "message": "Stäng" }, "quicktext.collapseSetting.label": { "message": "Collapse group when it only contains one template" }, "quicktext.controlKey.label": { "message": "Ctrl" }, "quicktext.counter.label": { "message": "Counter" }, "quicktext.cursor.label": { "message": "Markörposition" }, "quicktext.custom1.label": { "message": "Övrigt 1" }, "quicktext.custom2.label": { "message": "Övrigt 2" }, "quicktext.custom3.label": { "message": "Övrigt 3" }, "quicktext.custom4.label": { "message": "Övrigt 4" }, "quicktext.dateTime.label": { "message": "Datum/Tid" }, "quicktext.defaultImport.label": { "message": "Importeras vid uppstart" }, "quicktext.displayname.label": { "message": "Kortnamn" }, "quicktext.email.label": { "message": "E-post" }, "quicktext.enterKey.label": { "message": "Enter" }, "quicktext.export.label": { "message": "Export" }, "quicktext.f11Key.label": { "message": "F11" }, "quicktext.f12Key.label": { "message": "F12" }, "quicktext.f2Key.label": { "message": "F2" }, "quicktext.f4Key.label": { "message": "F4" }, "quicktext.f5Key.label": { "message": "F5" }, "quicktext.f8Key.label": { "message": "F8" }, "quicktext.faxnumber.label": { "message": "Faxnummer" }, "quicktext.file.label": { "message": "Arkiv" }, "quicktext.filename.label": { "message": "Filnamn" }, "quicktext.filenameAndSize.label": { "message": "Filnamn and storlek" }, "quicktext.firstname.label": { "message": "Förnamn" }, "quicktext.from.label": { "message": "Från" }, "quicktext.fullname.label": { "message": "Fullständiga namnet" }, "quicktext.general.label": { "message": "Allmänt" }, "quicktext.getScript.label": { "message": "Community Scripts" }, "quicktext.goToHomepage.label": { "message": "Gå till hemsidan" }, "quicktext.group.label": { "message": "Grupp" }, "quicktext.header.label": { "message": "Header (To, Cc, Bcc)" }, "quicktext.help.label": { "message": "Hjälp" }, "quicktext.homenumber.label": { "message": "Hemnummer" }, "quicktext.image.label": { "message": "Embedded HTML image" }, "quicktext.import.label": { "message": "Import" }, "quicktext.input.label": { "message": "Input value from user prompt" }, "quicktext.insertAs.label": { "message": "Infoga som" }, "quicktext.insertTextFromFileAsHTML.label": { "message": "Infoga fil som HTML" }, "quicktext.insertTextFromFileAsText.label": { "message": "Infoga fil som text" }, "quicktext.insertfile.label": { "message": "Content from file (quicktext variables will be replaced)" }, "quicktext.jobtitle.label": { "message": "Arbetstitel" }, "quicktext.keyword.label": { "message": "Nyckelord" }, "quicktext.keywordKeySetting.label": { "message": "är den tangent jag vill använda för att aktivera nyckelord" }, "quicktext.label": { "message": "Quicktext" }, "quicktext.lastname.label": { "message": "Efternamn" }, "quicktext.metaKey.label": { "message": "Meta" }, "quicktext.modifierSetting.label": { "message": "är den tangent jag vill använda för kortkommandon" }, "quicktext.nickname.label": { "message": "Smeknamn" }, "quicktext.none.label": { "message": "Inget" }, "quicktext.orgatt.label": { "message": "Original attachment info" }, "quicktext.orgheader.label": { "message": "Original header info" }, "quicktext.other.label": { "message": "Övrigt" }, "quicktext.remove.label": { "message": "Ta bort" }, "quicktext.resetcounter.label": { "message": "Återställ räknaren" }, "quicktext.showContextMenu.label": { "message": "Visa Quicktext-menyn vid högerklick" }, "quicktext.save.label": { "message": "Spara" }, "quicktext.script.label": { "message": "Skript" }, "quicktext.scripts.label": { "message": "Skript" }, "quicktext.selection.label": { "message": "Selection" }, "quicktext.settings.label": { "message": "Inställningar" }, "quicktext.settings.title": { "message": "Quicktext Inställningar" }, "quicktext.sharingScripts.label": { "message": "Dela skript" }, "quicktext.sharingTemplates.label": { "message": "Dela mallar" }, "quicktext.shortcut.label": { "message": "Kortkommando" }, "quicktext.shortcutTypeAdv.label": { "message": "Använd avancerat läge för kortkommandon" }, "quicktext.shortname.label": { "message": "Quicktext" }, "quicktext.spaceKey.label": { "message": "Mellanslag" }, "quicktext.subject.label": { "message": "Ämne" }, "quicktext.tabKey.label": { "message": "Tab" }, "quicktext.template.label": { "message": "Mall" }, "quicktext.templates.label": { "message": "Mallar" }, "quicktext.text.label": { "message": "Text" }, "quicktext.title.label": { "message": "Titel" }, "quicktext.to.label": { "message": "Till" }, "quicktext.url.label": { "message": "Response from URL" }, "quicktext.variables.label": { "message": "Variabler" }, "quicktext.version.label": { "message": "Thunderbird version" }, "quicktext.workphone.label": { "message": "Jobbnummer" }, "remove": { "message": "Är du säker på att du vill tabort ”$P1$”?", "placeholders": { "P1": { "content": "$1" } } }, "saveMessage": { "message": "Du har inte sparat de ändringar du gjort. Vill du spara dem?" }, "saveMessageTitle": { "message": "Spara inställningar" }, "scriptError": { "message": "There was an error in your Quicktext script:" }, "scriptLine": { "message": "Line" }, "scriptNotFound": { "message": "Quicktext script “$P1$” not found!", "placeholders": { "P1": { "content": "$1" } } }, "template": { "message": "Mall" }, "time": { "message": "Tid ($P1$)", "placeholders": { "P1": { "content": "$1" } } } } quicktext-6.3.2/api/000077500000000000000000000000001477370713100143265ustar00rootroot00000000000000quicktext-6.3.2/api/LegacyHelper/000077500000000000000000000000001477370713100166725ustar00rootroot00000000000000quicktext-6.3.2/api/LegacyHelper/README.md000066400000000000000000000036061477370713100201560ustar00rootroot00000000000000## Objective This API is a temporary helper while converting legacy extensions to modern WebExtensions. It allows to register `resource://` URLs, which are needed to load custom system modules (*.sys.mjs), and `chrome://` URLs, which are needed to open legacy XUL dialogs. ## Usage Add the [LegacyHelper API](https://github.com/thunderbird/webext-support/tree/master/experiments/LegacyHelper) to your add-on. Your `manifest.json` needs an entry like this: ```json "experiment_apis": { "LegacyHelper": { "schema": "api/LegacyHelper/schema.json", "parent": { "scopes": ["addon_parent"], "paths": [["LegacyHelper"]], "script": "api/LegacyHelper/implementation.js" } } }, ``` ## API Functions This API provides the following functions: ### async registerGlobalUrls(data) Register `chrome://*/content/` and `resource://*/` URLs. The function accepts a `data` parameter, which is an array of URL definition items. For example: ```javascript await browser.LegacyHelper.registerGlobalUrls([ ["content", "myaddon", "chrome/content/"], ["resource", "myaddon", "modules/"], ]); ``` This registers the following URLs: * `chrome://myaddon/content/` pointing to the `/chrome/content/` folder (the `/content/` part in the URL is fix and does not depend on the name of the folder it is pointing to) * `resource://myaddon/` pointing to the `/modules/` folder. To register a `resource://` URL which points to the root folder, use `.` instead". ### async openDialog(name, path) Open a XUL dialog. The `name` parameter is a unique name identifying the dialog. If the dialog with that name is already open, it will be focused instead of being re-opened. The `path` parameter is a `chrome://*/content/` URL pointing to the XUL dialog file (*.xul or *.xhtml). ```javascript browser.LegacyHelper.openDialog( "XulAddonOptions", "chrome://myaddon/content/options.xhtml" ); ``` quicktext-6.3.2/api/LegacyHelper/implementation.js000066400000000000000000000062671477370713100222700ustar00rootroot00000000000000/* * This file is provided by the webext-support repository at * https://github.com/thunderbird/webext-support * * Version 1.1 * - registerGlobalUrls() is now async, to be able to properly await registration * * Version 1.0 * - initial release * * Author: * - John Bieling (john@thunderbird.net) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; // Using a closure to not leak anything but the API to the outside world. (function (exports) { const aomStartup = Cc[ "@mozilla.org/addons/addon-manager-startup;1" ].getService(Ci.amIAddonManagerStartup); const resProto = Cc[ "@mozilla.org/network/protocol;1?name=resource" ].getService(Ci.nsISubstitutingProtocolHandler); const chromeHandlers = []; const resourceUrls = []; var LegacyHelper = class extends ExtensionCommon.ExtensionAPI { getAPI(context) { return { LegacyHelper: { registerGlobalUrls(data) { const manifestURI = Services.io.newURI( "manifest.json", null, context.extension.rootURI ); for (let entry of data) { // [ "resource", "shortname" , "path" ] switch (entry[0]) { case "resource": { let uri = Services.io.newURI( entry[2], null, context.extension.rootURI ); resProto.setSubstitutionWithFlags( entry[1], uri, resProto.ALLOW_CONTENT_ACCESS ); resourceUrls.push(entry[1]); } break; case "content": case "locale": { let handle = aomStartup.registerChrome( manifestURI, [entry] ); chromeHandlers.push(handle); } break; default: console.warn(`LegacyHelper: Unsupported url type: ${entry[0]}`) } } }, openDialog(name, path) { let window = Services.wm.getMostRecentWindow("mail:3pane"); window.openDialog( path, name, "chrome,resizable,centerscreen" ); }, }, }; } onShutdown(isAppShutdown) { if (isAppShutdown) { return; // the application gets unloaded anyway } for (let chromeHandler of chromeHandlers) { if (chromeHandler) { chromeHandler.destruct(); chromeHandler = null; } } for (let resourceUrl of resourceUrls) { resProto.setSubstitution( resourceUrl, null ); } // Flush all caches. Services.obs.notifyObservers(null, "startupcache-invalidate"); } }; exports.LegacyHelper = LegacyHelper; })(this);quicktext-6.3.2/api/LegacyHelper/schema.json000066400000000000000000000020021477370713100210170ustar00rootroot00000000000000[ { "namespace": "LegacyHelper", "functions": [ { "name": "registerGlobalUrls", "type": "function", "async": true, "description": "Register folders which should be available as legacy chrome:// urls or resource:// urls", "parameters": [ { "name": "data", "type": "array", "items": { "type": "array", "items": { "type": "string" } }, "description": "Array of manifest url definitions (content, locale or resource)" } ] }, { "name": "openDialog", "type": "function", "parameters": [ { "name": "name", "type": "string", "description": "name of the new dialog" }, { "name": "path", "type": "string", "description": "path of the dialog to be opened" } ] } ] } ]quicktext-6.3.2/api/NotifyTools/000077500000000000000000000000001477370713100166175ustar00rootroot00000000000000quicktext-6.3.2/api/NotifyTools/implementation.js000066400000000000000000000106641477370713100222110ustar00rootroot00000000000000/* * This file is provided by the addon-developer-support repository at * https://github.com/thundernest/addon-developer-support * * Version 1.5 * - adjusted to Thunderbird Supernova (Services is now in globalThis) * * Version 1.4 * - updated implementation to not assign this anymore * * Version 1.3 * - moved registering the observer into startup * * Version 1.1 * - added startup event, to make sure API is ready as soon as the add-on is starting * NOTE: This requires to add the startup event to the manifest, see: * https://github.com/thundernest/addon-developer-support/tree/master/auxiliary-apis/NotifyTools#usage * * Author: John Bieling (john@thunderbird.net) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; (function (exports) { // Get various parts of the WebExtension framework that we need. var { ExtensionCommon } = ChromeUtils.importESModule("resource://gre/modules/ExtensionCommon.sys.mjs"); var observerTracker = new Set(); class NotifyTools extends ExtensionCommon.ExtensionAPI { getAPI(context) { return { NotifyTools: { notifyExperiment(data) { return new Promise(resolve => { Services.obs.notifyObservers( { data, resolve }, "NotifyExperimentObserver", context.extension.id ); }); }, onNotifyBackground: new ExtensionCommon.EventManager({ context, name: "NotifyTools.onNotifyBackground", register: (fire) => { observerTracker.add(fire.sync); return () => { observerTracker.delete(fire.sync); }; }, }).api(), } }; } // Force API to run at startup, otherwise event listeners might not be added at the requested time. Also needs // "events": ["startup"] in the experiment manifest onStartup() { this.onNotifyBackgroundObserver = async (aSubject, aTopic, aData) => { if ( observerTracker.size > 0 && aData == this.extension.id ) { let payload = aSubject.wrappedJSObject; // Make sure payload has a resolve function, which we use to resolve the // observer notification. if (payload.resolve) { let observerTrackerPromises = []; // Push listener into promise array, so they can run in parallel for (let listener of observerTracker.values()) { observerTrackerPromises.push(listener(payload.data)); } // We still have to await all of them but wait time is just the time needed // for the slowest one. let results = []; for (let observerTrackerPromise of observerTrackerPromises) { let rv = await observerTrackerPromise; if (rv != null) results.push(rv); } if (results.length == 0) { payload.resolve(); } else { if (results.length > 1) { console.warn( "Received multiple results from onNotifyBackground listeners. Using the first one, which can lead to inconsistent behavior.", results ); } payload.resolve(results[0]); } } else { // Older version of NotifyTools, which is not sending a resolve function, deprecated. console.log("Please update the notifyTools API and the notifyTools script to at least v1.5"); for (let listener of observerTracker.values()) { listener(payload.data); } } } }; // Add observer for notifyTools.js Services.obs.addObserver( this.onNotifyBackgroundObserver, "NotifyBackgroundObserver", false ); } onShutdown(isAppShutdown) { if (isAppShutdown) { return; // the application gets unloaded anyway } // Remove observer for notifyTools.js Services.obs.removeObserver( this.onNotifyBackgroundObserver, "NotifyBackgroundObserver" ); // Flush all caches Services.obs.notifyObservers(null, "startupcache-invalidate"); } }; exports.NotifyTools = NotifyTools; })(this) quicktext-6.3.2/api/NotifyTools/notifyTools.js000066400000000000000000000114171477370713100215120ustar00rootroot00000000000000// Set this to the ID of your add-on, or call notifyTools.setAddonID(). const ADDON_ID = "{8845E3B3-E8FB-40E2-95E9-EC40294818C4}"; /* * This file is provided by the addon-developer-support repository at * https://github.com/thundernest/addon-developer-support * * For usage descriptions, please check: * https://github.com/thundernest/addon-developer-support/tree/master/scripts/notifyTools * * Version 1.6 * - adjusted to Thunderbird Supernova (Services is now in globalThis) * * Version 1.5 * - deprecate enable(), disable() and registerListener() * - add setAddOnId() * * Version 1.4 * - auto enable/disable * * Version 1.3 * - registered listeners for notifyExperiment can return a value * - remove WindowListener from name of observer * * Author: John Bieling (john@thunderbird.net) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ var notifyTools = { registeredCallbacks: {}, registeredCallbacksNextId: 1, addOnId: ADDON_ID, setAddOnId: function (addOnId) { this.addOnId = addOnId; }, onNotifyExperimentObserver: { observe: async function (aSubject, aTopic, aData) { if (notifyTools.addOnId == "") { throw new Error("notifyTools: ADDON_ID is empty!"); } if (aData != notifyTools.addOnId) { return; } let payload = aSubject.wrappedJSObject; // Make sure payload has a resolve function, which we use to resolve the // observer notification. if (payload.resolve) { let observerTrackerPromises = []; // Push listener into promise array, so they can run in parallel for (let registeredCallback of Object.values( notifyTools.registeredCallbacks )) { observerTrackerPromises.push(registeredCallback(payload.data)); } // We still have to await all of them but wait time is just the time needed // for the slowest one. let results = []; for (let observerTrackerPromise of observerTrackerPromises) { let rv = await observerTrackerPromise; if (rv != null) results.push(rv); } if (results.length == 0) { payload.resolve(); } else { if (results.length > 1) { console.warn( "Received multiple results from onNotifyExperiment listeners. Using the first one, which can lead to inconsistent behavior.", results ); } payload.resolve(results[0]); } } else { // Older version of NotifyTools, which is not sending a resolve function, deprecated. console.log("Please update the notifyTools API to at least v1.5"); for (let registeredCallback of Object.values( notifyTools.registeredCallbacks )) { registeredCallback(payload.data); } } }, }, addListener: function (listener) { if (Object.values(this.registeredCallbacks).length == 0) { Services.obs.addObserver( this.onNotifyExperimentObserver, "NotifyExperimentObserver", false ); } let id = this.registeredCallbacksNextId++; this.registeredCallbacks[id] = listener; return id; }, removeListener: function (id) { delete this.registeredCallbacks[id]; if (Object.values(this.registeredCallbacks).length == 0) { Services.obs.removeObserver( this.onNotifyExperimentObserver, "NotifyExperimentObserver" ); } }, removeAllListeners: function () { if (Object.values(this.registeredCallbacks).length != 0) { Services.obs.removeObserver( this.onNotifyExperimentObserver, "NotifyExperimentObserver" ); } this.registeredCallbacks = {}; }, notifyBackground: function (data) { if (this.addOnId == "") { throw new Error("notifyTools: ADDON_ID is empty!"); } return new Promise((resolve) => { Services.obs.notifyObservers( { data, resolve }, "NotifyBackgroundObserver", this.addOnId ); }); }, // Deprecated. enable: function () { console.log("Manually calling notifyTools.enable() is no longer needed."); }, disable: function () { console.log("notifyTools.disable() has been deprecated, use notifyTools.removeAllListeners() instead."); this.removeAllListeners(); }, registerListener: function (listener) { console.log("notifyTools.registerListener() has been deprecated, use notifyTools.addListener() instead."); this.addListener(listener); }, }; if (typeof window != "undefined" && window) { window.addEventListener( "unload", function (event) { notifyTools.removeAllListeners(); }, false ); } quicktext-6.3.2/api/NotifyTools/schema.json000066400000000000000000000015371477370713100207600ustar00rootroot00000000000000[ { "namespace": "NotifyTools", "events": [ { "name": "onNotifyBackground", "type": "function", "description": "Fired when a new notification from notifyTools.js in an Experiment has been received.", "parameters": [ { "name": "data", "type": "any", "description": "Restrictions of the structured clone algorithm apply." } ] } ], "functions": [ { "name": "notifyExperiment", "type": "function", "async": true, "description": "Notifies notifyTools.js in an Experiment and sends data.", "parameters": [ { "name": "data", "type": "any", "description": "Restrictions of the structured clone algorithm apply." } ] } ] } ]quicktext-6.3.2/api/Quicktext/000077500000000000000000000000001477370713100163075ustar00rootroot00000000000000quicktext-6.3.2/api/Quicktext/implementation.js000066400000000000000000000055661477370713100217060ustar00rootroot00000000000000/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; // Using a closure to not leak anything but the API to the outside world. (function (exports) { let managerWindow = null; var Quicktext = class extends ExtensionCommon.ExtensionAPI { getAPI(context) { return { Quicktext: { async getQuicktextFilePaths(templateFolder) { let rv = {}; // get profile directory let profileDir = Components.classes["@mozilla.org/file/directory_service;1"] .getService(Components.interfaces.nsIProperties) .get("ProfD", Components.interfaces.nsIFile); // check if an alternative path has been given for the config folder if (templateFolder) { profileDir = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsIFile); profileDir.initWithPath(templateFolder); } let quicktextDir = profileDir; quicktextDir.append("quicktext"); if (!quicktextDir.exists()) quicktextDir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0o755); if (!quicktextDir.isDirectory()) { // Must warn the user that the quicktext dir don't exists and couldn't be created } else { let templateFile = quicktextDir.clone(); templateFile.append("templates.xml"); // Checks if the template-file exists and import that, if it exists. if (templateFile.exists()) { rv.templateFilePath = templateFile.path; } // Checks if the script-file exists and import that, if it exists. let scriptFile = quicktextDir.clone(); scriptFile.append("scripts.xml"); if (scriptFile.exists()) { rv.scriptFilePath = scriptFile.path; } } return rv; }, openTemplateManager() { let window = Services.wm.getMostRecentWindow("mail:3pane"); managerWindow = window.openDialog( "chrome://quicktext/content/settings.xhtml", "quicktextConfig", "chrome,resizable,centerscreen" ); }, async readBinaryFile(aFilePath) { return IOUtils.read(aFilePath); }, async readTextFile(aFilePath) { return IOUtils.readUTF8(aFilePath); }, }, }; } onShutdown(isAppShutdown) { if (isAppShutdown) { return; // the application gets unloaded anyway } if (managerWindow) { managerWindow.close(); } } }; exports.Quicktext = Quicktext; })(this);quicktext-6.3.2/api/Quicktext/schema.json000066400000000000000000000015511477370713100204440ustar00rootroot00000000000000[ { "namespace": "Quicktext", "functions": [ { "name": "getQuicktextFilePaths", "type": "function", "async": true, "parameters": [ { "name": "templateFolder", "type": "string" } ] }, { "name": "openTemplateManager", "type": "function", "async": true, "parameters": [] }, { "name": "readBinaryFile", "type": "function", "async": true, "parameters": [ { "name": "aFilePath", "type": "string" } ] }, { "name": "readTextFile", "type": "function", "async": true, "parameters": [ { "name": "aFilePath", "type": "string" } ] } ] } ]quicktext-6.3.2/api/QuicktextToolbar/000077500000000000000000000000001477370713100176325ustar00rootroot00000000000000quicktext-6.3.2/api/QuicktextToolbar/composerToolbar.css000066400000000000000000000002751477370713100235220ustar00rootroot00000000000000#quicktext-toolbar button { border: 0px; margin-left: 2px; margin-right: 2px; min-width: auto; } #quicktext-toolbar { border-bottom: 1px solid var(--splitter-color); } quicktext-6.3.2/api/QuicktextToolbar/composerToolbar.js000066400000000000000000000202161477370713100233430ustar00rootroot00000000000000var quicktextToolbar = { windowId: null, extension: null, dateTimeFormat(format, timeStamp) { let options = {}; options["date-short"] = { dateStyle: "short" }; options["date-long"] = { dateStyle: "long" }; options["date-monthname"] = { month: "long" }; options["time-noseconds"] = { timeStyle: "short" }; options["time-seconds"] = { timeStyle: "long" }; return new Services.intl.DateTimeFormat(undefined, options[format.toLowerCase()]).format(timeStamp) }, getPrettyKeyName(key) { return this.extension.localeData.localizeMessage(`quicktext.${key}Key.label`) }, async load() { Services.scriptloader.loadSubScript("resource://quicktext/api/NotifyTools/notifyTools.js", quicktextToolbar, "UTF-8"); const { ExtensionParent } = ChromeUtils.importESModule( "resource://gre/modules/ExtensionParent.sys.mjs" ); this.extension = ExtensionParent.GlobalManager.getExtension( "{8845E3B3-E8FB-40E2-95E9-EC40294818C4}" ); await this.update(); document.getElementById("quicktext-variables-popup").addEventListener( "popupshowing", () => this.updateTimeMenus(), true ); }, unload() { }, async updateTimeMenus() { // Set the date/time in the variable menu. var timeStamp = new Date(); let fields = ["date-short", "date-long", "date-monthname", "time-noseconds", "time-seconds"]; for (let i = 0; i < fields.length; i++) { let field = fields[i]; let fieldtype = field.split("-")[0]; if (document.getElementById(field)) { document.getElementById(field).setAttribute( "label", this.extension.localeData.localizeMessage(fieldtype, [this.dateTimeFormat(field, timeStamp)]) ); } } }, async update() { this.updateTimeMenus(); // Empty all shortcuts and keywords ????? this.mShortcuts = {}; this.mKeywords = {}; // Update the toolbar var toolbar = document.getElementById("quicktext-templates-toolbar"); if (toolbar != null) { // Clear template toolbar. var length = toolbar.children.length; for (var i = length - 1; i >= 0; i--) { toolbar.removeChild(toolbar.children[i]); } // Rebuild template groups (the leftmost entries) const templates = await this.notifyTools.notifyBackground({ command: "getTemplates" }); const collapseGroup = await this.notifyTools.notifyBackground({ command: "getPref", pref: "menuCollapse" }); const shortcutModifier = await this.notifyTools.notifyBackground({ command: "getPref", pref: "shortcutModifier" }); var groupLength = templates.groups.length; for (var i = 0; i < groupLength; i++) { var textLength = templates.texts[i].length; if (textLength) { // Add first level element, this will be either a menu or a button (if // only one text in this group). var toolbarbuttonGroup; let t = document.createXULElement("button"); // Add a tabindex of -1 (not reachable via sequential keyboard navigation). // see: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex t.setAttribute("tabindex", "-1"); if (textLength == 1 && collapseGroup) { toolbarbuttonGroup = toolbar.appendChild(t); toolbarbuttonGroup.setAttribute("label", templates.texts[i][0].name); toolbarbuttonGroup.setAttribute("i", i); toolbarbuttonGroup.setAttribute("j", 0); toolbarbuttonGroup.setAttribute("class", "customEventListenerForDynamicMenu"); } else { t.setAttribute("type", "menu"); toolbarbuttonGroup = toolbar.appendChild(t); toolbarbuttonGroup.setAttribute("label", templates.groups[i].name); var menupopup = toolbarbuttonGroup.appendChild(document.createXULElement("menupopup")); // Add second level elements: all found texts of this group. for (var j = 0; j < textLength; j++) { var text = templates.texts[i][j]; var toolbarbutton = document.createXULElement("menuitem"); toolbarbutton.setAttribute("label", text.name); toolbarbutton.setAttribute("i", i); toolbarbutton.setAttribute("j", j); toolbarbutton.setAttribute("class", "customEventListenerForDynamicMenu"); var shortcut = text.shortcut; if (shortcut != "") { if (shortcut == 10) shortcut = 0; toolbarbutton.setAttribute("acceltext", `${this.getPrettyKeyName(shortcutModifier)} + ${shortcut}`); } menupopup.appendChild(toolbarbutton); } } toolbarbuttonGroup = null; // Update the keyshortcuts. for (var j = 0; j < textLength; j++) { var text = templates.texts[i][j]; var shortcut = text.shortcut; if (shortcut != "" && typeof this.mShortcuts[shortcut] == "undefined") this.mShortcuts[shortcut] = [i, j]; var keyword = text.keyword; if (keyword != "" && typeof this.mKeywords[keyword.toLowerCase()] == "undefined") this.mKeywords[keyword.toLowerCase()] = [i, j]; } } } } // Add event listeners. let items = document.getElementsByClassName("customEventListenerForDynamicMenu"); for (let i = 0; i < items.length; i++) { items[i].addEventListener("command", function () { quicktextToolbar.insertTemplate(this.getAttribute("i"), this.getAttribute("j")); }, true); } this.visibleToolbar(); }, // This may not needed, since the toolbar will be an extra add-on and the toolbar // will only be shown, when the extra add-on is installed? The "toolbar" pref has // no config UI at he moment. async visibleToolbar() { const toolbar = await this.notifyTools.notifyBackground({ command: "getPref", pref: "toolbar" }); if (toolbar) { document.getElementById("quicktext-toolbar").removeAttribute("collapsed"); } else { document.getElementById("quicktext-toolbar").setAttribute("collapsed", true); } }, focusMessageBody() { let editor = GetCurrentEditorElement();//document.getElementsByTagName("editor"); if (editor) { editor.focus(); } }, async insertVariable(aVar) { this.focusMessageBody(); await this.notifyTools.notifyBackground({ command: "insertVariable", aVar, windowId: this.windowId }); }, async insertTemplate(group, text) { this.focusMessageBody(); await this.notifyTools.notifyBackground({ command: "insertTemplate", group, text, windowId: this.windowId }); }, async insertContentFromFile(aType) { const file = await this.pickFile(aType, /* open */ 0, ""); // browser.i18n.getMessage("insertFile") this.focusMessageBody(); if (file) { await this.notifyTools.notifyBackground({ command: "insertFile", aType, file, windowId: this.windowId }); } }, async pickFile(aType, aMode, aTitle) { let filePicker = Components.classes["@mozilla.org/filepicker;1"].createInstance(Components.interfaces.nsIFilePicker); switch (aMode) { case 1: // save filePicker.init(window.browsingContext, aTitle, filePicker.modeSave); break; default: // open filePicker.init(window.browsingContext, aTitle, filePicker.modeOpen); break; } switch (aType) { case 0: // insert TXT file filePicker.appendFilters(filePicker.filterText); filePicker.defaultExtension = "txt"; break; case 1: // insert HTML file filePicker.appendFilters(filePicker.filterHTML); filePicker.defaultExtension = "html"; break; } filePicker.appendFilters(filePicker.filterAll); let rv = await new Promise(function (resolve, reject) { filePicker.open(result => { resolve(result); }); }); if (rv == filePicker.returnOK || rv == filePicker.returnReplace) { // Create DOM File from real file. const file = await File.createFromNsIFile(filePicker.file); return file; } else { return null; } } } quicktext-6.3.2/api/QuicktextToolbar/implementation.js000066400000000000000000000317651477370713100232310ustar00rootroot00000000000000/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; // Using a closure to not leak anything but the API to the outside world. (function (exports) { // Helper function to inject a legacy XUL string into the DOM of Thunderbird. // All injected elements will get the data attribute "data-extension-injected" // set to the extension id, for easy removal. const injectElements = function (extension, window, xulString, debug = false) { function checkElements(stringOfIDs) { let arrayOfIDs = stringOfIDs.split(",").map((e) => e.trim()); for (let id of arrayOfIDs) { let element = window.document.getElementById(id); if (element) { return element; } } return null; } function localize(entity) { let msg = entity.slice("__MSG_".length, -2); return extension.localeData.localizeMessage(msg); } function injectChildren(elements, container) { if (debug) console.log(elements); for (let i = 0; i < elements.length; i++) { if ( elements[i].hasAttribute("insertafter") && checkElements(elements[i].getAttribute("insertafter")) ) { let insertAfterElement = checkElements( elements[i].getAttribute("insertafter") ); if (debug) console.log( elements[i].tagName + "#" + elements[i].id + ": insertafter " + insertAfterElement.id ); if ( debug && elements[i].id && window.document.getElementById(elements[i].id) ) { console.error( "The id <" + elements[i].id + "> of the injected element already exists in the document!" ); } elements[i].setAttribute("data-extension-injected", extension.id); insertAfterElement.parentNode.insertBefore( elements[i], insertAfterElement.nextSibling ); } else if ( elements[i].hasAttribute("insertbefore") && checkElements(elements[i].getAttribute("insertbefore")) ) { let insertBeforeElement = checkElements( elements[i].getAttribute("insertbefore") ); if (debug) console.log( elements[i].tagName + "#" + elements[i].id + ": insertbefore " + insertBeforeElement.id ); if ( debug && elements[i].id && window.document.getElementById(elements[i].id) ) { console.error( "The id <" + elements[i].id + "> of the injected element already exists in the document!" ); } elements[i].setAttribute("data-extension-injected", extension.id); insertBeforeElement.parentNode.insertBefore( elements[i], insertBeforeElement ); } else if ( elements[i].id && window.document.getElementById(elements[i].id) ) { // existing container match, dive into recursively if (debug) console.log( elements[i].tagName + "#" + elements[i].id + " is an existing container, injecting into " + elements[i].id ); injectChildren( Array.from(elements[i].children), window.document.getElementById(elements[i].id) ); } else { // append element to the current container if (debug) console.log( elements[i].tagName + "#" + elements[i].id + ": append to " + container.id ); elements[i].setAttribute("data-extension-injected", extension.id); container.appendChild(elements[i]); } } } if (debug) console.log("Injecting into root document:"); let localizedXulString = xulString.replace( /__MSG_(.*?)__/g, localize ); injectChildren( Array.from( window.MozXULElement.parseXULToFragment(localizedXulString, []).children ), window.document.documentElement ); }; // Helper function to inject a css file into as "link" element into the DOM of // Thunderbird. The injected element will get the data attribute // "data-extension-injected" set to the extension id, for easy removal. const injectCSS = function (extension, window, cssFile) { let element = window.document.createElement("link"); element.setAttribute("data-extension-injected", extension.id); element.setAttribute("rel", "stylesheet"); element.setAttribute("href", cssFile); return window.document.documentElement.appendChild(element); }; var QuicktextToolbar = class extends ExtensionCommon.ExtensionAPI { getAPI(context) { return { QuicktextToolbar: { async injectLegacyToolbar(windowId) { // Get the native window belonging to the specified windowId. let { window } = context.extension.windowManager.get(windowId); // Load an additional JavaScript file into the window scope. Services.scriptloader.loadSubScript("resource://quicktext/api/QuicktextToolbar/composerToolbar.js", window, "UTF-8"); window.quicktextToolbar.windowId = windowId; injectCSS(context.extension, window, "resource://quicktext/api/QuicktextToolbar/composerToolbar.css"); injectElements(context.extension, window, ` ` ); await window.quicktextToolbar.load(); }, async updateLegacyToolbar(windowId) { let { window } = context.extension.windowManager.get(windowId); if (window.quicktextToolbar) { window.quicktextToolbar.update(); } } }, }; } onShutdown(isAppShutdown) { if (isAppShutdown) { return; // the application gets unloaded anyway } const { extension } = this; for (const window of Services.wm.getEnumerator("msgcompose")) { if (window) { let elements = Array.from( window.document.querySelectorAll( '[data-extension-injected="' + extension.id + '"]' ) ); for (let element of elements) { element.remove(); } if (window.quicktextToolbar) { window.quicktextToolbar.unload(); window.quicktextToolbar = null; } } } } }; exports.QuicktextToolbar = QuicktextToolbar; })(this);quicktext-6.3.2/api/QuicktextToolbar/schema.json000066400000000000000000000010161477370713100217630ustar00rootroot00000000000000[ { "namespace": "QuicktextToolbar", "functions": [ { "name": "injectLegacyToolbar", "type": "function", "async": true, "parameters": [ { "name": "windowId", "type": "integer" } ] }, { "name": "updateLegacyToolbar", "type": "function", "async": true, "parameters": [ { "name": "windowId", "type": "integer" } ] } ] } ]quicktext-6.3.2/assets/000077500000000000000000000000001477370713100150575ustar00rootroot00000000000000quicktext-6.3.2/assets/icon.png000066400000000000000000000031221477370713100165130ustar00rootroot00000000000000PNG  IHDR szztIME$űT pHYsiTSgAMA aIDATxŗ le6G6m C@Qq ,Hh 5QBb(E@ E'`ۀl 6etڭ;k;m-2M>} ici$Peuz#/:;AT)W03[/MzeWL֐/RYĴ:kʀa͋1hrdD\FNdpbruK2q%``O=GЍsq!"K%¢ $yTUE7i6Zv]ÊLaAK*Wց_.>f#u#]:\GtK=bT^ݎC|rZ..@[|.yAixa..5 "2KkXSLF̓s>lo4}mg0tNŃz-exr`,.{x0m(@1z@4C*{ L>=i|sn!ȅŒ$o3o[lfFZl4NAtV@jf"c0x.ᇙɔH|,Y v:uOjVd=c=ك Ɍg:6 lRNS1T x)<:Ph4WaԷ,&r2=8Tݴv0^342GR! fɃ#5'aɌ8V'u9#$mH?C$yj+c=gmtw ew%!#`yd}WwbD=G[g. FA|K"' ΎP $H8fT9K(FPHby5J\x@D$ nTBh%c%$)RҴ\UѠQf-ZcNYs%EcIEK.ʮ⠊*WH7iŖJC=u^H# yQ'L1Ì3MyY|m +tUV}frX㇩=O_ATIܜ1u3͙o6gJ͍aE/>o.16usoXS/)8]4Y)x^zu:hopa`խGGIBB)iC5Ow݄Z}$=(hԞI1HgɫgC䩯$%. ?LXچѣY2%e F :B48Ͻ|<+9X㙈b6ّܡ'ߡ]m$hՃ1B2s*3&rRz&l0jj,CF솃#I3cG~}+;y`FxNmNTY*6[kWMo+84Jlqǘbi7|7XdO?OpHz+sͤ)2c*R9co=b9TqL/ [QX9en:md3-򆾱2t8E| $j ~gQ1 kV7~%8j. _2g_tSkC.{ A ;6C}]"*Z3y YZZkb>_u9nKl"dA=+z$/)h4X'<~zGe2])97fcnt+y?0`XX$峥lϛI>Vb# h( n`/kZρ*^nW+hLa,YQDLnkrCRG@"#9B+gSz{'._2&} '!Սw!"yH|k@2~4wgTd E ~$RufC'A kBOYoi)B k]%eY pCSUq^I*]dР l0m5ho`I@X0˞4h,LZ@h Z0 \땅9y;݆k{a[^ւҕ$Y}hB/-1MZ jeJ^j̧8 !< H3&C[őItz>]XDy9iɴ94lf *!ǢS?digs*{LSŪa {6w(}ɬBVi:Z5ck;7Ga:VHm079kI{Y*)"Yf)-ƕHe/lcɲaIqmjdIzDe Qŧ{m=>zLcL&%)[z |=cJ'!igif˒rD̉^375brHن7Hb.t(ivTœNr{kEw&})U[ g)E6_O#dSOZc~֝IP-(u'8Ӛ"9eW5!ʚc,xĻ].SY ;[ݛ9KJ^@x*82U"Q=uQ6cU|'kDB͝Q e@xr:9ge4D,-뽬CY'`e#!,Sm(pa1dt8E̛Uj{.]Bz}p\/b/X" sH *a+l<"Ԙo+sPPπ h;EBh@$^%^Bȱ(KR9Hg(|$0y^0. &puF:ac JCP4CxPT ҇,IhY jK9r`bscZ |X-P,D"#D(D uLBW ΀\ab ]@$sz+dBW7|vH**9H P{vm diJ7sd?QuZT$H+Qj"Hm~Y1LD AYJhuu&OE%yIڇW)m-ggS 5eZmIb"kDzmd'䍦=yhip1%G钅22Z¯仳T!0?bC8z!&(W.WRT+-$2&AF DxϨɦ @%ʍ-LhElIW7ߌ '}X|XℭQ6\~`0 q` OÏ^Ӂt" 2^HܧQnoF<8_t4Sp?HB2FHz)U|IsJbuyp֫⧙@ yƴ sW>xS49+N-RniFJb`h8i`υ+EHsX$^Ge6Sɢ kc)u9G6VBQ,qHl+{ (Z8ȍ;gj9 K8?HTJT VzDJzAzrRdUy\: $m hZ85H"Idc1nڴzDT_1ZpH6NbAS ;eⴵG#YBâ5MrNpGM @M~$9ꌈ&ǘPIpN 54e^HsHd8Q *C]]*Bsvc(x/' u jJ`U&Q՗tzz4Bgؤau0Mt&K)B#-=AD@@1ń 3C>aQ̫uIja_kd/4-Wd(E3oX(MtzOڮ7I#F!kpguܹZ>yb܌ '606$(I$k@*RO벇%ܞ~Q]w[| + f2o NxRQ-l-FEVGeDn =H AI\h6&u`\d d NxZGNJQB7P Z _8ރim"- ɸxK\6ybrL W|UriS-"1Gb4T@ u8뿵+d6dD}N0z'dDgr1{RdjmRBO4/ig<,*(CA)ڂ^*Vڏ캽ԃ6Y}&S| :}XrbPPwTA-q:[ڬEg9A.|;p oIV8D1'Gj"X6J\f7Ӭףּ,73iMˣE_+ISNRo/r<Ä)Ox b?ɰ+-HQ 5 <伥,:9t̆ `%r65Q~qz38 e&.AEOyk*^q'[YC$ұS"LSbk zۊ "kWCi!KbB@UDMyD".^67NZxaΑ7616Vfuۤ{Vob}7n*1z4#zKess(ፉTwJ|W}UdI󬞏K X/#1C@bЩ?*:9&hUC9.J4e;@LtE94㨆IeU:[SvԭF wJiI2$EٺwfI$:Eu:HOғD=e{CB3, өpA׋Z܃&5ˋ|EQtH-(t. jN݆p#I 5:[m#id ]63|[鶨=ջ*,RI+v J(L.)2e]6e.Nu|6lA#J*`m$^J rۻ!57&*j!Gs8,3(?j|uګCȼw$)c։E)6S&9po; :w:J|+^s YpJFؐ_\;5:h_|,,^OrC_#9ge q)WVS}m֩fNmKh &O@ F3xQEiTƧ2@AD 7zx,E {w@Y0u-;[@k߲@ iL 6j.Ih[El@ 8* ? Gv*_2Pd*{4s3>E~Ï!d7dAq7ÚQ3SA V-VʧAV9B>xj*SN;" _G,Ds+%6~="^]56}ÿM g{ p[!Ppe·5/EA#2\5lvg%[Ljd/FLu!>[n:!  +  G;5NG姫3߶vl.>{o +Y_ԐFh*(Y\*RP0IgB1#6QtB@'**Flu X?l\u~*=Xe 6L8$d%W@KIWNg4$,Hw1Nm%|wqVjϵIUn$/84qj&wSR7:fR,lj&՘Ub'W3 Ċ9@pc[rWUq[֩@CJDshn"z8=EkY>S|Tt?IkBy~lܽwd>d2njcm;^7S0@A!5@>YmOҪ/Թ ?>RZDG°WPDŽ >y:Zkq"H2X9L-5@c$)x"SOc#3$?"_DH4RcJ!3kQ6LV^8h’~#RJMmNƔd>T׆Q{ny/^ )dkJp]|Q;UGMඝdѡ=D':Uч:%ɻ.8BfѬZ"aLwG׿۟Vf=}NQG?Tj TA *~EӢii $>4&&͋}&ݝ!浒X́ gs.&3lRPF2L7 &Guq&>4HPMX͏*5aԙcYC~lfJi$wܮMx%:[Xm6T[ X4ej)jG@*AF<CQ)G<mzY.mϜ zxFu.H6_+qvYf{S^ qh@p BkI1t2e=YfU(1iH$, ̾%v9b# acw O[_p3@bɎb[;^ɻl]:wfT~ 3DN9pܳxj{~oc/JM&*1aVCHJ2sa%(5 L~ )E-:L;Mjݏu~M+zHχ+Tl7,WOn% 7>w 9@ V"ـڿL|"pj Quicktext Popup quicktext-6.3.2/html/popup.js000066400000000000000000000120641477370713100162250ustar00rootroot00000000000000class QuicktextPopover { userInput = Promise.withResolvers(); get popover() { return document.getElementById("quicktext-popover"); } show() { this.popover.showPopover(); } result() { return this.userInput.promise; } } async function openQuicktextPopover(type, label, values) { let popover; if (type == "prompt") { popover = new class extends QuicktextPopover { show() { document.body.insertAdjacentHTML("beforeend", `
${label}
`); document.getElementById("quicktext-popover-cancel").addEventListener( "click", () => this.userInput.resolve() ); document.getElementById("quicktext-popover-ok").addEventListener( "click", () => this.userInput.resolve(this.value) ); document.addEventListener("keydown", e => this.keydownEventHandler(e)) this.prompt.focus(); super.show(); } get prompt() { return document.getElementById("quicktext-popover-prompt"); } get value() { return this.prompt.value; } set value(v) { this.prompt.value = v; } keydownEventHandler(e) { switch (e.code) { case "Escape": this.userInput.resolve(); break; case "Enter": case "NumpadEnter": this.userInput.resolve(this.value); break; } } } } else if (type == "select") { popover = new class extends QuicktextPopover { show() { document.body.insertAdjacentHTML("beforeend", `
${label}
`); document.getElementById("quicktext-popover-cancel").addEventListener( "click", () => this.userInput.resolve() ); document.getElementById("quicktext-popover-ok").addEventListener( "click", () => this.userInput.resolve(this.select.value) ); document.addEventListener("keydown", e => this.keydownEventHandler(e)) this.select.addEventListener("dblclick", e => this.dblclickEventHandler(e)) this.select.focus(); super.show(); } get select() { return document.getElementById("quicktext-popover-select"); } keydownEventHandler(e) { switch (e.code) { case "Escape": this.userInput.resolve(); break; case "Enter": case "NumpadEnter": this.userInput.resolve(this.select.value); break; } } dblclickEventHandler(e) { this.userInput.resolve(this.select.value); } } } else { console.error(`Unsupported popover type: ${type}`); return ""; } popover.show(); return popover.result(); } let config = await browser.runtime.sendMessage({ action: "config" }); if (config.selectLabel) { let rv = await openQuicktextPopover("select", config.selectLabel, config.selectValues); await browser.runtime.sendMessage({ action: "close", rv }); } else if (config.promptLabel) { let rv = await openQuicktextPopover("prompt", config.promptLabel, config.promptValue); await browser.runtime.sendMessage({ action: "close", rv }); } window.close();quicktext-6.3.2/manifest.json000066400000000000000000000050541477370713100162620ustar00rootroot00000000000000{ "manifest_version": 2, "applications": { "gecko": { "id": "{8845E3B3-E8FB-40E2-95E9-EC40294818C4}", "update_url": "https://raw.githubusercontent.com/jobisoft/quicktext/refs/heads/Main/updates.json", "strict_min_version": "128.0", "strict_max_version": "138.*" } }, "name": "Quicktext", "version": "6.3.2", "author": "John Bieling", "homepage_url": "https://github.com/jobisoft/quicktext", "default_locale": "en-US", "description": "__MSG_extensionDescription__", "icons": { "16": "assets/icon16.png", "24": "assets/icon24.png", "32": "assets/icon.png" }, "compose_action": { "default_title": "Quicktext", "type": "menu", "default_label": "", "default_icon": { "16": "assets/icon16.png", "24": "assets/icon24.png", "32": "assets/icon.png" } }, "browser_action": { "default_title": "Quicktext", "default_label": "", "default_icon": { "16": "assets/icon16.png", "24": "assets/icon24.png", "32": "assets/icon.png" } }, "permissions": [ "storage", "menus", "compose", "clipboardRead", "accountsRead", "addressBooks", "messagesRead", "downloads", "notifications" ], "background": { "type": "module", "scripts": [ "scripts/background.js" ] }, "experiment_apis": { "LegacyHelper": { "schema": "api/LegacyHelper/schema.json", "parent": { "scopes": [ "addon_parent" ], "paths": [ [ "LegacyHelper" ] ], "script": "api/LegacyHelper/implementation.js" } }, "NotifyTools": { "schema": "api/NotifyTools/schema.json", "parent": { "scopes": [ "addon_parent" ], "paths": [ [ "NotifyTools" ] ], "script": "api/NotifyTools/implementation.js", "events": [ "startup" ] } }, "Quicktext": { "schema": "api/Quicktext/schema.json", "parent": { "scopes": [ "addon_parent" ], "paths": [ [ "Quicktext" ] ], "script": "api/Quicktext/implementation.js" } }, "QuicktextToolbar": { "schema": "api/QuicktextToolbar/schema.json", "parent": { "scopes": [ "addon_parent" ], "paths": [ [ "QuicktextToolbar" ] ], "script": "api/QuicktextToolbar/implementation.js" } } } }quicktext-6.3.2/modules/000077500000000000000000000000001477370713100152255ustar00rootroot00000000000000quicktext-6.3.2/modules/menus.mjs000066400000000000000000000222031477370713100170660ustar00rootroot00000000000000/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import * as quicktext from "/modules/quicktext.mjs"; import * as storage from "/modules/storage.mjs"; import * as utils from "/modules/utils.mjs"; let composeContextEntries = []; export async function buildComposeBodyMenu() { await processMenuData(await getComposeBodyMenuData()); // Update the menus before showing them. messenger.menus.onShown.addListener(async () => { await updateDateTimeMenus(); messenger.menus.refresh(); }); new storage.StorageListener( { watchedPrefs: ["templates", "popup", "menuCollapse"], listener: async (changes) => { // Throw away the menu. for (let entry of composeContextEntries.reverse()) { await messenger.menus.remove(entry); } composeContextEntries = []; const popup = await storage.getPref("popup"); if (popup) { await processMenuData(await getComposeBodyMenuData()); } } } ) } async function processMenuData(menuData, parentId) { for (let entry of menuData) { let createData = {} createData.id = parentId ? `${parentId}.${entry.id}` : entry.id; if (entry.type == "separator") { createData.type = entry.type; } else { createData.title = entry.title ? entry.title : messenger.i18n.getMessage(`quicktext.${entry.id}.label`); } if (entry.contexts) createData.contexts = entry.contexts; if (entry.visible) createData.visible = entry.visible; if (entry.onclick) createData.onclick = entry.onclick; if (parentId) createData.parentId = parentId; const created = Promise.withResolvers() const id = messenger.menus.create(createData, () => { let receivedError = browser.runtime.lastError; if (receivedError) { console.error(receivedError); } created.resolve(); }); await created.promise; if (id != createData.id) { console.error(`Menu with requested id <${createData.id}> was created as <${id}>`) } if (composeContextEntries.includes(id)) { console.error(`Menu with id <${id}} exists already!`) } else { composeContextEntries.push(id); } if (entry.id && entry.children) { await processMenuData(entry.children, createData.id); } } } async function getContactMenuData(type) { let fields = ["firstname", "lastname", "fullname", "displayname", "nickname", "email", "workphone", "faxnumber", "cellularnumber", "jobtitle", "custom1", "custom2", "custom3", "custom4"]; let children = []; for (let field of fields) { children.push({ id: field, onclick: (info, tab) => quicktext.insertVariable({ tabId: tab.id, variable: `${type}=${field}` }) }) } return children; } async function getComposeBodyMenuData() { let menuData = []; let contexts = ["compose_body", "compose_action_menu"]; let templates = await storage.getTemplates(); for (let i = 0; i < templates.groups.length; i++) { let children = []; for (let j = 0; j < templates.texts[i].length; j++) { children.push({ id: `group-${i}-text-${j}`, title: templates.texts[i][j].name, onclick: (info, tab) => quicktext.insertTemplate(tab.id, i, j) }); } // Ignore this group, if it has now children. if (children.length == 0) { continue; } // If this group has only a single child, and menuCollapse is true, print // only that. if (await storage.getPref("menuCollapse") && children.length == 1) { menuData.push(children[0]); continue; } menuData.push({ contexts, id: `group-${i}`, title: templates.groups[i].name, children }); } if (templates.groups.length > 0) { menuData.push({ contexts, id: `group-separator`, type: "separator" }); } menuData.push( { contexts, id: "variables", children: [ { id: "to", children: await getContactMenuData("TO") }, { id: "from", children: await getContactMenuData("FROM") }, { id: "attachments", children: [ { id: "filename", onclick: (info, tab) => quicktext.insertVariable({ tabId: tab.id, variable: 'ATT=name' }) }, { id: "filenameAndSize", onclick: (info, tab) => quicktext.insertVariable({ tabId: tab.id, variable: 'ATT=full' }) }, ] }, { id: "dateTime", children: [ { id: "date", title: await quicktext.parseVariable({ variable: "DATE" }), onclick: (info, tab) => quicktext.insertVariable({ tabId: tab.id, variable: "DATE" }) }, { id: "date-long", title: await quicktext.parseVariable({ variable: "DATE=long" }), onclick: (info, tab) => quicktext.insertVariable({ tabId: tab.id, variable: "DATE=long" }) }, { id: "date-month", title: await quicktext.parseVariable({ variable: "DATE=monthname" }), onclick: (info, tab) => quicktext.insertVariable({ tabId: tab.id, variable: "DATE=monthname" }) }, { id: "time", title: await quicktext.parseVariable({ variable: "TIME" }), onclick: (info, tab) => quicktext.insertVariable({ tabId: tab.id, variable: "TIME" }) }, { id: "time-seconds", title: await quicktext.parseVariable({ variable: "TIME=seconds" }), onclick: (info, tab) => quicktext.insertVariable({ tabId: tab.id, variable: "TIME=seconds" }) } ] }, { id: "other", children: [ { id: "clipboard", onclick: (info, tab) => quicktext.insertVariable({ tabId: tab.id, variable: 'CLIPBOARD' }) }, { id: "counter", onclick: (info, tab) => quicktext.insertVariable({ tabId: tab.id, variable: 'COUNTER' }) }, { id: "subject", onclick: (info, tab) => quicktext.insertVariable({ tabId: tab.id, variable: 'SUBJECT' }) }, { id: "version", onclick: (info, tab) => quicktext.insertVariable({ tabId: tab.id, variable: 'VERSION' }) }, ] } ] }, { contexts, id: "other", children: [ { id: "insertTextFromFileAsText", onclick: (info, tab) => quicktext.insertContentFromFile(tab.id, 0) }, { id: "insertTextFromFileAsHTML", onclick: (info, tab) => quicktext.insertContentFromFile(tab.id, 1) }, ] }, { contexts, id: "separator", type: "separator", }, { contexts, id: "settings", title: messenger.i18n.getMessage("quicktext.settings.title"), onclick: (info, tab) => messenger.Quicktext.openTemplateManager() }, ); return menuData; } async function updateDateTimeMenus() { let fields = ["date-short", "date-long", "date-monthname", "time-noseconds", "time-seconds"]; let menus = ["variables.dateTime."]; let now = Date.now(); for (let menu of menus) { for (let field of fields) { const title = messenger.i18n.getMessage("date", utils.getDateTimeFormat(field, now)); await messenger.menus.update(`${menu}${field}`, { title }) } } }quicktext-6.3.2/modules/quicktext.mjs000066400000000000000000000263521477370713100177710ustar00rootroot00000000000000/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import * as storage from "/modules/storage.mjs"; import * as utils from "/modules/utils.mjs"; import { QuicktextParser } from "/modules/quicktextParser.mjs"; // Helper export async function readLegacyXmlTemplateFile() { let templateFolder = await storage.getPref("templateFolder"); let { templateFilePath } = await browser.Quicktext.getQuicktextFilePaths(templateFolder); let xmlData = await browser.Quicktext.readTextFile(templateFilePath); return parseLegacyXmlData(xmlData); } export async function readXmlScriptFile() { let templateFolder = await storage.getPref("templateFolder"); let { scriptFilePath } = await browser.Quicktext.getQuicktextFilePaths(templateFolder); let xmlData = await browser.Quicktext.readTextFile(scriptFilePath); return parseLegacyXmlData(xmlData); } export async function parseLegacyXmlData(xmlData) { const domParser = new DOMParser(); const dom = domParser.parseFromString(xmlData, "text/xml"); const version = dom.documentElement.getAttribute("version"); const foundGroups = []; const foundTexts = []; const foundScripts = []; switch (version) { case "2": const filetype = getTagValue(dom.documentElement, "filetype"); switch (filetype) { case "scripts": { const elems = dom.documentElement.getElementsByTagName("script"); for (let i = 0; i < elems.length; i++) { let tmp = { name: getTagValue(elems[i], "name"), script: getTagValue(elems[i], "body"), protected: false }; foundScripts.push(tmp); } } break; case "": case "templates": { const elems = dom.documentElement.getElementsByTagName("menu"); for (let i = 0; i < elems.length; i++) { let tmp = { name: getTagValue(elems[i], "title"), protected: false }; foundGroups.push(tmp); const subTexts = []; const textsNodes = elems[i].getElementsByTagName("texts"); if (textsNodes.length > 0) { const subElems = textsNodes[0].getElementsByTagName("text"); for (let j = 0; j < subElems.length; j++) { let tmp = { name: getTagValue(subElems[j], "name"), text: getTagValue(subElems[j], "body"), shortcut: subElems[j].getAttribute("shortcut"), type: subElems[j].getAttribute("type") == "0" ? "text/plain" : "text/html", keyword: getTagValue(subElems[j], "keyword"), subject: getTagValue(subElems[j], "subject"), attachments: getTagValue(subElems[j], "attachments"), }; subTexts.push(tmp); } } foundTexts.push(subTexts); } } break; default: // Alert the user that the importer don't understand the filetype break; } break; default: console.error("invalid data format", xmlData) return; } const imports = {} if (foundScripts.length > 0) { imports.scripts = []; for (let i = 0; i < foundScripts.length; i++) { imports.scripts.push(foundScripts[i]); } } if (foundGroups.length > 0 && foundTexts.length > 0) { imports.templates = {}; imports.templates.groups = []; for (let i = 0; i < foundGroups.length; i++) { imports.templates.groups.push(foundGroups[i]); } imports.templates.texts = []; for (let i = 0; i < foundTexts.length; i++) { imports.templates.texts.push(foundTexts[i]); } } return imports; } export async function parseConfigFileData(fileData) { let errors = []; try { return JSON.parse(fileData); } catch (e) { errors.push(e); } try { return await parseLegacyXmlData(fileData); } catch (e) { errors.push(e); } console.error("Failed to parse config file, does not seem to be a supported JSON or XML format", errors); } function getTagValue(aElem, aTag) { const tagElem = aElem.getElementsByTagName(aTag); if (tagElem.length > 0) { // can't be used anymore as sometimes there are several CDATA entries - see removeIllegalCharsCDATA // return tagElem[0].firstChild.nodeValue; let result = ''; for (const child of tagElem[0].childNodes) { result = result + child.nodeValue; } return result; } return ""; } // ---- MERGE export function mergeTemplates(templates, importedTemplates, forceProtected = false) { if (importedTemplates.groups && importedTemplates.texts && importedTemplates.texts.length > 0 && importedTemplates.groups.length == importedTemplates.texts.length) { // If a group exists already, import into the existing group. templates.groups.forEach((group, existingGroupIdx) => { let groupImportIdx = importedTemplates.groups.findIndex(i => i.name == group.name); if (groupImportIdx != -1) { console.log(`Found existing group ${group.name} in imported groups.`) templates.groups[existingGroupIdx] = importedTemplates.groups[groupImportIdx]; templates.groups[existingGroupIdx].protected = forceProtected; importedTemplates.groups.splice(groupImportIdx, 1); // Handle texts of this group: // merge imports.texts[groupImportIdx] into templates.texts[existingGroupIdx] templates.texts[existingGroupIdx].forEach((text, existingTextIndex) => { let textImportIdx = importedTemplates.texts[groupImportIdx].findIndex(i => i.name == text.name); if (textImportIdx != -1) { console.log(`Replacing text ${text.name} with imported version.`) templates.texts[existingGroupIdx][existingTextIndex] = importedTemplates.texts[groupImportIdx][textImportIdx]; importedTemplates.texts[groupImportIdx].splice(textImportIdx, 1); } }); // Add remaining texts to this group. templates.texts[existingGroupIdx].push(...importedTemplates.texts[groupImportIdx]); importedTemplates.texts.splice(groupImportIdx, 1); } }); // Add remaining new templates. templates.texts.push(...importedTemplates.texts); templates.groups.push(...importedTemplates.groups.map(g => ({ ...g, protected: forceProtected }))); } } export function mergeScripts(scripts, importedScripts, forceProtected = false) { if (importedScripts && importedScripts.length > 0) { // Overwrite local existing versions. scripts.forEach((script, existingScriptIdx) => { let importScriptIdx = importedScripts.findIndex(i => i.name == script.name); if (importScriptIdx != -1) { console.log(`Replacing script ${script.name} with imported version.`) scripts[existingScriptIdx] = importedScripts[importScriptIdx]; scripts[existingScriptIdx].protected = forceProtected; importedScripts.splice(importScriptIdx, 1); } }); // Add the remaining new scripts. scripts.push(...importedScripts.map(g => ({ ...g, protected: forceProtected }))); } } // ---- INSERT async function getQuicktextParser({ tabId, forceAsText }) { let templates = await storage.getTemplates(); let scripts = await storage.getScripts(); // If aForceAsText is not set, but after parsing it is set, we should rerun // with aForceAsText set from the beginning. let qParser = new QuicktextParser(tabId, templates, scripts, forceAsText); await qParser.loadState(); return qParser; } export async function insertTemplate(tabId, groupIdx, textIdx, forceAsText) { let qParser = await getQuicktextParser({ tabId, forceAsText }); let group = qParser.templates.groups[groupIdx]; let text = qParser.templates.texts[groupIdx][textIdx]; await qParser.clearNonPersistentData(); qParser.keepStates = true; await insertSubject({ qParser, subject: text.subject }); await insertAttachments({ qParser, attachments: text.attachments }); await insertVariable({ qParser, variable: `TEXT=${group.name}|${text.name}` }); qParser.keepStates = false; await qParser.clearNonPersistentData(); } export async function parseVariable({ tabId, variable, forceAsText, qParser }) { if (!qParser) { qParser = await getQuicktextParser({ tabId, forceAsText }) } return qParser.parse("[[" + variable + "]]"); } export async function insertVariable({ tabId, variable, forceAsText, qParser }) { if (!qParser) { qParser = await getQuicktextParser({ tabId, forceAsText }) } let parsed = await parseVariable({ tabId, variable, forceAsText, qParser }) if (parsed) { await qParser.insertBody(parsed, { extraSpace: false }); } } async function insertSubject({ qParser, subject }) { if (!subject) { return; } let parsedSubject = await qParser.parse(subject); if (parsedSubject && !parsedSubject.match(/^\s+$/)) { await qParser.setDetail("subject", parsedSubject); } } async function insertAttachments({ qParser, attachments }) { for (let attachment of attachments.split(";")) { if (!attachment) { continue; } let bytes = await browser.Quicktext.readBinaryFile(attachment); let leafName = utils.getLeafName(attachment); let type = utils.getTypeFromExtension(leafName); let file = new File([bytes], leafName, { type }); qParser.addAttachment(file); }; } export async function insertContentFromFile(aTabId, aType) { let file = utils.pickFileFromDisc(aType); if (file) { return insertFile(aTabId, file, aType); } } export async function insertFile(tabId, file, aType) { const content = await utils.getTextFileContent(file); if (!content) { return; } let qParser = await getQuicktextParser({ tabId, forceAsText: aType == 0 }) await qParser.insertBody(content, { extraSpace: false }); } // This function is called from outside and needs to use data of an existing // parser export async function getTag({ tabId, tag, variables }) { let qParser = await getQuicktextParser({ tabId }) return await qParser[`get_${tag.toLowerCase()}`](variables); } // This function is called from outside and needs to use data of an existing // parser export async function processTag({ tabId, tag, variables }) { let qParser = await getQuicktextParser({ tabId }) return await qParser[`process_${tag.toLowerCase()}`](variables); } // ---- TEMPLATE // This is defined async, so it can be used in an runtime.onMessage listener // without further logic to return a Promise. export async function getKeywordsAndShortcuts() { let templates = await storage.getTemplates(); let keywords = {}; let shortcuts = {}; for (let i = 0; i < templates.groups.length; i++) { for (let j = 0; j < templates.texts[i].length; j++) { let text = templates.texts[i][j]; let shortcut = text.shortcut; if (shortcut != "" && typeof shortcuts[shortcut] == "undefined") { shortcuts[shortcut] = [i, j]; } let keyword = text.keyword; if (keyword != "" && typeof keywords[keyword.toLowerCase()] == "undefined") keywords[keyword.toLowerCase()] = [i, j]; } } return { keywords, shortcuts }; } quicktext-6.3.2/modules/quicktextParser.mjs000066400000000000000000001066531477370713100211510ustar00rootroot00000000000000/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import * as utils from "/modules/utils.mjs"; import * as storage from "/modules/storage.mjs"; const allowedTags = [ 'ALERT', 'ATT', 'CLIPBOARD', 'COUNTER', 'CSCRIPT', 'DATE', 'ESCRIPT', 'FILE', 'IMAGE', 'FROM', 'INPUT', 'ORGATT', 'ORGHEADER', 'SCRIPT', 'SUBJECT', 'TEXT', 'TIME', 'TO', 'URL', 'VERSION', 'SELECTION', 'HEADER' ]; // The value of these tags are persistent and only computed once per tab. All other // tags are computed once per template insertion and then re-use the computed value. // If another template is inserted (or the same template again), the state is cleared. const persistentTags = ['COUNTER', 'ORGATT', 'ORGHEADER', 'VERSION']; export class QuicktextParser { constructor(aTabId, templates, scripts, forceAsText = false) { this.mTabId = aTabId; this.mTemplates = templates; this.mScripts = scripts; this.mForceAsText = forceAsText; this.mData = {} this.mDetails = null; this.keepStates = false; } async insertBody(aStr, options = {}) { let type = await this.getInsertType(); if (type == 0) { await messenger.tabs.sendMessage(this.mTabId, { insertText: aStr, extraSpace: options.extraSpace, }); } else { await messenger.tabs.sendMessage(this.mTabId, { insertHtml: utils.removeBadHTML(aStr), extraSpace: options.extraSpace, }); } } get tabId() { return this.mTabId } get scripts() { return this.mScripts; } get templates() { return this.mTemplates; } async clearNonPersistentData() { for (let key of Object.keys(this.mData)) { if (persistentTags.includes(key)) { continue; } delete this.mData[key]; } } async saveState() { let state = { mForceAsText: this.mForceAsText, mData: this.mData, } await browser.storage.local.set({ [`QuicktextStateData_${this.mTabId}`]: state }); } async loadState() { let stateData = await browser.storage.local .get({ [`QuicktextStateData_${this.mTabId}`]: null }) .then(rv => rv[`QuicktextStateData_${this.mTabId}`]); if (stateData) { this.mForceAsText = stateData.mForceAsText; this.mData = stateData.mData; } } async getInsertType() { let details = await this.getDetails(); if (details.isPlainText || this.mForceAsText) { return 0; } return 1; } async getDetails() { if (!this.mDetails) { this.mDetails = await browser.compose.getComposeDetails(this.mTabId); } return this.mDetails } async setDetail(name, newValue) { await browser.compose.setComposeDetails(this.mTabId, { [name]: newValue }); this.mDetails = await browser.compose.getComposeDetails(this.mTabId); } async addDetail(name, newValue) { let values = await browser.compose .getComposeDetails(this.tabId) .then(details => details[name]); if (!Array.isArray(values)) { values = [values]; } if (values.includes(newValue)) { return; } values.push(newValue); await browser.compose.setComposeDetails(this.mTabId, { [name]: values }); this.mDetails = await browser.compose.getComposeDetails(this.mTabId); } async addAttachment(file) { await browser.compose.addAttachment(this.mTabId, { file }) this.mDetails = await browser.compose.getComposeDetails(this.mTabId); } // These process functions get the data and mostly saves it // in this.mData so if the data is requested again, it is quick. // Not all tags have a process function. // The get-functions takes the data from the process-functions and // returns string depending of what aVariables is. async get_header(aVariables) { if (aVariables.length == 0) { return ""; } let name = aVariables[0].toLowerCase(); switch (name) { case "to": case "cc": case "bcc": await this.addDetail(name, aVariables[1]); break; case "reply-to": await this.addDetail("replyTo", aVariables[1]); break; case "from": case "subject": await this.setDetail(name, aVariables[1]); break; } return ""; } async get_script(aVariables) { return this.process_script(aVariables); } async process_script(aVariables) { if (aVariables.length == 0) return ""; let scriptName = aVariables.shift(); // Looks through all scripts and tries to find the one we look for. for (let script of this.mScripts) { if (script.name == scriptName) { let returnValue = ""; try { // MV2 - allows code injection via strings. returnValue = await browser.tabs.executeScript(this.mTabId, { code: `(async function (tabId, sVariables) { this.identities = {}; for (let func of [ "get", "getDefault", "list" ]) { this.identities[func] = (...params) => browser.runtime.sendMessage({ command: "identitiesAPI", func, params, }) } this.compose = {}; for (let func of [ "getComposeDetails", "setComposeDetails", "addAttachment", "removeAttachment", "updateAttachment", "getAttachmentFile", "listAttachments", "getActiveDictionaries", "setActiveDictionaries", "beginNew", "beginForward", "beginReply", ]) { this.compose[func] = (...params) => browser.runtime.sendMessage({ command: "composeAPI", func, params, }) } this.messages = {}; for (let func of [ "get", "getFull", "getRaw", "listAttachments", "listInlineTextParts", "getAttachmentFile", ]) { this.messages[func] = (...params) => browser.runtime.sendMessage({ command: "messagesAPI", func, params, }) } this.quicktext = { tabId, variables: sVariables, processTag: (tag, ...variables) => browser.runtime.sendMessage({ command: "processTag", tabId, tag, variables, }), getTag: (tag, ...variables) => browser.runtime.sendMessage({ command: "getTag", tabId, tag, variables, }), }; ${script.script}; }).call({}, ${this.mTabId},${JSON.stringify(aVariables)});`, }).then(rv => rv[0] ? rv[0] : ""); // MV3 - No string support :-(. /* returnValue = await browser.scripting.executeScript({ target: { tabId: this.mTabId }, args: [this.mTabId], func: new Function("tabId",`return tabId;`), }).then(rv => rv[0].result); */ // UNSAFE EVAL - Blocked by CPG, banned on ATN. // "content_security_policy": "script-src 'self' 'unsafe-eval'", /* let scope = {} scope.mDetails = await this.getDetails(); scope.mVariables = aVariables; scope.mQuicktext = this; scope.mTabId = this.mTabId; const AsyncFunction = Object.getPrototypeOf(async function () { }).constructor; const func = new AsyncFunction('with(this) { ' + script.script + ' }'); returnValue = await func.call(scope); */ } catch (e) { if (this.mTabId) { await messenger.tabs.sendMessage(this.mTabId, { alertLabel: `[${script.name}] ${browser.i18n.getMessage("scriptError")}\n${e.name}: ${e.message}`, }); } } return returnValue || ""; } } // If we reach this point, the user requested an non-existing script. await messenger.tabs.sendMessage(this.mTabId, { alertLabel: browser.i18n.getMessage("scriptNotFound", [scriptName]), }); return ""; } async get_escript(aVariables) { return this.process_escript(aVariables); } async process_escript(aVariables) { if (aVariables.length < 2) return ""; let [extensionId, scriptName, ...scriptArgs] = aVariables; let transmission = Promise.withResolvers(); try { let port = browser.runtime.connect(extensionId, { name: "quicktext" }); port.onMessage.addListener(async message => { switch (message.command) { case "evaluatedScript": transmission.resolve(message.evaluatedScript); break; case "processTag": { let processedTag = await this[`process_${message.tag.toLowerCase()}`](message.variables); port.postMessage({ command: "processedTag", processedTag }); } break; case "getTag": { let gotTag = await this[`get_${message.tag.toLowerCase()}`](message.variables); port.postMessage({ command: "gotTag", gotTag }); } break; } }); port.postMessage({ command: "evaluateScript", scriptName, scriptArgs, tabId: this.mTabId, }); let rv = await transmission.promise; port.disconnect(); return rv ? rv : ""; } catch (ex) { console.error(`Failed to request script from <${extensionId}>`, ex) } return ""; } async get_cscript(aVariables) { return this.process_cscript(aVariables); } async process_cscript(aVariables) { return this.process_escript(["quicktext.scripts@community.jobisoft.de", ...aVariables]); } // This needs the permission, otherwise requests to remote pages // will fail due to CORS. async process_url(aVariables) { if (aVariables.length == 0) { return ""; } let url = aVariables.shift(); if (url == "") { return ""; } let debug = true; let method = "post"; let post = []; if (aVariables.length > 0) { let variables = aVariables.shift().split(";"); for (let k = 0; k < variables.length; k++) { let tag = variables[k].toLowerCase(); let data = null; switch (tag) { case 'to': case 'att': case 'orgheader': case 'orgatt': data = await this["process_" + tag](); if (typeof data != 'undefined') { for (let i in data) for (let j in data[i]) post.push(tag + '[' + i + '][' + j + ']=' + data[i][j]); } break; case 'from': case 'version': case 'date': case 'time': data = await this["process_" + tag](); if (typeof data != 'undefined') { for (let i in data) post.push(tag + '[' + i + ']=' + data[i]); } break; case 'subject': case 'clipboard': case 'selection': case 'counter': data = await this["process_" + tag](); if (typeof data != 'undefined') post.push(tag + '=' + data); break; case 'post': case 'get': case 'options': method = tag; break; case 'debug': debug = true; break; } } } let response = new Promise(resolve => { let req = new XMLHttpRequest(); req.open(method, url, true); if (method == "post") req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); req.ontimeout = function () { if (debug) { resolve("Quicktext timeout"); } else { resolve() } }; req.onerror = function () { if (debug) { resolve(`Quicktext global error: ${req.status}`); } else { resolve() } }; req.onload = function () { if (req.status == 200) { resolve(req.responseText); } else if (debug) { resolve(`Quicktext onLoad error: ${req.status}`); } else { resolve(); } }; let postdata = method == "post" ? post.map(encodeURIComponent).join("&") : null; req.send(postdata); }); return response; } async get_url(aVariables) { return this.process_url(aVariables); } async get_file(aVariables) { return this.process_file(aVariables); } async process_file(aVariables) { if (aVariables.length > 0 && aVariables[0] != "") { // Tries to open the file and returning the content. try { let content = await browser.Quicktext.readTextFile(aVariables[0]); if (aVariables.length > 1 && aVariables[1].includes("force_as_text")) { this.mForceAsText = true; } if (aVariables.length > 1 && aVariables[1].includes("strip_html_comments")) { content = content.replace(/)/g, ''); } return content; } catch (e) { console.error(e); } } return ""; } async process_image_content(aVariables) { let rv = ""; if (aVariables.length > 0 && aVariables[0] != "") { let mode = (aVariables.length > 1 && "src" == aVariables[1].toString().toLowerCase()) ? "src" : "tag"; // Tries to open the file and returning the content try { let bytes = await browser.Quicktext.readBinaryFile(aVariables[0]); let leafName = utils.getLeafName(aVariables[0]); let type = utils.getTypeFromExtension(leafName); let binContent = utils.uint8ArrayToBase64(bytes); let src = "data:" + type + ";filename=" + leafName + ";base64," + binContent; rv = (mode == "tag") ? "" : src; } catch (e) { console.error(e); } } return rv; } async get_image(aVariables) { let details = await this.getDetails(); if (!details.isPlainText) { // image tag may only be added in html mode return this.process_image_content(aVariables); } else { return ""; } } async process_selection(aVariables) { let details = await this.getDetails(); if (details.isPlainText) { return messenger.tabs.sendMessage(this.mTabId, { getSelection: "TEXT", }); } else { return messenger.tabs.sendMessage(this.mTabId, { getSelection: "HTML", }); } } async get_selection(aVariables, aType) { return this.process_selection(aVariables, aType); } async process_text(aVariables) { if (aVariables.length != 2) return ""; // Looks after the group and text-name and returns // the text from it for (let i = 0; i < this.mTemplates.groups.length; i++) { if (aVariables[0] == this.mTemplates.groups[i].name) { for (let j = 0; j < this.mTemplates.texts[i].length; j++) { let text = this.mTemplates.texts[i][j]; if (aVariables[1] == text.name) { let content = text.text; // Force insertion mode to TEXT if the template requests it. // This will affect also the "parent" template, if the current // template is a nested template, because the entire parsed string // will be inserted in one go. if (text.type == "text/plain") { this.mForceAsText = true; } if (aVariables.length > 1 && aVariables[1].includes("force_as_text")) { this.mForceAsText = true; } if (aVariables.length > 1 && aVariables[1].includes("strip_html_comments")) { content = content.replace(/)/g, ''); } return content; } } } } return ""; } async get_text(aVariables) { return this.process_text(aVariables); } async process_input(aVariables) { if (typeof this.mData['INPUT'] == 'undefined') this.mData['INPUT'] = {}; if (typeof this.mData['INPUT'].data == 'undefined') this.mData['INPUT'].data = {}; if (typeof this.mData['INPUT'].data[aVariables[0]] != 'undefined') return this.mData['INPUT'].data; let rv; let label = browser.i18n.getMessage("inputText", [aVariables[0]]); let value = typeof aVariables[2] != 'undefined' ? aVariables[2] : ""; // There are two types of input: select and text. if (aVariables[1] == 'select') { let values = value.split(";"); rv = await utils.openPopup(this.mTabId, { selectLabel: label, selectValues: values, }); } else { rv = await utils.openPopup(this.mTabId, { promptLabel: label, promptValue: value, }); } if (rv) { this.mData['INPUT'].data[aVariables[0]] = rv } else { this.mData['INPUT'].data[aVariables[0]] = ""; } return this.mData['INPUT'].data; } async get_input(aVariables) { let data = await this.process_input(aVariables); if (typeof data[aVariables[0]] != "undefined") return data[aVariables[0]]; return ""; } async process_alert(aVariables) { messenger.tabs.sendMessage(this.mTabId, { alertLabel: aVariables[0], }); } async get_alert(aVariables) { // An alert does not stop the evaluation. this.process_alert(aVariables); return ""; } async preprocess_org() { this.mData['ORGHEADER'] = {}; this.mData['ORGHEADER'].checked = true; this.mData['ORGHEADER'].data = {}; this.mData['ORGATT'] = {}; this.mData['ORGATT'].checked = true; this.mData['ORGATT'].data = []; let details = await this.getDetails(); if (!details.relatedMessageId) { return } // Store all headers in the mData-variable let data = await browser.messages.getFull(details.relatedMessageId); for (let [name, value] of Object.entries(data.headers)) { if (typeof this.mData['ORGHEADER'].data[name] == 'undefined') { this.mData['ORGHEADER'].data[name] = []; } this.mData['ORGHEADER'].data[name].push(...value); } // Store all attachments in the mData-variable let attachments = await browser.messages.listAttachments(details.relatedMessageId); for (let attachment of attachments) { this.mData['ORGATT'].data.push(attachment); // {contentType, name, size, partName} } } async process_orgheader(aVariables) { if (this.mData['ORGHEADER'] && this.mData['ORGHEADER'].checked) return this.mData['ORGHEADER'].data; await this.preprocess_org(); return this.mData['ORGHEADER'].data; } async get_orgheader(aVariables) { if (aVariables.length == 0) { return ""; } let data = await this.process_orgheader(aVariables); let name = aVariables[0].toLowerCase(); let seperator = aVariables.length > 1 ? aVariables[1].replace(/\\n/g, "\n").replace(/\\t/g, "\t") : ", " // data is array of objects, reduce to array of specific object member. if (data[name]) { return data[name].join(seperator); } return ""; } async process_orgatt(aVariables) { if (this.mData['ORGATT'] && this.mData['ORGATT'].checked) return this.mData['ORGATT'].data; await this.preprocess_org(); return this.mData['ORGATT'].data; } async get_orgatt(aVariables) { let data = await this.process_orgatt(aVariables); let seperator = aVariables.length > 0 ? aVariables[0].replace(/\\n/g, "\n").replace(/\\t/g, "\t") : ", " // data is array of objects {contentType, name, size, partName}, reduce to // array of specific object member. return data.map(a => a["name"]).join(seperator); } async process_version(aVariables) { if (this.mData['VERSION'] && this.mData['VERSION'].checked) { return this.mData['VERSION'].data; } let info = await browser.runtime.getBrowserInfo(); this.mData['VERSION'] = {}; this.mData['VERSION'].checked = true; this.mData['VERSION'].data = {}; this.mData['VERSION'].data['number'] = info.version; this.mData['VERSION'].data['full'] = `${info.name} ${info.version}`; return this.mData['VERSION'].data; } async get_version(aVariables = []) { let data = await this.process_version(aVariables); if (aVariables.length < 1) { aVariables.push("full"); } if (typeof data[aVariables[0]] != 'undefined') { return data[aVariables[0]]; } return ""; } async process_att(aVariables) { if (this.mData['ATT'] && this.mData['ATT'].checked) return this.mData['ATT'].data; this.mData['ATT'] = {}; this.mData['ATT'].checked = true; this.mData['ATT'].data = []; let attachments = await browser.compose.listAttachments(this.mTabId); for (let attachment of attachments) { let file = await browser.compose.getAttachmentFile(attachment.id); this.mData['ATT'].data.push([file.name, file.size, file.lastModified]); } return this.mData['ATT'].data; } async get_att(aVariables) { let data = await this.process_att(aVariables); if (data.length > 0) { let value = []; for (let i in data) { if (aVariables[0] == "full") value.push(data[i][0] + " (" + await browser.messengerUtilities.formatFileSize(data[i][1]) + ")"); else if (aVariables[0] == "modified") value.push(data[i][2]) else value.push(data[i][0]); } if (aVariables.length < 2) aVariables[1] = ", "; return utils.trimString(value.join(aVariables[1].replace(/\\n/g, "\n").replace(/\\t/g, "\t"))); } return ""; } async process_subject(aVariables) { if (this.mData['SUBJECT'] && this.mData['SUBJECT'].checked) return this.mData['SUBJECT'].data; this.mData['SUBJECT'] = {}; this.mData['SUBJECT'].checked = true; this.mData['SUBJECT'].data = ""; let details = await this.getDetails(); this.mData['SUBJECT'].data = details.subject; return this.mData['SUBJECT'].data; } async get_subject(aVariables) { return this.process_subject(aVariables); } preprocess_datetime() { this.mData['DATE'] = {}; this.mData['DATE'].checked = true; this.mData['DATE'].data = {}; this.mData['TIME'] = {}; this.mData['TIME'].checked = true; this.mData['TIME'].data = {}; let timeStamp = new Date(); let fields = ["DATE-long", "DATE-short", "DATE-monthname", "TIME-seconds", "TIME-noseconds"]; for (let i = 0; i < fields.length; i++) { let field = fields[i]; let fieldinfo = field.split("-"); this.mData[fieldinfo[0]].data[fieldinfo[1]] = utils.trimString(utils.getDateTimeFormat(field, timeStamp)); } } async process_date(aVariables) { if (this.mData['DATE'] && this.mData['DATE'].checked) return this.mData['DATE'].data; this.preprocess_datetime(); return this.mData['DATE'].data; } async process_time(aVariables) { if (this.mData['TIME'] && this.mData['TIME'].checked) return this.mData['TIME'].data; this.preprocess_datetime(); return this.mData['TIME'].data; } async get_date(aVariables) { let data = await this.process_date(aVariables); if (aVariables.length < 1) aVariables[0] = "short"; if (typeof data[aVariables[0]] != 'undefined') return data[aVariables[0]]; return ""; } async get_time(aVariables) { let data = await this.process_time(aVariables); if (aVariables.length < 1) aVariables[0] = "noseconds"; if (typeof data[aVariables[0]] != 'undefined') return data[aVariables[0]]; return ""; } async process_clipboard(aVariables) { if (this.mData['CLIPBOARD'] && this.mData['CLIPBOARD'].checked) return this.mData['CLIPBOARD'].data; this.mData['CLIPBOARD'] = {}; this.mData['CLIPBOARD'].checked = true; this.mData['CLIPBOARD'].data = ""; // I do not know how to access html variant, but if, we would call // this.getDetails and check isPlainText to determine if we need it. this.mData['CLIPBOARD'].data = await navigator.clipboard.readText(); return this.mData['CLIPBOARD'].data; } async get_clipboard(aVariables) { return utils.trimString(await this.process_clipboard(aVariables)); } async process_counter(aVariables) { if (this.mData['COUNTER'] && this.mData['COUNTER'].checked) return this.mData['COUNTER'].data; this.mData['COUNTER'] = {}; this.mData['COUNTER'].checked = true; this.mData['COUNTER'].data = await storage.getPref("counter"); this.mData['COUNTER'].data++; await storage.setPref("counter", this.mData['COUNTER'].data); return this.mData['COUNTER'].data; } async get_counter(aVariables) { return this.process_counter(aVariables); } async process_from(aVariables) { if (this.mData['FROM'] && this.mData['FROM'].checked) { return this.mData['FROM'].data; } let details = await this.getDetails(); let identity = await browser.identities.get(details.identityId); this.mData['FROM'] = {}; this.mData['FROM'].checked = true; this.mData['FROM'].data = { 'email': identity.email, 'displayname': identity.name, 'firstname': '', 'lastname': '' }; await this.getcarddata_from(identity); return this.mData['FROM'].data; } async getcarddata_from(identity) { // 1. CardBook -> need cardbook api // ... // 2. search identity email let cards = await browser.contacts.quickSearch({ includeRemote: false, searchString: identity.email.toLowerCase() }) let card = cards.find(c => c.type == "contact"); // 3. vcard of identity -> todo: not yet supported if (!card && identity.escapedVCard) { //card = manager.escapedVCardToAbCard(aIdentity.escapedVCard); } if (!card) { return; } // Get directly stored props first. for (let [name, value] of Object.entries(card.properties)) { // For backward compatibility, use lowercase props. this.mData['FROM'].data[name.toLowerCase()] = value; } this.mData['FROM'].data['fullname'] = utils.trimString(this.mData['FROM'].data['firstname'] + " " + this.mData['FROM'].data['lastname']); } async get_from(aVariables) { let data = await this.process_from(aVariables); if (typeof data[aVariables[0]] != 'undefined') { return utils.trimString(data[aVariables[0]]); } return ""; } async process_to(aVariables) { if (this.mData['TO'] && this.mData['TO'].checked) return this.mData['TO'].data; this.mData['TO'] = {}; this.mData['TO'].checked = true; this.mData['TO'].data = { 'email': [], 'firstname': [], 'lastname': [], 'fullname': [] }; let details = await this.getDetails(); let emailAddresses = Array.isArray(details.to) ? details.to : [details.to]; for (let i = 0; i < emailAddresses.length; i++) { // TODO: Add code for getting info about all people in a mailing list let contactData = await utils.parseDisplayName(emailAddresses[i]); let k = this.mData['TO'].data['email'].length; this.mData['TO'].data['email'][k] = contactData.email.toLowerCase(); this.mData['TO'].data['fullname'][k] = utils.trimString(contactData.name); this.mData['TO'].data['firstname'][k] = ""; this.mData['TO'].data['lastname'][k] = ""; await this.getcarddata_to(k); let validParts = [this.mData['TO'].data['firstname'][k], this.mData['TO'].data['lastname'][k]].filter(e => e.trim() != ""); if (validParts.length == 0) { // if no first and last name, generate them from fullname let parts = this.mData['TO'].data['fullname'][k].replace(/,/g, ", ").split(" ").filter(e => e.trim() != ""); this.mData['TO'].data['firstname'][k] = parts.length > 1 ? utils.trimString(parts.splice(0, 1)) : ""; this.mData['TO'].data['lastname'][k] = utils.trimString(parts.join(" ")); } else { // if we have a first and/or last name (which can only happen if read from card), generate fullname from it this.mData['TO'].data['fullname'][k] = validParts.join(" "); } // swap names if wrong if (this.mData['TO'].data['firstname'][k].endsWith(",")) { let temp_firstname = this.mData['TO'].data['firstname'][k].replace(/,/g, ""); let temp_lastname = this.mData['TO'].data['lastname'][k]; this.mData['TO'].data['firstname'][k] = temp_lastname; this.mData['TO'].data['lastname'][k] = temp_firstname; // rebuild fullname this.mData['TO'].data['fullname'][k] = [this.mData['TO'].data['firstname'][k], this.mData['TO'].data['lastname'][k]].join(" "); } } return this.mData['TO'].data; } async getcarddata_to(aIndex) { // 1. CardBook -> need cardbook api // ... // take card value, if it exists // 2. search identity email let cards = await browser.contacts.quickSearch({ includeRemote: false, searchString: this.mData['TO'].data['email'][aIndex].toLowerCase() }) let card = cards.find(c => c.type == "contact"); if (card != null) { // Get directly stored props first. for (let [name, value] of Object.entries(card.properties)) { let lowerCaseName = name.toLowerCase(); if (typeof this.mData['TO'].data[lowerCaseName] == 'undefined') { this.mData['TO'].data[lowerCaseName] = [] } if (value != "" || typeof this.mData['TO'].data[lowerCaseName][aIndex] == 'undefined' || this.mData['TO'].data[lowerCaseName][aIndex] == "") { this.mData['TO'].data[lowerCaseName][aIndex] = utils.trimString(value); } } } return this.mData; } async get_to(aVariables) { let data = await this.process_to(aVariables); if (typeof data[aVariables[0]] != 'undefined') { // use ", " as default seperator let mainSep = (aVariables.length > 1) ? aVariables[1].replace(/\\n/g, "\n").replace(/\\t/g, "\t") : ", "; let lastSep = (aVariables.length > 2) ? aVariables[2].replace(/\\n/g, "\n").replace(/\\t/g, "\t") : mainSep; // clone the data, so we can work on it without mod the source object let entries = data[aVariables[0]].slice(0); let last = entries.pop(); // build the final string let all = []; if (entries.length > 0) all.push(entries.join(mainSep)); all.push(last); return all.join(lastSep); } return ""; } // ------------------------------------------------------------------------- async parse(aStr) { try { // Reparse the text until there is no difference in the text // or that we parse 100 times (so we don't make an infinitive loop) let oldStr; let count = 0; do { count++; oldStr = aStr; aStr = await this.parseText(aStr); } while (aStr != oldStr && count < 20); return aStr; } catch (ex) { console.log(ex); } } async parseText(aStr) { // If a template is inserted, keepStates is set to true and all non-persistent // states are kept until the entire template has been processed. The persistent // states are kept for the entire lifetime of the tab. if (!this.keepStates) { await this.clearNonPersistentData(); } let tags = getTags(aStr); // If we don't find any tags there will be no changes to the string so return. if (tags.length == 0) return aStr; // Replace all tags with there right contents for (let i = 0; i < tags.length; i++) { // Save state. await this.saveState(); let value = ""; let variable_limit = -1; switch (tags[i].tagName.toLowerCase()) { case 'att': case 'clipboard': case 'selection': case 'counter': case 'date': case 'subject': case 'time': case 'version': case 'orgatt': variable_limit = 0; break; case 'alert': case 'file': case 'image': case 'from': case 'input': case 'orgheader': case 'script': case 'cscript': case 'to': case 'url': variable_limit = 1; break; case 'text': case 'header': case 'escript': variable_limit = 2; break; } // if the method "get_[tagname]" exists and there is enough arguments we call it if (typeof this["get_" + tags[i].tagName.toLowerCase()] == "function" && variable_limit >= 0 && tags[i].variables.length >= variable_limit) { value = await this["get_" + tags[i].tagName.toLowerCase()](tags[i].variables); } // Save state. await this.saveState(); aStr = utils.replaceText(tags[i].tag, value, aStr); } return aStr; } } function getTags(aStr) { // We only get the beginning of the tag. // This is because we want to handle recursive use of tags. let rexp = new RegExp("\\[\\[((" + allowedTags.join("|") + ")(\\_[a-z]+)?)", "ig"); let results = []; let result = null; while ((result = rexp.exec(aStr))) results.push(result); // If we don't found any tags we return if (results.length == 0) return []; // Take care of the tags starting with the last one let hits = []; results.reverse(); let strLen = aStr.length; for (let i = 0; i < results.length; i++) { let tmpHit = {}; tmpHit.tag = results[i][0]; tmpHit.variables = []; // if the tagname contains a "_"-char that means // that is an old tag and we need to translate it // to a tagname and a variable let pos = results[i][1].indexOf("_"); if (pos > 0) { tmpHit.variables.push(results[i][1].substr(pos + 1).toLowerCase()); tmpHit.tagName = results[i][1].substring(0, pos); } else tmpHit.tagName = results[i][1]; // Get the end of the starttag pos = results[i].index + results[i][1].length + 2; // If the tag ended here we're done if (aStr.substr(pos, 2) == "]]") { tmpHit.tag += "]]"; hits = addTag(hits, tmpHit); } // If there is arguments we get them else if (aStr[pos] == "=") { // We go through until we find ]] but we must have went // through the same amount of [ and ] before. So if there // is an tag in the middle we just jump over it. pos++; let bracketCount = 0; let ready = false; let vars = ""; while (!ready && pos < strLen) { if (aStr[pos] == "[") bracketCount++; if (aStr[pos] == "]") { bracketCount--; if (bracketCount == -1 && aStr[pos + 1] == "]") { ready = true; break; } } vars += aStr[pos]; pos++; } // If we found the end we parses the arguments if (ready) { tmpHit.tag += "=" + vars + "]]"; vars = vars.split("|"); for (let j = 0; j < vars.length; j++) tmpHit.variables.push(vars[j]); // Adds the tag hits = addTag(hits, tmpHit); } } // We don't want to go over this tag again strLen = results[i].index; } hits.reverse(); return hits; } // Checks if the tag isn't added before. // We just want to handle all unique tags once function addTag(aTags, aNewTag) { for (let i = 0; i < aTags.length; i++) if (aTags[i].tag == aNewTag.tag) return aTags; aTags.push(aNewTag); return aTags; } quicktext-6.3.2/modules/storage.mjs000066400000000000000000000065521477370713100174140ustar00rootroot00000000000000/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ export async function getPref(aName, aFallback = null) { const defaultPref = await browser.storage.local .get({ [`${aName}.default`]: aFallback }) .then(o => o[`${aName}.default`]); return browser.storage.local .get({ [`${aName}.value`]: defaultPref }) .then(o => o[`${aName}.value`]); } export async function setPref(aName, aValue) { await browser.storage.local.set({ [`${aName}.value`]: aValue }); } export async function clearPref(aName) { await browser.storage.local.remove(`${aName}.value`); } export async function setTemplates(templates) { await browser.storage.local.set({ templates: JSON.stringify(templates) }); } export async function getTemplates() { return browser.storage.local.get({ templates: null }).then( e => e.templates ? JSON.parse(e.templates) : null); } export async function setScripts(scripts) { await browser.storage.local.set({ scripts: JSON.stringify(scripts) }); } export async function getScripts() { return browser.storage.local.get({ scripts: null }).then( e => e.scripts ? JSON.parse(e.scripts) : null); } export async function init(defaults = null) { // Migrate options from sync to local storage, as sync storage can only hold // 100 KB which will not be enough for templates. const { userPrefs: syncUserPrefs } = await browser.storage.sync.get({ userPrefs: null }); if (syncUserPrefs) { await browser.storage.local.set({ userPrefs: syncUserPrefs }); await browser.storage.sync.set({ userPrefs: null }); } // Migrate from userPrefs/defaultPrefs objects to *.value and *.default const { userPrefs } = await browser.storage.local.get({ userPrefs: null }); if (userPrefs) { for (let [key, value] of Object.entries(userPrefs)) { await browser.storage.local.set({ [`${key}.value`]: value }); } await browser.storage.local.remove("userPrefs"); } const { defaultPrefs } = await browser.storage.local.get({ defaultPrefs: null }); if (defaultPrefs) { await browser.storage.local.remove("defaultPrefs"); } // If defaults are given, push them into storage.local if (defaults) { for (let [key, value] of Object.entries(defaults)) { await browser.storage.local.set({ [`${key}.default`]: value }); } } } export class StorageListener { #watchedPrefs = []; #listener = null; #timeoutId; #changedWatchedPrefs = {}; #eventEmitter() { this.#listener(this.#changedWatchedPrefs); this.#changedWatchedPrefs = {} } #eventCollapse = (changes, area) => { if (area == "local") { for (let [key, value] of Object.entries(changes)) { const watchedPref = this.#watchedPrefs.find(p => key == `${p}.value` || key == p); if (watchedPref && value.oldValue != value.newValue) { this.#changedWatchedPrefs[watchedPref] = value; } } if (Object.keys(this.#changedWatchedPrefs).length > 0) { window.clearTimeout(this.#timeoutId); this.#timeoutId = window.setTimeout(() => this.#eventEmitter(), 500); } } } constructor(options = {}) { this.#watchedPrefs = options.watchedPrefs || []; this.#listener = options.listener; browser.storage.onChanged.addListener(this.#eventCollapse); } }quicktext-6.3.2/modules/utils.mjs000066400000000000000000000204241477370713100171020ustar00rootroot00000000000000/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ export function getDateTimeFormat(format, timeStamp) { let options = {}; options["date-short"] = { dateStyle: "short" }; options["date-long"] = { dateStyle: "full" }; options["date-monthname"] = { month: "long" }; options["time-noseconds"] = { timeStyle: "short" }; options["time-seconds"] = { timeStyle: "medium" }; return new Intl.DateTimeFormat(messenger.i18n.getUILanguage(), options[format.toLowerCase()]).format(timeStamp) } export function trimString(aStr) { if (!aStr) return ""; return aStr.toString().replace(/(^\s+)|(\s+$)/g, '') } export async function parseDisplayName(addr) { let [rv] = await browser.messengerUtilities.parseMailboxString(addr); return { name: rv?.name || "", email: rv?.email || addr, } } export function replaceText(tag, value, text) { var replaceRegExp; if (value != "") replaceRegExp = new RegExp(escapeRegExp(tag), 'g'); else replaceRegExp = new RegExp("( )?" + escapeRegExp(tag), 'g'); return text.replace(replaceRegExp, value); } function escapeRegExp(aStr) { return aStr.replace(/([\^\$\_\.\\\[\]\(\)\|\+\?])/g, "\\$1"); } export function removeBadHTML(aStr) { // Remove the head-tag aStr = aStr.replace(/]*)>.*<\/head>/gim, ''); // Remove html and body tags aStr = aStr.replace(/<(|\/)(head|body)(| [^>]*)>/gim, ''); return aStr; } export function getTypeFromExtension(filename) { let ext = filename.substring(filename.lastIndexOf('.')).toLowerCase(); // Extracted from https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#Image_types switch (ext) { case ".apng": return "image/apng"; case ".bmp": return "image/bmp"; case ".gif": return "image/gif"; case ".ico": case ".cur": return "image/x-icon"; case ".jpg": case ".jpeg": case ".jfif": case ".pjpeg": case ".pjp": return "image/jpeg"; case ".png": return "image/png"; case ".svg": return "image/svg+xml"; case ".tif": case ".tiff": return "image/tiff"; case ".webp": return "image/webp"; default: return "application/octet-stream"; } } export function uint8ArrayToBase64(bytes) { return btoa( bytes.reduce((acc, current) => acc + String.fromCharCode(current), "") ); } export function getLeafName(fileName) { return fileName.split('\\').pop().split('/').pop(); } export async function writeFileToDisc(data, filename) { const blob = new Blob([data], { type: "application/json" }); const url = URL.createObjectURL(blob); try { await browser.downloads.download({ url, filename, saveAs: true, }); } catch (error) { console.error("Error downloading the file:", error); } URL.revokeObjectURL(url); } export async function pickFileFromDisc(aTypes) { let picker = Promise.withResolvers(); // Hidden input to open file dialog. const inputElement = document.createElement("input"); inputElement.setAttribute("type", "file"); inputElement.addEventListener("change", () => { picker.resolve(inputElement.files) }, false); inputElement.addEventListener("cancel", () => { picker.resolve([]) }, false); let acceptedFileTypes = [] for (let aType of aTypes) { switch (aType) { case 0: // TXT files acceptedFileTypes.push("text/plain"); break; case 1: // HTML files acceptedFileTypes.push("text/html"); break; case 2: // arbitrary files break; case 3: // legacy Quicktext XML files acceptedFileTypes.push(".xml"); break; case 4: // image files acceptedFileTypes.push("images/*"); break; case 5: // JSON acceptedFileTypes.push(".json"); break; default: // attachments break; } } inputElement.setAttribute("accept", acceptedFileTypes.join(", ")); inputElement.click(); const [file] = await picker.promise; inputElement.remove(); return file; } export async function getTextFileContent(file) { const content = await new Promise(resolve => { const reader = new FileReader(); reader.onloadend = function (evt) { if (evt.target.readyState == FileReader.DONE) { var filedata = evt.target.result; resolve(filedata); } }; reader.readAsText(file) }) return content; } export async function fetchFileFromServer(url) { try { const response = await fetch(url); if (response?.ok) { return await response.text(); } throw new Error('Network response was not ok'); } catch (ex) { console.error('There was a problem with the fetch operation:', ex); } } export async function openPopup(tabId, config) { let status = "none"; let popup = Promise.withResolvers(); let popupId; let parentId = await browser.tabs.get(tabId).then(tab => tab.windowId); let lastFocusedWindow = parentId; const dimension = ({ top, left, width, height }) => { const excessWidth = 100; const excessHeight = 100; return { top: top + Math.round(0.5 * excessWidth), left: left + Math.round(0.5 * excessHeight), width: width - excessWidth, height: height - excessHeight, } } const onRemovedListener = windowId => { if (windowId == popupId) { status = "closed"; popup.resolve(); } }; const onFocusChangedListener = async windowId => { if (status != "active") { return; } let currentlyFocusedWindow = lastFocusedWindow; lastFocusedWindow = windowId; // GOAL: Force our popup window to always be directly above the parent. if (windowId == popupId && currentlyFocusedWindow != parentId) { await browser.windows.update(parentId, { focused: true }); } // GOAL: We want to allow switching away from the popup to a different // window, but if the parent is focused, bring us back in front. if (windowId == parentId) { await browser.windows.update(popupId, { focused: true, ...dimension(await browser.windows.get(parentId)) }); } }; const onMessageListener = (info, sender, sendResponse) => { if (sender.tab.windowId != popupId) { return false; } switch (info?.action) { case "config": status = "active"; return Promise.resolve(config); case "close": popup.resolve(info.rv); status = "closed"; return Promise.resolve(); case "isPopoverShown": return Promise.resolve(true); } return false; } browser.runtime.onMessage.addListener(onMessageListener); browser.windows.onRemoved.addListener(onRemovedListener); browser.windows.onFocusChanged.addListener(onFocusChangedListener); popupId = await browser.windows.create({ url: "/html/popup.html", type: "popup", allowScriptsToClose: true, ...dimension(await browser.windows.get(parentId)) }).then(window => window.id); await messenger.tabs.sendMessage(tabId, { setPopoverShown: true, popoverShownValue: true, }); let rv = await popup.promise; browser.runtime.onMessage.removeListener(onMessageListener); browser.windows.onRemoved.removeListener(onRemovedListener); browser.windows.onFocusChanged.removeListener(onFocusChangedListener); await messenger.tabs.sendMessage(tabId, { setPopoverShown: true, popoverShownValue: false, }); return rv; }quicktext-6.3.2/resources/000077500000000000000000000000001477370713100155675ustar00rootroot00000000000000quicktext-6.3.2/resources/icons/000077500000000000000000000000001477370713100167025ustar00rootroot00000000000000quicktext-6.3.2/resources/icons/quicktextAboutWindow.ico000066400000000000000000000173161477370713100236120ustar00rootroot00000000000000 h6   &(  @ 1?I: + .x9Fd[}x^ C !p#XrkJ7mLxn[*!&,1yN"@l &+u8T#_Z@C %_0|+9*5iI  X/r AR 2EJ &k>e Mgs0KH+e'Cf ?%>sF|>QC5 ) +  :GU>t|Q;a-  l9lcW6\'IQr!P8      ??(0 ` 1CL: 3e>O+rZ]  !K 7@L.Y|xZBOE 2Z*UrsdF136:>}J /Pp3 $'+/26:{; /`& #'+.2Di9 2i #'*.IV2r >^#'*PG+j*q"\#&[6 ?CLG"}H "a! ?"JfP < O1p+ T(` #,4U+J?hKo#az <<s|KCm* -7l]]UV:msx~e- 8`[''smkurx~*Ws' + 1:{_UOlrx}>A`% 3l IA@??quicktext-6.3.2/resources/icons/quicktextAboutWindow.xpm000066400000000000000000000046161477370713100236430ustar00rootroot00000000000000/* XPM */ static char * settingsWindow_xpm[] = { "16 16 113 2", " c None", ". c #ED0D08", "+ c #EF0F07", "@ c #F01106", "# c #F4200B", "$ c #F11E0F", "% c #EE1707", "& c #F31C05", "* c #FC7251", "= c #F02112", "- c #EF1807", "; c #FC8750", "> c #F33816", ", c #FE6C39", "' c #FB8463", ") c #EF1B0F", "! c #FA5713", "~ c #FF8836", "{ c #FEA25C", "] c #F44927", "^ c #F73A0D", "/ c #FF8747", "( c #FD8C55", "_ c #FF8E3E", ": c #FF7405", "< c #FF7C03", "[ c #FFAA51", "} c #F5613B", "| c #F22506", "1 c #FF883E", "2 c #FF730E", "3 c #FF9946", "4 c #FF7C01", "5 c #FF8401", "6 c #FF8D01", "7 c #FFAD3E", "8 c #F77F51", "9 c #EF290A", "0 c #FD731E", "a c #FF8E30", "b c #FE994B", "c c #FEA548", "d c #FF8E03", "e c #FF9601", "f c #FF9E01", "g c #FFB42B", "h c #F99665", "i c #EE270F", "j c #F88843", "k c #FDC466", "l c #F64104", "m c #FEA352", "n c #F1320D", "o c #F34515", "p c #FFB44A", "q c #FF9F01", "r c #FFA604", "s c #FFAD0A", "t c #FFBB26", "u c #FEC96B", "v c #FFCB3E", "w c #FECA65", "x c #F12B06", "y c #F33905", "z c #F7691E", "A c #FFBF49", "B c #FFB40F", "C c #FFBB15", "D c #FFC21A", "E c #FFC920", "F c #FED058", "G c #FA9640", "H c #FFC543", "I c #FFBC15", "J c #FFC31B", "K c #FFD025", "L c #FFE15F", "M c #F14022", "N c #FBAF6C", "O c #FFBE1C", "P c #FFCA20", "Q c #FFD126", "R c #FFD72B", "S c #FFE975", "T c #F03811", "U c #FBAF6E", "V c #FFD05B", "W c #FFC72A", "X c #FFCA21", "Y c #FFD82C", "Z c #FFDF31", "` c #FFEE79", " . c #F24E17", ".. c #EE2109", "+. c #F77010", "@. c #FBA423", "#. c #FED458", "$. c #FFE172", "%. c #FFE46B", "&. c #FFE34A", "*. c #FFE637", "=. c #FFF26D", "-. c #F14C18", ";. c #F0390F", ">. c #F14612", ",. c #F3641F", "'. c #FAB05B", "). c #FDDB7D", "!. c #FFF778", "~. c #F25E1D", "{. c #F03F14", "]. c #F14918", "^. c #F03A14", ". ", "+ @ ", " # $ % ", " & * = - ; > ", " , ' ) ! ~ { ] ", " ^ / ( _ : < [ } ", " | 1 2 3 4 5 6 7 8 9 ", " 0 a b c d e f g h i j k ", " l m n o p q r s t u v w ", " x y z A s B C D E F ", " G H I J E K L ", " M N O J P Q R S T ", " U V W X Q Y Z ` .", " ..+.@.#.$.%.&.*.=.-.", " ;.>.,.'.).!.~.", " {.].^."}; quicktext-6.3.2/resources/icons/quicktextSettingsWindow.ico000066400000000000000000000173161477370713100243400ustar00rootroot00000000000000 h6   &(  @ 1?I: + .x9Fd[}x^ C !p#XrkJ7mLxn[*!&,1yN"@l &+u8T#_Z@C %_0|+9*5iI  X/r AR 2EJ &k>e Mgs0KH+e'Cf ?%>sF|>QC5 ) +  :GU>t|Q;a-  l9lcW6\'IQr!P8      ??(0 ` 1CL: 3e>O+rZ]  !K 7@L.Y|xZBOE 2Z*UrsdF136:>}J /Pp3 $'+/26:{; /`& #'+.2Di9 2i #'*.IV2r >^#'*PG+j*q"\#&[6 ?CLG"}H "a! ?"JfP < O1p+ T(` #,4U+J?hKo#az <<s|KCm* -7l]]UV:msx~e- 8`[''smkurx~*Ws' + 1:{_UOlrx}>A`% 3l IA@??quicktext-6.3.2/resources/icons/quicktextSettingsWindow.xpm000066400000000000000000000046161477370713100243710ustar00rootroot00000000000000/* XPM */ static char * settingsWindow_xpm[] = { "16 16 113 2", " c None", ". c #ED0D08", "+ c #EF0F07", "@ c #F01106", "# c #F4200B", "$ c #F11E0F", "% c #EE1707", "& c #F31C05", "* c #FC7251", "= c #F02112", "- c #EF1807", "; c #FC8750", "> c #F33816", ", c #FE6C39", "' c #FB8463", ") c #EF1B0F", "! c #FA5713", "~ c #FF8836", "{ c #FEA25C", "] c #F44927", "^ c #F73A0D", "/ c #FF8747", "( c #FD8C55", "_ c #FF8E3E", ": c #FF7405", "< c #FF7C03", "[ c #FFAA51", "} c #F5613B", "| c #F22506", "1 c #FF883E", "2 c #FF730E", "3 c #FF9946", "4 c #FF7C01", "5 c #FF8401", "6 c #FF8D01", "7 c #FFAD3E", "8 c #F77F51", "9 c #EF290A", "0 c #FD731E", "a c #FF8E30", "b c #FE994B", "c c #FEA548", "d c #FF8E03", "e c #FF9601", "f c #FF9E01", "g c #FFB42B", "h c #F99665", "i c #EE270F", "j c #F88843", "k c #FDC466", "l c #F64104", "m c #FEA352", "n c #F1320D", "o c #F34515", "p c #FFB44A", "q c #FF9F01", "r c #FFA604", "s c #FFAD0A", "t c #FFBB26", "u c #FEC96B", "v c #FFCB3E", "w c #FECA65", "x c #F12B06", "y c #F33905", "z c #F7691E", "A c #FFBF49", "B c #FFB40F", "C c #FFBB15", "D c #FFC21A", "E c #FFC920", "F c #FED058", "G c #FA9640", "H c #FFC543", "I c #FFBC15", "J c #FFC31B", "K c #FFD025", "L c #FFE15F", "M c #F14022", "N c #FBAF6C", "O c #FFBE1C", "P c #FFCA20", "Q c #FFD126", "R c #FFD72B", "S c #FFE975", "T c #F03811", "U c #FBAF6E", "V c #FFD05B", "W c #FFC72A", "X c #FFCA21", "Y c #FFD82C", "Z c #FFDF31", "` c #FFEE79", " . c #F24E17", ".. c #EE2109", "+. c #F77010", "@. c #FBA423", "#. c #FED458", "$. c #FFE172", "%. c #FFE46B", "&. c #FFE34A", "*. c #FFE637", "=. c #FFF26D", "-. c #F14C18", ";. c #F0390F", ">. c #F14612", ",. c #F3641F", "'. c #FAB05B", "). c #FDDB7D", "!. c #FFF778", "~. c #F25E1D", "{. c #F03F14", "]. c #F14918", "^. c #F03A14", ". ", "+ @ ", " # $ % ", " & * = - ; > ", " , ' ) ! ~ { ] ", " ^ / ( _ : < [ } ", " | 1 2 3 4 5 6 7 8 9 ", " 0 a b c d e f g h i j k ", " l m n o p q r s t u v w ", " x y z A s B C D E F ", " G H I J E K L ", " M N O J P Q R S T ", " U V W X Q Y Z ` .", " ..+.@.#.$.%.&.*.=.-.", " ;.>.,.'.).!.~.", " {.].^."}; quicktext-6.3.2/resources/screenshoots/000077500000000000000000000000001477370713100203065ustar00rootroot00000000000000quicktext-6.3.2/resources/screenshoots/donate.png000066400000000000000000000140631477370713100222720ustar00rootroot00000000000000PNG  IHDR.'VsRGBgAMA a pHYsodIDATx^\ xT幞3kfd/@ $@6EQ]+\>^Q\jն׺V{tsP6Y,YٷIfϜ~79\ɛəyϿDREP(L&L h,~8f$IAV dAF8QB(YNP xp nZ7@]N$!V*zm LłpV\ HGd&9T5=l"RMbH5hSdDgTS@p:pT`M>ddD7T5=l4&:#GjcM5QEL"'j`?wH +oDB@qP+LV+8<YP.=ʥ`NP*gĠ(aI!^3H#kXdYՇÈ 4Q$"â ܝH h)륨*DFT!SZ5C1ZQ2ed*$ው9sFUWTiLX4Dc|FoV.=NrqFL<*{!]GtͺRF4YW„Kֹs P(q;W/źb% T>wT4lr<ڎRے{q@1Vʎ0Ĩ*h9ŻUx^Mht7 sB$n!q;Sb+Ԏ\2g.ASt;>T1~}x(s}kF􅷘ŻYi<\,yjygEєe \ht4I7SB[hpw~k @=NG!+@ۖ4D 0Gw|50t/}s ] wqz\@&o;a86+UGu?B_P٢0ȸKF}֟rެd>k22OprS.9?z!l!72<]zn:=TD7$ ; I3@.QСéy wq"Bs 7gQl@][ɫ--c:槉'׶M( IABqt)JXzNdLG G@ m67wA:R MnIжNT"5u7'?坲]59Rf@oë7Ml@vr$Y\jO3 =x2<:N.d] NmZXՕP˧\5O_[q߬zk 4z[SV^2?uyywg "+TKmi-%X%6}m Xl|278`!j UAX zȨ"uk]eR3ץ^yVyrkycU}Ǻ0/6?BUv[ndjh)1EyKQ6.}s|Ye~dDkveqtgb &1#O2M.^*ڿXgj{I/p_#! D * Gph]"*%S/?:fcc?|KGt9WYC$⽼Њ u䰂z.+tW,_ j{3xGgPn2 5́QS +k-)S o^RŐb'IҰFlLv,<}SCad1>6Ӛ]0\Mޖ ԬYdԣN?˂?}0߷_=*$Zv9s(?}TEo\#{! )`Sp9>iPet1#hgGW{Ͼև?x۟<^p[Tk|3ڷG?xp-%Uu55/<\;ݾ[Kx?zʷ6pIi P۝?~=tͣXⅪ;vMe $KHR #~_2.#0;nӣ>anE-},1jIc|6TɇR2mĪ\y`*=ɵ^Xuc'^i&d{#6~87s+bܚh lz>M)rl۪y]_ׂ^8|Ǫx/ՀE}ѝ+ySZ] FvtDŽіx8`/vhd͒ȯF U)pcetASON _u  +ƔM$pkEیE^Lm%푵ͷ70˪ ȴW,ywǰCSzpOcV5|bg/lp !$ A}{!C`~zsX CoIcĉ.lnfpa:.5If5LwyM4Zu^YͺTKƓM>GgDzM) sryd.'CJjX/+ň\Um0t?ōCYF/atLK~ʳEөxS(!N|:.h4㥩GŃ+`ᤖ57Ջх9d: .}v¥jIl>3Gm+bT[U~k΁pp^̗ca:1- k=[<̟\9sZAq(p-[*;#OGsfZ;,kclR ڪP\ieL$-S@4{mLz~`9ͬA0}|^IGv6xCfٔ7j8ڌq5'f񨆉ԣ4(J^Qx/8?J=nUXMMe`rI< $ Eqzqe{`7dX*qe~5K†c$c`X,i B@_  p18nAgCIkDsApC#oOf@<f]⸅-P]v}q!n@808i_;pVWt GXs./ 0 oyZ9=2ͨhZP5\4qd'?^V0N<2M)l3  fy7>cOʬd\hk8#cWcL5r&K/wdAʂ0$FW#9#&s &Mpx@\Eg/V9S0 GS8*&6ŃH6`?wH +o0A =BzP$ BpH '$us$̘HkVi髈TMo_U gKEHF0GrH#đɜ*2#դ^4& 5)&#̇ kc8R5p,]IENDB`quicktext-6.3.2/resources/screenshoots/quicktext-settings.png000066400000000000000000000172441477370713100247030ustar00rootroot00000000000000PNG  IHDRF#sRGBgAMA a pHYsod9IDATx^ \Te3ȋoJ)&WԖPӨ66[y涋msft7Vm376[ʚ+%ho# 39a`">e-6 5^ {F 8aշlؘtGuGmnwl n:aDOipjFLAځvc#C`w(_ָn ᘸ^ X%tYgv˧/W_#Ql}y[%@`gK9]{q fM ;Pa ;w gPzV !$,(XW{I7RGXpxP{0a;Vb\ ]Pر.V + xHX>UA z=ƍSuv.7[ }\ ݦm4^wlL*w T~cւze_֌ &r  J؏`_k 0P aWP @)HX aMpswkiV68c̿P}5h-{T*X kS ;Hքejz `/M +kkkky?=!C 5a3gDEE>oG]]]YY٭F %CÂZ- =%TxiR{ף M`q3'#omW@cؖ5~/Vllɼa޼yEE,IMPd $JAfl۶B8-> ]J'd"^nR, s<'0V ?Ӳ{C?N@UwlGFFNoooV;2M:*W!II}Ayrzj sV.z,)vT>:ޏzUu4]qT/xԫUlAβw1L UtB9UVjX^%ʻۃYXqb)]{F)bR `ŋY^xw_UuԩS 5=t_^2պQG_U*Gtw }OX@7O̜1Cu4iΗ'ϼ0#0`HԨÇ͘1SmMJ󡡡GZ=>sR,;qG­nႇV0^|8ao. {Qu]0k73~C+ (ˎ5=$e"##N s`;+\o[!ٚ양GlGyny駟 }g;)Cg4ж8WMhhUM KL 1 Vv[__K/},lj ok:[>Cbٔ K`EcX_;o8p`C~s\tᶖ/ǎ~Q|ӂHXCZSS~m>qBA=e|䩧x ^L2N8gRcTnoqe˂{\1a_\ڵk9S>Z%MFÛmus~3bwURO ͑#G֬Yl{eQ x_6:|Β7|a5`ʕ+h pAi_էeA#3lU'c5,Yx/rss?~$z }Lf~gP0}k a]-V)XɈ˕.  n/^HXg.^G~]/^š?FÞƺ -~g}恀#C}}}E:x/l߿o߾*X_rjmrR[_1cCuuuON8{ \ އ~dɒ&\ٱ3ȇCѶ0eSL}+((HbTuTx`:s̋/Hgi;~dc?Fmpȭ7xMTE>_վe?_\a\H~Tرcʕ-`yꩧ#" FGnXڲfƚLv 68qov6++kC`7nO}yJc4k9='5lAAڵkyE<~SRȺ|>j;w^=z(p3HOOIch-gFGq߾[o3$MXF\M/M Ԡ(g#7 #GTTT$''Z*))ro F!Ti]{C|榯۷vÆ ,T(d-)b]tiHHwdddJJJ`` PӮB)%_Nr<s<16A}ΆZ>U3|vRܢhe_N8núLC rAфeVP7HPo8CN%yy'w!|@M7ӌ|]vv>!LkA$^x4{ğ)uOTkqm1Mv~cr~T,/gv*] {[kfq$Շ:u*h;PHkӱvn}u{|tK FLEQc˖-ld|@iiitt4~$~ebӶe$w,2X]m݅  XSZ VwNV$뜰({cԴcrcXBӱC |BqJ˸xMV*H+OWt̄bf:.iA/Ju݈=a ǬlelVc«gKԈ/m2_m4\~ξ7ߤƎ;lVVV@@@ bƍ+//e,R[V'$$,Hf5*D.RWJ@J]!R%T^;YUmRZ=tŽ>YHŦ7 Qsg#$i~4&({ ,~k,O^nW $EmųݫJ͠ɭsRl2VZ(pc:ɟ&TylڴtUM:bL/izOJ/ײo۲]v-[QR>h:BJ zZ9]t>qhHao7ybmK~1!vKR(_/KD,%D嗔S)$au֞ũ}zfTmܞ7G=)殯uw9g^sCns~Um_:44oj…1^aԫhH6?W/tCcY讒6]/))y绋WF<4%z]>&W:YR&̙͛#8JjÆ 4ʕ+Y 7oZVW>2:;AUrpwb~NgҢͺtΩ AZDŽJcY$N3z.G^."k;?q<&h[Fxv1dʤEoCϮ눐iɺ߿?99ovALķ$~'NWjP&Je[M (gpoo ӧO'%љ]'{06OwY>Eƽٿ :m~!JUV9Vx=?҅ a ?$_tejuU{N^}]:f[?īkV ~C串^w]koP;ˣRMM[oy-.,_·n*JӜ*{k-ճlS+njXpv%.b `N2k_cf|fƍ+WC>/YaWd ; $]/=~)X)^]QY_%.tZF/Zrg(o}']I֛孯V!aE/V^MMM0Х:ʅ1c}}GMMo1}tyP4X%pJj/^^e\r-t'*YBm l԰ ʸW_}5)))&&fڵvӋ/8o޼9sP ?4򂂂`jnٲ5Cuܹs 4s+װf 6q{Q*c0+PQ~Q+w xy=iطo#MHfOa!K(U|5YےRR`´g?aWHHHO Y]]݂ (d?NF#/_f.DYiWiW_у,..fwxnvv6ܣZږaD+l%- .,lKʩJwqU^c;Ȑ0@dee#% NhOz5^- u)^Ԡx]:IRWRJfj;Rov69Fee]Snp=Ǿ B( $,RJA(]]]o&vW%ޭ $,RJA(C,@l3IENDB`quicktext-6.3.2/resources/screenshoots/settings.png000066400000000000000000000360751477370713100226670ustar00rootroot00000000000000PNG  IHDRT5sRGBgAMA a pHYsod;IDATx^tAQHU*N u6a*QҪh f0) E)lKW jΏņ,ښ@.w%.׻^?=1g={=3~>wgν~%1eY]<.""""2(""""2(""""2(""""2(""""2(""""2\uk~#a7|gwr"""""Cso?~(4`xOfG~s[\V?;#?yۇWyósyo|W3OwCDDDDO/h?oCK oOW%>?M-~s_""""9}um{;H粘,ӵ2]V7+|hXw//]׽<,?>?(-?. wb_ τ g/Q{ /_ /c&/pr}"|s:}cJ5?MuN,/zheӻ׿=,gA 7>??ɻτ]>[ _Xdus1UQmo~1oa0UKr|M['w L>E:7R:FQ]V?>?_y??w߫3>W۟.p yO}??ҹϝR? oUnQb|("""-Q4}ֹtӻ ۞-jԧ>^z2/ŗ?_x.|χһgY_}|Y,)~/տ܈%_uM #W׹_Cqe$g_LoDDDuOgLSR*1(|_N'?~9|(J> ywχ/3~3ܽ߹=e5.VVbIN|[HQLoJe: og[uҚ  漪eK,` ""rkۛJMfVeuzyZW_}5oFYX}e|0;᏾,|77#,_YU""""S'ꚟ:7r:Va]V7l=_C§bŲ\j1/|"< _8|ɛO ?޹Ϙ7[|S,UܪvGlͷmm fo:]7b2?=CeE˶U2rs)uOgsQX{՘ ׅſU[᯾/ /Όc/y;ֿ?:פ V=Y*Pq۪J[N]r\)gEL pyI~yZ=~ ]_s2W_J}#"""2Y&3(@U%| 7 y{Ÿ_ ;~Wk__' < Y|~fSR&{~s;#_@7sd)Gg[XW.UVo}3?Ɵ ߹2 """rܹ*""""rQVEDDDdQVEDDDdQVEDDDdQVEDDDdQVEDDDdQVEDDDdQVEDDDdٔUeRV-eRVe,H\p2ě:o}5V}*t\ϲzpe,IA-j~#RVuicK{=V;[]d}r?#:4}`YlYq@0o#~qܽsnjdePp:ejm `.cqu`ur>U~yD/Z2D`>F(縅cjU<\~1+?Vm/9?{ۯ7.amU2`fzcpa#rtv{8NQh-U-(MY_5YeSV[DDDDdVQVEDDDdQVEDDDdQVEDDDdQVEDDDd9}֧~9|Y͔U9,ݱ6?朮ǠY=aTU銲z”U9ʲzZb7yj "ȱ疏NY zGYc{ KG%_dxozu.SVKF Ow/JUQV~l`\cY=_ĭQv٪Xp^륗쮻l]wX.:ݜS<澆,qTupeUDDDae5JN3׬['?^c:E{jkf@lMˊ9f3[V*{wNmߤa9VCI}H_s.W]FY /ɨ{&4)5YݳMwJɶO26#ΗUֱ:{{NR} 8nKc5oο}_yL?t("""ҕkYMJIkNYPrm%YYֱ^Ae5ZC>Ze3Y/T _XX-}YX;1w}NGd7cu𡬊Hwb̻LMk8 ,:*j,Iiez/H-WaY-j~ٰZySjtiF] """}26e#-5yyQc8$ٛY~2ҏ]{*/1GY .eZg,,e^{L_XxZFVe#tut*_h=fvGpUDYEQVEDD+ SVEDDأ0eUDDD= ;HWN:9FY,@² cQV-eRVaBs詧]UPRV0e&?U8LY !eSVaBsHYÔUPRV0e&?U8LY !ezEX,:\Uy{>\f( /4ͲynVuϻ=|F\heW_ oo|#njzY= 旿)nVn#2V>я.s(/W{xljUmu`z:Uϭ|8r稈ȡo/r=g+5Ϟ7BK/>u>P^V9F(s\(9ZYC}ueo~:]eufXfq8[WopCs(/Wzz\nwl]:o9 @]GSV5o10_y3lR F)i֙>\k9 f[V]VG"LCY )0 RV`e&ten RV`e&0*LHYaU (0!eEY}EN.]Uf6e_9(-oy,9eUd(ǡELe8(󢬊Le8(󢬊Le8(󢬊Le8(󢬊Le8(<.eww½Cɔb7ΰ\,^,.]/~Y٪0.euyp/ܹs7ܽsQTV!ӏ*02eq[UV;?t)3΃{w{6vSEY=(e&??t)̓pQ-GX8xν{BzhY}T;Ų~n~2N׷9TO;7_V{(uaY.kc{Zj},;}V 0uZ-q~϶uqyB2N}7չUPZN-qu*xb^*hv/)eIY-n'F5+3)eqMߴmqR1eu?/dV"C6\/ۦ,k_Uy`?n_f#wj3VwDLeJ3?t(L,yIQ$H(j!VVs,]#yìjkal˷8sMҢKs@M{vy h<\6#6hjy}deg2>L߃rz6CYae/".(Ka5KTٻ^^VE͖%YܽR{ 3{O=+UnY:3_Vh݇LzUXYneU2Qzoq/\F׋"7GY2)k҃FYMe`^[ZǼ\KQV 0/ʪDQV 0/ʪDQV 0/ʪDQVC|Qy%7*rj颬0(p[(0 RV`YծPE=]Uf6eTD5*\eUd(p=UPVEF CY!*\eUdZY=[-r}^OVa:'.p2h; Z)SVEFɍvX`v~׾oo'9\euܿ;ms?]  ]6erɕrdtUTF,u8RX:U w w\T.SV.}w ɕpd$5i#E e\Xje6XeKZfMiα\/euMV)M!da*OQ~艥-+iejeqDg=̩v1\U ~)ZWGb҂#cz[\euQVɋטZotVLKrt|]t9ٲ SVGN輫.H>F%C˒l~ɩ󗙚]rtuX}4^Uu?}VUʪI^deHUʪ쉲z(p=Ue*QVz("#DY롬e*2BU)".* 3 xY"'u9fQV]V(0!eQVaB* „UFY )0 RV`e&4]Y= 2ɍd:,Ͳ*ͲZ;of:=`e&4W\'-Vt#WY}rHa[ե]m*}C.7ۑrD^tukue*;E|-i}퐫nއ\(//շNW<[]ʜ8yC)Z{Ki,}q_۫ղXSfY{EٚKQ ]os!6.:_i:?W~Ws>7 :[g$ozIsL[V]w}V},mJ$ϳVf'/9yvm_YLႯ٦ZM[#;^l[d>!97׼5~w=ޑFF)Eٙ_5),7t:.M*Y=$?t:[V?GZϛGt]D9ΡIsp+QysH kZTwso4HcM+}3޴6(=緦}wT˚Ey4ԣve5AM-]Iey[Q2:P_v^eY:Fo4S&U_oo~}qSeۣI-q2+˓ksȶN˶ba("G[V.M(߈ZǛ;;?t:o_YG8&']Vv>ٲq `L.Y2#Q^7_p\o}e.te5ץ7aER ЛV(ʡ.Z}o]؎&qL+W{=c&@G_VKWTUl$h[KV왿'w6S&qg,G\<>ձgeƦNZN _bŵY^-z͵{L_IU;i9 ၲXv#Uy=/ri8 cSV{'-'Jdlof|'~sY= eXwM7zSd.Dq|t^mVgJUlUh-[e ٮ_> IRV{'-'Jd2>`:6 \Zn#$s/i˧ L`T[WM0)t^,&P*z`ȧ85j@*elFm7tJq}$6󫂺)tN+*2QYըLm]SZeyFAud|(.Mڋ7up2Uͮe඙uYS3mY#(e>}6#u9ͧ8I*Lh AY )0 RV`e&0*LHYaU (0!eQVaB* „UFY )0 RV`e&0*LHYaU (0!eQVaB* „UFY )0 RV`e&0*LHYaUte,˰>'yX/a:+nò|s0s:)0*gEX^)LOY DY=_/+SV Wa\vK ^bQ5[^2_)>V/VT!n3/:8ۜö\w{k8e&4mYW򲚔óXZrY-k#IܪۖtqrU/gwX |d뗩2.OfkT6_o։%E٦߱}{kse&4yY5Z0+ytYMWh6ďusF[]p*UЍBY6%/]|Џj9簻)7 pUMը˺`2|4/X旅HH./*Fo$p̔Ute>n*LHYڎ~*LvAQ=}(0!#DЏ RVUUJ„U"e?e&4]Y4SJIT~gͱ.6cG/e6(0ij]]._dr:ݮ ma_n*.o{3yg_Í=PVSVaBGWV[U1)?_ZuNc]˾s쒮;d1PVJY jٟKl^5;n.Gal/QHM/n>o_P lZx?U0_\tWq]QVaB*MRul~:KY絣kܾ*n6l].yl[:4}vu5ltl|6IAm#.N"uGY j>Ootr-%_tQ6]*=I mq=QVaBGUV HakVM?Nߌ;n|C}nGtR}ze?e&tleugzc|߳kT\YvL]KmJkX72eઔUs<iͷqtuݎ*qu(/.V*Lh>e)AY M[VH_:ZN3p]Vie?e&4]YeΔUU (0!eQVaB* „UFY )0 RV`e&0*LHYaU (0!eQVaB* „UFY )0 RV`e&0*LHYaU (0!eQVaB* „UFY )0 RV`e&0*LHYaU (0!eQVaB* „UFY )0 RV`e&0*LHYaU (0!eQVaB* „UFY )0 RV`e&0*LHYaU (0!eQVaB* „UFY )0 RV`e&0*LHYaU (0!eQVaB* „UFY )0 RV`e&0*LHYaU (0!eQVaB* „UFY )0 RV`e&4vY9Uɘen eF)0eNY(pu*DYSVa$*\ #QVU WHU:eF)0eNY(30?]ߧGY( ?(tHSV9RVMY(*sB #QVOYUHY6eFΟ ̑ m*DY?eUA#eڔU:JS.bxsc0Oէ-i<9DYLSVj*˸|s].U& *).>a}^NUgظ_sቇyⱥr{(0)[FNOde :,Z1.'qjZLsϏ~yQ:*DYe'CXهϕ5ő}|eq^\I*qTuz|\~z^e߭88:c[GYL_V7yX/if9ZogZ:|fyCǤ;;ܜae5+E1JjS?AJ¾r3 EjԏcN1mU͔ ^oH \%϶pd핬u+q *Q:͈i /S{?iI8Tbmy~{]MwͺeqmK=Ϊc-Ǜt*VAMk17nwYmHnld :4Ulӥ,'>o=aFe5) Ḁ BJEva#nul[9]z^m~NƌXVPVa$* yTȴ>eǛAe竚trs-o/G[V~v g_@wL#M~,rUj1ˇ~̚I?f-Łeq: V=P V:/X]& :ަzT+z,=Fg9/esۥͿ(HfUV7d%oeyh)Sx,?]ǻlqť3 E=-mwQ1v`}*w~Zc.c$/{4yrnRYeF2MY*UaUhSVa$) )ЦHSV9RVMY( o{m죬HU:eF)0eNY(pu*DY-""2U:]/e&Ο 0/*LHY?e`^U:*(0!euUyQVaB)„SVEY MVVVaXYz~gaXy=:_e'HYe&4IY-eRPm@Y;e`^U$e5.aX?TV*(0IjYaN׷luvlr^6auVG3Xk^HOKYe&4MY1vEeX)T}*.,*)0j kV٪c֨jR9v;w*(0j| NqO.UyQVaBG9z(„/""2U WHU:eF)0eNY(ualr*DYEn RVOYe&Ο 0/*LHY?e`^U:*(0!euUyQVaB)„)gaXy=zY=='7%>-q\V3^z>jJy\I3uY=_/òhqͿ[!*W5yYw﷖ݽ_kzϸM?^U.KYu c,kU%ަ)IA-b l /t[OKiyX7#뺘r<~V1.(/U~˪Eua<+SߖeqX}tȧrv~]}_C/N&ۗYv2}X;^u[e0ijz{ȡrYLkV7fE\ĔU2UY1xz):RZN髪P6oPCˢlŗS鹷._GiU&6~Y=(\*2B*\U)rYʪQVU)rYʪQVU)rYʪQVU)rYʪQVC,"WMU.o6eUEY۩56.cen eQVaB* „UFY )0 RV`IG?+Sp^P^V=owVV?񏇏}cxu^z[[s ?ymts\۔Sa|½3a+e5ۖCU-uU`KY !eSVaBsHYÔUfKY`\VEDDDDLWmrdUmUmUmUmUmUmUmUdxQ `CygGeUDDD6*gNv(}QVEDDWBU(n{񢬊H(eUDDDzEYeu("""+(EY^QVGY/ʪ􊲺?xQVEDDW&)O=EGS]0-υ'j"=+?]<x._~QVEDDWF/=J j1Sge?>ܧʪXF/qTu3w\_YFT[EeUDDDN,ղ@-COJ~m_F?H_Vc{T0)YŵZ mMVĊ ufe(uzU?$h}mΘ*"""2MYSm T,Md5zQ:;z3˲wdcMVUVEDDW&-E{⡪Tyݎubj-]fWV\z(;H^Vzbr]GU[GqGãE)k_jz4UXkTf=et*"""2zYKG/4)Ͳcp۴5NfYVcaskZV/;H_V7-'eUDDDzEYeu("""+(EY^QVGY/ʪ􊲺?xQVEDDWQVNj*"""2ٟPՋHt3i~;Xtw1ʪ6ʪ6ʪ6ʪ6ʪ6ʪ6ʪ6ʪ6*""""2JyOB3IENDB`quicktext-6.3.2/resources/screenshoots/usage.PNG000066400000000000000000000317741477370713100217740ustar00rootroot00000000000000PNG  IHDRsRGBgAMA a pHYsod3IDATx^}$AMR3*P@A) J kTblބ02 l :d@^ #2&F@6`Y:ɒd$dΖ3=t3=/;;[~駟m_;$I< q%I$KR$I,TA$IPA$BI$ U$I,ԅ?{;zUݐ-C$Ƀ\Ao\yW_6|o g>w_8m_~CWC$ɃA¯[$u6<ۢq[,6wu|4ǧ{ۯ ߞwoM}.q8NHֽ\Rfe{>9%km>4KsJLtY}:ϱIi$>KUOfm9~  s^ٺC^pnv.KxPcmm+qFO_\8:W9Ʋڵ#I..!K0"F;W΅՟{v<|1潷 ||:_|Cn^Wa#SQζ\EPj*Ώ$L.e4Uvų t;|o;pӵMo|Uع;︿}pmpg>~O'4կCj{u/(ycs78>:bʎhFX@~utyGl;1~ i,49< Tc k$U!m15mKmAj|g]g\N>_7%uOѩO$˳+}.Rf?=pA# ODO?]ub$~ɽ:+T[WO6kw{1Z4`,Ap±!jK/=m?:ޱm8~xnv=:Qwi^s[lK# Z9N;VlM;pI ɭORfC`7}+3;_|2u\.>zol zo;Of3AmAp`4)>m|̜sn[ڶ뜶S`sm/Ovi#Id#]쇹Was|_/>[?o3^|t8S_Jxɻu?~G҇}aؿ93:6ݎdhd3 "=f67?ع _;p,ji˻~ϵUnj?6I0ɭORfN |{;{+ŸeS}͟ g>χO?d?3[gmm8֜=GUHOO'4j=! T& ;K>4=ˍ؆F.^圻7"=׷{9$oWrJwwoD/Ɂ1W#,%KcP>'I,ե7x_T/} 3_#._g4ɅF8::>J$KuA57^ΏGw׼T _Ζ.?$ H$ã H$Y Id $I*$I H$Y Id $I: .\$IdA $I*$I H$Y Idv'ñx]©pT]~,Ǐ{rc7ڴ' 3]X8vrǙ؎_>Y켖}-Nq$k uN*`З%FWh+?54i.}>E$'Y 'b}~}cat܋2]F}r$] [e`RO1j!7g/@YuP?uho[van`:N}ipzA+w&c8z<ۖ~l媀2O瑜~:<\3yR68c}ϻd.$Ip\ Ǎ7ЄvLJGܢ7icq$([ V8"? mh}enulO׶.msϬgh;^OIw`.W5 q.[^ak,:2цyM?NApP?2h؞ںhXz&,I\eM;S:D4ϧ}VS0Xoǎ;U>0l<5$0toduL־-__O)31<$: riz:zU,ү#UXu.x}uarRmǎl{{OGVtіEML۶춵}F{zNs!Ir?y\$G\e;f4Wv/6WkomA0h͵mnqAӈ)pL\HOA$IPA$BI$ U$I,TA$IPA$BI$ W*|_n#I,AA0$I6$3H$KPl#I,AA0$I>|W"|~oYΕHA0m/KJ 铟Tx&oo=?Ir'{f x`7e/z׻w1=zq:xj$7f I1K#i6=A x;*T0WnG| _8|׹2Gbuܶk$e}LuNՕ8[o`t*9 X!~=h_ȕ_b2: O&dt~Ib}Lu[<ݶ,Woz]~wve ~ȿ6>0_)82#W" =A~#\Ib}Lu꣯n[+ Aj`\_~/QUϢİW`<Ǹ Xl (rwS$Y1O-OgՑU/{lxMJ`H Aui\ Gb_{ٸebܢ =A0^1 Ƒ< ,c6qp~C=s>cKs8{U>?{_pYxJ`j 1Ha3}ɡ:^a" =Ap Hc3>o~ī"7䛟~tv[_/?쥫_n7CkILjX=u^n[XY~ 䲌*)[j;×ǟ]|Wxʯ O#/p;:uoA \'sA0^.z:kI?/B}~Wux31vak^zic^ 9\/q~O5w9sŻyЯ\q/+gi\x]_X}їpսkz^]_/gSع-|=;o2[oWei BehbɟѸ` 5n  Y1Ł8o_z-]M-7['^]Gop?{'o/[W[A0ml_? Pq r]}5N??oÅw]^/kA8^P'…p~ww+$`f:X[[j(\$\,<$j/p.|γ;{3Ik.^5b  o8.?vuK…B-__ w~ccn?IA0mvFuq r=ճk;6C_Bo >v4\<+&_[A0mb-5@ug5|pfoip[×{i8{/em x{k_ Í;Ajp2W'ñS干ui%WO=Aٓzc'ۖgl~y$<ү_K.~g"\e<|O_.7>[޹/پБ<{O&grB̖]ܕ\KyW˼O$8sx86Ŷ腻+X?8?yI$yX=uh8zΰm?'χs88%khq_x3h}5OɹL{֍C=ݧr#WvMgRTs`S{mIpn1\t~J+s$tp51r}uzwAg5_s >Abl_(wuk9{`aLꃹ~g6o$|?5fcbɛݡo3\ϟvA$)N }Ő+/mhzquy6ID>صe7GɺI"M}tR?l%mGzԯ$&š3b3.K쇷`[{zxḜMƒe;t m.~uf9"1}m>ߧ경ԱO N]K۲NZ7^1_I߹7ÙA\v_=?c%"S#R07MIdCA0w@c~!Ir`f[w#&ݕFSƐ>I(f$I F$Y`fId m$I%Xl$I,]A$IPA$BI$ uof$I0q;$Id7 {oH$Y1 ?pi$I`~ xx$I0=I<9s\Zo㊇~8<#$I\ccٯ덏>(I$:e`n$I Id $I*$I H$Y In!CA$Iέ [ I[Ap5~~mƺ-᫾^Y6ldc{ܶԮ97ۃm;[Ȯ'mT$./#sVɖ <\rIծ4 ~#w0(Lk{q^:0M-IiӉ˚j\J[03i?\HVwծc:[ߒӆqJHRnq[" { ~sH6x1x7T G:G㶝oyyͭЦQ۶6wi_X۽mv2דudky\3_U4 !0A[sxq3):{ݮq=5^X $ڿH)_4?+/tjyY/¬mJZo[ 4}rC2v49>̠sn\CU-5F~ r>&|mMC+_j] e̻44u춼I]skZǂu>YIlUWf.Kik{>"zϤI_Iƍ}ns#u!W^y~IA#wrˋ5wjhٮU HPC`Ѣ..+ \AҦI_I.;F=uRȅ䗠qqN[^8: JkZsu׹vܶ9&Y10,3F=`*`[ώ3iWѮ{%SW]=lnkmycM]WCvwj8.n6Q_!]Jc38mL:^kd.'FAkuY>IK j |[n~Cm z\?í Ȃc$V$I,TA$IPA$BI$ U$I,TA$IPA$BI$ U$I,TA$IPA$BI$ U$I,TA@o&$Y< 4^ A6(A AAdCArPA6(A AAdCArPCFN|WAACo+l#TvZvwAAպo ub@ݲ}!$ΎVIF`_[Q3Lkco8V:pXכoocPR\T]2kc[b{cGm=>엝f "ذ4- r=lr~@3 muk_,W24 !0DIl.9S>7vX9?7a՗]`ϤM/4ښ@: 폈UK.wO V}U;uDicy,vƱG_Nv8}s xН8Il.<jTq $u6Jt]e `o.k x $u6Jt]eF@: %"hB Irͅ]~g}!$Ck3ھH\gsD׵_&nj$I.{*$y o{׭ Z!I۩A_[IPA$a3 `=4ϝ;.^zOp4s=ٳU8dop-Ta'FCd' x5Ta0 u AL'u]N:UM+_\=0q /[{jls#m/|n=Z?}CwL;8ĬI6sN䶭9;g`:]<rZЋ `2,&a:8% Q[g '~.=fl$V]b.a ~GpZ=/Tn{:̎0nt֎>2',7MGf,?#6"c=`ܞR.q4έ˵Ŵ1ꤺAk{6P'7r?Uu6KSphzY */fC9AEACd'AAX?AvR`IACd'A֏Al+>IA!i cA0G { 7pĉ* L5xMk㩧\)0);w.>}:r-U!i'xB)^x8 tԩjZex-k"^O?JNA0~S1\5G5 AI Џ/\렾.S! P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @" P( @2 wM$R<}(>$I,DA$IPA$W`|c $I@AQA$( *$ADA$W asc#l$nnu5w$l^l#f7:66{suk6uqʱ7 {F8ݶ I+EQ,P6#[aZ7y{Bfz[Uzy [GW$Ir m~Ǽ>a88 ]3o{W#mSI\+o:SW~+#/}G)zy};+7ʵ9slrQ{*9MaѪ18F\>=Fnݠމmϵ5ۯϷ(>k>Ne4tA$W 2%net $Il4mR@/?ZLQnԯ { if (details.reason == "update") { browser.notifications.create("qtupdate", { type: "basic", title: "Quicktext", message: `Quicktext pre-release was updated to v${browser.runtime.getManifest().version}\n(new script engine, click for details)`, }); } }); browser.notifications.onClicked.addListener(notificationId => { if (notificationId != "qtupdate") { return; } browser.tabs.create({ url: `https://github.com/jobisoft/quicktext/releases/tag/v${browser.runtime.getManifest().version}`, }) }) import * as quicktext from "../modules/quicktext.mjs"; import * as storage from "../modules/storage.mjs"; import * as menus from "../modules/menus.mjs"; import * as utils from "../modules/utils.mjs"; // Legacy: Register global urls. await browser.LegacyHelper.registerGlobalUrls([ ["content", "quicktext", "xul_settings_dialog/"], ["resource", "quicktext", "."], ]); // Define default prefs. let defaultPrefs = { "counter": 0, "templateFolder": "", "defaultImport": "", "menuCollapse": true, "toolbar": true, "popup": true, "keywordKey": "Tab", "shortcutModifier": "alt", "shortcutTypeAdv": false, "collapseState": "" }; await storage.init(defaultPrefs); // Fix invalid options: // - reset the value of shortcutModifier to "alt", if it has not a valid value - see issue #177 const shortcutModifier = await storage.getPref("shortcutModifier"); if (!["alt", "control", "meta"].includes(shortcutModifier)) { await storage.setPref("shortcutModifier", "alt"); } // Define prefs, which can be overridden by system admins. Admins have to migrate // these manually from legacy prefs to managed storage. const managedPrefs = [ "defaultImport", ]; let managedStorageAvailable = true; for (let managedPref of managedPrefs) { try { let override = await browser.storage.managed.get({ [managedPref]: null }); if (override[managedPref] !== null) { await storage.setPref(managedPref, override[managedPref]); } await storage.setPref(`${managedPref}.managed`, true); } catch { // No managed storage available. await storage.setPref(`${managedPref}.managed`, false); managedStorageAvailable = false; } } // Legacy: The XML files will be kept for backup, but are read only if they have // not already been migrated to local storage. Uninstalling Quicktext (which // clears the storage) and installing it again, will re-import the XML files. // For the future, users have to be reminded to backup their templates. let templates = await storage.getTemplates(); if (!templates) { try { templates = await quicktext.readLegacyXmlTemplateFile().then(e => e.templates); console.log("Migrating XML template file to JSON stored in local storage."); await storage.setTemplates(templates); } catch { } } if (!templates) { templates = { groups: [], texts: [] }; await storage.setTemplates(templates); } let scripts = await storage.getScripts(); if (!scripts) { try { scripts = await quicktext.readXmlScriptFile().then(e => e.scripts); console.log("Migrating XML script file to JSON stored in local storage.") await storage.setScripts(scripts); } catch { } } if (!scripts) { scripts = []; await storage.setScripts(scripts); } // Startup import. const defaultImport = await storage.getPref("defaultImport"); if (defaultImport) { const defaultImports = defaultImport.split(";").map(e => e.trim()).reverse(); for (let path of defaultImports) { try { // Import XML or JSON config data from remote server or local file system. // Support for importing from the local file system will be removed for the // pure WebExtension version. Use managed storage instead. const data = path.match(/^(http|https):\/\//) ? await utils.fetchFileFromServer(path) : await browser.Quicktext.readTextFile(path); const imports = quicktext.parseConfigFileData(data); if (imports.templates) { quicktext.mergeTemplates(templates, imports.templates, true); } if (imports.scripts) { quicktext.mergeScripts(scripts, imports.scripts, true); } } catch (e) { console.error(e); } } await storage.setTemplates(templates); await storage.setScripts(scripts); } // Startup import via managed storage. if (managedStorageAvailable) { let { templates: managedTemplates } = await browser.storage.managed.get({ templates: null }); if (managedTemplates) { quicktext.mergeTemplates(templates, managedTemplates, true); } let { scripts: managedScripts } = await browser.storage.managed.get({ scripts: null }); if (managedScripts) { quicktext.mergeScripts(scripts, managedScripts, true); } } // NotifyTools needed by Experiment code to access WebExtension code. messenger.NotifyTools.onNotifyBackground.addListener(async (info) => { switch (info.command) { case "setPref": return storage.setPref(info.pref, info.value); case "getPref": return storage.getPref(info.pref); case "setScripts": return storage.setScripts(info.data); case "getScripts": return storage.getScripts(); case "setTemplates": return storage.setTemplates(info.data); case "getTemplates": return storage.getTemplates(); case "openWebPage": return browser.windows.openDefaultBrowser(info.url); case "parseConfigFile": return browser.Quicktext.readTextFile(info.path).then(quicktext.parseConfigFileData); case "pickAndParseConfigFile": // Currently not used. Instead the settings window keeps using the legacy // file picker. return utils.pickFileFromDisc([3, 5]) .then(utils.getTextFileContent) .then(quicktext.parseConfigFileData); case "exportTemplates": return storage.getTemplates().then(templates => templates ? utils.writeFileToDisc(JSON.stringify({ templates }, null, 2), "templates.json") : null ); case "exportScripts": return storage.getScripts().then(scripts => scripts ? utils.writeFileToDisc(JSON.stringify({ scripts }, null, 2), "scripts.json") : null ); // Experiment toolbar actions from the compose window. case "insertFile": return messenger.tabs .query({ windowId: info.windowId, type: "messageCompose" }) .then(tabs => quicktext.insertFile(tabs[0].id, info.file, info.aType)); case "insertVariable": return messenger.tabs .query({ windowId: info.windowId, type: "messageCompose" }) .then(tabs => quicktext.insertVariable({ tabId: tabs[0].id, variable: info.aVar })); case "insertTemplate": return messenger.tabs .query({ windowId: info.windowId, type: "messageCompose" }) .then(tabs => quicktext.insertTemplate(tabs[0].id, info.group, info.text)); } }); // Listener for the compose script. messenger.runtime.onMessage.addListener((info, sender, sendResponse) => { // All these functions return Promises. switch (info.command) { case "getKeywordsAndShortcuts": return quicktext.getKeywordsAndShortcuts(); case "insertTemplate": return quicktext.insertTemplate(sender.tab.id, info.group, info.text); case "composeAPI": return browser.compose[info.func](sender.tab.id, ...info.params); case "messagesAPI": return browser.messages[info.func](...info.params); case "identitiesAPI": return browser.identities[info.func](...info.params); case "processTag": return quicktext.processTag({ tabId: info.tabId, tag: info.tag, variables: info.variables }); case "getTag": return quicktext.getTag({ tabId: info.tabId, tag: info.tag, variables: info.variables }); default: return false; } }); // Add entry to tools menu. browser.menus.create({ contexts: ["tools_menu"], onclick: () => browser.Quicktext.openTemplateManager(), title: browser.i18n.getMessage("quicktext.label"), }) // Add Quicktext composeBody context menu. await menus.buildComposeBodyMenu(); // Add listeners to open template manager. browser.composeAction.onClicked.addListener(tab => { browser.Quicktext.openTemplateManager() }); browser.browserAction.onClicked.addListener(tab => { browser.Quicktext.openTemplateManager() }); // TODO: Move this into a module. async function prepareComposeTab(tab) { if (tab.type != "messageCompose") { return; } // BUG: Thunderbird should wait with executeScript until tab is ready. // Getting the compose details works around this. await messenger.compose.getComposeDetails(tab.id); await messenger.tabs.executeScript(tab.id, { file: "/scripts/compose.js" }); } // Load compose script into all open compose windows. let composeTabs = await messenger.tabs.query({ type: "messageCompose" }); for (let composeTab of composeTabs) { await prepareComposeTab(composeTab); } // Load compose script into any new compose window being opened. messenger.tabs.onCreated.addListener(prepareComposeTab); // Remove saved state data after tab closed. messenger.tabs.onRemoved.addListener(tabId => { browser.storage.session.remove(`QuicktextStateData_${tabId}`); }); // Prevent sending, if a popover is shown. browser.compose.onBeforeSend.addListener(async (tab, details) => { let isPopoverShown = await messenger.tabs.sendMessage(tab.id, { isPopoverShown: true, }); return { cancel: isPopoverShown } }) // Legacy: Inject toolbar into all already open compose windows. let windows = await browser.windows.getAll({ windowTypes: ["messageCompose"] }) for (let window of windows) { await browser.QuicktextToolbar.injectLegacyToolbar(window.id); } // Legacy: Inject toolbar into any new compose window being opened. browser.windows.onCreated.addListener(async window => { if (window.type == "messageCompose") { await browser.QuicktextToolbar.injectLegacyToolbar(window.id); } }); // Legacy: Update toolbar if relevant settings changed. new storage.StorageListener( { watchedPrefs: ["templates", "menuCollapse", "shortcutModifier"], listener: async (changes) => { let windows = await browser.windows.getAll({ windowTypes: ["messageCompose"] }) windows.forEach(window => browser.QuicktextToolbar.updateLegacyToolbar(window.id)); } } )quicktext-6.3.2/scripts/compose.js000066400000000000000000000217061477370713100172550ustar00rootroot00000000000000/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ const alternatives = { "Enter": ["NumpadEnter"] } let keywords, keywordKey, shortcutTypeAdv, shortcutModifier, shortcuts; let advShortcutModifierIsDown = false; let advShortcutString = ""; let popoverShown = false; // ----------------------------------------------------------------------------- async function insertHtmlFragment(message) { // A normal space causes the selection to ignore the space. let space = message.extraSpace ? " " : ""; document.execCommand('insertHtml', false, `${message.insertHtml}${space}`); await handlerCursorTags(); } async function insertTextFragment(message) { let space = message.extraSpace ? " " : ""; document.execCommand('insertText', false, `${message.insertText}${space}`); await handlerCursorTags(); } function requestInsertTemplate(text) { return messenger.runtime.sendMessage({ command: "insertTemplate", group: text[0], text: text[1] }); } async function getSelection(mode) { let selection = window.getSelection(); if (mode == "TEXT") { return selection.toString(); } // https://stackoverflow.com/questions/5083682/get-selected-html-in-browser-via-javascript if (selection.rangeCount > 0) { // It may be beneficial to include the surrounding node // to copy the format // let wrapperNode = selection.anchorNode.parentElement.tagName; let range = selection.getRangeAt(0); let clonedSelection = range.cloneContents(); //let container = document.createElement(wrapperNode); //container.appendChild(clonedSelection); let div = document.createElement('div'); div.appendChild(clonedSelection); return div.innerHTML; } return ""; } async function handlerCursorTags() { const CURSOR = '[[CURSOR]]' try { let items = window.document.evaluate("//*", document, null, XPathResult.ANY_TYPE, null); let foundElements = []; let nextItem; do { if (nextItem && nextItem.childNodes.length > 0) { for (let node of nextItem.childNodes) { if (node.nodeType == 3 && node.nodeValue.includes(CURSOR)) { foundElements.push(node); } } } nextItem = items.iterateNext(); } while (nextItem) if (foundElements.length == 0) { return; } let selection = window.getSelection(); for (let foundElement of foundElements) { let startPos = -1; do { if (startPos != -1) { let range = document.createRange(); range.setStart(foundElement, startPos); range.setEnd(foundElement, startPos + CURSOR.length); selection.removeAllRanges(); selection.addRange(range); // execCommand() does not collapse the leading and trailing // spaces which selection.deleteFromDocument() does. All the // text altering functions from selection and range seem to // collapse spaces. document.execCommand('delete'); //selection.deleteFromDocument(); } startPos = foundElement.nodeValue.indexOf(CURSOR); } while (startPos != -1) } } catch (ex) { console.debug(ex); } } // ----------------------------------------------------------------------------- function hasMatchingModifier(e, modifier) { return ( e.altKey && modifier == "alt" || e.ctrlKey && modifier == "control" || e.metaKey && modifier == "meta" ) } function isMatchingModifier(e, modifier) { return ( e.key == "Alt" && modifier == "alt" || e.key == "Control" && modifier == "control" || e.key == "Meta" && modifier == "meta" ) } function isRealKey(e) { return e.key.length == 1; } function keywordListener(e) { if (e.code == keywordKey || alternatives[keywordKey]?.includes(e.code)) { let selection = window.getSelection(); if (!(selection.rangeCount > 0)) { return; } // This gives us a range object of the currently selected text // and as the user usually does not have any text selected when // triggering keywords, it is a collapsed range at the current // cursor position. let initialSelectionRange = selection.getRangeAt(0).cloneRange(); // Get a temp selection, which we can modify to search for the beginning // of the last word. let tmpRange = initialSelectionRange.cloneRange(); tmpRange.collapse(false); selection.removeAllRanges(); selection.addRange(tmpRange); // Extend selection to the beginning of the current word. selection.modify("extend", "backward", "word"); // We should only have one word selected, but make sure to only get the // last one by chopping up its content. let lastWord = selection.toString().split(" ").pop().toLowerCase(); if (!lastWord) { // Restore to the initialSelectionRange and abort. selection.removeAllRanges(); selection.addRange(initialSelectionRange); return; } let lastWordIsKeyword = keywords.hasOwnProperty(lastWord); if (!lastWordIsKeyword) { // Restore to the initialSelectionRange and abort. selection.removeAllRanges(); selection.addRange(initialSelectionRange); return; } // So this is it. Eat the keypress, remove the keyword from the document // and insert the template. e.stopPropagation(); e.preventDefault(); // The following line will remove the keyword before we replace it. If we // do not do that, we see the keyword being selected and then replaced. // It does look interesting, but I keep it as it was before. selection.deleteFromDocument() requestInsertTemplate(keywords[lastWord]) } } function shortcutKeyDown(e) { if (!hasMatchingModifier(e, shortcutModifier)) { return; } if (shortcutTypeAdv) { advShortcutModifierIsDown = true; if (isRealKey(e)) { advShortcutString += e.key; } // Eat keys if we acted upon them. e.stopPropagation(); e.preventDefault(); } else if (isRealKey(e) && shortcuts[e.key] && !e.repeat) { requestInsertTemplate(shortcuts[e.key]); // Eat keys if we acted upon them. e.stopPropagation(); e.preventDefault(); } } async function shortcutKeyUp(e) { if (advShortcutModifierIsDown && shortcutTypeAdv && isMatchingModifier(e, shortcutModifier)) { if (advShortcutString != "" && typeof shortcuts[advShortcutString] != "undefined") { requestInsertTemplate(shortcuts[advShortcutString]); } advShortcutModifierIsDown = false; advShortcutString = ""; } } async function getLatestPrefs() { const storage = await import(browser.runtime.getURL("/modules/storage.mjs")); keywordKey = await storage.getPref("keywordKey"); shortcutTypeAdv = await storage.getPref("shortcutTypeAdv"); shortcutModifier = await storage.getPref("shortcutModifier"); let rv = await messenger.runtime.sendMessage({ command: "getKeywordsAndShortcuts" }); keywords = rv.keywords; shortcuts = rv.shortcuts; } // ----------------------------------------------------------------------------- async function setup() { const storage = await import(browser.runtime.getURL("/modules/storage.mjs")); await getLatestPrefs(); window.addEventListener("keydown", shortcutKeyDown, true); window.addEventListener("keyup", shortcutKeyUp, true); window.addEventListener("keydown", keywordListener, false); new storage.StorageListener( { watchedPrefs: ["templates", "keywordKey", "shortcutTypeAdv", "shortcutModifier"], listener: (changes) => { getLatestPrefs(); } } ) } messenger.runtime.onMessage.addListener((message, sender) => { if (message.insertText) { return insertTextFragment(message); } if (message.insertHtml) { return insertHtmlFragment(message); } if (message.alertLabel) { return Promise.resolve(window.alert(message.alertLabel)); } if (message.getSelection) { return getSelection(message.getSelection) } if (message.isPopoverShown) { return Promise.resolve(popoverShown); } if (message.setPopoverShown) { popoverShown = message.popoverShownValue; return Promise.resolve(); } return false; }); setup(); console.log("Quicktext compose script loaded"); quicktext-6.3.2/updates.json000066400000000000000000000007211477370713100161150ustar00rootroot00000000000000{ "addons": { "{8845E3B3-E8FB-40E2-95E9-EC40294818C4}": { "updates": [ { "version": "6.3.1", "update_info_url": "https://github.com/jobisoft/quicktext/issues/439", "update_link": "https://github.com/jobisoft/quicktext/releases/download/v6.3.1/quicktext_6_3_1.xpi", "applications": { "gecko": { "strict_min_version": "128.0" } } } ] } } }quicktext-6.3.2/xul_settings_dialog/000077500000000000000000000000001477370713100176245ustar00rootroot00000000000000quicktext-6.3.2/xul_settings_dialog/i18n.js000066400000000000000000000037321477370713100207460ustar00rootroot00000000000000/* * This file is provided by the addon-developer-support repository at * https://github.com/thundernest/addon-developer-support * * For usage descriptions, please check: * https://github.com/thundernest/addon-developer-support/tree/master/scripts/i18n * * Version 1.1 * * Derived from: * http://github.com/piroor/webextensions-lib-l10n * * Original license: * The MIT License, Copyright (c) 2016-2019 YUKI "Piro" Hiroshi * */ var i18n = { updateString(string) { let re = new RegExp(this.keyPrefix + "(.+?)__", "g"); return string.replace(re, (matched) => { const key = matched.slice(this.keyPrefix.length, -2); let rv = this.extension ? this.extension.localeData.localizeMessage(key) : messenger.i18n.getMessage(key); return rv || matched; }); }, updateSubtree(node) { const texts = document.evaluate( 'descendant::text()[contains(self::text(), "' + this.keyPrefix + '")]', node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for (let i = 0, maxi = texts.snapshotLength; i < maxi; i++) { const text = texts.snapshotItem(i); if (text.nodeValue.includes(this.keyPrefix)) text.nodeValue = this.updateString(text.nodeValue); } const attributes = document.evaluate( 'descendant::*/attribute::*[contains(., "' + this.keyPrefix + '")]', node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for (let i = 0, maxi = attributes.snapshotLength; i < maxi; i++) { const attribute = attributes.snapshotItem(i); if (attribute.value.includes(this.keyPrefix)) attribute.value = this.updateString(attribute.value); } }, updateDocument(options = {}) { this.extension = null; this.keyPrefix = "__MSG_"; if (options) { if (options.extension) this.extension = options.extension; if (options.keyPrefix) this.keyPrefix = options.keyPrefix; } this.updateSubtree(document); }, }; quicktext-6.3.2/xul_settings_dialog/settings.css000066400000000000000000000006141477370713100221770ustar00rootroot00000000000000.quicktext-icon { list-style-image: url("resource://quicktext/assets/icon16.png"); } dialog[OS=WINNT] legend.insideTab { padding-right: 5px; padding-left: 5px; margin-bottom:5px; background-color: -moz-Field !important; } .textarea-container { margin:4px; overflow: hidden; } textarea { margin: 0px; resize: none; } #text-defaultImport:disabled { background-color: #ccc; }quicktext-6.3.2/xul_settings_dialog/settings.js000066400000000000000000001670371477370713100220400ustar00rootroot00000000000000var { ExtensionParent } = ChromeUtils.importESModule( "resource://gre/modules/ExtensionParent.sys.mjs" ); var extension = ExtensionParent.GlobalManager.getExtension( "{8845E3B3-E8FB-40E2-95E9-EC40294818C4}" ); var { wzQuicktextGroup } = ChromeUtils.importESModule( `chrome://quicktext/content/wzQuicktextGroup.sys.mjs?v=${extension.manifest.version}` ); var { wzQuicktextTemplate } = ChromeUtils.importESModule( `chrome://quicktext/content/wzQuicktextTemplate.sys.mjs?v=${extension.manifest.version}` ); var { wzQuicktextScript } = ChromeUtils.importESModule( `chrome://quicktext/content/wzQuicktextScript.sys.mjs?v=${extension.manifest.version}` ); const kFileShortcuts = ['ProfD', 'UsrDocs', 'Home', 'Desk', 'Pers']; const OS = Services.appinfo.OS; Services.scriptloader.loadSubScript("resource://quicktext/api/NotifyTools/notifyTools.js", window, "UTF-8"); // This exists for historic reasons, but all of it is related to the settings // dialog as well. var gQuicktext = { mGroup: [], mTexts: [], mScripts: [], mEditingGroup: [], mEditingTexts: [], mEditingScripts: [], mViewPopup: false, mCollapseGroup: true, mDefaultImport: "", mKeywordKey: "Tab", mShortcutModifier: "alt", mShortcutTypeAdv: false, mObserverList: [], mCollapseState: "", mSelectionContent: "", mSelectionContentHtml: "", mCurrentTemplate: "", get viewToolbar() { return this.mViewToolbar; }, set viewToolbar(aViewToolbar) { this.mViewToolbar = aViewToolbar; notifyTools.notifyBackground({ command: "setPref", pref: "toolbar", value: aViewToolbar }); this.notifyObservers("updatetoolbar", ""); return this.mViewToolbar; }, get viewPopup() { return this.mViewPopup; }, set viewPopup(aViewPopup) { this.mViewPopup = aViewPopup; notifyTools.notifyBackground({ command: "setPref", pref: "popup", value: aViewPopup }); return this.mViewPopup; }, get collapseGroup() { return this.mCollapseGroup; }, set collapseGroup(aCollapseGroup) { this.mCollapseGroup = aCollapseGroup; notifyTools.notifyBackground({ command: "setPref", pref: "menuCollapse", value: aCollapseGroup }); this.notifyObservers("updatesettings", ""); return this.mCollapseGroup; }, get defaultImport() { return this.mDefaultImport; }, set defaultImport(aDefaultImport) { this.mDefaultImport = aDefaultImport; notifyTools.notifyBackground({ command: "setPref", pref: "defaultImport", value: aDefaultImport }); return this.mDefaultImport; }, get keywordKey() { return this.mKeywordKey; }, set keywordKey(aKeywordKey) { this.mKeywordKey = aKeywordKey; notifyTools.notifyBackground({ command: "setPref", pref: "keywordKey", value: aKeywordKey }); return this.mKeywordKey; }, get shortcutModifier() { return this.mShortcutModifier; }, set shortcutModifier(aShortcutModifier) { this.mShortcutModifier = aShortcutModifier; notifyTools.notifyBackground({ command: "setPref", pref: "shortcutModifier", value: aShortcutModifier }); return this.mShortcutModifier; }, get collapseState() { return this.mCollapseState; }, set collapseState(aCollapseState) { this.mCollapseState = aCollapseState; notifyTools.notifyBackground({ command: "setPref", pref: "collapseState", value: aCollapseState }); return this.mCollapseState; }, get shortcutTypeAdv() { if (OS.substr(0, 3).toLowerCase() == "mac" || (OS.substr(0, 3).toLowerCase() == "win" && this.mShortcutModifier == "alt")) return false; return this.mShortcutTypeAdv; }, set shortcutTypeAdv(aShortcutTypeAdv) { this.mShortcutTypeAdv = aShortcutTypeAdv; notifyTools.notifyBackground({ command: "setPref", pref: "shortcutTypeAdv", value: aShortcutTypeAdv }); return this.mShortcutTypeAdv; }, loadSettings: async function () { const scripts = await notifyTools.notifyBackground({ command: "getScripts" }); const { groups, texts } = await notifyTools.notifyBackground({ command: "getTemplates" }); this.mScripts = (scripts || []).map(e => new wzQuicktextScript(e)); this.mGroup = (groups || []).map(e => new wzQuicktextGroup(e)); this.mTexts = [] // The templates are grouped. for (let groupTexts of (texts || [])) { this.mTexts.push(groupTexts.map(e => new wzQuicktextTemplate(e))) } // Get prefs this.mViewToolbar = await notifyTools.notifyBackground({ command: "getPref", pref: "toolbar" }); this.mCollapseGroup = await notifyTools.notifyBackground({ command: "getPref", pref: "menuCollapse" }); this.mKeywordKey = await notifyTools.notifyBackground({ command: "getPref", pref: "keywordKey" }); this.mViewPopup = await notifyTools.notifyBackground({ command: "getPref", pref: "popup" }); this.mShortcutTypeAdv = await notifyTools.notifyBackground({ command: "getPref", pref: "shortcutTypeAdv" }); this.mShortcutModifier = await notifyTools.notifyBackground({ command: "getPref", pref: "shortcutModifier" }); this.mCollapseState = await notifyTools.notifyBackground({ command: "getPref", pref: "collapseState" }); this.mDefaultImport = await notifyTools.notifyBackground({ command: "getPref", pref: "defaultImport" }); const defaultImportManaged = await notifyTools.notifyBackground({ command: "getPref", pref: "defaultImport.managed" }); if (defaultImportManaged) { document.getElementById("text-defaultImport").setAttribute("disabled", "true"); } this.startEditing(); // Notify that settings has been changed this.notifyObservers("updatesettings", ""); }, // Rename the legacy quicktext class members. prettify(data) { function prettifier(value) { if (Array.isArray(value)) { let pArray = []; for (let entry of value) { pArray.push(prettifier(entry)) } return pArray; } if (typeof value === 'object' && value !== null) { let pObj = {}; for (let [k, v] of Object.entries(value)) { const pKey = k.startsWith("m") ? k[1].toLowerCase() + k.slice(2) : k; pObj[pKey] = prettifier(v); } return pObj; } return value; } return prettifier(data); }, saveSettings: async function () { // Save prefs. await notifyTools.notifyBackground({ command: "setPref", pref: "toolbar", value: this.mViewToolbar }); await notifyTools.notifyBackground({ command: "setPref", pref: "menuCollapse", value: this.mCollapseGroup }); await notifyTools.notifyBackground({ command: "setPref", pref: "keywordKey", value: this.mKeywordKey }); await notifyTools.notifyBackground({ command: "setPref", pref: "popup", value: this.mViewPopup }); await notifyTools.notifyBackground({ command: "setPref", pref: "shortcutTypeAdv", value: this.mShortcutTypeAdv }); await notifyTools.notifyBackground({ command: "setPref", pref: "shortcutModifier", value: this.mShortcutModifier }); await notifyTools.notifyBackground({ command: "setPref", pref: "collapseState", value: this.mCollapseState }); await notifyTools.notifyBackground({ command: "setPref", pref: "defaultImport", value: this.mDefaultImport }); // Save templates and scripts. this.endEditing(); await notifyTools.notifyBackground({ command: "setScripts", data: this.prettify(this.mScripts) }); await notifyTools.notifyBackground({ command: "setTemplates", data: { texts: this.prettify(this.mTexts), groups: this.prettify(this.mGroup) } }); this.startEditing(); this.notifyObservers("updatesettings", ""); }, addGroup: function (aName, aEditingMode) { var tmp = new wzQuicktextGroup(); tmp.name = aName; tmp.protected = false; if (aEditingMode) { this.mEditingGroup.push(tmp); this.mEditingTexts.push([]); } else { this.mGroup.push(tmp); this.mTexts.push([]); } }, removeGroup: function (aRow, aEditingMode) { if (aEditingMode) { this.mEditingGroup.splice(aRow, 1); this.mEditingTexts.splice(aRow, 1); } else { this.mGroup.splice(aRow, 1); this.mTexts.splice(aRow, 1); } }, getGroup: function (aGroupIndex, aEditingMode) { if (aEditingMode) { if (typeof this.mEditingGroup[aGroupIndex] != 'undefined') return this.mEditingGroup[aGroupIndex]; } else { if (typeof this.mGroup[aGroupIndex] != 'undefined') return this.mGroup[aGroupIndex]; } }, getGroupLength: function (aEditingMode) { if (aEditingMode) return this.mEditingGroup.length; else return this.mGroup.length; }, moveGroup: function (aFromIndex, aToIndex, aEditingMode) { if (aEditingMode) { var tmpGroup = this.mEditingGroup.splice(aFromIndex, 1)[0]; var tmpTexts = this.mEditingTexts.splice(aFromIndex, 1)[0]; if (aToIndex > aFromIndex) { this.mEditingGroup.splice(aToIndex - 1, 0, tmpGroup); this.mEditingTexts.splice(aToIndex - 1, 0, tmpTexts); } else { this.mEditingGroup.splice(aToIndex, 0, tmpGroup); this.mEditingTexts.splice(aToIndex, 0, tmpTexts); } } else { var tmpGroup = this.mGroup.splice(aFromIndex, 1)[0]; var tmpTexts = this.mTexts.splice(aFromIndex, 1)[0]; if (aToIndex > aFromIndex) { this.mGroup.splice(aToIndex - 1, 0, tmpGroup); this.mTexts.splice(aToIndex - 1, 0, tmpTexts); } else { this.mGroup.splice(aToIndex, 0, tmpGroup); this.mTexts.splice(aToIndex, 0, tmpTexts); } } }, addText: function (aGroupIndex, aName, aEditingMode) { var tmp = new wzQuicktextTemplate(); tmp.name = aName; tmp.shortcut = ""; if (aEditingMode) this.mEditingTexts[aGroupIndex].push(tmp); else this.mTexts[aGroupIndex].push(tmp); }, removeText: function (aGroupIndex, aRow, aEditingMode) { if (aEditingMode) this.mEditingTexts[aGroupIndex].splice(aRow, 1); else this.mTexts[aGroupIndex].splice(aRow, 1); }, getText: function (aGroupIndex, aTextIndex, aEditingMode) { if (aEditingMode) { if (typeof this.mEditingTexts[aGroupIndex][aTextIndex] != 'undefined') return this.mEditingTexts[aGroupIndex][aTextIndex]; } else { if (typeof this.mTexts[aGroupIndex][aTextIndex] != 'undefined') return this.mTexts[aGroupIndex][aTextIndex]; } }, getTextLength: function (aGroupIndex, aEditingMode) { if (aEditingMode) { if (this.mEditingTexts[aGroupIndex]) return this.mEditingTexts[aGroupIndex].length; } else { if (this.mTexts[aGroupIndex]) return this.mTexts[aGroupIndex].length; } return 0; }, doTextExists: function (aGroupIndex, aTextIndex, aEditingMode) { if (aEditingMode) return (typeof this.mEditingTexts[aGroupIndex][aTextIndex] != 'undefined') ? true : false; else return (typeof this.mTexts[aGroupIndex][aTextIndex] != 'undefined') ? true : false; }, moveText: function (aFromGroupIndex, aFromTextIndex, aToGroupIndex, aToTextIndex, aEditingMode) { if (aEditingMode) { var tmpText = this.mEditingTexts[aFromGroupIndex].splice(aFromTextIndex, 1)[0]; if (aFromGroupIndex == aToGroupIndex && aFromTextIndex < aToTextIndex) this.mEditingTexts[aToGroupIndex].splice(aToTextIndex - 1, 0, tmpText); else this.mEditingTexts[aToGroupIndex].splice(aToTextIndex, 0, tmpText); } else { var tmpText = this.mTexts[aFromGroupIndex].splice(aFromTextIndex, 1)[0]; if (aFromGroupIndex == aToGroupIndex && aFromTextIndex < aToTextIndex) this.mTexts[aFromGroupIndex].splice(aToTextIndex - 1, 0, tmpText); else this.mTexts[aFromGroupIndex].splice(aToTextIndex, 0, tmpText); } }, addScript: function (aName, aEditingMode) { var tmp = new wzQuicktextScript(); tmp.name = aName; tmp.protected = false; if (aEditingMode) this.mEditingScripts.push(tmp); else this.mScripts.push(tmp); }, removeScript: function (aIndex, aEditingMode) { if (aEditingMode) this.mEditingScripts.splice(aIndex, 1); else this.mScripts.splice(aIndex, 1); }, getScript: function (aIndex, aEditingMode) { if (aEditingMode) { if (typeof this.mEditingScripts[aIndex] != 'undefined') return this.mEditingScripts[aIndex]; } else { if (typeof this.mScripts[aIndex] != 'undefined') return this.mScripts[aIndex]; } }, getScriptLength: function (aEditingMode) { if (aEditingMode) return this.mEditingScripts.length; else return this.mScripts.length; }, // Create temporary vars that hold the edited-but-not-yet-saved scripts and // templates. startEditing: function () { this.mEditingGroup = []; this.mEditingTexts = []; for (var i = 0; i < this.mGroup.length; i++) { this.mEditingGroup[i] = this.mGroup[i].clone(); this.mEditingTexts[i] = []; if (this.mTexts[i]) for (var j = 0; j < this.mTexts[i].length; j++) this.mEditingTexts[i][j] = this.mTexts[i][j].clone(); } this.mEditingScripts = []; for (var i = 0; i < this.mScripts.length; i++) { this.mEditingScripts[i] = this.mScripts[i].clone(); } }, // When the editing ended, move the values back to the original vars. endEditing: function () { this.mGroup = []; this.mTexts = []; for (var i = 0; i < this.mEditingGroup.length; i++) { this.mGroup[i] = this.mEditingGroup[i].clone(); this.mTexts[i] = []; if (this.mEditingTexts[i]) for (var j = 0; j < this.mEditingTexts[i].length; j++) this.mTexts[i][j] = this.mEditingTexts[i][j].clone(); } this.mScripts = []; for (var i = 0; i < this.mEditingScripts.length; i++) { this.mScripts[i] = this.mEditingScripts[i].clone(); } }, /* * FILE FUNCTIONS */ async pickFile(aTypes, aMode, aTitle) { let filePicker = Components.classes["@mozilla.org/filepicker;1"].createInstance(Components.interfaces.nsIFilePicker); switch (aMode) { case 1: // save filePicker.init(window.browsingContext, aTitle, filePicker.modeSave); break; default: // open filePicker.init(window.browsingContext, aTitle, filePicker.modeOpen); break; } for (let aType of aTypes) { switch (aType) { case 0: // insert TXT file filePicker.appendFilters(filePicker.filterText); filePicker.defaultExtension = "txt"; break; case 1: // insert HTML file filePicker.appendFilters(filePicker.filterHTML); filePicker.defaultExtension = "html"; break; case 2: // insert file break; case 3: // Quicktext XML file filePicker.appendFilter("Quicktext XML Export", "*.xml"); filePicker.defaultExtension = "xml"; break; case 4: // images filePicker.appendFilters(filePicker.filterImages); case 5: // JSON filePicker.appendFilter("Quicktext JSON Export", "*.json"); filePicker.defaultExtension = "json"; default: // attachments break; } } filePicker.appendFilters(filePicker.filterAll); let rv = await new Promise(function (resolve, reject) { filePicker.open(result => { resolve(result); }); }); if (rv == filePicker.returnOK || rv == filePicker.returnReplace) { return filePicker.file; } else { return null; } }, importTemplates(templates) { let importedGroup = (templates?.groups || []).map(e => new wzQuicktextGroup(e)); let importedTexts = []; // The templates are grouped. for (let texts of templates?.texts || []) { importedTexts.push(texts.map(e => new wzQuicktextTemplate(e))) } // Imports are not not saved directly, but imported as unsaved changes. for (var i = 0; i < importedGroup.length; i++) this.mEditingGroup.push(importedGroup[i]); for (var i = 0; i < importedTexts.length; i++) this.mEditingTexts.push(importedTexts[i]); }, importScripts(scripts) { let importedScripts = scripts.map(e => new wzQuicktextScript(e)); // Imports are not not saved directly, but imported as unsaved changes. for (var i = 0; i < importedScripts.length; i++) this.mEditingScripts.push(importedScripts[i]); }, /* * OBSERVERS */ addObserver: function (aObserver) { this.mObserverList.push(aObserver); }, removeObserver: function (aObserver) { for (var i = 0; i < this.mObserverList.length; i++) { if (this.mObserverList[i] == aObserver) this.mObserverList.splice(i, 1); } }, notifyObservers: function (aTopic, aData) { for (var i = 0; i < this.mObserverList.length; i++) this.mObserverList[i].observe(this, aTopic, aData); } } var settingsDialog = { mChangesMade: false, mTextChangesMade: [], mScriptChangesMade: [], mGeneralChangesMade: [], mTreeArray: [], mCollapseState: [], mScriptIndex: null, mPickedIndex: null, init: async function () { await window.i18n.updateDocument({ extension }); document.getElementById('quicktextSettingsWindow').setAttribute("OS", Services.appinfo.OS); console.log("Adding attribute 'OS' = '" + Services.appinfo.OS + "' to settings dialog element."); gQuicktext.addObserver(this); await gQuicktext.loadSettings() var states = gQuicktext.collapseState; if (states != "") { states = states.split(/;/); for (var i = 0; i < states.length; i++) this.mCollapseState[i] = (states[i] == "1"); } var groupLength = gQuicktext.getGroupLength(true); if (states.length < groupLength) { for (var i = states.length; i < groupLength; i++) this.mCollapseState[i] = true; } document.getElementById('tabbox-main').selectedIndex = 1; document.getElementById('text-keyword').addEventListener("keypress", function (e) { settingsDialog.noSpaceForKeyword(e); }, false); this.disableSave(); document.getElementById("savebutton").addEventListener("command", function (e) { settingsDialog.save(); }, false); document.getElementById("closebutton").addEventListener("command", function (e) { settingsDialog.close(true); }, false); document.getElementById("helpbutton").addEventListener("command", function (e) { settingsDialog.openHomepage(); }, false); }, unload: function () { gQuicktext.removeObserver(this); var states = []; for (var i = 0; i < this.mCollapseState.length; i++) states[i] = (this.mCollapseState[i]) ? "1" : ""; gQuicktext.collapseState = states.join(";"); document.getElementById('text-keyword').removeEventListener("keypress", function (e) { settingsDialog.noSpaceForKeyword(e); }, false); }, close: async function (aClose) { this.saveText(); this.saveScript(); if (this.mChangesMade) { promptService = Services.prompt; if (promptService) { result = promptService.confirmEx(window, extension.localeData.localizeMessage("saveMessageTitle"), extension.localeData.localizeMessage("saveMessage"), (promptService.BUTTON_TITLE_SAVE * promptService.BUTTON_POS_0) + (promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_1) + (promptService.BUTTON_TITLE_DONT_SAVE * promptService.BUTTON_POS_2), null, null, null, null, { value: 0 }); switch (result) { // Cancel case 1: return false; // Save case 0: await this.save(); break; // Quit case 2: break; } } } if (aClose) window.close(); return true; }, save: async function () { this.saveText(); this.saveScript(); if (document.getElementById("checkbox-viewPopup")) gQuicktext.viewPopup = document.getElementById("checkbox-viewPopup").checked; if (document.getElementById("text-defaultImport")) gQuicktext.defaultImport = document.getElementById("text-defaultImport").value; if (document.getElementById("select-shortcutModifier")) gQuicktext.shortcutModifier = document.getElementById("select-shortcutModifier").value; if (document.getElementById("checkbox-shortcutTypeAdv")) gQuicktext.shortcutTypeAdv = document.getElementById("checkbox-shortcutTypeAdv").checked; if (document.getElementById("select-keywordKey")) gQuicktext.keywordKey = document.getElementById("select-keywordKey").value; if (document.getElementById("checkbox-collapseGroup")) gQuicktext.collapseGroup = document.getElementById("checkbox-collapseGroup").checked; await gQuicktext.saveSettings(); this.mChangesMade = false; this.mTextChangesMade = []; this.mScriptChangesMade = []; this.mGeneralChangesMade = []; this.disableSave(); this.updateGUI(); }, saveText: function () { if (this.mPickedIndex != null) { if (this.mPickedIndex[1] > -1) { var title = document.getElementById('text-title').value; if (title.replace(/[\s]/g, '') == "") title = extension.localeData.localizeMessage("newTemplate"); this.saveTextCell(this.mPickedIndex[0], this.mPickedIndex[1], 'name', title); this.saveTextCell(this.mPickedIndex[0], this.mPickedIndex[1], 'text', document.getElementById('text').value); if (gQuicktext.shortcutTypeAdv) this.saveTextCell(this.mPickedIndex[0], this.mPickedIndex[1], 'shortcut', document.getElementById('text-shortcutAdv').value); else this.saveTextCell(this.mPickedIndex[0], this.mPickedIndex[1], 'shortcut', document.getElementById('text-shortcutBasic').value); this.saveTextCell(this.mPickedIndex[0], this.mPickedIndex[1], 'type', document.getElementById('text-type').value); this.saveTextCell(this.mPickedIndex[0], this.mPickedIndex[1], 'keyword', document.getElementById('text-keyword').value.replace(/[\s]/g, '')); this.saveTextCell(this.mPickedIndex[0], this.mPickedIndex[1], 'subject', document.getElementById('text-subject').value); this.saveTextCell(this.mPickedIndex[0], this.mPickedIndex[1], 'attachments', document.getElementById('text-attachments').value); } else { var title = document.getElementById('text-title').value; if (title.replace(/[\s]/g, '') == "") title = extension.localeData.localizeMessage("newGroup"); this.saveGroupCell(this.mPickedIndex[0], 'name', title); } } }, saveTextCell: function (aGroupIndex, aTextIndex, aColumn, aValue) { var text = gQuicktext.getText(aGroupIndex, aTextIndex, true); if (typeof text[aColumn] != "undefined" && text[aColumn] != aValue) { text[aColumn] = aValue; this.changesMade(); return true; } return false; }, saveGroupCell: function (aGroupIndex, aColumn, aValue) { var group = gQuicktext.getGroup(aGroupIndex, true); if (typeof group[aColumn] != "undefined" && group[aColumn] != aValue) { group[aColumn] = aValue; this.changesMade(); return true; } return false; }, saveScript: function () { if (this.mScriptIndex != null) { var title = document.getElementById('script-title').value; if (title.replace(/[\s]/g, '') == "") title = extension.localeData.localizeMessage("newScript"); this.saveScriptCell(this.mScriptIndex, 'name', title); this.saveScriptCell(this.mScriptIndex, 'script', document.getElementById('script').value); } }, saveScriptCell: function (aIndex, aColumn, aValue) { var script = gQuicktext.getScript(aIndex, true); if (typeof script[aColumn] != "undefined" && script[aColumn] != aValue) { script[aColumn] = aValue; this.changesMade(); return true; } return false; }, noSpaceForKeyword: function (e) { if (e.charCode == KeyEvent.DOM_VK_SPACE) { e.stopPropagation(); e.preventDefault(); } }, checkForGeneralChanges: function (aIndex) { var ids = ['checkbox-viewPopup', 'checkbox-collapseGroup', 'select-shortcutModifier', 'checkbox-shortcutTypeAdv', 'select-keywordKey', 'text-defaultImport']; var type = ['checked', 'checked', 'value', 'checked', 'value', 'value']; var keys = ['viewPopup', 'collapseGroup', 'shortcutModifier', 'shortcutTypeAdv', 'keywordKey', 'defaultImport']; if (typeof ids[aIndex] == 'undefined') return; var value = document.getElementById(ids[aIndex])[type[aIndex]]; if (gQuicktext[keys[aIndex]] != value) this.generalChangeMade(aIndex); else this.noGeneralChangeMade(aIndex); }, checkForTextChanges: function (aIndex) { if (!this.mPickedIndex) return; var ids = ['text-title', 'text', 'text-shortcutBasic', 'text-type', 'text-keyword', 'text-subject', 'text-attachments']; var keys = ['name', 'text', 'shortcut', 'type', 'keyword', 'subject', 'attachments']; if (gQuicktext.shortcutTypeAdv) ids[2] = 'text-shortcutAdv'; var value = document.getElementById(ids[aIndex]).value; switch (aIndex) { case 0: if (value.replace(/[\s]/g, '') == "") if (this.mPickedIndex[1] > -1) value = extension.localeData.localizeMessage("newTemplate"); else value = extension.localeData.localizeMessage("newGroup"); break; case 2: if (gQuicktext.shortcutTypeAdv) { value = value.replace(/[^\d]/g, ''); document.getElementById(ids[aIndex]).value = value; } case 4: value = value.replace(/[\s]/g, ''); document.getElementById(ids[aIndex]).value = value; break; } if (this.mPickedIndex[1] > -1) { if (gQuicktext.getText(this.mPickedIndex[0], this.mPickedIndex[1], true)[keys[aIndex]] != value) this.textChangeMade(aIndex); else this.noTextChangeMade(aIndex); } else { if (gQuicktext.getGroup(this.mPickedIndex[0], true)[keys[aIndex]] != value) this.textChangeMade(aIndex); else this.noTextChangeMade(aIndex); } if (aIndex == 0 || aIndex == 2) { var selectedIndex = document.getElementById('group-tree').view.selection.currentIndex; if (aIndex == 0) { this.mTreeArray[selectedIndex][6] = value; } else { this.mTreeArray[selectedIndex][7] = value; } document.getElementById('group-tree').invalidateRow(selectedIndex); this.updateVariableGUI(); } }, checkForScriptChanges: function (aIndex) { if (this.mScriptIndex == null) return; var ids = ['script-title', 'script']; var keys = ['name', 'script']; var value = document.getElementById(ids[aIndex]).value; switch (aIndex) { case 0: if (value.replace(/[\s]/g, '') == "") value = extension.localeData.localizeMessage("newScript"); break; } if (gQuicktext.getScript(this.mScriptIndex, true)[keys[aIndex]] != value) this.scriptChangeMade(aIndex); else this.noScriptChangeMade(aIndex); if (aIndex == 0) { this.updateVariableGUI(); var listItem = document.getElementById('script-list').getItemAtIndex(this.mScriptIndex); listItem.firstChild.value = value; } }, changesMade: function () { this.mChangesMade = true; this.enableSave(); }, anyChangesMade: function () { if (this.textChangesMade() || this.scriptChangesMade() || this.generalChangesMade()) return true; return false; }, generalChangesMade: function () { for (var i = 0; i < this.mGeneralChangesMade.length; i++) { if (typeof this.mGeneralChangesMade[i] != "undefined" && this.mGeneralChangesMade[i] == true) return true; } return false; }, generalChangeMade: function (aIndex) { this.enableSave(); this.mGeneralChangesMade[aIndex] = true; }, noGeneralChangeMade: function (aIndex) { this.mGeneralChangesMade[aIndex] = false; if (!this.mChangesMade && !this.anyChangesMade()) this.disableSave(); }, textChangesMade: function () { for (var i = 0; i < this.mTextChangesMade.length; i++) { if (typeof this.mTextChangesMade[i] != "undefined" && this.mTextChangesMade[i] == true) return true; } return false; }, textChangeMade: function (aIndex) { this.enableSave(); this.mTextChangesMade[aIndex] = true; }, noTextChangeMade: function (aIndex) { this.mTextChangesMade[aIndex] = false; if (!this.mChangesMade && !this.anyChangesMade()) this.disableSave(); }, scriptChangesMade: function () { for (var i = 0; i < this.mScriptChangesMade.length; i++) { if (typeof this.mScriptChangesMade[i] != "undefined" && this.mScriptChangesMade[i] == true) return true; } return false; }, scriptChangeMade: function (aIndex) { this.enableSave(); this.mScriptChangesMade[aIndex] = true; }, noScriptChangeMade: function (aIndex) { this.mScriptChangesMade[aIndex] = false; if (!this.mChangesMade && !this.anyChangesMade()) this.disableSave(); }, shortcutModifierChange: function () { var state = (OS.substr(0, 3).toLowerCase() == "mac" || (OS.substr(0, 3).toLowerCase() == "win" && document.getElementById('select-shortcutModifier').value == "alt")); document.getElementById('checkbox-shortcutTypeAdv').disabled = state; }, /* * GUI CHANGES */ updateGUI: function () { const dateTimeFormat = (format, timeStamp) => { let options = {}; options["date-short"] = { dateStyle: "short" }; options["date-long"] = { dateStyle: "long" }; options["date-monthname"] = { month: "long" }; options["time-noseconds"] = { timeStyle: "short" }; options["time-seconds"] = { timeStyle: "long" }; return new Services.intl.DateTimeFormat(undefined, options[format.toLowerCase()]).format(timeStamp) } // Set the date/time in the variablemenu var timeStamp = new Date(); let fields = ["date-short", "date-long", "date-monthname", "time-noseconds", "time-seconds"]; for (let i = 0; i < fields.length; i++) { let field = fields[i]; let fieldtype = field.split("-")[0]; if (document.getElementById(field)) { document.getElementById(field).setAttribute( "label", extension.localeData.localizeMessage(fieldtype, [dateTimeFormat(field, timeStamp)]) ); } } // Update info in the generalsettings tab if (document.getElementById("checkbox-viewPopup")) document.getElementById("checkbox-viewPopup").checked = gQuicktext.viewPopup; if (document.getElementById("checkbox-collapseGroup")) document.getElementById("checkbox-collapseGroup").checked = gQuicktext.collapseGroup; if (document.getElementById("select-shortcutModifier")) document.getElementById("select-shortcutModifier").value = gQuicktext.shortcutModifier; if (document.getElementById("checkbox-shortcutTypeAdv")) { var elem = document.getElementById("checkbox-shortcutTypeAdv"); elem.checked = gQuicktext.shortcutTypeAdv; this.shortcutModifierChange(); } if (document.getElementById("text-defaultImport")) document.getElementById("text-defaultImport").value = gQuicktext.defaultImport; if (document.getElementById("select-keywordKey")) document.getElementById("select-keywordKey").value = gQuicktext.keywordKey; // Update the variable menu this.updateVariableGUI(); // Update Script list this.updateScriptGUI(); // Update the tree this.buildTreeGUI(); // Update the remove and add buttons this.updateButtonStates(); }, updateVariableGUI: function () { // Set all other text in the variablemenu var topParent = document.getElementById('quicktext-other-texts'); for (var i = topParent.childNodes.length - 1; i >= 0; i--) topParent.removeChild(topParent.childNodes[i]); var groupLength = gQuicktext.getGroupLength(true); if (groupLength > 0) { topParent.removeAttribute('hidden'); parent = document.createXULElement("menupopup"); parent = topParent.appendChild(parent); for (var i = 0; i < groupLength; i++) { var textLength = gQuicktext.getTextLength(i, true); if (textLength > 0) { var group = gQuicktext.getGroup(i, true); var groupElem = document.createXULElement("menu"); groupElem.setAttribute('label', group.name); groupElem = parent.appendChild(groupElem); groupParent = document.createXULElement("menupopup"); groupParent = groupElem.appendChild(groupParent); for (var j = 0; j < textLength; j++) { var textElem = document.createXULElement("menuitem"); var text = gQuicktext.getText(i, j, true); textElem.setAttribute('label', text.name); textElem.setAttribute('group', group.name); textElem.addEventListener("command", function () { settingsDialog.insertVariable("TEXT=" + this.getAttribute("group") + "|" + this.getAttribute("label")); }); textElem = groupParent.appendChild(textElem); } } } } else topParent.setAttribute('hidden', true); var topParent = document.getElementById('variables-scripts'); for (var i = topParent.childNodes.length - 1; i >= 0; i--) topParent.removeChild(topParent.childNodes[i]); var scriptLength = gQuicktext.getScriptLength(true); if (scriptLength > 0) { topParent.removeAttribute('hidden'); parent = document.createXULElement("menupopup"); parent = topParent.appendChild(parent); for (var i = 0; i < scriptLength; i++) { var script = gQuicktext.getScript(i, true); var textElem = document.createXULElement("menuitem"); textElem.setAttribute('label', script.name); textElem.addEventListener("command", function () { settingsDialog.insertVariable("SCRIPT=" + this.getAttribute("label")); }); textElem = parent.appendChild(textElem); } } else topParent.setAttribute('hidden', true); }, updateScriptGUI: function () { // Update the listmenu in the scripttab and the variable-menu var scriptLength = gQuicktext.getScriptLength(true); listElem = document.getElementById('script-list'); var selectedIndex = listElem.selectedIndex; var oldLength = listElem.getRowCount(); if (scriptLength > 0) { for (var i = 0; i < scriptLength; i++) { var script = gQuicktext.getScript(i, true); if (i < oldLength) { var listItem = listElem.getItemAtIndex(i); listItem.firstChild.value = script.name; listItem.value = i; } else { let newItem = document.createXULElement("richlistitem"); newItem.value = i; let newItemLabel = document.createXULElement("label"); newItemLabel.value = script.name; newItem.appendChild(newItemLabel); listElem.appendChild(newItem); } } } if (oldLength > scriptLength) { for (var i = scriptLength; i < oldLength; i++) listElem.getItemAtIndex(scriptLength).remove(); } if (selectedIndex >= 0) listElem.selectedIndex = selectedIndex; else if (scriptLength > 0) listElem.selectedIndex = 0; else listElem.selectedIndex = -1; this.pickScript(); }, disableShortcuts: function (aShortcut) { var grouplist = document.getElementById('popup-shortcutBasic'); for (var i = 0; i <= 10; i++) grouplist.childNodes[i].removeAttribute("disabled"); var groupLength = gQuicktext.getGroupLength(true); for (var i = 0; i < groupLength; i++) { var textLength = gQuicktext.getTextLength(i, true); for (var j = 0; j < textLength; j++) { var shortcut = gQuicktext.getText(i, j, true).shortcut; var selectedIndex = (shortcut == "0") ? 10 : shortcut; if (shortcut != "" && shortcut != aShortcut && grouplist.childNodes[selectedIndex]) grouplist.childNodes[selectedIndex].setAttribute("disabled", true); } } }, disableSave: function () { document.getElementById("savebutton").setAttribute("disabled", true); }, enableSave: function () { document.getElementById("savebutton").removeAttribute("disabled"); }, /* * Update the treeview */ makeTreeArray: function () { this.mTreeArray = []; var k = 0; var groupLength = gQuicktext.getGroupLength(true); if (this.mCollapseState.length < groupLength) { for (var i = this.mCollapseState.length; i < groupLength; i++) this.mCollapseState[i] = true; } else if (this.mCollapseState.length > groupLength) this.mCollapseState.splice(groupLength, this.mCollapseState.length - groupLength); for (var i = 0; i < groupLength; i++) { var groupIndex = k; var textLength = gQuicktext.getTextLength(i, true); this.mTreeArray[k] = [i, -1, 0, -1, true, textLength, gQuicktext.getGroup(i, true).name, '']; k++; if (!this.mCollapseState[i]) continue; for (var j = 0; j < textLength; j++) { var text = gQuicktext.getText(i, j, true); var shortcut = text.shortcut; this.mTreeArray[k] = [i, j, 1, groupIndex, false, 0, text.name, shortcut]; k++; } } }, updateTreeGUI: function () { // maybe }, buildTreeGUI: function () { this.makeTreeArray(); var treeview = { rowCount: this.mTreeArray.length, lastIndex: null, isContainer: function (aRow) { return (settingsDialog.mTreeArray[aRow][1] == -1); }, isContainerOpen: function (aRow) { return settingsDialog.mCollapseState[settingsDialog.mTreeArray[aRow][0]]; }, isContainerEmpty: function (aRow) { return (settingsDialog.mTreeArray[aRow][5] == 0); }, isSeparator: function (aRow) { return false; }, isSorted: function (aRow) { return false; }, isEditable: function (aRow) { return false; }, hasNextSibling: function (aRow, aAfter) { return (settingsDialog.mTreeArray[aAfter + 1] && settingsDialog.mTreeArray[aRow][2] == settingsDialog.mTreeArray[aAfter + 1][2] && settingsDialog.mTreeArray[aRow][3] == settingsDialog.mTreeArray[aAfter + 1][3]); }, getLevel: function (aRow) { return settingsDialog.mTreeArray[aRow][2]; }, getImageSrc: function (aRow, aCol) { return null; }, getParentIndex: function (aRow) { return settingsDialog.mTreeArray[aRow][3]; }, getRowProperties: function (aRow, aProps) { }, getCellProperties: function (aRow, aCol, aProps) { }, getColumnProperties: function (aColid, aCol, aProps) { }, getProgressMode: function (aRow, aCol) { }, getCellValue: function (aRow, aCol) { return null; }, canDropBeforeAfter: function (aRow, aBefore) { if (aBefore) return this.canDrop(aRow, -1); return this.canDrop(aRow, 1); }, canDropOn: function (aRow) { return this.canDrop(aRow, 0); }, canDrop: function (aRow, aOrient) { var index = document.getElementById('group-tree').view.selection.currentIndex; if (index == aRow) return false; // Can only drop templates on groups if (aOrient == 0) { if (settingsDialog.mTreeArray[index][2] > 0 && settingsDialog.mTreeArray[aRow][2] == 0) return true; else return false; } // Take care if we drag a group if (settingsDialog.mTreeArray[index][2] == 0) { if (aOrient < 0 && settingsDialog.mTreeArray[aRow][2] == 0) return true; if (aOrient > 0 && settingsDialog.mTreeArray.length - 1 == aRow) return true; } // Take care if we drag a template else { if (settingsDialog.mTreeArray[aRow][2] > 0) return true; } return false; }, drop: function (aRow, aOrient) { settingsDialog.saveText(); settingsDialog.mPickedIndex = null; var selectIndex = -1; var index = document.getElementById('group-tree').view.selection.currentIndex; // Droping a group if (settingsDialog.mTreeArray[index][2] == 0) { var textLength = gQuicktext.getTextLength(settingsDialog.mTreeArray[index][0], true); if (!settingsDialog.mCollapseState[settingsDialog.mTreeArray[index][0]]) textLength = 0; if (aOrient > 0) { gQuicktext.moveGroup(settingsDialog.mTreeArray[index][0], gQuicktext.getGroupLength(true), true); var state = settingsDialog.mCollapseState.splice(settingsDialog.mTreeArray[index][0], 1); state = (state == "false") ? false : true; settingsDialog.mCollapseState.push(state); selectIndex = settingsDialog.mTreeArray.length - textLength - 1; } else { gQuicktext.moveGroup(settingsDialog.mTreeArray[index][0], settingsDialog.mTreeArray[aRow][0], true); var state = settingsDialog.mCollapseState.splice(settingsDialog.mTreeArray[index][0], 1); state = (state == "false") ? false : true; settingsDialog.mCollapseState.splice(settingsDialog.mTreeArray[aRow][0], 0, state); selectIndex = (aRow > index) ? aRow - textLength - 1 : aRow; } } // Droping a template else { switch (aOrient) { case 0: var textLength = gQuicktext.getTextLength(settingsDialog.mTreeArray[aRow][0], true); gQuicktext.moveText(settingsDialog.mTreeArray[index][0], settingsDialog.mTreeArray[index][1], settingsDialog.mTreeArray[aRow][0], textLength, true); selectIndex = (settingsDialog.mTreeArray[index][0] == settingsDialog.mTreeArray[aRow][0] || aRow > index) ? aRow + textLength : aRow + textLength + 1; break; case 1: gQuicktext.moveText(settingsDialog.mTreeArray[index][0], settingsDialog.mTreeArray[index][1], settingsDialog.mTreeArray[aRow][0], settingsDialog.mTreeArray[aRow][1] + 1, true); selectIndex = (aRow > index) ? aRow : aRow + 1; break; default: gQuicktext.moveText(settingsDialog.mTreeArray[index][0], settingsDialog.mTreeArray[index][1], settingsDialog.mTreeArray[aRow][0], settingsDialog.mTreeArray[aRow][1], true); selectIndex = (aRow > index) ? aRow - 1 : aRow; break; } } settingsDialog.makeTreeArray(); document.getElementById('group-tree').invalidate(); document.getElementById('group-tree').view.selection.select(selectIndex); settingsDialog.changesMade(); }, getCellText: function (aRow, aCol) { colName = (aCol.id) ? aCol.id : aCol; if (colName == "group") { return settingsDialog.mTreeArray[aRow][6]; } else if (colName == "shortcut" && settingsDialog.mTreeArray[aRow][1] > -1) { return settingsDialog.mTreeArray[aRow][7]; } return ""; }, toggleOpenState: function (aRow) { var state = settingsDialog.mCollapseState[settingsDialog.mTreeArray[aRow][0]]; settingsDialog.mCollapseState[settingsDialog.mTreeArray[aRow][0]] = !state; settingsDialog.makeTreeArray(); var treeObject = document.getElementById('group-tree'); if (state) treeObject.rowCountChanged(aRow, -settingsDialog.mTreeArray[aRow][5]); else treeObject.rowCountChanged(aRow, settingsDialog.mTreeArray[aRow][5]); treeObject.invalidate(); document.getElementById('group-tree').view.selection.select(aRow); }, setTree: function (aTreebox) { this.treebox = aTreebox; } } var firstVisibleRow = document.getElementById('group-tree').getFirstVisibleRow(); var selectedIndex = document.getElementById('group-tree').view.selection.currentIndex; if (selectedIndex == -1 && this.mTreeArray.length) selectedIndex = 0; document.getElementById('group-tree').view = treeview; document.getElementById('group-tree').scrollToRow(firstVisibleRow); this.selectTreeRow(selectedIndex); this.pickText(); }, selectTreeRow: function (aRow) { document.getElementById('group-tree').view.selection.select(aRow); document.getElementById('group-tree').ensureRowIsVisible(aRow); }, updateButtonStates: function () { // Update the add-buttons if (this.mTreeArray.length) { var index = document.getElementById('group-tree').view.selection.currentIndex; if (this.mTreeArray[index] && gQuicktext.getGroup(this.mTreeArray[index][0], true).protected) { document.getElementById("group-button-remove").setAttribute("disabled", true); document.getElementById("group-button-add-text").setAttribute("disabled", true); } else { document.getElementById("group-button-remove").removeAttribute("disabled"); document.getElementById("group-button-add-text").removeAttribute("disabled"); } } else { document.getElementById('group-button-add-text').setAttribute("disabled", true); document.getElementById('group-button-remove').setAttribute("disabled", true); } let scriptIndex = document.getElementById('script-list').value; let script = gQuicktext.getScript(scriptIndex, true); if (gQuicktext.getScriptLength(true) && !script.protected) document.getElementById('script-button-remove').removeAttribute("disabled"); else document.getElementById('script-button-remove').setAttribute("disabled", true); }, /* * INSERT VARIABLES */ insertVariable: function (aStr) { var textbox = document.getElementById("text-subject"); if (!textbox.getAttribute("focused")) var textbox = document.getElementById("text"); var selStart = textbox.selectionStart; var selEnd = textbox.selectionEnd; var selLength = textbox.textLength; var s1 = (textbox.value).substring(0, selStart); var s2 = (textbox.value).substring(selEnd, selLength) textbox.value = s1 + "[[" + aStr + "]]" + s2; var selNewStart = selStart + 4 + aStr.length; textbox.setSelectionRange(selNewStart, selNewStart); this.enableSave(); }, // TODO: Hardcoding files is no longer possible in pure WebExt, either Exp only or gallery. insertFileVariable: async function () { if ((file = await gQuicktext.pickFile([2], 0, extension.localeData.localizeMessage("insertFile"))) != null) { this.insertVariable('FILE=' + file.path); } this.enableSave(); }, // TODO: Hardcoding files is no longer possible in pure WebExt, either Exp only or gallery. insertImageVariable: async function () { if ((file = await gQuicktext.pickFile([4], 0, extension.localeData.localizeMessage("insertImage"))) != null) { this.insertVariable('IMAGE=' + file.path); } this.enableSave(); }, /* * IMPORT/EXPORT FUNCTIONS */ exportTemplatesToFile: async function () { await notifyTools.notifyBackground({ command: "exportTemplates" }); window.focus(); }, importTemplatesFromFile: async function () { // We use the legacy file picker here, because the user event handler sometimes // gets lost when piped through notify Tools. // const parsedData = await notifyTools.notifyBackground({ command: "pickAndParseConfigFile" }); const file = await gQuicktext.pickFile([5, 3], 0, extension.localeData.localizeMessage("importFile")); if (!file) return; const parsedData = await notifyTools.notifyBackground({ command: "parseConfigFile", path: file.path }); if (!parsedData || !parsedData.templates) return; this.saveText(); this.saveScript(); var length = this.mTreeArray.length; gQuicktext.importTemplates(parsedData.templates) this.changesMade(); this.makeTreeArray(); document.getElementById('group-tree').rowCountChanged(length - 1, this.mTreeArray.length - length); this.updateButtonStates(); }, exportScriptsToFile: async function () { await notifyTools.notifyBackground({ command: "exportScripts" }); window.focus(); }, importScriptsFromFile: async function () { // We use the legacy file picker here, because the user event handler sometimes // gets lost when piped through notify Tools. // const parsedData = await notifyTools.notifyBackground({ command: "pickAndParseConfigFile" }); const file = await gQuicktext.pickFile([5, 3], 0, extension.localeData.localizeMessage("importFile")); if (!file) return; const parsedData = await notifyTools.notifyBackground({ command: "parseConfigFile", path: file.path }); if (!parsedData || !parsedData.scripts) return; this.saveText(); this.saveScript(); gQuicktext.importScripts(parsedData.scripts) this.changesMade(); this.updateScriptGUI(); this.updateButtonStates(); }, browseAttachment: async function () { if ((file = await gQuicktext.pickFile([], 0, extension.localeData.localizeMessage("attachmentFile"))) != null) { var filePath = file.path; var attachments = document.getElementById('text-attachments').value; if (attachments != "") document.getElementById('text-attachments').value = attachments + ";" + filePath; else document.getElementById('text-attachments').value = filePath; this.checkForTextChanges(6); } }, pickScript: function () { var index = document.getElementById('script-list').value; if (index == null) { document.getElementById('script-title').value = ""; document.getElementById('script').value = ""; this.mScriptIndex = null; document.getElementById('script-title').disabled = true; document.getElementById('script').hidden = true; return; } document.getElementById('script').hidden = false; if (this.mScriptIndex != index) { if (this.scriptChangesMade()) { this.changesMade(); this.mScriptChangesMade = []; } this.saveScript(); } this.mScriptIndex = index; var script = gQuicktext.getScript(index, true); let disabled = script.protected; document.getElementById('script-title').value = script.name; document.getElementById('script').value = script.script; document.getElementById('script-title').disabled = disabled; document.getElementById('script').disabled = disabled; if (disabled) document.getElementById('script-button-remove').setAttribute("disabled", true); else document.getElementById('script-button-remove').removeAttribute("disabled"); }, pickText: function () { var index = document.getElementById('group-tree').view.selection.currentIndex; if (!this.mTreeArray[index]) { document.getElementById('text-caption').textContent = extension.localeData.localizeMessage("group"); document.getElementById('text-title').value = ""; this.showElement("group", true); this.mPickedIndex = null; return; } groupIndex = this.mTreeArray[index][0]; textIndex = this.mTreeArray[index][1]; if (this.mPickedIndex && this.textChangesMade()) { this.changesMade(); this.mTextChangesMade = []; this.saveText(); } this.mPickedIndex = [groupIndex, textIndex]; if (textIndex > -1) { var text = gQuicktext.getText(groupIndex, textIndex, true); document.getElementById('text-caption').textContent = extension.localeData.localizeMessage("template"); document.getElementById('text-title').value = text.name; document.getElementById('text').value = text.text; document.getElementById('text-keyword').value = text.keyword; document.getElementById('text-subject').value = text.subject; document.getElementById('text-attachments').value = text.attachments; document.getElementById('label-shortcutModifier').value = extension.localeData.localizeMessage(document.getElementById('select-shortcutModifier').value + "Key") + "+"; if (gQuicktext.shortcutTypeAdv) { var elem = document.getElementById('text-shortcutAdv'); elem.value = text.shortcut; elem.hidden = false; document.getElementById('text-shortcutBasic').hidden = true; } else { var shortcut = text.shortcut; var elem = document.getElementById('text-shortcutBasic'); if (shortcut < 10) elem.selectedIndex = (shortcut == "0") ? 10 : shortcut; else elem.selectedIndex = 0; elem.hidden = false; document.getElementById('text-shortcutAdv').hidden = true; this.disableShortcuts(shortcut); } document.getElementById('text-type').selectedIndex = text.type == "text/html" ? 1 : 0; } else { document.getElementById('text-caption').textContent = extension.localeData.localizeMessage("group"); document.getElementById("text-title").value = gQuicktext.getGroup(groupIndex, true).name; document.getElementById("text").value = ""; document.getElementById("text-keyword").value = ""; document.getElementById("text-subject").value = ""; document.getElementById("text-attachments").value = ""; } var disabled = false; if (gQuicktext.getGroup(groupIndex, true).protected) { document.getElementById("group-button-remove").setAttribute("disabled", true); document.getElementById("group-button-add-text").setAttribute("disabled", true); disabled = true; } else { document.getElementById("group-button-remove").removeAttribute("disabled"); document.getElementById("group-button-add-text").removeAttribute("disabled"); } if (textIndex < 0) this.showElement("group", disabled); else this.showElement("text", disabled); }, showElement: function (aType, aDisabled) { var elements = document.getElementsByAttribute("candisable", "true"); for (var i = 0; i < elements.length; i++) { if (aDisabled) elements[i].setAttribute("disabled", true); else elements[i].removeAttribute("disabled"); } var elements = document.getElementsByAttribute("showfor", "*"); for (var i = 0; i < elements.length; i++) { var types = elements[i].getAttribute("showfor").split(","); var found = false; for (var type = 0; type < types.length; type++) { if (types[type] == aType) found = true; } if (found) elements[i].hidden = false; else elements[i].hidden = true; } }, /* * Add/Remove groups/templates */ addGroup: function () { var title = extension.localeData.localizeMessage("newGroup"); this.saveText(); gQuicktext.addGroup(title, true); this.mCollapseState.push(true); this.makeTreeArray(); var treeObject = document.getElementById('group-tree'); treeObject.rowCountChanged(this.mTreeArray.length - 1, 1); treeObject.invalidateRow(this.mTreeArray.length - 1); selectedIndex = this.mTreeArray.length - 1; this.selectTreeRow(selectedIndex); this.updateButtonStates(); this.changesMade(); var titleElem = document.getElementById('text-title'); titleElem.focus(); titleElem.setSelectionRange(0, title.length); }, addText: function () { var title = extension.localeData.localizeMessage("newTemplate"); this.saveText(); var groupIndex = -1; if (this.mPickedIndex) groupIndex = this.mPickedIndex[0]; var groupLength = gQuicktext.getGroupLength(true); if (groupIndex == -1) { if (groupLength == 0) return; else groupIndex = 0; } gQuicktext.addText(groupIndex, title, true); this.makeTreeArray(); var selectedIndex = -1; for (var i = 0; i <= groupIndex; i++) { selectedIndex++; if (this.mCollapseState[i]) selectedIndex += gQuicktext.getTextLength(i, true); } var treeObject = document.getElementById('group-tree'); treeObject.rowCountChanged(selectedIndex - 1, 1); treeObject.invalidateRow(selectedIndex); this.selectTreeRow(selectedIndex); this.updateButtonStates(); this.changesMade(); var titleElem = document.getElementById('text-title'); titleElem.focus(); titleElem.setSelectionRange(0, title.length); }, removeText: function () { this.saveText(); if (this.mPickedIndex) { var groupIndex = this.mPickedIndex[0]; var textIndex = this.mPickedIndex[1]; var title = gQuicktext.getGroup(groupIndex, true).name; if (textIndex > -1) title = gQuicktext.getText(groupIndex, textIndex, true).name; if (confirm(extension.localeData.localizeMessage("remove", [title]))) { this.mPickedIndex = null; var textLength = gQuicktext.getTextLength(groupIndex, true); var selectedIndex = document.getElementById('group-tree').view.selection.currentIndex; var moveSelectionUp = false; if (this.mTreeArray[selectedIndex + 1] && this.mTreeArray[selectedIndex + 1][2] < this.mTreeArray[selectedIndex][2]) moveSelectionUp = true; var treeObject = document.getElementById('group-tree'); if (textIndex == -1) { gQuicktext.removeGroup(groupIndex, true); if (this.mCollapseState[groupIndex]) treeObject.rowCountChanged(selectedIndex, -(textLength + 1)); else treeObject.rowCountChanged(selectedIndex, -1); this.makeTreeArray(); treeObject.invalidate(); } else { gQuicktext.removeText(groupIndex, textIndex, true); treeObject.rowCountChanged(selectedIndex, -1); this.makeTreeArray(); treeObject.invalidate(); } this.updateVariableGUI(); this.updateButtonStates(); this.changesMade(); var selectedRow = false; if (moveSelectionUp) { selectedRow = true; this.selectTreeRow(selectedIndex - 1); } var rowCount = this.mTreeArray.length - 1; if (selectedIndex > rowCount || selectedIndex == -1) { selectedRow = true; this.selectTreeRow(rowCount); } if (!selectedRow) this.selectTreeRow(selectedIndex); } } }, addScript: function () { this.saveScript(); var title = extension.localeData.localizeMessage("newScript"); gQuicktext.addScript(title, true); this.updateScriptGUI(); this.updateButtonStates(); var listElem = document.getElementById('script-list'); selectedIndex = listElem.getRowCount() - 1; listElem.selectedIndex = selectedIndex; this.changesMade(); var titleElem = document.getElementById('script-title'); titleElem.focus(); titleElem.setSelectionRange(0, title.length); }, removeScript: function () { this.saveScript(); var scriptIndex = document.getElementById('script-list').value; if (scriptIndex != null) { var title = gQuicktext.getScript(scriptIndex, true).name; if (confirm(extension.localeData.localizeMessage("remove", [title]))) { gQuicktext.removeScript(scriptIndex, true); this.changesMade(); if (gQuicktext.getScriptLength(true) > 0) { var selectedIndex = document.getElementById('script-list').selectedIndex - 1; if (selectedIndex < 0) selectedIndex = 0; this.mScriptIndex = selectedIndex; } else { this.mScriptIndex = null; selectedIndex = -1; } document.getElementById('script-list').selectedIndex = selectedIndex; this.updateScriptGUI(); this.updateVariableGUI(); this.updateButtonStates(); } } }, /* * Other actions */ getCommunityScripts: function () { notifyTools.notifyBackground({ command: "openWebPage", url: "https://github.com/jobisoft/quicktext/wiki/Community-scripts" }); }, openHomepage: function () { notifyTools.notifyBackground({ command: "openWebPage", url: "https://github.com/jobisoft/quicktext/wiki/" }); }, resetCounter: function () { notifyTools.notifyBackground({ command: "setPref", pref: "counter", value: 0 }); }, /* * OBSERVERS */ observe: function (aSubject, aTopic, aData) { if (aTopic == "updatesettings") { this.updateGUI(); } } } window.addEventListener("DOMContentLoaded", () => settingsDialog.init()); window.addEventListener("unload", () => settingsDialog.unload()); quicktext-6.3.2/xul_settings_dialog/settings.xhtml000066400000000000000000000636371477370713100225610ustar00rootroot00000000000000 __MSG_quicktext.settings.title__
__MSG_quicktext.settings.label__
__MSG_quicktext.defaultImport.label__
__MSG_quicktext.sharingTemplates.label__
__MSG_quicktext.sharingScripts.label__
__MSG_quicktext.counter.label__
__MSG_quicktext.title.label__
__MSG_quicktext.template.label__
__MSG_quicktext.title.label__
__MSG_quicktext.script.label__