40 | Hi! This requires JavaScript for dynamically rendering the HTML interface.
41 |
42 | If you see this message perhaps JavaScript is off, or controlled by an extension.
43 |
44 |
45 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
--------------------------------------------------------------------------------
/css/fontawesome/linux.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #### userjs-tool.html
2 |
3 | > This is a continuation of the project by the same maintainer (previously under @icpantsparti)
4 |
5 | Interactive view, compare, and more for Firefox user.js (eg arkenfox/user.js) + about:config functions
6 |
7 | * [Open userjs-tool.html on-line (github.io)](https://icpantsparti2.github.io/firefox-user.js-tool/userjs-tool.html)
8 |
9 | View the current arkenfox user.js* in a table (github.io):
10 |
11 | * https://icpantsparti2.github.io/firefox-user.js-tool/arkenfox-gui.html
12 | * https://arkenfox.github.io/gui
13 | * https://icpantsparti2.github.io/firefox-user.js-tool/userjs-tool.html?at
14 |
15 | [Functions to get more out of about:config (eg: find, filter, list, save to file, etc)](https://raw.githubusercontent.com/icpantsparti2/firefox-user.js-tool/master/userjs-tool-aboutconfig-functions.js)
16 |
17 | > > > \*Note: the excellent `arkenfox user.js` is by other developers at:
18 | > > > [arkenfox user.js home](https://github.com/arkenfox/user.js) / [arkenfox user.js issues](https://github.com/arkenfox/user.js/issues?q=sort%3Aupdated-desc) / [arkenfox user.js wiki](https://github.com/arkenfox/user.js/wiki)
19 |
20 | ----
21 |
22 | Introduction
23 |
24 | Display a Mozilla Firefox user.js settings file contents in your Firefox browser, with:
25 | * highlighting, links, themes*, re-size, wrap, about:config links/regex/groups
26 | * expanding sections, and index to go to sections (with compatible user.js projects)
27 | * compare preferences in two user.js, in a table format with order/layout options and bold cell border around differences
28 | * actions including: user-overrides.js* append* (with comment-out*), point and click overrides collector, skeleton, prefs.js cleaner*, group by values
29 | * load/save, drag/drop, or copy/paste user.js files (can load from some on-line URLs too)
30 | * functions for find (filter/list)/reset/set on about:config Web Console (Firefox/forks/Thunderbird/SeaMonkey)
31 | * This is coded in HTML/CSS/JavaScript with no cross domain dependency
32 | * open [userjs-tool.html on-line](https://icpantsparti2.github.io/firefox-user.js-tool/userjs-tool.html) or save for off-line use
33 |
34 | (*arkenfox/user.js inspired. Please visit [arkenfox/user.js](https://github.com/arkenfox/user.js) and read their info on [arkenfox/user.js/wiki](https://github.com/arkenfox/user.js/wiki). They also have nice scripts for append/clean/troubleshoot.)
35 |
36 | This started as an over the top experiment for learning some HTML/CSS/JavaScript (first released 2019.01.02, compare added 2020.02.22). This is a viewer/tool, and not an editor/installer.
37 |
38 | Disclaimer: Use with care at your own risk, and verify any results
39 |
40 | ----
41 |
42 |
43 |
44 | (Optional) How to save and open userjs-tool.html off-line
45 |
46 | * Click the Code button on this repo and Download ZIP (https://github.com/icpantsparti2/firefox-user.js-tool/archive/refs/heads/master.zip)
47 | * Open the saved `userjs-tool.html` file with your Firefox browser
48 | (you can drag and drop it from your Downloads folder into a new tab)
49 | * Bookmark it for easy access
50 | * Remember to check here for updates
51 |
52 | ----
53 |
54 |
55 |
56 | Other Info
57 |
58 | * The `userjs-tool-aboutconfig-functions.js` file is also embeded in `userjs-tool.html` (view with the [a:c Functions] button).
59 |
60 | * You can do these (and more) from the interface, or by using URL parameters:
61 |
62 | * [View the current arkenfox user.js (github.io)](https://icpantsparti2.github.io/firefox-user.js-tool/userjs-tool.html?av)
63 |
64 | * [View the current arkenfox user.js in a table (github.io)](https://icpantsparti2.github.io/firefox-user.js-tool/userjs-tool.html?at)
65 |
66 | * Load and view a user.js URL: [https://icpantsparti2.github.io/firefox-user.js-tool/userjs-tool.html?action=view1&load1=%68ttps://raw.githubusercontent.com/arkenfox/user.js/master/user.js](https://icpantsparti2.github.io/firefox-user.js-tool/userjs-tool.html?action=view1&load1=%68ttps://raw.githubusercontent.com/arkenfox/user.js/master/user.js)
67 |
68 | ----
69 |
70 |
71 |
72 | Preview
73 |
74 |
75 |
--------------------------------------------------------------------------------
/js/userjs-tool-userjs-append.js:
--------------------------------------------------------------------------------
1 | // Name : userjs-tool-userjs-append.js
2 | // Project : https://github.com/icpantsparti2/firefox-user.js-tool
3 | // On-line : https://icpantsparti2.github.io/firefox-user.js-tool/userjs-tool.html
4 | // License (MIT): https://raw.githubusercontent.com/icpantsparti2/firefox-user.js-tool/master/LICENSE
5 | // Version : 2022.04.06
6 |
7 | // *************************************
8 | // userjsAppend
9 | // *************************************
10 |
11 | function userjsAppend(input_box_name, input_box_name_2, output_box_name) {
12 |
13 | var input_box = document.getElementById(input_box_name);
14 | var input_box_2 = document.getElementById(input_box_name_2);
15 | var output_box = document.getElementById(output_box_name);
16 | // convert in-block comments to in-line (improves inactive pref recognition)
17 | var append_content =
18 | amendCodeComments(input_box_2.value, true)
19 | .replace(/(\r\n|\r)/g,'\n').split("\n");
20 |
21 | var x = new RegExp("^[ \t]*\/\/\/\/ --- add-override-comment ---[ \t]*$", "mi");
22 | var override_tagging_on = x.test(input_box_2.value);
23 | output_box.value = '';
24 | updateDateTimeStampVariable();
25 | output_box.value +=
26 | '// ' + date_time_stamp
27 | + " appended user-overrides.js to user-template.js\n\n"
28 | + input_box.value.replace(/[\r\n]*$/, "")
29 | + "\n\n\n\n\n"
30 | + "/*** (overrides) __________ "
31 | + "(start of overrides) __________ ***/\n"
32 | + 'user_pref("_user.js.parrot", "(overrides) (start of overrides)");'
33 | + "\n\n\n\n\n";
34 |
35 | var i = 0;
36 | for (i in append_content) {
37 | var line = append_content[i];
38 | var prefName;
39 |
40 | // (after amendCodeComments) change '// /*...*/' to '/*...*/'
41 | x = new RegExp("^\\/\\/ ([ \t]*\\/\\*.*\\*\\/[ \t]*)$", "gm");
42 | line = line.replace(x, "$1");
43 |
44 | // overrides: comment-out
45 | x = new RegExp("^[ \t]*\/\/\/\/ --- comment-out --- '([^']+)'.*$");
46 | if (x.test(line)) {
47 | // override-out comment pref in the output
48 | prefName = line.replace(x, "$1");
49 | x = new RegExp("user_pref[ \t]*\\([ \t]*[\"']"
50 | + RegExp.escape(prefName) + "[\"']", "gm");
51 | output_box.value = output_box.value.replace(x, "\/\/\/\/COMMENT-OUT: $&");
52 | // prevent duplicated ////COMMENT-OUT:
53 | x = new RegExp("\/\/\/\/COMMENT-OUT: (\/\/\/\/COMMENT-OUT: "
54 | + "user_pref[ \t]*\\([ \t]*[\"']"
55 | + RegExp.escape(prefName) + "[\"'])", "gm");
56 | output_box.value = output_box.value.replace(x, "$1");
57 | }
58 |
59 | // if override tagging is required, for active overrides user_pref
60 | // prefix any already occurring same name user_pref with ////OVERRIDE:
61 | x = new RegExp("^[ \t]*user_pref", "i");
62 | if ( (override_tagging_on) && (x.test(line)) ) {
63 | // get prefname
64 | x = new RegExp("^(.*user_pref)" // $1 user_pref //user_pref etc
65 | + "([ \t]*\\([ \t]*[\"'])" // $2 (" ('
66 | + "([^\"']+)" // $3 prefname
67 | + "([\"'][ \t]*,[ \t]*)" // $4 ", ',
68 | + "(.*)" // $5 prefvalue "prefvalue" 'prefvalue'
69 | + "([ \t]*\\)[ \t]*;)" // $6 );
70 | + "(.*)$", "gi"); // $7 afters/comment
71 | prefName = line.replace(x,"$3");
72 | // override comment pref in the output
73 | if (prefName != "_user.js.parrot") {
74 | x = new RegExp("user_pref[ \t]*\\([ \t]*[\"']"
75 | + RegExp.escape(prefName) + "[\"']", "gm");
76 | output_box.value = output_box.value.replace(x, "\/\/\/\/OVERRIDE: $&");
77 | // prevent duplicated ////OVERRIDE:
78 | x = new RegExp("\/\/\/\/OVERRIDE: (\/\/\/\/OVERRIDE: "
79 | + "user_pref[ \t]*\\([ \t]*[\"']"
80 | + RegExp.escape(prefName) + "[\"'])", "gm");
81 | output_box.value = output_box.value.replace(x, "$1");
82 | }
83 | }
84 |
85 | // append line
86 | output_box.value += line + "\n";
87 | }
88 | append_content = [];
89 |
90 | output_box.value += "\n\n\n\n/*** (overrides) (end of overrides) ***/\n";
91 | output_box.value +=
92 | 'user_pref("_user.js.parrot", "(overrides) (end of overrides)'
93 | + ': SUCCESS");' + "\n";
94 | } /* end function userjsAppend */
95 |
--------------------------------------------------------------------------------
/js/userjs-tool-userjs-reduce.js:
--------------------------------------------------------------------------------
1 | // Name : userjs-tool-userjs-reduce.js
2 | // Project : https://github.com/icpantsparti2/firefox-user.js-tool
3 | // On-line : https://icpantsparti2.github.io/firefox-user.js-tool/userjs-tool.html
4 | // License (MIT): https://raw.githubusercontent.com/icpantsparti2/firefox-user.js-tool/master/LICENSE
5 | // Version : 2022.04.06
6 |
7 | // *************************************
8 | // userjsReduce
9 | // *************************************
10 |
11 | function userjsReduce(input_box_name, output_box_name, skeleton) {
12 |
13 | var input_box = document.getElementById(input_box_name);
14 | var output_box = document.getElementById(output_box_name);
15 | output_box.value = '';
16 |
17 | // convert in-block comments to in-line (improves inactive pref recognition)
18 | var input_content = amendCodeComments(input_box.value, true)
19 | .replace(/(\r\n|\r)/g,'\n').split("\n");
20 |
21 | var section_number_tag = "0000";
22 | var section_number_tag_9999_prefix = "";
23 | var userjs_type = "";
24 | updateDateTimeStampVariable();
25 | if (skeleton) {
26 | output_box.value += "// " + date_time_stamp + " skeleton\n\n";
27 | output_box.value += "/*** (overrides) (TOP) / Introduction ***/";
28 | }
29 | else {
30 | output_box.value += "// " + date_time_stamp + " reduced\n";
31 | }
32 |
33 | var i = 0;
34 | for (i in input_content) {
35 | var line = input_content[i];
36 | var x="",r="";
37 |
38 | if (skeleton) {
39 | if (line == "/*** (overrides) (TOP) / Introduction ***/") { continue; }
40 | }
41 |
42 | userjs_type = detectUserjsType(line, userjs_type, i);
43 |
44 | // pick up the arkenfox/user.js section number
45 | if (userjs_type == "arkenfox") {
46 | if (
47 | new RegExp("^\/\/ /[*/]+ +(START|END|[0-9][^:]+):").test(line)
48 | || new RegExp("^\/\/ /[*/]+ +\\[SECTION [^:]+:").test(line)
49 | ) {
50 | section_number_tag = line;
51 | x = new RegExp("^(?:\/\/ )/[*/]+ +\\[SECTION ([^\\]]+)\\]:.*$");
52 | section_number_tag = section_number_tag.replace(x, "$1");
53 | x = new RegExp("^(?:\/\/ )/[*/]+ +([^:]+):.*$");
54 | section_number_tag = section_number_tag.replace(x, "$1");
55 | if (/^9999/.test(section_number_tag)) {
56 | section_number_tag_9999_prefix = '9999:';
57 | }
58 | else if (/^END/.test(section_number_tag)) {
59 | section_number_tag_9999_prefix = '';
60 | }
61 | }
62 | }
63 |
64 | if (skeleton) {
65 | // prefix arkenfox/user.js parrot value
66 | x = new RegExp("^([ \t/*]*user_pref[ \t]*"
67 | + "\\([ \t]*[\"']_user\.js\.parrot[\"'][ \t]*,[ \t]*[\"'])"
68 | + "(.*)$");
69 | if (new RegExp("\\(overrides\\)").test(line) == false) {
70 | line = line.replace(x, "$1(overrides) $2");
71 | }
72 | }
73 |
74 | // prefix user_pref line with a temporary ##PREF## identifier
75 | line = line.replace("\/\/user_pref", "\/\/ user_pref");
76 | line = line.replace("\/\*user_pref", "\/* user_pref");
77 | x = new RegExp(
78 | "^[ \t]*"
79 | + "(user_pref|\/[\/\*].*user_pref)"
80 | + "[ \t]*" + "(\\()"
81 | + "[ \t]*" + "([\"'][^\"']+[\"'])"
82 | + "[ \t]*,[ \t]*" + "(.*)"
83 | + "[ \t]*" + "(\\))"
84 | + "[ \t]*" + "(;).*$");
85 | if (skeleton) {
86 | // comment the pref //
87 | line = line.replace(x, "##PREF##\/\/ $1$2$3, $4$5$6");
88 | }
89 | else {
90 | line = line.replace(x, "##PREF##$1$2$3, $4$5$6");
91 | }
92 |
93 | // keep section_heading or pref lines
94 | if ( detectSectionHeading(line, userjs_type, i) == true ) {
95 | line = tidySectionHeading(line, true);
96 | if (skeleton) {
97 | // output heading line (with '(overrides)' inserted)
98 | line = line.replace(new RegExp("^\\(overrides\\) "), "");
99 | output_box.value += "\n\n/*** (overrides) " + line + " ***/";
100 | }
101 | else {
102 | output_box.value += "\n\n/*** " + line + " ***/";
103 | }
104 | }
105 | else if (/^##PREF##/.test(line)) {
106 | // remove the prefix
107 | line = line.replace(new RegExp("^##PREF##"), "");
108 |
109 | if (skeleton) {
110 | // un-comment the arkenfox/user.js parrot
111 | x = new RegExp("^//[ \t/*]*(user_pref[ \t]*"
112 | + "\\([ \t]*[\"']_user\.js\.parrot[\"'][ \t]*,[ \t]*[\"'].*)$");
113 | line = line.replace(x, "$1");
114 | }
115 |
116 | // output user_pref line (and add section number if arkenfox)
117 | output_box.value += "\n" + line;
118 | if (userjs_type == "arkenfox") {
119 | output_box.value +=
120 | " // " + section_number_tag_9999_prefix + section_number_tag;
121 | }
122 | }
123 |
124 | } /* end for (i in input_content) */
125 | input_content = [];
126 |
127 | output_box.value += "\n";
128 | } /* end function userjsReduce */
129 |
--------------------------------------------------------------------------------
/js/jsdiff-modified.js:
--------------------------------------------------------------------------------
1 | //
11 |
12 | /*
13 | * Javascript Diff Algorithm
14 | * By John Resig (http://ejohn.org/)
15 | * Modified by Chu Alan "sprite"
16 | *
17 | * Released under the MIT license.
18 | *
19 | * More Info:
20 | * http://ejohn.org/projects/javascript-diff-algorithm/
21 | */
22 |
23 | function escape(s) {
24 | var n = s;
25 | // n = n.replace(/&/g, "&");
26 | // n = n.replace(//g, ">");
28 | // n = n.replace(/"/g, """);
29 |
30 | return n;
31 | }
32 |
33 | function diffString( o, n ) {
34 | o = o.replace(/\s+$/, '');
35 | n = n.replace(/\s+$/, '');
36 |
37 | var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/) );
38 | var str = "";
39 |
40 | var oSpace = o.match(/\s+/g);
41 | if (oSpace == null) {
42 | oSpace = ["\n"];
43 | } else {
44 | oSpace.push("\n");
45 | }
46 | var nSpace = n.match(/\s+/g);
47 | if (nSpace == null) {
48 | nSpace = ["\n"];
49 | } else {
50 | nSpace.push("\n");
51 | }
52 |
53 | if (out.n.length == 0) {
54 | for (var i = 0; i < out.o.length; i++) {
55 | str += '' + escape(out.o[i]) + oSpace[i] + "";
56 | }
57 | } else {
58 | if (out.n[0].text == null) {
59 | for (n = 0; n < out.o.length && out.o[n].text == null; n++) {
60 | str += '' + escape(out.o[n]) + oSpace[n] + "";
61 | }
62 | }
63 |
64 | for ( var i = 0; i < out.n.length; i++ ) {
65 | if (out.n[i].text == null) {
66 | str += '' + escape(out.n[i]) + nSpace[i] + "";
67 | } else {
68 | var pre = "";
69 |
70 | for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
71 | pre += '' + escape(out.o[n]) + oSpace[n] + "";
72 | }
73 | str += " " + out.n[i].text + nSpace[i] + pre;
74 | }
75 | }
76 | }
77 |
78 | return str;
79 | }
80 |
81 | function randomColor() {
82 | return "rgb(" + (Math.random() * 100) + "%, " +
83 | (Math.random() * 100) + "%, " +
84 | (Math.random() * 100) + "%)";
85 | }
86 | function diffString2( o, n ) {
87 | o = o.replace(/\s+$/, '');
88 | n = n.replace(/\s+$/, '');
89 |
90 | var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/) );
91 |
92 | var oSpace = o.match(/\s+/g);
93 | if (oSpace == null) {
94 | oSpace = ["\n"];
95 | } else {
96 | oSpace.push("\n");
97 | }
98 | var nSpace = n.match(/\s+/g);
99 | if (nSpace == null) {
100 | nSpace = ["\n"];
101 | } else {
102 | nSpace.push("\n");
103 | }
104 |
105 | var os = "";
106 | var colors = new Array();
107 | for (var i = 0; i < out.o.length; i++) {
108 | colors[i] = randomColor();
109 |
110 | if (out.o[i].text != null) {
111 | os += '' +
112 | escape(out.o[i].text) + oSpace[i] + "";
113 | } else {
114 | os += "" + escape(out.o[i]) + oSpace[i] + "";
115 | }
116 | }
117 |
118 | var ns = "";
119 | for (var i = 0; i < out.n.length; i++) {
120 | if (out.n[i].text != null) {
121 | ns += '' +
122 | escape(out.n[i].text) + nSpace[i] + "";
123 | } else {
124 | ns += "" + escape(out.n[i]) + nSpace[i] + "";
125 | }
126 | }
127 |
128 | return { o : os , n : ns };
129 | }
130 |
131 | function diff( o, n ) {
132 | var ns = new Object();
133 | var os = new Object();
134 |
135 | for ( var i = 0; i < n.length; i++ ) {
136 | if ( ns[ n[i] ] == null )
137 | ns[ n[i] ] = { rows: new Array(), o: null };
138 | ns[ n[i] ].rows.push( i );
139 | }
140 |
141 | for ( var i = 0; i < o.length; i++ ) {
142 | if ( os[ o[i] ] == null )
143 | os[ o[i] ] = { rows: new Array(), n: null };
144 | os[ o[i] ].rows.push( i );
145 | }
146 |
147 | for ( var i in ns ) {
148 | if ( ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1 ) {
149 | n[ ns[i].rows[0] ] = { text: n[ ns[i].rows[0] ], row: os[i].rows[0] };
150 | o[ os[i].rows[0] ] = { text: o[ os[i].rows[0] ], row: ns[i].rows[0] };
151 | }
152 | }
153 |
154 | for ( var i = 0; i < n.length - 1; i++ ) {
155 | if ( n[i].text != null && n[i+1].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
156 | n[i+1] == o[ n[i].row + 1 ] ) {
157 | n[i+1] = { text: n[i+1], row: n[i].row + 1 };
158 | o[n[i].row+1] = { text: o[n[i].row+1], row: i + 1 };
159 | }
160 | }
161 |
162 | for ( var i = n.length - 1; i > 0; i-- ) {
163 | if ( n[i].text != null && n[i-1].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
164 | n[i-1] == o[ n[i].row - 1 ] ) {
165 | n[i-1] = { text: n[i-1], row: n[i].row - 1 };
166 | o[n[i].row-1] = { text: o[n[i].row-1], row: i - 1 };
167 | }
168 | }
169 |
170 | return { o: o, n: n };
171 | }
172 |
--------------------------------------------------------------------------------
/js/download.js:
--------------------------------------------------------------------------------
1 | //
10 |
11 | //download.js v4.2, by dandavis; 2008-2016. [CCBY2] see http://danml.com/download.html for tests/usage
12 | // v1 landed a FF+Chrome compat way of downloading strings to local un-named files, upgraded to use a hidden frame and optional mime
13 | // v2 added named files via a[download], msSaveBlob, IE (10+) support, and window.URL support for larger+faster saves than dataURLs
14 | // v3 added dataURL and Blob Input, bind-toggle arity, and legacy dataURL fallback was improved with force-download mime and base64 support. 3.1 improved safari handling.
15 | // v4 adds AMD/UMD, commonJS, and plain browser support
16 | // v4.1 adds url download capability via solo URL argument (same domain/CORS only)
17 | // v4.2 adds semantic variable names, long (over 2MB) dataURL support, and hidden by default temp anchors
18 | // https://github.com/rndme/download
19 |
20 | (function (root, factory) {
21 | if (typeof define === 'function' && define.amd) {
22 | // AMD. Register as an anonymous module.
23 | define([], factory);
24 | } else if (typeof exports === 'object') {
25 | // Node. Does not work with strict CommonJS, but
26 | // only CommonJS-like environments that support module.exports,
27 | // like Node.
28 | module.exports = factory();
29 | } else {
30 | // Browser globals (root is window)
31 | root.download = factory();
32 | }
33 | }(this, function () {
34 |
35 | return function download(data, strFileName, strMimeType) {
36 |
37 | var self = window, // this script is only for browsers anyway...
38 | defaultMime = "application/octet-stream", // this default mime also triggers iframe downloads
39 | mimeType = strMimeType || defaultMime,
40 | payload = data,
41 | url = !strFileName && !strMimeType && payload,
42 | anchor = document.createElement("a"),
43 | toString = function(a){return String(a);},
44 | myBlob = (self.Blob || self.MozBlob || self.WebKitBlob || toString),
45 | fileName = strFileName || "download",
46 | blob,
47 | reader;
48 | myBlob= myBlob.call ? myBlob.bind(self) : Blob ;
49 |
50 | if(String(this)==="true"){ //reverse arguments, allowing download.bind(true, "text/xml", "export.xml") to act as a callback
51 | payload=[payload, mimeType];
52 | mimeType=payload[0];
53 | payload=payload[1];
54 | }
55 |
56 |
57 | if(url && url.length< 2048){ // if no filename and no mime, assume a url was passed as the only argument
58 | fileName = url.split("/").pop().split("?")[0];
59 | anchor.href = url; // assign href prop to temp anchor
60 | if(anchor.href.indexOf(url) !== -1){ // if the browser determines that it's a potentially valid url path:
61 | var ajax=new XMLHttpRequest();
62 | ajax.open( "GET", url, true);
63 | ajax.responseType = 'blob';
64 | ajax.onload= function(e){
65 | download(e.target.response, fileName, defaultMime);
66 | };
67 | setTimeout(function(){ ajax.send();}, 0); // allows setting custom ajax headers using the return:
68 | return ajax;
69 | } // end if valid url?
70 | } // end if url?
71 |
72 |
73 | //go ahead and download dataURLs right away
74 | if(/^data\:[\w+\-]+\/[\w+\-]+[,;]/.test(payload)){
75 |
76 | if(payload.length > (1024*1024*1.999) && myBlob !== toString ){
77 | payload=dataUrlToBlob(payload);
78 | mimeType=payload.type || defaultMime;
79 | }else{
80 | return navigator.msSaveBlob ? // IE10 can't do a[download], only Blobs:
81 | navigator.msSaveBlob(dataUrlToBlob(payload), fileName) :
82 | saver(payload) ; // everyone else can save dataURLs un-processed
83 | }
84 |
85 | }//end if dataURL passed?
86 |
87 | blob = payload instanceof myBlob ?
88 | payload :
89 | new myBlob([payload], {type: mimeType}) ;
90 |
91 |
92 | function dataUrlToBlob(strUrl) {
93 | var parts= strUrl.split(/[:;,]/),
94 | type= parts[1],
95 | decoder= parts[2] == "base64" ? atob : decodeURIComponent,
96 | binData= decoder( parts.pop() ),
97 | mx= binData.length,
98 | i= 0,
99 | uiArr= new Uint8Array(mx);
100 |
101 | for(i;i summary { font-weight: bold; }
293 | details > summary:hover { cursor: pointer; }
294 | abbr { cursor: help; }
295 | /* details[open] > summary { text-decoration: underline; } */
296 | del { font-weight: bold; }
297 | ins { text-decoration: none; }
298 | .jump {
299 | color: #FF0000 !important; /*Red*/
300 | background-color: #FFFF00 !important; /*Yellow*/
301 | }
302 |
303 | .vcentertext {
304 | display: flex;
305 | justify-content: center;
306 | align-content: center;
307 | flex-direction: column;
308 | }
309 |
--------------------------------------------------------------------------------
/js/userjs-tool-userjs-to-value-groups.js:
--------------------------------------------------------------------------------
1 | // Name : userjs-tool-userjs-to-value-groups.js
2 | // Project : https://github.com/icpantsparti2/firefox-user.js-tool
3 | // On-line : https://icpantsparti2.github.io/firefox-user.js-tool/userjs-tool.html
4 | // License (MIT): https://raw.githubusercontent.com/icpantsparti2/firefox-user.js-tool/master/LICENSE
5 | // Version : 2022.04.06
6 |
7 | // *************************************
8 | // userjsToValueGroups
9 | // *************************************
10 |
11 | function userjsToValueGroups(input_box_name, output_box_name) {
12 | var input_box = document.getElementById(input_box_name);
13 | var output_box = document.getElementById(output_box_name);
14 | output_box.value = '';
15 | var prefArray = [];
16 |
17 | // each id in valueGroups gets unique incrementing index
18 | var valueGroups = {
19 | 'bfa': { 'id': 0, 'count': 0, 'name': "active boolean false" },
20 | 'bta': { 'id': 0, 'count': 0, 'name': "active boolean true" },
21 | 'i0a': { 'id': 0, 'count': 0, 'name': "active integer 0" },
22 | 'i1a': { 'id': 0, 'count': 0, 'name': "active integer 1" },
23 | 'i2a': { 'id': 0, 'count': 0, 'name': "active integer 2" },
24 | // 'i3a': { 'id': 0, 'count': 0, 'name': "active integer 3" },
25 | 'ixa': { 'id': 0, 'count': 0, 'name': "active integer other" },
26 | 'sea': { 'id': 0, 'count': 0, 'name': "active string empty" },
27 | 'sxa': { 'id': 0, 'count': 0, 'name': "active string other" },
28 | 'zza': { 'id': 0, 'count': 0, 'name': "active invalid" },
29 | 'bfi': { 'id': 0, 'count': 0, 'name': "inactive boolean false" },
30 | 'bti': { 'id': 0, 'count': 0, 'name': "inactive boolean true" },
31 | 'i0i': { 'id': 0, 'count': 0, 'name': "inactive integer 0" },
32 | 'i1i': { 'id': 0, 'count': 0, 'name': "inactive integer 1" },
33 | 'i2i': { 'id': 0, 'count': 0, 'name': "inactive integer 2" },
34 | // 'i3i': { 'id': 0, 'count': 0, 'name': "inactive integer 3" },
35 | 'ixi': { 'id': 0, 'count': 0, 'name': "inactive integer other" },
36 | 'sei': { 'id': 0, 'count': 0, 'name': "inactive string empty" },
37 | 'sxi': { 'id': 0, 'count': 0, 'name': "inactive string other" },
38 | 'zzi': { 'id': 0, 'count': 0, 'name': "inactive invalid" }
39 | }
40 | var idinc=1;
41 | Object.keys(valueGroups).forEach(function(key){
42 | valueGroups[key].id = idinc++;
43 | });
44 |
45 | // add dividers to prefArray
46 | Object.keys(valueGroups).forEach(function(key){
47 | if (valueGroups[key].id > 0) {
48 | prefArray.push( {
49 | 'group': valueGroups[key].id,
50 | 'name': "", 'state': "-", 'value': "-", 'line': "",
51 | 'hidden': false, 'count': 0
52 | } );
53 | }
54 | });
55 |
56 | var user_pref_regex = new RegExp(
57 | "^([ \t]*user_pref|.*//.*user_pref)" // $1 user_pref //user_pref etc
58 | + "([ \t]*\\([ \t]*[\"'])" // $2 (" ('
59 | + "([^\"']+)" // $3 prefname
60 | + "([\"'][ \t]*,[ \t]*)" // $4 ", ',
61 | + "(.*)" // $5 prefvalue "prefvalue" 'prefvalue'
62 | + "([ \t]*\\)[ \t]*;)" // $6 );
63 | + "(.*)$", "gi" // $7 afters/comment
64 | );
65 |
66 | var line, prefState, prefName, prefValue, prefComment, found, ic = 0;
67 |
68 | // convert in-block comments to in-line (improves inactive pref recognition)
69 | var input_content = amendCodeComments(input_box.value, true)
70 | .replace(/(\r\n|\r)/g,'\n').split("\n");
71 |
72 | // read user_pref into prefArray
73 | for (ic in input_content) {
74 | line = input_content[ic];
75 | if (user_pref_regex.test(line)) {
76 | prefState = line.replace(user_pref_regex, "$1");
77 | prefName = line.replace(user_pref_regex, "$3");
78 | prefValue = line.replace(user_pref_regex, "$5");
79 | prefComment = line.replace(user_pref_regex, "$7");
80 | if (new RegExp("^.*[/][/*].*user_pref", "i").test(prefState)) {
81 | prefState = "//";
82 | }
83 | else {
84 | prefState = "";
85 | }
86 | // check if already in the results array
87 | found=-1;
88 | for (var j = 0, len = prefArray.length; j < len; j++) {
89 | if (prefArray[j].name == prefName) {
90 | found = j;
91 | break;
92 | }
93 | }
94 | // update or add to the results array
95 | if (found > -1) {
96 | // new pref replaces previous if new=active or previous=inactive
97 | if ( (prefState == '') || (prefArray[found].state != '') ) {
98 | prefArray[found].state = prefState;
99 | prefArray[found].value = prefValue;
100 | prefArray[found].line = line;
101 | if (/hidden/i.test(prefComment)) {
102 | prefArray[found].hidden = true;
103 | }
104 | // and append ////{#count: previous}
105 | // prefArray[found].line =
106 | // line + ' ////{#' + prefArray[found].count + ': '
107 | // + prefArray[found].line
108 | // .replace(/^(.*)user_pref\("[^"]+", *(.*)\);(.*)/, "$1$2$3")
109 | // + '}';
110 | }
111 | prefArray[found].count ++;
112 | }
113 | else {
114 | // add
115 | prefArray.push( {
116 | 'group': 0,
117 | 'name': prefName,
118 | 'state': prefState,
119 | 'value': prefValue,
120 | 'line': line,
121 | 'hidden': (/hidden/i.test(prefComment) ? true : false),
122 | 'count': 1,
123 | } );
124 | }
125 | }
126 | }
127 | input_content = [];
128 |
129 | // allocate value groups (and add count to line end if >1)
130 | var groupBase = "", groupSuffix = "";
131 | for (var i = 0, len = prefArray.length; i < len; i++) {
132 | if (prefArray[i].state != "-") {
133 | if (prefArray[i].state == '//') { groupSuffix = "i" }
134 | else { groupSuffix = "a" }
135 | if (prefArray[i].value == "false") { groupBase = "bf"; }
136 | else if (prefArray[i].value == "true") { groupBase = "bt"; }
137 | else if (prefArray[i].value == "0") { groupBase = "i0"; }
138 | else if (prefArray[i].value == "1") { groupBase = "i1"; }
139 | else if (prefArray[i].value == "2") { groupBase = "i2"; }
140 | // else if (prefArray[i].value == "3") { groupBase = "i3"; }
141 | else if (new RegExp("^[0-9.+-]+$").test(prefArray[i].value)) {
142 | groupBase = "ix"; // integer other
143 | }
144 | else if (new RegExp("^[\"'][\"']$").test(prefArray[i].value)) {
145 | groupBase = "se"; // string empty
146 | }
147 | else if (new RegExp("^[\"'].*[\"']$").test(prefArray[i].value)) {
148 | groupBase = "sx"; // string other
149 | }
150 | else {
151 | groupBase = "zz"; // invalid
152 | }
153 | valueGroups[groupBase + groupSuffix].count++;
154 | prefArray[i].group = valueGroups[groupBase + groupSuffix].id;
155 | }
156 | // add count and hidden for multiple occurance
157 | if (prefArray[i].count > 1) {
158 | prefArray[i].line += ' //// (x' + prefArray[i].count
159 | + (prefArray[i].hidden ? " [HIDDEN PREF]?" : "") + ')';
160 | }
161 | }
162 |
163 | // sort
164 | prefArray.sort((a, b) => a.name.localeCompare(b.name));
165 | prefArray.sort((a, b) => a.group - b.group);
166 |
167 | // output
168 | updateDateTimeStampVariable();
169 | var activeTitleNeeded = true, inactiveTitleNeeded = true;
170 | for (var i = 0, len = prefArray.length; i < len; i++) {
171 | if (prefArray[i].state == "-") {
172 | // output title
173 | Object.keys(valueGroups).forEach(function(key){
174 | // find the valueGroups that matches the title
175 | if (prefArray[i].group == valueGroups[key].id) {
176 | // output active/inactive heading (if not already done)
177 | if ( (activeTitleNeeded)
178 | && (/^active/.test(valueGroups[key].name)) )
179 | {
180 | output_box.value =
181 | "/*** __________ " + date_time_stamp + " active user_pref"
182 | + " grouped by values (no repeats) __________ ***/\n";
183 | activeTitleNeeded = false;
184 | }
185 | if ( (inactiveTitleNeeded)
186 | && (/^inactive/.test(valueGroups[key].name)) )
187 | {
188 | output_box.value +=
189 | "\n/*** __________ " + date_time_stamp + " inactive user_pref"
190 | + " grouped by values (no repeats) __________ ***/\n";
191 | inactiveTitleNeeded = false;
192 | }
193 | // output title
194 | output_box.value += "\n/*** " + valueGroups[key].name
195 | + " (" + valueGroups[key].count + ") ***/\n"
196 | }
197 | });
198 | }
199 | else {
200 | // output user_pref
201 | output_box.value += prefArray[i].line +"\n"
202 | }
203 | }
204 |
205 | } /* end function userjsToValueGroups */
206 |
--------------------------------------------------------------------------------
/js/userjs-tool-common.js:
--------------------------------------------------------------------------------
1 | // Name : userjs-tool-common.js
2 | // Project : https://github.com/icpantsparti2/firefox-user.js-tool
3 | // On-line : https://icpantsparti2.github.io/firefox-user.js-tool/userjs-tool.html
4 | // License (MIT): https://raw.githubusercontent.com/icpantsparti2/firefox-user.js-tool/master/LICENSE
5 | // Version : 2022.04.07
6 |
7 | // *************************************
8 | // returnDateTime
9 | // *************************************
10 |
11 | function returnDateTime() {
12 | var d = new Date();
13 | // var months = ["Jan","Feb","Mar","Apr","May","Jun",
14 | // "Jul","Aug","Sep","Oct","Nov","Dec"];
15 | // var days = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
16 | // Date.now() Get the time. ECMAScript 5.
17 | return d.getFullYear()
18 | // + months[d.getMonth()]
19 | + ((d.getMonth()+1) < 10 ? "0" : "") + (d.getMonth()+1)
20 | + (d.getDate() < 10 ? "0" : "") + d.getDate() + "_"
21 | // + days[d.getDay()]
22 | + (d.getHours() < 10 ? "0" : "") + d.getHours()
23 | + (d.getMinutes() < 10 ? "0" : "") + d.getMinutes()
24 | + (d.getSeconds() < 10 ? "0" : "") + d.getSeconds();
25 | // + "." + getMilliseconds();
26 | }
27 |
28 | // *************************************
29 | // RegExp.escape
30 | // *************************************
31 |
32 | // function to escape a variable for use in regex
33 | // https://stackoverflow.com/questions/6318710/javascript-equivalent-of-perls-q-e-or-quotemeta
34 |
35 | RegExp.escape = function(text) {
36 | return (text+'').replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
37 | }
38 |
39 | // *************************************
40 | // b64EncodeUnicode/b64DecodeUnicode
41 | // *************************************
42 |
43 | // functions to base64 encode/decode (and cope with Unicode characters)
44 | // https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_Unicode_Problem
45 |
46 | function b64EncodeUnicode(str) {
47 | // first we use encodeURIComponent to get percent-encoded UTF-8,
48 | // then we convert the percent encodings into raw bytes which
49 | // can be fed into btoa.
50 | return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,
51 | function toSolidBytes(match, p1) {
52 | return String.fromCharCode('0x' + p1);
53 | }));
54 | }
55 |
56 | function b64DecodeUnicode(str) {
57 | // Going backwards: from bytestream, to percent-encoding, to original string.
58 | return decodeURIComponent(atob(str).split('').map(function(c) {
59 | return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
60 | }).join(''));
61 | }
62 |
63 | // *************************************
64 | // computedStyle
65 | // *************************************
66 |
67 | // function to get element style values
68 | // https://stackoverflow.com/questions/6134471/using-elements-that-are-added-to-an-array-with-document-getelementbyidid/6134501#6134501
69 | // var element = document.getElementById('Img3');
70 | // alert(computedStyle(element,'width'));
71 |
72 | var computedStyle = function (el,style) {
73 | var cs;
74 | if (typeof el.currentStyle != 'undefined') {
75 | cs = el.currentStyle;
76 | }
77 | else {
78 | cs = document.defaultView.getComputedStyle(el,null);
79 | }
80 | return cs[style];
81 | }
82 |
83 | // *************************************
84 | // escapeHtml
85 | // *************************************
86 |
87 | // function to replace & < > " ' characters with HTML escape codes
88 | // action = decode+quotes|encode+quotes|decode|encode
89 | // (blank or anything else = encode)
90 | // based on code from:
91 | // https://stackoverflow.com/questions/1787322/htmlspecialchars-equivalent-in-javascript/4835406
92 |
93 | function escapeHtml(text, action) {
94 | if (action == "decode+quotes") {
95 | // decode (+ quotes)
96 | var map = { '&': '&', '<': '<', '>': '>',
97 | '"': '"', ''': "'" };
98 | return text.replace(/&|<|>|"|'/g,
99 | function(m) { return map[m]; });
100 | }
101 | else if (action == "encode+quotes") {
102 | // encode (+ quotes)
103 | var map = { '&': '&', '<': '<', '>': '>',
104 | '"': '"', "'": ''' };
105 | return text.replace(/[&<>"']/g, function(m) { return map[m]; });
106 | }
107 | else if (action == "decode") {
108 | // decode
109 | var map = { '&': '&', '<': '<', '>': '>' };
110 | return text.replace(/&|<|>/g,
111 | function(m) { return map[m]; });
112 | }
113 | else {
114 | // encode
115 | var map = { '&': '&', '<': '<', '>': '>' };
116 | return text.replace(/[&<>]/g, function(m) { return map[m]; });
117 | }
118 | }
119 |
120 | // *************************************
121 | // changeClass
122 | // *************************************
123 |
124 | // based on code from:
125 | // https://stackoverflow.com/questions/195951/change-an-elements-css-class-with-javascript
126 |
127 | function changeClass(object,oldClass,newClass)
128 | {
129 | if (oldClass == "") {
130 | if ( ! /(?:^|\s)newClass(?!\S)/.test(object.className) ) {
131 | object.className += " "+newClass;
132 | }
133 | }
134 | else {
135 | var regExp = new RegExp('(?:^|\\s)' + oldClass + '(?!\\S)', 'ig');
136 | object.className = object.className.replace( regExp , newClass );
137 | }
138 | }
139 |
140 | // *************************************
141 | // getURLVariable
142 | // *************************************
143 |
144 | /* process URL variables */
145 | // https://stackoverflow.com/questions/831030/how-to-get-get-request-parameters-in-javascript
146 |
147 | function getURLVariable(name){
148 | // window.location.search.substring(1)
149 | if (name=(new RegExp('[?&]'
150 | + encodeURIComponent(name) + '=([^]*)')).exec(location.search))
151 | return decodeURIComponent(name[1])
152 | }
153 |
154 | // *************************************
155 | // amendCodeComments
156 | // *************************************
157 |
158 | /*
159 | function to either:
160 | (1) remove javascript comments, or
161 | (2) convert in-block comments to in-line
162 | based on removeCodeComments function from:
163 | https://stackoverflow.com/questions/5989315/regex-for-match-replacing-javascript-comments-both-multiline-and-inline#52630274
164 | and modified to add: convertInBlockToInLine (optional) asteriskPosition (fix)
165 | */
166 |
167 | function amendCodeComments(code="", convertInBlockToInLine=false) {
168 | var inQuoteChar = null;
169 | var inBlockComment = false;
170 | var asteriskPosition = null;
171 | var inLineComment = false;
172 | var inRegexLiteral = false;
173 | var newCode = '';
174 | for (var i=0,j=code.length;i asteriskPosition
210 | ) {
211 | inBlockComment = false;
212 | asteriskPosition = null;
213 | if (convertInBlockToInLine && code[i] !== '\n') {
214 | newCode += '\n';
215 | }
216 | }
217 | if (inLineComment && code[i] === '\n') {
218 | inLineComment = false;
219 | }
220 | }
221 | if ((!inBlockComment && !inLineComment) || convertInBlockToInLine) {
222 | newCode += code[i];
223 | }
224 | if (convertInBlockToInLine && inBlockComment && code[i] === '\n') {
225 | newCode += '// ';
226 | }
227 | }
228 | return newCode;
229 | } /* end function amendCodeComments */
230 |
231 | // *************************************
232 | // indexSelectAction
233 | // *************************************
234 |
235 | function indexSelectAction(element) {
236 | // expand, focus, and scroll to the chosen section
237 | var id = element.value;
238 | // make the select element show first choice (button title)
239 | element.selectedIndex = 0;
240 | element.blur();
241 | if (id) {
242 | if (
243 | /(compare_div|tableview_div)/
244 | .test(document.getElementById("view_area").innerHTML)
245 | ) {
246 | /* for compare or tableview */
247 | document.getElementById("tview_slider").value = id;
248 | if (id == 0) {
249 | scroll(0,0);
250 | }
251 | else {
252 | document.getElementById(id).scrollIntoView();
253 | }
254 | }
255 | else {
256 | var e = document.getElementById(id);
257 | if (e) {
258 | e.nextElementSibling.style.display = "block";
259 | section_focus = e;
260 | refocusSection();
261 | }
262 | else if (id == "(TOP) / Introduction") {
263 | scroll(0,0);
264 | }
265 | }
266 | }
267 | }
268 |
--------------------------------------------------------------------------------
/css/userjs-tool-themes.css:
--------------------------------------------------------------------------------
1 | /*
2 | Name : userjs-tool-themes.css
3 | Project : https://github.com/icpantsparti2/firefox-user.js-tool
4 | On-line : https://icpantsparti2.github.io/firefox-user.js-tool/userjs-tool.html
5 | License (MIT): https://raw.githubusercontent.com/icpantsparti2/firefox-user.js-tool/master/LICENSE
6 | Version : 2022.04.09
7 | */
8 |
9 | /* ************************************* */
10 | /* color themes */
11 | /* ************************************* */
12 |
13 | /* default theme has same values as dark theme */
14 | /* color codes: https://www.w3schools.com/colors/colors_groups.asp */
15 |
16 |
17 | /* default theme */
18 | .body_default, .view_area_default, .panels_default
19 | { background-color: #161b22; /*(black)*/
20 | color: #b3b3b3; /*(gray)*/ }
21 | .controls_default { background-color: #555555; /*DimGray*/
22 | color: #C0C0C0; /*Silver*/ }
23 | .controls_default:focus { outline: 2px auto #FF0000; /*Red*/ }
24 | .controls_default:hover { background-color: #DAA520; /*GoldenRod*/
25 | color: #000000; /*Black*/ }
26 | .borders_default { box-shadow: 3px 3px 4px #FFFFFF; /*White*/
27 | border: 1px solid #A9A9A9; /*DarkGray*/
28 | border-width: 1px 1px 0px 1px; }
29 | .view_area_default .pref { color: #FFFFFF; /*White*/ }
30 | .body_default a { color: #ffbf80; /*(brown)*/ }
31 | .view_area_default .false { color: #FF6347; /*Tomato*/ }
32 | .view_area_default .true { color: #00FF00; /*Lime*/ }
33 | .view_area_default .integer { color: #FFFF00; /*Yellow*/ }
34 | .view_area_default .string { color: #DDA0DD; /*Plum*/ }
35 | .view_area_default .http { color: #99ccff; /*(blue)*/ }
36 | .view_area_default .warn { background-color: #FF3333; /*(Red)*/
37 | color: #FFFFFF; /*White*/ }
38 | .view_area_default .hid { color: #C6F3C6; /*(Green)*/ }
39 | .view_area_default .ref { color: #98E498; /*(Green)*/ }
40 |
41 |
42 | /* dark theme */
43 | .body_dark, .view_area_dark, .panels_dark
44 | { background-color: #161b22; /*(black)*/
45 | color: #b3b3b3; /*(gray)*/ }
46 | .controls_dark { background-color: #555555; /*DimGray*/
47 | color: #C0C0C0; /*Silver*/ }
48 | .controls_dark:focus { outline: 2px auto #FF0000; /*Red*/ }
49 | .controls_dark:hover { background-color: #DAA520; /*GoldenRod*/
50 | color: #000000; /*Black*/ }
51 | .borders_dark { box-shadow: 3px 3px 4px #FFFFFF; /*White*/
52 | border: 1px solid #A9A9A9; /*DarkGray*/
53 | border-width: 1px 1px 0px 1px; }
54 | .view_area_dark .pref { color: #FFFFFF; /*White*/ }
55 | .body_dark a { color: #ffbf80; /*(brown)*/ }
56 | .view_area_dark .false { color: #FF6347; /*Tomato*/ }
57 | .view_area_dark .true { color: #00FF00; /*Lime*/ }
58 | .view_area_dark .integer { color: #FFFF00; /*Yellow*/ }
59 | .view_area_dark .string { color: #DDA0DD; /*Plum*/ }
60 | .view_area_dark .http { color: #99ccff; /*(blue)*/ }
61 | .view_area_dark .warn { background-color: #FF3333; /*(Red)*/
62 | color: #FFFFFF; /*White*/ }
63 | .view_area_dark .hid { color: #C6F3C6; /*(Green)*/ }
64 | .view_area_dark .ref { color: #98E498; /*(Green)*/ }
65 |
66 |
67 | /* light theme */
68 | .body_light, .view_area_light, .panels_light
69 | { background-color: #FFFFFF; /*White*/
70 | color: #808080; /*Gray*/ }
71 | .controls_light { background-color: #C0C0C0; /*Silver*/
72 | color: #000000; /*Black*/ }
73 | .controls_light:focus { outline: 2px auto #FF0000; /*Red*/ }
74 | .controls_light:hover { background-color: #DAA520; /*GoldenRod*/
75 | color: #000000; /*Black*/ }
76 | .borders_light { box-shadow: 3px 3px 4px #000000; /*Black*/
77 | border: 1px solid #000000; /*Black*/
78 | border-width: 1px 1px 0px 1px; }
79 | .view_area_light .pref { color: #000000; /*Black*/ }
80 | .body_light a { color: #D2691E; /*Chocolate*/ }
81 | .view_area_light .false { color: #FF6347; /*Tomato*/ }
82 | .view_area_light .true { color: #32CD32; /*LimeGreen*/ }
83 | .view_area_light .integer { color: #9932CC; /*DarkOrchid*/ }
84 | .view_area_light .string { color: #DDA0DD; /*Plum*/ }
85 | .view_area_light .http { color: #1982D1; /*(Blue)*/ }
86 | .view_area_light .warn { background-color: #FF3333; /*(Red)*/
87 | color: #FFFFFF; /*White*/ }
88 | .view_area_light .hid { color: #598033; /*(Green)*/ }
89 | .view_area_light .ref { color: #A53C00; /*(Brown)*/ }
90 |
91 |
92 | /* mono theme */
93 | .body_mono, .view_area_mono, .panels_mono
94 | { background-color: #FFFFFF; /*White*/
95 | color: #000000; /*Black*/ }
96 | .controls_mono { background-color: #FFFFFF; /*White*/
97 | color: #000000; /*Black*/ }
98 | .controls_mono:focus { outline: 2px auto #FF0000; /*Red*/ }
99 | .controls_mono:hover { background-color: #000000; /*Black*/
100 | color: #FFFFFF; /*White*/ }
101 | .borders_mono { box-shadow: 3px 3px 4px #000000; /*Black*/
102 | border: 1px solid #000000; /*Black*/
103 | border-width: 1px 1px 0px 1px; }
104 | .view_area_mono .pref { color: #000000; /*Black*/ }
105 | .body_mono a { color: #696969; /*DimGray*/ }
106 | .view_area_mono .false { color: #000000; /*Black*/ }
107 | .view_area_mono .true { color: #000000; /*Black*/ }
108 | .view_area_mono .integer { color: #000000; /*Black*/ }
109 | .view_area_mono .string { color: #000000; /*Black*/ }
110 | .view_area_mono .http { color: #696969; /*DimGray*/ }
111 | .view_area_mono .warn { background-color: #000000; /*Black*/
112 | color: #FFFFFF; /*White*/ }
113 | .view_area_mono .hid { color: #000000; /*Black*/ }
114 | .view_area_mono .ref { color: #000000; /*Black*/ }
115 |
116 |
117 | /* inverse theme */
118 | .body_inverse, .view_area_inverse, .panels_inverse
119 | { background-color: #000000; /*Black*/
120 | color: #FFFFFF; /*White*/ }
121 | .controls_inverse { background-color: #000000; /*Black*/
122 | color: #FFFFFF; /*White*/ }
123 | .controls_inverse:focus { outline: 2px auto #FF0000; /*Red*/ }
124 | .controls_inverse:hover { background-color: #FFFFFF; /*White*/
125 | color: #000000; /*Black*/ }
126 | .borders_inverse { box-shadow: 3px 3px 4px #FFFFFF; /*White*/
127 | border: 1px solid #FFFFFF; /*White*/
128 | border-width: 1px 1px 0px 1px; }
129 | .view_area_inverse .pref { color: #FFFFFF; /*White*/ }
130 | .body_inverse a { color: #D3D3D3; /*LightGray*/ }
131 | .view_area_inverse .false { color: #FFFFFF; /*White*/ }
132 | .view_area_inverse .true { color: #FFFFFF; /*White*/ }
133 | .view_area_inverse .integer { color: #FFFFFF; /*White*/ }
134 | .view_area_inverse .string { color: #FFFFFF; /*White*/ }
135 | .view_area_inverse .http { color: #D3D3D3; /*LightGray*/ }
136 | .view_area_inverse .warn { background-color: #FFFFFF; /*White*/
137 | color: #000000; /*Black*/ }
138 | .view_area_inverse .hid { color: #FFFFFF; /*White*/ }
139 | .view_area_inverse .ref { color: #FFFFFF; /*White*/ }
140 |
141 |
142 | /* arkenfox theme */
143 | .body_arkenfox, .view_area_arkenfox, .panels_arkenfox
144 | { background-color: #161b22;
145 | color: #b3b3b3; }
146 | .controls_arkenfox { background-color: #161b22;
147 | color: #b3b3b3; }
148 | .controls_arkenfox:focus { outline: 2px auto #FF0000; }
149 | .controls_arkenfox:hover { background-color: #dcdc8c;
150 | color: #000000; }
151 | .borders_arkenfox { /*box-shadow: 3px 3px 4px #808080;*/
152 | border: 1px solid #b3b3b3;
153 | border-width: 1px 1px 1px 1px; }
154 | .view_area_arkenfox .pref { color: #ffffff; } /* section header */
155 | .body_arkenfox a { color: #b3b3b3; } /* prefname */
156 | .view_area_arkenfox .false { color: #f07878; }
157 | .view_area_arkenfox .true { color: #78f078; }
158 | .view_area_arkenfox .integer { color: #f0f078; }
159 | .view_area_arkenfox .string { color: #a078f0; }
160 | .view_area_arkenfox .http { color: #78a0f0; } /* a http */
161 | .view_area_arkenfox .warn { background-color: #ff4f4f;
162 | color: #FFFFFF; }
163 | .view_area_arkenfox .hid { color: #b3b3b3; }
164 | .view_area_arkenfox .ref { color: #f0c878; } /* id+desc */
165 |
--------------------------------------------------------------------------------
/js/userjs-tool-af-mode.js:
--------------------------------------------------------------------------------
1 | // Name : userjs-tool-af-mode.js
2 | // Project : https://github.com/icpantsparti2/firefox-user.js-tool
3 | // On-line : https://icpantsparti2.github.io/firefox-user.js-tool/userjs-tool.html
4 | // License (MIT): https://raw.githubusercontent.com/icpantsparti2/firefox-user.js-tool/master/LICENSE
5 | // Version : 2024.06.09
6 |
7 | ////////////////////////////////////////
8 | // userjsTableViewWhenArkenfoxRepoMode
9 | // (used by both userjs-tool.html and arkenfoxGUIStart() calls this)
10 | ////////////////////////////////////////
11 |
12 | function userjsTableViewWhenArkenfoxRepoMode() {
13 |
14 | var theme = document.body.className.replace( /(^| *)[^_]+_/ , '');
15 |
16 | // hide some elements
17 | var e = document.getElementsByClassName("afmode2none");
18 | for (var i = 0, j = e.length; i < j; i++) {
19 | e[i].style.display="none";
20 | }
21 | // reveal some elements
22 | var e = document.getElementsByClassName("afmode2block");
23 | for (var i = 0, j = e.length; i < j; i++) {
24 | e[i].style.display="block";
25 | }
26 | var e = document.getElementsByClassName("afmode2flex");
27 | for (var i = 0, j = e.length; i < j; i++) {
28 | e[i].style.display="flex";
29 | }
30 |
31 | // add another index button (as original is hidden)
32 | document.getElementById("tview_collapse_button").insertAdjacentHTML("beforebegin",
33 | ' ');
38 |
39 | // make index button have same content as original
40 | document.getElementById("tview_index_select").innerHTML =
41 | document.getElementById("index_select").innerHTML;
42 |
43 | document.getElementById("tview_index_select").options[0].innerHTML=
44 | ' ☛ Index'
45 |
46 | // place "About" text into element
47 | if (!!(document.getElementById("about_textarea"))) {
48 | document.getElementById("tview_about_inner_div").innerHTML =
49 | document.getElementById("about_textarea").value;
50 | }
51 | else {
52 | // if no text just put the arkenfox url
53 | document.getElementById("tview_about_inner_div").innerHTML =
54 | 'https://github.com/arkenfox/user.js';
57 | }
58 |
59 | // hide the search option under the filter button
60 | var e = document.getElementById("tview_filter_select_search_option");
61 | e.disabled=true;
62 | e.hidden=true;
63 |
64 | changeClass(document.getElementById("tview_filter_select"),"","afmode_button");
65 |
66 |
67 | // event listeners
68 |
69 | // [Index] button
70 | document.getElementById("tview_index_select").addEventListener("change", function() {
71 | indexSelectAction(this);
72 | });
73 |
74 | // [Search] box
75 | document.getElementById("tview_search_input").addEventListener("keyup", function() {
76 | userjsTableViewTagFilter(null,this.value);
77 | });
78 |
79 | document.getElementById("tview_search_clear_button").style.borderTop = "0px";
80 | document.getElementById("tview_search_clear_button").style.borderRight = "0px";
81 | document.getElementById("tview_search_clear_button").style.borderBottom = "0px";
82 |
83 | // search clear button
84 | document.getElementById("tview_search_clear_button").addEventListener("click", function() {
85 | if (!(document.getElementById("tview_search_input").value=="")) {
86 | userjsTableViewTagFilter(null,"");
87 | }
88 | });
89 |
90 | // [About] button (toggle)
91 | document.getElementById("tview_about_button").addEventListener("click", function() {
92 | if (document.getElementById("tview_about_div").style.display=="block") {
93 | document.getElementById("tview_about_div").style.display="none";
94 | }
95 | else {
96 | document.getElementById("tview_about_div").style.display="block";
97 | }
98 | });
99 |
100 | // top bar opaque and re-size
101 | var e = document.getElementById("tview_buttons_div");
102 | e.style.backgroundColor="#000000";
103 | e.style.border="1px solid #b3b3b3";
104 | e.style.borderWidth="0px 0px 1px 0px";
105 | e.style.top="0";
106 | e.style.width="100%";
107 | e.style.padding="0.9em 0";
108 | e.style.height="4em";
109 | e.style.maxWidth = "1400px";
110 | e.style.margin = "0 auto";
111 | e.style.zIndex = "100";
112 |
113 | // max/min width
114 | document.body.style.maxWidth = "1400px";
115 | document.body.style.margin = "0 auto";
116 | document.body.style.float = "none";
117 | document.getElementById("table_tview").style.minWidth="600px";
118 |
119 | // inactive pref background
120 | var e = document.getElementsByClassName("tr_tview_inactive");
121 | for (var i = 0, j = e.length; i < j; i++) {
122 | e[i].style.backgroundColor="#313131";
123 | }
124 |
125 | // adjust offsets (for preventing content hidden behind top bar)
126 | if (!!(document.getElementById("body_offset"))) {
127 | document.getElementById("body_offset").innerHTML="";
128 | }
129 | document.getElementById("tableview_offset").innerHTML="";
130 | document.getElementById("tableview_div").style.marginTop="7em";
131 | var e = document.getElementsByClassName("anchor");
132 | for (var i = 0, j = e.length; i < j; i++) {
133 | e[i].style.marginTop="-7em";
134 | e[i].style.paddingBottom="7em";
135 | }
136 |
137 | // add some button margins
138 | document.getElementById("tview_index_select").style.marginLeft="2em";
139 | for (const id of [ "tview_index_select", "tview_expand_collapse_button",
140 | "tview_filter_select", "tview_about_button" ] )
141 | {
142 | document.getElementById(id).style.marginRight="1em";
143 | }
144 | for (const id of [ "tview_version_div", "tview_about_button" ] )
145 | {
146 | document.getElementById(id).style.marginLeft="1em";
147 | }
148 |
149 | // disable the prefname about:config search formatted links
150 | var e = document.getElementsByClassName("td_tview_name");
151 | for (var i = 0, j = e.length; i < j; i++) {
152 | var e2 = e[i].getElementsByTagName("a");
153 | for (var i2 = 0, j2 = e2.length; i2 < j2; i2++) {
154 | e2[i2].removeAttribute("href");
155 | }
156 | }
157 |
158 | } /* end function userjsTableViewWhenArkenfoxRepoMode */
159 |
160 |
161 | ///////////////////////////////////////
162 | // userjstoolWhenArkenfoxRepoMode
163 | // (used by userjs-tool.html)
164 | ///////////////////////////////////////
165 |
166 | function userjstoolWhenArkenfoxRepoMode() {
167 | if (getURLVariable("afmode")=="off") {
168 | arkenfoxRepoMode="";
169 | }
170 | else if (getURLVariable("afmode")=="demo"
171 | || getURLVariable("afmode")=="test"
172 | ) {
173 | arkenfoxRepoMode=getURLVariable("afmode");
174 | }
175 | else if (
176 | /^https:\/\/arkenfox\.github\.io\//.test(location)
177 | || (getURLVariable("afmode")=="on")
178 | ) {
179 | arkenfoxRepoMode="on";
180 | }
181 | } /* end function userjstoolWhenArkenfoxRepoMode */
182 |
183 |
184 | ////////////////////////////////////////////////
185 | // arkenfoxGUIStart
186 | // (used by arkenfox-gui.html)
187 | // (aka index.html on arkenfox gui repo)
188 | ////////////////////////////////////////////////
189 |
190 | function arkenfoxGUIStart(text_box="") {
191 |
192 | var txtbx = document.getElementById(text_box);
193 |
194 | document.body.style.fontSize = "70%";
195 |
196 | // must have these ids or it breaks
197 | txtbx.insertAdjacentHTML("afterend",
198 | ''
199 | +'');
200 |
201 | var timeout = 0;
202 |
203 | if ( (txtbx.value=="")
204 | || (/^\?(a|b)($|&)/.test(location.search))
205 | || (/^(\?|.*&)v=[^&]+($|&)/.test(location.search))
206 | ) {
207 | // fetch file from main repo instead
208 | txtbx.value="";
209 | var url="https://raw.githubusercontent.com/arkenfox/user.js/master/user.js";
210 | if (/^(\?|.*&)v=[^&]+($|&)/.test(location.search)) {
211 | // eg "?v=115.1", then in url replace "/master/" with "/115.1/"
212 | // https://github.com/arkenfox/user.js/tags
213 | // eg https://github.com/arkenfox/user.js/tree/115.1
214 | url=url.replace(/\/master\//,`/${
215 | location.search.replace(/^(\?|.*&)v=([^&]+)($|&.*$)/,"$2")}/`);
216 | }
217 | var msg = "\nTroubleshooting: Check connection?"
218 | + " Blocked by an extension (eg uMatrix XHR)?"
219 | + " Site allows fetch? Valid URL/file?\n"
220 | + url;
221 | fetch(url)
222 | .then(function(response) {
223 | if (response.ok) {
224 | return response.text()
225 | }
226 | else {
227 | throw Error(response.status);
228 | }
229 | })
230 | .then(function(text) {
231 | txtbx.value = text;
232 | })
233 | .catch(function(err) {
234 | alert("File fetch error:\n" + err.message + msg);
235 | });
236 | timeout = 1000;
237 | }
238 |
239 | setTimeout(function(){
240 | userjsTableView(text_box,getURLVariable("t"),getURLVariable("s"));
241 | userjsTableViewWhenArkenfoxRepoMode();
242 | }, timeout);
243 |
244 | // provide the user.js from main as base64
245 | if (/^\?(b)($|&)/.test(location.search)) {
246 | setTimeout(function(){
247 | document.getElementById("tableview_div").insertAdjacentHTML("afterbegin",
248 | '');
253 | }, 1000);
254 | }
255 |
256 | // list the urls in the hardcoded user.js
257 | if (/^\?(u)($|&)/.test(location.search)) {
258 | setTimeout(function(){
259 | // https://javascript.tutorialink.com/extract-urls-from-paragraph-or-block-of-text-using-a-regular-expression/
260 | var urlRegex = /((mailto:|ftp:\/\/|https?:\/\/)\S+?)[^\s]+/ig;
261 | document.getElementById("tableview_div").insertAdjacentHTML("afterbegin",
262 | '');
266 | }, 500);
267 | }
268 |
269 | }
270 |
--------------------------------------------------------------------------------
/js/userjs-tool-file-loading.js:
--------------------------------------------------------------------------------
1 | // Name : userjs-tool-file-loading.js
2 | // Project : https://github.com/icpantsparti2/firefox-user.js-tool
3 | // On-line : https://icpantsparti2.github.io/firefox-user.js-tool/userjs-tool.html
4 | // License (MIT): https://raw.githubusercontent.com/icpantsparti2/firefox-user.js-tool/master/LICENSE
5 | // Version : 2022.04.06
6 |
7 | // *************************************
8 | // downloadFile
9 | // *************************************
10 |
11 | // based on code from:
12 | // https://stackoverflow.com/questions/196498/how-do-i-load-the-contents-of-a-text-file-into-a-javascript-variable
13 | // https://stackoverflow.com/questions/6348207/making-a-paragraph-in-html-contain-a-text-from-a-file
14 | // https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data
15 | // https://cameronnokes.com/blog/4-common-mistakes-front-end-developers-make-when-using-fetch/
16 |
17 | // browser security policies prevent same origin local file:// loading
18 |
19 | function downloadFile(url, text_box){
20 | var e = document.getElementById(text_box);
21 | var msg = "\nTroubleshooting: Check connection?"
22 | + " Blocked by an extension (eg uMatrix XHR)?"
23 | + " Site allows fetch? Valid URL/file?"
24 | + " Visit the URL and copy/paste the content instead?\n"
25 | + url;
26 | clearTextAreaContents(text_box);
27 | toggleTextAreaReadOnly(text_box, true, false);
28 | fetch(url)
29 | .then(function(response) {
30 | if (response.ok) {
31 | return response.text()
32 | }
33 | else {
34 | throw Error(response.status);
35 | }
36 | })
37 | .then(function(text) {
38 | e.value = text;
39 | })
40 | .catch(function(err) {
41 | if (location.protocol == "file:") {
42 | console.error('// local (file:) fetch failed - firefox flip "security.fileuri.strict_origin_policy" (and change it back afterwards)');
43 | }
44 | alert("File fetch error:\n" + err.message + msg);
45 | });
46 | } // end function downloadFile
47 |
48 | // *************************************
49 | // loadButtonAction
50 | // *************************************
51 |
52 | function loadButtonAction(select, input, text_box, filenameforsave){
53 | var url = select.value;
54 | select.selectedIndex = 0;
55 | if (url == "LOCAL") {
56 | // trigger the (hidden) local file load selector (does not work for Fennec)
57 | if (
58 | document.getElementById("collect_button").style.textDecoration == "line-through"
59 | && (text_box == "box_1_template" || text_box == "box_2_overrides")
60 | ) {
61 | return;
62 | }
63 | document.getElementById(input).click();
64 | }
65 | else if (url == "BUTTON") {
66 | // show the Browse button (Fennec workaround)
67 | for (const id of [ "template", "overrides", "userjs", "other" ])
68 | {
69 | if (document.getElementById("load_" + id + "_input").style.display === "block") {
70 | document.getElementById("load_" + id + "_input").style.display = "none";
71 | document.getElementById("loadsave_" + id + "_select").options[2].textContent =
72 | document.getElementById("loadsave_" + id + "_select").options[2].textContent
73 | .replace(/\u{25A3}/u, "\u25A2");
74 | }
75 | else {
76 | document.getElementById("load_" + id + "_input").style.display = "block";
77 | document.getElementById("loadsave_" + id + "_select").options[2].textContent =
78 | document.getElementById("loadsave_" + id + "_select").options[2].textContent
79 | .replace(/\u{25A2}/u, "\u25A3");
80 | }
81 | }
82 | }
83 | else if (url == "SAVE") {
84 | download(document.getElementById(text_box).value,
85 | filenameforsave, "application/javascript");
86 | }
87 | else if (/^.+$/.test(url)) {
88 | if (
89 | document.getElementById("collect_button").style.textDecoration == "line-through"
90 | && (text_box == "box_1_template" || text_box == "box_2_overrides")
91 | ) {
92 | return;
93 | }
94 | if (url == "URL") {
95 | url = "";
96 | url = prompt("Please input URL of file to load\n"
97 | + "(Only works if the site allows this)\n"
98 | + "(eg arkenfox /master/ /vNN/ or /vNN.0-beta/ /NN.0/)",
99 | "https://raw.githubusercontent.com/arkenfox/user.js/master/user.js");
100 | }
101 | if (url != null && url != "") {
102 | downloadFile(url, text_box);
103 | setTimeout(function(){
104 | toggleTextAreaReadOnly(text_box, true);
105 | e.selectionStart = 0;
106 | e.selectionEnd = 0;
107 | e.focus();
108 | }, 1000);
109 | }
110 | }
111 | } // end function loadButtonAction
112 |
113 | // *************************************
114 | // loadLocalFile / drag and drop
115 | // *************************************
116 |
117 | // based on code from:
118 | // https://www.html5rocks.com/en/tutorials/file/dndfiles/
119 | // https://stackoverflow.com/questions/16215771/how-open-select-file-dialog-via-js/16215950
120 | // https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/File_drag_and_drop
121 | function loadLocalFile(ev, text_box){
122 | // get files from Browse selection or drag and drop
123 | var files = [];
124 | if (typeof ev == 'string') {
125 | var files = document.getElementById(ev).files;
126 | }
127 | else {
128 | // dropHandler(ev)
129 | // Prevent default behavior (Prevent file from being opened)
130 | ev.preventDefault();
131 | if (ev.dataTransfer.items) {
132 | // Use DataTransferItemList interface to access the file(s)
133 | for (var i = 0; i < ev.dataTransfer.items.length; i++) {
134 | // If dropped items aren't files, reject them
135 | if (ev.dataTransfer.items[i].kind === 'file') {
136 | files.push(ev.dataTransfer.items[i].getAsFile());
137 | }
138 | }
139 | } else {
140 | // Use DataTransfer interface to access the file(s)
141 | for (var i = 0; i < ev.dataTransfer.files.length; i++) {
142 | files.push(ev.dataTransfer.files[i]);
143 | }
144 | }
145 | }
146 |
147 | // determine which box to load the selected files
148 |
149 | var fe, ft, fo, fu, fx; // filename for each box (fe is current box)
150 |
151 | if (!files.length) {
152 | // no files selected
153 | return;
154 | }
155 | else if (files.length > 4) {
156 | alert("Too many files selected. (" + files.length + " > maximum 4)");
157 | return;
158 | }
159 | else if (files.length == 1) {
160 | // one file selected (load into current box)
161 | fe=files[0];
162 | }
163 | else {
164 | // multiple files selected (load into corresponding boxes)
165 | // loop through the file list
166 | var matched = "", noMatch = "";
167 | for (var i=0, f; f=files[i]; i++) {
168 | if ( (/^user\.js.*$/.test(f.name)) && (!fu) ) {
169 | if (!fu) { fu=f; } else { noMatch += "\n?: " + f.name; }
170 | }
171 | else if ( (/^user-overrides.*\.js$/.test(f.name)) && (!fo) ) {
172 | if (!fo) { fo=f; } else { noMatch += "\n?: " + f.name; }
173 | }
174 | else if ( (/user-template.*\.js$/.test(f.name)) && (!ft) ) {
175 | if (!ft) { ft=f; } else { noMatch += "\n?: " + f.name; }
176 | }
177 | else if ( (/^.*\.js$/.test(f.name)) && (!fx) ) {
178 | if (!fx) { fx=f; } else { noMatch += "\n?: " + f.name; }
179 | }
180 | else {
181 | noMatch += "\n?: " + f.name;
182 | }
183 | }
184 | matched = "\n1: "
185 | if (ft) { matched += ft.name ; }
186 | matched += "\n2: "
187 | if (fo) { matched += fo.name ; }
188 | matched += "\n3: "
189 | if (fu) { matched += fu.name ; }
190 | matched += "\n4: "
191 | if (fx) { matched += fx.name ; }
192 | if (noMatch) {
193 | noMatch = "\n\nNot matched to a box:" + noMatch;
194 | }
195 | if (!confirm("Load into boxes?" + matched + noMatch)) {
196 | return;
197 | }
198 | }
199 |
200 | // separate reads and variables (to avoid delayed loads into wrong box)
201 |
202 | if (fe) {
203 | var e = document.getElementById(text_box);
204 | var reader_e = new FileReader();
205 | // If we use onloadend, we need to check the readyState.
206 | reader_e.onloadend = function(evt) {
207 | if (evt.target.readyState == FileReader.DONE) { // DONE == 2
208 | // if (typeof evt.target.result == 'string') {
209 | e.value = evt.target.result;
210 | // }
211 | // else {
212 | // let utf8decoder = new TextDecoder('utf-8');
213 | // e.value = utf8decoder.decode(decomp(evt.target.result));
214 | // }
215 | // e.select();
216 | toggleTextAreaReadOnly(text_box, true);
217 | e.selectionStart = 0;
218 | e.selectionEnd = 0;
219 | e.focus();
220 | }
221 | };
222 | reader_e.readAsText(fe);
223 | // reader_e.readAsArrayBuffer(fe);
224 | // reader_e.readAsBinaryString(fe);
225 | }
226 |
227 | if (ft) {
228 | var t = document.getElementById("box_1_template");
229 | var reader_t = new FileReader();
230 | // If we use onloadend, we need to check the readyState.
231 | reader_t.onloadend = function(evt) {
232 | if (evt.target.readyState == FileReader.DONE) { // DONE == 2
233 | t.value = evt.target.result;
234 | toggleTextAreaReadOnly("box_1_template", true);
235 | // t.select();
236 | t.selectionStart = 0;
237 | t.selectionEnd = 0;
238 | t.focus();
239 | }
240 | };
241 | reader_t.readAsText(ft);
242 | }
243 |
244 | if (fo) {
245 | var o = document.getElementById("box_2_overrides");
246 | var reader_o = new FileReader();
247 | // If we use onloadend, we need to check the readyState.
248 | reader_o.onloadend = function(evt) {
249 | if (evt.target.readyState == FileReader.DONE) { // DONE == 2
250 | o.value = evt.target.result;
251 | toggleTextAreaReadOnly("box_2_overrides", true);
252 | // o.select();
253 | o.selectionStart = 0;
254 | o.selectionEnd = 0;
255 | o.focus();
256 | }
257 | };
258 | reader_o.readAsText(fo);
259 | }
260 |
261 | if (fu) {
262 | var u = document.getElementById("box_3_userjs");
263 | var reader_u = new FileReader();
264 | // If we use onloadend, we need to check the readyState.
265 | reader_u.onloadend = function(evt) {
266 | if (evt.target.readyState == FileReader.DONE) { // DONE == 2
267 | u.value = evt.target.result;
268 | toggleTextAreaReadOnly("box_3_userjs", true);
269 | // u.select();
270 | u.selectionStart = 0;
271 | u.selectionEnd = 0;
272 | u.focus();
273 | }
274 | };
275 | reader_u.readAsText(fu);
276 | }
277 |
278 | if (fx) {
279 | var x = document.getElementById("box_4_other");
280 | var reader_x = new FileReader();
281 | // If we use onloadend, we need to check the readyState.
282 | reader_x.onloadend = function(evt) {
283 | if (evt.target.readyState == FileReader.DONE) { // DONE == 2
284 | x.value = evt.target.result;
285 | toggleTextAreaReadOnly("box_4_other", true);
286 | // t.select();
287 | x.selectionStart = 0;
288 | x.selectionEnd = 0;
289 | x.focus();
290 | }
291 | };
292 | reader_x.readAsText(fx);
293 | }
294 |
295 | } // end function loadLocalFile
296 |
297 | function dragOverHandler(ev) {
298 | // Prevent default behavior (Prevent file from being opened)
299 | ev.preventDefault();
300 | }
301 |
302 | function dropHandler1(ev) {
303 | if (
304 | document.getElementById("collect_button").style.textDecoration != "line-through"
305 | ) {
306 | loadLocalFile(ev, "box_1_template");
307 | }
308 | }
309 |
310 | function dropHandler2(ev) {
311 | if (
312 | document.getElementById("collect_button").style.textDecoration != "line-through"
313 | ) {
314 | loadLocalFile(ev, "box_2_overrides");
315 | }
316 | }
317 |
318 | function dropHandler3(ev) { loadLocalFile(ev, "box_3_userjs"); }
319 |
320 | function dropHandler4(ev) { loadLocalFile(ev, "box_4_other"); }
321 |
--------------------------------------------------------------------------------
/js/userjs-tool-userjs-viewer.js:
--------------------------------------------------------------------------------
1 | // Name : userjs-tool-userjs-viewer.js
2 | // Project : https://github.com/icpantsparti2/firefox-user.js-tool
3 | // On-line : https://icpantsparti2.github.io/firefox-user.js-tool/userjs-tool.html
4 | // License (MIT): https://raw.githubusercontent.com/icpantsparti2/firefox-user.js-tool/master/LICENSE
5 | // Version : 2022.04.06
6 |
7 | // *************************************
8 | // userjsViewer
9 | // *************************************
10 |
11 | /* build and display userjs as HTML */
12 |
13 | function userjsViewer(text_box_name, convert_code_comments) {
14 |
15 | // update date of hidden heading (H1/H3/DL tags for bookmarks import compatibility)
16 | updateDateTimeStampVariable();
17 |
18 | document.getElementById("hiddendate").innerHTML =
19 | document.getElementById("hiddendate").innerHTML
20 | .replace(/(--userjs_)[0-9_]+/, "$1" + date_time_stamp);
21 |
22 | // get content and clear input and page
23 | document.getElementById("view_area").innerHTML = "";
24 | var content;
25 |
26 | // if View+ style is selected in the menu
27 | if (typeof convert_code_comments !== "boolean") {
28 | convert_code_comments = toggleViewPlusOnView("status");
29 | }
30 |
31 | // convert in-block comments to in-line
32 | // (improves inactive pref recognition)
33 | if (convert_code_comments) {
34 | content =
35 | amendCodeComments(document.getElementById(text_box_name).value, true)
36 | .replace(/(\r\n|\r)/g,'\n').split("\n");
37 | }
38 | else {
39 | content = document.getElementById(text_box_name).value
40 | .replace(/(\r\n|\r)/g,'\n').split("\n");
41 | }
42 |
43 | var theme = document.body.className.replace( /(^| *)[^_]+_/ , '');
44 |
45 | // variables for holding HTML that we build from the content
46 | var index_select_html = ''
47 | + ' \n';
48 | var groups_container_html = '';
49 | var content_html = '';
50 |
51 | var section_heading = '(TOP) / Introduction';
52 | // if there is only 1 section we will not collapse the viewer
53 | var section_count = 1;
54 | var userjs_type = "";
55 | var group_user_pref_list = '';
56 | var previousLineWasBlank = true, currentLineWasBlank;
57 |
58 | // some common HTML used for each section_heading
59 |
60 | function appendSectionStartHtml() {
61 | index_select_html += ' \n';
62 | groups_container_html += '