bitwrench 1.2.16 → 2.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/README.md +160 -158
  2. package/bin/bitwrench.js +3 -0
  3. package/dist/bitwrench-code-edit.cjs.js +639 -0
  4. package/dist/bitwrench-code-edit.es5.js +875 -0
  5. package/dist/bitwrench-code-edit.es5.min.js +15 -0
  6. package/dist/bitwrench-code-edit.esm.js +628 -0
  7. package/dist/bitwrench-code-edit.esm.min.js +15 -0
  8. package/dist/bitwrench-code-edit.umd.js +645 -0
  9. package/dist/bitwrench-code-edit.umd.min.js +15 -0
  10. package/dist/bitwrench.cjs.js +6983 -0
  11. package/dist/bitwrench.cjs.min.js +62 -0
  12. package/dist/bitwrench.css +5100 -0
  13. package/dist/bitwrench.es5.js +8446 -0
  14. package/dist/bitwrench.es5.min.js +31 -0
  15. package/dist/bitwrench.esm.js +6981 -0
  16. package/dist/bitwrench.esm.min.js +62 -0
  17. package/dist/bitwrench.umd.js +6989 -0
  18. package/dist/bitwrench.umd.min.js +62 -0
  19. package/dist/builds.json +127 -0
  20. package/dist/sri.json +18 -0
  21. package/package.json +86 -24
  22. package/readme.html +288 -0
  23. package/src/bitwrench-code-edit.js +627 -0
  24. package/src/bitwrench-color-utils.js +311 -0
  25. package/src/bitwrench-component-base.js +736 -0
  26. package/src/bitwrench-components-inline.js +374 -0
  27. package/src/bitwrench-components-v2.js +1879 -0
  28. package/src/bitwrench-components.js +610 -0
  29. package/src/bitwrench-styles.js +3240 -0
  30. package/src/bitwrench.js +3367 -0
  31. package/src/cli/convert.js +205 -0
  32. package/src/cli/index.js +122 -0
  33. package/src/cli/inject.js +55 -0
  34. package/src/cli/layout-default.js +142 -0
  35. package/src/generate-css.js +381 -0
  36. package/src/vendor/quikdown.js +654 -0
  37. package/src/version.js +16 -0
  38. package/.eslintrc.json +0 -27
  39. package/.github/workflows/codeql-analysis.yml +0 -72
  40. package/.travis.yml +0 -34
  41. package/bitwrench.css +0 -92
  42. package/bitwrench.js +0 -3348
  43. package/bitwrench.js_sri.txt +0 -1
  44. package/bitwrench.min.js +0 -1
  45. package/bitwrench.min.js_sri.txt +0 -1
  46. package/bitwrench_ESM.js +0 -3207
  47. package/bitwrench_ESM.js_sri.txt +0 -1
  48. package/bitwrench_ESM.min.js +0 -1
  49. package/bitwrench_ESM.min.js_sri.txt +0 -1
  50. package/dev/bitwrench-todo.md +0 -215
  51. package/dev/css-arrows.md +0 -23
  52. package/dev/docStringDev.js +0 -124
  53. package/dev/docStringParseDev.js +0 -171
  54. package/dev/example11-load-mjs-page.html +0 -17
  55. package/dev/figures.html +0 -37
  56. package/dev/html_gen.js +0 -349
  57. package/dev/htmld.md +0 -250
  58. package/dev/htmldev.html +0 -45
  59. package/dev/index-old.html +0 -87
  60. package/dev/misc-notes.md +0 -21
  61. package/dev/norm.css +0 -30
  62. package/dev/notes.md +0 -2
  63. package/dev/pageData.mjs +0 -69
  64. package/dev/sizes.html +0 -49
  65. package/dev/universal-js-module.js +0 -37
  66. package/examples/example1.html +0 -78
  67. package/examples/example10.html +0 -84
  68. package/examples/example11.html +0 -17
  69. package/examples/example12.html +0 -18
  70. package/examples/example2.html +0 -44
  71. package/examples/example3.html +0 -50
  72. package/examples/example4.html +0 -22
  73. package/examples/example5.html +0 -82
  74. package/examples/example6.html +0 -128
  75. package/examples/example7.html +0 -91
  76. package/examples/example8.html +0 -27
  77. package/examples/example9.html +0 -102
  78. package/examples/examplePageData12.mjs +0 -73
  79. package/examples/pageData.mjs +0 -69
  80. package/examples/pico.min.css +0 -5
  81. package/icon/bitwrench-dark-tall.png +0 -0
  82. package/icon/bitwrench-dark.png +0 -0
  83. package/icon/bitwrench-icon-lt-grey.png +0 -0
  84. package/icon/bitwrench-icon.vsd +0 -0
  85. package/icon/bitwrench-logo-dark.png +0 -0
  86. package/icon/bitwrench-logo-full.png +0 -0
  87. package/icon/bitwrench-logo-green.png +0 -0
  88. package/icon/bitwrench-logo-grey.png +0 -0
  89. package/icon/bitwrench-logo-white.png +0 -0
  90. package/icon/bitwrench-logos-colors.png +0 -0
  91. package/icon/bitwrench-thick-logo.png +0 -0
  92. package/icon/bitwrench-thick-teal/android-chrome-192x192.png +0 -0
  93. package/icon/bitwrench-thick-teal/android-chrome-512x512.png +0 -0
  94. package/icon/bitwrench-thick-teal/apple-touch-icon.png +0 -0
  95. package/icon/bitwrench-thick-teal/browserconfig.xml +0 -9
  96. package/icon/bitwrench-thick-teal/favicon-16x16.png +0 -0
  97. package/icon/bitwrench-thick-teal/favicon-32x32.png +0 -0
  98. package/icon/bitwrench-thick-teal/favicon.ico +0 -0
  99. package/icon/bitwrench-thick-teal/mstile-144x144.png +0 -0
  100. package/icon/bitwrench-thick-teal/mstile-150x150.png +0 -0
  101. package/icon/bitwrench-thick-teal/mstile-310x150.png +0 -0
  102. package/icon/bitwrench-thick-teal/mstile-310x310.png +0 -0
  103. package/icon/bitwrench-thick-teal/mstile-70x70.png +0 -0
  104. package/icon/bitwrench-thick-teal/site.webmanifest +0 -19
  105. package/icon/bitwrench-thick-teal.ico +0 -0
  106. package/icon/bitwrench-thick-teal.svg +0 -44
  107. package/icon/bitwrench-thick-teal.zip +0 -0
  108. package/icon/favicon-test.html +0 -20
  109. package/icon/logos-test.PNG +0 -0
  110. package/images/bitwrench-512x512.png +0 -0
  111. package/images/bitwrench-logo-med.png +0 -0
  112. package/images/bitwrench-thick-logo.png +0 -0
  113. package/images/bitwrench-thick-logo.svg +0 -64
  114. package/images/bitwrench-thick-teal.ico +0 -0
  115. package/images/favicon.ico +0 -0
  116. package/index.html +0 -282
  117. package/instr_tmp/bitwrench.js +0 -1350
  118. package/karma.conf.js +0 -140
  119. package/makefile +0 -21
  120. package/quick-docs.html +0 -206
  121. package/test/bitwrench_test.js +0 -1255
  122. package/test/karma-test.js +0 -1081
  123. package/tools/bw_deprecatedNames.js +0 -19
  124. package/tools/bwconsole.js +0 -20
  125. package/tools/createSimpleHTMLPage.js +0 -41
  126. package/tools/emitreadme.sh +0 -4
  127. package/tools/export-bw-default-css.js +0 -41
  128. package/tools/umd2ModuleHack.js +0 -32
  129. package/tools/update-bw-package.js +0 -36
  130. package/tools/updatereadme.js +0 -34
