WM Config Interface

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

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/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. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址