MonkeyConfigg

Easy configuration dialog builder for user scripts

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/521137/1505441/MonkeyConfigg.js

  1. // ==UserScript==
  2. // @name MonkeyConfigg
  3. // @namespace http://odyniec.net/
  4. // @description Easy configuration dialog builder for user scripts
  5. // @include *
  6. // ==/UserScript==
  7.  
  8. /*
  9. * MonkeyConfig
  10. * version 0.1.3
  11. *
  12. * Copyright (c) 2011-2013 Michal Wojciechowski (odyniec.net)
  13. */
  14.  
  15. console.log("MonkeyConfig loaded");
  16.  
  17. function MonkeyConfig() {
  18. var cfg = this,
  19. /* Data object passed to the constructor */
  20. data,
  21. /* Configuration parameters (data.parameters or data.params) */
  22. params,
  23. /* Current values of configuration parameters */
  24. values = {},
  25. /* Identifier used to store/retrieve configuration */
  26. storageKey,
  27. /* Is the configuration dialog displayed? */
  28. displayed,
  29. /* Currently displayed window/layer */
  30. openWin, openLayer,
  31. /* DOM element wrapping the configuration form */
  32. container,
  33. /* Darkened overlay used in the layer display mode */
  34. overlay;
  35.  
  36. /**
  37. * Initialize configuration
  38. *
  39. * @param newData New data object
  40. */
  41. function init(newData) {
  42. data = newData;
  43.  
  44. if (data) {
  45. params = data.parameters || data.params;
  46.  
  47. if (data.buttons === undefined)
  48. /* Set default buttons */
  49. data.buttons = [ 'save', 'defaults', 'cancel' ];
  50.  
  51. if (data.title === undefined)
  52. /*
  53. * If GM_getMetadata is available, get the name of the script
  54. * and use it in the dialog title
  55. */
  56. if (typeof GM_getMetadata == 'function') {
  57. var scriptName = GM_getMetadata('name');
  58. data.title = scriptName + ' Configuration';
  59. }
  60. else
  61. data.title = 'Configuration';
  62. }
  63.  
  64. /* Make a safe version of title to be used as stored value identifier */
  65. var safeTitle = data && data.title ?
  66. data.title.replace(/[^a-zA-Z0-9]/g, '_') : '';
  67.  
  68. storageKey = '_MonkeyConfig_' + safeTitle + '_cfg';
  69.  
  70. var storedValues;
  71.  
  72. /* Load stored values (if present) */
  73. if (GM_getValue(storageKey))
  74. storedValues = JSON.parse(GM_getValue(storageKey));
  75.  
  76. for (var name in params) {
  77. /* If there's a value defined in the passed data object, use it */
  78. if (params[name]['value'] !== undefined)
  79. set(name, params[name].value);
  80. /* Check if there's a stored value for this parameter */
  81. else if (storedValues && storedValues[name] !== undefined)
  82. set(name, storedValues[name]);
  83. /* Otherwise, set the default value (if defined) */
  84. else if (params[name]['default'] !== undefined)
  85. set(name, params[name]['default']);
  86. else
  87. set(name, '');
  88. }
  89.  
  90. if (data.menuCommand) {
  91. /* Add an item to the User Script Commands menu */
  92. var caption = data.menuCommand !== true ? data.menuCommand :
  93. data.title;
  94.  
  95. GM_registerMenuCommand(caption, function () { cfg.open(); });
  96. }
  97.  
  98. /* Expose public methods */
  99. cfg.open = open;
  100. cfg.close = close;
  101. cfg.get = get;
  102. cfg.set = function (name, value) {
  103. set(name, value);
  104. update();
  105. };
  106. }
  107.  
  108. /**
  109. * Get the value of a configuration parameter
  110. *
  111. * @param name Name of the configuration parameter
  112. * @returns Value of the configuration parameter
  113. */
  114. function get(name) {
  115. return values[name];
  116. }
  117.  
  118. /**
  119. * Set the value of a configuration parameter
  120. *
  121. * @param name Name of the configuration parameter
  122. * @param value New value of the configuration parameter
  123. */
  124. function set(name, value) {
  125. values[name] = value;
  126. }
  127.  
  128. /**
  129. * Reset configuration parameters to default values
  130. */
  131. function setDefaults() {
  132. for (var name in params) {
  133. if (typeof params[name]['default'] !== 'undefined') {
  134. set(name, params[name]['default']);
  135. }
  136. }
  137. }
  138.  
  139. /**
  140. * Render the configuration dialog
  141. */
  142. function render() {
  143. var html = '<div class="__MonkeyConfig_container">' +
  144. '<h1>' + data.title + '</h1>' +
  145. '<table>';
  146.  
  147. for (var name in params) {
  148. html += MonkeyConfig.formatters['tr'](name, params[name]);}
  149.  
  150. html += '<tr><td colspan="2" class="__MonkeyConfig_buttons">' +
  151. '<table><tr>';
  152.  
  153. /* Render buttons */
  154. for (var button in data.buttons) {
  155. html += '<td>';
  156.  
  157. switch (data.buttons[button]) {
  158. case 'cancel':
  159. html += '<button type="button" ' +
  160. 'id="__MonkeyConfig_button_cancel">' +
  161. '<img src="data:image/png;base64,' +
  162. MonkeyConfig.res.icons.cancel + '" />&nbsp;' +
  163. 'Cancel</button>';
  164. break;
  165. case 'defaults':
  166. html += '<button type="button" ' +
  167. 'id="__MonkeyConfig_button_defaults">' +
  168. '<img src="data:image/png;base64,' +
  169. MonkeyConfig.res.icons.arrow_undo + '" />&nbsp;' +
  170. 'Set&nbsp;Defaults</button>';
  171. break;
  172. case 'save':
  173. html += '<button type="button" ' +
  174. 'id="__MonkeyConfig_button_save">' +
  175. '<img src="data:image/png;base64,' +
  176. MonkeyConfig.res.icons.tick + '" />&nbsp;' +
  177. 'Save</button>';
  178. break;
  179. }
  180.  
  181. html += '</td>';
  182. }
  183.  
  184. html += '</tr></table></td></tr>';
  185.  
  186. html += "</table><div>";
  187.  
  188. return MonkeyConfig.trustedPolicy.createHTML(html);
  189. }
  190.  
  191. /**
  192. * Update the fields in the dialog to reflect current values
  193. */
  194. function update() {
  195. /* Do nothing if the dialog is not currently displayed */
  196. if (!displayed)
  197. return;
  198.  
  199. for (var name in params) {
  200. var value = values[name];
  201.  
  202. switch (params[name].type) {
  203. case 'checkbox':
  204. var elem = container.querySelector('[name="' + name + '"]');
  205. elem.checked = !!value;
  206. break;
  207. case 'custom':
  208. params[name].set(value, container
  209. .querySelector('#__MonkeyConfig_parent_' + name));
  210. break;
  211. case 'number': case 'text':
  212. var elem = container.querySelector('[name="' + name + '"]');
  213. elem.value = value;
  214. break;
  215. case 'select':
  216. var elem = container.querySelector('[name="' + name + '"]');
  217.  
  218. if (elem.tagName.toLowerCase() == 'input') {
  219. if (elem.type && elem.type == 'radio') {
  220. /* Single selection with radio buttons */
  221. elem = container.querySelector(
  222. '[name="' + name + '"][value="' + value + '"]');
  223. elem.checked = true;
  224. }
  225. else if (elem.type && elem.type == 'checkbox') {
  226. /* Multiple selection with checkboxes */
  227. var checkboxes = container.querySelectorAll(
  228. 'input[name="' + name + '"]');
  229.  
  230. for (var i = 0; i < checkboxes.length; i++)
  231. checkboxes[i].checked =
  232. (value.indexOf(checkboxes[i].value) > -1);
  233. }
  234. }
  235. else if (elem.tagName.toLowerCase() == 'select')
  236. if (elem.multiple) {
  237. /* Multiple selection element */
  238. var options = container.querySelectorAll(
  239. 'select[name="' + name + '"] option');
  240.  
  241. for (var i = 0; i < options.length; i++)
  242. options[i].selected =
  243. (value.indexOf(options[i].value) > -1);
  244. }
  245. else
  246. /* Single selection element */
  247. elem.value = value;
  248. break;
  249. }
  250. }
  251. }
  252.  
  253. /**
  254. * Save button click event handler
  255. */
  256. function saveClick() {
  257. for (name in params) {
  258. switch (params[name].type) {
  259. case 'checkbox':
  260. var elem = container.querySelector('[name="' + name + '"]');
  261. values[name] = elem.checked;
  262. break;
  263. case 'custom':
  264. values[name] = params[name].get(container
  265. .querySelector('#__MonkeyConfig_parent_' + name));
  266. break;
  267. case 'number': case 'text':
  268. var elem = container.querySelector('[name="' + name + '"]');
  269. values[name] = elem.value;
  270. break;
  271. case 'select':
  272. var elem = container.querySelector('[name="' + name + '"]');
  273.  
  274. if (elem.tagName.toLowerCase() == 'input') {
  275. if (elem.type && elem.type == 'radio')
  276. /* Single selection with radio buttons */
  277. values[name] = container.querySelector(
  278. '[name="' + name + '"]:checked').value;
  279. else if (elem.type && elem.type == 'checkbox') {
  280. /* Multiple selection with checkboxes */
  281. values[name] = [];
  282. var inputs = container.querySelectorAll(
  283. 'input[name="' + name + '"]');
  284.  
  285. for (var i = 0; i < inputs.length; i++)
  286. if (inputs[i].checked)
  287. values[name].push(inputs[i].value);
  288. }
  289. }
  290. else if (elem.tagName.toLowerCase() == 'select' && elem.multiple) {
  291. /* Multiple selection element */
  292. values[name] = [];
  293. var options = container.querySelectorAll(
  294. 'select[name="' + name + '"] option');
  295.  
  296. for (var i = 0; i < options.length; i++)
  297. if (options[i].selected)
  298. values[name].push(options[i].value);
  299. }
  300. else
  301. values[name] = elem.value;
  302. break;
  303. }
  304. }
  305.  
  306. GM_setValue(storageKey, JSON.stringify(values));
  307.  
  308. close();
  309.  
  310. if (data.onSave)
  311. data.onSave(values);
  312. }
  313.  
  314. /**
  315. * Cancel button click event handler
  316. */
  317. function cancelClick() {
  318. close();
  319. }
  320.  
  321. /**
  322. * Set Defaults button click event handler
  323. */
  324. function defaultsClick() {
  325. setDefaults();
  326. update();
  327. }
  328.  
  329. /**
  330. * Open configuration dialog
  331. *
  332. * @param mode
  333. * Display mode ("iframe", "layer", or "window", defaults to
  334. * "iframe")
  335. * @param options
  336. * Display mode options
  337. */
  338. function open(mode, options) {
  339. function openDone() {
  340. /* Attach button event handlers */
  341. var button;
  342.  
  343. if (button = container.querySelector('#__MonkeyConfig_button_save'))
  344. button.addEventListener('click', saveClick, true);
  345. if (button = container.querySelector('#__MonkeyConfig_button_cancel'))
  346. button.addEventListener('click', cancelClick, true);
  347. if (button = container.querySelector('#__MonkeyConfig_button_defaults'))
  348. button.addEventListener('click', defaultsClick, true);
  349.  
  350. displayed = true;
  351. update();
  352. }
  353.  
  354. switch (mode) {
  355. case 'window':
  356. var windowFeatures = {
  357. location: 'no',
  358. status: 'no',
  359. left: window.screenX,
  360. top: window.screenY,
  361. width: 100,
  362. height: 100
  363. };
  364.  
  365. /* Additional features may be specified as an option */
  366. if (options && options.windowFeatures)
  367. for (var name in options.windowFeatures)
  368. windowFeatures[name] = options.windowFeatures[name];
  369.  
  370. var featuresArray = [];
  371.  
  372. for (var name in windowFeatures)
  373. featuresArray.push(name + '=' + windowFeatures[name]);
  374.  
  375. var win = window.open('', data.title, featuresArray.join(','));
  376.  
  377. /* Find head and body (then call the blood spatter analyst) */
  378. var head = win.document.getElementsByTagName('head')[0],
  379. body = win.document.getElementsByTagName('body')[0];
  380.  
  381. head.innerHTML = '<title>' + data.title + '</title>' +
  382. '<style type="text/css">' +
  383. MonkeyConfig.res.stylesheets.main + '</style>';
  384.  
  385. body.className = '__MonkeyConfig_window';
  386. /* Place the rendered configuration dialog inside the window body */
  387. body.innerHTML = render();
  388.  
  389. /* Find the container (CBAN-3489) */
  390. container = win.document.querySelector('.__MonkeyConfig_container');
  391.  
  392. /* Resize window to the dimensions of the container div */
  393. win.innerWidth = container.clientWidth;
  394. win.resizeBy(0, -win.innerHeight + container.clientHeight);
  395.  
  396. /* Place the window centered relative to the parent */
  397. win.moveBy(Math.round((window.outerWidth - win.outerWidth) / 2),
  398. Math.round((window.outerHeight - win.outerHeight) / 2));
  399.  
  400. openWin = win;
  401.  
  402. openDone();
  403.  
  404. break;
  405. case 'layer':
  406. if (!MonkeyConfig.styleAdded) {
  407. GM_addStyle(MonkeyConfig.res.stylesheets.main);
  408. MonkeyConfig.styleAdded = true;
  409. }
  410.  
  411. var body = document.querySelector('body');
  412.  
  413. /* Create the layer element */
  414. openLayer = document.createElement('div');
  415. openLayer.className = '__MonkeyConfig_layer';
  416.  
  417. /* Create the overlay */
  418. overlay = document.createElement('div');
  419. overlay.className = '__MonkeyConfig_overlay';
  420. overlay.style.left = 0;
  421. overlay.style.top = 0;
  422. overlay.style.width = window.innerWidth + 'px';
  423. overlay.style.height = window.innerHeight + 'px';
  424. overlay.style.zIndex = 9999;
  425.  
  426. body.appendChild(overlay);
  427. body.appendChild(openLayer);
  428.  
  429. /*
  430. * Place the rendered configuration dialog inside the layer element
  431. */
  432. openLayer.innerHTML = render();
  433.  
  434. /* Position the layer in the center of the viewport */
  435. openLayer.style.left = Math.round((window.innerWidth -
  436. openLayer.clientWidth) / 2) + 'px';
  437. openLayer.style.top = Math.round((window.innerHeight -
  438. openLayer.clientHeight) / 2) + 'px';
  439. openLayer.style.zIndex = 9999;
  440.  
  441. container = document.querySelector('.__MonkeyConfig_container');
  442.  
  443. openDone();
  444.  
  445. break;
  446. case 'iframe':
  447. default:
  448. if (!MonkeyConfig.styleAdded) {
  449. GM_addStyle(MonkeyConfig.res.stylesheets.main);
  450. MonkeyConfig.styleAdded = true;
  451. }
  452.  
  453. var body = document.querySelector('body');
  454. var iframe = document.createElement('iframe');
  455.  
  456. /* Create the layer element */
  457. openLayer = document.createElement('div');
  458. openLayer.className = '__MonkeyConfig_layer';
  459.  
  460. /* Create the overlay */
  461. overlay = document.createElement('div');
  462. overlay.className = '__MonkeyConfig_overlay';
  463. overlay.style.left = 0;
  464. overlay.style.top = 0;
  465. overlay.style.width = window.innerWidth + 'px';
  466. overlay.style.height = window.innerHeight + 'px';
  467. overlay.style.zIndex = 9999;
  468.  
  469. iframe.id = '__MonkeyConfig_frame';
  470. /*
  471. * Make the iframe transparent so that it remains invisible until
  472. * the document inside it is ready
  473. */
  474. iframe.style.opacity = 0;
  475. iframe.src = 'about:blank';
  476.  
  477. /* Make the iframe seamless with no border and no scrollbars */
  478. if (undefined !== iframe.frameborder)
  479. iframe.frameBorder = '0';
  480. if (undefined !== iframe.scrolling)
  481. iframe.scrolling = 'no';
  482. if (undefined !== iframe.seamless)
  483. iframe.seamless = true;
  484.  
  485. /* Do the rest in the load event handler */
  486. iframe.addEventListener('load', function () {
  487.  
  488. iframe.contentDocument.body.innerHTML = render();
  489. iframe.style.opacity = 1;
  490.  
  491. /* Append the style to the head */
  492. var head = iframe.contentDocument.querySelector('head'),
  493. style = iframe.contentDocument.createElement('style');
  494. style.setAttribute('type', 'text/css');
  495. style.appendChild(iframe.contentDocument.createTextNode(
  496. MonkeyConfig.res.stylesheets.main));
  497. head.appendChild(style);
  498.  
  499. var body = iframe.contentDocument.querySelector('body');
  500. body.className = '__MonkeyConfig_body';
  501.  
  502. container = iframe.contentDocument
  503. .querySelector('.__MonkeyConfig_container');
  504.  
  505. iframe.width = container.clientWidth;
  506. iframe.height = container.clientHeight;
  507.  
  508. /* Position the layer in the center of the viewport */
  509. openLayer.style.left = Math.round((window.innerWidth -
  510. openLayer.clientWidth) / 2) + 'px';
  511. openLayer.style.top = Math.round((window.innerHeight -
  512. openLayer.clientHeight) / 2) + 'px';
  513. openLayer.style.zIndex = 9999;
  514.  
  515. openDone();
  516. }, false);
  517.  
  518. setTimeout(function () {
  519. iframe.width = container.clientWidth;
  520. iframe.height = container.clientHeight;
  521.  
  522. /* Position the layer in the center of the viewport */
  523. openLayer.style.left = Math.round((window.innerWidth -
  524. openLayer.clientWidth) / 2) + 'px';
  525. openLayer.style.top = Math.round((window.innerHeight -
  526. openLayer.clientHeight) / 2) + 'px';
  527. openLayer.style.zIndex = 9999;
  528. }, 0);
  529.  
  530. body.appendChild(overlay);
  531. body.appendChild(openLayer);
  532. openLayer.appendChild(iframe);
  533.  
  534. break;
  535. }
  536. }
  537.  
  538. /**
  539. * Close configuration dialog
  540. */
  541. function close() {
  542. if (openWin) {
  543. openWin.close();
  544. openWin = undefined;
  545. }
  546. else if (openLayer) {
  547. openLayer.parentNode.removeChild(openLayer);
  548. openLayer = undefined;
  549.  
  550. if (overlay) {
  551. overlay.parentNode.removeChild(overlay);
  552. overlay = undefined;
  553. }
  554. }
  555.  
  556. displayed = false;
  557. }
  558.  
  559. init(arguments[0]);
  560. }
  561.  
  562. /**
  563. * Replace double quotes with entities so that the string can be safely used
  564. * in a HTML attribute
  565. *
  566. * @param string A string
  567. * @returns String with double quotes replaced with entities
  568. */
  569. MonkeyConfig.esc = function (string) {
  570. return string.replace(/"/g, '&quot;');
  571. };
  572.  
  573. MonkeyConfig.HTML = {
  574. '_field': function (name, options, data) {
  575. var html;
  576.  
  577. if (options.type && MonkeyConfig.HTML[options.type])
  578. html = MonkeyConfig.HTML[options.type](name, options, data);
  579. else
  580. return;
  581.  
  582. if (/\[FIELD\]/.test(options.html)) {
  583. html = options.html.replace(/\[FIELD\]/, html);
  584. }
  585.  
  586. return html;
  587. },
  588. '_label': function (name, options, data) {
  589. var label = options['label'] ||
  590. name.substring(0, 1).toUpperCase() + name.substring(1)
  591. .replace(/_/g, '&nbsp;');
  592.  
  593. return '<label for="__MonkeyConfig_field_' + name + '">' + label +
  594. '</label>';
  595. },
  596. 'checkbox': function (name, options, data) {
  597. return '<input id="__MonkeyConfig_field_' + name +
  598. '" type="checkbox" name="' + name + '" />';
  599. },
  600. 'custom': function (name, options, data) {
  601. return options.html;
  602. },
  603. 'number': function (name, options, data) {
  604. return '<input id="__MonkeyConfig_field_' + name + '" ' +
  605. 'type="text" class="__MonkeyConfig_field_number" ' +
  606. 'name="' + name + '" />';
  607. },
  608. 'select': function (name, options, data) {
  609. var choices = {}, html = '';
  610.  
  611. if (options.choices.constructor == Array) {
  612. /* options.choices is an array -- build key/value pairs */
  613. for (var i = 0; i < options.choices.length; i++)
  614. choices[options.choices[i]] = options.choices[i];
  615. }
  616. else
  617. /* options.choices is an object -- use it as it is */
  618. choices = options.choices;
  619.  
  620. if (!options.multiple) {
  621. /* Single selection */
  622. if (!/^radio/.test(options.variant)) {
  623. /* Select element */
  624. html += '<select id="__MonkeyConfig_field_' + name + '" ' +
  625. 'class="__MonkeyConfig_field_select" ' +
  626. 'name="' + name + '">';
  627.  
  628. for (var value in choices)
  629. html += '<option value="' + MonkeyConfig.esc(value) + '">' +
  630. choices[value] + '</option>';
  631.  
  632. html += '</select>';
  633. }
  634. else {
  635. /* Radio buttons */
  636. for (var value in choices) {
  637. html += '<label><input type="radio" name="' + name + '" ' +
  638. 'value="' + MonkeyConfig.esc(value) + '" />&nbsp;' +
  639. choices[value] + '</label>' +
  640. (/ column/.test(options.variant) ? '<br />' : '');
  641. }
  642. }
  643. }
  644. else {
  645. /* Multiple selection */
  646. if (!/^checkbox/.test(options.variant)) {
  647. /* Checkboxes */
  648. html += '<select id="__MonkeyConfig_field_' + name + '" ' +
  649. 'class="__MonkeyConfig_field_select" ' +
  650. 'multiple="multiple" ' +
  651. 'name="' + name + '">';
  652.  
  653. for (var value in choices)
  654. html += '<option value="' + MonkeyConfig.esc(value) + '">' +
  655. choices[value] + '</option>';
  656.  
  657. html += '</select>';
  658. }
  659. else {
  660. /* Select element */
  661. for (var value in choices) {
  662. html += '<label><input type="checkbox" ' +
  663. 'name="' + name + '" ' +
  664. 'value="' + MonkeyConfig.esc(value) + '" />&nbsp;' +
  665. choices[value] + '</label>' +
  666. (/ column/.test(options.variant) ? '<br />' : '');
  667. }
  668. }
  669. }
  670.  
  671. return html;
  672. },
  673. 'text': function (name, options, data) {
  674. if (options.long)
  675. return '<textarea id="__MonkeyConfig_field_' + name + '" ' +
  676. 'class="__MonkeyConfig_field_text" ' +
  677. (!isNaN(options.long) ? 'rows="' + options.long + '" ' : '') +
  678. 'name="' + name + '"></textarea>';
  679. else
  680. return '<input id="__MonkeyConfig_field_' + name + '" ' +
  681. 'type="text" class="__MonkeyConfig_field_text" ' +
  682. 'name="' + name + '" />';
  683. }
  684. };
  685.  
  686. MonkeyConfig.formatters = {
  687. 'tr': function (name, options, data) {
  688. var html = '<tr>';
  689.  
  690. switch (options.type) {
  691. case 'checkbox':
  692. /* Checkboxes get special treatment */
  693. html += '<td id="__MonkeyConfig_parent_' + name + '" colspan="2">';
  694. html += MonkeyConfig.HTML['_field'](name, options, data) + ' ';
  695. html += MonkeyConfig.HTML['_label'](name, options, data);
  696. html += '</td>';
  697. break;
  698. default:
  699. html += '<td>';
  700. html += MonkeyConfig.HTML['_label'](name, options, data);
  701. html += '</td><td id="__MonkeyConfig_parent_' + name + '">';
  702. html += MonkeyConfig.HTML['_field'](name, options, data);
  703. html += '</td>';
  704. break;
  705. }
  706.  
  707. html += '</tr>';
  708.  
  709. return html;
  710. }
  711. };
  712.  
  713. if (typeof trustedTypes !== "undefined") {
  714. MonkeyConfig.trustedPolicy = trustedTypes.createPolicy("monkeyConfigPolicy", {
  715. createHTML: (s) => s
  716. });
  717. } else {
  718. MonkeyConfig.trustedPolicy = {
  719. createHTML: (s) => s
  720. };
  721. }
  722.  
  723. /* Has the stylesheet been added? */
  724. MonkeyConfig.styleAdded = false;
  725.  
  726. /* Resources */
  727. MonkeyConfig.res = {};
  728.  
  729. /* Icons */
  730. MonkeyConfig.res.icons = {
  731. 'arrow_undo': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0\
  732. U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIJSURBVDjLpVM9aJNRFD35GsRSoUKKzQ/B\
  733. 0NJJF3EQlKrVgijSCBmC4NBFKihIcXBwEZdSHVoUwUInFUEkQ1DQ4CKiFsQsTrb5xNpgaZHw2Uog\
  734. 5t5zn0NJNFaw0guX97hwzuPcc17IOYfNlIdNVrhxufR6xJkZjAbSQGXjNAorqixSWFDV3KPhJ+UG\
  735. LtSQMPryrDscPwLnAHOEOQc6gkbUpIagGmApWIb/pZRX4fjj889nWiSQtgYyBZ1BTUEj6AjPa0P7\
  736. 1nb0Jfqwa+futIheHrzRn2yRQCUK/lOQhApBJVQJChHfnkCqOwWEQ+iORJHckUyX5ksvAEyGNuJC\
  737. +s6xCRXNHNxzKMmQ4luwgjfvZp69uvr2+IZcyJ8rjIporrxURggetnV0QET3rrPxzMNM2+n7p678\
  738. jUTrCiWhphAjVHR9DlR0WkSzf4IHxg5MSF0zXZEuVKWKSlCBCostS8zeG7oV64wPqxInbw86lbVX\
  739. KEQ8mkAqmUJ4SxieeVhcnANFC02C7N2h69HO2IXeWC8MDj2JnqaFNAMd8f3HKjx6+LxQRmnOz1OZ\
  740. axKIaF1VISYwB9ARZoQaYY6o1WpYCVYxt+zDn/XzVBv/MOWXW5J44ubRyVgkelFpmF/4BJVfOVDl\
  741. VyqLVBZI5manPjajDOdcswfG9k/3X9v3/vfZv7rFBanriIo++J/f+BMT+YWS6hXl7QAAAABJRU5E\
  742. rkJggg==',
  743. 'cancel': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0\
  744. U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHdSURBVDjLpZNraxpBFIb3a0ggISmmNISW\
  745. XmOboKihxpgUNGWNSpvaS6RpKL3Ry//Mh1wgf6PElaCyzq67O09nVjdVlJbSDy8Lw77PmfecMwZg\
  746. /I/GDw3DCo8HCkZl/RlgGA0e3Yfv7+DbAfLrW+SXOvLTG+SHV/gPbuMZRnsyIDL/OASziMxkkKkU\
  747. QTJJsLaGn8/iHz6nd+8mQv87Ahg2H9Th/BxZqxEkEgSrq/iVCvLsDK9awtvfxb2zjD2ARID+lVVl\
  748. babTgWYTv1rFL5fBUtHbbeTJCb3EQ3ovCnRC6xAgzJtOE+ztheYIEkqbFaS3vY2zuIj77AmtYYDu\
  749. sPy8/zuvunJkDKXM7tYWTiyGWFjAqeQnAD6+7ueNx/FLpRGAru7mcoj5ebqzszil7DggeF/DX1nB\
  750. N82rzPqrzbRayIsLhJqMPT2N83Sdy2GApwFqRN7jFPL0tF+10cDd3MTZ2AjNUkGCoyO6y9cRxfQo\
  751. wFUbpufr1ct4ZoHg+Dg067zduTmEbq4yi/UkYidDe+kaTcP4ObJIajksPd/eyx3c+N2rvPbMDPbU\
  752. FPZSLKzcGjKPrbJaDsu+dQO3msfZzeGY2TCvKGYQhdSYeeJjUt21dIcjXQ7U7Kv599f4j/oF55W4\
  753. g/2e3b8AAAAASUVORK5CYII=',
  754. 'tick': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0\
  755. U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAGrSURBVDjLvZPZLkNhFIV75zjvYm7VGFNC\
  756. qoZUJ+roKUUpjRuqp61Wq0NKDMelGGqOxBSUIBKXWtWGZxAvobr8lWjChRgSF//dv9be+9trCwAI\
  757. /vIE/26gXmviW5bqnb8yUK028qZjPfoPWEj4Ku5HBspgAz941IXZeze8N1bottSo8BTZviVWrEh5\
  758. 46EO03EXpuJOdG63otJbjBKHkEp/Ml6yNYYzpuezWL4s5VMtT8acCMQcb5XL3eJE8VgBlR7BeMGW\
  759. 9Z4yT9y1CeyucuhdTGDxfftaBO7G4L+zg91UocxVmCiy51NpiP3n2treUPujL8xhOjYOzZYsQWAN\
  760. yRYlU4Y9Br6oHd5bDh0bCpSOixJiWx71YY09J5pM/WEbzFcDmHvwwBu2wnikg+lEj4mwBe5bC5h1\
  761. OUqcwpdC60dxegRmR06TyjCF9G9z+qM2uCJmuMJmaNZaUrCSIi6X+jJIBBYtW5Cge7cd7sgoHDfD\
  762. aAvKQGAlRZYc6ltJlMxX03UzlaRlBdQrzSCwksLRbOpHUSb7pcsnxCCwngvM2Rm/ugUCi84fycr4\
  763. l2t8Bb6iqTxSCgNIAAAAAElFTkSuQmCC'
  764. };
  765.  
  766. /* Stylesheets */
  767. MonkeyConfig.res.stylesheets = {
  768. 'main': '\
  769. body.__MonkeyConfig_window {\
  770. appearance: window !important;\
  771. -moz-appearance: window !important;\
  772. background: auto;\
  773. font-family: sans-serif !important;\
  774. height: 100% !important;\
  775. margin: 0 !important;\
  776. padding: 0 !important;\
  777. width: 100% !important;\
  778. }\
  779. \
  780. div.__MonkeyConfig_container {\
  781. display: table !important;\
  782. font-family: sans-serif !important;\
  783. padding: 0.3em !important;\
  784. }\
  785. \
  786. body.__MonkeyConfig_window div.__MonkeyConfig_container {\
  787. appearance: window !important;\
  788. -moz-appearance: window !important;\
  789. height: 100%;\
  790. width: 100%;\
  791. }\
  792. \
  793. div.__MonkeyConfig_container h1 {\
  794. border-bottom: solid 1px #999 !important;\
  795. font-family: sans-serif !important;\
  796. font-size: 120% !important;\
  797. margin: 0 !important;\
  798. padding: 0 0 0.3em 0 !important;\
  799. }\
  800. \
  801. div.__MonkeyConfig_container table {\
  802. border-spacing: 0 !important;\
  803. margin: 0 !important;\
  804. }\
  805. \
  806. div.__MonkeyConfig_container table td {\
  807. border: none !important;\
  808. line-height: 100% !important;\
  809. padding: 0.3em !important;\
  810. text-align: left !important;\
  811. vertical-align: top !important;\
  812. white-space: nowrap !important;\
  813. }\
  814. \
  815. div.__MonkeyConfig_container table td.__MonkeyConfig_buttons {\
  816. padding: 0.2em 0 !important;\
  817. }\
  818. \
  819. .__MonkeyConfig_field_number {\
  820. width: 5em !important;\
  821. }\
  822. \
  823. div.__MonkeyConfig_container td.__MonkeyConfig_buttons table {\
  824. border-top: solid 1px #999 !important;\
  825. width: 100% !important;\
  826. }\
  827. \
  828. div.__MonkeyConfig_container td.__MonkeyConfig_buttons td {\
  829. padding: 0.6em 0.3em 0.1em 0.3em !important;\
  830. text-align: center !important;\
  831. vertical-align: top;\
  832. }\
  833. \
  834. div.__MonkeyConfig_container td.__MonkeyConfig_buttons button {\
  835. appearance: button !important;\
  836. -moz-appearance: button !important;\
  837. background-position: 8px 50% !important;\
  838. background-repeat: no-repeat !important;\
  839. padding: 3px 8px 3px 24px !important;\
  840. padding: 3px 8px !important;\
  841. white-space: nowrap !important;\
  842. }\
  843. \
  844. div.__MonkeyConfig_container td.__MonkeyConfig_buttons button img {\
  845. vertical-align: middle !important;\
  846. }\
  847. \
  848. div.__MonkeyConfig_layer {\
  849. display: table !important;\
  850. position: fixed !important;\
  851. }\
  852. \
  853. div.__MonkeyConfig_layer div.__MonkeyConfig_container,\
  854. body.__MonkeyConfig_body > div.__MonkeyConfig_container {\
  855. background: #eee linear-gradient(180deg,\
  856. #f8f8f8 0, #ddd 100%) !important;\
  857. border-radius: 0.5em !important;\
  858. box-shadow: 2px 2px 16px #000 !important;\
  859. color: #000 !important;\
  860. font-family: sans-serif !important;\
  861. font-size: 11pt !important;\
  862. padding: 1em 1em 0.4em 1em !important;\
  863. }\
  864. \
  865. div.__MonkeyConfig_layer div.__MonkeyConfig_container td,\
  866. div.__MonkeyConfig_layer div.__MonkeyConfig_container label,\
  867. div.__MonkeyConfig_layer div.__MonkeyConfig_container input,\
  868. div.__MonkeyConfig_layer div.__MonkeyConfig_container select,\
  869. div.__MonkeyConfig_layer div.__MonkeyConfig_container textarea,\
  870. div.__MonkeyConfig_layer div.__MonkeyConfig_container button {\
  871. color: #000 !important;\
  872. font-family: sans-serif !important;\
  873. font-size: 11pt !important;\
  874. line-height: 100% !important;\
  875. margin: 0 !important;\
  876. vertical-align: baseline !important;\
  877. }\
  878. \
  879. div.__MonkeyConfig_container label {\
  880. line-height: 120% !important;\
  881. vertical-align: baseline !important;\
  882. }\
  883. \
  884. div.__MonkeyConfig_container textarea {\
  885. vertical-align: text-top !important;\
  886. width: 100%;\
  887. }\
  888. \
  889. div.__MonkeyConfig_layer div.__MonkeyConfig_container input[type="text"] {\
  890. appearance: textfield !important;\
  891. -moz-appearance: textfield !important;\
  892. background: #fff !important;\
  893. }\
  894. \
  895. div.__MonkeyConfig_layer div.__MonkeyConfig_container h1 {\
  896. font-weight: bold !important;\
  897. text-align: left !important;\
  898. }\
  899. \
  900. div.__MonkeyConfig_layer div.__MonkeyConfig_container td.__MonkeyConfig_buttons button,\
  901. body > div.__MonkeyConfig_container td.__MonkeyConfig_buttons button {\
  902. appearance: button !important;\
  903. -moz-appearance: button !important;\
  904. background: #ccc linear-gradient(180deg,\
  905. #ddd 0, #ccc 45%, #bbb 50%, #aaa 100%) !important;\
  906. border-style: solid !important;\
  907. border-width: 1px !important;\
  908. border-radius: 0.5em !important;\
  909. box-shadow: 0 0 1px #000 !important;\
  910. color: #000 !important;\
  911. font-size: 11pt !important;\
  912. }\
  913. \
  914. div.__MonkeyConfig_layer div.__MonkeyConfig_container td.__MonkeyConfig_buttons button:hover,\
  915. body > div.__MonkeyConfig_container td.__MonkeyConfig_buttons button:hover {\
  916. background: #d2d2d2 linear-gradient(180deg,\
  917. #e2e2e2 0, #d2d2d2 45%, #c2c2c2 50%, #b2b2b2 100%) !important;\
  918. }\
  919. \
  920. div.__MonkeyConfig_overlay {\
  921. background-color: #000 !important;\
  922. opacity: 0.6 !important;\
  923. position: fixed !important;\
  924. }\
  925. \
  926. iframe#__MonkeyConfig_frame {\
  927. border: none !important;\
  928. box-shadow: 2px 2px 16px #000 !important;\
  929. }\
  930. \
  931. body.__MonkeyConfig_body {\
  932. margin: 0 !important;\
  933. padding: 0 !important;\
  934. }\
  935. '
  936. };