package/bitwrench.js DELETED
@@ -1,3348 +0,0 @@
1
- /*
2
- * bitwrench.js --- Misc Helper Functions ..
3
- *
4
- * bitwrench is just a named space set of javascript helper functions useful for common web tasks and
5
- * some server side js. No rhyme or reason I just needed these items over and overgain and didn't feel
6
- * like cobbling together different common libs
7
- *
8
- * M. A. Chatterjee 2013
9
- *
10
- * @copy Copyright (C) <2013> <M. A. Chatterjee>
11
- *
12
- * @author M A Chatterjee <deftio [at] deftio [dot] com>
13
- *
14
- * This software is provided 'as-is', without any express or implied
15
- * warranty. In no event will the authors be held liable for any damages
16
- * arising from the use of this software.
17
- *
18
- * Permission is granted to anyone to use this software for any purpose,
19
- * including commercial applications, and to alter it and redistribute it
20
- * freely, subject to the following restrictions:
21
- *
22
- * 1. The origin of this software must not be misrepresented; you must not
23
- * claim that you wrote the original software. If you use this software
24
- * in a product, an acknowledgment in the product documentation is required.
25
- *
26
- * 2. Altered source versions must be plainly marked as such, and must not be
27
- * misrepresented as being the original software.
28
- *
29
- * 3. This notice may not be removed or altered from any source
30
- * distribution.
31
- *
32
- */
33
- //JS Hint linter directives
34
- /*jshint -W069 */ //suppresses warning about using x.var_name vs x["var_name"]
35
-
36
- //usage in browser
37
- //<script type="text/javascript" src="./bitwrench.js"></script>
38
-
39
- //usage in nodejs
40
- //var bw = require('./bitwrench.js'); //adds to current scope in nodejs
41
-
42
- // optional polyfill for IE8 and earlier
43
- "use strict";
44
- /* istanbul ignore next */
45
- (function(fn){ // this is a polyfill for IE7/IE8
46
- /*
47
- //node.textContent
48
- // Source: Eli Grey @ https://eligrey.com/blog/post/textcontent-in-ie8
49
- if (Object.defineProperty
50
- && Object.getOwnPropertyDescriptor
51
- && Object.getOwnPropertyDescriptor(Element.prototype, "textContent")
52
- && !Object.getOwnPropertyDescriptor(Element.prototype, "textContent").get) {
53
- (function() {
54
- var innerText = Object.getOwnPropertyDescriptor(Element.prototype, "innerText");
55
- Object.defineProperty(Element.prototype, "textContent",
56
- // Passing innerText or innerText.get directly does not work,
57
- // wrapper function is required.
58
- {
59
- get: function() {
60
- return innerText.get.call(this);
61
- },
62
- set: function(s) {
63
- return innerText.set.call(this, s);
64
- }
65
- }
66
- );
67
- })();
68
- }
69
- */
70
- //Array stuff
71
- if (!Array.prototype.indexOf) {
72
- Array.prototype.indexOf = function (searchElement ) {
73
- "use strict";
74
- if (this == null) {
75
- throw new TypeError();
76
- }
77
- var t = Object(this);
78
- var len = t.length >>> 0;
79
- if (len === 0) {
80
- return -1;
81
- }
82
- var n = 0;
83
- if (arguments.length > 0) {
84
- n = Number(arguments[1]);
85
- if (n != n) { // shortcut for verifying if it's NaN
86
- n = 0;
87
- } else if (n != 0 && n != Infinity && n != -Infinity) {
88
- n = (n > 0 || -1) * Math.floor(Math.abs(n));
89
- }
90
- }
91
- if (n >= len) {
92
- return -1;
93
- }
94
- var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
95
- for (; k < len; k++) {
96
- if (k in t && t[k] === searchElement) {
97
- return k;
98
- }
99
- }
100
- return -1;
101
- };
102
- }
103
- if (!fn.join) fn.join = function(s) {var i,r="";s=s?s:""; if (this.length) {for(i=0;i<this.length-1;i++){r+= this[i].toString()+s;} r= (i>=0) ? r+this[i].toString() : r;} return r;};
104
- if (!fn.map) fn.map=function(f){var r=[];for(var i=0;i<this.length;i++)r.push(f(this[i]));return r;};
105
- if (!fn.filter) fn.filter=function(f){var r=[];for(var i=0;i<this.length;i++)if(f(this[i]))r.push(this[i]);return r;};
106
- if (!String.prototype.trim) {String.prototype.trim = function () { return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ""); };}
107
-
108
- })(Array.prototype); // end polyfills
109
- // * /
110
-
111
- (function (root, factory) {
112
- if (typeof define === "function" && define.amd) { // eslint-disable-line no-undef
113
- // AMD. Register as an anonymous module.
114
- //define(['myRequiredDependancyModule'], factory); // use this if other modules required
115
- define([], factory); // eslint-disable-line no-undef
116
- } else if (typeof module === "object") {
117
-
118
- if ((typeof module !== "object" ) || (typeof module !== "function") ) // this hack required for older versions of node
119
- // var m =require("module");
120
- // Node. Does not work with strict CommonJS, but
121
- // only CommonJS-like environments that support module.exports,
122
- // like Node.
123
- //console.log("node...");
124
- var libm= factory();
125
- libm.exportModuleType = "module.exports";
126
- module.exports=libm;
127
-
128
- } else {
129
- //console.log("browser..",root, typeof root);
130
- // Browser globals (root is window)
131
- var libg = factory();
132
- libg.exportModuleType="global";
133
- root[libg["exportName"]] = libg;
134
-
135
- }
136
- }(typeof self !== "undefined" ? self : this, function () { // note if needing requirements use ... (typeof self !== "undefined" ? self : this, function (myRequiredDependancyModule)
137
- "use strict";
138
- // Use b in some fashion.
139
-
140
- // Just return a value to define the module export.
141
- // This example returns an object, but the module
142
- // can return a function as the exported value.
143
- //BEGIN_LIBRARY_CODE
144
- var bw = {};
145
- bw.exportName = "bw"; //
146
- bw.exportModuleType = "AMD"; //default export see UMD wrapper above for more info this. it allows the consumer to know how this was loaded.
147
-
148
-
149
- // ===================================================================================
150
- bw.choice = function (x,choices,def) {
151
- /**
152
- bw.choice(x,choices-dictionary, default)
153
-
154
-
155
- Allows a dictionary to be used as a switch statement, including functions.
156
-
157
- example:
158
- colors = {"red": 1, "blue": 2, "aqua" : function(z){return z+"marine"}};
159
- bw.choice("red",colors,"0") ==> "1"
160
- bw.choice("shiny",colors,"0") ==> "0"
161
- bw.choice("aqua",colors) ==> "aquamarine"
162
- */
163
- var z = (x in choices) ? choices[x] : def;
164
- return _to(z) == "function" ? z(x) : z;
165
- };
166
-
167
-
168
- // ===================================================================================
169
- bw.jsonClone = function (x) {
170
- /**
171
- bw.jsonClone(object)
172
-
173
- crude deep copy by value of an object as long as no js dates or functions
174
- */
175
- return JSON.parse(JSON.stringify(x));
176
- };
177
-
178
-
179
- // ===================================================================================
180
- bw.typeOf = function (x, baseTypeOnly) {
181
- /**
182
- _to(x, baseTypeOnly) returns a useful typeOf the object.
183
-
184
- _to(2) // "number"
185
- bw.typeof( function(){}) // "function"
186
-
187
- function Car(make, model, year) {
188
- this.make = make;
189
- this.model = model;
190
- this.year = year;
191
- }
192
-
193
- x = new Car("Ford", "Escape", 2009);
194
-
195
- _to(Car) // "function"
196
- _to(x) // "Car" ---> returns correct object type
197
- _to(x,true) // "object" ---> returns base object type
198
-
199
- */
200
-
201
- //A useable typeof operator. See this fantastic reference for a starter
202
- //https://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/
203
-
204
- if (x === null)
205
- return "null";
206
-
207
- var y = (typeof x == "undefined") ? "undefined" : (({ /*empty*/}).toString.call(x).match(/\s([a-zA-Z]+)/)[1].toLocaleLowerCase());
208
-
209
- if ((y != "object") && (y != "function"))
210
- return y;
211
- if (baseTypeOnly == true) // so if undefind or anything but true
212
- return y;
213
-
214
- var r = y;
215
- try {
216
- r = (x.constructor.name.toLocaleLowerCase() == y.toLocaleLowerCase()) ? y : x.constructor.name; // return object's name e.g.
217
- }
218
- catch (e) {/*empty*/}
219
- if (r == "object") {
220
- if (x["_is_BW_HTMLNode"] == true )
221
- r="BW_HTMLNode";
222
- }
223
- return r;
224
- };
225
-
226
- var _to = bw.typeOf;
227
- bw.to = _to;
228
- //===============================================
229
- // internally used type check and assign function
230
- bw.typeAssign = function (a, typeString, trueValue, falseValue) {
231
- /**
232
- bw.typeAssign(variable, typeString, trueValue, falseValue)
233
- typeAssign is used to see if the argument a is of type typeString as defined by _to().
234
- if it is then trueValue is returned else falseValue.
235
-
236
- bw.typeAssign("23","number","is a number!", "not a number!") ==> "is a number!"
237
- bw.typeAssign([23],"number","is a number!", "not a number!") ==> "not a number!" // is an array of length 1
238
-
239
- can also supply list of types
240
- bw.typeAssign(23,["string","number"], "string or num", "something else") ==> "string or num"
241
- bw.typeAssign(true,["string","number"], "string or num", "something else") ==> "something else"
242
- */
243
- if (["string","array"].indexOf(_to(typeString)) == -1) // typeString must be a string or an arrag or strings
244
- typeString = "notValidType";
245
-
246
- if (_to(typeString) == "string")
247
- typeString = [typeString];
248
-
249
- return (typeString.indexOf(_to(a)) >= 0) ? trueValue : falseValue;
250
- };
251
-
252
- var _toa = bw.toa = bw.typeAssign; // eslint-disable-line no-unused-vars
253
-
254
-
255
- //===============================================
256
- // internally used type check and assign function with functional support (trueValue or falseValue can be functions which are passed the param a)
257
-
258
- bw.typeConvert = function (a, typeString, trueValue, falseValue) {
259
- /**
260
- bw.typeConvert(variable, typeString, trueValue, falseValue)
261
- typeConvert is used to see if the argument a is of type typeString as defined by _to().
262
- if it is then trueValue is returned else falseValue.
263
-
264
- bw.typeConvert("23","number","is a number!", "not a number!") ==> "is a number!"
265
- bw.typeConvert([23],"number","is a number!", "not a number!") ==> "not a number!" // is an array of length 1
266
-
267
- can also supply list of types
268
- bw.typeConvert(23,["string","number"], "string or num", "something else") ==> "string or num"
269
- bw.typeConvert(true,["string","number"], "string or num", "something else") ==> "something else"
270
-
271
- bw.typeConvert(23,["string","number"],function(x){return x+1},function(){return function(x){return x+2}})}) ==> 24
272
-
273
- bw.typeConvert(23,["string"],function(x){return x+1},function(){return function(x){return x+2;}})}) ==> function(x){return x+2;}
274
-
275
- however typeConvert also allows functions (as apposed to typeAssign)
276
- */
277
- if (["string","array"].indexOf(_to(typeString)) == -1) // typeString must be a string or an arrag or strings
278
- typeString = "notValidType";
279
-
280
- if (_to(typeString) == "string")
281
- typeString = [typeString];
282
-
283
- return (typeString.indexOf(_to(a)) >= 0) ? (_to(trueValue) == "function") ? trueValue(a) : trueValue : ( _to(falseValue) == "function") ? falseValue(a): falseValue;
284
- };
285
- //var _tc = bw.typeConvert;
286
- var _toc = bw.tc = bw.typeConvert; // eslint-disable-line no-unused-vars
287
- //===============================================
288
- // internally used function for options copy
289
- // keys in opts are copied to dopts (or overwrite options in dopts)
290
- /* istanbul ignore next */
291
- var optsCopy = function(dopts,opts) {
292
- /* istanbul ignore next */
293
- if ((_to(opts) == "object") && (_to(dopts)=="object")) {
294
- var i;
295
- for (i in opts) {
296
- if ((_to(opts[i]) == "object" )||(_to(dopts[i])=="object")) {
297
- var j;
298
- for (j in opts[i])
299
- dopts[i][j] = opts[i][j];
300
- }
301
- else
302
- dopts[i] = opts[i];
303
- }
304
- }
305
- return dopts;
306
- };
307
- bw._oc = optsCopy;
308
- // ===================================================================================
309
- bw.arrayUniq = function (x){
310
- /**
311
- arrayUniq(x)
312
- returns uniq elements of simple array x.
313
- */
314
- if (_to(x) != "array")
315
- return [];
316
- return x.filter (function (v, i, arr) {return (arr.indexOf(v)==i);});
317
- };
318
- // ===================================================================================
319
- bw.arrayBinA = function (a,b) {
320
- /**
321
- arrayBinA(x)
322
- returns intersection elements of to simple arrays a and b
323
- */
324
- if ((_to(a)!="array") || (_to(b)!== "array"))
325
- return [];
326
- return bw.arrayUniq(a.filter(function(n) { return b.indexOf(n) !== -1;}));
327
- };
328
-
329
- bw.arrayBNotInA = function (a,b) {
330
- /**
331
- arrayBNotinA(x)
332
- returns elements of b not present in a
333
- */
334
- if ((_to(a)!="array") || (_to(b)!== "array"))
335
- return [];
336
- return bw.arrayUniq(b.filter(function(n) { return a.indexOf(n) < 0;}));
337
- };
338
-
339
- //===============================================
340
- /* istanbul ignore next */
341
- bw.DOMIsElement = function(el) {
342
- /**
343
- @method bw.DOMIsElement() - returns whether a supplied element is a HTML DOM element. only useful in browser,
344
- */
345
- var r = false;
346
- try {
347
- if(_to(el)== "undefined")
348
- return r;
349
- if ((bw.isNodeJS() == false) || (typeof Element == "function"))
350
- r = el instanceof Element;
351
-
352
- }
353
- catch(e) {
354
- r = (typeof HTMLElement === "object" ? el instanceof HTMLElement : //DOM2
355
- el && (typeof el === "object") && (el !== null) && (el.nodeType === 1) && (typeof el.nodeName==="string")
356
- );
357
- bw.logd(e.toString());
358
- }
359
- return r;
360
- };
361
-
362
- var _isEl = bw.DOMIsElement;
363
-
364
- //===============================================
365
- /* istanbul ignore next */
366
- bw.DOMGetElements = function (el, type) {
367
- /**
368
- @method DOMGetElements(el, type) returns an array of DOM elements (if running in browser)
369
-
370
- @param {string | DOM_node} el - if string uses CSS selector other wise if already a DOM element returns itself
371
- @return an js array of zero or more matching DOM nodes
372
-
373
- DOMGetElements always looks in the root.
374
-
375
- */
376
-
377
- /*
378
- TODO:
379
- var container = document.querySelector("#test");
380
- var matches = container.querySelectorAll("div.highlighted > p");
381
-
382
- */
383
- var r=[],a=[],i;
384
-
385
- if (bw.isNodeJS() == false)
386
- { // we're running in a browser
387
- if (_isEl(el))
388
- return [el];
389
- if (_to(el) == "string") { // now its a string so we have choices..
390
- type = _toa(type,"string",type,"auto"); // auto means detect whether has a # or . in front of it
391
- el.trim();
392
- if (type == "auto")
393
- type = bw.choice(el[0],{".":"className", "#":"id"},"tagName");
394
- type=type.toLowerCase();
395
- switch (type) {
396
- case "id" : //get Element by ID
397
- el = (el[0]=="#") ? el.substring(1,el.length) : el;
398
- a = document.getElementById(el);
399
- a = _toa(a,"null",[],[a]);
400
- break;
401
- case "classname": // get Elements by class name
402
- el = (el[0]==".") ? el.substring(1,el.length) : el;
403
- a = document.getElementsByClassName(el);
404
- break;
405
- case "tagname" : // get Elements by tag name
406
- a = document.getElementsByTagName(el);
407
- break;
408
- case "name":
409
- a = document.getElementsByName(el);
410
- break;
411
- case "css" :
412
- a = document.querySelectorAll(el);
413
- break;
414
- default:
415
- a = document.querySelectorAll(el);
416
-
417
- }
418
- for (i in a)
419
- r.push(a[i]);
420
- }
421
- }
422
-
423
- return r.filter(function(x){return _isEl(x);});
424
- };
425
- //var _els = bw.DOMGetElements;
426
-
427
- // =============================================================================================
428
- /* istanbul ignore next */
429
- bw.DOMSetElements = function(domElement,param) {
430
- /**
431
- @method DOMSetElements(domElement, param) sets DOM elements with the supplied (optional) params
432
-
433
- @param {string | array | dict |function} - params to set on DOMElements
434
- @return an js array of zero or more matching DOM nodes
435
- */
436
-
437
- var els = bw.DOMGetElements(domElement);
438
- if (els==[])
439
- bw.log("dom element not found");
440
-
441
- var i,l,e, ef = function(x,p){bw.log(x,p);};
442
- for (l=0; l<els.length; l++) {
443
- e = els[l];
444
- switch(_to(param)) {
445
- case "array":
446
- try{
447
- for (i=0; i<param.length; i++) e[param[i][0]] = param[i][1];
448
- }
449
- catch(d) {ef(d,param);}
450
- break;
451
- case "object":
452
- try {
453
- for (i in param) e[i] = param[i];
454
- }
455
- catch(d) {ef(d,param);}
456
- break;
457
- case "string":
458
- try {
459
- e.innerHTML = param;
460
- }
461
- catch(d) {ef(d,param);}
462
- break;
463
- case "function":
464
- try {
465
- param(e); // apply a function to e
466
- }
467
- catch(d) {ef(d,param);}
468
- break;
469
- default: break;
470
- }
471
- }
472
-
473
- return els;
474
- };
475
-
476
- bw.DOM = bw.DOMSetElements; //short hand
477
- //================================================================================
478
- bw.DOMInsertElement = function (parentEl, htmldata, putFirst) {
479
- /**
480
- DOMInsertElement (attachEl, html , putFirst)
481
- creates an HTML element (browser only). If an attachment element is provided it will attach the new element to the attachElement.
482
- if putFirst == true it is made the first child of the attachEl else it is the lastChild of the attachEl
483
- */
484
- var el = null;
485
- if (bw.isNodeJS() == false) {
486
- if (bw.DOMIsElement(htmldata))
487
- el = htmldata;
488
- else {
489
- el = document.createElement("div"); //outer wrapper
490
- el.innerHTML = bw.html(htmldata);
491
- el = el.firstChild; // get our element back
492
- }
493
- if (parentEl) {
494
- parentEl = bw.DOM(parentEl)[0];
495
- if (putFirst ) {
496
- parentEl.insertBefore(el, parentEl.firstChild); // put it first
497
- }
498
- else
499
- parentEl.appendChild(el); // put it last
500
- }
501
- }
502
- return el;
503
- };
504
- bw.DOMIns = bw.DOMInsertElement;
505
-
506
- // =============================================================================================
507
- bw.htmlToElement = function (htmldata) {
508
- var el=null;
509
- if (bw.isNodeJS() == false) {
510
- if (bw.DOMIsElement(htmldata))
511
- el = htmldata;
512
- else {
513
- el = document.createElement("div"); //outer wrapper
514
- el.innerHTML = bw.html(htmldata);
515
- el = el.firstChild; // get our element back
516
- }
517
- }
518
- return el;
519
- };
520
- // =============================================================================================
521
-
522
- bw.DOMReplaceElement = function(oldEl, newEl) {
523
- if (bw.isNodeJS() == false) {
524
- var e = bw.DOM(oldEl)[0];
525
- return e.parentNode.replaceChild(bw.htmlToElement(newEl), e);
526
- }
527
- return null;
528
- };
529
- // =============================================================================================
530
- /**
531
- bitwrench: color functions (used for theming and interpolations)
532
-
533
- bitwrench color functons operate using this internal color representation model:
534
- [c0, c1, c2, alpha, model]
535
- where c0, c1, c2 are model dependant
536
- alpha represents the transperancy
537
- model is a color model string (lowercase) "rgb", or "hsl" (compatible with HTML/CSS colors)
538
-
539
- colorParse() ==> take an input color of anymodel and output a bw [c0,c1,c2,a,m] array
540
- */
541
- bw.colorInterp = function(x, in0, in1, colors, stretch) {
542
- /**
543
- @method colorInterp (x, lo, hi, colors[], stretch) - interpolate between and array of colors.
544
- x is a number between the numbers in0 <= x <= in1
545
- colors is an array of colors supplied in rgb format e.g. ["#123", "#234"]
546
- colors can be anylength
547
- */
548
- var c = _toa(colors,"array",colors,["#000","#fff"]); // make sure we have an array of colors
549
- c = c.length == 0 ? ["#000","#fff"] : c; // no colors provide .. interp grayscale is default
550
- if (c.length == 1)
551
- return c[0];
552
- //ok now we we have an array of atleast length 2 which hopefully contains colors.
553
- c = c.map(function(x){return bw.colorParse(x);}); // all colors will now be converted to bw RGB format
554
- var a = bw.mapScale(x,in0,in1,0,c.length-1,{clip: true, expScale: stretch});
555
- var i = bw.clip(Math.floor(a),0,c.length-2);
556
- var r = a-i;
557
- var _f = function(x) {return bw.mapScale(r,0,1, c[i][x],c[i+1][x],{clip:true});};
558
- return [_f(0), _f(1), _f(2),_f(3),"rgb"];
559
-
560
- };
561
-
562
-
563
- // =============================================================================================
564
- bw.colorHslToRgb = function (h, s, l, a, rnd){
565
- /**
566
- @method colorHslToRgb
567
- Converts an HSL color value to RGB. Conversion formula
568
-
569
- Assumes h is [0..360] , s, and l are contained in the set [0 .. 100].
570
- returns r, g, and b in the set [0, 255].
571
-
572
- @param {number} h The hue [0..360]
573
- @param {number} s The saturation [0..100]
574
- @param {number} l The lightness [0..100]
575
-
576
- OR...
577
-
578
- pass the colors as a bitwrench color array as a single parameter:
579
-
580
- colorHslToRgb([h,s,l,a,"hsl"])
581
-
582
- @return {Array} The RGB representation as [r, g, b, alpha, "rgb"]
583
-
584
- last parameter rnd rounds the results to 0..255. set to false to eliminate rounding. This can be useful for chained calcs
585
-
586
- see : adapted from http://hsl2rgb.nichabi.com/javascript-function.php
587
-
588
- */
589
- if (_to(h)=="array") { // handles colors of [h,s,l,a,"hsl"]
590
- s=h[1];
591
- l=h[2];
592
- a=h[3];
593
- h=h[0]; //do this last so it doesn't overwrite iself
594
- }
595
- var _fn = rnd == false ? function(x){return x;} : function(x){return bw.clip(Math.round(x),0,255);} ;
596
-
597
- var r,g,b,c,x,m;
598
- h = (h+360)%360;
599
- h /= 60;
600
- if (h < 0) h = 6 - (-h % 6);
601
- h %= 6;
602
-
603
- s = Math.max(0, Math.min(1, s / 100));
604
- l = Math.max(0, Math.min(1, l / 100));
605
-
606
- c = (1 - Math.abs((2 * l) - 1)) * s;
607
- x = c * (1 - Math.abs((h % 2) - 1));
608
-
609
- if (h < 1) {
610
- r = c; g = x; b = 0;
611
- } else if (h < 2) {
612
- r = x; g = c; b = 0;
613
- } else if (h < 3) {
614
- r = 0; g = c; b = x;
615
- } else if (h < 4) {
616
- r = 0; g = x; b = c;
617
- } else if (h < 5) {
618
- r = x; g = 0; b = c;
619
- } else {
620
- r = c; g = 0; b = x;
621
- }
622
-
623
- m = l - c / 2;
624
- r = (r + m) * 255;
625
- g = (g + m) * 255;
626
- b = (b + m) * 255;
627
- return [_fn(r),_fn(g),_fn(b),a,"rgb"];
628
- };
629
-
630
- // =============================================================================================
631
- bw.colorRgbToHsl = function (r, g, b, a, rnd) {
632
- /**
633
- Converts an RGB color value to HSL. Conversion formula
634
- adapted from http://en.wikipedia.org/wiki/HSL_color_space.
635
- Assumes r, g, and b are contained in the set [0, 255] and
636
- returns h as [0..360] s, and l in the set [0 .. 100].
637
-
638
- @param {number} r The red color value
639
- @param {number} g The green color value
640
- @param {number} b The blue color value
641
-
642
- pass the colors as a bitwrench color array as a single parameter:
643
- colorRgbToHsl([h,s,l,a,"rgb"])
644
-
645
- last parameter rnd rounds the results to 0..255. set to false to eliminate rounding. This can be useful for chained calcs
646
- @return {Array} The HSL representation
647
- */
648
- if (_to(r)=="array") { // handles colors of [h,s,l,a,"hsl"]
649
- g=r[1];
650
- b=r[2];
651
- a=r[3];
652
- r=r[0]; //do this last so it doesn't overwrite iself
653
- }
654
-
655
- r /= 255, g /= 255, b /= 255;
656
- var max = Math.max(r, g, b), min = Math.min(r, g, b);
657
- var h, s, l = (max + min) / 2;
658
-
659
- if(max == min){
660
- h = s = 0; // achromatic
661
- }else{
662
- var d = max - min;
663
- s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
664
- switch(max){
665
- case r: h = (g - b) / d + (g < b ? 6 : 0); break;
666
- case g: h = (b - r) / d + 2; break;
667
- case b: h = (r - g) / d + 4; break;
668
- }
669
- h /= 6;
670
- }
671
- var _fn = rnd == false ? function (x){return x;} : function(x){return Math.round(x);} ;
672
- return [_fn(h*360), _fn(s*100), _fn(l*100), a, "hsl"];
673
- };
674
-
675
- // =============================================================================================
676
-
677
- bw.colorParse = function(s,defAlpha) {
678
- /**
679
- @method bw.colorParse(s)
680
-
681
- @description take a valid CSS style color string: #rgb | #rgba | #rrggbb | #rrggbbaa | rgb(r,g,b) | rgb(r,g,b,a) | hsl(h,s,l) | hsla(h,s,l,a )
682
- ... and return array [c0,c1,c2,a,model] where model is one of "rgb", "hsl"
683
- */
684
- defAlpha = _toa(defAlpha,"number",defAlpha,255);
685
- var r = [0,0,0,defAlpha,"rgb"]; // always return a valid type
686
- if (_to(s)=="array"){ // it could be a bwcolor type [c0,c1,c2,a,model]
687
- var p,df = [0,0,0,255,"rgb"];
688
- for (p=0; p< s.length; p++)
689
- df[p]=s[p];
690
- s= String(df[4])+"("+String(df[0])+","+String(df[1])+","+String(df[2])+","+String(df[3])+")"; //could use slice..join(",")
691
- }
692
-
693
- s = String(s).replace(/\s/g,"");
694
- var reT = /\s*(#|hsl|rgb|yuv|hsv){1}([a-f|A-F|0-9|,().\t ]*)/img;
695
- var i,j=0,x = reT.exec(s);
696
- if (_to(x)=="array" && (x.length >= 3)) {
697
- r[4]= x[1] == "#" ? "rgb" : x;
698
- if (x[1] == "#") { //parse one of these #rgb #rgba #rrggbb #rrggbbaa
699
- switch (x[2].length) {
700
- case 3: //#rgb
701
- case 4: //#rgba
702
- for (i=0; i< x[2].length; i++)
703
- r[i] = parseInt(x[2][i]+x[2][i],16);
704
- break;
705
- case 6: //#rrggbb
706
- case 8: //#rrggbbaa
707
- for (i=0; i< x[2].length; i+=2)
708
- r[j++] = parseInt(x[2][i]+x[2][i+1],16);
709
- break;
710
- default:
711
- bw.logd("bw.parseColor bad input "+ s);
712
- }
713
- }
714
- else { // its should be of form (c0,c1,c2) or (c0,c1,c2,alpha)
715
- r[4] = x[1].toLocaleLowerCase();
716
- if ((x[2][0] == "(") && (x[2][x[2].length-1] == ")")) { // parans are present
717
- var v = x[2].substring(1,x[2].length-1);
718
- v = v.split(",");
719
- switch(v.length){ // valid entries are 3 or 4 components
720
- case 3:
721
- case 4:
722
- for (i=0; i< v.length; i++)
723
- r[i] = Number(v[i]);
724
- break;
725
- default:
726
- bw.logd("bw.parseColor bad input : " + s);
727
- }
728
- } else {
729
- bw.logd("bw.parseColor bad input : " + s);
730
- }
731
- }
732
- }
733
- return r;
734
- };
735
-
736
- // =============================================================================================
737
- bw.colorToRGBHex = function(c, format) {
738
- /**
739
- @method bw.colorToRGBHex(color)
740
- @description take a color of the form a string or [c0,c1,c2,alpha,model] ==> convert to #rrggbbaa format
741
- format (optional) can be set to auto in which case alpha is ommitted if set to 255
742
- */
743
- var r = "#00000000";
744
- var ph = function(x){var y=(bw.clip(Math.round(x),0,255)).toString(16); return (y.length==1)?"0"+y:y;}; // pad hex
745
- c = bw.colorParse(c); // converts color to bw color vector format
746
- switch(c[4]) {
747
- case "rgb":
748
- r = "#"+ph(c[0])+ph(c[1])+ph(c[2]);
749
- if (!((format == "auto") && (c[3]==255)))
750
- r += ph(c[3]);
751
- break;
752
- case "hsl":
753
- r= bw.colorToRGBHex(bw.colorHslToRgb(c));
754
- break;
755
- default:
756
- bw.logd("colorToRGBHex : unsupported format" + c[4]);
757
- }
758
- return r; // default
759
- };
760
- // =============================================================================================
761
- bw.colorConvertColorSpace = function(c, space, rnd) {
762
- /**
763
- @method bw.colorConvertColorSpace(color, spaceToConvertTo)
764
- @description take a color and convert it to the destination color space ("rgb" | "hsl")
765
- color can be any valid color type ("#abc" | "hs(...)" or [r,g,b,a,"rgb"] etc)
766
-
767
- optional 3rd param rnd if set to false will suppress rounding in calcs to allow chained color conversion w/o loss of precision
768
-
769
- */
770
- c = bw.colorParse(c);
771
- if (space == c[4])
772
- return c;
773
-
774
- switch(c[4]) {
775
- case "rgb":
776
- break;
777
- case "hsl":
778
- c = bw.colorHslToRgb(c[0],c[1],c[2],c[3],rnd); // turns off rounding
779
- break;
780
- default:
781
- bw.logd("colorConvertColorSpace: unsupported color format");
782
- }
783
- //now c is in the rgb space
784
-
785
- switch(space) {
786
- case "rgb":
787
- break;
788
- case "hsl":
789
- c = bw.colorRgbToHsl(c[0],c[1],c[2],c[3],rnd); // turns off rounding
790
- break;
791
- default:
792
- bw.logd("colorConvertColorSpace: unsupported color format");
793
- }
794
- return c;
795
- };
796
-
797
- // =============================================================================================
798
- var _logdata=[];
799
-
800
- bw.log = function (value,msg,opts) {
801
- /**
802
- bw.log(value, message, options)
803
- write a value to the in-memory log
804
- options {
805
- clear: false | true | "clear-only"
806
- false : normal write
807
- true : clear log and add 1st entry
808
- clear-only - only clear don't write, value, msg
809
- saveMethod: "raw" | "JSON" // raw is default, save object as passed, JSON saves stringified version (useful for exporting or saving state)
810
- }
811
- */
812
- var dopts = {
813
- clear : false, // values fales, true, "clear-only"
814
- saveMethod: "raw" // else "JSON"
815
- };
816
-
817
- dopts = optsCopy(dopts,opts);
818
- if ((dopts["clear"] == true) || (dopts["clear"] == "clear-only")) {
819
- _logdata = [["Time-stamp (ms)"," Value "," Message "]];
820
- var ct = (new Date());
821
- _logdata.push ([0, ct.getTime()," log started at " + ct.toString()]);
822
- }
823
-
824
- msg = _toa(msg,"undefined","",String(msg));
825
- value = (dopts["saveMethod"]=="raw") ? value : JSON.stringify(value);
826
-
827
- if ((_to(value) != "undefined") && (dopts["clear"] != "clear-only"))
828
- _logdata.push([(new Date()).getTime()-_logdata[1][1], value, msg]);
829
-
830
- return _logdata.length -1;
831
- };
832
- bw.log("","",{clear:"clear-only"}); // initialize
833
-
834
- // =============================================================================================
835
- bw.logd = function() {
836
- /**
837
- @method bw.logd()
838
- @description: bw.logd is a log funciton which behaves similar to console.log() however instread of outputting to console,
839
- it writes to bw.log() function with the following differences:
840
-
841
-
842
- */
843
- /*
844
- todo: comma seperated items; ? done
845
- console ==> also (attempt) to output to console.log ? would need to set a bw.state variable..
846
- bwdbg ==> log bw catches / errors (else silent)
847
- none ==> no output (of any kind)
848
- stringify ==> takes bw.logd args and strinigyfies before writing to bw.log
849
- example:
850
- logd=console,bwlogd
851
-
852
- */
853
- var logdargs = ("bwlogd" in bw.bwargs) ? bw.bwargs["bwlogd"].split(",") : [];
854
-
855
- if (logdargs.indexOf("none") < 0) {
856
- var i=0;
857
- var _a = [];
858
- for (i=0; i< arguments.length; i++)
859
- _a.push(arguments[i]); //arguments, a reserved javascript keyword, is not a true array
860
- bw.log(_a,"bw.logd: "+bw.bwargs["bwlogd"]); // message
861
- }
862
- };
863
- // =============================================================================================
864
- bw.logExport = function(opts) {
865
- /**
866
- bw.logExport(options)
867
- export the built in log.
868
- default is "raw" which is an array of values:
869
- [timestamp, <value logged>, <optional message from the event>]
870
- [ .. , .. , .. ]
871
-
872
- also can be exported as an HTML table.
873
- bw.logExport({"format":"HTML"})
874
-
875
- or as a simple text file:
876
- bw.logExport("format" : "text"})
877
-
878
- see bw.saveClientFile(fname) for saving the log as a file
879
- */
880
- var dopts = {
881
- "format" : "raw" // can also be HTML table if set to "HTML"
882
- };
883
- dopts = optsCopy(dopts,opts);
884
-
885
- var _ld = _logdata;
886
-
887
- if (dopts["format"] == "HTML") {
888
- return bw.makeHTMLTableStr(_ld,{sortable:true});
889
- }
890
-
891
- if (dopts["format"] == "text") {
892
- return _ld.map(function(x){return x.map(function(y){return bw.padString(y.toString(),16,"left");}).join("\t");}).join("\n");
893
- }
894
-
895
- return _ld;
896
- };
897
-
898
-
899
- // ===================================================================================
900
- bw.setCookie = function (cname, cvalue, exdays) {
901
- /**
902
- @method bw.setCookie(cookieName, value, expireDays) set a client side cookie. (browser only)
903
- @param cname : a string for the name of the cookie
904
- @param cvalue : a string for the value of the cookie
905
- @param expdays : cookie expiration date in days
906
- */
907
- var d = new Date();
908
- d.setTime(d.getTime() + (exdays*24*60*60*1000));
909
- var expires = "expires="+d.toUTCString();
910
- document.cookie = cname + "=" + cvalue + "; " + expires;
911
- };
912
-
913
- // ===================================================================================
914
- bw.getCookie = function (cname, defaultValue) {
915
- /**
916
- @method bw.getCookie: bw.getCookie(cookieName, defaultValueIfNotFound) (browser only)
917
- get a client side cookie, if it is set. returns defaultValue if cookie could not be found
918
- */
919
- var name = cname + "=";
920
- var ca = document.cookie.split(";");
921
- for(var i=0; i<ca.length; i++) {
922
- var c = ca[i];
923
- while (c.charAt(0)==" ") c = c.substring(1);
924
- if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
925
- }
926
- return defaultValue;
927
- };
928
-
929
-
930
- // ===================================================================================
931
- bw.getURLParam = function (key, defaultValue) {
932
- /**
933
- @method bw.getURLParam(key,defaultValueIfNotFound)
934
- read the URL (e.g. http://example.com/my/page?this=that&foo=123&bub&x=123) and parse the URL paraemeters
935
-
936
- x = bw.getURLParam() ==> returns entire dict of url params ==? {this:"that",foo:"123",bub:true,x:"123"}
937
- x = bw.getURLParam("foo","whatever") ==> returns "123"
938
- x = bw.getURLParam("bar","whatever") ==> returns "whatever" since bar isn't set
939
- x = bw.getURLParam("bub","whatever") ==> returns true since bub doesn't have a value (note boolean true not "true")
940
-
941
- */
942
- if ((bw.isNodeJS()== true) || (typeof window != "object"))
943
- return defaultValue;
944
- try {
945
- if (window.location.href) {
946
- return bw.URLParamParse(window.location.href,key,defaultValue);
947
- }
948
- }
949
- catch (e) {
950
- bw.log(e);
951
- }
952
- return defaultValue;
953
-
954
- };
955
- bw.URLHash = function (url,defValue) {
956
- /**
957
- @method bw.URLHash(url,defValue) - returns the hash portion of a URL (if present) else return defValue
958
- */
959
- if (_to(url)=="undefined")
960
- url = typeof window == "object" ? window.location.href : "";
961
-
962
- var r = url.split(/#+/);
963
- return url.includes("#") ? r[r.length-1] : defValue;
964
- };
965
- //=================================================
966
- bw.URLParamParse = function (url,key,defValue,allowHash) {
967
- /**
968
-
969
- @method bw.URLParamParse(urlString, key, defaultValue)
970
-
971
- decode a URL encoded string in to a javascript dictionary. Other params (http, port, path) are not handled
972
-
973
- if key is present than only that value is returned (as a string ) else defValue is returned.
974
-
975
- examples:
976
- x = URLParamParse("http://example.com?a=123&b=345") ==> {a:"123", b:"456"}
977
- x = URLParamParse("http://example.com?a=123&b=345","a") ==> "123"
978
- x = URLParamParse("http://example.com?a=123&b=345","c","otherValue") ==> {a:"123", b:"456"} ==> "otherValue"
979
- */
980
-
981
- try {
982
- var hs=function(u){var x = u.split(/^.*\?+/); return x.length==2 ? x[1] : "";};
983
- var sh=function(u,b){return (b==true) ? u : u.split(/#+/)[0];};
984
- var params={}, parts = sh(hs(url),allowHash).split("&");
985
- for (var i = 0; i < parts.length; i++) {
986
- var e = parts[i].split("=");
987
- if (!e[0])
988
- continue;
989
- params[decodeURIComponent(e[0])] = _to(e[1])=="string" ? decodeURIComponent(e[1].replace("#","%23")) : true;
990
- }
991
- if (_to(key)=="undefined")
992
- return params;
993
- return params.hasOwnProperty(key) ? params[key] : defValue;
994
- }
995
- catch (e) {
996
- bw.log(e);
997
- return defValue;
998
- }
999
- };
1000
- //=================================================
1001
- bw.URLParamPack = function (simpleDict,inclQuestion) {
1002
- /**
1003
- @method bw.URLParamPack(simpleDict, inclQuestion) : packs a simple dict in to URL encoded format
1004
- @param simpleDict(object) - dictionary of simple key value pairs (not nested) if "deep" JSON needs to be packed then stringify that first
1005
- @param InclQuestion(boolean) - if true adds "?" to string otherwise ommitted.
1006
-
1007
- see also URLParamParse.
1008
- note if using bw.URLParamParse besure to include "?"" ==> bw.URLParamParse(bw.URLParamPack({a:1,b;2},"true"))
1009
- */
1010
- var k,s=[];
1011
- if (_to(simpleDict) == "object") {
1012
- for (k in simpleDict) {
1013
- s.push([encodeURIComponent(k)+"="+encodeURIComponent(simpleDict[k].toString())]);
1014
- }
1015
- s = s.join("&");
1016
- }
1017
- else
1018
- s="";
1019
-
1020
- return (inclQuestion ? "?" : "") + s;
1021
- };
1022
-
1023
-
1024
-
1025
- // ===================================================================================
1026
- bw.htmlSafeStr = function (str) {
1027
- /**
1028
- bw.htmlSageString(str)
1029
- Replace non valid HTML characters with HTML escaped equivalents.
1030
- */
1031
- //generic way..
1032
- //var x = function(x){return "&#"+x.toString().charCodeAt(0)+";";}
1033
- //return (str.toString()).replace(/[<>&\\#]/gm,x).replace(/[\n]/gm,"<br>");
1034
-
1035
- //old way is "pretty", tabs are issued 4 spaces..
1036
- var c = {"<":"&lt;", ">":"&gt;", "&":"&amp;", "\"":"&quot;", "'":"&#039;","#":"&#035;","\\\\":"","\n":"<br>","\t":"&nbsp;&nbsp;&nbsp;&nbsp;"};
1037
- return (str.toString()).replace(new RegExp("["+Object.keys(c).join("")+"]","gm"),function(s){return c[s];});
1038
- };
1039
-
1040
- // ===================================================================================
1041
- bw.htmlFavicon = function(iconStr,color) {
1042
- /**
1043
- create and HTML favicon from a string. Can use any unicode char including emoticons.
1044
- */
1045
- iconStr = iconStr ? iconStr : "🔧";// ♪ ❤ ♡ 🦉 🔧 🌴 ♫
1046
- var c = bw.to(color)=="string" ? color : "black";
1047
- return bw.html( {t:"link", a: {href: "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='0.9em' font-size='90' style='fill:"+ c+"'>"+iconStr+"</text></svg>", rel: "icon"} } );
1048
- };
1049
-
1050
- // ===================================================================================
1051
- bw.htmlJSON=function (json,pwrap) {
1052
- /**
1053
- @method bw.htmlJSON(object, styles)
1054
- pretty print any javascript object as displayable HTML.
1055
- e.g.
1056
- document.getElementById("myPlaceToDisplay").innerHTML = bw.htmlJSON(...any object ....)
1057
- */
1058
- //TODO make style dict as a param
1059
- function f(json) {
1060
- json = JSON.stringify(json, undefined, 2);
1061
- if (typeof json != "string") { json = JSON.stringify(json, undefined, 2);}
1062
-
1063
- json = json.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"); //html safe chars
1064
- //json = bw.htmlSafeStr(json);
1065
- return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g, function (match) {
1066
- var sty = "color: darkorange;";
1067
- if (/^"/.test(match)) {
1068
- if (/:$/.test(match)) {
1069
- sty = "color:red";
1070
- } else {
1071
- sty = "color:purple";
1072
- }
1073
- } else if (/true|false/.test(match)) {
1074
- sty = "color:grey";
1075
- } else if (/null/.test(match)) {
1076
- sty = "color:black";
1077
- } else
1078
- sty = "color:green";
1079
- return "<span style=\"" + sty + "\">" + match + "</span>";
1080
- });
1081
- }
1082
- pwrap = _toa(pwrap,"undefined","white-space:pre-wrap;","");
1083
-
1084
- return "<pre style='"+pwrap+"'>"+f(json)+"</pre>";
1085
- };
1086
-
1087
- // ===================================================================================
1088
- bw.makeCSS = function (cssData, options) {
1089
- /**
1090
- bw.makeCSS(cssData, options)
1091
-
1092
- cssData = "h2 {color:blue;}" // string as full rule (all correctness is on the caller)
1093
- cssData = ["h2 {color:blue;}"] // array entry but single string
1094
- cssData = ["h2 {color:blue}", "div {width:30px}"] // 2 entries, both strings
1095
- cssData = [["h2","color:blue"]] // array of rules (here length 1 rule)
1096
- cssData = [["h2","color:blue"], ["h3", "font-color:red"]] // array of rules
1097
- cssData = [
1098
- [["h2","h4"], "color:blue"], // array or selectors, string for rule
1099
- ["h3", "color:red"] // string for selector, string for rule
1100
- ]
1101
- cssData = [
1102
- [["h1","div p"],["color:blue","display:block"]], ==> h1, div p {color: blue; diplay:block;}
1103
- "h3 {color:red;}", ==> h3 {color: red;}
1104
- [["div",".myClass"],"color : red"], ==> div,.myClass {color: red;}
1105
- ["p > .myclass", ["color:red","display:block"]] ==> p > .myClass {color: red; display:block;}
1106
- ]
1107
- cssData = [
1108
- [str, {}]
1109
- ]
1110
- cssData = [
1111
- [[selectors], { dict }]
1112
- ]
1113
-
1114
- dicts not used at root because css can have multiple redundant selectors with different rules
1115
-
1116
- */
1117
- var dopts = {
1118
- emitStyleTag: false,
1119
- atr: {},
1120
- pretty : false
1121
- };
1122
- dopts = optsCopy(dopts,options);
1123
-
1124
- var s="\n";
1125
- var tb = function (a) {a =(String(a)).trim(); a=(a[0]=="{"?" ":" {")+a; a+=(a[a.length]=="}"?"":"}")+"\n"; return a;};
1126
- //var rl = "";
1127
- try {
1128
- switch (_to(cssData)) {
1129
- case "string":
1130
- s += cssData +"\n";
1131
- break;
1132
- case "array":
1133
- var i;
1134
- for (i=0; i<cssData.length; i++) {
1135
- var j = cssData[i];
1136
- switch (_to(j)) {
1137
- case "string": // this means we assume correcly formatted style is being passed in and we're just letting it through e.g. ".myclass {color:red}"
1138
- s+= j+"\n";
1139
- break;
1140
- case "array" : //expects length 2 array for each entry, though 2nd member can be dict or array
1141
- // ==>[str, str], [[str,str,str],str] , [str, {}], [[str,str,str],{}]
1142
- if ((j.length == 1) && (_to(j[0])=="string")) {
1143
- s+= j[0]+"\n";
1144
- break;
1145
- }
1146
-
1147
- if (j.length == 2) {
1148
- var _name = j[0], _rule = j[1], _ruleOutput="";
1149
- if (_to(_name)=="array") {
1150
- s+= _name.join(", ");
1151
- }
1152
- else {
1153
- s+= String(_name);
1154
- }
1155
- // now we have the names e.g. ("h2" or "h2,.myClass") done we need to emit the rules
1156
- switch( _to(_rule)) {
1157
- case "array" : // ["h2", ["color: black","left:20%"]] or [["h2",".myClass"], ["color: black","left:20%"]]
1158
- _ruleOutput = _rule.join("; ")+";";
1159
- break;
1160
- case "object" : // ["h2", {color: "black", left:"20%"}] or [["h2",".myClass"], {color:black, left:"20%"}]
1161
- {
1162
- var x;
1163
- for (x in _rule) { _ruleOutput += (x + ": " + _rule[x]+"; ");}
1164
- //_ruleOutput = bw.makeCSSRule([_name,_rule],{pretty:opts.pretty});
1165
- }
1166
- break;
1167
- case "string": // ["h2", "color: black"] or [["h2",".myClass"], "color:black"]
1168
- default:
1169
- _ruleOutput=_rule;
1170
- }
1171
- s+= tb(_ruleOutput)+"\n";
1172
-
1173
- }
1174
-
1175
- break;
1176
- default:
1177
- }
1178
- }
1179
-
1180
- break;
1181
- default:
1182
- s="";
1183
- }
1184
- }
1185
- catch (e) {bw.logd(e);} // eslint-disable-line no-empty
1186
- if (dopts["emitStyleTag"]) {
1187
- s = bw.html(["style",dopts["atr"],s]);
1188
- }
1189
- s.replace(/\n+/g,"\n").replace(/s+/g," ");
1190
- return s;
1191
- };
1192
-
1193
- // ===================================================================================
1194
- bw.makeCSSRule = function (cssData, options) {
1195
- /**
1196
- @method bw.makeCSSRule(cssData, options)
1197
-
1198
- expects this form:
1199
- [str, {k,v}]
1200
- or
1201
- [[array of rules str], {k,v}]
1202
-
1203
- e,g, [".myClass", {"color": "red", "font-weight" : "700 !important!"}]
1204
- or
1205
- [[".myClass","div > p"], {"color": "red", "font-weight" : "700 !important!"}]
1206
-
1207
- */
1208
- var dopts = {
1209
- emitStyleTag: false,
1210
- atr: {},
1211
- pretty: true // make it pretty otherwise compact form generated
1212
- };
1213
- dopts = optsCopy(dopts,options);
1214
-
1215
- var k,d,v=[],s="",sp=dopts.pretty?" ":"", cr=dopts.pretty?"\n":"";
1216
-
1217
- try {
1218
- if (_to(cssData)== "array") {
1219
- k=cssData[0], d=cssData[1];
1220
- s +=_toa(k,"array",k,[k.toString()]).join(","+sp)+cr;
1221
- for (k in d) {
1222
- v.push([sp+sp+k+":"+sp+cssData[1][k]+";"+sp+cr]);
1223
- }
1224
- s+= "{"+cr+v.join("")+"}"+cr;
1225
- }
1226
- } catch(e) {
1227
- bw.logd(e);
1228
- }
1229
- return s;
1230
-
1231
- };
1232
-
1233
- // ===================================================================================
1234
- /*
1235
- bw.htmlPage = function (head, body, options) {
1236
- /**
1237
- TBD finish (include bw params, handling meta w/o close tags)
1238
- bw.makeHTMLDoc(head,body,options)
1239
- make a simple HTML document.
1240
-
1241
- inline-bw-css --> emit bw default styles as inline css (include globals option)
1242
- * /
1243
- var dopts = {
1244
- docType : "<!DOCTYPE html>",
1245
- htmlParams : {lang: "en"},
1246
- headDefaultContent : [
1247
- ["meta", {"http-equiv":"Content-Type", "content":"text/html", "charset":"utf-8"}, ""]
1248
- //["title", {}, "bw doc"]
1249
- ],
1250
- headIncludeBitWrenchJS : false, // false : don't include, "embed" or "path-string"
1251
- headIncludeBitWrenchCSS : false, // exports bitwrench css classes in <style> section in head
1252
- headFavicon : "" //<link rel="icon" type="image/x-icon" href="../images/favicon-32x32.png" />
1253
- };
1254
- dopts = optsCopy(dopts,options);
1255
-
1256
- var s = dopts["docType"]+"\n";
1257
- s += bw.html(["html",dopts["htmlParams"],[
1258
- "\n",
1259
- ["head", {}, [ "\n",dopts["headDefaultContent"].map(function(x){return bw.html(x);}).join("\n"),head,"\n"]],
1260
- "\n",
1261
- ["body", {}, [ "\n",body,"\n"]],
1262
- "\n"
1263
- ]]);
1264
- return s;
1265
- };
1266
- */
1267
- // ===================================================================================
1268
- /**
1269
- htmlIsVoidTag(tagString) returns true if the supplied string is a html void tag (e.g. meta or br) which doesn't require a closing bracket else false
1270
- */
1271
- bw.htmlIsVoidTag = function(tag) {
1272
- return " area base br col command embed hr img input keygen link meta param source track wbr ".search(" "+String(tag).trim().toLowerCase()+" ") >=0;
1273
- };
1274
- // ===================================================================================
1275
- bw.htmlNode = function(x,opts) {
1276
- /**
1277
-
1278
- bw.htmlNode - converts acceptable data contructs into htmlEmit() compatible form,
1279
- { t: <tag>, a: {attribs}, c: [content], o: {options} }
1280
- or
1281
- a string e.g. "my html content" note that this can include html as well.
1282
- or
1283
- a function to be evaluated later
1284
- f(){return htmlNode compatible data structure} ==> when bw.HTMLEmit encounters this it will evaluate the the function contents. Useful for live templating.
1285
-
1286
- How htmlNode handles different objects:
1287
-
1288
- "object"
1289
- accepted keys below, other keys ignored (e.g. if your objects looks like this: {tag:"div", c:["this is my content"], data: [ ....] } the key called data will be ignored by htmlNode
1290
- t: String | Number | Date() ==> tag function==> f().toString(), null means no outer tag will be emitted.
1291
- a: {} ==> key : value ==> num | str | Date | [] ==> [].join(dopts.a_join) ,
1292
- c: [] || String | Number | Date ==> each_item : str | {html_dict}
1293
- o: {} ==> options (note inherit / copy) => if not supplied uses previous levels options
1294
-
1295
-
1296
- also accepts: "tag", "attrib", "content", "options" as keys instead of t,a,c,o,s
1297
-
1298
- if any of t,a,c,o are a function it will be invoked immediatly w no params ==> t:myFunc ===> t:myFunc() <==
1299
-
1300
- defaults:
1301
- t ==> "div"
1302
- a ==> {}
1303
- c ==> []
1304
- o ==> {}
1305
-
1306
- s ==> {level:0, nodes: 0}
1307
-
1308
- "string" | "number" | Date() ==> {}
1309
- t ==> "div"
1310
- a ==> {}
1311
- c ==> .toString()
1312
- o ==> {}
1313
-
1314
- s ==> {}
1315
-
1316
- "array" type objects are mapped BW_HTMLNodes as follows:
1317
- [ ] ==> {t:"span", a: {}, c: "", o: {}}
1318
- [c ] ==> {t:"span", a: {}, c: c , o: {}}
1319
- [t,c ] ==> {t:t, a: {}, c: c , o: {}}
1320
- [t,a,c ] ==> {t:t, a: a, c: c}
1321
- [t,a,c,o ] ==> {}
1322
- [ 5+ ] ==> {} // uses, first 4 entries, others ignored
1323
-
1324
- // this dict repreesnts the mapping
1325
- {
1326
- 0 : { }
1327
- 1 : {c : 0},
1328
- 2 : {t : 0, c : 1},
1329
- 3 : {t : 0, a : 1, c : 2}
1330
- 4 : {t : 0, a : 1, c : 3, o : 4}
1331
- 5 : {t : 0, a : 1, c : 3, o : 4, s : 5}
1332
- }
1333
-
1334
- // this array contruct implements the above dict mapping more compactly
1335
- var i,idx = [[],["c"], ["t","c"], ["t","a","c"],["t","a","c","o"],["t","a","c","o","s"]];
1336
- for (i=0; i< x.length; i++)
1337
- hd[idx[x.length]][i] = x[i];
1338
-
1339
- returns [BWHTMLNode object,errorInfoString]
1340
-
1341
- */
1342
-
1343
- var err="",dopts = {
1344
- functionExec : true, // if this node data is a function, execute it with no params eg x ====> x()
1345
- atomic2span : false // convert atomic strings to a span element
1346
- };
1347
-
1348
- dopts = optsCopy(dopts,opts);
1349
- var isv = bw.htmlIsVoidTag;
1350
- var isnu = function(x) {return bw.toa(x,["null","undefined"],true,false);}; // is x null or undefined
1351
- var HTMLNode = function BW_HTMLNode() {this.t="div"; this.a={}; this.c=[]; this.o={tagClose:"auto"}; this._is_BW_HTMLNode=true;}; //isBWHTMLNode is for IE compatiblity
1352
- //function bwError (v,x) {this.value=v; this.msg = (typeof x == "undefined") ? "error" : x;}
1353
-
1354
- var i,n = new HTMLNode(); // default html dict format
1355
- switch (bw.to(x)) {
1356
- case "null" :
1357
- case "undefined" :
1358
- n = "";
1359
- err = "error: html node content is " + bw.to(x);
1360
- break;
1361
- case "object":
1362
- [["tag","t"],["attrib","a"],["content","c"],["options","o"]].forEach(function(z){ n[z[1]]= z[0] in x ? x[z[0]] : n[z[1]];});
1363
- for (i in n) { // we only copy those fields we care about..
1364
- n[i] = (i in x) ? x[i] : n[i]; // need to handle complicated types: t:"", a:{}, c:"" | []
1365
- if (isnu(n[i])) {
1366
- n = ""; // force entire object to be null or undefined
1367
- err = ("Error HTMLNode : a field is null or undefined");
1368
- break;
1369
- }
1370
- }
1371
- break;
1372
- case "BW_HTMLNode" :
1373
- for ( i in x) { n[i] = x[i];}
1374
- break;
1375
- case "array":
1376
- var idx = [[],["c"], ["t","c"], ["t","a","c"],["t","a","c","o"]];
1377
- var m = (x.length > 4) ? 4 : x.length;
1378
- for (i=0; i< m; i++) {
1379
- // console.log(idx[m][i] + ":" + x[i]);
1380
- n[idx[m][i]] = x[i];
1381
- }
1382
- for (i in n)
1383
- if (isnu(n[i])) {
1384
- n = "";
1385
- err = "Error HTMLNode : bad array array input";
1386
- break;
1387
- }
1388
- //n.c = _toa(n.c,"array",n.c,[n.c]);
1389
- break;
1390
- case "function": // this whole node is a function
1391
- var h;
1392
- if (dopts.functionExec) {
1393
- h = bw.htmlNode(x(),dopts);
1394
- n=h.node;
1395
- err = h.error;
1396
- }
1397
- else
1398
- n=h;
1399
- break;
1400
- default: // string, number, Date, bool, Regex ==> will be come just plain rendered content later
1401
- if (dopts.atomic2span) {
1402
- n.c =[x.toString()];
1403
- n.t = "span";
1404
- }
1405
- else
1406
- n = x.toString();
1407
- }
1408
- var r= {
1409
- node : n,
1410
- ntype : bw.typeOf(n), // BW_HTMLNode | string | function
1411
- error : err,
1412
- isVoidTag : (bw.typeOf(n)=="BW_HTMLNode")? isv(n.t) : false
1413
- };
1414
-
1415
- return r;
1416
- };
1417
- // ===================================================================================
1418
- bw.htmlEmit = function(htmlData, opts, state) {
1419
-
1420
- var dopts = {
1421
- tagClose : "inherit",
1422
- htmlEscContent : false // change spaces, /n /t to html equivalents
1423
- };
1424
-
1425
- state = bw.toa(state,["undefined","null"], {
1426
- nodesCnt : 0,
1427
- levelCnt : 0,
1428
- levelMax : 0
1429
- },state);
1430
-
1431
- dopts = optsCopy(dopts,opts);
1432
-
1433
- var _atr = function(n){
1434
- // handle "smart" attributes ==>
1435
- // class : ["class1", "class2"] ==> style : bw.makeCSS(),
1436
- // functions e.g. onclick:function(){} // html on... events can be encoded auto e.g. onclick=function() ==> onclick=bw.registerfunction(... )
1437
-
1438
- var as = [], k,v,vr;
1439
-
1440
- for (k in n.a) {
1441
- v = n.a[k]; // now we have k, v
1442
- if (v == null) {
1443
- as.push(k); //null values are ignored. e.g.g {t:"div", a:{checked:null, c:...} ==> <div checked /> ...
1444
- continue;
1445
- }
1446
- if (k.search(/^on/) >=0 ) { // its a on... hanlder
1447
- if (bw.to(v) == "function") {
1448
- if (n.o["atrOnEventRegister"] == false) {
1449
- vr = String(v()); // its a function but execute it and return a string value
1450
- }
1451
- else { // register it
1452
- vr = bw.funcGetDispatchStr(bw.funcRegister(v),"this"); //
1453
- }
1454
- }else { // not a function but some other type
1455
- vr = "";
1456
- try {
1457
- vr = v.toString();
1458
- } catch (e) { vr = String(v);}
1459
- }
1460
- }
1461
- else // not an "on" handler
1462
- {
1463
-
1464
- switch(k) {
1465
- case "style" :
1466
- if (_to(v) == "string")
1467
- vr=v.toString();
1468
- else
1469
- vr = bw.makeCSSRule(["",v],{pretty:false}).trim().replace(/^{/,"").replace(/}$/,"").trim();
1470
- break;
1471
- default :
1472
- if (bw.to(v)=="array")
1473
- vr = v.join(" ");
1474
- vr = v.toString();
1475
- }
1476
- }
1477
- as.push(k+"="+"\""+vr.replace("\"","\\\"")+"\"");
1478
- }
1479
- as = as.join(" ");
1480
- return (as.length > 0 ? " ": "") + as + (as.length > 0 ? " ": "");
1481
- };
1482
-
1483
- var h=[],n= bw.htmlNode(htmlData);
1484
-
1485
- if (_to(n.node) == "function") {
1486
- n = bw.htmlNode(n.node());
1487
- n = _toa(n.ntype,["BW_HTMLNode","string"],n,""); // if its still not a string or BW_HTMLNode we just need to punt it.
1488
-
1489
- }
1490
- state.nodesCnt++;
1491
- if (n.ntype != "BW_HTMLNode") {
1492
- h.push( dopts.htmlEscContent ? bw.htmlSafeStr(n.node.toString()) : n.node.toString() );
1493
- }
1494
- else { // bw_HTMLNode
1495
-
1496
- if (n.node.t != "")
1497
- h.push("<",n.node.t, _atr(n.node)); // add tag
1498
-
1499
-
1500
- var tagClose = dopts.tagClose != "inherit" ? dopts.tagClose : n.node.o.tagClose;
1501
- switch(tagClose) {
1502
- /*eslint no-fallthrough: [0, { "commentPattern": "break[\\s\\w]*omitted" }]*/
1503
- case "auto":
1504
- if (n.isVoidTag){
1505
- // <tag a{} /> # content is not rendered for void tags # ["<",n.t , a{}, "/>" ]
1506
- h.push( "/>");
1507
- break;
1508
- }
1509
-
1510
- case "all":
1511
- default:
1512
- //<tag a{}> .... </tag> # h=["<",n.t , a{}, crend() , "</", n.t, ">"]
1513
- if (n.node.t != "")
1514
- h.push(">");
1515
- var i,x;
1516
- if (bw.typeOf (n.node.c) != "array") {
1517
- state.levelCnt++;
1518
- state.levelMax = state.levelCnt > state.levelMax ? state.levelCnt : state.levelMax;
1519
- x = bw.htmlEmit(n.node.c,dopts,state);
1520
- state.levelCnt--;
1521
- h.push(x.html);
1522
- }
1523
- else {
1524
- for (i in n.node.c) {
1525
- state.levelCnt++;
1526
- state.levelMax = state.levelCnt > state.levelMax ? state.levelCnt : state.levelMax;
1527
- x= bw.htmlEmit(n.node.c[i],dopts,state);
1528
- state.levelCnt--;
1529
- h.push(x.html);
1530
- }
1531
- }
1532
- if ( tagClose != "none" ) {
1533
- if (n.node.t != "")
1534
- h.push( "</",n.node.t,">");
1535
- }
1536
- }
1537
-
1538
- }
1539
- var html = h.join("");
1540
- return {html: html, state: state};
1541
- };
1542
- // ===================================================================================
1543
- bw.html = function(data,options) {
1544
- return bw.htmlEmit(data,options).html;
1545
- };
1546
- // ===================================================================================
1547
- bw.htmla = function (listData,options) {
1548
- /**
1549
- bw.htmla(listData,options)
1550
-
1551
- listData is a single dim array of bw.html() compatible cnostructs
1552
-
1553
- */
1554
- if (_to(listData) != "array")
1555
- return bw.html(listData,options);
1556
-
1557
- return listData.map( function(x) {return bw.html(x,options);}).join("");
1558
- };
1559
-
1560
- // ===================================================================================
1561
- bw.htmlList = function (listData, listType, atr, atri) {
1562
- /**
1563
- bw.makeHTMLList (listData, listType, attribute{}, attribute_for_each_items {})
1564
-
1565
- listType = "ul" | "ol"
1566
- listData = [ item1, item2, item3, .. ]
1567
-
1568
- */
1569
- if (_to(listData) != "array")
1570
- return "";
1571
-
1572
- if (listData.length < 1)
1573
- return "";
1574
-
1575
- atr = _toa(atr,"object",atr,{});
1576
- atri = _toa(atr,"object",atr,{});
1577
-
1578
- var lc = listData.map(function(x){return bw.html(["li",atri,x]);});
1579
- listType = ["ul","ol"].indexOf(listType)== -1 ? "ol" : listType;
1580
- return bw.html ({t:listType,a:atr,c:lc});
1581
- };
1582
-
1583
- // ===================================================================================
1584
- bw.openFullScreen = function () {
1585
- /**
1586
- bw.openFullScreen() attempt to open the document full screen (usefull for signs, banners)
1587
- */
1588
- var elem = document.documentElement;
1589
- if (elem.requestFullscreen) {
1590
- elem.requestFullscreen();
1591
- } else if (elem.mozRequestFullScreen) { /* Firefox */
1592
- elem.mozRequestFullScreen();
1593
- } else if (elem.webkitRequestFullscreen) { /* Chrome, Safari and Opera */
1594
- elem.webkitRequestFullscreen();
1595
- } else if (elem.msRequestFullscreen) { /* IE/Edge */
1596
- elem.msRequestFullscreen();
1597
- }
1598
- };
1599
-
1600
- // ===================================================================================
1601
- bw.classStrAddDel = function (classData,classesToAdd,classesToDel) {
1602
- /**
1603
- classStrAddDel (classData, classesToAdd, classesToDel)
1604
- for CSS classes
1605
-
1606
- takes a valid classData string e.g. "myclass1 myclass2" etc
1607
-
1608
- and adds/del classes from classesToAdd string if they are not already present in classData
1609
-
1610
- classStrAddDel("class1 class2", "class3") ==> "class1 class2 class3"
1611
- classStrAddDel("class1 class2", "class3 class4") ==> "class1 class2 class3 class4"
1612
- classStrAddDel("class1 class2", "class2 class3") ==> "class1 class2 class3" // doesn't add class2 again
1613
-
1614
- classStrAddDel("class1 class2", "class 2 class3",class1) ==> "class2 class3" // doesn't add class2 again. removes class1
1615
- classStrAddDel("class1 class2", "",class1) ==> "class2" // removes class1
1616
-
1617
- classData, classesToAdd, classesToDel may be strings (space delimited) or arrays of strings (["c1", "c2"], ["c3", "c4"], ["c1"])
1618
- */
1619
-
1620
- var tnorm = function(x){x=bw.toa(x,"undefined",[],x); return (bw.to(x)=="array")? x : x.toString().trim().split(/\s+/ig);};
1621
- var c = tnorm(classData);
1622
- var ca = tnorm(classesToAdd);
1623
- var cd = tnorm(classesToDel);
1624
- return bw.arrayBNotInA(cd,c.concat(ca)).join(" ").trim().replace(/\s+/ig," ");
1625
-
1626
- };
1627
- // ===================================================================================
1628
- bw.classStrToggle = function (classData, classesToToggle) {
1629
- /**
1630
- classStrToggle (classData, classesToToggle)
1631
-
1632
- toggles classes listed in classesToToggle
1633
-
1634
- takes a valid classData string e.g. "myclass1 myclass2" etc
1635
- */
1636
- var tnorma = function(x){x=bw.toa(x,"undefined",[],x); return (bw.to(x)=="array")? x : x.toString().trim().split(/\s+/ig);};
1637
- var c = tnorma(classData);
1638
- var t = tnorma(classesToToggle);
1639
- return bw.classStrAddDel(classData,bw.arrayBNotInA(c,t),bw.arrayBinA(c,t));
1640
- };
1641
-
1642
- // ===================================================================================
1643
- bw.htmlTabs = function(tabData, opts) {
1644
- /**
1645
- bw.makeHTMLTabs(tabData, atr)
1646
- tabData = [[tab1Title,tab1-content], [tab2Title,tab2-content], [tab3Title,tab3-content]]
1647
- */
1648
- if (_to(tabData) != "array")
1649
- return "";
1650
- if (tabData.length < 1)
1651
- return "";
1652
-
1653
- var dopts = {
1654
- atr : {"class":""}, //container {}
1655
- tab_atr : {"class":""}, //attributs for each tab container
1656
- tabc_atr: {"class":""}, //attributes for each tab-content area container
1657
- indent : "", //indent string for pretty printing
1658
- pretty : false
1659
- };
1660
- dopts = optsCopy(dopts,opts);
1661
-
1662
- var ti = tabData.map(function(x){return ["li",{"class":"bw-tab-item", "onclick":"bw.selectTabContent(this)"},x[0]];});
1663
- var tc = tabData.map(function(x){return ["div",{"class":"bw-tab-content"},x[1]];});
1664
-
1665
- ti[0][1]["class"] = bw.classStrAddDel(ti[0][1]["class"], "bw-tab-active");
1666
- tc[0][1]["class"] = bw.classStrAddDel(tc[0][1]["class"], "bw-show");
1667
-
1668
- dopts["atr" ]["class"] = bw.classStrAddDel (dopts["atr" ]["class"],"bw-tab-container");
1669
- dopts["tab_atr" ]["class"] = bw.classStrAddDel (dopts["tab_atr" ]["class"],"bw-tab-item-list");
1670
- dopts["tabc_atr"]["class"] = bw.classStrAddDel (dopts["tabc_atr"]["class"],"bw-tab-content-list");
1671
-
1672
- return bw.html({t:"div",a: dopts["atr"],c:[["ul",dopts["tab_atr"],ti],["div",dopts["tabc_atr"],tc]]});
1673
- };
1674
-
1675
-
1676
- // ===================================================================================
1677
-
1678
- bw.htmlTable = function(data,opts) {
1679
- /**
1680
- bw.makeHTMLTableStr (data, options)
1681
-
1682
- Creates an HTML table element (as a string) from raw array data.
1683
-
1684
- var table1 =
1685
- [["this", "that", "the", "other"],[,6,4,0,4],[3,5,1,4],[1,2,4,5],["2u30","23",function(){return 834},23]];
1686
- document.getElementById("myTableDiv") = bw.makeHTMLTableStr(table1); // displays simple table.
1687
-
1688
- var options = {
1689
- useFirstRowAsHeaders:false, // first row is data
1690
- caption:"Important Table" // caption
1691
- sortable: false | true | function // make table sortable (false is default, if true uses bw built-in sort, else supply function)
1692
- }
1693
- document.getElementById("myTableDiv") = bw.htmlTable(table1, options);
1694
-
1695
- Options:
1696
- useFirstRowAsHeaders : true; //
1697
- */
1698
- if ((_to(data) != "array") || (data.length < 1))
1699
- return "";
1700
-
1701
- //default options
1702
- var dopts = {
1703
- useFirstRowAsHeaders : true,
1704
- useDefaultStyle : true, // for
1705
- atr : {}, // attributes for table object can use function() for dynamic
1706
- thead_atr : {}, // attributes for table head section
1707
- th_atr : {}, // attributes for header cells,
1708
- tbody_atr : {}, // atttributs for table body section
1709
- tr_atr : {}, // attributes for rows
1710
- td_atr : {}, // attributes for cells
1711
- caption : "", // optional table caption (can be HTML, or function, bw.buildHTMLObjString compatible data)
1712
- sortable : false// make table sortable. if true, uses default sort, otherwise pass function to sort table. f(a,b,optionalColumnNumber)
1713
- };
1714
-
1715
- var i=0,head="",body="",r,_hs=bw.html;
1716
- dopts = optsCopy(dopts,opts);
1717
-
1718
- if (dopts.useDefaultStyle) {
1719
- // dopts.atr["class"] = "bw-table-stripe bw-table-col0-bold bw-table-compact bw-table-border-round bw-table-head bw-table-cellpad";
1720
- dopts.atr["class"] = "bw-table bw-table-stripe";
1721
- }
1722
- if (dopts.sortable == true) {
1723
- dopts.th_atr["onclick"] = "bw.sortTableDispatch(this)";
1724
- if ("class" in dopts.th_atr)
1725
- dopts.th_atr["class"] += dopts.th_atr["class"].split(/[ ]+/).indexOf("bw-table-sort-xxa") <0 ? " bw-table-sort-xxa" : "";
1726
- else
1727
- dopts.th_atr["class"] = "bw-table-sort-xxa";
1728
- }
1729
- else {
1730
- if (_to(dopts.sortable) == "function") {
1731
- var sfid = bw.funcRegister(dopts.sortable);
1732
- dopts.th_atr["onclick"] = bw.funcGetDispatchStr(sfid,"this");
1733
- }
1734
- }
1735
-
1736
- if (dopts["useFirstRowAsHeaders"]) {
1737
- head=data[0].map(function(x){return _hs({t:"th",a:dopts.th_atr,c:x});}).join("");
1738
- head= _hs({t:"tr",a:dopts.tr_atr,c:head});
1739
- i=1;
1740
- }
1741
- else
1742
- i=0;
1743
- head = bw.html({t:"thead",a:dopts.thead_atr,c:head});
1744
-
1745
- for (; i<data.length; i++) {
1746
- r = data[i].map(function(x){return _hs({t:"td",a:dopts.td_atr,c:x});}).join("");
1747
- body+= _hs({t:"tr",a:dopts.tr_atr,c:r});
1748
- }
1749
- body = bw.html({t:"tbody",a:dopts.tbody_atr,c:body});
1750
- //console.log(head,'\n',body);
1751
- dopts.caption = dopts.caption == "" ? "" : _hs({t:"caption",a:{},c:dopts.caption});
1752
- return _hs({t:"table",a:dopts.atr,c:[dopts.caption,head,body]});
1753
- };
1754
-
1755
-
1756
- bw.htmlAccordian = function (data, opts) {
1757
- /**
1758
- htmlAccordian
1759
-
1760
- [[data-title, data-to-show, {show: true|false}], // show determines whether the default content is visible
1761
- [...]]
1762
-
1763
- data-title and data-to-show can be strings or any valid bw.html() constructs
1764
- */
1765
- var s = "";
1766
- if (_to(data) !== "array")
1767
- return s;
1768
-
1769
- var dopts = {
1770
- "atr" : { "class": "bw-accordian-container"}, // div for overall accordian
1771
- "atr_h" : { "onclick":"bw.DOMClassToggle(this.nextSibling,'bw-hide')", "class" : "bw-thm-light"}, // div wrapping each header
1772
- "atr_c" : { "class":"bw-hide"} // div wrapping each content
1773
- };
1774
- dopts = optsCopy(dopts,opts);
1775
- dopts.atr_h["onclick"]="bw.DOMClassToggle(this.nextSibling,'bw-hide')";
1776
- //dopts.atr_h["class"]="bw-thm-light";
1777
- //console.log(dopts);
1778
- s = data.map(function(x){
1779
- var a=dopts["atr_c"],show;
1780
- show = ( (x.length > 2) && (x[2].show==true));
1781
-
1782
-
1783
- if (a["class"]) {
1784
- a["class"] = show ? bw.classStrAddDel(a["class"],"","bw-hide"):bw.classStrAddDel(a["class"],"bw-hide") ;
1785
- }
1786
- else a["class"]=show ? "":"bw-hide";
1787
-
1788
- return bw.html({t:"div",a:dopts["atr_h"],c:[x[0]]})+bw.html({t:"div",a:a,c:[x[1]]} );
1789
- }).join("");
1790
- s = bw.html({t:"div",a:dopts["atr"],c:[s]});
1791
- return s;
1792
- };
1793
- // ===================================================================================
1794
- bw.htmlSign = function (content, opts) {
1795
- /**
1796
- htmlSign("my content",options)
1797
- create a centered banner / billboard
1798
- */
1799
- var dopts = {
1800
- atr : {style:{"font-weight":"700", "font-size":"7em"}},
1801
- escContent : false,
1802
- };
1803
-
1804
- dopts = optsCopy(dopts,opts);
1805
- content = dopts.escContent!=false ? bw.htmlSafeStr(content) : content;
1806
- var c = {a:{class:"bw-sign" },c:[{c:{a:dopts.atr, c:[content]}}]};
1807
- //{a:{class:"bw-jumbo"},c:[{c:{ c:"foo"}}]}
1808
- return bw.html(c);
1809
- };
1810
- // ===================================================================================
1811
- bw.getFile = function (fname,callback_fn, options) {
1812
- /**
1813
- bw.getFile(filename,callback)
1814
- Attempt to load a file.
1815
- Works both client side and i nodejs.
1816
- */
1817
- var dops = {
1818
- parser : "raw" // valid types are "raw", "JSON", future "CSV", "TSV" or parserFunction
1819
- };
1820
-
1821
- dops = optsCopy(dops,options);
1822
-
1823
- if (_to(fname) != "string") {
1824
- return "invalid filename";
1825
- }
1826
-
1827
- var prs = (dops["parser"]=="JSON") ? JSON.parse : function(s){return s;};
1828
-
1829
-
1830
- if (bw.isNodeJS() ==true) {
1831
- var fs = require("fs");
1832
- fs.readFile(fname, "utf8", function (err, data) { if (err) throw err; callback_fn(prs(data)); });
1833
- }
1834
- else // running in a browser
1835
- {
1836
- var x = new XMLHttpRequest();
1837
- x.overrideMimeType("application/json");
1838
- x.open("GET", fname, true);
1839
- x.onreadystatechange =
1840
- function () {if (x.readyState == 4 && x.status == "200") {callback_fn(prs(x.responseText));}};
1841
- x.send(null);
1842
- }
1843
- return "BW_OK";
1844
- };
1845
-
1846
- bw.getJSONFile = function (fname,callback_fn) { return bw.getFile(fname,callback_fn,{"parser":"JSON"});};
1847
-
1848
- bw.copyToClipboard = function(data) {
1849
- /**
1850
- bw.copyToClipboard
1851
- simple copy content to clipboard. (browser only)
1852
- */
1853
-
1854
- /*
1855
- var temp = document.createElement("input");
1856
- var b = document.getElementsByTagName("body")[0];
1857
- b.appendChild(temp);
1858
-
1859
- temp.innerText = data;
1860
- temp.select();
1861
- document.execCommand("copy");
1862
- temp.remove();
1863
-
1864
-
1865
-
1866
- var temp = document.createElement("input");
1867
- document.getElementsByTagName("body")[0].append(temp);
1868
- temp.innerHTML = data;
1869
- //temp.val(data).select();
1870
-
1871
- //var temp = document.createElement("input");
1872
- //var b = document.getElementsByTagName("body")[0];
1873
- //b.appendChild(temp);
1874
- //temp.innerText = data;
1875
- temp.select();
1876
- document.execCommand("copy");
1877
- temp.remove();
1878
- */
1879
- if (bw.isNodeJS())
1880
- return;
1881
- var listener = function (e) {
1882
- e.clipboardData.setData("text/html", data);
1883
- e.clipboardData.setData("text/plain", data);
1884
- e.preventDefault();
1885
- };
1886
- document.addEventListener("copy", listener);
1887
- document.execCommand("copy");
1888
- document.removeEventListener("copy", listener);
1889
- };
1890
-
1891
- // ===================================================================================
1892
- bw.saveClientFile = function(fname,data) {
1893
- /**
1894
- bw.saveClientFile(fname,data) saves data the program the client environtmnet
1895
- fname is filename to save as
1896
- data is data to save.
1897
-
1898
- works both in node and browser.
1899
- */
1900
- if (bw.isNodeJS()) {
1901
- var fs = require("fs");
1902
- fs.writeFile(fname, data, function (err) {
1903
- if (err) return bw.log(err);
1904
- bw.log("error saving ",fname,data);
1905
- });
1906
- }
1907
- else { // we're in a browser
1908
-
1909
- var saveData = (function () {
1910
- var a = document.createElement("a");
1911
- document.body.appendChild(a);
1912
- a.style = "display: none";
1913
- return function (data, fname) {
1914
- var json = JSON.stringify(data),
1915
- blob = new Blob([json], {type: "octet/stream"}),
1916
- url = window.URL.createObjectURL(blob);
1917
- a.href = url;
1918
- a.download = fname;
1919
- a.click();
1920
- window.URL.revokeObjectURL(url);
1921
- };
1922
- }());
1923
- saveData(data,fname);
1924
- }
1925
- };
1926
-
1927
- // ===================================================================================
1928
- //Timers ... clear / read / fixed number of events
1929
-
1930
- // ===================================================================================
1931
- // crude performance measurements
1932
- var gBWTime = (new Date()).getTime(); //global closure for time. 'cause we always want a gbw gbw time :)
1933
-
1934
- // ===================================================================================
1935
- bw.clearTimer = function (message) {
1936
- /**
1937
- bw.clearTimer("message")
1938
- When bitwrench loads its starts a timer which can be checked at any time as a ref running (see bw.readTimer()).
1939
- bw.clearTimer() clears the timer with optional message.
1940
- */
1941
- gBWTime = (new Date()).getTime();
1942
- if (_to(message) != "undefined")
1943
- bw.logd(String(message));
1944
- return gBWTime;
1945
- };
1946
-
1947
- // ===================================================================================
1948
- bw.readTimer = function (message) {
1949
- /**
1950
- bw.readTimer("message")
1951
- When bitwrench loads its starts a page timer which can be checked for how long the page as been running.
1952
- */
1953
- var ct = (new Date()).getTime();
1954
- if (_to(message) != "undefined")
1955
- bw.logd(String(message));
1956
- return ct-gBWTime;
1957
- };
1958
- bw.clearTimer(); //when bw is loaded, we start the timer.
1959
-
1960
- // ===================================================================================
1961
- bw.setIntervalX = function (callback, delay, number_of_repetitions) {
1962
- /**
1963
- bw.setIntervalX(callbackFn, delayBtwCalls, repetitions)
1964
- set a javascript timer to only run a max of N repetions.
1965
-
1966
- Example:
1967
- bw.setIntervalX(function(x){console.log(x)},100,5)
1968
- this will the function 5 times 100ms apart
1969
- */
1970
- var x = 0;
1971
- var intervalID = setInterval(function () {
1972
- callback(x);
1973
-
1974
- if (++x >= number_of_repetitions) {
1975
- clearInterval(intervalID);
1976
- }
1977
- }, delay);
1978
- };
1979
-
1980
- // ===================================================================================
1981
- bw.repeatUntil = function (testFn, successFn, failFn, delay, maxReps, lastFn) {
1982
- /**
1983
- bw.repeatUntil()
1984
- repeatUntil runs the supplied testFn every delay milliseconds up until a maxReps number of times.
1985
- if the test function returns true it runs the successFn and stops the iterations.
1986
- then the lastFn is called with the params (true, number_of_attempts).
1987
- lastFn is optional.
1988
-
1989
- for each time the testFn is called and fails, the failFn() is called.
1990
-
1991
- After the last rep has been completed the lastFn is called with (with the last testFn result and
1992
- with the current iteration).
1993
-
1994
-
1995
- lastFn is optional.
1996
- failFn is optional
1997
-
1998
- Example:
1999
- bw.repeatUntil( myLibsAndDataAreLoaded_fn, renderMyChart, null, 250, 10, null); // attempts to wait until mylib is loaded 10 times before giving up
2000
-
2001
- */
2002
- var _count = 0;
2003
- if (typeof testFn != "function")
2004
- return "err";
2005
- if (typeof delay != "number")
2006
- delay = 250; // 250ms
2007
- if (typeof maxReps != "number")
2008
- maxReps = 1; // run 1 time.
2009
-
2010
- var _testFn = testFn;
2011
- var _successFn = (typeof successFn == "function") ? successFn : function () {};
2012
- var _failFn = (typeof failFn == "function") ? failFn : function () {};
2013
- var _lastFn = (typeof lastFn == "function") ? lastFn : function () {};
2014
-
2015
- var _f = function () {
2016
- var success = _testFn();
2017
- if (true == success) {
2018
- _successFn();
2019
- _lastFn(true, _count);
2020
- }
2021
- else {
2022
- _failFn();
2023
-
2024
- if (_count >= maxReps) {
2025
- _lastFn(success, _count);
2026
- }
2027
- else {
2028
- _count++;
2029
- window.setTimeout(_f, delay);
2030
- }
2031
- }
2032
- };
2033
- _f();
2034
- };
2035
- // =============================================================================================
2036
- /*
2037
- bw.htmlDataToImg = function(data, opts) {
2038
- /**
2039
- htmlDataToImg(data, opts) // takes a 2D array of numbers and render as an image
2040
- each data point must evaluate to a Number or be a function which will be called with its positional arguments and must return a number.
2041
-
2042
- OR
2043
-
2044
- function can be a string as long as it returns a valud HTML color prefixed with "#"
2045
-
2046
- e.g.
2047
- "#123"
2048
- "#112233"
2049
-
2050
- e.g.:
2051
- function (return 23)
2052
- function(x,y) { return x+y;}
2053
-
2054
- * /
2055
- var dopts = {
2056
- outputType : "canvas" , // "table" | "divs" | "svg"
2057
- colorMode : "auto", // use greyscale map
2058
- colorStretch: 1.0
2059
- }
2060
-
2061
- dopts = optsCopy(dopts,opts);
2062
- // if (_to(dopts["colorMapFn"]) != "function")
2063
- // dopts["colorMapFn"] = function(x){var c= mapScale(x,0,255,0,255,true).}
2064
-
2065
-
2066
-
2067
- }
2068
- */
2069
- // =============================================================================================
2070
- bw.naturalCompare = function (as, bs){
2071
- /**
2072
- bw.naturalCompare(a,b) {
2073
- bw.naturalCompare() is a function which can be passed to an array sort to provide natural sorting of mixed array elements.
2074
-
2075
- [3,4,2,1,"10","111","foo","bar","01","this123","This123", "848"].sort()
2076
- vs
2077
- [3,4,2,1,"10","111","foo","bar","01","this123","This123", "848"].sort(bw.naturalCompare)
2078
-
2079
- it is the default sort for bw.sortHTMLTable()
2080
-
2081
- */
2082
- //https://www.webdeveloper.com/forum/d/254726-sorting-alphanumeric-array (taken from here) see also
2083
- //using .localCompare() in newer versions of JS
2084
-
2085
- var a, b, a1, b1, i= 0, L, rx= /(\d+)|(\D+)/g, rd= /\d/;
2086
- if(isFinite(as) && isFinite(bs)) return Math.sign(as - bs);
2087
- a= String(as).toLocaleLowerCase();
2088
- b= String(bs).toLocaleLowerCase();
2089
- if(a=== b) return (as > bs) ? 1 : 0;
2090
- if(!(rd.test(a) && rd.test(b))) return a> b? 1:-1;
2091
- a= a.match(rx);
2092
- b= b.match(rx);
2093
- L= a.length> b.length? b.length:a.length;
2094
- while(i<L){
2095
- a1= a[i];
2096
- b1= b[i++];
2097
- if(a1!== b1){
2098
- if(isFinite(a1) && isFinite(b1)){
2099
- if(a1.charAt(0)=== "0") a1= "." + a1;
2100
- if(b1.charAt(0)=== "0") b1= "." + b1;
2101
- return a1 - b1;
2102
- }
2103
- else return a1> b1? 1:-1;
2104
- }
2105
- }
2106
- return Math.sign(a.length - b.length);
2107
- };
2108
-
2109
- // =============================================================================================
2110
- bw.sortHTMLTable = function (table, col, dir, sortFunction) {
2111
- /**
2112
- bw.sortHTMLTable(table, column, optionalSortFunction).
2113
-
2114
- sort any HTML table active in the DOM
2115
- table must be a valid DOM table element or CSS selector (first element is used)
2116
-
2117
- default uses string compare. but can pass in a function
2118
- sortFunc(a,b,col) // a and b are the cells to compare, col is optional info on what column this is
2119
- */
2120
-
2121
- var rows, switching, i, x, y, shouldSwitch;
2122
- var sortF = _to(sortFunction) == "function" ? sortFunction : bw.naturalCompare;
2123
-
2124
- table = bw.DOM(table)[0];
2125
-
2126
- dir = (dir==true) || (dir=="up") ? true : false;
2127
-
2128
- switching = true;
2129
- col = _to(col) == "number" ? col : 0; //default sort on left most column
2130
-
2131
- //Make a loop that will continue until no switching has been done
2132
- while (switching) {
2133
- //start by saying: no switching is done:
2134
- switching = 0;
2135
- rows = table.getElementsByTagName("TR");
2136
- /*Loop through all table rows (except the first, which contains table headers):*/
2137
- for (i = 1; i < (rows.length - 1); i++) {
2138
- //start by saying there should be no switching:
2139
- shouldSwitch = 0;
2140
- /*Get the two elements you want to compare,
2141
- one from current row and one from the next:*/
2142
- x = rows[i].getElementsByTagName("TD")[col].innerHTML;
2143
- y = rows[i + 1].getElementsByTagName("TD")[col].innerHTML;
2144
-
2145
- //check if the two rows should switch place:
2146
-
2147
- shouldSwitch = (dir) ? sortF(x,y,col) > 0 : sortF(x,y,col) < 0;
2148
- if (shouldSwitch)
2149
- break;
2150
- }
2151
-
2152
- if (shouldSwitch) {
2153
- //If a switch has been marked, make the switch and mark that a switch has been done:
2154
- rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
2155
- switching = true;
2156
- }
2157
- }
2158
- };
2159
-
2160
- // =============================================================================================
2161
- bw.sortTableDispatch = function (item,fn) {
2162
- /**
2163
- bw.sortTableDispatch(el) is used to bind sorting functions to tables generated by bw.htmlTable(....)
2164
- item must be a valid DOM element or id.
2165
- */
2166
- var i;
2167
-
2168
- item = bw.DOM(item)[0];
2169
-
2170
- if (_to(item).substr(0,4) != "html")
2171
- return false; //something not right about this table element
2172
-
2173
- var index=0,dir;
2174
- var cols = item.parentElement.getElementsByTagName("th");
2175
- //update which tab selected
2176
- for (i=0; i< cols.length; i++) {
2177
- if (cols[i] == item) { // selected tab logic
2178
- index = i;
2179
- dir = bw.DOMClass(cols[i],"bw-table-sort-upa") ; // ifthe current col is already up..
2180
- if (dir) {
2181
- bw.DOMClass(cols[i],"bw-table-sort-upa", "bw-table-sort-dna" );
2182
- }
2183
- else { //dna or xxa
2184
- if (bw.DOMClass(cols[i],"bw-table-sort-dna")) {
2185
- bw.DOMClass(cols[i],"bw-table-sort-dna", "bw-table-sort-upa" );
2186
- } else
2187
- bw.DOMClass(cols[i],"bw-table-sort-xxa", "bw-table-sort-upa" );
2188
- }
2189
- }
2190
- else{ // its not the selected column so we clear the up / down arrow
2191
- bw.DOMClass(cols[i],"bw-table-sort-upa","");
2192
- bw.DOMClass(cols[i],"bw-table-sort-dna","");
2193
- bw.DOMClass(cols[i],"bw-table-sort-xxa","bw-table-sort-xxa");
2194
- }
2195
-
2196
- }
2197
- bw.sortHTMLTable(item.parentElement.parentElement.parentElement,index,dir,fn);
2198
- };
2199
- // ===================================================================================
2200
- /**
2201
- bw.function dispatch for DOM elements..
2202
-
2203
- the bw.fnRegistry{} is a dict of user supplied functions are assigned IDs by bitwrench. Using these IDs one can call the functions which is useful in DOM string contexts such as makeHTMLTable() or buildHTMLObjStr().
2204
- */
2205
- var _fnRegistry = {};
2206
- var _fnIDCounter = 0;
2207
-
2208
-
2209
- bw.funcRegister = function (fn, forceName) {
2210
- /**
2211
- bw.funcRegister()
2212
- register a function to be called by iD.
2213
- fn is any function or can be anonymous function.
2214
- (optional) forceName forces the returned ID used to be forceName. forceName must be only alpha and numeric chars.
2215
- forceName is useful when declaring static HTML content and one wants to use the bwFunctionDispatch but before bitwrench has been loaded or run.
2216
-
2217
- In this case in the static code call like this:
2218
-
2219
- <div class="..." onclick="bw.funcGetById('myFnName')(this)"> regular html content goes here </div>
2220
- <script ..>
2221
- function superDuperFunctionCode (a) { .... code for my function ... };
2222
- bw.funcRegister(superDuperFunctionCode,"myFnName"); //now when the element is clicked on superDuperFunctionCode() will be called.
2223
- </script>
2224
-
2225
- */
2226
- var fnID = "class_bwfn_" + _fnIDCounter;
2227
- _fnIDCounter++;
2228
- fnID = _to(forceName) == "string" ? forceName : fnID;
2229
- fnID.trim();
2230
- _fnRegistry[fnID] = fn;
2231
- return fnID;
2232
- };
2233
-
2234
- bw.funcUnregister = function (fnID) {
2235
- /**
2236
- bw.funcUnregister(fnID)
2237
- remove a function from the bitwrench dispatch registry
2238
- */
2239
- if (fnID in _fnRegistry)
2240
- delete _fnRegistry[fnID];
2241
- };
2242
-
2243
- bw.funcGetById = function(fnID,errFn) {
2244
- /**
2245
- bw.funcGetById(fnId, errFn)
2246
- allows a function to be exectued by its bw function ID.
2247
- bw.funcGetById(myId)(... args ...)
2248
-
2249
- errFn is optional function to call if fnID is not found.
2250
-
2251
- example:
2252
- var myFunc = bw.getFuncById("myFuncID"); // function must already be registered.
2253
- */
2254
- fnID = String(fnID);
2255
- if (fnID in _fnRegistry)
2256
- return _fnRegistry[fnID];
2257
- else {
2258
- var _id = fnID;
2259
- return (_to(errFn) == "function") ? errFn : function(){bw.log(_id,"bw.funcGetById(): unregistered fn error");} ;
2260
- }
2261
- };
2262
-
2263
- bw.funcGetDispatchStr = function (fnID, argstring) {
2264
- /**
2265
- bw.funcGetDispatchStr(fnID, argString)
2266
- create a string suitble for use in DOM element dispatch. note argstring is a literal so variables must be reduce to their values.
2267
- see bw.funcRegister() for getting valid IDs for user supplied functions.
2268
-
2269
- example: bw.funcGetDispatchStr("myFuncID","param1,param2")
2270
- */
2271
-
2272
- switch (_to(argstring)) {
2273
- case "string" :
2274
- case "number" :
2275
- argstring = String(argstring);
2276
- break;
2277
- case "array" :
2278
- argstring = argstring.join(",");
2279
- break;
2280
- case "function":
2281
- argstring = argstring();
2282
- break;
2283
- default:
2284
- argstring = "";
2285
- }
2286
-
2287
- return "bw.funcGetById('"+fnID+"')("+argstring+")";
2288
- };
2289
-
2290
- bw.funcGetRegistry = function() {
2291
- return _fnRegistry;
2292
- };
2293
-
2294
- // =============================================================================================
2295
- bw.loremIpsum = function (numChars, startSpot, startWithCapitalLetter) {
2296
- /**
2297
- bw.loremIpsum(numChars, startSpot)
2298
-
2299
- generate a simple string of Lorem Ipsum text (sample typographer's text) of numChars in length.
2300
-
2301
- if startSpot is supplied, it starts the string at the supplied index e.g. bw.loremIpsum(200, 50)
2302
- will supply 200 chars of loremIpsum starting at index 50 of the Lorem Ipsum sample text.
2303
-
2304
- if startWithCapitalLetter == true then the function will capitlize the first character or inject a capital letter if ihe first character isn't a capital letter.
2305
- default is true;
2306
-
2307
- Default is a paragraph of lorem ipsum (446 chars)
2308
- */
2309
-
2310
- startSpot = _to(startSpot) != "number" ? 0 : Math.round(startSpot);
2311
-
2312
- var l = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ";
2313
- startSpot = startSpot % l.length;
2314
- l= l.substring(startSpot, l.length) + l.substring(0,startSpot);
2315
-
2316
- if (_to(numChars) != "number")
2317
- numChars = l.length;
2318
-
2319
- var i=numChars, s="";
2320
-
2321
-
2322
- while (i>0) {
2323
- s+= (i < l.length) ? l.substring(0,i) : l;
2324
- i-= l.length;
2325
- }
2326
- if (s[s.length-1] == " ")
2327
- s= s.substring(0,s.length-1) + "."; // always end on non-whitespace. "." was chosen arbitrarily.
2328
- if (startWithCapitalLetter != false) {
2329
- var c = s[0].toUpperCase();
2330
- c = c.match(/[A-Z]/) ? c:"M";
2331
- s = c+s.substring(1,s.length);
2332
- }
2333
-
2334
- return s;
2335
-
2336
- };
2337
-
2338
- bw.docString = function (s, options) {
2339
- /**
2340
- bw.docString(functionAsString, options)
2341
- returns array of valid docStrings embedded in a string
2342
-
2343
- @param docType{string} : "jsdoc" | "python" | "custom" (python means triplequote (") 3 times), "custom" means supply delims
2344
- @param options {delims:[string,string]} : start, stop delimiters (only used if docType set to "custom")
2345
-
2346
- @return array{strings} : array of captured params
2347
-
2348
- */
2349
-
2350
- var dopts = {
2351
- docType : "jsdoc", // "js doc", "python", "other" (jsdoc is default)
2352
- delims : ["/**","*/"],
2353
- parseJSDocParams : false,
2354
- dropLeadin : false // removes lead-in whitespace or floating single * on each line e.g. " * @mycomment" ==> "@mycomment"
2355
- };
2356
- dopts = optsCopy(dopts,options);
2357
-
2358
- var _es = function (str) {return str.replace(/(?=[\\^$*+?.()|{}[\]])/g, "\\");}; // do escape of regex chars
2359
-
2360
- dopts["delims"] = bw.choice(dopts["docType"],{
2361
- "jsdoc" : ["/**","*/"],
2362
- "python": ["\"\"\"","\"\"\""], // old regex: /["]{3}([\s\S]*?)["]{3}/ig
2363
- "jspy" : ["/**\"\"\"","\"\"\"*/"] // js && python
2364
- },dopts["delims"]);
2365
-
2366
- var c = (_to(s)=="function") ? s.toString() : String(s);
2367
- var r = [];
2368
-
2369
- try {
2370
- var re = (new RegExp( _es(dopts["delims"][0])+ "\\s*\\n*([^\\*]|(\\*(?!\\/)))*" +_es(dopts["delims"][1]),"ig")); // "([\\s\\S]*?)"
2371
- r = c.match(re);
2372
- }
2373
- catch (e) {bw.log(String(e));}
2374
-
2375
- if (_to(r)=="array") {
2376
- r = r.map(function(x){return x.substring(dopts["delims"][0].length, x.length-dopts["delims"][1].length);}); // this is an array of the contents of docStrings which can still be multiline in thier own right
2377
- r = (dopts["dropLeadin"]==true) ? r.map(function(x){return x.split(/[\n\r]/).map(function(y){return bw.trim(y,"left")+"\n";});}) : r; // need to hanlde multiline stuff here
2378
- }
2379
- else
2380
- r=[];
2381
-
2382
- return r;
2383
- };
2384
- // =============================================================================================
2385
- bw.docStringParseLine = function(s) {
2386
- /**
2387
- Parse a single line of a jsdoc string.
2388
- @param {string} s - line of docstring to parse
2389
- @return - dict of line contents {source: s, field:string, name:string, description: string, types: type1,type2 }
2390
- if not a valid doc string line then returns source string only
2391
- */
2392
- var r={"source":s, "field" : "", "types":"", "name" :"", "description" : ""};
2393
- var a = s.replace(/^\s*(\/\*\*?)?|(\*\/)?\s*$/ig,""); // remove the comment markers if still there "/** my comment */"" ==> "my comment"
2394
- a = a.replace(/^\s*\**\s*/,""); // remove any cruft at beginning of line " * @myParam {}....." ==> "@myParam {}....."
2395
- if (a.charAt(0) == "@") { // if we have hit a @fieldname parameter we start parsing.
2396
- // ([str, regex, fieldStr, result{}]) ==> ([str, regex, fieldStr, result{}]) ::> ([str,result{},fieldStr,regex])
2397
- /*
2398
- var _tok = function(x){
2399
- var m = x[0].match(x[1]);
2400
- if (m != null) {x[4][3]=m[1];}
2401
- x[0] = x[0].replace(x[1],"");
2402
- return x;
2403
- }
2404
- */
2405
- //r = [[e,f],[e,f],[e,f],[e,f]].reduce(,_tok);
2406
-
2407
- var e,x;
2408
- var t = bw.trim;
2409
- e =/^@([A-Za-z0-9_<>[\]]*)/i;
2410
- x = a.match(e);
2411
- if (x != null) {r["field"] = t(x[1]);} else return r; // didn't match... opt out here
2412
- a = a.replace(e,"");
2413
-
2414
- e = /^\s*\{([A-Za-z0-9_|\s,.\-+!@#$%^&*()=[\]]*)\}/i;
2415
- x = a.match(e);
2416
- if (x != null) {r["types"]=t(x[1]);} // types is optional..
2417
- a = a.replace(e,"");
2418
-
2419
- e = /^\s*([\S]*)/i;
2420
- x = a.match(e);
2421
- if (x != null) {r["description"]=t(x[1]);} //
2422
- a = a.replace(e,"");
2423
-
2424
- e = /^\s*([\S]*)/i;
2425
- x = a.match(e);
2426
- if (x != null) {r["name"]=t(x[1]);} //
2427
- a = a.replace(e,"");
2428
-
2429
- // descrpition ==> name: "" description : "description"
2430
- // description we we ==> name: "" description : "description we we "
2431
- // name - description we we ==> name: "name" descrpition : "description we we"
2432
- // - description we we ==> name: "" description : "description we we"
2433
- if (r["name"].match(/^\s*-+\s*/) != null) {
2434
- r["name"] = r["description"];
2435
- r["description"] = t(a);
2436
- } else {
2437
- r["description"] = r["description"]+" "+r["name"]+" "+t(a);
2438
- r["name"] ="";
2439
- }
2440
- }
2441
- return r;
2442
- };
2443
- // =============================================================================================
2444
- bw.docStringParse = function(s) {
2445
- /**
2446
- @method bw.parseJsDocString() parse and extract info from a jsdoc style comment. expects there to be only a single docString comment
2447
- @description docStringParse parses a jsdoc string
2448
- and returns the paramters as an array which can be formatted for display or interrogtion.
2449
- @param{string} - a valid js docstring
2450
-
2451
- @returns An array of triplets [@param, {types}, comment info]
2452
- */
2453
-
2454
- /*
2455
- implementation notes:
2456
- the parser splits the candidate doc string in to lines.
2457
-
2458
- Examples:
2459
-
2460
- * Assign the project to an employee.
2461
- * @param {Object} - The employee who is responsible for the project. ==> ["@param","object","", "The employee who is resposnsible for the project"]
2462
- * @param {string} employee.name - The name of the employee.
2463
- * @param {string} employee.department - The employee's department.
2464
-
2465
-
2466
- */
2467
-
2468
-
2469
- s=bw.docString(s)[0];
2470
- var a = s.split("\n");
2471
- //console.log(a);
2472
- var i,r=[bw.docStringParseLine(a[0])];
2473
- for (i=1;i<a.length;i++) {
2474
- var l = bw.docStringParseLine(a[i]);
2475
- if (l["field"]=="") { // nothing parseable...
2476
- if (r[r.length-1]["field"]=="") {
2477
- r[r.length-1]["source"] += l["source"];
2478
- } else
2479
- r[r.length-1]["description"] += l["source"];
2480
- } else r.push(l);
2481
- }
2482
- return r;
2483
- };
2484
- // =============================================================================================
2485
- bw.isHexStr = function (str, allowChars) {
2486
- /**
2487
- isHexStr() returns a number of hex digits found or false if non-hex string.
2488
- allow is an optional string of characters "-+."etc to permit in the string.
2489
- the allow characters are not counted in the result
2490
-
2491
- examples:
2492
- bw.isHEXStr("123a") ===> 4
2493
- bw.isHEXStr("12-3a") ===> false
2494
- bw.isHEXStr("12-3a","-") ===> 4
2495
- */
2496
- if ( _to(str) == "string") {
2497
- str = str.replace(new RegExp("["+allowChars+"]","g"),"");
2498
- var isHexReg = new RegExp("^[0-9A-Fa-f]{"+str.length+"}$");
2499
- return (isHexReg.test(str) == true) ? str.length : false;
2500
- }
2501
- return false;
2502
- };
2503
-
2504
- // =============================================================================================
2505
- //bw.__monkey_patch_is_nodejs__ = "ignore"; //used in test suites. use carefully. only acceptable values are true, false, "ignore"
2506
- bw.__monkey_patch_is_nodejs__ = new (function() { var _t="ignore"; this.set=function(x){_t = _toa(x,"boolean",x,"ignore");}; this.get=function(){return _t;}; return this;});
2507
-
2508
- bw.isNodeJS = function () {
2509
- /**
2510
- bw.isNodeJS() ==> returns true if running in node environment (else browser)
2511
- */
2512
- if (bw.__monkey_patch_is_nodejs__.get() != "ignore")
2513
- return bw.__monkey_patch_is_nodejs__.get();
2514
- return (typeof module !== "undefined" && module.exports) !== false; //a hack will fix later
2515
- };
2516
- //console.log("=====",bw.isNodeJS())
2517
-
2518
- // =============================================================================================
2519
- bw.fixNum = function(num,digits) {
2520
- /**
2521
- bw.fixedNum(num,digits)
2522
-
2523
- Truncate a number at digits number of places.
2524
- bw.fixNum(1.2345,2) ===> 1.23
2525
- bw.fixNum(234.32,-2) ===> 200
2526
- */
2527
- num = Number(num);
2528
-
2529
- if (isNaN(num))
2530
- return NaN;
2531
-
2532
- digits = _to(digits) == "number" ? digits : 3;
2533
- num *= Math.pow(10,digits);
2534
-
2535
- //num = Math.trunc(num);
2536
- num = (num > 0) ? Math.floor(num) : Math.ceil(num); // some browsers don't support Math.trunc()
2537
-
2538
- num /= Math.pow(10,digits);
2539
- return num;
2540
- };
2541
-
2542
- // =============================================================================================
2543
- bw.multiArray = function (value, dims) {
2544
- /**
2545
- bw.multiArray(value, dims)
2546
-
2547
- return a multidimensional array where all cells are initialized to value.
2548
-
2549
- bw.multiArray(0,[4,5]) // returns 4x5 array of 0s
2550
- bw.multiArray("test",[4,5]) // returns 4x5 array of "test"
2551
-
2552
- this shorthand is available for single dim arrays
2553
- bw.multiArray(0,5) ===> returns 5x1 array of 0s
2554
-
2555
- bw.multiArray also accepts functions
2556
-
2557
- bw.multiArray(bw.random, [3,4]) ===> creates 3x5 array of random #s btw 0..100
2558
-
2559
- bw.multiArray(function(){return (new Date()).getTime();},[4,6] ) ==> returns values based on the Javascript date
2560
- */
2561
-
2562
- var v = function() { return (_to(value) == "function") ? value(): value;};
2563
- dims = _to(dims) == "number" ? [dims] : dims;
2564
-
2565
- var _array = function(a,dim) {
2566
- if(dim < dims.length) {
2567
- for(var i=0; i<dims[dim]; i++) {
2568
- a[i]= (dim== dims.length -1) ? v() : _array([],dim+1);
2569
- }
2570
- return a;
2571
- }
2572
- };
2573
- return _array([],0);
2574
- };
2575
-
2576
- // =============================================================================================
2577
- bw.clip = function (data, min, max) {
2578
- /**
2579
- @method: bw.clip(data, min, max) clips data in between min and max.
2580
-
2581
- Examples:
2582
- bw.clip(5,2,20) ==> 5 // already in range
2583
- bw.clip(1,2,20) ==> 2 // less than the min value so clips to min value
2584
- bw.clip([1,4,8,35], 2, 20) ==> [2,4,5,20]
2585
- */
2586
- var l = min < max ? min : max;
2587
- var h = max > min ? max : min;
2588
-
2589
- if (_to(data) == "array") {
2590
- return data.map(function(x){ return (x < l) ? l : ((x > h) ? h : x);});
2591
- }
2592
- else
2593
- return (data < l) ? l : ((data > h) ? h : data);
2594
- };
2595
-
2596
- // =============================================================================================
2597
- bw.mapScale = function (x, in0, in1, out0, out1, options) {
2598
- /**
2599
- @method: bw.mapScale()
2600
-
2601
- Map an input value x in its natural range in0...in1 to the output space out0...out1 with optional clipping
2602
- expScale allows sigmoidal warping to stretch input values contrained to a small range. (floating point scale factor)
2603
- x can be either a number or array of numbers.
2604
-
2605
- if options["clip"] = false, then mapScale will extrapolate outside of out0,out1
2606
-
2607
- //this is the function that oficially started bitwrench..
2608
- */
2609
- var dopts = {
2610
- clip : true,
2611
- expScale : false
2612
- };
2613
-
2614
- dopts = optsCopy ( dopts, options);
2615
-
2616
- if (in0==in1)
2617
- return x;
2618
- out0 = _toa(out0, "number", out0, 0);
2619
- out1 = _toa(out1, "number", out1, 1);
2620
-
2621
- var ms= function (z) {
2622
- if (dopts["expScale"]) {
2623
- var y = ((z-((in1+in0) / 2.0)) / (in1 - in0) ) * dopts["expScale"];
2624
- z = ((out1-out0)*(1/(1+Math.exp(-y)))) + out0;
2625
- }
2626
- else
2627
- z = (((z-in0)/(in1-in0))*(out1-out0))+out0;
2628
-
2629
- if (dopts["clip"])
2630
- z= bw.clip(z,out0,out1);
2631
- return z;
2632
- };
2633
-
2634
- if (_to(x) == "number")
2635
- return ms(x);
2636
- return x.map(ms);
2637
- };
2638
-
2639
- // =============================================================================================
2640
- //https://stackoverflow.com/questions/10073699/pad-a-number-with-leading-zeros-in-javascript
2641
- bw.padNum = function(x, width, options) {
2642
- /**
2643
- @description bw.padnum() takes a number and pads left pads (default is '0'). padNum also accepts strings so
2644
-
2645
- bw.padNum(123,5) ==> " 123"
2646
- bw.padNum(1234,5) ==> " 1234"
2647
- bw.padNum("foo",5)==> " foo"
2648
- @param x {number}
2649
- @return {string} padded number
2650
- */
2651
- var dopts = {
2652
- pad : " "
2653
- };
2654
- dopts = optsCopy(dopts, options);
2655
- x = String(x);
2656
- return (x.length >= width) ? x : new Array(width - x.length+1).join(dopts["pad"]) + x;
2657
- };
2658
- // =============================================================================================
2659
- bw.trim = function (s, dir) {
2660
- /**
2661
- @description bw.trim() trims whitespace from string on either left, right, or both. (cross browser works before IE8)
2662
- @param s {string} : a string to trim white space on
2663
- @param dir {"left" | "right" | "both" | "none"} : trim white space on left only, right only or both sides, or no trim (default is both)
2664
- */
2665
- var t = bw.choice(
2666
- dir,
2667
- {
2668
- "left" : /^[\s\uFEFF\xA0\n]+/g,
2669
- "right" : /[\s\uFEFF\xA0\n]+$/g,
2670
- "none" : /(?!)/ // useful for programmatic scenarios (eg. [....].map ) where not all of the entries should be trimmed.
2671
- },
2672
- /^[\s\uFEFF\xA0\n]+|[\s\uFEFF\xA0\n]+$/g
2673
- );
2674
- return String(_toa(s,"undefined","",s)).replace(t,"");
2675
- };
2676
-
2677
- // =============================================================================================
2678
- bw.padString = function (s, width, dir, options) {
2679
- /**
2680
- @description bw.padString() takes a string and pads it to the specified number of chars either left or right or centered.
2681
- */
2682
- var dopts = {
2683
- pad : " ",
2684
- trimDir : "both" // pre-trim the input string: "left", "right", "both", "none"
2685
- };
2686
- dopts = optsCopy(dopts, options);
2687
-
2688
- s = String(s);
2689
- var x = bw.trim(s,dopts["trimDir"]);
2690
- var p = (width > x.length ) ? (width - x.length+1) : 0 ; // total padding
2691
- var q = bw.choice(dir,
2692
- {
2693
- "left" : [p,0],
2694
- "right" : [0,p],
2695
- "center" : [Math.round(p/2), (p-Math.round(p/2)+1)]
2696
- },
2697
- [0,0]
2698
- );
2699
- return ((new Array(q[0])).join(dopts["pad"]))+x+(new Array(q[1])).join(dopts["pad"]);
2700
- };
2701
-
2702
- // =============================================================================================
2703
- bw.random = function(rangeBegin, rangeEnd, options) {
2704
- /**
2705
- @method: random
2706
-
2707
- Return a random number between rangeBegin and RangeEnd (inclusive)
2708
- default is 0,100
2709
-
2710
- options
2711
- {
2712
- setType : "int"
2713
- dims : false | number | [ , , ] // selector for dimensions
2714
- }
2715
-
2716
- options
2717
- setType:
2718
- "int" ==> return an integer (default)
2719
- "float" or "number" ==> return floating point number
2720
-
2721
- dims
2722
- false or ommitted ==> return a single number
2723
- 5 ==> return a 5x1 array of random numbers
2724
- [3,5,2] ==> return a 3x5x2 array of random numbers
2725
-
2726
- example:
2727
- bw.random() ==> returns a number btw 0,100
2728
- bw.random(-4,4,{setType: "float", dims[4,5]}) ==> returns a 3x5 array of floating pt numbers btw -4,4
2729
-
2730
- see also prandom for psuedorandom numbers
2731
-
2732
- */
2733
- rangeBegin = _to(rangeBegin) == "number" ? rangeBegin : 0;
2734
- rangeEnd = _to(rangeEnd) == "number" ? rangeEnd : 100;
2735
-
2736
- var dopts = {
2737
- setType : "int",
2738
- dims : false // if dims is array e.g. [3,4,5] returns random elements array
2739
- };
2740
-
2741
- dopts = optsCopy(dopts,options);
2742
-
2743
- var _rnd = function () {
2744
- var n = 0;
2745
-
2746
- dopts.setType = ["int","float","number"].indexOf(dopts.setType) == -1 ? "int" : dopts.setType;
2747
-
2748
- if (rangeEnd < rangeBegin ) {
2749
- rangeBegin ^= rangeEnd; rangeEnd ^= rangeBegin; rangeBegin ^= rangeEnd;
2750
- }
2751
- n = ((Math.random() * (rangeEnd-rangeBegin)) + rangeBegin);
2752
-
2753
- return (dopts.setType == "int") ? Math.round(n) : n;
2754
- };
2755
-
2756
- if ((_to(dopts["dims"]) == "array") || (_to(dopts["dims"])== "number"))
2757
- return bw.multiArray( _rnd, dopts["dims"]);
2758
-
2759
- return _rnd();
2760
- };
2761
-
2762
- // =============================================================================================
2763
- bw.prandom = function (rangeBegin,rangeEnd,seed, options) {
2764
- /**
2765
- prandom - generate a psuedo random number from internal hash function in a given range
2766
- */
2767
- rangeBegin = _to(rangeBegin) == "number" ? rangeBegin : 0;
2768
- rangeEnd = _to(rangeEnd) == "number" ? rangeEnd : 100;
2769
-
2770
- var dopts = {
2771
- setType : "int",
2772
- dims : false // if dims is array e.g. [3,4,5] returns random elements array
2773
- };
2774
-
2775
- dopts = optsCopy(dopts,options);
2776
- var _cseed = seed;
2777
- var _rnd = function () {
2778
- var n = 0;
2779
-
2780
- dopts.setType = ["int","float","number"].indexOf(dopts.setType) == -1 ? "int" : dopts.setType;
2781
-
2782
- if (rangeEnd < rangeBegin ) {
2783
- rangeBegin ^= rangeEnd; rangeEnd ^= rangeBegin; rangeBegin ^= rangeEnd;
2784
- }
2785
- n = (((bw.hashFnv32a("start string",_cseed) & 0xffff)/(65536)) * (rangeEnd-rangeBegin)) + rangeBegin;
2786
-
2787
- _cseed = (dopts.setType == "int") ? Math.round(n) : n;
2788
- return (dopts.setType == "int") ? Math.round(n) : n;
2789
- };
2790
-
2791
- if ((_to(dopts["dims"]) == "array") || (_to(dopts["dims"])== "number"))
2792
- return bw.multiArray( _rnd, dopts["dims"]);
2793
-
2794
- return _rnd();
2795
-
2796
- };
2797
- // =============================================================================================
2798
-
2799
-
2800
- bw.hashFnv32a= function (str, seed, returnHexStr) {
2801
- /**
2802
- @method Calculate a 32 bit FNV-1a hash
2803
- Found here: https://gist.github.com/vaiorabbit/5657561
2804
- Ref.: http://isthe.com/chongo/tech/comp/fnv/
2805
-
2806
- @param {string} str the input value
2807
-
2808
- @param {integer} [seed] optionally pass the hash of the previous chunk
2809
-
2810
- @param {boolean} [asString=false] set to true to return the hash value as
2811
- 8-digit hex string instead of an integer
2812
-
2813
- @returns {integer | string}
2814
- */
2815
- /*jshint bitwise:false */
2816
- var i, l,
2817
- hval = (typeof seed == "undefined") ? 0x811c9dc5 : seed;
2818
-
2819
- for (i = 0, l = str.length; i < l; i++) {
2820
- hval ^= str.charCodeAt(i);
2821
- hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
2822
- }
2823
- if( returnHexStr ){
2824
- // Convert to 8 digit hex string
2825
- return ("0000000" + (hval >>> 0).toString(16)).substr(-8);
2826
- }
2827
- return hval >>> 0;
2828
- };
2829
-
2830
- // =============================================================================================
2831
- bw.CSSMakeTheme = function(color) {
2832
- /**
2833
- makeThemeCSS (color)
2834
-
2835
- makes a CSS theme color palettte based on the supplied color which is exported as a css style
2836
-
2837
- TODO
2838
- */
2839
- var c = bw.colorRgbToHsl( bw.colorParse(color));
2840
-
2841
- var p = "bw-theme-";
2842
- var thm = ["l5","l4","l3","l2","l1","d1","d2","d3","d4","d5"].map(function(x){return p+x;});
2843
- var im = " !important";
2844
- thm = thm.map(function(x,i){return [x,[["color", ((i<5)?"#000" : "#fff")+im ],["background-color",c + im] ]]; });
2845
-
2846
- return thm;
2847
-
2848
- };
2849
- // =============================================================================================
2850
- bw.CSSSimpleStyles = function(appendToHead, options) {
2851
- /*
2852
- bw.CSSimpleStyles(appendToHead,options)
2853
-
2854
- Generate simple styles for bitwrench.
2855
- write a quick grid style sheet for quick n dirty layout. See docs for examples.
2856
-
2857
- appendToHead ==> if true, attempts to append to HTML <head> (only writes if not already present)
2858
- options: {
2859
- "basics" : "load" // if set to "load will load some global constants for html, body, font-family", set to false to leave these unchanged.
2860
- "exportCSS": false // if true will wrap the output css in "script" tags.
2861
- "id" : "bw-default-styles" // id assigned to the script tag, used for preventing multiple loading in a browser page
2862
- }
2863
-
2864
- */
2865
-
2866
- var dopts = {
2867
- "globals" : false,
2868
- "id" : "bw-default-styles",
2869
- "exportCSS" : false,
2870
- "colorset" : {"color" : "#000", "background-color" :"#ddd", "active" : "#222"},
2871
- "pretty" : false, //make easy to read
2872
- "themes" : // built-in primitive themes
2873
- [ // must be valid CSS keys / values
2874
- [".bw-thm-light" , {"color": "#020202 !important;", "background-color": "#e2e2e2 !important;"}],
2875
- [".bw-thm-dark" , {"color": "#e2e2e2 !important;", "background-color": "#020202 !important;"}],
2876
- ]
2877
- };
2878
-
2879
- var s ="\n", i;
2880
- //var i,j,k,l;
2881
- var _r = bw.fixNum;
2882
- var rl = bw.makeCSSRule;
2883
- dopts = optsCopy(dopts,options);
2884
-
2885
- var defs = { // defaults
2886
- defGlobals: {"box-sizing": "border-box"},
2887
- defContainer: {"height": "100%", "width":"90%", "margin": "0 auto", "padding-left": "2%","padding-right":"2%","left":"0","top":"1%","box-sizing":"border-box"},
2888
- defFontSerif: {"font-family": "Times New Roman, Times, serif"},
2889
- defFontSansSerif: {"font-family": "Arial, Helvetica, sans-serif" }
2890
- };
2891
-
2892
- if (dopts["globals"] == "load") {
2893
- s+= rl([["html","body"],defs.defContainer]);
2894
- s+= rl(["*"+defs.defFontSansSerif]);
2895
- }
2896
-
2897
-
2898
-
2899
- var d = [
2900
- //globals
2901
- ["*", defs.defGlobals],
2902
- [".bw-def-page-setup" , defs.defContainer],
2903
- [".bw-font-serif" , defs.defFontSerif],
2904
- [".bw-font-sans-serif", defs.defFontSansSerif],
2905
- "\n",
2906
- //text handling
2907
- [".bw-left", {"text-align": "left"}],
2908
- [".bw-right", {"text-align": "right"}],
2909
- [".bw-center", {"text-align": "center", "margin": "0 auto"}],
2910
- [".bw-justify", {"text-align": "justify"}],
2911
- [".bw-code", {"font-family":"monospace", "white-space":"pre-wrap"}],
2912
- [".bw-pad1", {"padding-left": "1%", "padding-right":"1%"}],
2913
- "\n",
2914
- //tables
2915
- [".bw-table", {"border-collapse":"collapse", "border-spacing": "0", "border":"1px solid #444"}],
2916
- [".bw-table th", {"background-color": "#bbb", "padding": "4px","border":"1px solid #444"}],
2917
- [".bw-table td", {"padding": "4px","border":"1px solid #444"}],
2918
- [".bw-table-stripe tr:nth-child(even)" , {"background-color":"#f0f0f0"}], // striped rows
2919
- [".bw-table tr td:first-child", {"font-weight": "700"}], // make first col bold
2920
- [".bw-table-border-round", {"border-radius":"2px"}],
2921
- [".bw-table-sort-upa::after", {"content": "\"\\2191\""}], // table sort arrow up (when visible arrows chosen)
2922
- [".bw-table-sort-dna::after", {"content": "\"\\2193\""}], // table sort arrow dn (when visible arrows chosen)
2923
- [".bw-table-sort-xxa::after", {"content": "\"\\00a0\""}], // table sort space (when visible arrows chosen)
2924
- "\n",
2925
- //tabs
2926
- [".bw-tab-item-list", { "margin": 0, "padding-inline-start":0}],
2927
- [".bw-tab-item",{"display":"inline", "padding-top":"0.75em", "padding-left":"0.75em", "padding-right":"0.75em" , "border-top-right-radius":"7px", "border-top-left-radius": "7px"}],
2928
- [".bw-tab-active", {/* padding-top:4px; padding-left:6px; padding-right:6px; padding-bottom:0; */ "font-weight":"700"}],
2929
- [".bw-tab:hover",{"cursor": "pointer", "font-weight": 700/* border: 1px solid #bbb; */}],
2930
- [".bw-tab-content-list", { margin: 0, "padding-top": "0.0em"}],
2931
- [".bw-tab-content",{ display:"none", "border-radius":0}],
2932
- [".bw-tab-content, .bw-tab-active", {"background-color": "#ddd", "padding":"0.5em"}],
2933
- "\n",
2934
- //accordian
2935
- [".bw-accordian-container > div", {"padding": "0.5em"}],
2936
- "\n",
2937
- //grid setup
2938
- [".bw-container",{ margin: "0 auto"}],
2939
- [".bw-row", { width: "100%", display: "block"}],
2940
- [".bw-row [class^=\"bw-col\"]", { float: "left"}],
2941
- [".bw-row::after", { content: "\"\"", display: "table", clear:"both"}],
2942
- [".bw-box-1", {"padding-top":"10px","padding-bottom": "10px", "border-radius": "8px"}],
2943
- "\n",
2944
- [".bw-sign", {"position": "inherit", "display": "table", "height": "100%", "width": "100%"}],
2945
- [".bw-sign > div", {display:"table-cell", "vertical-align" : "middle"}],
2946
- [".bw-sign > div > div", {"text-align":"center"}],
2947
- "\n",
2948
- //misc element controls
2949
- [".bw-hide", { display: "none"}],
2950
- [".bw-show", { display: "block"}]
2951
- ];
2952
-
2953
- //heading generator
2954
- [1,2,3,4,5,6].map(function(x){d.push([".bw-h"+x, {"font-size":_r(3.2*Math.pow(.85,x+1))+"rem"}]);});
2955
-
2956
- d.push("\n");
2957
- // grid system (generated)
2958
- for (var k=1; k<=12; k++)
2959
- d.push([".bw-col-"+k, {width:(_r(k*100/12)+"%")}]);
2960
-
2961
- d.push("\n");
2962
- // generate CSS from above rules
2963
- s+= d.map(function(x){return rl(x,{pretty:dopts.pretty});}).join("\n")+"\n";
2964
-
2965
- d.push("\n");
2966
- //primtive in-built color themeing see opts to overide
2967
- for (i in dopts["colorset"]){
2968
- s+= ".bw-color-"+i+" {"+i+":" +dopts["colorset"][i]+"}\n";
2969
- }
2970
-
2971
- d.push("\n");
2972
- bw.makeCSS( dopts["themes"]);
2973
- for (i=0; i< dopts["themes"].length; i++) {
2974
- s+= rl( dopts["themes"][i]);
2975
- //s+= bw.makeCSS( dopts["themes"][i])
2976
- }
2977
-
2978
- //responsive screen
2979
- var m = "@media only screen and (min-width: ";
2980
- s+= m + "540px) {.bw-def-page-setup {width: 96%;}}\n";
2981
- s+= m + "720px) {.bw-def-page-setup {width: 92%;}}\n";
2982
- s+= m + "960px) {.bw-def-page-setup {width: 88%;}}\n";
2983
- s+= m + "1100px){.bw-def-page-setup {width: 86%;}}\n";
2984
- s+= m + "1600px){.bw-def-page-setup {width: 84%;}}\n";
2985
-
2986
-
2987
- if (bw.isNodeJS() == false) {
2988
- var h = bw.DOM("head")[0];
2989
- var el = document.createElement("style");
2990
- el.id = dopts["id"];
2991
- el.textContent = s;
2992
-
2993
- if (appendToHead && (document.getElementById(dopts["id"]) == null)) // only append once
2994
- h.appendChild(el);
2995
- }
2996
- if (dopts["exportCSS"])
2997
- s = bw.html(["style",{"id":dopts["id"]},"\n/**\n bitwrench basic css styles\n version: "+bw.version()["version"]+"\n */"+s]);
2998
- return s;
2999
- };
3000
-
3001
-
3002
-
3003
- //================================================================================
3004
-
3005
- bw.CSSSimpleThemes = function (d,appendToHead) {
3006
- /**
3007
- bw.bwSimpleThemes() selects simple (we do mean simple) HTML themes for some basic elements.
3008
- if d is an number it selects the built-in theme by index (see docs) else if d is a dictionary the elements
3009
- in d will be converted to a CSS style.
3010
-
3011
- output is a CSS style. if appendToHead is true or omitted then the theme is appended to the head element.
3012
- */
3013
- var s ="",xs={};
3014
- /*
3015
- var thm = {
3016
- defBkgCol : "#333",
3017
- defCol : "#ddd",
3018
- col1 : "#555",
3019
- col2 : "#f0f0f0",
3020
- brd : "#ddd"
3021
- };
3022
-
3023
- var thmCSS =
3024
- [
3025
- ["*" , {"background-color": thm.defBkgCol, "color":thm.defCol, "font-family": "sans-serif", "box-sizing":"border-box"}],
3026
- ["body" , {"margin-top":"1%"}],
3027
- ["th" , {"background-color":thm.col1}],
3028
- ["tbody tr:nth-child(even)" , {"background-color": thm.col2}],
3029
- [["table", "td", "th"] , {"border-collapse":"collapse", "border":"1px solid "+thm.brd}],
3030
- [["td","th"] , {"padding":"4px"}],
3031
- [["div","body","button","table","input"] , {"border-radius": "2px"}]
3032
- // ["div", {"padding-left":"2%", "padding-right":"2%","padding-top":"1%","padding-bottom":"1%"}]
3033
- ];
3034
- */
3035
- var def = [ // default styles
3036
- {
3037
-
3038
- css:
3039
- [
3040
- ["*" , {"background-color": "#333", "color":"#ddd", "font-family": "sans-serif", "box-sizing":"border-box"}],
3041
- ["body" , {"margin-top":"1%"}],
3042
- ["th" , {"background-color":"#555"}],
3043
- ["tbody tr:nth-child(even)" , {"background-color": "#f0f0f0"}],
3044
- [["table", "td", "th"] , {"border-collapse":"collapse", "border":"1px solid #ddd"}],
3045
- [["td","th"] , {"padding":"4px"}],
3046
- [["div","body","button","table","input"] , {"border-radius": "2px"}]
3047
- // ["div", {"padding-left":"2%", "padding-right":"2%","padding-top":"1%","padding-bottom":"1%"}]
3048
- ],
3049
- },
3050
- {
3051
- css:
3052
- [
3053
- ["*" , {"background-color": "#f8f8f8", "color":"#111", "font-family": "sans-serif", "box-sizing":"border-box"}],
3054
- ["body" , {"margin-top":"1%"}],
3055
- ["th" , {"background-color":"#ddd"}],
3056
- ["tbody tr:nth-child(even)" , {"background-color":"#ddd"}],
3057
- [["table", "td", "th"] , {"border-collapse":"collapse", "border":"1px solid #111"}],
3058
- [["td","th"] , {"padding":"4px"}],
3059
- [["div","body","button","table","input"] , {"border-radius": "2px"}]
3060
- // ["div", {"padding-left":"2%", "padding-right":"2%","padding-top":"1%","padding-bottom":"1%"}]
3061
- ],
3062
- }
3063
- ];
3064
- xs = bw.choice(_to(d),{
3065
- "object" : d,
3066
- // "string" : function(){}
3067
- "number" : ((d>=0) && (d<def.length))?def[d].css:def[0].css
3068
- },def[0].css);
3069
-
3070
- s= xs.map(function(y){return bw.makeCSSRule(y,{pretty:false});}).join("\n");
3071
- if (appendToHead != false) {
3072
- //var hs = document.getElementById("bw-simple-theme-styles");
3073
- var hs = bw.DOM("bw-simple-theme-styles");
3074
- if (hs.length == 0) {// first time
3075
- //var h = document.getElementsByTagName("head")[0];
3076
- var h = bw.DOM("head")[0];
3077
- var el = document.createElement("style");
3078
- el.id = "bw-simple-theme-styles";
3079
- el.textContent = s; //note IE8 requires .text=
3080
- h.appendChild(el);
3081
- }
3082
- else { // replace it
3083
- hs.textContent = s; //note IE8 requires .text=
3084
- }
3085
-
3086
- }
3087
-
3088
- return s;
3089
- };
3090
-
3091
- // =============================================================================================
3092
- bw.selectTabContent = function (item, target) {
3093
- /**
3094
- This function is used inside a tab block to show the appropriate content. Note that this is
3095
- designed to work even if code is emitted as document.getElementById("myTabs").innerHTML = <<generated code..>>
3096
- or statically written by the programmer.
3097
-
3098
- note that DOM IDs are not required as selectTabContent() uses DOM path relative logic internally
3099
-
3100
- <div class="bw-tab-container"> <!-- bw-tab-container -- bw-tab-items (array of items), bw-tab-content (array of content to show) -->
3101
- <ul class="bw-tab-item-list"> <!-- container for the tabs -->
3102
- <li class="bw-tab userTab bw-tab-active" onclick="bw.selectTabContent(this)" >Tab 1</li>
3103
- <li class="bw-tab userTab " onclick="bw.selectTabContent(this)" >Tab 2</li>
3104
- <li class="bw-tab userTab " onclick="bw.selectTabContent(this)" >Tab 3</li>
3105
- <li class="bw-tab userTab " onclick="bw.selectTabContent(this)" >Tab 4</li>
3106
- </ul>
3107
- <div class="bw-tab-content-list"> <!-- container for the tab content -->
3108
- <div class="bw-tab-content bw-show" >coontent area 1 </div> <!-- bw-show picks which tab to make active at first -->
3109
- <div class="bw-tab-content" >content area 2</div>
3110
- <div class="bw-tab-content" >content area 3</div>
3111
- <div class="bw-tab-content" >content area 4</div>
3112
- </div> <!-- end of tab content sect -->
3113
- </div>
3114
- */
3115
- //if (_to(item)=="string")
3116
- // item = document.getElementById(item);
3117
- item = bw.DOM(item)[0];
3118
-
3119
- if (_to(item).substr(0,4) != "html")
3120
- return false; //unable to set tab content
3121
- document.gx=item;
3122
- var i,j,index=0;
3123
- var cols = item.parentNode.getElementsByTagName("li");
3124
- //update which tab selected
3125
- for (i=0; i< cols.length; i++) {
3126
- if (cols[i] == item) { // selected tab logic
3127
- index = i;
3128
- cols[i].className = bw.classStrAddDel(cols[i].className,"bw-tab-active");
3129
- }
3130
- else { // unselected tab logic
3131
- cols[i].className = bw.classStrAddDel(cols[i].className,"","bw-tab-active");
3132
- }
3133
- }
3134
- //console.log(item);
3135
- var tcols=[];// = item.parentNode.parentNode.getElementsByClassName("bw-tab-content-list")[0].getElementsByClassName("bw-tab-content");
3136
-
3137
-
3138
- for (i=0; i<item.parentNode.parentNode.children.length; i++) {
3139
- if (item.parentNode.parentNode.children[i].className.trim().split(/\s+/).indexOf("bw-tab-content-list")>=0) {
3140
- //were in the right child...
3141
- for (j=0; j<item.parentNode.parentNode.children[i].children.length;j++) {
3142
- if (item.parentNode.parentNode.children[i].children[j].className.trim().split(/\s+/).indexOf("bw-tab-content") >=0)
3143
- tcols.push(item.parentNode.parentNode.children[i].children[j]);
3144
- }
3145
- }
3146
-
3147
- }
3148
-
3149
- if (tcols.length <= 0)
3150
- return false;
3151
-
3152
- target = (_to(target) == "undefined") ? tcols[index] : target; //we will infer it by the tab index
3153
- target = (_to(target) == "string" ) ? bw.DOM(target)[0] : target; // we hav an ID so we'll use that
3154
-
3155
- for (i=0; i < tcols.length; i++) {
3156
- if (tcols[i] == target)
3157
- tcols[i].className = bw.classStrAddDel(tcols[i].className,"bw-show");
3158
- //bw.DOMClass(tcols[i],"bw-show","bw-show"); //tcols[i].style.display = "block";
3159
- else
3160
- tcols[i].className = bw.classStrAddDel(tcols[i].className,"","bw-show");
3161
- //bw.DOMClass(tcols[i],"bw-show","");//tcols[i].style.display = "none";
3162
-
3163
- }
3164
- return true;
3165
- };
3166
-
3167
- // =============================================================================================
3168
-
3169
- bw.DOMClass = function(el, key, replace) {
3170
- /**
3171
- bw.DOMClass(el,value)
3172
-
3173
- returns whether a specific DOM element class name (key) is set on atleast one the supplied element(s).
3174
-
3175
- If replace is supplied then the class name (key) is replaced or added if it doesn't exist.
3176
- note that if key is not found but a replace is supplied the return-value is still false as the supplied key was not found
3177
-
3178
- el must be valid element or CSS selector
3179
-
3180
- markElement is used by bw UI toggles
3181
- */
3182
- var r = false, elems, x,j;
3183
- elems = bw.DOM(el);
3184
- if (elems.length <=0 )
3185
- return r;
3186
-
3187
- for (j=0; j< elems.length; j++) {
3188
- x = elems[j];
3189
- try {
3190
-
3191
- var c = x.className.split(/[ ]+/);
3192
- var i = c.indexOf(key);
3193
-
3194
- if (i >= 0) // found key
3195
- r = true;
3196
-
3197
-
3198
- if ((_to(replace) == "string") && (c.indexOf(replace)== -1)){
3199
- if (i == -1) //key not found
3200
- c.push(replace);
3201
- else {
3202
- if (replace.length > 0)
3203
- c[i]=replace;
3204
- else
3205
- c.splice(i,1);
3206
- }
3207
- x.className = c.join(" ").trim();
3208
- r = true;
3209
- // element.className = element.className.replace(/\bmystyle\b/g, "");
3210
- }
3211
- /*
3212
- var c = x.className;
3213
- x.className = bw.classStrAddDel(c,key,replace);
3214
- r=true;
3215
- */
3216
- }
3217
- catch(e) { bw.log(e);}
3218
- }
3219
- return r;
3220
- };
3221
-
3222
- // =============================================================================================
3223
- bw.DOMClassToggle = function(el,className) {
3224
- /**
3225
- bw.DOMClassToggle(el,classname)
3226
- for each element specified in el (eg "#id", ".myClass", "h2", <DOM OBJECT>) toggle className.
3227
-
3228
- If className is present on the object then it is removed. if it is not present it is added.
3229
-
3230
-
3231
- classNames with spaces or tabs are not valid and result in undefined behavior.
3232
-
3233
- returns last element current toggle state.
3234
- */
3235
- var x,i,elems = bw.DOM(el), r=false;
3236
- for (i=0; i< elems.length; i++) {
3237
- x=elems[i];
3238
- try {
3239
- r = bw.DOMClass(x,className);
3240
- if (r)
3241
- bw.DOMClass(x,className,"");
3242
- else
3243
- bw.DOMClass(x,className,className);
3244
-
3245
- } catch(e) { bw.log(e); }
3246
- }
3247
- return !r;
3248
- };
3249
- // =============================================================================================
3250
- bw.version = function() {
3251
- /**
3252
- @method version() - bitwrench runtime version & license info.
3253
-
3254
- */
3255
- var v = {
3256
- "version" : "1.2.16",
3257
- "about" : "bitwrench is a simple library of miscellaneous Javascript helper functions for common web design tasks.",
3258
- "copy" : "(c) M A Chatterjee deftio (at) deftio (dot) com",
3259
- "url" : "http://github.com/deftio/bitwrench",
3260
- "license" : "BSD-2-Clause"
3261
- };
3262
- return v;
3263
- };
3264
-
3265
- // ==============================================================================================
3266
- /**
3267
- command line handling
3268
-
3269
- this can be done via URL e.g. myPage.com?bw-load-styles=true
3270
-
3271
- or via script tag
3272
- <script type="text/javascript" src="./path/to/bitwrenchjs" bwargs="bw-load-styles=true"></script>
3273
-
3274
- */
3275
- bw.bwargs = {enableUJURLArgs : "true"}; // the arguments are exported so one can see them as a simple dict
3276
-
3277
- var parseArgs = function(s) {
3278
- var args = {};
3279
- if ((typeof s == "string") && (s!= "")) {
3280
- s=s.split(";");
3281
- var j;
3282
- for (j in s) {
3283
- var k = s[j].split(":");
3284
- args[k[0]]=k[1];
3285
- }
3286
- }
3287
- return args;
3288
- };
3289
-
3290
- var getArgs = function () {
3291
- if(bw.isNodeJS()==false) { // in browser
3292
- //var els = document.getElementsByTagName("script"); // array of script elements
3293
- var els = bw.DOM("script");
3294
- var i,a,b;
3295
- for (i in els) {
3296
- try {
3297
- // bw.log(_args[i]);
3298
- var el = els[i]; //
3299
- if (el.hasOwnProperty("src") != false)
3300
- break;
3301
-
3302
- var s = String(el.getAttribute("src"));
3303
- var f = "bitwrench.js";
3304
-
3305
- if (s.toLocaleLowerCase().substring(s.length-f.length,s.length) == f.toLocaleLowerCase()) {
3306
- s = _to(s) == "string" ? el.getAttribute("bwargs") : [""];
3307
- s = _to(s) == "string" ? el.getAttribute("data-bwargs") : s; //the html4/5 standard way
3308
- a = parseArgs(s);
3309
- for (b in a)
3310
- bw.bwargs[b]=a[b];
3311
- }
3312
-
3313
- } catch (e) {
3314
- //bw.log(String(["err 1418",i,e]));
3315
- }
3316
- }
3317
-
3318
- //pick up from URL
3319
- if(bw.bwargs["enableUJURLArgs"] == "true") { //note string literal "true"
3320
- //note in the script tag you can disable ?bwload=foo:bar; params with this
3321
- //<script type="text/javascript" src="./path/to/bitwrench.js" bwargs="enableURLConfig:false"></script>
3322
- a = parseArgs(bw.getURLParam("bwargs",""));
3323
- for (b in a)
3324
- bw.bwargs[b]=a[b];
3325
- }
3326
- }
3327
- };
3328
-
3329
-
3330
- // ==============================================================================================
3331
- // ==============================================================================================
3332
- // ==============================================================================================
3333
- //internally used function declarations:
3334
-
3335
-
3336
- getArgs();
3337
-
3338
- // do command line stuff
3339
- var loadStyles = bw.bwargs["bw-load-styles"]!="false";
3340
- var loadStyleBasics = bw.typeAssign(bw.bwargs["bw-load-style-basics"],"string", bw.bwargs["bw-load-style-basics"], "load");
3341
- bw.CSSSimpleStyles(loadStyles,{"globals":loadStyleBasics}); // append to head the bitwrench css styles by default
3342
-
3343
- bw.funcRegister(bw.log,"bw_log"); // this is globally registered for debugging purposes, it will never get called though unless programmer does this explicitly.
3344
-
3345
- return bw;
3346
- //END_LIBRARY_CODE
3347
- }));
3348
-