html-utils

utils for DOM manipulation and fetching info of a webpage

当前为 2016-09-07 提交的版本,查看 最新版本

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

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

QingJ © 2025

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