html-utils

utils for DOM manipulation and fetching info of a webpage

当前为 2016-08-30 提交的版本,查看 最新版本

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

  1. var APP = APP || {};
  2. /**
  3. * Html Elements
  4. * @type {{Element, Button, Div, Input, Checkbox, Label, TextArea, Option, Select}}
  5. */
  6. APP.htmlUtils = (function() {
  7. 'use strict';
  8. var objectUtils = APP.objectUtils;
  9. var keeper = new objectUtils.Keeper();
  10. /**
  11. * Adds a HTML child node to a HTML parent node.
  12. * @param {HtmlElement|Element} parent - The html parent node
  13. * @param {HtmlElement|Element} child - The html child Element to be connected to the parent node
  14. * @param {boolean} [asFirstChild] - <code>true</code> to have the child be added as the first child before any other child
  15. */
  16. var connectParentChild = function(parent, child, asFirstChild) {
  17. var elParent = parent instanceof Element ? parent.domElement : parent;
  18. var elChild = child instanceof Element ? child.domElement : child;
  19. if (asFirstChild && elParent.hasChildNodes()) {
  20. elParent.insertBefore(elChild, elParent.firstChild);
  21. } else {
  22. elParent.appendChild(elChild);
  23. }
  24. };
  25. /**
  26. * Removes a HTML child element from a HTML parent node.
  27. * @param {HTMLElement} parent - The parent node
  28. * @param {HTMLElement} elChild - The child node to be removed of the parent element
  29. */
  30. var disconnectParentChild = function(parent, elChild) {
  31. var elParent = parent instanceof Element ? parent.domElement : parent;
  32. elParent.removeChild(elChild);
  33. };
  34. /**
  35. * Removes all HTML children from a parent node.
  36. * @param {HTMLElement} parent - The HTML parent node
  37. */
  38. var removeAllChildren = function(parent) {
  39. var elParent = parent instanceof Element ? parent.domElement : parent;
  40. while (elParent.hasChildNodes()) {
  41. elParent.removeChild(elParent.firstChild);
  42. }
  43. };
  44.  
  45. /**
  46. * Sorts options of a html 'select' element from a certain property of the option (e.g. text or value).
  47. * @param {HTMLElement|Element} select - The Select Element to be sorted
  48. * @param {string} [property=text] - The Name of the property from wich the option should be compared like <code>value</code> or <code>text</code>.
  49. * @param {boolean} [isOrderDescending] - <code>true</code> to reverse the sort order.
  50. */
  51. var sortSelectBy = function(select, property, isOrderDescending) {
  52. var elSelect = select instanceof Element ? select.domElement : select;
  53. var propertyName = property || 'text';
  54. var sortOptions = [];
  55. // options to array
  56. for (var i = 0; i <= select.length - 1; i++) {
  57. var option = select[i];
  58. sortOptions.push({
  59. value:option.value,
  60. text:option.text,
  61. selected:option.selected
  62. });
  63. }
  64. // sort array
  65. sortOptions.sort(function (a, b) {
  66. if (a[propertyName] < b[propertyName]) { return isOrderDescending ? 1 : -1; }
  67. if (a[propertyName] > b[propertyName]) { return isOrderDescending ? -1 : 1; }
  68. return 0;
  69. });
  70. // array to options
  71. sortOptions.forEach(function (opt, i) {
  72. select[i].text = opt.text;
  73. select[i].value = opt.value;
  74. select[i].selected = opt.selected;
  75. });
  76. };
  77.  
  78. /**
  79. * Wrapper for any type of HTML element.
  80. * @param {string} tagName - The type of element to be created and value of the <code>nodeName</code> attribute
  81. * @param {string} [id] - The value for the <code>id</code> attribute
  82. * @param {string} [className] - The value for the <code>class</code> attribute
  83. * @constructor
  84. */
  85. function Element(tagName, id, className) {
  86. if (!(this instanceof Element)) {
  87. return new Element(tagName, id, className);
  88. }
  89. var domElement = document.createElement(tagName);
  90. Object.defineProperty(this, "domElement", {
  91. get: function() { return domElement },
  92. configurable: true, enumerable: true
  93. });
  94. if (typeof id !== 'undefined') {
  95. this.domElement.id = id;
  96. }
  97. if (typeof className !== 'undefined') {
  98. this.domElement.className = className;
  99. }
  100. }
  101. Element.prototype = {
  102. constructor: Element,
  103. /**
  104. * Adds this HTML element to a parent node HTML element.
  105. * It will be added as the last child of the node.
  106. * @param {HTMLElement|Element} elParent - The parent HTML node element
  107. */
  108. addAsLastChild : function(elParent) {
  109. var parent = elParent instanceof Element ? elParent.domElement : elParent;
  110. connectParentChild(elParent, this.domElement, false);
  111. },
  112. /**
  113. * Adds this HTML element to a parent node HTML element.
  114. * It will be added as the first child of the node.
  115. * @param {HTMLElement|Element} elParent - The parent HTML node element
  116. */
  117. addAsFirstChild : function(elParent) {
  118. var parent = elParent instanceof Element ? elParent.domElement : elParent;
  119. connectParentChild(elParent, this, true);
  120. },
  121. /**
  122. * Adds this HTML element to a parent node HTML element.
  123. * All children elements will be removed and replaced with this node.
  124. * @param {HTMLElement|Element} elParent - The parent HTML node element
  125. */
  126. addAsOnlyChild : function(elParent) {
  127. var parent = elParent instanceof Element ? elParent.domElement : elParent;
  128. removeAllChildren(elParent);
  129. connectParentChild(elParent, this);
  130. },
  131. /**
  132. * Appends Html node elements to this node as their last children.
  133. * @param {...HTMLElement|Element} elements - Html elements to be added as children.
  134. */
  135. appendChildren : function(elements) {
  136. for (var i = 0; i <= arguments.length - 1; i++) {
  137. var child = arguments[i];
  138. this.domElement.appendChild(child instanceof Element ? child.domElement : child);
  139. }
  140. },
  141. /**
  142. * Adds Html node Elements to this node as their new children.
  143. * All current children elements will be removed and replaced with the new children.
  144. * @param {...HTMLElement} [elements] Html elements to be added as children
  145. * No argument will only remove all children.
  146. */
  147. setChildren : function(elements) {
  148. removeAllChildren(this);
  149. for (var i = 0; i <= arguments.length - 1; i++) {
  150. connectParentChild(this, arguments[i]);
  151. }
  152. }
  153. };
  154.  
  155. /**
  156. * Wrapper for a 'button' html element.
  157. * @param {string} [className] - the value for the <code>class</code> attribute
  158. * @param {function} [callback] - the callback function for the <code>onclick<code> event
  159. * @param {string} [text] - the content text of the element (text shown on the button)
  160. * @param {string} [id] - the value for the <code>id</code> attribute
  161. * @constructor
  162. */
  163. function Button(className, callback, text, id) {
  164. if (!(this instanceof Button)) {
  165. return new Button(className, callback, text, id);
  166. }
  167. Element.call(this, 'BUTTON', id, className);
  168. if (typeof callback === 'function') {
  169. this.domElement.addEventListener('click', callback);
  170. }
  171. if (typeof text !== 'undefined') {
  172. this.domElement.appendChild(document.createTextNode(text));
  173. }
  174. }
  175. objectUtils.extend(Button).from(Element);
  176.  
  177. /**
  178. * Wrapper for a 'div' html element.
  179. * @param {string} [id] - The value for the <code>id</code> attribute
  180. * @param {string} [className] - The value for the <code>class</code> attribute
  181. * @constructor
  182. */
  183. function Div(id, className) {
  184. if (!(this instanceof Div)) {
  185. return new Div(className, id);
  186. }
  187. Element.call(this, 'DIV', id, className);
  188. }
  189. objectUtils.extend(Div).from(Element);
  190.  
  191. /**
  192. * Wrapper for an 'input' HTML element as a field for text.
  193. * @param {number|string} [maxLength] - The maximum number of characters
  194. * @param {string} [text] - The value of the <code>text</code> attribute (content initially shown in the field)
  195. * @param {string} [className] - The value for the <code>class</code> attribute
  196. * @param {string} [id] - The value for the <code>id</code> attribute
  197. * @constructor
  198. */
  199. function Input(maxLength, text, className, id) {
  200. if (!(this instanceof Input)) {
  201. return new Input(maxLength, text, className, id);
  202. }
  203. Element.call(this, 'INPUT', id, className);
  204. if (typeof maxLength !== 'undefined') {
  205. this.domElement.maxlength = maxLength;
  206. }
  207. if (typeof text !== 'undefined') {
  208. this.domElement.value = text;
  209. }
  210. }
  211. objectUtils.extend(Input).from(Element);
  212.  
  213. /**
  214. * Creates an 'input' HTML element of type 'checkbox'.
  215. * @param {function} [callback] - The callback function for the <code>onChange<code> event
  216. * @param {string} [className] - The value for the <code>class</code> attribute
  217. * @param {string} [id] - The value for the <code>id</code> attribute
  218. * @constructor
  219. */
  220. function Checkbox (callback, className, id) {
  221. if (!(this instanceof Checkbox)) {
  222. return new Checkbox(callback, className, id);
  223. }
  224. Element.call(this, 'INPUT', id, className);
  225. this.domElement.type = 'checkbox';
  226. if (typeof callback === 'function') {
  227. this.domElement.addEventListener('change', callback);
  228. }
  229. }
  230. objectUtils.extend(Checkbox).from(Element);
  231.  
  232. /**
  233. * Wrapper for a 'label' html element.
  234. * @param {string} htmlFor - The value of the <code>for</code> attribute. The id value of another element to bind the label to that element.
  235. * @param {string} [text] - The content text of the element (text shown on the label)
  236. * @param {string} [className] - The value for the <code>class</code> attribute
  237. * @param {string} [id] - The value for the <code>id</code> attribute
  238. * @constructor
  239. */
  240. function Label(htmlFor, text, className, id) {
  241. if (!(this instanceof Label)) {
  242. return new Label(htmlFor, text, className, id);
  243. }
  244. Element.call(this, 'LABEL', id, className);
  245. if (typeof text !== 'undefined') {
  246. this.domElement.appendChild(document.createTextNode(text));
  247. }
  248. if (typeof htmlFor !== 'undefined') {
  249. this.domElement.htmlFor = htmlFor;
  250. }
  251. }
  252. objectUtils.extend(Label).from(Element);
  253.  
  254. /**
  255. * Wrapper for a 'TextArea' html element.
  256. * @param {number|string} [cols] - The number of columns
  257. * @param {number|string} [maxLength] The maximum number of characters
  258. * @param {string} [text] - The value of the <code>text</code> attribute (content initially shown in the field)
  259. * @param {string} [className] - The value for the <code>class</code> attribute
  260. * @param {string} [id] - The value of the <code>id</code> attribute
  261. * @constructor
  262. */
  263. function TextArea(cols, maxLength, text, className, id) {
  264. if (!(this instanceof TextArea)) {
  265. return new TextArea(cols, maxLength, text, className, id);
  266. }
  267. Element.call(this, 'TEXTAREA', id, className);
  268. if (typeof cols !== 'undefined') {
  269. this.domElement.cols = cols;
  270. }
  271. if (typeof maxLength !== 'undefined') {
  272. this.domElement.maxlength = maxLength;
  273. }
  274. if (typeof text !== 'undefined') {
  275. this.domElement.value = text;
  276. }
  277. }
  278. objectUtils.extend(TextArea).from(Element);
  279.  
  280. /**
  281. * Wrapper for an 'option' html element which can be added to a 'select' html element.
  282. * @param text The value of the <code>text</code> attribute shown in the select dropdown
  283. * @param value THe value of the <code>value</code> attribute
  284. * @constructor
  285. */
  286. function Option(text, value) {
  287. if (!(this instanceof Option)) {
  288. return new Option(text, value);
  289. }
  290. Element.call(this, 'OPTION');
  291. this.domElement.text = text;
  292. this.domElement.value = value;
  293. }
  294. objectUtils.extend(Option).from(Element);
  295.  
  296. /**
  297. * Wrapper for a 'Select' html element.
  298. * @param {string} [id] - The value of the <code>id</code> attribute
  299. * @param {function} [callback] - callback function triggered by the events <code>OnChange</code>, <code>OnKeyUp</code> and <code>OnFocus</code>
  300. * @param {string} [className] - The value for the <code>class</code> attribute
  301. * @constructor
  302. */
  303. function Select(className, callback, id) {
  304. if (!(this instanceof Select)) {
  305. return new Select(className, id);
  306. }
  307. Element.call(this, 'SELECT', id, className);
  308.  
  309. var idx = keeper.push({ onChangeCallback : callback });
  310. Object.defineProperty(this, 'idx', { get: function() { return idx } });
  311. Select.prototype.setOnChangeKeyUpFocus(callback);
  312. }
  313. Select.prototype = {
  314. constructor: Select,
  315. addNewOption: function(text, value) {
  316. var newOption = Option(text, value);
  317. this.domElement.add(newOption.domElement);
  318. return newOption;
  319. },
  320. sortOptionsByText: function(isOrderDesc) {
  321. sortSelectBy(this.domElement, 'text', isOrderDesc);
  322. },
  323. sortOptionsByValue: function(isOrderDesc) {
  324. sortSelectBy(this.domElement, 'value', isOrderDesc);
  325. },
  326. /**
  327. * Sets a callback function triggered from the events <code>OnChange</code>, <code>OnKeyUp</code> and <code>OnFocus</code>.
  328. * Removes any former callback function registered to these events.
  329. * @param {function} callback
  330. */
  331. setOnChangeKeyUpFocus: function(callback) {
  332. var newCallback = (typeof callback === 'function') ? callback : objectUtils.emptyFunction;
  333.  
  334. var formerCallback = keeper.get(this.idx).onChangeCallback;
  335. this.domElement.removeEventListener("focus", formerCallback);
  336. this.domElement.removeEventListener("change", formerCallback);
  337. this.domElement.removeEventListener("keyup", formerCallback);
  338.  
  339. keeper.get(this.idx).onChangeCallback = newCallback;
  340. this.domElement.addEventListener("focus", newCallback);
  341. this.domElement.addEventListener("change", newCallback);
  342. this.domElement.addEventListener("keyup", newCallback);
  343. }
  344. };
  345. objectUtils.extend(Select).from(Element);
  346.  
  347. /**
  348. * Parses a param object into a query string and vice verca.
  349. * @param {Object|string} query - the queryObject object or query string
  350. * @return {string|Object}
  351. */
  352. var parseParams = function(query){
  353. if (typeof query === 'string') {
  354. var result = {};
  355. var decode = function(s) {
  356. return decodeURIComponent(s.replace(/\+/g, " "));
  357. };
  358. var match, search = /([^&=]+)=?([^&]*)/g;
  359. while ((match = search.exec(query)) !== null) {
  360. result[decode(match[1])] = decode(match[2]);
  361. }
  362. return result;
  363. } else {
  364. var result = "";
  365. Object.keys(query).forEach(function(key, index) {
  366. if (index >= 1) {
  367. result += "&";
  368. }
  369. result += key + "=" + query[key];
  370. });
  371. return result;
  372. }
  373. };
  374.  
  375. /**
  376. * Deals with parameters of a query.
  377. * @param {string|Object} query - the query search as a string or as parameter object in {key:value} form
  378. * @constructor
  379. */
  380. function Params(query) {
  381. if (!(this instanceof Params)) {
  382. return new Params(query);
  383. }
  384. var _params = {};
  385. Object.defineProperties(this, {
  386. /** The {key:value} parameter object */
  387. queryObject: {
  388. get: function() { return _params; },
  389. enumerable: true, configurable: true
  390. },
  391. /** The queryString without leading '?' */
  392. queryString: {
  393. get: function () {
  394. if (!_params || Object.keys(_params).length === 0) {
  395. return "";
  396. } else {
  397. return parseParams(_params);
  398. }
  399. },
  400. set: function(val) {
  401. if (val) {
  402. if (val.charAt(0) === '?') {
  403. val = val.substring(1);
  404. }
  405. _params = parseParams(val);
  406. } else {
  407. _params = {};
  408. }
  409. },
  410. enumerable: true, configurable: true
  411. }
  412. });
  413. if (typeof query === 'string') {
  414. this.queryString = query;
  415. } else {
  416. _params = query;
  417. }
  418. Object.defineProperty(this, "value", {
  419. get: function () { return this.queryString; }
  420. });
  421. }
  422. objectUtils.extend(Params).from(objectUtils.Truthy);
  423.  
  424. var getPageAsync = function(url, onSuccess, onError) {
  425. if (typeof onSuccess !== 'function') { onSuccess = objectUtils.emptyFunction;}
  426. if (typeof onError !== 'function') { onError = objectUtils.emptyFunction;}
  427.  
  428. return GM_xmlhttpRequest({
  429. method: 'GET',
  430. url: url,
  431. onload: function(resp) {
  432. if (resp.status == 200 || resp.status == 304) {
  433. resp.html = new DOMParser().parseFromString(resp.responseText, 'text/html');
  434. onSuccess(resp);
  435. } else {
  436. onError(resp);
  437. }
  438. },
  439. onerror: onError
  440. });
  441. };
  442.  
  443. return {
  444. Element: Element,
  445. Button: Button,
  446. Div : Div,
  447. Input : Input,
  448. Checkbox : Checkbox,
  449. Label : Label,
  450. TextArea : TextArea,
  451. Option : Option,
  452. Select : Select,
  453. Params : Params,
  454. requestPageAsync : getPageAsync
  455. };
  456. })();

QingJ © 2025

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