Greasy Fork is available in English.

WM Config Interface

Creates a configuration interface which allows users to set and get options easily.

Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greatest.deepsurf.us/scripts/419/27764/WM%20Config%20Interface.js

  1. // ==UserScript==
  2. // @name WM Config Interface
  3. // @namespace MerricksdadConfigInterface
  4. // @description Creates a configuration interface which allows users to set and get options easily.
  5. // @license http://creativecommons.org/licenses/by-nc-nd/3.0/us/
  6. // @version 4.0.0.2
  7. // @copyright Charlie Ewing
  8. // ==/UserScript==
  9.  
  10. //this script is based on GM_config by JoeSimmons, sizzlemctwizzle, and izzysoft
  11. //this script requires some functions in the WM Common Library
  12.  
  13. (function(){
  14.  
  15.  
  16.  
  17. //config element types
  18. this.ConfigElementTypes = {
  19. checkbox:{defaultValue:false,valueMember:"checked"},
  20. text:{defaultValue:""},
  21. section:{defaultValue:"none",valueMember:"data-ft"}, //closed
  22. separator: {defaultValue:"none",valueMember:"data-ft"}, //closed
  23. optionblock: {doNotSave:true}, //not to be stored
  24. textarea: {defaultValue:""},
  25. radio: {defaultValue:false},
  26. select: {defaultValue:""}, //none selected
  27. button: {doNotSave:true}, //not to be stored
  28. "button_highlight": {doNotSave:true}, //not to be stored
  29. "button_selectmulti": {doNotSave:true}, //not to be stored
  30. "button_selectprefix": {doNotSave:true}, //not to be stored
  31. hidden: {defaultValue:false},
  32. link: {defaultValue:false}, //not to be stored
  33. tabcontrol: {doNotSave:true}, //not to be stored
  34. tabelement: {doNotSave:true}, //not to be stored
  35. tabbody: {defaultValue:"none",valueMember:"data-ft"}, //closed
  36. tab: {defaultValue:"none",valueMember:"data-ft"}, //closed
  37. "float": {defaultValue:0.0},
  38. "long": {defaultValue:0},
  39. "int": {defaultValue:0},
  40. colorbox: {defaultValue:"black"},
  41. "message": {doNotSave:true}, //not to be stored
  42. selecttime: {defaultValue:""},
  43. };
  44.  
  45. //instanceable config system
  46. this.Config = function(params){
  47. //alert(params);
  48. var self = this;
  49.  
  50. //defaults
  51. this.storageName = "settings";
  52. this.css = "";
  53. this.logo = null;
  54. this.onOpen = null;
  55. this.onClose = null;
  56. this.onSave = null;
  57. this.settings = {};
  58. this.title = "Settings - Anonymous Script";
  59. this.fields = {}; //list of ConfigField objects
  60. this.values = {}; //saveable list of data
  61. this.sectionsAsTabs = false;
  62. this.separatorsAsTabs = false;
  63. this.useScrollIntoView = false;
  64. this.confirms = {save:true,cancel:true,"import":true, restore:true};
  65.  
  66. //init
  67. this.init = function(params) {
  68. //debug.print("creating new config interface: "+params.title);
  69. try{
  70. params=params||{};
  71.  
  72. //get special params first
  73. if (exists(params.css)) {
  74. this.css.user = params.css;
  75. delete params.css;
  76. }
  77. //set params
  78. for (var p in params){
  79. this[p]=params[p];
  80. }
  81.  
  82. //get values
  83. this.values=this.read();
  84. //configure values and fields table
  85. this.configure();
  86. }catch(e){log("Config.init: "+e);}};
  87.  
  88. //read vars from local storage
  89. this.read = function(params) {try{
  90. params=params||{};
  91. return getOptJSON(params.storageName||this.storageName)||{};
  92. }catch(e){log("Config.read: "+e);}};
  93. //write vars to local storage
  94. this.write = function(params) {try{
  95. params=params||{};
  96. setOptJSON(params.storageName||this.storageName)||{};
  97. }catch(e){log("Config.write: "+e);}};
  98. //convert the tree structure to a 2D table of fields
  99. //get saved and default values as well as element types
  100. //pass destroy:true to clear the fields list and start over
  101. //pass reset:true to set all values to their defaults
  102. this.configure = function(params) {try{
  103. params=params||{};
  104. //destroy current config if requested
  105. if (params.destroy) this.fields={};
  106. //traverse the entire settings tree
  107. //OR just the passed settings param
  108. var settings = params.settings || this.settings;
  109. for (var field in settings) {
  110. //copy branch to 2D table
  111. data = settings[field];
  112. this.fields[field] = data;
  113. //setup default values
  114. data["default"] = (exists(data["default"]))?data["default"]:ConfigElementTypes[data.type].defaultValue;
  115. //set value for saveable types only
  116. if (!(ConfigElementTypes[data.type].doNotSave||false)){
  117. if (params.reset||false) {
  118. //set the value to its default value
  119. data.value = data["default"];
  120. this.values[field]=data.value;
  121. } else {
  122. if (exists(this.values[field])) {
  123. //a value exists, copy it to the field
  124. data.value = this.values[field];
  125. } else {
  126. //a value does not yet exist, create one
  127. data.value = data["default"];
  128. this.values[field]=data.value;
  129. }
  130. }
  131. }
  132. //traverse children if needed
  133. if (exists(data.kids)) {
  134. this.configure({
  135. settings:data.kids, //pass children
  136. parent:this.fields[field], //link parent
  137. reset:params.reset, //pass the reset command
  138. });
  139. }
  140. }
  141. }catch(e){log("Config.configure: "+e);}};
  142. //take additional settings data and append it to a specific field
  143. this.append = function(params) {try{
  144. params=params||{};
  145. //detect branch
  146. var branch = (exists(params.branch))?this.fields[params.branch].kids:this.settings;
  147. //copy data to specified branch
  148. for (var field in params.data) {
  149. branch[field]=params.data[field];
  150. }
  151.  
  152. //reconfigure just the passed branch
  153. this.configure({
  154. settings: params.data, //pass the new children
  155. parent: params.branch||null, //link parent
  156. });
  157. //return the branch to which we were appended
  158. return branch;
  159. }catch(e){log("Config.append: "+e);}};
  160. //open the config menu in an iframe
  161. this.open = function(params) {try{
  162. //confirm(this.sectionsAsTabs);
  163. params=params||{};
  164. //check if already open
  165. if (document.evaluate("//iframe[@id='Config']",document,null,9,null).singleNodeValue) return;
  166. //create iframe
  167. document.body.appendChild(
  168. this.frame = createElement("iframe",{
  169. id:"Config",
  170. style:(
  171. "position:fixed;"+
  172. "top:0; left:0;"+
  173. "opacity:0;"+
  174. "display:none !important;"+
  175. "z-index:9998;"+
  176. "width:75%; height:75%;"+
  177. "max-height:95%; max-width:95%;"+
  178. "border:1px solid #000000;"+
  179. "overflow:auto;"+
  180. ""//leave here
  181. )
  182. })
  183. );
  184. //load a blank document into our frame
  185. this.frame.src = "about:blank";
  186. //when it loads add our config page
  187. var self=this;
  188. this.frame.addEventListener("load", function(){
  189.  
  190. self.frameDoc=this.contentDocument;
  191. frameBody = this.contentDocument.getElementsByTagName("body")[0];
  192. //select display settings
  193. //use the passed field name as the top of our settings
  194. //or select the entire thing
  195. var settings=exists(params.field)?self.fields[params.field].kids:self.settings;
  196. //set up our frame's css
  197. self.frame.contentDocument.getElementsByTagName("head")[0].appendChild(
  198. createElement("style",{
  199. type: "text/css",
  200. textContent: self.css.basic + self.css.user
  201. })
  202. );
  203.  
  204. //add header and title
  205. frameBody.appendChild(
  206. createElement("div",{
  207. id: "header",
  208. className: "config_header block center",
  209. innerHTML: self.title
  210. })
  211. );
  212.  
  213. //append elements
  214. var prevSibling=null; //<-this part allows tabs at the top level
  215. for (var i in settings) {
  216. var newElem = self.addToFrame(settings[i], i, true, prevSibling, null).elem;
  217. prevSibling=frameBody.appendChild(newElem);
  218. }
  219.  
  220. //add config toolbar
  221. frameBody.appendChild(
  222. createElement('div', {id:'buttons_holder'}, [
  223. createElement('button',{
  224. //id:'saveBtn',
  225. textContent:'Save',
  226. title:'Save options and close window',
  227. //className:'saveclose_buttons',
  228. onclick:function(){self.close({doSave:true});}
  229. }),
  230. createElement('button',{
  231. //id:'cancelBtn',
  232. textContent:'Cancel',
  233. title:'Close window',
  234. //className:'saveclose_buttons',
  235. onclick:function(){self.close({doSave:false});}
  236. }),
  237. createElement('button', {
  238. //id:'resetBtn',
  239. textContent:'Restore to default',
  240. title:'Restore settings to default configuration',
  241. //className:'saveclose_buttons',
  242. onclick:function(){self.reset();}
  243. }),
  244. createElement('button', {
  245. //id:'resetBtn',
  246. textContent:'Import Settings',
  247. title:'Import saved settings as text.',
  248. //className:'saveclose_buttons',
  249. onclick:function(){self.importSettings();}
  250. }),
  251. createElement('button', {
  252. //id:'resetBtn',
  253. textContent:'Export Settings',
  254. title:'Export settings as text for storage elsewhere.',
  255. //className:'saveclose_buttons',
  256. onclick:function(){self.exportSettings();}
  257. })
  258. ])
  259. );
  260. //add some whitespace to the bottom of the page
  261. frameBody.appendChild(
  262. createElement("span",{className:"bigSpacer"})
  263. );
  264. // Show and center it
  265. self.center();
  266. // Center it on resize
  267. window.addEventListener('resize', function(){self.center();}, false);
  268. //call the onOpen function if available
  269. if (!(params.noEvents||false)) if (self.onOpen) doAction(self.onOpen);
  270. // Close frame on window close
  271. window.addEventListener('beforeunload', function(){
  272. remove(this);
  273. }, false);
  274. }, false);
  275. }catch(e){log("Config.open: "+e);}};
  276.  
  277. this.close = function(params) {try{
  278. params=params||{};
  279. //update the values list
  280. if (params.doSave||false) {
  281. var ask=this.confirms.save;
  282. if (params.noConfirm || !ask || (ask && confirm("Save options?"))) {
  283. var fields = this.fields, values = this.values;
  284. for (var f in fields) {
  285. var field=fields[f];
  286. var valueMember=ConfigElementTypes[field.type].valueMember||"value";
  287. var elem=this.frame.contentDocument.getElementById('field_'+f);
  288. if (elem) {
  289. //if (f.contains("interval")) debug.print(["before",values[f],field.value]);
  290. values[f]=(["value","checked"].inArray(valueMember))?elem[valueMember]:elem.getAttribute(valueMember);
  291. field.value=values[f];
  292. //if (f.contains("interval")) debug.print(["after",values[f],field.value]);
  293. } else {
  294. log("cannot find element: "+f);
  295. }
  296. }
  297. this.save();
  298. // Call the onSave function if available
  299. if (this.onSave) doAction(this.onSave);
  300. }
  301. } else {
  302. //ask to cancel without save
  303. var ask=this.confirms.cancel;
  304. if (!(params.noConfirm || !ask || (ask && confirm("Close without saving?")))) return;
  305. }
  306. //destroy the iframe and forget it
  307. if (this.frame) remove(this.frame);
  308. delete this.frame;
  309. //call the onClose function if available
  310. if (!params.noEvents && this.onClose) doAction(this.onClose);
  311. }catch(e){log("Config.close: "+e);}};
  312. this.reload=function(){
  313. this.close({noEvents:true, doSave:false, noConfirm:true})
  314. this.open({noEvents:true});
  315. };
  316.  
  317. this.set = function(name,val) {try{
  318. this.values[name] = val;
  319. this.fields[name].value = val;
  320. }catch(e){log("Config.set: "+e);}};
  321.  
  322. this.get = function(name) {try{
  323. return this.values[name];
  324. }catch(e){log("Config.get: "+e);}};
  325.  
  326. /* unused functions
  327. getValue : function(name, def) {try{ return (this.isGM?GM_getValue:(function(name,def){return localStorage.getItem(name)||def}))(name, def||""); }catch(e){log("Config.getValue: "+e);}},
  328.  
  329. setValue : function(name, value) {try{ return (this.isGM?GM_setValue:(function(name,value){return localStorage.setItem(name,value)}))(name, value||""); }catch(e){log("Config.setValue: "+e);}},
  330. */
  331. this.save = function(storageName) {try{
  332. var shrunk={}, fields=this.fields;
  333.  
  334. //clone the values data to preserve items we no longer have
  335. //fields for
  336. var shrunk=mergeJSON(this.values);
  337. //do not store values that match the default value
  338. for (var f in fields) {
  339. if ((ConfigElementTypes[fields[f].type].doNotSave||false) || (fields[f].value==fields[f]["default"])) {
  340. delete shrunk[f];
  341. }
  342. }
  343. setOptJSON((storageName||this.storageName),shrunk);
  344. }catch(e){log("Config.save: "+e);}};
  345.  
  346. this.reset = function() {try{
  347. var ask=this.confirms.restore;
  348. if (!ask || (ask && confirm("Reset all values to defaults?"))) {
  349. this.configure({reset:true});
  350. this.save();
  351. this.reload();
  352. }
  353. }catch(e){log("Config.reset: "+e);}};
  354.  
  355. this.selectBlock = function(e) {try{
  356. var boxes = selectNodes(".//input[@type='checkbox']",{type:6,node:e.parentNode||$(e,$("Config").contentDocument).parentNode,doc:$("Config").contentDocument});
  357. for (var i=0,box;(box=boxes.snapshotItem(i)); i++) box.checked=true;
  358. //http://i55.tinypic.com/6ih93q.png
  359. }catch(e){log("Config.selectBlock: "+e);}};
  360.  
  361. this.deselectBlock = function(e) {try{
  362. var boxes = selectNodes(".//input[@type='checkbox']",{type:6,node:e.parentNode||$(e,$("Config").contentDocument).parentNode,doc:$("Config").contentDocument});
  363. for (var i=0,box;(box=boxes.snapshotItem(i)); i++) box.checked=false;
  364. //http://i55.tinypic.com/2lk2xyw.png
  365. }catch(e){log("Config.deselectBlock: "+e);}};
  366.  
  367. //highlights option menu elements in an array, first clearing any elements provided in clearFirst array
  368. this.highlightElements =function(options,clearFirst) {try{
  369. if (clearFirst) for (var i=0;i<clearFirst.length; i++) if (box=$('field_'+clearFirst[i],$("Config").contentDocument) ) box.parentNode.className=box.className.replace(" highlight","");
  370. if (options) for (var i=0;i<options.length; i++) if (box=$('field_'+options[i],$("Config").contentDocument) ) box.parentNode.className=box.className.replace(" highlight","")+" highlight";
  371. }catch(e){log("Config.highlightElements: "+e);}};
  372.  
  373. //selects option menu elements in an array, first clearing any elements provided in clearFirst array
  374. this.selectElements = function(options,clearFirst) {try{
  375. if (clearFirst) for (var i=0;i<clearFirst.length; i++) if (box=$('field_'+clearFirst[i],$("Config").contentDocument)) box.checked=true;
  376. if (options) for (var i=0;i<options.length; i++) if (box=$('field_'+options[i],$("Config").contentDocument)) box.checked=true;
  377. }catch(e){log("Config.selectElements: "+e);}};
  378.  
  379. //selects option menu elements with a certain prefix, first clearing any elements starting with text appearing in clearFirst
  380. //this button only selects elements at the level the button appears or deeper in the option menu tree
  381. this.selectElementsByPrefix =function(prefix,clearPrefix) {try{
  382. if (clearPrefix){
  383. forNodes(".//*[starts-with(@id, 'field_"+clearPrefix+"')]",{doc:$("Config").contentDocument}, function(box){box.checked=false;});
  384. };
  385.  
  386. if (prefix){
  387. alert("prefix:"+prefix);
  388. forNodes(".//*[starts-with(@id, 'field_"+prefix+"')]",{doc:$("Config").contentDocument}, function(box){alert("checking"); box.checked=true;});
  389. };
  390. }catch(e){log("Config.selectElementsByPrefix: "+e);}};
  391.  
  392. this.addToFrame = function(field, i, k, prevSibling, objReference) {try{
  393. var isForms2Ready = (exists(jsForms) && exists(jsForms.colorPicker));
  394. var elem, elemObj, nextElem;
  395. var anch = this.frame;
  396. var Options = field.options;
  397. var isKid = k!=null && k===true;
  398. var now = timeStamp();
  399. //prefetch some stuff
  400. var title = field.title||"", label = field.label||"", value = field.value;
  401. //check that it is switched on by time
  402. if (exists(field.startDate)) {
  403. if ((now-Date.parse(field.startDate))<0) return; //not started yet
  404. }
  405. //check that it has not been switched off
  406. if (exists(field.endDate)) {
  407. if ((now-Date.parse(field.endDate))>0) return; //already ended
  408. }
  409.  
  410. var styleItems=[];
  411. //check if options change separators and sections to tabs
  412. var swapType=
  413. (this.sectionsAsTabs && field.type=="section")?"tab":
  414. (this.separatorsAsTabs && field.type=="separator")?"tab":
  415. field.type;
  416. //check if previous element was a tab
  417. var tabHeader, tabParent;
  418. if (prevSibling!=null && prevSibling.className.contains('tab_container')) tabParent = prevSibling;
  419.  
  420. /*if (swapType!="tab" && tabParent) {
  421. //detect if a tab is selected
  422. var tabSelected=selectSingleNode("./span/a[contains(@class,'tab_selected')]",{node:tabParent,doc:this.frameDoc});
  423. if (!tabSelected) {
  424. //detect the first tab element
  425. var firstTab=selectSingleNode("./span/a",{node:tabParent,doc:this.frameDoc});
  426. if (firstTab) {
  427. //toggle that tab
  428. //var e = firstTab.id.removePrefix("tab_");
  429. //this.toggleTab(e);
  430. click(firstTab);
  431. }
  432. }
  433. }*/
  434. //draw it
  435. var counterHolder=null;
  436. switch(swapType) {
  437. case 'section':
  438. elem = createElement('div', {title:title, className: 'section_header_holder'},[
  439. createElement('a', {className:'section_header center text_border_sec hottracking', href:"javascript:void(0);", onclick:function(){self.toggle(i,true);}},[
  440. createElement("span",{textContent:label}),
  441. counterHolder=createElement("span",{className:"counter"})
  442. ]),
  443. nextElem = createElement('div', {id:'field_'+i, className:'section_kids',"data-ft":value, style:"display:"+((value=="none")?"none":"block")+";"})
  444. ]);
  445. styleItems[0]=elem;
  446. break;
  447. case 'separator':
  448. elem = createElement("div", {title:title||'', className: 'separator section_header_holder'},[
  449. createElement('div', {id:'field_'+i+'_all',className:'field_label block_select_all littleButton oddBlue',type:((field.hideSelectAll)?'hidden':'button'),title:'Select All',onclick:function(){self.selectBlock(this);},style:'float:right; margin-top:4px;'},[createElement("span",{className:"resourceIcon checkAll16"})]),
  450. createElement('div', {id:'field_'+i+'_none',className:'field_label block_select_none littleButton oddBlue',type:((field.hideSelectAll)?'hidden':'button'),title:'Select None',onclick:function(){self.deselectBlock(this);},style:'float:right; margin-top:4px;'},[createElement("span",{className:"resourceIcon uncheckAll16"})]),
  451. styleItems[0]=createElement('a', {className:'separator_label text_border_sep hottracking', href:"javascript:void(0);", textContent:label, onclick:function(){self.toggle(i,true);}}),
  452. counterHolder=createElement("span",{className:"counter"}),
  453. styleItems[1]=(nextElem=createElement('div', {id:'field_'+i, className:'section_kids',"data-ft":value, style:"display:"+((value=="none")?"none":"block")+";"}))
  454. ]);
  455. break;
  456. case 'optionblock':
  457. elem = createElement("div", {title:title||'', className: 'config_var underline'},[
  458. createElement('label', {textContent:label, className:'optionblock_label', "for":'field_'+i}),
  459. createElement('div', {id:'field_'+i+'_all',className:'field_label block_select_all littleButton oddBlue',type:((field.hideSelectAll)?'hidden':'button'),title:'Select All',onclick:function(){self.selectBlock(this);}},[createElement("span",{className:"resourceIcon checkAll16"})]),
  460. createElement('div', {id:'field_'+i+'_none',className:'field_label block_select_none littleButton oddBlue',type:((field.hideSelectAll)?'hidden':'button'),title:'Select None',onclick:function(){self.deselectBlock(this);}},[createElement("span",{className:"resourceIcon uncheckAll16"})]),
  461. createElement('br'),
  462. createElement('input', {id:'field_'+i, type:'hidden', value:''}),
  463. ]);
  464. styleItems[0]=elem;
  465. break;
  466. case 'textarea':
  467. elem = createElement("span", {title:title||'', className: 'config_var'},[
  468. createElement('span', {textContent:label, className:'field_label'}),
  469. createElement('textarea', {id:'field_'+i,innerHTML:value, cols:(field.cols?field.cols:20), rows:(field.rows?field.rows:2)})
  470. ]);
  471. styleItems[0]=elem;
  472. break;
  473. case 'radio':
  474. var boxes = [];
  475. for (var j = 0,len = Options.length; j<len; j++) {
  476. boxes.push(createElement('span', {textContent:Options[j]}));
  477. boxes.push(createElement('input', {value:Options[j], type:'radio', name:i, checked:Options[j]==value?true:false}));
  478. }
  479. elem = createElement("span", {title:title||'', className: 'config_var '+(field.format||'block')},[
  480. createElement('span', {textContent:label, className:'field_label'}),
  481. createElement('span', {id:'field_'+iboxes},boxes)
  482. ]);
  483. styleItems[0]=elem;
  484. break;
  485. case 'select':
  486. var options = [];
  487. if (isObject(Options)) for (var j in Options) options.push(createElement('option',{textContent:Options[j],value:j,selected:(j==value)}));
  488. else options.push(createElement("option", {textContent:"Error - options needs to be an object type, not an array.",value:"error",selected:"selected"}));
  489.  
  490. elem = createElement(isKid ? "span" : "div", {title:title||'', className: 'config_var'},[
  491. createElement('span', {textContent:label, className:'field_label'}),
  492. createElement('select',{id:'field_'+i},options)
  493. ]);
  494. styleItems[0]=elem;
  495. break;
  496. case 'button':
  497. var tmp;
  498. elem = createElement("span", {className: 'config_var '+(field.format||'inline')},[
  499. (tmp=createElement('input', {id:'field_'+i, type:'button', value:label, size:(field.size?field.size:25), title:title||''}))
  500. ]);
  501. if (field.script) self.addEvent(tmp, 'click', field.script);
  502. styleItems[0]=elem;
  503. break;
  504. case 'button_highlight':
  505. var tmp;
  506. elem = createElement("span", {className: 'config_var '+(field.format||'inline')},[
  507. createElement('input', {id:'field_'+i, type:'button', value:label, size:(field.size?field.size:25), title:title||'',onclick:function(){self.highlightElements(field.options,field.clearfirst);}})
  508. ]);
  509. styleItems[0]=elem;
  510. break;
  511. case 'button_selectmulti':
  512. var tmp;
  513. elem = createElement("span", {className: 'config_var '+(field.format||'inline')},[
  514. createElement('input', {id:'field_'+i, type:'button', value:label, size:(field.size?field.size:25), title:title||'',onclick:function(){self.selectElements(field.options,field.clearFirst);}})
  515. ]);
  516. styleItems[0]=elem;
  517. break;
  518. case 'button_selectprefix':
  519. var tmp;
  520. elem = createElement("span", {className: 'config_var '+(field.format||'inline')},[
  521. createElement('input', {id:'field_'+i, type:'button', value:label, size:(field.size?field.size:25), title:title||'',onclick:function(){self.selectElementsByPrefix(field.prefix,field.clearPrefix);}})
  522. ]);
  523. styleItems[0]=elem;
  524. break;
  525. case 'hidden':
  526. elem = createElement("span", {title:title||'', className: 'config_var'},[
  527. createElement('input', {id:'field_'+i, type:'hidden', value:value})
  528. ]);
  529. styleItems[0]=elem;
  530. break;
  531. case 'link':
  532. elem = createElement("span", {title:title||'', className: (field.format||'block')},[
  533. createElement('a', {id:'field_'+i, href:field.href, title:title||'', textContent:field.label, target:'_blank', className:'field_label link_label'+(field.newitem?' newopt':'')})
  534. ]);
  535. styleItems[0]=elem;
  536. break;
  537.  
  538. case 'message':
  539. elem = createElement("span", {title:title||'', className: (field.format||'block')},[
  540. createElement('span', {id:'field_'+i, title:title||'', textContent:field.textContent, className:'field_label message_text'+(field.newitem?' newopt':'')})
  541. ]);
  542. styleItems[0]=elem;
  543. break;
  544. case 'selecttime':
  545. //creates an interval from some text input
  546. var timevalue = calcTime(value);
  547. var timedays = parseInt(timevalue/day);
  548. var timehours = parseInt((timevalue-(timedays*day))/hour);
  549. var timeminutes = parseInt((timevalue-(timehours*hour)-(timedays*day))/minute);
  550. var timeseconds = parseInt((timevalue-(timeminutes*minute)-(timehours*hour)-(timedays*day))/second);
  551. var daynode, hournode, minutenode, secondnode, returnnode;
  552. var fnCalcTime = function(){
  553. returnnode.value = "t:"+daynode.value+"d:"+hournode.value+"h:"+minutenode.value+"m:"+secondnode.value+"s"
  554. };
  555.  
  556. elem = createElement("span", {title:title||'', className: 'config_var'},[
  557. createElement('span', {textContent:label, className:'field_label'}),
  558. returnnode=createElement('input', {id:'field_'+i,value:value,type:"hidden"}),
  559. daynode=createElement('input', {value:timedays, type:"number", onchange:fnCalcTime,size:2}),
  560. createElement('span', {textContent:"d", className:'field_label'}),
  561. hournode=createElement('input', {value:timehours, type:"number", onchange:fnCalcTime,size:2}),
  562. createElement('span', {textContent:"h", className:'field_label'}),
  563. minutenode=createElement('input', {value:timeminutes, type:"number", onchange:fnCalcTime,size:2}),
  564. createElement('span', {textContent:"m", className:'field_label'}),
  565. secondnode=createElement('input', {value:timeseconds, type:"number", onchange:fnCalcTime,size:2}),
  566. createElement('span', {textContent:"s", className:'field_label'}),
  567. ]);
  568. styleItems[0]=elem;
  569. break;
  570. //deprecated
  571. case 'tabcontrol':
  572. elem = createElement("div",{title:title||'', className: 'tab_container'});
  573. styleItems[0]=elem;
  574. break;
  575. case 'tabelement':
  576. var value2 = self.values[field.key];
  577. elem = createElement("span",{title:title||'',className:'tab_element'},[
  578. createElement('a', {id:'tab_'+field.key,className:'tab_header text_border_sec hottracking'+((value2=='block')?" tab_selected":""),href:"javascript:void(0);", textContent:label, onclick:function(){self.toggleTab(field.key);}})
  579. ]);
  580. styleItems[0]=elem;
  581. break;
  582. case 'tabbody':
  583. elem = createElement("div",{id:'field_'+i,title:title||'',"data-ft":value,style:("display:"+value+";"),className:'tab_body'});
  584. styleItems[0]=elem;
  585. break;
  586. //end deprecated
  587. case 'tab': //tab shortform
  588. var objRef=null;
  589. if (null && isForms2Ready) {
  590. //build tabs using the jsForms library
  591. //objReference should be a jsForms.tabControl object
  592. if (objReference) {
  593. //we have a reference to a jsForms.tabControl object
  594. objRef=objReference;
  595. } else {
  596. //need to realize a tabControl for this tab
  597. objRef=new jsForms.tabControl({
  598. dock:"fill",
  599. preventAutoSelectTab:true,
  600. });
  601. }
  602. //add our tab as a jsForms.tabPage
  603. var thisTab = objRef.addTab({
  604. text:label,
  605. });
  606. //prepare for child elements to be added
  607. elem=objRef.node; //always return the tabControl
  608. nextElem=thisTab.pageNode;
  609. //set tab and tab page to be stylized
  610. styleItems[0]=thisTab.buttonNode;
  611. styleItems[1]=nextElem;
  612. } else {
  613. //build tabs using this library
  614. //create tab container if needed
  615. if (!tabParent){
  616. tabParent = createElement("div",{className:'tab_container'},[
  617. tabHeader=createElement("div",{className:'tab_header_container'})
  618. ]);
  619. }
  620. //ALWAYS return the tabContainer element so the next
  621. //element can join with it if needed
  622. elem=tabParent;
  623.  
  624. //create tab header if needed
  625. if (!tabHeader){
  626. tabHeader = tabParent.firstChild; //assume no header
  627. if (!tabHeader.className.contains('tab_header_container')) {
  628. tabParent.appendChild(tabHeader=createElement("div",{className:'tab_header_container'}) );
  629. }
  630. }
  631.  
  632. //create tab element
  633. tabHeader.appendChild(
  634. styleItems[0]=createElement("span",{className:'tab_element '},[
  635. createElement('a', {id:'tab_'+i,className:'tab_header text_border_sec hottracking'+((value=='block')?" tab_selected":""),href:"javascript:void(0);", onclick:function(){self.toggleTab(i);}},[
  636. createElement("span",{textContent:label}),
  637. counterHolder=createElement("span",{className:"counter"})
  638. ])
  639. ])
  640. );
  641. //create tab body
  642. tabParent.appendChild(
  643. styleItems[1]=(nextElem=createElement("div",{id:'field_'+i,title:title||'',"data-ft":value,style:("display:"+value+";"),className:'tab_body'}) )
  644. );
  645. }
  646. break;
  647.  
  648. case 'text':
  649. case 'float':
  650. case 'long':
  651. case 'int':
  652. case 'colorbox':
  653. var box;
  654. if (isForms2Ready && field.type=="colorbox") {
  655. var o,l;
  656. elem = createElement(isKid ? "span" : "div", {title:title||'', className: 'config_var tablerow'},[
  657. createElement('span', {textContent:label, className:'field_label tablecell'}),
  658. box=(o=jsForms.createElement("colorPicker",{
  659. dropDownSize:{height:"200px"},
  660. text:value,
  661. })).node
  662. ]);
  663. o.textNode.id="field_"+i;
  664. box.className="tablecell";
  665. } else {
  666. elem = createElement(isKid ? "span" : "div", {title:title||'', className: 'config_var'},[
  667. createElement('span', {textContent:label, className:'field_label'}),
  668. box=createElement('input', {id:'field_'+i, type:'text', value:value, size:(field.size?field.size:25)})
  669. ]);
  670. }
  671. styleItems[0]=elem;
  672. if (field.type=="colorbox" && !isForms2Ready){
  673. box.style.setProperty("background-color",value,"important");
  674. box.style.color="white";
  675. box.style.textShadow="-1px -1px 1px #000000, 1px 1px 1px #000000, 1px -1px 1px #000000, -1px 1px 1px #000000";
  676. box.style.fontWeight="bold";
  677. box.onchange=function(){
  678. this.style.setProperty("background-color",this.value,"important");
  679. }
  680. }
  681. break;
  682.  
  683. default:
  684. case 'checkbox':
  685. elem = createElement("span", {title:title||'', className: 'config_var '+(field.format||'block')},[
  686. createElement('label', {textContent:label, className:'field_label', "for":'field_'+i}),
  687. createElement('input', {id:'field_'+i, type:'checkbox', value:value, checked:value})
  688. ]);
  689. styleItems[0]=elem;
  690. }
  691. //cleanup
  692. tabContainer=null; tabParent=null;
  693.  
  694. //add special classes and styles
  695. if (styleItems.length) for (si=0,silen=styleItems.length;si<silen;si++){
  696. styleItems[si].className+=(field.newitem?' newopt'+((field.newitem===true)?"":field.newitem):'')+" "+(field.css||"");
  697. if(field.backgroundColor) styleItems[si].style.backgroundColor=field.backgroundColor;
  698. if(field.fontColor) styleItems[si].style.color=field.fontColor;
  699. }
  700.  
  701. //add its kids
  702. var newCount=(field.newitem?1:0);
  703. if (field.kids) {
  704. var kids=field.kids,prev;
  705. for (var kid in kids) {
  706. var childRet = this.addToFrame(kids[kid], kid, true, prev, objRef);
  707. (nextElem||elem).appendChild(prev=childRet.elem);
  708. newCount=newCount+childRet.newCount
  709. }
  710. }
  711. //display the new item count for this branch
  712. if (newCount && (swapType=="tab" || swapType=="section" || swapType=="separator") && counterHolder){
  713. counterHolder.textContent=newCount;
  714. counterHolder.style.display="inline-block";
  715. counterHolder.title=newCount+" new items in this section.";
  716. counterHolder.className+=" newOpt"; //make it green
  717. }
  718.  
  719. //return this branch and its new item count
  720. return {elem:elem, newCount:newCount};
  721. }catch(e){log("Config.addToFrame: "+e);}};
  722.  
  723. this.exportSettings = function(){try{
  724. var v = JSON.stringify(this.values)
  725. prompt("Copy and save these settings with a text editor such as notepad.",v);
  726. }catch(e){log("Config.exportSettings: "+e);}};
  727.  
  728. this.importSettings = function(){try{
  729. var ask=this.confirms.import
  730. if (!ask || (ask && confirm("This will overwrite your current settings. Are you sure?"))) {
  731. var v = prompt("Paste saved settings below.",null);
  732. if (v!=null && v!=""){
  733. v=JSON.parse(v);
  734. if (v) {
  735. this.values = v;
  736. this.configure();
  737. this.save();
  738. alert("Please refresh your browser to use the new settings.");
  739. } else {
  740. alert("Could not import settings!");
  741. }
  742. }
  743. }
  744. }catch(e){log("Config.importSettings: "+e);}};
  745.  
  746. this.css = {
  747. basic: 'body {background:#FFFFFF;}\n' +
  748. '.indent40 {margin-left:40%;}\n' +
  749. '* {font-family: arial, tahoma, sans-serif, myriad pro;}\n' +
  750. '.field_label {font-weight:bold; font-size:12px; margin-right:6px;}\n' +
  751. '.block {display:block;}\n' +
  752. '.saveclose_buttons {margin:16px 10px 10px 10px;padding:2px 12px 2px 12px;}\n' +
  753. '.reset, #buttons_holder, .reset a {text-align:right; color:#000000;}\n' +
  754. '.config_header {font-size:20pt; margin:0;}\n' +
  755. '.config_desc, .section_desc, .reset {font-size:9pt;}\n' +
  756. '.center {text-align:center;}\n' +
  757. '.config_var {margin:0 0 4px 0; display:block;}\n' +
  758. 'input[type="radio"] {margin-right:8px;}\n'+
  759.  
  760.  
  761. "body {color: buttontext !important; margin:0 !important; background:buttonface !important;}\n"+
  762. ".logo {width:128px; height:74px;}\n"+
  763.  
  764. '.section_header {font-size:13pt; background:#414141; color:#FFFFFF; border:1px solid #000000; margin:0;}\n' +
  765. ".section_header {border:1px solid #000000; border-radius: 5px 5px 5px 5px; color:white !important;background:buttonshadow !important; display:block; font-size: 15px !important; font-weight: 700 !important; line-height:23px !important;text-decoration:none !important;}\n"+
  766. '.section_desc {font-size:9pt; background:#EFEFEF; color:#575757; border:1px solid #CCCCCC; margin:0 0 6px 0;}\n' +
  767. ".separator_label {border:1px solid #007195; border-radius: 5px 5px 5px 5px; font-size: 15px !important; line-height:19px !important; font-weight: 700 !important; color:white !important; text-decoration:none !important; margin:0 !important; padding:1px 0 1px 6px !important; display:block !important; background:buttonshadow !important;}\n"+
  768. ".section_header_holder {border-radius: 5px 5px 5px 5px;padding:0 6px 0 6px !important; margin-bottom:6px !important; }\n"+
  769. ".section_kids {background:buttonface !important;border-radius: 0 0 5px 5px;border: 1px solid #000000 !important;border-top:0 !important;padding: 0 6px 6px !important;margin: 0 6px 0 6px !important;}\n"+
  770. "#header {font-size:18px !important;}\n"+
  771. "div.config_var span.config_var {display:inline-block !important; margin-left:10px !important;}\n"+
  772. "div.config_var {margin:0 !important; padding: 2px 0 2px 0 !important;}\n"+
  773. ".optionblock_label {display:inline-block; font-size:16px !important; font-weight:bold; padding-top:10px; color:buttontext;}\n"+
  774. //".block_select_all {margin-top:4px; background: #ccffff url('http://i55.tinypic.com/6ih93q.png') no-repeat center;width:17px;height:17px;border-radius: 2px 2px 2px 2px;}\n"+
  775. //".block_select_none {margin-top:4px; background: #ccffff url('http://i55.tinypic.com/2lk2xyw.png') no-repeat center;width:17px;height:17px;border-radius: 2px 2px 2px 2px;}\n"+
  776. ".field_label {font-size:11px !important;}\n"+
  777. ".link_label {line-height:19px; position:relative;z-index:0;padding:2px 6px 2px 6px; border-radius: 0px 25px 0px 25px / 0px 100px 0px 100px; margin-left:6px !important; text-decoration:none;border: 1px solid black; color:black !important; background:#EFF2F7 !important;}\n"+
  778. ".link_label:hover, .link_label:active {z-index:1; background:#D8DFEA !important;}\n"+
  779. "span.field_label:not([class*=\"separator\"]) {margin-right:8px !important;} label.field_label {margin:0 !important;}\n"+
  780. "span > label.field_label {margin-right:0 !important;}\n"+
  781. "select, input[type=\"text\"], textarea {background-color:window !important; color:windowtext !important; border:none !important;}\n"+
  782.  
  783. ".tab_element {display:inline-block !important;}\n"+
  784. ".tab_header {background:buttonshadow !important;color:buttonface !important; padding:2px 6px;border:1px solid #000000; border-radius: 5px 5px 0 0; margin:0 !important; font-size: 13px !important; line-height:19px !important; font-weight: 700 !important; text-decoration:none !important;position:relative;z-index:0;}\n"+
  785. ".hottracking:hover {background:highlight !important;}\n"+
  786. ".tab_body {padding: 10px !important;margin: 0 !important; background:buttonface !important;border-radius: 0 5px 5px 5px;border: 1px solid #000000 !important;display:none;position:relative;z-index:1;top:0px;}\n"+
  787. ".tab_selected {background:buttonface !important;border-bottom:0 !important;color:black !important; z-index:2; text-shadow:none !important;}\n"+
  788.  
  789. ".inline {display:inline-block;}\n"+
  790. ".block {display:block;}\n"+
  791. ".tablerow {display:table-row;}\n"+
  792. ".tablecell {display:table-cell;}\n"+
  793. ".floatright {float:right;}\n"+
  794. ".floatleft {float:left;}\n"+
  795.  
  796. ".underline {border-bottom:1px solid #70BAFF;}\n"+
  797. ".overline {border-bottom:1px solid #70BAFF;}\n"+
  798. ".hidden {display:none;}\n"+
  799. ".unreleased, .ghost, .ended {opacity:0.25;}\n"+
  800. ".highlight {background:#94BC41 !important; color:black;}\n"+
  801. ".green {background:green !important;color:black;}\n"+
  802. ".red {background:darkred !important;color:black;}\n"+
  803. ".blue {background:royalblue !important;color:black;}\n"+
  804. ".orange {background:darkorange !important;color:black;}\n"+
  805. ".yellow {background:gold !important;color:black;}\n"+
  806. ".silver {background:silver !important;color:black;}\n"+
  807. ".gray {background:gray !important;color:black;}\n"+
  808. ".white {background:white !important;color:black;}\n"+
  809. ".black {background:black !important;color:white;}\n"+
  810. ".box {border:1px solid silver;}\n"+
  811. ".newopt {background:#027B09 !important;}\n"+
  812. ".newopt1 {background:green !important;}\n"+
  813. ".newopt2 {background:darkred !important;}\n"+
  814. ".newopt3 {background:royalblue !important;}\n"+
  815.  
  816. ".text_border_sep {font-family:tahoma; text-shadow: 0 0 1px black, 0 0 1px black, 0 0 1px black, 0 0 1px black;text-transform:uppercase; font-weight:900 !important;}\n"+
  817. ".text_border_sec {font-family:tahoma; text-shadow: 0 0 1px black, 0 0 1px black, 0 0 1px black, 0 0 1px black;text-transform:uppercase; font-weight:900 !important;}\n"+
  818.  
  819. "#buttons_holder {bottom: 0; position: fixed; right: 0; z-index: 1;}\n"+
  820. ".bigSpacer {height:50px; display:block;}\n"+
  821.  
  822. //little button div
  823. ".littleButton {background-color:threedshadow; border-radius:5px; margin:1px; display:inline-block; vertical-align:middle;}\n"+
  824. ".littleButton:hover {background-color:highlight !important;}\n"+
  825. ".littleButton>img {position:relative; display:block;}\n"+
  826. ".littleButton.oddOrange {background-color:#FF9968;}\n"+
  827. ".littleButton.oddBlack {background-color:#82976E;}\n"+
  828. ".littleButton.oddBlue {background-color:#51D1EA;}\n"+
  829. ".littleButton.oddGreen {background-color:#B7E54F;}\n"+
  830. ".counter {margin-left: 5px; margin-right:-5px; font-size: .75em; padding: 2px; border: 1px solid black; border-radius: 4px; position: relative; top: -1em; display: none; line-height:1em; text-shadow:none; color:white;}\n"+
  831. "", //leave here
  832. user: ""
  833. };
  834.  
  835. this.center = function() {try{
  836. var node = this.frame;
  837. if (!node) return;
  838. var style = node.style, beforeOpacity = style.opacity;
  839. if(style.display=='none') style.opacity='0';
  840. style.display = '';
  841. style.top = Math.floor((window.innerHeight/2)-(node.offsetHeight/2)) + 'px';
  842. style.left = Math.floor((window.innerWidth/2)-(node.offsetWidth/2)) + 'px';
  843. style.opacity = '1';
  844. }catch(e){log("Config.center: "+e);}};
  845.  
  846. this.addEvent = function(el,ev,scr) {try{
  847. el.addEventListener(ev, function() { typeof scr == 'function' ? doAction(scr) : eval(scr) }, false);
  848. }catch(e){log("Config.addEvent: "+e);}};
  849.  
  850. this.toggle = function(e,newMode) {try{
  851. var node=this.frame.contentDocument.getElementById((newMode)?'field_'+e:e);
  852. node.style.display=(node.style.display!='none')?'none':'block';
  853. node.setAttribute("data-ft",node.style.display);
  854. if (this.useScrollIntoView && node.style.display!='none') node.parentNode.scrollIntoView(true);
  855. //Config.setValue(e, node.style.display);
  856. }catch(e){log("Config.toggle: "+e);}};
  857.  
  858. this.toggleTab = function(e) {try{
  859. var tabBodyNode=this.frame.contentDocument.getElementById('field_'+e);
  860. var tabHeaderNode=this.frame.contentDocument.getElementById('tab_'+e);
  861.  
  862. //unselect selected tabs
  863. var tabCtrl = tabBodyNode.parentNode;
  864. var tabs=selectNodes("./span[contains(@class,'tab_element')]/a[contains(@class,'tab_selected')] | ./div[contains(@class,'tab_header_container')]/span[contains(@class,'tab_element')]/a[contains(@class,'tab_selected')]",{node:tabCtrl,doc:$("Config").contentDocument});
  865. if (tabs) for (var i=0,tab;(tab=tabs.snapshotItem(i));i++) {
  866. var id=tab.id.substring(4);
  867. tab.className = tab.className.replace(' tab_selected','');
  868. var node=$('field_'+id,$("Config").contentDocument);
  869. node.style.display='none';
  870. node.setAttribute("data-ft","none");
  871. tab=null;
  872. }
  873.  
  874. //select the tab
  875. tabHeaderNode.className += " tab_selected";
  876. tabBodyNode.style.display="block";
  877. tabBodyNode.setAttribute("data-ft","block");
  878.  
  879. //bring into view
  880. if (this.useScrollIntoView) tabHeaderNode.scrollIntoView(true);
  881.  
  882. //cleanup
  883. tabBodyNode = null;tabHeaderNode=null;tabCtrl=null;tabs=null;
  884. }catch(e){log("Config.toggleTab: "+e);}};
  885.  
  886. //initialize
  887. if (exists(params)) {
  888. this.init(params);
  889. }
  890. return self;
  891. };
  892. })();