MonkeyConfig

Easy configuration dialog builder for user scripts

目前为 2018-02-14 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/38445/251319/MonkeyConfig.js

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