html-utils

utils for DOM manipulation and fetching info of a webpage

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

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

QingJ © 2025

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