MonkeyConfig-branch

Easy configuration dialog builder for user scripts

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greatest.deepsurf.us/scripts/486241/1321368/MonkeyConfig-branch.js

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