GM_config_zh

GM_config 中文版

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/447340/1252278/GM_config_zh.js

  1. // ==UserScript==
  2. // @name GM_config_zh
  3. // @author Mike Medley & zxf10608 & maomao1996
  4. // @version 1.0.1
  5. // @description GM_config 中文版
  6. // @grant GM_getValue
  7. // @grant GM_setValue
  8. // @grant GM_deleteValue
  9. // @exclude *
  10. // @license LGPL 3
  11. // ==/UserScript==
  12.  
  13. // The GM_config constructor
  14. function GM_configStruct() {
  15. // call init() if settings were passed to constructor
  16. if (arguments.length) {
  17. GM_configInit(this, arguments)
  18. this.onInit()
  19. }
  20. }
  21.  
  22. function noop() {}
  23.  
  24. // This is the initializer function
  25. function GM_configInit(config, args) {
  26. // Initialize instance variables
  27. if (typeof config.fields == 'undefined') {
  28. config.fields = {}
  29. config.onInit = config.onInit || noop
  30. config.onOpen = config.onOpen || noop
  31. config.onSave = config.onSave || noop
  32. config.onClose = config.onClose || noop
  33. config.onReset = config.onReset || noop
  34. config.isOpen = false
  35. config.title = '用户脚本设置'
  36. config.css = {
  37. basic:
  38. [
  39. '#GM_config * { font-family: arial,tahoma,myriad pro,sans-serif; }',
  40. '#GM_config { background: #FFF; }',
  41. "#GM_config input[type='radio'] { margin-right: 8px; }",
  42. '#GM_config .indent40 { margin-left: 40%; }',
  43. '#GM_config .field_label { font-size: 14px; font-weight: bold; margin-right: 6px; }',
  44. '#GM_config .radio_label { font-size: 14px; }',
  45. '#GM_config .block { display: block; }',
  46. '#GM_config .saveclose_buttons { margin: 16px 10px 10px; padding: 2px 12px; }',
  47. '#GM_config .reset, #GM_config .reset a,' +
  48. ' #GM_config_buttons_holder { color: #000; text-align: right; }',
  49. '#GM_config .config_header { font-size: 20pt; margin: 0; }',
  50. '#GM_config .config_desc, #GM_config .section_desc, #GM_config .reset { font-size: 9pt; }',
  51. '#GM_config .center { text-align: center; }',
  52. '#GM_config .section_header_holder { margin-top: 8px; }',
  53. '#GM_config .config_var { margin: 0 0 4px; }',
  54. '#GM_config .section_header { background: #414141; border: 1px solid #000; color: #FFF;' +
  55. ' font-size: 12pt; margin: 0; }',
  56. '#GM_config .section_desc { background: #EFEFEF; border: 1px solid #CCC; color: #575757;' +
  57. ' font-size: 10pt; margin: 0 0 6px; }',
  58. // newer
  59. "#GM_config input[type='number'] { width: 60px; }",
  60. '#GM_config .nav-tabs { margin: 10 0}',
  61. '#GM_config .nav-tabs > div { display: inline; padding: 3px 10px; }',
  62. '#pv-prefs .section_header_holder { padding-left: 10px; }',
  63. ].join('\n') + '\n',
  64. skin_tab:
  65. [
  66. '#GM_config { background: #EEE; }',
  67. '#GM_config textarea { width: 98%; height: 45px; margin-top: 5px; }',
  68. '#GM_config .field_label { display: inline-block; font-weight: normal; }',
  69. // 在同一行内的设置
  70. "#GM_config .inline input[type='checkbox'] {margin: 3px 3px 3px 0px;}",
  71. '#GM_config .inline .config_var { margin-left: 15px; }',
  72. // 内容样式
  73. '#GM_config .config_var { font-size: 14px; padding: 5px; margin: 0; }',
  74. '#GM_config .config_header a { text-decoration: none; color: #000; }',
  75. '#GM_config .nav-tabs { margin: 20 0}',
  76. '#GM_config .nav-tabs > div { font-size: 15px; color: #999; cursor: pointer; padding: 10px 20px; }',
  77. '#GM_config .nav-tabs > .active { cursor: default; color: #FFF; }',
  78. '#GM_config .nav-tabs > div:hover { color: #FFF; }',
  79. ].join('\n') + '\n',
  80. skin_1:
  81. [
  82. // 仿 Mouseover Popup Image Viewer 样式
  83. '#GM_config { background: #EEE; }',
  84. '#GM_config textarea { width: 98%; height: 45px; margin-top: 5px; }',
  85. '#GM_config .config_var { font-size: 12px; }',
  86. '#GM_config .inline .config_var { margin-left: 15px; }',
  87. '#GM_config .field_label { display: inline-block; font-weight: normal; }',
  88. '#GM_config { padding: 20px 30px; margin: 0; }',
  89. '#GM_config .config_header { margin-bottom: 10px; }',
  90. '#GM_config div.config_var { padding: 7px 0; }',
  91. ].join('\n') + '\n',
  92. basicPrefix: 'GM_config',
  93. stylish: '',
  94. }
  95. }
  96.  
  97. if (args.length == 1 && typeof args[0].id == 'string' && typeof args[0].appendChild != 'function')
  98. var settings = args[0]
  99. else {
  100. // Provide backwards-compatibility with argument style intialization
  101. var settings = {}
  102.  
  103. // loop through GM_config.init() arguments
  104. for (var i = 0, l = args.length, arg; i < l; ++i) {
  105. arg = args[i]
  106.  
  107. // An element to use as the config window
  108. if (typeof arg.appendChild == 'function') {
  109. settings.frame = arg
  110. continue
  111. }
  112.  
  113. switch (typeof arg) {
  114. case 'object':
  115. for (var j in arg) {
  116. // could be a callback functions or settings object
  117. if (typeof arg[j] != 'function') {
  118. // we are in the settings object
  119. if (typeof arg[j] == 'string') {
  120. settings.frameStyle = arg
  121. } else {
  122. settings.fields = arg // store settings object
  123. }
  124. break // leave the loop
  125. } // otherwise it must be a callback function
  126. if (!settings.events) settings.events = {}
  127. settings.events[j] = arg[j]
  128. }
  129. break
  130. case 'function': // passing a bare function is set to open callback
  131. settings.events = { open: arg }
  132. break
  133. case 'string': // could be custom CSS or the title string
  134. // if (/[\w\.]+\s*\{\s*[\w-]+\s*:\s*\w+[\s|\S]*\}/.test(arg))
  135. if (/[\w\.]+\s*\{\s*[\w-]+\s*:[\s|\S]*\}/.test(arg)) settings.css = arg
  136. else if (arg) settings.title = arg
  137. break
  138. }
  139. }
  140. }
  141.  
  142. /* Initialize everything using the new settings object */
  143. // Set the id
  144. if (settings.id) config.id = settings.id
  145. else if (typeof config.id == 'undefined') config.id = 'GM_config'
  146.  
  147. // Set the title
  148. if (settings.title) config.title = settings.title
  149.  
  150. // Set the custom css
  151. if (settings.css) config.css.stylish = settings.css
  152.  
  153. if (settings.skin) {
  154. var skin = config.css['skin_' + settings.skin]
  155. if (skin) {
  156. config.css.basic += skin
  157. }
  158. }
  159.  
  160. // Set the frame
  161. if (settings.frame) config.frame = settings.frame
  162. if (settings.frameStyle) config.frameStyle = settings.frameStyle
  163.  
  164. config.isTabs = settings.isTabs
  165.  
  166. // Set the event callbacks
  167. if (settings.events) {
  168. var events = settings.events
  169. for (var e in events) config['on' + e.charAt(0).toUpperCase() + e.slice(1)] = events[e]
  170. }
  171.  
  172. // Create the fields
  173. if (settings.fields) {
  174. var stored = config.read(), // read the stored settings
  175. fields = settings.fields,
  176. customTypes = settings.types || {}
  177.  
  178. for (var id in fields) {
  179. var field = fields[id]
  180.  
  181. // for each field definition create a field object
  182. if (field)
  183. config.fields[id] = new GM_configField(field, stored[id], id, customTypes[field.type])
  184. else if (config.fields[id]) delete config.fields[id]
  185. }
  186. }
  187.  
  188. // If the id has changed we must modify the default style
  189. if (config.id != config.css.basicPrefix) {
  190. config.css.basic = config.css.basic.replace(
  191. new RegExp('#' + config.css.basicPrefix, 'gm'),
  192. '#' + config.id,
  193. )
  194. config.css.basicPrefix = config.id
  195. }
  196. }
  197.  
  198. GM_configStruct.prototype = {
  199. // Support old method of initalizing
  200. init: function () {
  201. GM_configInit(this, arguments)
  202. this.onInit()
  203. },
  204.  
  205. // call GM_config.open() from your script to open the menu
  206. open: function () {
  207. // Die if the menu is already open on this page
  208. // You can have multiple instances but you can't open the same instance twice
  209. var match = top.document.getElementById(this.id)
  210. if (match && (match.tagName == 'IFRAME' || match.childNodes.length > 0)) return
  211.  
  212. // Sometimes "this" gets overwritten so create an alias
  213. var config = this
  214.  
  215. // Function to build the mighty config window :)
  216. function buildConfigWin(body, head) {
  217. var create = config.create,
  218. fields = config.fields,
  219. configId = config.id,
  220. bodyWrapper = create('div', { id: configId + '_wrapper' })
  221.  
  222. // Append the style which is our default style plus the user style
  223. head.appendChild(
  224. create('style', {
  225. type: 'text/css',
  226. textContent: config.css.basic + config.css.stylish,
  227. }),
  228. )
  229.  
  230. // Add header and title
  231. bodyWrapper.appendChild(
  232. create(
  233. 'div',
  234. {
  235. id: configId + '_header',
  236. className: 'config_header block center',
  237. },
  238. config.title,
  239. ),
  240. )
  241.  
  242. // Append elements
  243. var section = bodyWrapper,
  244. secNum = 0 // Section count
  245. var lastParentNode = null
  246.  
  247. // loop through fields
  248. for (var id in fields) {
  249. var field = fields[id],
  250. settings = field.settings
  251.  
  252. if (settings.section) {
  253. // the start of a new section
  254. section = bodyWrapper.appendChild(
  255. create('div', {
  256. className: 'section_header_holder',
  257. id: configId + '_section_' + secNum,
  258. }),
  259. )
  260.  
  261. if (Object.prototype.toString.call(settings.section) !== '[object Array]')
  262. settings.section = [settings.section]
  263.  
  264. if (settings.section[0])
  265. section.appendChild(
  266. create(
  267. 'div',
  268. {
  269. className: 'section_header center',
  270. id: configId + '_section_header_' + secNum,
  271. },
  272. settings.section[0],
  273. ),
  274. )
  275.  
  276. if (settings.section[1])
  277. section.appendChild(
  278. create(
  279. 'p',
  280. {
  281. className: 'section_desc center',
  282. id: configId + '_section_desc_' + secNum,
  283. },
  284. settings.section[1],
  285. ),
  286. )
  287. ++secNum
  288. }
  289.  
  290. if (settings.line == 'start' && lastParentNode) {
  291. // 切换到下一行
  292. lastParentNode = null
  293. }
  294.  
  295. // Create field elements and append to current section
  296. ;(lastParentNode || section).appendChild(
  297. (field.wrapper = field.toNode(configId, lastParentNode)),
  298. )
  299.  
  300. if (settings.line == 'start') {
  301. lastParentNode = field.wrapper
  302. lastParentNode.classList.add('inline')
  303. } else if (settings.line == 'end') {
  304. lastParentNode = null
  305. }
  306. }
  307.  
  308. // Add save and close buttons
  309. bodyWrapper.appendChild(
  310. create(
  311. 'div',
  312. { id: configId + '_buttons_holder' },
  313.  
  314. create('button', {
  315. id: configId + '_saveBtn',
  316. textContent: '确定',
  317. title: '部分选项需要刷新页面才能生效',
  318. className: 'saveclose_buttons',
  319. onclick: function () {
  320. config.save()
  321. config.close()
  322. },
  323. }),
  324.  
  325. create('button', {
  326. id: configId + '_closeBtn',
  327. textContent: '取消',
  328. title: '取消本次设置,所有选项还原',
  329. className: 'saveclose_buttons',
  330. onclick: function () {
  331. config.close()
  332. },
  333. }),
  334.  
  335. create(
  336. 'div',
  337. { className: 'reset_holder block' },
  338.  
  339. // Reset link
  340. create('a', {
  341. id: configId + '_resetLink',
  342. textContent: '恢复默认设置',
  343. href: '#',
  344. title: '恢复所有设置的内容为默认值',
  345. className: 'reset',
  346. onclick: function (e) {
  347. e.preventDefault()
  348. config.reset()
  349. },
  350. }),
  351. ),
  352. ),
  353. )
  354.  
  355. body.appendChild(bodyWrapper) // Paint everything to window at once
  356. config.center() // Show and center iframe
  357. top.addEventListener('resize', config.center, false) // Center frame on resize
  358.  
  359. // Call the open() callback function
  360. config.onOpen(
  361. config.frame.contentDocument || config.frame.ownerDocument,
  362. config.frame.contentWindow || window,
  363. config.frame,
  364. )
  365.  
  366. if (config.isTabs) {
  367. config.toTabs()
  368. }
  369.  
  370. // Close frame on window close
  371. window.addEventListener(
  372. 'beforeunload',
  373. function () {
  374. config.close()
  375. },
  376. false,
  377. )
  378.  
  379. // Now that everything is loaded, make it visible
  380. config.frame.style.display = 'block'
  381. config.isOpen = true
  382. }
  383.  
  384. // Change this in the onOpen callback using this.frame.setAttribute('style', '')
  385. var defaultStyle =
  386. 'bottom: auto; border: 1px solid #000; display: none; height: 75%;' +
  387. ' left: 0; margin: 0; max-height: 95%; max-width: 95%; opacity: 0;' +
  388. ' overflow: auto; padding: 0; position: fixed; right: auto; top: 0;' +
  389. ' width: 75%; z-index: 999999999;'
  390.  
  391. // Either use the element passed to init() or create an iframe
  392. if (this.frame) {
  393. this.frame.id = this.id // Allows for prefixing styles with the config id
  394. this.frame.setAttribute('style', defaultStyle)
  395. buildConfigWin(this.frame, this.frame.ownerDocument.getElementsByTagName('head')[0])
  396. } else {
  397. // Create frame
  398. top.document.body.appendChild(
  399. (this.frame = this.create('iframe', {
  400. id: this.id,
  401. style: defaultStyle,
  402. })),
  403. )
  404.  
  405. if (this.frameStyle) {
  406. Object.keys(this.frameStyle).forEach(function (key) {
  407. config.frame.style[key] = config.frameStyle[key]
  408. })
  409. }
  410.  
  411. // In WebKit src can't be set until it is added to the page
  412. this.frame.src = 'about:blank'
  413. // we wait for the iframe to load before we can modify it
  414. this.frame.addEventListener(
  415. 'load',
  416. function (e) {
  417. var frame = config.frame
  418. var body = frame.contentDocument.getElementsByTagName('body')[0]
  419. body.id = config.id // Allows for prefixing styles with the config id
  420. buildConfigWin(body, frame.contentDocument.getElementsByTagName('head')[0])
  421. },
  422. false,
  423. )
  424. }
  425. },
  426.  
  427. save: function () {
  428. var forgotten = this.write()
  429. this.onSave(forgotten) // Call the save() callback function
  430. },
  431.  
  432. close: function () {
  433. if (!this.frame) return
  434. // If frame is an iframe then remove it
  435. if (this.frame.contentDocument) {
  436. this.remove(this.frame)
  437. this.frame = null
  438. } else {
  439. // else wipe its content
  440. this.frame.innerHTML = ''
  441. this.frame.style.display = 'none'
  442. }
  443.  
  444. // Null out all the fields so we don't leak memory
  445. var fields = this.fields
  446. for (var id in fields) {
  447. var field = fields[id]
  448. field.wrapper = null
  449. field.node = null
  450. }
  451.  
  452. this.onClose() // Call the close() callback function
  453. this.isOpen = false
  454. },
  455.  
  456. set: function (name, val) {
  457. this.fields[name].value = val
  458.  
  459. if (this.fields[name].node) {
  460. this.fields[name].reload()
  461. }
  462. },
  463.  
  464. get: function (name, getLive) {
  465. var field = this.fields[name],
  466. fieldVal = null
  467.  
  468. if (getLive && field.node) {
  469. fieldVal = field.toValue()
  470. }
  471.  
  472. return fieldVal != null ? fieldVal : field.value
  473. },
  474.  
  475. write: function (store, obj) {
  476. if (!obj) {
  477. var values = {},
  478. forgotten = {},
  479. fields = this.fields
  480.  
  481. for (var id in fields) {
  482. var field = fields[id]
  483. var value = field.toValue()
  484.  
  485. if (field.save) {
  486. if (value != null) {
  487. values[id] = value
  488. field.value = value
  489. } else values[id] = field.value
  490. } else forgotten[id] = value
  491. }
  492. }
  493. try {
  494. this.setValue(store || this.id, this.stringify(obj || values))
  495. } catch (e) {
  496. this.log('GM_config failed to save settings!')
  497. }
  498.  
  499. return forgotten
  500. },
  501.  
  502. read: function (store) {
  503. try {
  504. var rval = this.parser(this.getValue(store || this.id, '{}'))
  505. } catch (e) {
  506. this.log('GM_config failed to read saved settings!')
  507. var rval = {}
  508. }
  509. return rval
  510. },
  511.  
  512. reset: function () {
  513. var fields = this.fields
  514.  
  515. // Reset all the fields
  516. for (var id in fields) fields[id].reset()
  517.  
  518. this.onReset() // Call the reset() callback function
  519. },
  520.  
  521. create: function () {
  522. switch (arguments.length) {
  523. case 1:
  524. var A = document.createTextNode(arguments[0])
  525. break
  526. default:
  527. var A = document.createElement(arguments[0]),
  528. B = arguments[1]
  529. for (var b in B) {
  530. if (b.indexOf('on') == 0) A.addEventListener(b.substring(2), B[b], false)
  531. else if (
  532. ',style,accesskey,id,name,src,href,which,for'.indexOf(',' + b.toLowerCase()) != -1
  533. )
  534. A.setAttribute(b, B[b])
  535. else if (typeof B[b] != 'undefined') A[b] = B[b]
  536. }
  537. if (typeof arguments[2] == 'string') A.innerHTML = arguments[2]
  538. else for (var i = 2, len = arguments.length; i < len; ++i) A.appendChild(arguments[i])
  539. }
  540. return A
  541. },
  542.  
  543. center: function () {
  544. var node = this.frame
  545. if (!node) return
  546. var style = node.style,
  547. beforeOpacity = style.opacity
  548. if (style.display == 'none') style.opacity = '0'
  549. style.display = ''
  550. style.top = Math.floor(top.innerHeight / 2 - node.offsetHeight / 2) + 'px'
  551. style.left = Math.floor(top.innerWidth / 2 - node.offsetWidth / 2) + 'px'
  552. style.opacity = '1'
  553. },
  554.  
  555. remove: function (el) {
  556. if (el && el.parentNode) el.parentNode.removeChild(el)
  557. },
  558.  
  559. toTabs: function () {
  560. // 转为 tab 的形式
  561. var body = this.frame.tagName == 'IFRAME' ? this.frame.contentWindow.document : this.frame,
  562. configId = this.id
  563. var $ = function (id) {
  564. return body.getElementById(configId + '_' + id)
  565. }
  566.  
  567. var headers = body.querySelectorAll('.section_header')
  568. if (!headers.length) return
  569.  
  570. var anch = this.create('div', {
  571. // id: configId + '_tab_holder',
  572. className: 'nav-tabs',
  573. })
  574.  
  575. for (var i = 0, header; i < headers.length; i++) {
  576. header = headers[i]
  577. if (i == 0) {
  578. header.classList.add('active')
  579. }
  580. anch.appendChild(header)
  581. }
  582.  
  583. anch.addEventListener('click', this.toggleTab.bind(this), false)
  584.  
  585. $('section_0').parentNode.insertBefore(anch, $('section_0'))
  586.  
  587. var curTab = localStorage.getItem('picviewerCE.config.curTab') || 0
  588. this.toggleTab(parseInt(curTab, 10))
  589. },
  590. toggleTab: function (e) {
  591. var body = this.frame.tagName == 'IFRAME' ? this.frame.contentWindow.document : this.frame,
  592. configId = this.id
  593.  
  594. var curTab = typeof e == 'number' ? e : /\_(\d+)/.exec(e.target.id)[1]
  595.  
  596. ;[].forEach.call(body.querySelectorAll('.section_header'), function (header, i) {
  597. if (i == curTab) {
  598. header.classList.add('active')
  599. } else {
  600. header.classList.remove('active')
  601. }
  602. })
  603. ;[].forEach.call(body.querySelectorAll('.section_header_holder'), function (holder, i) {
  604. holder.style.display = i == curTab ? 'block' : 'none'
  605. })
  606.  
  607. localStorage.setItem('picviewerCE.config.curTab', curTab)
  608. },
  609. }
  610.  
  611. // Define a bunch of API stuff
  612. ;(function () {
  613. var isGM = typeof GM_getValue != 'undefined' && typeof GM_getValue('a', 'b') != 'undefined',
  614. setValue,
  615. getValue,
  616. stringify,
  617. parser
  618.  
  619. // Define value storing and reading API
  620. if (!isGM) {
  621. setValue = function (name, value) {
  622. return localStorage.setItem(name, value)
  623. }
  624. getValue = function (name, def) {
  625. var s = localStorage.getItem(name)
  626. return s == null ? def : s
  627. }
  628.  
  629. // We only support JSON parser outside GM
  630. stringify = JSON.stringify
  631. parser = JSON.parse
  632. } else {
  633. setValue = GM_setValue
  634. getValue = GM_getValue
  635. stringify =
  636. typeof JSON == 'undefined'
  637. ? function (obj) {
  638. return obj.toSource()
  639. }
  640. : JSON.stringify
  641. parser =
  642. typeof JSON == 'undefined'
  643. ? function (jsonData) {
  644. return new Function('return ' + jsonData + ';')()
  645. }
  646. : JSON.parse
  647. }
  648.  
  649. GM_configStruct.prototype.isGM = isGM
  650. GM_configStruct.prototype.setValue = setValue
  651. GM_configStruct.prototype.getValue = getValue
  652. GM_configStruct.prototype.stringify = stringify
  653. GM_configStruct.prototype.parser = parser
  654. GM_configStruct.prototype.log = window.console
  655. ? console.log
  656. : isGM && typeof GM_log != 'undefined'
  657. ? GM_log
  658. : window.opera
  659. ? opera.postError
  660. : function () {
  661. /* no logging */
  662. }
  663. })()
  664.  
  665. function GM_configDefaultValue(type, options) {
  666. var value
  667.  
  668. if (type && type.indexOf('unsigned ') == 0) type = type.substring(9)
  669.  
  670. switch (type) {
  671. case 'radio':
  672. case 'select':
  673. value = options[0]
  674. break
  675. case 'checkbox':
  676. value = false
  677. break
  678. case 'int':
  679. case 'integer':
  680. case 'float':
  681. case 'number':
  682. value = 0
  683. break
  684. default:
  685. value = ''
  686. }
  687.  
  688. return value
  689. }
  690.  
  691. function GM_configField(settings, stored, id, customType) {
  692. // Store the field's settings
  693. this.settings = settings
  694. this.id = id
  695. this.node = null
  696. this.wrapper = null
  697. this.save = typeof settings.save == 'undefined' ? true : settings.save
  698.  
  699. // Buttons are static and don't have a stored value
  700. if (settings.type == 'button') this.save = false
  701. if (settings.type == 'span') this.save = false
  702.  
  703. // if a default value wasn't passed through init() then
  704. // if the type is custom use its default value
  705. // else use default value for type
  706. // else use the default value passed through init()
  707. this['default'] =
  708. typeof settings['default'] == 'undefined'
  709. ? customType
  710. ? customType['default']
  711. : GM_configDefaultValue(settings.type, settings.options)
  712. : settings['default']
  713.  
  714. // Store the field's value
  715. this.value = typeof stored == 'undefined' ? this['default'] : stored
  716.  
  717. // Setup methods for a custom type
  718. if (customType) {
  719. this.toNode = customType.toNode
  720. this.toValue = customType.toValue
  721. this.reset = customType.reset
  722. }
  723. }
  724.  
  725. GM_configField.prototype = {
  726. create: GM_configStruct.prototype.create,
  727.  
  728. toNode: function (configId, lastParentNode) {
  729. var field = this.settings,
  730. value = this.value,
  731. options = field.options,
  732. type = field.type,
  733. id = this.id,
  734. labelPos = field.labelPos,
  735. create = this.create
  736.  
  737. function addLabel(pos, labelEl, parentNode, beforeEl) {
  738. if (!beforeEl) {
  739. beforeEl = lastParentNode ? parentNode.lastChild : parentNode.firstChild // oneLine 的修正
  740. }
  741.  
  742. switch (pos) {
  743. case 'right':
  744. case 'below':
  745. if (pos == 'below') parentNode.appendChild(create('br', {}))
  746. parentNode.appendChild(labelEl)
  747. break
  748. default:
  749. if (pos == 'above') parentNode.insertBefore(create('br', {}), beforeEl)
  750. parentNode.insertBefore(labelEl, beforeEl)
  751. }
  752. }
  753.  
  754. var retNode = create('div', {
  755. className: 'config_var',
  756. id: configId + '_' + id + '_var',
  757. title: field.title || '',
  758. }),
  759. firstProp
  760.  
  761. // Retrieve the first prop
  762. for (var i in field) {
  763. firstProp = i
  764. break
  765. }
  766.  
  767. var label =
  768. field.label && type != 'button'
  769. ? create(
  770. 'label',
  771. {
  772. id: configId + '_' + id + '_field_label',
  773. for: configId + '_field_' + id,
  774. className: 'field_label',
  775. },
  776. field.label,
  777. )
  778. : null
  779.  
  780. switch (type) {
  781. case 'span':
  782. label = null
  783.  
  784. this.node = create('span', {
  785. innerHTML: field.label,
  786. className: 'field_label',
  787. title: field.title,
  788. style: field.style,
  789. })
  790. retNode = this.node
  791. break
  792. case 'textarea':
  793. retNode.appendChild(
  794. (this.node = create('textarea', {
  795. innerHTML: value,
  796. id: configId + '_field_' + id,
  797. className: 'block' + (field.className ? ' ' + field.className : ''),
  798. cols: field.cols ? field.cols : 20,
  799. rows: field.rows ? field.rows : 2,
  800. placeholder: field.placeholder,
  801. })),
  802. )
  803. break
  804. case 'radio':
  805. var wrap = create('div', {
  806. id: configId + '_field_' + id,
  807. className: field.className,
  808. })
  809. this.node = wrap
  810.  
  811. for (var i = 0, len = options.length; i < len; ++i) {
  812. var radLabel = create(
  813. 'label',
  814. {
  815. className: 'radio_label',
  816. },
  817. options[i],
  818. )
  819.  
  820. var rad = wrap.appendChild(
  821. create('input', {
  822. value: options[i],
  823. type: 'radio',
  824. name: id,
  825. checked: options[i] == value,
  826. }),
  827. )
  828.  
  829. var radLabelPos =
  830. labelPos && (labelPos == 'left' || labelPos == 'right')
  831. ? labelPos
  832. : firstProp == 'options'
  833. ? 'left'
  834. : 'right'
  835.  
  836. addLabel(radLabelPos, radLabel, wrap, rad)
  837. }
  838.  
  839. retNode.appendChild(wrap)
  840. break
  841. case 'select':
  842. var wrap = create('select', {
  843. id: configId + '_field_' + id,
  844. })
  845. this.node = wrap
  846.  
  847. for (var i = 0, len = options.length; i < len; ++i) {
  848. var option = options[i]
  849. wrap.appendChild(
  850. create(
  851. 'option',
  852. {
  853. value: option,
  854. selected: option == value,
  855. },
  856. option,
  857. ),
  858. )
  859. }
  860.  
  861. retNode.appendChild(wrap)
  862. break
  863. default:
  864. // fields using input elements
  865. var props = {
  866. id: configId + '_field_' + id,
  867. type: type,
  868. value: type == 'button' ? field.label : value,
  869. }
  870.  
  871. switch (type) {
  872. case 'checkbox':
  873. props.checked = value
  874. break
  875. case 'button':
  876. props.size = field.size ? field.size : 25
  877. if (field.script) field.click = field.script
  878. if (field.click) props.onclick = field.click
  879. break
  880. case 'hidden':
  881. break
  882. default:
  883. // type = text, int, or float
  884. props.type = 'text'
  885. props.size = field.size ? field.size : 25
  886. }
  887.  
  888. retNode.appendChild((this.node = create('input', props)))
  889. }
  890.  
  891. if (label) {
  892. // If the label is passed first, insert it before the field
  893. // else insert it after
  894. if (!labelPos) labelPos = firstProp == 'label' || type == 'radio' ? 'left' : 'right'
  895.  
  896. addLabel(labelPos, label, retNode)
  897. }
  898.  
  899. return retNode
  900. },
  901.  
  902. toValue: function () {
  903. var node = this.node,
  904. field = this.settings,
  905. type = field.type,
  906. unsigned = false,
  907. rval = null
  908.  
  909. if (!node) return rval
  910.  
  911. if (type.indexOf('unsigned ') == 0) {
  912. type = type.substring(9)
  913. unsigned = true
  914. }
  915.  
  916. switch (type) {
  917. case 'checkbox':
  918. rval = node.checked
  919. break
  920. case 'select':
  921. rval = node[node.selectedIndex].value
  922. break
  923. case 'radio':
  924. var radios = node.getElementsByTagName('input')
  925. for (var i = 0, len = radios.length; i < len; ++i)
  926. if (radios[i].checked) rval = radios[i].value
  927. break
  928. case 'button':
  929. break
  930. case 'int':
  931. case 'integer':
  932. case 'float':
  933. case 'number':
  934. var num = Number(node.value)
  935. var warn = '字符 "' + field.label + '" 必须输入' + (unsigned ? ' 正 ' : 'n ') + '整数值'
  936.  
  937. if (
  938. isNaN(num) ||
  939. (type.substr(0, 3) == 'int' && Math.ceil(num) != Math.floor(num)) ||
  940. (unsigned && num < 0)
  941. ) {
  942. alert(warn + '.')
  943. return null
  944. }
  945.  
  946. if (!this._checkNumberRange(num, warn)) return null
  947. rval = num
  948. break
  949. default:
  950. rval = node.value
  951. break
  952. }
  953.  
  954. return rval // value read successfully
  955. },
  956.  
  957. reset: function () {
  958. var node = this.node,
  959. field = this.settings,
  960. type = field.type
  961.  
  962. if (!node) return
  963.  
  964. switch (type) {
  965. case 'checkbox':
  966. node.checked = this['default']
  967. break
  968. case 'select':
  969. for (var i = 0, len = node.options.length; i < len; ++i)
  970. if (node.options[i].value == this['default']) node.selectedIndex = i
  971. break
  972. case 'radio':
  973. var radios = node.getElementsByTagName('input')
  974. for (var i = 0, len = radios.length; i < len; ++i)
  975. if (radios[i].value == this['default']) radios[i].checked = true
  976. break
  977. case 'button':
  978. break
  979. default:
  980. node.value = this['default']
  981. break
  982. }
  983. },
  984.  
  985. remove: function (el) {
  986. GM_configStruct.prototype.remove(el || this.wrapper)
  987. this.wrapper = null
  988. this.node = null
  989. },
  990.  
  991. reload: function () {
  992. var wrapper = this.wrapper
  993. if (wrapper) {
  994. var fieldParent = wrapper.parentNode
  995. fieldParent.insertBefore((this.wrapper = this.toNode()), wrapper)
  996. this.remove(wrapper)
  997. }
  998. },
  999.  
  1000. _checkNumberRange: function (num, warn) {
  1001. var field = this.settings
  1002. if (typeof field.min == 'number' && num < field.min) {
  1003. alert(warn + '必须大于或等于' + field.min + '.')
  1004. return null
  1005. }
  1006.  
  1007. if (typeof field.max == 'number' && num > field.max) {
  1008. alert(warn + '必须小于或等于' + field.max + '.')
  1009. return null
  1010. }
  1011. return true
  1012. },
  1013. }
  1014.  
  1015. // Create default instance of GM_config
  1016. var GM_config = new GM_configStruct()

QingJ © 2025

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