Greasy Fork is available in English.

GM_config

A lightweight, reusable, cross-browser graphical settings framework for inclusion in user scripts.

ეს სკრიპტი არ უნდა იყოს პირდაპირ დაინსტალირებული. ეს ბიბლიოთეკაა, სხვა სკრიპტებისთვის უნდა ჩართეთ მეტა-დირექტივაში // @require https://update.greatest.deepsurf.us/scripts/28536/184529/GM_config.js.

  1. /*
  2. Copyright 2009+, GM_config Contributors (https://github.com/sizzlemctwizzle/GM_config)
  3.  
  4. GM_config Contributors:
  5. Mike Medley <medleymind@gmail.com>
  6. Joe Simmons
  7. Izzy Soft
  8. Marti Martz
  9.  
  10. GM_config is distributed under the terms of the GNU Lesser General Public License.
  11.  
  12. GM_config is free software: you can redistribute it and/or modify
  13. it under the terms of the GNU Lesser General Public License as published by
  14. the Free Software Foundation, either version 3 of the License, or
  15. (at your option) any later version.
  16.  
  17. This program is distributed in the hope that it will be useful,
  18. but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. GNU Lesser General Public License for more details.
  21.  
  22. You should have received a copy of the GNU Lesser General Public License
  23. along with this program. If not, see <http://www.gnu.org/licenses/>.
  24. */
  25.  
  26. // The GM_config constructor
  27. function GM_configStruct() {
  28. // call init() if settings were passed to constructor
  29. if (arguments.length) {
  30. GM_configInit(this, arguments);
  31. this.onInit();
  32. }
  33. }
  34.  
  35. // This is the initializer function
  36. function GM_configInit(config, args) {
  37. // Initialize instance variables
  38. if (typeof config.fields == "undefined") {
  39. config.fields = {};
  40. config.onInit = config.onInit || function() {};
  41. config.onOpen = config.onOpen || function() {};
  42. config.onSave = config.onSave || function() {};
  43. config.onClose = config.onClose || function() {};
  44. config.onReset = config.onReset || function() {};
  45. config.isOpen = false;
  46. config.title = 'User Script Settings';
  47. config.css = {
  48. basic: [
  49. "#GM_config * { font-family: arial,tahoma,myriad pro,sans-serif; }",
  50. "#GM_config { background: #FFF; }",
  51. "#GM_config input[type='radio'] { margin-right: 8px; }",
  52. "#GM_config .indent40 { margin-left: 40%; }",
  53. "#GM_config .field_label { font-size: 12px; font-weight: bold; margin-right: 6px; }",
  54. "#GM_config .radio_label { font-size: 12px; }",
  55. "#GM_config .block { display: block; }",
  56. "#GM_config .saveclose_buttons { margin: 16px 10px 10px; padding: 2px 12px; }",
  57. "#GM_config .reset, #GM_config .reset a," +
  58. " #GM_config_buttons_holder { color: #000; text-align: right; }",
  59. "#GM_config .config_header { font-size: 20pt; margin: 0; }",
  60. "#GM_config .config_desc, #GM_config .section_desc, #GM_config .reset { font-size: 9pt; }",
  61. "#GM_config .center { text-align: center; }",
  62. "#GM_config .section_header_holder { margin-top: 8px; }",
  63. "#GM_config .config_var { margin: 0 0 4px; }",
  64. "#GM_config .section_header { background: #414141; border: 1px solid #000; color: #FFF;",
  65. " font-size: 13pt; margin: 0; }",
  66. "#GM_config .section_desc { background: #EFEFEF; border: 1px solid #CCC; color: #575757;" +
  67. " font-size: 9pt; margin: 0 0 6px; }"
  68. ].join('\n') + '\n',
  69. basicPrefix: "GM_config",
  70. stylish: ""
  71. };
  72. }
  73.  
  74. if (args.length == 1 &&
  75. typeof args[0].id == "string" &&
  76. typeof args[0].appendChild != "function") var settings = args[0];
  77. else {
  78. // Provide backwards-compatibility with argument style intialization
  79. var settings = {};
  80.  
  81. // loop through GM_config.init() arguments
  82. for (var i = 0, l = args.length, arg; i < l; ++i) {
  83. arg = args[i];
  84.  
  85. // An element to use as the config window
  86. if (typeof arg.appendChild == "function") {
  87. settings.frame = arg;
  88. continue;
  89. }
  90.  
  91. switch (typeof arg) {
  92. case 'object':
  93. for (var j in arg) { // could be a callback functions or settings object
  94. if (typeof arg[j] != "function") { // we are in the settings object
  95. settings.fields = arg; // store settings object
  96. break; // leave the loop
  97. } // otherwise it must be a callback function
  98. if (!settings.events) settings.events = {};
  99. settings.events[j] = arg[j];
  100. }
  101. break;
  102. case 'function': // passing a bare function is set to open callback
  103. settings.events = {onOpen: arg};
  104. break;
  105. case 'string': // could be custom CSS or the title string
  106. if (/\w+\s*\{\s*\w+\s*:\s*\w+[\s|\S]*\}/.test(arg))
  107. settings.css = arg;
  108. else
  109. settings.title = arg;
  110. break;
  111. }
  112. }
  113. }
  114.  
  115. /* Initialize everything using the new settings object */
  116. // Set the id
  117. if (settings.id) config.id = settings.id;
  118. else if (typeof config.id == "undefined") config.id = 'GM_config';
  119.  
  120. // Set the title
  121. if (settings.title) config.title = settings.title;
  122.  
  123. // Set the custom css
  124. if (settings.css) config.css.stylish = settings.css;
  125.  
  126. // Set the frame
  127. if (settings.frame) config.frame = settings.frame;
  128.  
  129. // Set the event callbacks
  130. if (settings.events) {
  131. var events = settings.events;
  132. for (var e in events)
  133. config["on" + e.charAt(0).toUpperCase() + e.slice(1)] = events[e];
  134. }
  135.  
  136. // Create the fields
  137. if (settings.fields) {
  138. var stored = config.read(), // read the stored settings
  139. fields = settings.fields,
  140. customTypes = settings.types || {};
  141.  
  142. for (var id in fields) {
  143. var field = fields[id];
  144.  
  145. // for each field definition create a field object
  146. if (field)
  147. config.fields[id] = new GM_configField(field, stored[id], id,
  148. customTypes[field.type]);
  149. else if (config.fields[id]) delete config.fields[id];
  150. }
  151. }
  152.  
  153. // If the id has changed we must modify the default style
  154. if (config.id != config.css.basicPrefix) {
  155. config.css.basic = config.css.basic.replace(
  156. new RegExp('#' + config.css.basicPrefix, 'gm'), '#' + config.id);
  157. config.css.basicPrefix = config.id;
  158. }
  159. }
  160.  
  161. GM_configStruct.prototype = {
  162. // Support old method of initalizing
  163. init: function() {
  164. GM_configInit(this, arguments);
  165. this.onInit();
  166. },
  167.  
  168. // call GM_config.open() from your script to open the menu
  169. open: function () {
  170. // Die if the menu is already open on this page
  171. // You can have multiple instances but you can't open the same instance twice
  172. var match = document.getElementById(this.id);
  173. if (match && (match.tagName == "IFRAME" || match.childNodes.length > 0)) return;
  174.  
  175. // Sometimes "this" gets overwritten so create an alias
  176. var config = this;
  177.  
  178. // Function to build the mighty config window :)
  179. function buildConfigWin (body, head) {
  180. var create = config.create,
  181. fields = config.fields,
  182. configId = config.id,
  183. bodyWrapper = create('div', {id: configId + '_wrapper'});
  184.  
  185. // Append the style which is our default style plus the user style
  186. head.appendChild(
  187. create('style', {
  188. type: 'text/css',
  189. textContent: config.css.basic + config.css.stylish
  190. }));
  191.  
  192. // Add header and title
  193. bodyWrapper.appendChild(create('div', {
  194. id: configId + '_header',
  195. className: 'config_header block center'
  196. }, config.title));
  197.  
  198. // Append elements
  199. var section = bodyWrapper,
  200. secNum = 0; // Section count
  201.  
  202. // loop through fields
  203. for (var id in fields) {
  204. var field = fields[id],
  205. settings = field.settings;
  206.  
  207. if (settings.section) { // the start of a new section
  208. section = bodyWrapper.appendChild(create('div', {
  209. className: 'section_header_holder',
  210. id: configId + '_section_' + secNum
  211. }));
  212.  
  213. if (Object.prototype.toString.call(settings.section) !== '[object Array]')
  214. settings.section = [settings.section];
  215.  
  216. if (settings.section[0])
  217. section.appendChild(create('div', {
  218. className: 'section_header center',
  219. id: configId + '_section_header_' + secNum
  220. }, settings.section[0]));
  221.  
  222. if (settings.section[1])
  223. section.appendChild(create('p', {
  224. className: 'section_desc center',
  225. id: configId + '_section_desc_' + secNum
  226. }, settings.section[1]));
  227. ++secNum;
  228. }
  229.  
  230. // Create field elements and append to current section
  231. section.appendChild((field.wrapper = field.toNode(configId)));
  232. }
  233.  
  234. // Add save and close buttons
  235. bodyWrapper.appendChild(create('div',
  236. {id: configId + '_buttons_holder'},
  237.  
  238. create('button', {
  239. id: configId + '_saveBtn',
  240. textContent: 'Save',
  241. title: 'Save settings',
  242. className: 'saveclose_buttons',
  243. onclick: function () { config.save() }
  244. }),
  245.  
  246. create('button', {
  247. id: configId + '_closeBtn',
  248. textContent: 'Close',
  249. title: 'Close window',
  250. className: 'saveclose_buttons',
  251. onclick: function () { config.close() }
  252. }),
  253.  
  254. create('div',
  255. {className: 'reset_holder block'},
  256.  
  257. // Reset link
  258. create('a', {
  259. id: configId + '_resetLink',
  260. textContent: 'Reset to defaults',
  261. href: '#',
  262. title: 'Reset fields to default values',
  263. className: 'reset',
  264. onclick: function(e) { e.preventDefault(); config.reset() }
  265. })
  266. )));
  267.  
  268. body.appendChild(bodyWrapper); // Paint everything to window at once
  269. config.center(); // Show and center iframe
  270. window.addEventListener('resize', config.center, false); // Center frame on resize
  271.  
  272. // Call the open() callback function
  273. config.onOpen(config.frame.contentDocument || config.frame.ownerDocument,
  274. config.frame.contentWindow || window,
  275. config.frame);
  276.  
  277. // Close frame on window close
  278. window.addEventListener('beforeunload', function () {
  279. config.close();
  280. }, false);
  281.  
  282. // Now that everything is loaded, make it visible
  283. config.frame.style.display = "block";
  284. config.isOpen = true;
  285. }
  286.  
  287. // Change this in the onOpen callback using this.frame.setAttribute('style', '')
  288. var defaultStyle = 'bottom: auto; border: 1px solid #000; display: none; height: 75%;'
  289. + ' left: 0; margin: 0; max-height: 95%; max-width: 95%; opacity: 0;'
  290. + ' overflow: auto; padding: 0; position: fixed; right: auto; top: 0;'
  291. + ' width: 75%; z-index: 9999;';
  292.  
  293. // Either use the element passed to init() or create an iframe
  294. if (this.frame) {
  295. this.frame.id = this.id; // Allows for prefixing styles with the config id
  296. this.frame.setAttribute('style', defaultStyle);
  297. buildConfigWin(this.frame, this.frame.ownerDocument.getElementsByTagName('head')[0]);
  298. } else {
  299. // Create frame
  300. document.body.appendChild((this.frame = this.create('iframe', {
  301. id: this.id,
  302. style: defaultStyle
  303. })));
  304.  
  305. // In WebKit src can't be set until it is added to the page
  306. this.frame.src = 'about:blank';
  307. // we wait for the iframe to load before we can modify it
  308. this.frame.addEventListener('load', function(e) {
  309. var frame = config.frame;
  310. var body = frame.contentDocument.getElementsByTagName('body')[0];
  311. body.id = config.id; // Allows for prefixing styles with the config id
  312. buildConfigWin(body, frame.contentDocument.getElementsByTagName('head')[0]);
  313. }, false);
  314. }
  315. },
  316.  
  317. save: function () {
  318. var forgotten = this.write();
  319. this.onSave(forgotten); // Call the save() callback function
  320. },
  321.  
  322. close: function() {
  323. // If frame is an iframe then remove it
  324. if (this.frame.contentDocument) {
  325. this.remove(this.frame);
  326. this.frame = null;
  327. } else { // else wipe its content
  328. this.frame.innerHTML = "";
  329. this.frame.style.display = "none";
  330. }
  331.  
  332. // Null out all the fields so we don't leak memory
  333. var fields = this.fields;
  334. for (var id in fields) {
  335. var field = fields[id];
  336. field.wrapper = null;
  337. field.node = null;
  338. }
  339.  
  340. this.onClose(); // Call the close() callback function
  341. this.isOpen = false;
  342. },
  343.  
  344. set: function (name, val) {
  345. this.fields[name].value = val;
  346. },
  347.  
  348. get: function (name) {
  349. return this.fields[name].value;
  350. },
  351.  
  352. write: function (store, obj) {
  353. if (!obj) {
  354. var values = {},
  355. forgotten = {},
  356. fields = this.fields;
  357.  
  358. for (var id in fields) {
  359. var field = fields[id];
  360. var value = field.toValue();
  361.  
  362. if (field.save) {
  363. if (value != null) {
  364. values[id] = value;
  365. field.value = value;
  366. } else
  367. values[id] = field.value;
  368. } else
  369. forgotten[id] = value;
  370. }
  371. }
  372. try {
  373. this.setValue(store || this.id, this.stringify(obj || values));
  374. } catch(e) {
  375. this.log("GM_config failed to save settings!");
  376. }
  377.  
  378. return forgotten;
  379. },
  380.  
  381. read: function (store) {
  382. try {
  383. var rval = this.parser(this.getValue(store || this.id, '{}'));
  384. } catch(e) {
  385. this.log("GM_config failed to read saved settings!");
  386. var rval = {};
  387. }
  388. return rval;
  389. },
  390.  
  391. reset: function () {
  392. var fields = this.fields;
  393.  
  394. // Reset all the fields
  395. for (var id in fields) fields[id].reset();
  396.  
  397. this.onReset(); // Call the reset() callback function
  398. },
  399.  
  400. create: function () {
  401. switch(arguments.length) {
  402. case 1:
  403. var A = document.createTextNode(arguments[0]);
  404. break;
  405. default:
  406. var A = document.createElement(arguments[0]),
  407. B = arguments[1];
  408. for (var b in B) {
  409. if (b.indexOf("on") == 0)
  410. A.addEventListener(b.substring(2), B[b], false);
  411. else if (",style,accesskey,id,name,src,href,which,for".indexOf("," +
  412. b.toLowerCase()) != -1)
  413. A.setAttribute(b, B[b]);
  414. else
  415. A[b] = B[b];
  416. }
  417. if (typeof arguments[2] == "string")
  418. A.innerHTML = arguments[2];
  419. else
  420. for (var i = 2, len = arguments.length; i < len; ++i)
  421. A.appendChild(arguments[i]);
  422. }
  423. return A;
  424. },
  425.  
  426. center: function () {
  427. var node = this.frame;
  428. if (!node) return;
  429. var style = node.style,
  430. beforeOpacity = style.opacity;
  431. if (style.display == 'none') style.opacity = '0';
  432. style.display = '';
  433. style.top = Math.floor((window.innerHeight / 2) - (node.offsetHeight / 2)) + 'px';
  434. style.left = Math.floor((window.innerWidth / 2) - (node.offsetWidth / 2)) + 'px';
  435. style.opacity = '1';
  436. },
  437.  
  438. remove: function (el) {
  439. if (el && el.parentNode) el.parentNode.removeChild(el);
  440. }
  441. };
  442.  
  443. // Define a bunch of API stuff
  444. (function() {
  445. var isGM = typeof GM_getValue != 'undefined' &&
  446. typeof GM_getValue('a', 'b') != 'undefined',
  447. setValue, getValue, stringify, parser;
  448.  
  449. // Define value storing and reading API
  450. if (!isGM) {
  451. setValue = function (name, value) {
  452. return localStorage.setItem(name, value);
  453. };
  454. getValue = function(name, def){
  455. var s = localStorage.getItem(name);
  456. return s == null ? def : s
  457. };
  458.  
  459. // We only support JSON parser outside GM
  460. stringify = JSON.stringify;
  461. parser = JSON.parse;
  462. } else {
  463. setValue = GM_setValue;
  464. getValue = GM_getValue;
  465. stringify = typeof JSON == "undefined" ?
  466. function(obj) {
  467. return obj.toSource();
  468. } : JSON.stringify;
  469. parser = typeof JSON == "undefined" ?
  470. function(jsonData) {
  471. return (new Function('return ' + jsonData + ';'))();
  472. } : JSON.parse;
  473. }
  474.  
  475. GM_configStruct.prototype.isGM = isGM;
  476. GM_configStruct.prototype.setValue = setValue;
  477. GM_configStruct.prototype.getValue = getValue;
  478. GM_configStruct.prototype.stringify = stringify;
  479. GM_configStruct.prototype.parser = parser;
  480. GM_configStruct.prototype.log = window.console ?
  481. console.log : (isGM && typeof GM_log != 'undefined' ?
  482. GM_log : (window.opera ?
  483. opera.postError : function(){ /* no logging */ }
  484. ));
  485. })();
  486.  
  487. function GM_configDefaultValue(type, options) {
  488. var value;
  489.  
  490. if (type.indexOf('unsigned ') == 0)
  491. type = type.substring(9);
  492.  
  493. switch (type) {
  494. case 'radio': case 'select':
  495. value = options[0];
  496. break;
  497. case 'checkbox':
  498. value = false;
  499. break;
  500. case 'int': case 'integer':
  501. case 'float': case 'number':
  502. value = 0;
  503. break;
  504. default:
  505. value = '';
  506. }
  507.  
  508. return value;
  509. }
  510.  
  511. function GM_configField(settings, stored, id, customType) {
  512. // Store the field's settings
  513. this.settings = settings;
  514. this.id = id;
  515. this.node = null;
  516. this.wrapper = null;
  517. this.save = typeof settings.save == "undefined" ? true : settings.save;
  518.  
  519. // Buttons are static and don't have a stored value
  520. if (settings.type == "button") this.save = false;
  521.  
  522. // if a default value wasn't passed through init() then
  523. // if the type is custom use its default value
  524. // else use default value for type
  525. // else use the default value passed through init()
  526. this['default'] = typeof settings['default'] == "undefined" ?
  527. customType ?
  528. customType['default']
  529. : GM_configDefaultValue(settings.type, settings.options)
  530. : settings['default'];
  531.  
  532. // Store the field's value
  533. this.value = typeof stored == "undefined" ? this['default'] : stored;
  534.  
  535. // Setup methods for a custom type
  536. if (customType) {
  537. this.toNode = customType.toNode;
  538. this.toValue = customType.toValue;
  539. this.reset = customType.reset;
  540. }
  541. }
  542.  
  543. GM_configField.prototype = {
  544. create: GM_configStruct.prototype.create,
  545.  
  546. toNode: function(configId) {
  547. var field = this.settings,
  548. value = this.value,
  549. options = field.options,
  550. type = field.type,
  551. id = this.id,
  552. labelPos = field.labelPos,
  553. create = this.create;
  554.  
  555. function addLabel(pos, labelEl, parentNode, beforeEl) {
  556. if (!beforeEl) beforeEl = parentNode.firstChild;
  557. switch (pos) {
  558. case 'right': case 'below':
  559. if (pos == 'below')
  560. parentNode.appendChild(create('br', {}));
  561. parentNode.appendChild(labelEl);
  562. break;
  563. default:
  564. if (pos == 'above')
  565. parentNode.insertBefore(create('br', {}), beforeEl);
  566. parentNode.insertBefore(labelEl, beforeEl);
  567. }
  568. }
  569.  
  570. var retNode = create('div', { className: 'config_var',
  571. id: configId + '_' + id + '_var',
  572. title: field.title || '' }),
  573. firstProp;
  574.  
  575. // Retrieve the first prop
  576. for (var i in field) { firstProp = i; break; }
  577.  
  578. var label = field.label && type != "button" ?
  579. create('label', {
  580. id: configId + '_' + id + '_field_label',
  581. for: configId + '_field_' + id,
  582. className: 'field_label'
  583. }, field.label) : null;
  584.  
  585. switch (type) {
  586. case 'textarea':
  587. retNode.appendChild((this.node = create('textarea', {
  588. innerHTML: value,
  589. id: configId + '_field_' + id,
  590. className: 'block',
  591. cols: (field.cols ? field.cols : 20),
  592. rows: (field.rows ? field.rows : 2)
  593. })));
  594. break;
  595. case 'radio':
  596. var wrap = create('div', {
  597. id: configId + '_field_' + id
  598. });
  599. this.node = wrap;
  600.  
  601. for (var i = 0, len = options.length; i < len; ++i) {
  602. var radLabel = create('label', {
  603. className: 'radio_label'
  604. }, options[i]);
  605.  
  606. var rad = wrap.appendChild(create('input', {
  607. value: options[i],
  608. type: 'radio',
  609. name: id,
  610. checked: options[i] == value
  611. }));
  612.  
  613. var radLabelPos = labelPos &&
  614. (labelPos == 'left' || labelPos == 'right') ?
  615. labelPos : firstProp == 'options' ? 'left' : 'right';
  616.  
  617. addLabel(radLabelPos, radLabel, wrap, rad);
  618. }
  619.  
  620. retNode.appendChild(wrap);
  621. break;
  622. case 'select':
  623. var wrap = create('select', {
  624. id: configId + '_field_' + id
  625. });
  626. this.node = wrap;
  627.  
  628. for (var i = 0, len = options.length; i < len; ++i) {
  629. var option = options[i];
  630. wrap.appendChild(create('option', {
  631. value: option,
  632. selected: option == value
  633. }, option));
  634. }
  635.  
  636. retNode.appendChild(wrap);
  637. break;
  638. default: // fields using input elements
  639. var props = {
  640. id: configId + '_field_' + id,
  641. type: type,
  642. value: type == 'button' ? field.label : value
  643. };
  644.  
  645. switch (type) {
  646. case 'checkbox':
  647. props.checked = value;
  648. break;
  649. case 'button':
  650. props.size = field.size ? field.size : 25;
  651. if (field.script) field.click = field.script;
  652. if (field.click) props.onclick = field.click;
  653. break;
  654. case 'hidden':
  655. break;
  656. default:
  657. // type = text, int, or float
  658. props.type = 'text';
  659. props.size = field.size ? field.size : 25;
  660. }
  661.  
  662. retNode.appendChild((this.node = create('input', props)));
  663. }
  664.  
  665. if (label) {
  666. // If the label is passed first, insert it before the field
  667. // else insert it after
  668. if (!labelPos)
  669. labelPos = firstProp == "label" || type == "radio" ?
  670. "left" : "right";
  671.  
  672. addLabel(labelPos, label, retNode);
  673. }
  674.  
  675. return retNode;
  676. },
  677.  
  678. toValue: function() {
  679. var node = this.node,
  680. field = this.settings,
  681. type = field.type,
  682. unsigned = false,
  683. rval = null;
  684.  
  685. if (!node) return rval;
  686.  
  687. if (type.indexOf('unsigned ') == 0) {
  688. type = type.substring(9);
  689. unsigned = true;
  690. }
  691.  
  692. switch (type) {
  693. case 'checkbox':
  694. rval = node.checked;
  695. break;
  696. case 'select':
  697. rval = node[node.selectedIndex].value;
  698. break;
  699. case 'radio':
  700. var radios = node.getElementsByTagName('input');
  701. for (var i = 0, len = radios.length; i < len; ++i)
  702. if (radios[i].checked)
  703. rval = radios[i].value;
  704. break;
  705. case 'button':
  706. break;
  707. case 'int': case 'integer':
  708. case 'float': case 'number':
  709. var num = Number(node.value);
  710. var warn = 'Field labeled "' + field.label + '" expects a' +
  711. (unsigned ? ' positive ' : 'n ') + 'integer value';
  712.  
  713. if (isNaN(num) || (type.substr(0, 3) == 'int' &&
  714. Math.ceil(num) != Math.floor(num)) ||
  715. (unsigned && num < 0)) {
  716. alert(warn + '.');
  717. return null;
  718. }
  719.  
  720. if (!this._checkNumberRange(num, warn))
  721. return null;
  722. rval = num;
  723. break;
  724. default:
  725. rval = node.value;
  726. break;
  727. }
  728.  
  729. return rval; // value read successfully
  730. },
  731.  
  732. reset: function() {
  733. var node = this.node,
  734. field = this.settings,
  735. type = field.type;
  736.  
  737. if (!node) return;
  738.  
  739. switch (type) {
  740. case 'checkbox':
  741. node.checked = this['default'];
  742. break;
  743. case 'select':
  744. for (var i = 0, len = node.options.length; i < len; ++i)
  745. if (node.options[i].textContent == this['default'])
  746. node.selectedIndex = i;
  747. break;
  748. case 'radio':
  749. var radios = node.getElementsByTagName('input');
  750. for (var i = 0, len = radios.length; i < len; ++i)
  751. if (radios[i].value == this['default'])
  752. radios[i].checked = true;
  753. break;
  754. case 'button' :
  755. break;
  756. default:
  757. node.value = this['default'];
  758. break;
  759. }
  760. },
  761.  
  762. remove: function(el) {
  763. GM_configStruct.prototype.remove(el || this.wrapper);
  764. this.wrapper = null;
  765. this.node = null;
  766. },
  767.  
  768. reload: function() {
  769. var wrapper = this.wrapper;
  770. if (wrapper) {
  771. var fieldParent = wrapper.parentNode;
  772. fieldParent.insertBefore((this.wrapper = this.toNode()), wrapper);
  773. this.remove(wrapper);
  774. }
  775. },
  776.  
  777. _checkNumberRange: function(num, warn) {
  778. var field = this.settings;
  779. if (typeof field.min == "number" && num < field.min) {
  780. alert(warn + ' greater than or equal to ' + field.min + '.');
  781. return null;
  782. }
  783.  
  784. if (typeof field.max == "number" && num > field.max) {
  785. alert(warn + ' less than or equal to ' + field.max + '.');
  786. return null;
  787. }
  788. return true;
  789. }
  790. };
  791.  
  792. // Create default instance of GM_config
  793. var GM_config = new GM_configStruct();