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 |
--------------------------------------------------------------------------------
/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-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 |
--------------------------------------------------------------------------------
/js/userjs-tool-userjs-table-view.js:
--------------------------------------------------------------------------------
1 | // Name : userjs-tool-userjs-table-view.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.09.11 (minor tweaks of v2022.04.09)
6 |
7 | // TODO: code improvements:
8 | // TODO: https://github.com/arkenfox/gui/issues/2#issuecomment-1159625494
9 | // TODO: https://github.com/arkenfox/gui/issues/2#issuecomment-1159626088
10 |
11 | // *************************************
12 | // various functions for userjsTableView
13 | // *************************************
14 |
15 | function userjsTableViewExpandAll() {
16 | var e = document.getElementsByClassName("det");
17 | for (var i = 0, j = e.length; i < j; i++) {
18 | e[i].open = true;
19 | }
20 | }
21 |
22 | function userjsTableViewExpandPrefDesc() {
23 | userjsTableViewCollapseSectionDesc();
24 | var e = document.getElementsByClassName("prefDet");
25 | for (var i = 0, j = e.length; i < j; i++) {
26 | e[i].open = true;
27 | }
28 | }
29 |
30 | function userjsTableViewCollapseSectionDesc() {
31 | var e = document.getElementsByClassName("secDet");
32 | for (var i = 0, j = e.length; i < j; i++) {
33 | e[i].open = false;
34 | }
35 | }
36 |
37 | function userjsTableViewCollapseAll() {
38 | var e = document.getElementsByClassName("det");
39 | for (var i = 0, j = e.length; i < j; i++) {
40 | e[i].open = false;
41 | }
42 | }
43 |
44 | function userjsTableViewExpandCollapseAll() {
45 | var b = document.getElementById("tview_expand_collapse_button");
46 | userjsTableViewCollapseAll();
47 | if (/Expand/.test(b.innerHTML)) {
48 | userjsTableViewExpandPrefDesc();
49 | b.innerHTML='- Collapse';
50 | }
51 | else {
52 | b.innerHTML='+ Expand';
53 | }
54 | }
55 |
56 | ////////////////////////////////////////////////////////
57 | // userjsTableViewUpdateURLBar
58 | ////////////////////////////////////////////////////////
59 |
60 | function userjsTableViewUpdateURLBar(textToAdd="",filterType="") {
61 | if (filterType=="t") {
62 | // tags are already URI encoded
63 | textToAdd=textToAdd.replace(/^TAGS_/,"");
64 | textToAdd="t="+textToAdd;
65 | }
66 | else if (filterType=="s") {
67 | textToAdd=encodeURIComponent(textToAdd);
68 | textToAdd="s="+textToAdd;
69 | }
70 | else if (textToAdd) {
71 | textToAdd=encodeURIComponent(textToAdd);
72 | }
73 |
74 | if (getURLVariable("afmode")) {
75 | if (textToAdd) {
76 | textToAdd=textToAdd.replace(/^/,"afmode="+(getURLVariable("afmode"))+"\&");
77 | }
78 | else {
79 | textToAdd="afmode="+(getURLVariable("afmode"));
80 | }
81 | }
82 | // location.protocol + "//" + location.pathname + textToAdd;
83 | // https://stackoverflow.com/questions/824349/how-do-i-modify-the-url-without-reloading-the-page
84 | // location.search += textToAdd;
85 | window.history.replaceState(null, document.title,"?"+textToAdd);
86 | }
87 |
88 | ////////////////////////////////////////////////////////
89 | // userjsTableViewTagFilter
90 | ////////////////////////////////////////////////////////
91 |
92 | function userjsTableViewTagFilter(filter_tag=null,filter_search=null) {
93 | var s = document.getElementById("tview_filter_select");
94 | var svalue = s.value;
95 | s.selectedIndex = 0;
96 | var hideheadingsoption = 2;
97 | var hideinactiveoption = 3;
98 | var hideactiveoption = 4;
99 | var invertoption = 5;
100 | var searchoption = 6;
101 | var firstfilteronoption = 6;
102 | var search_item_count = 0, search_line_count = 0;
103 | var e = document.getElementById("table_tview").querySelectorAll("tr");
104 | var group_user_pref_list_filter = "";
105 |
106 | // get menu status
107 | var hideinactive =
108 | /\u{25A3}/u.test(s.options[hideinactiveoption].textContent) ? true : false;
109 | var hideactive =
110 | /\u{25A3}/u.test(s.options[hideactiveoption].textContent) ? true : false;
111 | var hideheadings =
112 | /\u{25A3}/u.test(s.options[hideheadingsoption].textContent) ? true : false;
113 | var invert =
114 | /\u{25A3}/u.test(s.options[invertoption].textContent) ? true : false;
115 | var search_regexp =
116 | s.options[searchoption].textContent.replace(/^.*\u{00A0}/u, "");
117 | var filteron = "";
118 | for (var si = firstfilteronoption, sj = s.options.length; si < sj; si++) {
119 | if (/\u{25A3}/u.test(s.options[si].textContent)) {
120 | filteron = s.options[si].value;
121 | }
122 | }
123 |
124 | if ( (filter_tag) && (filter_search) ) {
125 | // cannot do both
126 | alert("cannot filter for a tag and search text");
127 | return;
128 | }
129 | else if (filter_tag) {
130 | svalue = "TAGS_" + encodeURIComponent(filter_tag);
131 | filteron = svalue;
132 | hideheadings = true;
133 | userjsTableViewUpdateURLBar(svalue,"t");
134 | }
135 | else if ((filter_search) && !(filter_search=="")) {
136 | svalue = "SEARCH";
137 | search_regexp = filter_search;
138 | filteron = svalue;
139 | hideheadings = true;
140 | userjsTableViewUpdateURLBar(search_regexp,"s");
141 | }
142 | else if ((svalue == "SHOWALL") || (filter_search=="")) {
143 | svalue = "SHOWALL";
144 | hideinactive = false;
145 | hideactive = false;
146 | hideheadings = false;
147 | invert = false;
148 | filteron = "";
149 | userjsTableViewUpdateURLBar("");
150 | document.getElementById("tview_search_input").value="";
151 | }
152 | else if (svalue == "HIDEHEADINGS") {
153 | svalue = "";
154 | hideheadings = !hideheadings;
155 | }
156 | else if (svalue == "HIDEINACTIVE") {
157 | svalue = "";
158 | hideinactive = !hideinactive;
159 | hideactive = false;
160 | }
161 | else if (svalue == "HIDEACTIVE") {
162 | svalue = "";
163 | hideactive = !hideactive;
164 | hideinactive = false;
165 | }
166 | else if (svalue == "INVERT") {
167 | svalue = "";
168 | invert = !invert;
169 | }
170 | else if (svalue == "SEARCH") {
171 | var new_regexp = prompt("\u{1f50d} Enter text to find (RegExp syntax)\n"
172 | + " eg clear \\.clear letter.*box|inner \\b(netflix|eme|gmp|cdm|drm)\\b"
173 | , search_regexp);
174 | if (new_regexp == null) {
175 | // prompt cancel button was clicked
176 | svalue = "";
177 | }
178 | else if (new_regexp=="") {
179 | svalue = "SHOWALL";
180 | hideinactive = false;
181 | hideactive = false;
182 | hideheadings = false;
183 | invert = false;
184 | filteron = "";
185 | userjsTableViewUpdateURLBar("");
186 | document.getElementById("tview_search_input").value="";
187 | }
188 | else {
189 | search_regexp = new_regexp;
190 | filteron = svalue;
191 | hideheadings = true;
192 | userjsTableViewUpdateURLBar(search_regexp,"s");
193 | document.getElementById("tview_search_input").value=new_regexp;
194 | }
195 | }
196 | else if (svalue == filteron) {
197 | svalue = "SHOWALL";
198 | filteron = "";
199 | hideheadings = false;
200 | userjsTableViewUpdateURLBar("");
201 | }
202 | else {
203 | filteron = svalue;
204 | hideheadings = true;
205 | userjsTableViewUpdateURLBar(svalue,"t");
206 | }
207 |
208 | // loop through all tr and apply/re-apply filter
209 | for (var i = 1, j = e.length; i < j; i++) {
210 | e[i].style.display =
211 | (svalue == "SHOWALL" || filteron == "SEARCH"
212 | || new RegExp(filteron + " ").test(e[i].className))
213 | ? null : "none";
214 | }
215 | // if search
216 | if (filteron == "SEARCH") {
217 | for (var i = 1, j = e.length; i < j; i++) {
218 | if (new RegExp(search_regexp,"ig").test(e[i].textContent)) {
219 | e[i].style.display = null;
220 | if (!(/HEADING /.test(e[i].className))) {
221 | // count matches
222 | search_line_count++;
223 | search_item_count+=((e[i].textContent || '')
224 | .match(new RegExp(search_regexp,"ig")) || []).length;
225 | }
226 | }
227 | else {
228 | e[i].style.display = "none"
229 | }
230 | }
231 | }
232 | // if invert
233 | if (invert) {
234 | for (var i = 1, j = e.length; i < j; i++) {
235 | e[i].style.display = (e[i].style.display == "none") ? null : "none";
236 | }
237 | }
238 | // if hide inactive
239 | if (hideinactive) {
240 | for (var i = 1, j = e.length; i < j; i++) {
241 | if (/TAGS_Inactive /.test(e[i].className)) {
242 | e[i].style.display = "none";
243 | }
244 | }
245 | }
246 | // if hide active
247 | if (hideactive) {
248 | for (var i = 1, j = e.length; i < j; i++) {
249 | if (/TAGS_Active /.test(e[i].className)) {
250 | e[i].style.display = "none";
251 | }
252 | }
253 | }
254 | // hide/unhide headings
255 | for (var i = 1, j = e.length; i < j; i++) {
256 | if (/HEADING /.test(e[i].className)) {
257 | e[i].style.display = hideheadings ? "none" : null;
258 | }
259 | }
260 |
261 | // mark the filter options on/off on the filter select/button
262 | s.options[hideinactiveoption].textContent = hideinactive
263 | ? s.options[hideinactiveoption].textContent.replace(/\u{25A2}/u, "\u25A3")
264 | : s.options[hideinactiveoption].textContent.replace(/\u{25A3}/u, "\u25A2");
265 | s.options[hideactiveoption].textContent = hideactive
266 | ? s.options[hideactiveoption].textContent.replace(/\u{25A2}/u, "\u25A3")
267 | : s.options[hideactiveoption].textContent.replace(/\u{25A3}/u, "\u25A2");
268 | s.options[hideheadingsoption].textContent = hideheadings
269 | ? s.options[hideheadingsoption].textContent.replace(/\u{25A2}/u, "\u25A3")
270 | : s.options[hideheadingsoption].textContent.replace(/\u{25A3}/u, "\u25A2");
271 | s.options[invertoption].textContent = invert
272 | ? s.options[invertoption].textContent.replace(/\u{25A2}/u, "\u25A3")
273 | : s.options[invertoption].textContent.replace(/\u{25A3}/u, "\u25A2");
274 | // search option - show count and the searched text
275 | s.options[searchoption].textContent =
276 | s.options[searchoption].textContent
277 | .replace(/^(.*\()[0-9;]*(\)\u{00A0}).*$/u, "$1"
278 | + search_line_count + ";" + search_item_count + "$2" + search_regexp);
279 | // mark the filter used and unmark others (except hide/invert)
280 | for (var si = firstfilteronoption, sj = s.options.length; si < sj; si++) {
281 | s.options[si].textContent = (s.options[si].value == filteron)
282 | ? s.options[si].textContent.replace(/\u{25A2}/u, "\u25A3")
283 | : s.options[si].textContent.replace(/\u{25A3}/u, "\u25A2");
284 | }
285 | // filter button (indicates if any filter is used)
286 | s.options[0].textContent =
287 | (hideinactive || hideactive || hideheadings || invert || filteron)
288 | ? s.options[0].textContent.replace(/\u{25A2}/u, "\u25A3")
289 | : s.options[0].textContent.replace(/\u{25A3}/u, "\u25A2");
290 |
291 | // for testing, get the Filter select options and counts in an alert
292 | // alert(s.textContent.replace(/[\u{25A2}\u{25A3}]/ug, "\n$0"));
293 |
294 | // update group_link_showing_table_filter (inside groups_container div)
295 | var prefnametd;
296 | for (var i = 1, j = e.length; i < j; i++) {
297 | if (!(e[i].style.display == "none")) {
298 | // get prefname from table text (where e[i] is the tr)
299 | prefnametd = e[i].getElementsByClassName("td_tview_name");
300 | if (prefnametd.length > 0) {
301 | if (prefnametd[0].textContent) {
302 | group_user_pref_list_filter +=
303 | prefnametd[0].textContent.replace(/([*.+])/g, "\\$1") + "|";
304 | }
305 | }
306 | }
307 | }
308 | if(!!(document.getElementById("group_link_showing_table_filter"))) {
309 | document.getElementById("group_link_showing_table_filter").href =
310 | 'about:config?filter=/^\\*$|^('
311 | + group_user_pref_list_filter.replace(/\|$/, '')
312 | + ')(;|$)|^$/i';
313 | }
314 | s.blur();
315 |
316 | } /* end function userjsTableViewTagFilter */
317 |
318 | ////////////////////////////////////////////////////////
319 | // userjsTableView
320 | ////////////////////////////////////////////////////////
321 |
322 | function userjsTableView(input_box_name,filter_tag="",filter_search="") {
323 |
324 | var input_box = document.getElementById(input_box_name);
325 |
326 | var theme = document.body.className.replace( /(^| *)[^_]+_/ , '');
327 |
328 | // tags (shown under filter button in this order)
329 | // these are used on the table row eg: