Everything-Hook

it can hook everything

目前为 2019-06-12 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/372672/707958/Everything-Hook.js

  1. // ==UserScript==
  2. // @name Everything-Hook
  3. // @namespace https://gitee.com/HGJing/everthing-hook/
  4. // @updateURL https://gitee.com/HGJing/everthing-hook/raw/master/src/everything-hook.js
  5. // @version 0.5.9047
  6. // @include *
  7. // @description it can hook everything
  8. // @author Cangshi
  9. // @match http://*/*
  10. // @grant none
  11. // @run-at document-start
  12. // ==/UserScript==
  13.  
  14. /**
  15. * ---------------------------
  16. * Time: 2017/9/20 18:33.
  17. * Author: Cangshi
  18. * View: http://palerock.cn
  19. * ---------------------------
  20. */
  21. 'use strict';
  22. /**
  23. * Every-Utils
  24. * version:0.0.2001
  25. */
  26. (function (global, factory) {
  27.  
  28. "use strict";
  29.  
  30. if (typeof module === "object" && typeof module.exports === "object") {
  31.  
  32. // For CommonJS and CommonJS-like environments where a proper `window`
  33. // is present, execute the factory and get jQuery.
  34. // For environments that do not have a `window` with a `document`
  35. // (such as Node.js), expose a factory as module.exports.
  36. // This accentuates the need for the creation of a real `window`.
  37. // e.g. var jQuery = require("jquery")(window);
  38. // See ticket #14549 for more info.
  39. module.exports = global.document ?
  40. factory(global, true) :
  41. function (w) {
  42. if (!w.document) {
  43. throw new Error("eUtils requires a window with a document");
  44. }
  45. return factory(w);
  46. };
  47. } else {
  48. factory(global);
  49. }
  50.  
  51. }(typeof window !== "undefined" ? window : this, function (_global, noGlobal) {
  52.  
  53. // base
  54. var BaseUtils = {
  55. /**
  56. * 对象是否为数组
  57. * @param arr
  58. */
  59. isArray: function (arr) {
  60. return Array.isArray(arr) || Object.prototype.toString.call(arr) === "[object Array]";
  61. },
  62. /**
  63. * 判断是否为方法
  64. * @param func
  65. * @return {boolean}
  66. */
  67. isFunction: function (func) {
  68. if (!func) {
  69. return false;
  70. }
  71. return typeof func === 'function';
  72. },
  73. /**
  74. * 判断是否是一个有效的对象
  75. * @param obj
  76. * @return {*|boolean}
  77. */
  78. isExistObject: function (obj) {
  79. return obj && (typeof obj === 'object');
  80. },
  81. isString: function (str) {
  82. if (str === null) {
  83. return false;
  84. }
  85. return typeof str === 'string';
  86. },
  87. uniqueNum: 1000,
  88. /**
  89. * 根据当前时间戳生产一个随机id
  90. * @returns {string}
  91. */
  92. buildUniqueId: function () {
  93. var prefix = new Date().getTime().toString();
  94. var suffix = this.uniqueNum.toString();
  95. this.uniqueNum++;
  96. return prefix + suffix;
  97. }
  98. };
  99.  
  100. //
  101. var serviceProvider = {
  102. _parseDepends: function (depends) {
  103. var dependsArr = [];
  104. if (!BaseUtils.isArray(depends)) {
  105. return;
  106. }
  107. depends.forEach(function (depend) {
  108. if (BaseUtils.isString(depend)) {
  109. dependsArr.push(serviceProvider[depend.toLowerCase()]);
  110. }
  111. });
  112. return dependsArr;
  113. }
  114. };
  115.  
  116. //
  117. var factory = function (name, depends, construction) {
  118. if (!BaseUtils.isFunction(construction)) {
  119. return;
  120. }
  121. serviceProvider[name.toLowerCase()] = construction.apply(this, serviceProvider._parseDepends(depends));
  122. };
  123.  
  124. var depend = function (depends, construction) {
  125. if (!BaseUtils.isFunction(construction)) {
  126. return;
  127. }
  128. construction.apply(this, serviceProvider._parseDepends(depends));
  129. };
  130.  
  131. factory('BaseUtils', [], function () {
  132. return BaseUtils;
  133. });
  134.  
  135. // logger
  136. factory('logger', [], function () {
  137. return console;
  138. });
  139.  
  140. // DateTimeUtils
  141. factory('DateTimeUtils', ['logger'], function (logger) {
  142. return {
  143. /**
  144. * 打印当前时间
  145. */
  146. printNowTime: function () {
  147. var date = new Date();
  148. console.log(this.pattern(date, 'hh:mm:ss:S'));
  149. },
  150. /**
  151. * 格式化日期
  152. * @param date
  153. * @param fmt
  154. * @returns {*}
  155. */
  156. pattern: function (date, fmt) {
  157. var o = {
  158. "M+": date.getMonth() + 1, //月份
  159. "d+": date.getDate(), //日
  160. "h+": date.getHours() % 12 === 0 ? 12 : date.getHours() % 12, //小时
  161. "H+": date.getHours(), //小时
  162. "m+": date.getMinutes(), //分
  163. "s+": date.getSeconds(), //秒
  164. "q+": Math.floor((date.getMonth() + 3) / 3), //季度
  165. "S": date.getMilliseconds() //毫秒
  166. };
  167. var week = {
  168. "0": "/u65e5",
  169. "1": "/u4e00",
  170. "2": "/u4e8c",
  171. "3": "/u4e09",
  172. "4": "/u56db",
  173. "5": "/u4e94",
  174. "6": "/u516d"
  175. };
  176. if (/(y+)/.test(fmt)) {
  177. fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
  178. }
  179. if (/(E+)/.test(fmt)) {
  180. fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? "/u661f/u671f" : "/u5468") : "") + week[date.getDay() + ""]);
  181. }
  182. for (var k in o) {
  183. if (new RegExp("(" + k + ")").test(fmt)) {
  184. fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
  185. }
  186. }
  187. return fmt;
  188. },
  189. /**
  190. * 以当前时间获取id
  191. * @returns {number}
  192. */
  193. getCurrentId: function () {
  194. var date = new Date();
  195. return date.getTime();
  196. },
  197. /**
  198. * 获取指定时间距离现在相差多久
  199. * @param date {number|Date}
  200. * @param isCeil{boolean=} 是否对结果向上取整,默认[false]
  201. * @param type {string=} 单位可取值['day','month','year']默认'day'
  202. * @returns {number}
  203. */
  204. getNowBetweenADay: function (date, isCeil, type) {
  205. if (!type) {
  206. type = 'day'
  207. }
  208. if (typeof date === 'number') {
  209. date = new Date(date);
  210. }
  211. if (!(date instanceof Date)) {
  212. throw new TypeError('该参数类型必须是Date')
  213. }
  214. var time = date.getTime();
  215. var now = new Date();
  216. var nowTime = now.getTime();
  217. if (nowTime - time < 0) {
  218. logger.warn('需要计算的时间必须在当前时间之前');
  219. }
  220. var result = 0;
  221. switch (type) {
  222. default:
  223. case 'day':
  224. result = (nowTime - time) / (1000 * 60 * 60 * 24);
  225. break;
  226. case 'month':
  227. var yearDifference = now.getFullYear() - date.getFullYear();
  228. if (yearDifference > 0) {
  229. result += yearDifference * 12;
  230. }
  231. result += now.getMonth() - date.getMonth();
  232. break;
  233. case 'year':
  234. result += now.getFullYear() - date.getFullYear();
  235. break;
  236. }
  237. if (!isCeil) {
  238. return Math.floor(result);
  239. } else {
  240. if (result === 0 && isCeil) {
  241. result = 1;
  242. }
  243. return Math.ceil(result);
  244. }
  245. }
  246. }
  247. });
  248.  
  249. // ArrayUtils
  250. factory('ArrayUtils', ['BaseUtils'], function (BaseUtils) {
  251. return {
  252. isArrayObject: function (arr) {
  253. return BaseUtils.isArray(arr);
  254. },
  255. /**
  256. * 遍历数组
  257. * @param context {Object}
  258. * @param arr {Array}
  259. * @param cb {Function} 回调函数
  260. */
  261. ergodicArrayObject: function (context, arr, cb) {
  262. if (!context) {
  263. context = window;
  264. }
  265. if (!BaseUtils.isArray(arr) || !BaseUtils.isFunction(cb)) {
  266. return;
  267. }
  268. for (var i = 0; i < arr.length; i++) {
  269. var result = cb.call(context, arr[i], i);
  270. if (result && result === -1) {
  271. break;
  272. }
  273. }
  274. },
  275. /**
  276. * 获取数组对象的一个属性发起动作
  277. * @param context {Object}
  278. * @param arr {Array}
  279. * @param propertyName {String}
  280. * @param cb {Function}
  281. * @param checkProperty {boolean} 是否排除不拥有该属性的对象[default:true]
  282. */
  283. getPropertyDo: function (context, arr, propertyName, cb, checkProperty) {
  284. if (checkProperty === null) {
  285. checkProperty = true;
  286. }
  287. this.ergodicArrayObject(context, arr, function (ele) {
  288. if (!checkProperty || ele.hasOwnProperty(propertyName)) {
  289. cb.call(context, ele[propertyName], ele);
  290. }
  291. })
  292. },
  293. /**
  294. * [私有方法]将多个键值对对象转换为map
  295. * @param arr {Array}
  296. * @returns {{}}
  297. */
  298. parseKeyValue: function (arr) {
  299. var map = {};
  300. if (!(BaseUtils.isArray(arr))) {
  301. return map;
  302. }
  303. this.ergodicArrayObject(this, arr, function (ele) {
  304. if (ele.key === null) {
  305. return;
  306. }
  307. if (!map.hasOwnProperty(ele.key)) {
  308. map[ele.key] = ele.value;
  309. }
  310. });
  311. return map;
  312. },
  313. /**
  314. * 获取数组的哈希码
  315. * @param arr {Array}
  316. * @returns {number}
  317. */
  318. getHashCode: function (arr) {
  319. var str = arr.toString();
  320. var hash = 31;
  321. if (str.length === 0) return hash;
  322. for (var i = 0; i < str.length; i++) {
  323. var char = str.charCodeAt(i);
  324. hash = ((hash << 5) - hash) + char;
  325. hash = hash & hash; // Convert to 32bit integer
  326. }
  327. return hash;
  328. },
  329. /**
  330. * 通过数组中每个对象的指定属性生成一个新数组
  331. * @param arr {Array}
  332. * @param propertyName {String}
  333. */
  334. parseArrayByProperty: function (arr, propertyName) {
  335. var result = [];
  336. if (!this.isArrayObject(arr)) {
  337. return result;
  338. }
  339. this.getPropertyDo(this, arr, propertyName, function (value) {
  340. result.push(value);
  341. }, true);
  342. return result;
  343. },
  344. /**
  345. * 数组对象是否包含一个对象
  346. * @param arr {Array}
  347. * @param obj
  348. * @param cb {function=}
  349. * @returns {boolean}
  350. */
  351. isContainsObject: function (arr, obj, cb) {
  352. var isContainsObject = false;
  353. this.ergodicArrayObject(this, arr, function (value, i) {
  354. if (obj === value) {
  355. isContainsObject = true;
  356. if (BaseUtils.isFunction(cb)) {
  357. cb.call(window, i);
  358. }
  359. return -1;
  360. }
  361. });
  362. return isContainsObject;
  363. },
  364. /**
  365. * 获取数组中的最大值
  366. * @param arr 若数组中的对象还是数组,则按里面数组的每个对象进行多级比较
  367. * @param cb
  368. * @returns {*}
  369. */
  370. getMaxInArray: function (arr, cb) {
  371. var maxObject = null;
  372. var maxIndex = -1;
  373. while (maxObject === null && maxIndex < arr.length) {
  374. maxObject = arr[++maxIndex]
  375. }
  376. for (var i = maxIndex + 1; i < arr.length; i++) {
  377. // 若是比较对象都是数组,则对每个数组的第一个元素进行比较,若相同,则比较第二个元素
  378. if (maxObject !== null && this.isArrayObject(maxObject) && this.isArrayObject(arr[i])) {
  379. var classLength = maxObject.length;
  380. var classLevel = 0;
  381. // console.log(maxObject[classLevel],arr[i][classLevel]);
  382. while (maxObject[classLevel] === arr[i][classLevel] && classLevel < classLength) {
  383. classLevel++
  384. }
  385. if (maxObject[classLevel] !== null && maxObject[classLevel] < arr[i][classLevel]) {
  386. maxObject = arr[i];
  387. maxIndex = i;
  388. }
  389. continue;
  390. }
  391. if (maxObject !== null && maxObject < arr[i]) {
  392. maxObject = arr[i];
  393. maxIndex = i;
  394. }
  395. }
  396. if (BaseUtils.isFunction(cb)) {
  397. cb.call(this, maxObject, maxIndex);
  398. }
  399. return maxObject;
  400. },
  401. /**
  402. * 获取数组中的总值
  403. * @param arr{Array<number>}
  404. * @param cb {function=}
  405. */
  406. getSumInArray: function (arr, cb) {
  407. if (!this.isArrayObject(arr)) {
  408. return;
  409. }
  410. var sum = 0;
  411. var count = 0;
  412. this.ergodicArrayObject(this, arr, function (value) {
  413. if (typeof value === 'number' && !Number.isNaN(value)) {
  414. sum += value;
  415. count += 1;
  416. }
  417. });
  418. if (BaseUtils.isFunction(cb)) {
  419. cb.call(window, sum, count);
  420. }
  421. return sum;
  422. },
  423. /**
  424. * 获取数组中的平均值
  425. * @param arr{Array<number>}
  426. */
  427. getAverageInArray: function (arr) {
  428. var average = 0;
  429. this.getSumInArray(arr, function (sum, i) {
  430. i === 0 || (average = sum / i);
  431. });
  432. return average;
  433. },
  434. /**
  435. * 为数组排序
  436. * @param arr
  437. * @param order
  438. * @param sortSetting {object=}
  439. */
  440. sortingArrays: function (arr, order, sortSetting) {
  441. if (!this.isArrayObject(arr)) {
  442. return;
  443. }
  444. var DESC = 0;
  445. var ASC = 1;
  446. var thisArr = arr.slice(0);
  447. var _thisAction = null;
  448. // 解析配置
  449. var isSetting = sortSetting && sortSetting.getComparedProperty &&
  450. BaseUtils.isFunction(sortSetting.getComparedProperty);
  451. if (isSetting) {
  452. thisArr = sortSetting.getComparedProperty(arr);
  453. }
  454. // ==UserScript==
  455. // @name Everything-Hook
  456. // @namespace https://gitee.com/HGJing/everthing-hook/
  457. // @updateURL https://gitee.com/HGJing/everthing-hook/raw/master/src/everything-hook.js
  458. // @version 0.5.9047
  459. // @include *
  460. // @description it can hook everything
  461. // @author Cangshi
  462. // @match http://*/*
  463. // @grant none
  464. // @run-at document-start
  465. // ==/UserScript==
  466.  
  467. /**
  468. * ---------------------------
  469. * Time: 2017/9/20 18:33.
  470. * Author: Cangshi
  471. * View: http://palerock.cn
  472. * ---------------------------
  473. */
  474. 'use strict';
  475. /**
  476. * Every-Utils
  477. * version:0.0.2001
  478. */
  479. (function (global, factory) {
  480.  
  481. "use strict";
  482.  
  483. if (typeof module === "object" && typeof module.exports === "object") {
  484.  
  485. // For CommonJS and CommonJS-like environments where a proper `window`
  486. // is present, execute the factory and get jQuery.
  487. // For environments that do not have a `window` with a `document`
  488. // (such as Node.js), expose a factory as module.exports.
  489. // This accentuates the need for the creation of a real `window`.
  490. // e.g. var jQuery = require("jquery")(window);
  491. // See ticket #14549 for more info.
  492. module.exports = global.document ?
  493. factory(global, true) :
  494. function (w) {
  495. if (!w.document) {
  496. throw new Error("eUtils requires a window with a document");
  497. }
  498. return factory(w);
  499. };
  500. } else {
  501. factory(global);
  502. }
  503.  
  504. }(typeof window !== "undefined" ? window : this, function (_global, noGlobal) {
  505.  
  506. // base
  507. var BaseUtils = {
  508. /**
  509. * 对象是否为数组
  510. * @param arr
  511. */
  512. isArray: function (arr) {
  513. return Array.isArray(arr) || Object.prototype.toString.call(arr) === "[object Array]";
  514. },
  515. /**
  516. * 判断是否为方法
  517. * @param func
  518. * @return {boolean}
  519. */
  520. isFunction: function (func) {
  521. if (!func) {
  522. return false;
  523. }
  524. return typeof func === 'function';
  525. },
  526. /**
  527. * 判断是否是一个有效的对象
  528. * @param obj
  529. * @return {*|boolean}
  530. */
  531. isExistObject: function (obj) {
  532. return obj && (typeof obj === 'object');
  533. },
  534. isString: function (str) {
  535. if (str === null) {
  536. return false;
  537. }
  538. return typeof str === 'string';
  539. },
  540. uniqueNum: 1000,
  541. /**
  542. * 根据当前时间戳生产一个随机id
  543. * @returns {string}
  544. */
  545. buildUniqueId: function () {
  546. var prefix = new Date().getTime().toString();
  547. var suffix = this.uniqueNum.toString();
  548. this.uniqueNum++;
  549. return prefix + suffix;
  550. }
  551. };
  552.  
  553. //
  554. var serviceProvider = {
  555. _parseDepends: function (depends) {
  556. var dependsArr = [];
  557. if (!BaseUtils.isArray(depends)) {
  558. return;
  559. }
  560. depends.forEach(function (depend) {
  561. if (BaseUtils.isString(depend)) {
  562. dependsArr.push(serviceProvider[depend.toLowerCase()]);
  563. }
  564. });
  565. return dependsArr;
  566. }
  567. };
  568.  
  569. //
  570. var factory = function (name, depends, construction) {
  571. if (!BaseUtils.isFunction(construction)) {
  572. return;
  573. }
  574. serviceProvider[name.toLowerCase()] = construction.apply(this, serviceProvider._parseDepends(depends));
  575. };
  576.  
  577. var depend = function (depends, construction) {
  578. if (!BaseUtils.isFunction(construction)) {
  579. return;
  580. }
  581. construction.apply(this, serviceProvider._parseDepends(depends));
  582. };
  583.  
  584. factory('BaseUtils', [], function () {
  585. return BaseUtils;
  586. });
  587.  
  588. // logger
  589. factory('logger', [], function () {
  590. return console;
  591. });
  592.  
  593. // DateTimeUtils
  594. factory('DateTimeUtils', ['logger'], function (logger) {
  595. return {
  596. /**
  597. * 打印当前时间
  598. */
  599. printNowTime: function () {
  600. var date = new Date();
  601. console.log(this.pattern(date, 'hh:mm:ss:S'));
  602. },
  603. /**
  604. * 格式化日期
  605. * @param date
  606. * @param fmt
  607. * @returns {*}
  608. */
  609. pattern: function (date, fmt) {
  610. var o = {
  611. "M+": date.getMonth() + 1, //月份
  612. "d+": date.getDate(), //日
  613. "h+": date.getHours() % 12 === 0 ? 12 : date.getHours() % 12, //小时
  614. "H+": date.getHours(), //小时
  615. "m+": date.getMinutes(), //分
  616. "s+": date.getSeconds(), //秒
  617. "q+": Math.floor((date.getMonth() + 3) / 3), //季度
  618. "S": date.getMilliseconds() //毫秒
  619. };
  620. var week = {
  621. "0": "/u65e5",
  622. "1": "/u4e00",
  623. "2": "/u4e8c",
  624. "3": "/u4e09",
  625. "4": "/u56db",
  626. "5": "/u4e94",
  627. "6": "/u516d"
  628. };
  629. if (/(y+)/.test(fmt)) {
  630. fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
  631. }
  632. if (/(E+)/.test(fmt)) {
  633. fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? "/u661f/u671f" : "/u5468") : "") + week[date.getDay() + ""]);
  634. }
  635. for (var k in o) {
  636. if (new RegExp("(" + k + ")").test(fmt)) {
  637. fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
  638. }
  639. }
  640. return fmt;
  641. },
  642. /**
  643. * 以当前时间获取id
  644. * @returns {number}
  645. */
  646. getCurrentId: function () {
  647. var date = new Date();
  648. return date.getTime();
  649. },
  650. /**
  651. * 获取指定时间距离现在相差多久
  652. * @param date {number|Date}
  653. * @param isCeil{boolean=} 是否对结果向上取整,默认[false]
  654. * @param type {string=} 单位可取值['day','month','year']默认'day'
  655. * @returns {number}
  656. */
  657. getNowBetweenADay: function (date, isCeil, type) {
  658. if (!type) {
  659. type = 'day'
  660. }
  661. if (typeof date === 'number') {
  662. date = new Date(date);
  663. }
  664. if (!(date instanceof Date)) {
  665. throw new TypeError('该参数类型必须是Date')
  666. }
  667. var time = date.getTime();
  668. var now = new Date();
  669. var nowTime = now.getTime();
  670. if (nowTime - time < 0) {
  671. logger.warn('需要计算的时间必须在当前时间之前');
  672. }
  673. var result = 0;
  674. switch (type) {
  675. default:
  676. case 'day':
  677. result = (nowTime - time) / (1000 * 60 * 60 * 24);
  678. break;
  679. case 'month':
  680. var yearDifference = now.getFullYear() - date.getFullYear();
  681. if (yearDifference > 0) {
  682. result += yearDifference * 12;
  683. }
  684. result += now.getMonth() - date.getMonth();
  685. break;
  686. case 'year':
  687. result += now.getFullYear() - date.getFullYear();
  688. break;
  689. }
  690. if (!isCeil) {
  691. return Math.floor(result);
  692. } else {
  693. if (result === 0 && isCeil) {
  694. result = 1;
  695. }
  696. return Math.ceil(result);
  697. }
  698. }
  699. }
  700. });
  701.  
  702. // ArrayUtils
  703. factory('ArrayUtils', ['BaseUtils'], function (BaseUtils) {
  704. return {
  705. isArrayObject: function (arr) {
  706. return BaseUtils.isArray(arr);
  707. },
  708. /**
  709. * 遍历数组
  710. * @param context {Object}
  711. * @param arr {Array}
  712. * @param cb {Function} 回调函数
  713. */
  714. ergodicArrayObject: function (context, arr, cb) {
  715. if (!context) {
  716. context = window;
  717. }
  718. if (!BaseUtils.isArray(arr) || !BaseUtils.isFunction(cb)) {
  719. return;
  720. }
  721. for (var i = 0; i < arr.length; i++) {
  722. var result = cb.call(context, arr[i], i);
  723. if (result && result === -1) {
  724. break;
  725. }
  726. }
  727. },
  728. /**
  729. * 获取数组对象的一个属性发起动作
  730. * @param context {Object}
  731. * @param arr {Array}
  732. * @param propertyName {String}
  733. * @param cb {Function}
  734. * @param checkProperty {boolean} 是否排除不拥有该属性的对象[default:true]
  735. */
  736. getPropertyDo: function (context, arr, propertyName, cb, checkProperty) {
  737. if (checkProperty === null) {
  738. checkProperty = true;
  739. }
  740. this.ergodicArrayObject(context, arr, function (ele) {
  741. if (!checkProperty || ele.hasOwnProperty(propertyName)) {
  742. cb.call(context, ele[propertyName], ele);
  743. }
  744. })
  745. },
  746. /**
  747. * [私有方法]将多个键值对对象转换为map
  748. * @param arr {Array}
  749. * @returns {{}}
  750. */
  751. parseKeyValue: function (arr) {
  752. var map = {};
  753. if (!(BaseUtils.isArray(arr))) {
  754. return map;
  755. }
  756. this.ergodicArrayObject(this, arr, function (ele) {
  757. if (ele.key === null) {
  758. return;
  759. }
  760. if (!map.hasOwnProperty(ele.key)) {
  761. map[ele.key] = ele.value;
  762. }
  763. });
  764. return map;
  765. },
  766. /**
  767. * 获取数组的哈希码
  768. * @param arr {Array}
  769. * @returns {number}
  770. */
  771. getHashCode: function (arr) {
  772. var str = arr.toString();
  773. var hash = 31;
  774. if (str.length === 0) return hash;
  775. for (var i = 0; i < str.length; i++) {
  776. var char = str.charCodeAt(i);
  777. hash = ((hash << 5) - hash) + char;
  778. hash = hash & hash; // Convert to 32bit integer
  779. }
  780. return hash;
  781. },
  782. /**
  783. * 通过数组中每个对象的指定属性生成一个新数组
  784. * @param arr {Array}
  785. * @param propertyName {String}
  786. */
  787. parseArrayByProperty: function (arr, propertyName) {
  788. var result = [];
  789. if (!this.isArrayObject(arr)) {
  790. return result;
  791. }
  792. this.getPropertyDo(this, arr, propertyName, function (value) {
  793. result.push(value);
  794. }, true);
  795. return result;
  796. },
  797. /**
  798. * 数组对象是否包含一个对象
  799. * @param arr {Array}
  800. * @param obj
  801. * @param cb {function=}
  802. * @returns {boolean}
  803. */
  804. isContainsObject: function (arr, obj, cb) {
  805. var isContainsObject = false;
  806. this.ergodicArrayObject(this, arr, function (value, i) {
  807. if (obj === value) {
  808. isContainsObject = true;
  809. if (BaseUtils.isFunction(cb)) {
  810. cb.call(window, i);
  811. }
  812. return -1;
  813. }
  814. });
  815. return isContainsObject;
  816. },
  817. /**
  818. * 获取数组中的最大值
  819. * @param arr 若数组中的对象还是数组,则按里面数组的每个对象进行多级比较
  820. * @param cb
  821. * @returns {*}
  822. */
  823. getMaxInArray: function (arr, cb) {
  824. var maxObject = null;
  825. var maxIndex = -1;
  826. while (maxObject === null && maxIndex < arr.length) {
  827. maxObject = arr[++maxIndex]
  828. }
  829. for (var i = maxIndex + 1; i < arr.length; i++) {
  830. // 若是比较对象都是数组,则对每个数组的第一个元素进行比较,若相同,则比较第二个元素
  831. if (maxObject !== null && this.isArrayObject(maxObject) && this.isArrayObject(arr[i])) {
  832. var classLength = maxObject.length;
  833. var classLevel = 0;
  834. // console.log(maxObject[classLevel],arr[i][classLevel]);
  835. while (maxObject[classLevel] === arr[i][classLevel] && classLevel < classLength) {
  836. classLevel++
  837. }
  838. if (maxObject[classLevel] !== null && maxObject[classLevel] < arr[i][classLevel]) {
  839. maxObject = arr[i];
  840. maxIndex = i;
  841. }
  842. continue;
  843. }
  844. if (maxObject !== null && maxObject < arr[i]) {
  845. maxObject = arr[i];
  846. maxIndex = i;
  847. }
  848. }
  849. if (BaseUtils.isFunction(cb)) {
  850. cb.call(this, maxObject, maxIndex);
  851. }
  852. return maxObject;
  853. },
  854. /**
  855. * 获取数组中的总值
  856. * @param arr{Array<number>}
  857. * @param cb {function=}
  858. */
  859. getSumInArray: function (arr, cb) {
  860. if (!this.isArrayObject(arr)) {
  861. return;
  862. }
  863. var sum = 0;
  864. var count = 0;
  865. this.ergodicArrayObject(this, arr, function (value) {
  866. if (typeof value === 'number' && !Number.isNaN(value)) {
  867. sum += value;
  868. count += 1;
  869. }
  870. });
  871. if (BaseUtils.isFunction(cb)) {
  872. cb.call(window, sum, count);
  873. }
  874. return sum;
  875. },
  876. /**
  877. * 获取数组中的平均值
  878. * @param arr{Array<number>}
  879. */
  880. getAverageInArray: function (arr) {
  881. var average = 0;
  882. this.getSumInArray(arr, function (sum, i) {
  883. i === 0 || (average = sum / i);
  884. });
  885. return average;
  886. },
  887. /**
  888. * 为数组排序
  889. * @param arr
  890. * @param order
  891. * @param sortSetting {object=}
  892. */
  893. sortingArrays: function (arr, order, sortSetting) {
  894. if (!this.isArrayObject(arr)) {
  895. return;
  896. }
  897. var DESC = 0;
  898. var ASC = 1;
  899. var thisArr = arr.slice(0);
  900. var _thisAction = null;
  901. // 解析配置
  902. var isSetting = sortSetting && sortSetting.getComparedProperty &&
  903. BaseUtils.isFunction(sortSetting.getComparedProperty);
  904. if (isSetting) {
  905. thisArr = sortSetting.getComparedProperty(arr);
  906. }
  907. switch (order) {
  908. default :
  909. case DESC:
  910. _thisAction = thisArr.push;
  911. break;
  912. case ASC:
  913. _thisAction = thisArr.unshift;
  914. break;
  915. }
  916. var resultArr = [];
  917. for (var j = 0; j < thisArr.length; j++) {
  918. this.getMaxInArray(thisArr, function (max, i) {
  919. delete thisArr[i];
  920. _thisAction.call(resultArr, arr[i]);
  921. });
  922. }
  923. if (sortSetting && sortSetting.createNewData) {
  924. return resultArr.slice(0);
  925. }
  926. return resultArr;
  927. },
  928. /**
  929. * 将类数组转化为数组
  930. * @param arrLike 类数组对象
  931. */
  932. toArray: function (arrLike) {
  933. if (!arrLike || arrLike.length === 0) {
  934. return [];
  935. }
  936. // 非伪类对象,直接返回最好
  937. if (!arrLike.length) {
  938. return arrLike;
  939. }
  940. // 针对IE8以前 DOM的COM实现
  941. try {
  942. return [].slice.call(arrLike);
  943. } catch (e) {
  944. var i = 0,
  945. j = arrLike.length,
  946. res = [];
  947. for (; i < j; i++) {
  948. res.push(arrLike[i]);
  949. }
  950. return res;
  951. }
  952. },
  953. /**
  954. * 判断是否为类数组
  955. * @param o
  956. * @returns {boolean}
  957. */
  958. isArrayLick: function (o) {
  959. if (o && // o is not null, undefined, etc.
  960. typeof o === 'object' && // o is an object
  961. isFinite(o.length) && // o.length is a finite number
  962. o.length >= 0 && // o.length is non-negative
  963. o.length === Math.floor(o.length) && // o.length is an integer
  964. o.length < 4294967296) // o.length < 2^32
  965. return true; // Then o is array-like
  966. else
  967. return false; // Otherwise it is not
  968.  
  969. },
  970. /**
  971. * 判断数组是否包含对象
  972. * @param arr
  973. * @param obj
  974. */
  975. contains: function (arr, obj) {
  976. var contains = false;
  977. this.ergodicArrayObject(this, arr, function (a) {
  978. if (a === obj) {
  979. contains = true;
  980. return -1;
  981. }
  982. });
  983. return contains;
  984. }
  985. }
  986. });
  987.  
  988. // ObjectUtils
  989. factory('ObjectUtils', ['ArrayUtils', 'BaseUtils'], function (ArrayUtils, BaseUtils) {
  990. return {
  991. /**
  992. * 获取对象属性[支持链式表达式,如获取学生所在班级所在的学校(student.class.school):'class.school']
  993. * @param obj
  994. * @param linkProperty {string|Array} 属性表达式,获取多个属性则用数组
  995. * @param cb {function=}
  996. * @return 对象属性
  997. */
  998. readLinkProperty: function (obj, linkProperty, cb) {
  999. var callback = null;
  1000. if (BaseUtils.isFunction(cb)) {
  1001. callback = cb;
  1002. }
  1003. if (typeof linkProperty === 'string') {
  1004. // 除去所有的空格
  1005. linkProperty = linkProperty.replace(/ /g, '');
  1006. // 不判断为空的值
  1007. if (linkProperty === '') {
  1008. return null;
  1009. }
  1010. // 若是以','隔开的伪数组,则转化为数组再进行操作
  1011. if (linkProperty.indexOf(',') !== -1) {
  1012. var propertyNameArr = linkProperty.split(',');
  1013. return this.readLinkProperty(obj, propertyNameArr, callback);
  1014. }
  1015. if (linkProperty.indexOf('.') !== -1) {
  1016. var names = linkProperty.split('.');
  1017. var iterationObj = obj;
  1018. var result = null;
  1019. ArrayUtils.ergodicArrayObject(this, names, function (name, i) {
  1020. iterationObj = this.readLinkProperty(iterationObj, name);
  1021. if (names[names.length - 1] === name && names.length - 1 === i) {
  1022. result = iterationObj;
  1023. if (callback) {
  1024. callback.call(window, result, linkProperty);
  1025. }
  1026. }
  1027. // 终止对接下来的属性的遍历
  1028. if (typeof iterationObj === 'undefined') {
  1029. return -1;
  1030. }
  1031. });
  1032. return result;
  1033. }
  1034. var normalResult = null;
  1035. if (linkProperty.slice(linkProperty.length - 2) === '()') {
  1036. var func = linkProperty.slice(0, linkProperty.length - 2);
  1037. normalResult = obj[func]();
  1038. } else {
  1039. normalResult = obj[linkProperty];
  1040. }
  1041. if (normalResult === null) {
  1042. console.warn(obj, '的属性[\'' + linkProperty + '\']值未找到');
  1043. }
  1044. if (callback) {
  1045. callback.call(window, normalResult, linkProperty);
  1046. }
  1047. return normalResult;
  1048. }
  1049. if (BaseUtils.isArray(linkProperty)) {
  1050. var results = [];
  1051. ArrayUtils.ergodicArrayObject(this, linkProperty, function (name) {
  1052. var value = this.readLinkProperty(obj, name);
  1053. results.push(value);
  1054. if (callback && name !== '') {
  1055. return callback.call(window, value, name);
  1056. }
  1057. });
  1058. results.isMultipleResults = true;
  1059. return results;
  1060. }
  1061. },
  1062. /**
  1063. * 为对象属性赋值
  1064. * (同一个对象中不能够既有数字开头的属性名和普通属性名)
  1065. * @param obj
  1066. * @param linkProperty {string|Array} 属性表达式,多个属性则用数组
  1067. * @param value
  1068. */
  1069. createLinkProperty: function (obj, linkProperty, value) {
  1070. if (obj === null) {
  1071. obj = {};
  1072. }
  1073. if (typeof linkProperty === 'string') {
  1074. // 除去所有的空格
  1075. linkProperty = linkProperty.replace(/ /g, '');
  1076. // 不判断为空的值
  1077. if (linkProperty === '') {
  1078. throw new TypeError('对象属性名不能为空')
  1079. }
  1080. if (linkProperty.indexOf(',') !== -1) {
  1081. var propertyNameArr = linkProperty.split(',');
  1082. this.createLinkProperty(obj, propertyNameArr, value);
  1083. return obj;
  1084. }
  1085. if (linkProperty.indexOf('.') !== -1) {
  1086. var names = linkProperty.split('.');
  1087. if (!obj.hasOwnProperty(names[0])) {
  1088. obj[names[0]] = {}
  1089. }
  1090. // 判断属性名是否以数字开头(若是代表是一个数组)
  1091. if (!Number.isNaN(parseInt(names[0]))) {
  1092. if (!ArrayUtils.isArrayObject(obj)) {
  1093. obj = [];
  1094. }
  1095. }
  1096. var propertyObj = obj[names[0]];
  1097. var newProperties = names.slice(1, names.length);
  1098. var newLinkProperty = '';
  1099. ArrayUtils.ergodicArrayObject(this, newProperties, function (property, i) {
  1100. if (i < newProperties.length - 1) {
  1101. newLinkProperty = newLinkProperty + property + '.'
  1102. } else {
  1103. newLinkProperty = newLinkProperty + property;
  1104. }
  1105. });
  1106. obj[names[0]] = this.createLinkProperty(propertyObj, newLinkProperty, value);
  1107. return obj;
  1108. }
  1109. // 判断属性名是否以数字开头(若是代表是一个数组)
  1110. if (!Number.isNaN(parseInt(linkProperty))) {
  1111. if (!ArrayUtils.isArrayObject(obj)) {
  1112. obj = [];
  1113. }
  1114. }
  1115. obj[linkProperty] = value;
  1116. return obj;
  1117. } else if (BaseUtils.isArray(linkProperty)) {
  1118. ArrayUtils.ergodicArrayObject(this, linkProperty, function (link) {
  1119. obj = this.createLinkProperty(obj, link, value);
  1120. });
  1121. return obj;
  1122. }
  1123. },
  1124. /**
  1125. * 遍历对象属性
  1126. * @param context {object} 上下文
  1127. * @param obj {object} 遍历对象
  1128. * @param cb {function} 回调函数
  1129. * @param isReadInnerObject {boolean=} 是否遍历内部对象的属性
  1130. */
  1131. ergodicObject: function (context, obj, cb, isReadInnerObject) {
  1132. var keys = Object.keys(obj);
  1133. ArrayUtils.ergodicArrayObject(this, keys, function (propertyName) {
  1134. // 若内部对象需要遍历
  1135. var _propertyName = propertyName;
  1136. if (isReadInnerObject && obj[propertyName] !== null && typeof obj[propertyName] === 'object') {
  1137. this.ergodicObject(this, obj[propertyName], function (value, key) {
  1138. return cb.call(context, value, _propertyName + '.' + key);
  1139. }, true)
  1140. } else {
  1141. return cb.call(context, obj[propertyName], propertyName);
  1142. }
  1143. })
  1144. },
  1145. /**
  1146. * 当指定属性为空或不存在时执行回到函数;
  1147. * @param context {object} 上下文
  1148. * @param obj {object} 检测对象
  1149. * @param propertyNames{Array|string} 需要检测的属性名
  1150. * 可以检查多级属性如:'a.b.c.e',
  1151. * 多个属性使用数组,支持纯字符串多个属性用','隔开
  1152. * @param cb {function} 回调函数[参数:为空或不存在的属性名,返回值为'-1'时,跳过之后的回调函数]
  1153. */
  1154. whileEmptyObjectProperty: function (context, obj, propertyNames, cb) {
  1155. // 解析单个属性名
  1156. if (typeof propertyNames === 'string') {
  1157. // 除去所有的空格
  1158. propertyNames = propertyNames.replace(/ /g, '');
  1159. // 不判断为空的值
  1160. if (propertyNames === '') {
  1161. return;
  1162. }
  1163. // 若是以','隔开的伪数组,则转化为数组再进行操作
  1164. if (propertyNames.indexOf(',') !== -1) {
  1165. var propertyNameArr = propertyNames.split(',');
  1166. return this.whileEmptyObjectProperty(context, obj, propertyNameArr, cb);
  1167. }
  1168. // 若指定级联属性
  1169. if (propertyNames.indexOf('.') !== -1) {
  1170. var names = propertyNames.split('.');
  1171. var iterationObj = obj;
  1172. var result = null;
  1173. ArrayUtils.ergodicArrayObject(this, names, function (name) {
  1174. if (iterationObj && iterationObj.hasOwnProperty(name)) {
  1175. iterationObj = iterationObj[name];
  1176. } else {
  1177. result = cb.call(window, propertyNames);
  1178. // 终止对接下来的属性的遍历
  1179. return -1;
  1180. }
  1181. });
  1182. return result;
  1183. }
  1184. // 正常流程
  1185. if (!obj.hasOwnProperty(propertyNames)) {
  1186. return cb.call(context, propertyNames);
  1187. }
  1188. if (obj[propertyNames] === null || obj[propertyNames] === '') {
  1189. return cb.call(context, propertyNames);
  1190. }
  1191. } else if (BaseUtils.isArray(propertyNames)) {
  1192. // 解析数组
  1193. ArrayUtils.ergodicArrayObject(this, propertyNames, function (propertyName) {
  1194. // 递归调用
  1195. return this.whileEmptyObjectProperty(context, obj, propertyName, cb);
  1196. })
  1197. }
  1198. },
  1199. whileEmptyObjectPropertyV2: function (context, obj, propertyNames, cb) {
  1200. this.readLinkProperty(obj, propertyNames, function (value, propertyName) {
  1201. if (value === null || value === '' || parseInt(value) < 0) {
  1202. return cb.call(context, propertyName);
  1203. }
  1204. })
  1205. },
  1206. /**
  1207. * 克隆对象[只克隆属性,不克隆原型链]
  1208. * @param obj {*}
  1209. */
  1210. cloneObject: function (obj) {
  1211. var newObj = {};
  1212. // 判断是否为基本数据类型,若是则直接返回
  1213. if (typeof obj === 'string' ||
  1214. typeof obj === 'number' ||
  1215. typeof obj === 'undefined' ||
  1216. typeof obj === 'function' ||
  1217. typeof obj === 'boolean') {
  1218. return obj;
  1219. }
  1220. // 判断是否是数组
  1221. if (BaseUtils.isArray(obj)) {
  1222. newObj = [];
  1223. // 遍历数组并递归调用该方法获取数组内部对象的克隆对象并push到新数组
  1224. ArrayUtils.ergodicArrayObject(this, obj, function (arrObjValue) {
  1225. newObj.push(this.cloneObject(arrObjValue));
  1226. })
  1227. } else if (typeof obj === 'object') {
  1228. // 当目标为一般对象时即 typeof 为 object
  1229. if (obj === null) {
  1230. // 当克隆对象为空时,返回空
  1231. return null;
  1232. }
  1233. // 遍历对象的属性并调用递归方法获得该属性对应的对象的克隆对象并将其重新赋值到该属性
  1234. this.ergodicObject(this, obj, function (value, key) {
  1235. newObj[key] = this.cloneObject(value);
  1236. });
  1237. }
  1238. return newObj;
  1239. },
  1240. // cloneIndeed: function (obj) {
  1241. // var hash = new Map();
  1242. // var result = this._cloneIndeed(obj, hash);
  1243. // for (var item of hash.values()) {
  1244. // ArrayUtils.ergodicArrayObject(this, item.settingArr, function (func) {
  1245. // func.call(this);
  1246. // })
  1247. // }
  1248. // return result;
  1249. // },
  1250. // _cloneIndeed: function (obj, hash) {
  1251. // hash = hash || new Map();
  1252. // var result = {};
  1253. // // 获取数据类型
  1254. // var dataType = typeof obj;
  1255. // switch (dataType.toLowerCase()) {
  1256. // case 'string':
  1257. // case 'number':
  1258. // case 'boolean':
  1259. // case 'undefined':
  1260. // return obj;
  1261. // case 'object':
  1262. // default: {
  1263. // for (var key in obj) {
  1264. // var nextObj = obj[key];
  1265. // var hashObj = hash.get(nextObj);
  1266. // if (hashObj != null && hashObj.clonedObj != null) {
  1267. // obj[key] = null;
  1268. // }
  1269. // hash.set(nextObj, {
  1270. // clonedObj: result,
  1271. // settingArr: [],
  1272. // active: false
  1273. // }
  1274. // );
  1275. // result[key] = this._cloneIndeed(nextObj, hash);
  1276. // }
  1277. // if (obj != null) {
  1278. // result['__proto__'] = obj['__proto__'];
  1279. // }
  1280. // }
  1281. //
  1282. // }
  1283. // return result;
  1284. // },
  1285. /**
  1286. * 获取对象的哈希码
  1287. * @param obj {Object}
  1288. * @returns {number}
  1289. */
  1290. getObjHashCode: function (obj) {
  1291. var str = JSON.stringify(obj);
  1292. var hash = 0, i, chr, len;
  1293. console.log(str)
  1294. console.log(hash)
  1295. if (str.length === 0) return hash;
  1296. for (i = 0, len = str.length; i < len; i++) {
  1297. chr = str.charCodeAt(i);
  1298. hash = ((hash << 5) - hash) + chr;
  1299. hash |= 0; // Convert to 32bit integer
  1300. }
  1301. console.log(str)
  1302. console.log(hash)
  1303. return hash;
  1304. },
  1305. /**
  1306. * 扩展对象属性
  1307. * @param obj 原对象
  1308. * @param extendedObj 被扩展的对象
  1309. * @param isCover {boolean=} 扩展的属性和原来属性冲突时是否覆盖 默认[false]
  1310. * @param isClone {boolean=} 是否返回一个新的对象,默认[false]返回扩展后的原对象
  1311. */
  1312. expandObject: function (obj, extendedObj, isCover, isClone) {
  1313. var resultObj = obj;
  1314. if (isClone) {
  1315. resultObj = this.cloneObject(obj);
  1316. }
  1317. this.ergodicObject(this, extendedObj, function (value, key) {
  1318. if (isCover && this.readLinkProperty(resultObj, key) !== null) {
  1319. return;
  1320. }
  1321. resultObj = this.createLinkProperty(resultObj, key, value);
  1322. }, true);
  1323. return resultObj;
  1324. },
  1325. /**
  1326. * 为数组排序,当数组中的元素为对象时,根据指定对象的属性名进行排序
  1327. * @param arr 数组
  1328. * @param propertyName 属性名(当有多个属性名时,为多级排序)
  1329. * @param order 升降序
  1330. * @returns {*}
  1331. */
  1332. sortingArrayByProperty: function (arr, propertyName, order) {
  1333. var _this = this;
  1334. var sortSetting = {
  1335. // 是否创建新数据
  1336. createNewData: false,
  1337. // 通过该方法获取数组中每个对象中用来比较的属性
  1338. getComparedProperty: function (arr) {
  1339. var compareArr = [];
  1340. ArrayUtils.ergodicArrayObject(_this, arr, function (obj, i) {
  1341. if (typeof obj !== 'object') {
  1342. compareArr.push(obj);
  1343. } else {
  1344. var compareValue = this.readLinkProperty(obj, propertyName);
  1345. if (compareValue !== null) {
  1346. compareArr.push(compareValue);
  1347. } else {
  1348. compareArr.push(obj);
  1349. }
  1350. }
  1351. });
  1352. return compareArr.slice(0);
  1353. }
  1354. };
  1355. return ArrayUtils.sortingArrays(arr, order, sortSetting);
  1356. },
  1357. /**
  1358. * 转话为目标的实例
  1359. * @param constructor {function} 构造函数
  1360. * @param obj {object|Array}判断的对象
  1361. * @param defaultProperty {object=}
  1362. */
  1363. toAimObject: function (obj, constructor, defaultProperty) {
  1364. if (BaseUtils.isArray(obj)) {
  1365. var originArr = [];
  1366. ArrayUtils.ergodicArrayObject(this, obj, function (value) {
  1367. originArr.push(this.toAimObject(value, constructor, defaultProperty));
  1368. });
  1369. return originArr;
  1370. } else if (typeof obj === 'object') {
  1371. if (defaultProperty) {
  1372. this.ergodicObject(this, defaultProperty, function (value, key) {
  1373. if (obj[key] === null) {
  1374. obj[key] = value;
  1375. }
  1376. });
  1377. }
  1378. if (obj instanceof constructor) {
  1379. return obj;
  1380. }
  1381. var originObj = obj;
  1382. while (originObj.__proto__ !== null && originObj.__proto__ !== Object.prototype) {
  1383. originObj = originObj.__proto__;
  1384. }
  1385. originObj.__proto__ = constructor.prototype;
  1386. return originObj;
  1387. }
  1388. },
  1389. /**
  1390. * 将数组中结构类似对象指定属性融合为一个数组
  1391. * @param arr {Array}
  1392. * @param propertyNames
  1393. */
  1394. parseTheSameObjectPropertyInArray: function (arr, propertyNames) {
  1395. var result = {};
  1396. var temp = {};
  1397. ArrayUtils.ergodicArrayObject(this, arr, function (obj) {
  1398. // 获取想要得到的所有属性,以属性名为键值存储到temp中
  1399. this.readLinkProperty(obj, propertyNames, function (value, property) {
  1400. if (!temp.hasOwnProperty(property) || !(BaseUtils.isArray(temp[property]))) {
  1401. temp[property] = [];
  1402. }
  1403. temp[property].push(value);
  1404. });
  1405. });
  1406. // 遍历temp获取每个键值中的值,并单独取出
  1407. this.ergodicObject(this, temp, function (value, key) {
  1408. result = this.createLinkProperty(result, key, value);
  1409. });
  1410. return this.cloneObject(result);
  1411. },
  1412. /**
  1413. * 将数组中结构类似对象指定属性融合为一个数组
  1414. * @param arr {Array}
  1415. */
  1416. parseTheSameObjectAllPropertyInArray: function (arr) {
  1417. if (!ArrayUtils.isArrayObject(arr) || arr.length < 1) {
  1418. return;
  1419. }
  1420. // 获取一个对象的所有属性,包括内部对象的属性
  1421. var propertyNames = [];
  1422. this.ergodicObject(this, arr[0], function (v, k) {
  1423. propertyNames.push(k);
  1424. }, true);
  1425. return this.parseTheSameObjectPropertyInArray(arr, propertyNames);
  1426. },
  1427. /**
  1428. * 获取对象属性,若为数组则计算其中数字的平均值或其它
  1429. * @param obj
  1430. * @param propertyNames{Array<string>|string}
  1431. * @param type
  1432. */
  1433. getCalculationInArrayByLinkPropertyNames: function (obj, propertyNames, type) {
  1434. var resultObject = {};
  1435. var _this = this;
  1436. switch (type) {
  1437. default:
  1438. case 'sum':
  1439. this.readLinkProperty(obj, propertyNames, function (value, key) {
  1440. if (ArrayUtils.isArrayObject(value)) {
  1441. resultObject = _this.createLinkProperty(resultObject, key, ArrayUtils.getSumInArray(value));
  1442. }
  1443. });
  1444. break;
  1445. case 'average':
  1446. this.readLinkProperty(obj, propertyNames, function (value, key) {
  1447. if (ArrayUtils.isArrayObject(value)) {
  1448. resultObject = _this.createLinkProperty(resultObject, key, ArrayUtils.getAverageInArray(value));
  1449. }
  1450. });
  1451. break;
  1452. }
  1453. return resultObject;
  1454. }
  1455. }
  1456. });
  1457.  
  1458. // ColorUtils
  1459. factory('ColorUtils', [], function () {
  1460. return {
  1461. /**
  1462. * 转换颜色rgb为16进制
  1463. * @param r
  1464. * @param g
  1465. * @param b
  1466. * @return {string}
  1467. */
  1468. rgbToHex: function (r, g, b) {
  1469. var hex = ((r << 16) | (g << 8) | b).toString(16);
  1470. return "#" + new Array(Math.abs(hex.length - 7)).join("0") + hex;
  1471. },
  1472. /**
  1473. * 转换颜色16进制为rgb
  1474. * @param hex
  1475. * @return {Array}
  1476. */
  1477. hexToRgb: function (hex) {
  1478. hex = hex.replace(/ /g, '');
  1479. var length = hex.length;
  1480. var rgb = [];
  1481. switch (length) {
  1482. case 4:
  1483. rgb.push(parseInt(hex[1] + hex[1], 16));
  1484. rgb.push(parseInt(hex[2] + hex[2], 16));
  1485. rgb.push(parseInt(hex[3] + hex[3], 16));
  1486. return rgb;
  1487. case 7:
  1488. for (var i = 1; i < 7; i += 2) {
  1489. rgb.push(parseInt("0x" + hex.slice(i, i + 2)));
  1490. }
  1491. return rgb;
  1492. default:
  1493. break
  1494. }
  1495. },
  1496. /**
  1497. * 根据两个颜色以及之间的百分比获取渐进色
  1498. * @param start
  1499. * @param end
  1500. * @param percentage
  1501. * @return {*}
  1502. */
  1503. gradientColorsPercentage: function (start, end, percentage) {
  1504. var resultRgb = [];
  1505. var startRgb = this.hexToRgb(start);
  1506. if (end == null) {
  1507. return start;
  1508. }
  1509. var endRgb = this.hexToRgb(end);
  1510. var totalR = endRgb[0] - startRgb[0];
  1511. var totalG = endRgb[1] - startRgb[1];
  1512. var totalB = endRgb[2] - startRgb[2];
  1513. resultRgb.push(startRgb[0] + totalR * percentage);
  1514. resultRgb.push(startRgb[1] + totalG * percentage);
  1515. resultRgb.push(startRgb[2] + totalB * percentage);
  1516. return this.rgbToHex(resultRgb[0], resultRgb[1], resultRgb[2])
  1517. }
  1518. }
  1519. });
  1520.  
  1521. factory('FunctionUtils', [], function () {
  1522. return {
  1523. /**
  1524. * 获取方法的名字
  1525. * @param func
  1526. * @returns {*}
  1527. */
  1528. getFunctionName: function (func) {
  1529. if (typeof func === 'function' || typeof func === 'object') {
  1530. var name = ('' + func).match(/function\s*([\w\$]*)\s*\(/);
  1531. }
  1532. return func.name || name[1];
  1533. },
  1534. /**
  1535. * 获取方法的参数名
  1536. * @param func
  1537. * @returns {*}
  1538. */
  1539. getFunctionParams: function (func) {
  1540. if (typeof func === 'function' || typeof func === 'object') {
  1541. var name = ('' + func).match(/function.*\(([^)]*)\)/);
  1542. return name[1].replace(/( )|(\n)/g, '').split(',');
  1543. }
  1544. return;
  1545. },
  1546. /**
  1547. * 通过方法的arguments获取调用该方法的函数
  1548. * @param func_arguments
  1549. * @returns {string}
  1550. */
  1551. getCallerName: function (func_arguments) {
  1552. var caller = func_arguments.callee.caller;
  1553. var callerName = '';
  1554. if (caller) {
  1555. callerName = this.getFunctionName(caller);
  1556. }
  1557. return callerName;
  1558. },
  1559. FunctionBuilder: function (func) {
  1560. var _this = this;
  1561. var fs = [];
  1562. fs.push(func);
  1563. var properties = ['push', 'unshift', 'slice', 'map', 'forEach', 'keys', 'find', 'concat', 'fill', 'shift', 'values'];
  1564. properties.map(function (property) {
  1565. if (typeof Array.prototype[property] === 'function') {
  1566. Object.defineProperty(_this, property, {
  1567. get: function () {
  1568. return function () {
  1569. fs[property].apply(fs, arguments);
  1570. return this;
  1571. }
  1572. }
  1573. });
  1574. }
  1575. });
  1576. this.result = function (context) {
  1577. var rfs = [];
  1578. fs.map(function (f, index) {
  1579. if (typeof f === 'function') {
  1580. rfs.push(f);
  1581. }
  1582. });
  1583. return function () {
  1584. var declareVar = {
  1585. arguments: arguments,
  1586. this: this
  1587. };
  1588. rfs.map(function (f) {
  1589. var dv = f.apply(context || this, [declareVar]);
  1590. if (dv) {
  1591. Object.keys(dv).map(function (key) {
  1592. declareVar[key] = dv[key];
  1593. });
  1594. }
  1595. });
  1596. return declareVar.returnValue;
  1597. }
  1598. }
  1599. },
  1600. invokeMethods: function (context, methods, args) {
  1601. if (!this.isArray(methods)) {
  1602. return;
  1603. }
  1604. var results = [];
  1605. var _this = this;
  1606. this.ergodicArrayObject(context, methods, function (method) {
  1607. if (!_this.isFunction(method)) {
  1608. return;
  1609. }
  1610. results.push(
  1611. method.apply(context, args)
  1612. );
  1613. });
  1614. return results;
  1615. }
  1616. }
  1617. });
  1618.  
  1619. factory('UrlUtils', [], function () {
  1620. return {
  1621. getUrlInfo: function (url) {
  1622. var a = document.createElement('a');
  1623. a.href = url;
  1624. return {
  1625. source: url,
  1626. protocol: a.protocol.replace(':', ''),
  1627. host: a.hostname,
  1628. port: a.port,
  1629. query: a.search,
  1630. file: (a.pathname.match(/\/([^\/?#]+)$/i) || [, ''])[1],
  1631. hash: a.hash.replace('#', ''),
  1632. path: a.pathname.replace(/^([^\/])/, '/$1'),
  1633. relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [, ''])[1],
  1634. segments: a.pathname.replace(/^\//, '').split('/'),
  1635. params: (function () {
  1636. var ret = {};
  1637. var seg = a.search.replace(/^\?/, '').split('&').filter(function (v, i) {
  1638. if (v !== '' && v.indexOf('=')) {
  1639. return true;
  1640. }
  1641. });
  1642. seg.forEach(function (element, index) {
  1643. var idx = element.indexOf('=');
  1644. var key = element.substring(0, idx);
  1645. var val = element.substring(idx + 1);
  1646. ret[key] = val;
  1647. });
  1648. return ret;
  1649. })()
  1650. };
  1651. },
  1652. urlMatching: function (url, matchUrl) {
  1653. var pattern = new RegExp(matchUrl);
  1654. return pattern.test(url);
  1655. },
  1656. getUrlWithoutParam: function (url) {
  1657. return url.split('?')[0];
  1658. },
  1659. getParamFromUrl: function (url) {
  1660. var params = [];
  1661. var paramsObject = this.getUrlInfo(url).params;
  1662. Object.keys(paramsObject).forEach(function (key) {
  1663. params.push({
  1664. key: key,
  1665. value: paramsObject[key]
  1666. })
  1667. });
  1668. // var parts = url.split('?');
  1669. // if (parts.length < 2) {
  1670. // return params;
  1671. // }
  1672. // var paramsStr = parts[1].split('&');
  1673. // for (var i = 0; i < paramsStr.length; i++) {
  1674. // var index = paramsStr[i].indexOf('=');
  1675. // var ps = new Array(2);
  1676. // if (index !== -1) {
  1677. // ps = [
  1678. // paramsStr[i].substring(0, index),
  1679. // paramsStr[i].substring(index + 1),
  1680. // ];
  1681. // } else {
  1682. // ps[0] = paramsStr[i];
  1683. // }
  1684. // params.push({
  1685. // key: ps[0],
  1686. // value: ps[1]
  1687. // });
  1688. // }
  1689. return params;
  1690. },
  1691. margeUrlAndParams: function (url, params) {
  1692. if (url.indexOf('?') !== -1 || !(params instanceof Array)) {
  1693. return url;
  1694. }
  1695. var paramsStr = [];
  1696. for (var i = 0; i < params.length; i++) {
  1697. if (params[i].key !== null && params[i].value !== null) {
  1698. if (!params[i].key) {
  1699. paramsStr.push(params[i].value);
  1700. } else {
  1701. paramsStr.push(params[i].key + '=' + params[i].value);
  1702. }
  1703. }
  1704. }
  1705. return url + '?' + paramsStr.join('&');
  1706. }
  1707. }
  1708. });
  1709.  
  1710. factory('PointUtils', [], function () {
  1711. var Point2D = function (x, y) {
  1712. this.x = x || 0;
  1713. this.y = y || 0;
  1714. };
  1715. Point2D.prototype = {
  1716. constructor: Point2D,
  1717. /**
  1718. * 获取指定距离和角度对应的平面点
  1719. * @param distance
  1720. * @param deg
  1721. */
  1722. getOtherPointFromDistanceAndDeg: function (distance, deg) {
  1723. var radian = Math.PI / 180 * deg;
  1724. var point = new this.constructor();
  1725. point.x = distance * Math.sin(radian) + this.x;
  1726. point.y = this.y - distance * Math.cos(radian);
  1727. return point;
  1728. },
  1729. /**
  1730. * 获取当前平面点与另一个平面点之间的距离
  1731. * @param p
  1732. * @returns {number}
  1733. */
  1734. getDistanceFromAnotherPoint: function (p) {
  1735. return Math.sqrt((this.x - p.x) * (this.x - p.x) + (this.y - p.y) * (this.y - p.y));
  1736. },
  1737. /**
  1738. * 获取当前平面点与另一个平面点之间的角度
  1739. * @param p
  1740. * @returns {number}
  1741. */
  1742. getDegFromAnotherPoint: function (p) {
  1743. var usedPoint = new Point2D(p.x * 1000000 - this.x * 1000000, p.y * 1000000 - this.y * 1000000);
  1744. var radian = Math.atan2(usedPoint.x * 1000000, usedPoint.y * 1000000);
  1745. var deg = radian * 180 / Math.PI;
  1746. return 180 - deg;
  1747. },
  1748. /**
  1749. * 判断该点是否位于一矩形内部
  1750. * @param x 矩形开始坐标x
  1751. * @param y 矩形开始坐标y
  1752. * @param width 矩形宽
  1753. * @param height 矩形长
  1754. * @returns {boolean}
  1755. */
  1756. isInRect: function (x, y, width, height) {
  1757. var px = this.x;
  1758. var py = this.y;
  1759. if (px < x || px > x + width) {
  1760. return false;
  1761. }
  1762. return !(py < y || py > y + height);
  1763. }
  1764. };
  1765. return {
  1766. Point2D: Point2D
  1767. }
  1768. });
  1769.  
  1770. _global.everyUtils = function () {
  1771. if (BaseUtils.isArray(arguments[0])) {
  1772. depend.call(arguments[2] || this, arguments[0], arguments[1]);
  1773. } else if (BaseUtils.isFunction(arguments[0])) {
  1774. var args = arguments;
  1775. depend.call(arguments[1] || this, ['FunctionUtils'], function (FunctionUtils) {
  1776. var depends = FunctionUtils.getFunctionParams(args[0]);
  1777. depend(depends, args[0]);
  1778. })
  1779. }
  1780. };
  1781.  
  1782. _global.eUtils = (function () {
  1783. var utils = {};
  1784. if (window.everyUtils) {
  1785. window.everyUtils(function (
  1786. ArrayUtils,
  1787. ObjectUtils,
  1788. BaseUtils,
  1789. FunctionUtils,
  1790. ColorUtils,
  1791. PointUtils,
  1792. UrlUtils) {
  1793. utils = {
  1794. ArrayUtils: ArrayUtils,
  1795. ObjectUtils: ObjectUtils,
  1796. BaseUtils: BaseUtils,
  1797. ColorUtils: ColorUtils,
  1798. UrlUtils: UrlUtils,
  1799. urlUtils: UrlUtils,
  1800. PointUtils: PointUtils,
  1801. FunctionUtils: FunctionUtils
  1802. };
  1803. });
  1804. }
  1805. var proxy = {};
  1806. Object.keys(utils).forEach(function (utilName) {
  1807. if (!utilName) {
  1808. return;
  1809. }
  1810. Object.defineProperty(proxy, utilName, {
  1811. get: function () {
  1812. return utils[utilName];
  1813. }
  1814. });
  1815. Object.keys(utils[utilName]).forEach(function (key) {
  1816. if (!key) {
  1817. return;
  1818. }
  1819. if (proxy[key]) {
  1820. return;
  1821. }
  1822. Object.defineProperty(proxy, key, {
  1823. get: function () {
  1824. return utils[utilName][key];
  1825. }
  1826. })
  1827. })
  1828. });
  1829. return proxy;
  1830. })();
  1831.  
  1832. return _global.eUtils;
  1833. }));
  1834.  
  1835.  
  1836. ~function (utils) {
  1837. var _global = this;
  1838. var EHook = function () {
  1839. var _autoId = 1;
  1840. var _hookedMap = {};
  1841. this._getHookedMap = function () {
  1842. return _hookedMap;
  1843. };
  1844. this._getAutoStrId = function () {
  1845. return '__auto__' + _autoId++;
  1846. };
  1847. this._getAutoId = function () {
  1848. return _autoId++;
  1849. };
  1850. };
  1851. EHook.prototype = {
  1852. /**
  1853. * 获取一个对象的劫持id,若没有则创建一个
  1854. * @param context
  1855. * @return {*}
  1856. * @private
  1857. */
  1858. _getHookedId: function (context) {
  1859. var hookedId = context.___hookedId;
  1860. if (hookedId == null) {
  1861. hookedId = context.___hookedId = this._getAutoStrId();
  1862. }
  1863. return hookedId;
  1864. },
  1865. /**
  1866. * 获取一个对象的劫持方法映射,若没有则创建一个
  1867. * @param context
  1868. * @return {*}
  1869. * @private
  1870. */
  1871. _getHookedMethodMap: function (context) {
  1872. var hookedId = this._getHookedId(context);
  1873. var hookedMap = this._getHookedMap();
  1874. var thisTask = hookedMap[hookedId];
  1875. if (!utils.isExistObject(thisTask)) {
  1876. thisTask = hookedMap[hookedId] = {};
  1877. }
  1878. return thisTask;
  1879. },
  1880. /**
  1881. * 获取对应方法的hook原型任务对象,若没有则初始化一个。
  1882. * @param context
  1883. * @param methodName
  1884. * @private
  1885. */
  1886. _getHookedMethodTask: function (context, methodName) {
  1887. var thisMethodMap = this._getHookedMethodMap(context);
  1888. var thisMethod = thisMethodMap[methodName];
  1889. if (!utils.isExistObject(thisMethod)) {
  1890. thisMethod = thisMethodMap[methodName] = {
  1891. original: undefined,
  1892. replace: undefined,
  1893. task: {
  1894. before: [],
  1895. current: undefined,
  1896. after: []
  1897. }
  1898. };
  1899. }
  1900. return thisMethod;
  1901. },
  1902. /**
  1903. * 执行多个方法并注入一个方法和参数集合
  1904. * @param context
  1905. * @param methods
  1906. * @param args
  1907. * @return result 最后一次执行方法的有效返回值
  1908. * @private
  1909. */
  1910. _invokeMethods: function (context, methods, args) {
  1911. if (!utils.isArray(methods)) {
  1912. return;
  1913. }
  1914. var result = null;
  1915. utils.ergodicArrayObject(context, methods, function (_method) {
  1916. if (!utils.isFunction(_method.method)) {
  1917. return;
  1918. }
  1919. var r = _method.method.apply(this, args);
  1920. if (r != null) {
  1921. result = r;
  1922. }
  1923. });
  1924. return result;
  1925. },
  1926. /**
  1927. * 生成和替换劫持方法
  1928. * @param parent
  1929. * @param context
  1930. * @param methodName {string}
  1931. * @private
  1932. */
  1933. _hook: function (parent, methodName, context) {
  1934. if (context === undefined) {
  1935. context = parent;
  1936. }
  1937. var method = parent[methodName];
  1938. var methodTask = this._getHookedMethodTask(parent, methodName);
  1939. if (!methodTask.original) {
  1940. methodTask.original = method;
  1941. }
  1942. if (utils.isExistObject(methodTask.replace) && utils.isFunction(methodTask.replace.method)) {
  1943. parent[methodName] = methodTask.replace.method(methodTask.original);
  1944. return;
  1945. }
  1946. var invokeMethods = this._invokeMethods;
  1947. // 组装劫持函数
  1948. var builder = new utils.FunctionBuilder(function (v) {
  1949. return {
  1950. result: undefined
  1951. };
  1952. });
  1953. if (methodTask.task.before.length > 0) {
  1954. builder.push(function (v) {
  1955. invokeMethods(context || v.this, methodTask.task.before, [methodTask.original, v.arguments]);
  1956. });
  1957. }
  1958. if (utils.isExistObject(methodTask.task.current) && utils.isFunction(methodTask.task.current.method)) {
  1959. builder.push(function (v) {
  1960. return {
  1961. result: methodTask.task.current.method.call(context || v.this, parent, methodTask.original, v.arguments)
  1962. }
  1963. });
  1964. } else {
  1965. builder.push(function (v) {
  1966. return {
  1967. result: methodTask.original.apply(context || v.this, v.arguments)
  1968. }
  1969. });
  1970. }
  1971. if (methodTask.task.after.length > 0) {
  1972. builder.push(function (v) {
  1973. var args = [];
  1974. args.push(methodTask.original);
  1975. args.push(v.arguments);
  1976. args.push(v.result);
  1977. var r = invokeMethods(context || v.this, methodTask.task.after, args);
  1978. return {
  1979. result: (r != null ? r : v.result)
  1980. };
  1981. });
  1982. }
  1983. builder.push(function (v) {
  1984. return {
  1985. returnValue: v.result
  1986. };
  1987. });
  1988. // var methodStr = '(function(){\n';
  1989. // methodStr = methodStr + 'var result = undefined;\n';
  1990. // if (methodTask.task.before.length > 0) {
  1991. // methodStr = methodStr + 'invokeMethods(context, methodTask.task.before,[methodTask.original, arguments]);\n';
  1992. // }
  1993. // if (utils.isExistObject(methodTask.task.current) && utils.isFunction(methodTask.task.current.method)) {
  1994. // methodStr = methodStr + 'result = methodTask.task.current.method.call(context, parent, methodTask.original, arguments);\n';
  1995. // } else {
  1996. // methodStr = methodStr + 'result = methodTask.original.apply(context, arguments);\n';
  1997. // }
  1998. // if (methodTask.task.after.length > 0) {
  1999. // methodStr = methodStr + 'var args = [];args.push(methodTask.original);args.push(arguments);args.push(result);\n';
  2000. // methodStr = methodStr + 'var r = invokeMethods(context, methodTask.task.after, args);result = (r!=null?r:result);\n';
  2001. // }
  2002. // methodStr = methodStr + 'return result;\n})';
  2003. // 绑定劫持函数
  2004. var resultFunc = builder.result();
  2005. for (var proxyName in methodTask.original) {
  2006. Object.defineProperty(resultFunc, proxyName, {
  2007. get: function () {
  2008. return methodTask.original[proxyName];
  2009. },
  2010. set: function (v) {
  2011. methodTask.original[proxyName] = v;
  2012. }
  2013. })
  2014. }
  2015. resultFunc.prototype = methodTask.original.prototype;
  2016. parent[methodName] = resultFunc;
  2017. },
  2018. /**
  2019. * 劫持一个方法
  2020. * @param parent
  2021. * @param methodName {string}
  2022. * @param config
  2023. */
  2024. hook: function (parent, methodName, config) {
  2025. var hookedFailure = -1;
  2026. // 调用方法的上下文
  2027. var context = config.context !== undefined ? config.context : parent;
  2028. if (parent[methodName] == null) {
  2029. parent[methodName] = function () {
  2030. }
  2031. }
  2032. if (!utils.isFunction(parent[methodName])) {
  2033. return hookedFailure;
  2034. }
  2035. var methodTask = this._getHookedMethodTask(parent, methodName);
  2036. var id = this._getAutoId();
  2037. if (utils.isFunction(config.replace)) {
  2038. methodTask.replace = {
  2039. id: id,
  2040. method: config.replace
  2041. };
  2042. hookedFailure = 0;
  2043. }
  2044. if (utils.isFunction(config.before)) {
  2045. methodTask.task.before.push({
  2046. id: id,
  2047. method: config.before
  2048. });
  2049. hookedFailure = 0;
  2050. }
  2051. if (utils.isFunction(config.current)) {
  2052. methodTask.task.current = {
  2053. id: id,
  2054. method: config.current
  2055. };
  2056. hookedFailure = 0;
  2057. }
  2058. if (utils.isFunction(config.after)) {
  2059. methodTask.task.after.push({
  2060. id: id,
  2061. method: config.after
  2062. });
  2063. hookedFailure = 0;
  2064. }
  2065. if (hookedFailure === 0) {
  2066. this._hook(parent, methodName, context);
  2067. return id;
  2068. } else {
  2069. return hookedFailure;
  2070. }
  2071.  
  2072. },
  2073. /**
  2074. * 劫持替换一个方法
  2075. * @param parent
  2076. * @param context
  2077. * @param methodName {string}
  2078. * @param replace {function}
  2079. * @return {number} 该次劫持的id
  2080. */
  2081. hookReplace: function (parent, methodName, replace, context) {
  2082. return this.hook(parent, methodName, {
  2083. replace: replace,
  2084. context: context
  2085. });
  2086. },
  2087. hookBefore: function (parent, methodName, before, context) {
  2088. return this.hook(parent, methodName, {
  2089. before: before,
  2090. context: context
  2091. });
  2092. },
  2093. hookCurrent: function (parent, methodName, current, context) {
  2094. return this.hook(parent, methodName, {
  2095. current: current,
  2096. context: context
  2097. });
  2098. },
  2099. hookAfter: function (parent, methodName, after, context) {
  2100. return this.hook(parent, methodName, {
  2101. after: after,
  2102. context: context
  2103. });
  2104. },
  2105. hookClass: function (parent, className, replace, innerName, excludeProperties) {
  2106. var _this = this;
  2107. var originFunc = parent[className];
  2108. if (!excludeProperties) {
  2109. excludeProperties = [];
  2110. }
  2111. excludeProperties.push('prototype');
  2112. excludeProperties.push('caller');
  2113. excludeProperties.push('arguments');
  2114. innerName = innerName || '_innerHook';
  2115. var resFunc = function () {
  2116. this[innerName] = new originFunc();
  2117. replace.apply(this, arguments);
  2118. };
  2119. this.hookedToString(originFunc, resFunc);
  2120. this.hookedToProperties(originFunc, resFunc, true, excludeProperties);
  2121. var prototypeProperties = Object.getOwnPropertyNames(originFunc.prototype);
  2122. var prototype = resFunc.prototype = {
  2123. constructor: resFunc
  2124. };
  2125. prototypeProperties.forEach(function (name) {
  2126. if (name === 'constructor') {
  2127. return;
  2128. }
  2129. var method = function () {
  2130. if (originFunc.prototype[name] && utils.isFunction(originFunc.prototype[name])) {
  2131. return originFunc.prototype[name].apply(this[innerName], arguments);
  2132. }
  2133. return undefined;
  2134. };
  2135. _this.hookedToString(originFunc.prototype[name], method);
  2136. prototype[name] = method;
  2137. });
  2138. this.hookReplace(parent, className, function () {
  2139. return resFunc;
  2140. }, parent)
  2141. },
  2142. hookedToProperties: function (originObject, resultObject, isDefined, excludeProperties) {
  2143. var objectProperties = Object.getOwnPropertyNames(originObject);
  2144. objectProperties.forEach(function (property) {
  2145. if (utils.contains(excludeProperties, property)) {
  2146. return;
  2147. }
  2148. if (!isDefined) {
  2149. resultObject[property] = originObject[property];
  2150. } else {
  2151. Object.defineProperty(resultObject, property, {
  2152. configurable: false,
  2153. enumerable: false,
  2154. value: originObject[property],
  2155. writable: false
  2156. });
  2157. }
  2158. });
  2159. },
  2160. hookedToString: function (originObject, resultObject) {
  2161. var toString = function () {
  2162. return originObject.toString();
  2163. };
  2164. var toLocaleString = function () {
  2165. return originObject.toLocaleString();
  2166. };
  2167. Object.defineProperties(resultObject, {
  2168. toString: {
  2169. configurable: false,
  2170. enumerable: false,
  2171. value: toString,
  2172. writable: false
  2173. },
  2174. toLocaleString: {
  2175. configurable: false,
  2176. enumerable: false,
  2177. value: toLocaleString,
  2178. writable: false
  2179. }
  2180. })
  2181. },
  2182. /**
  2183. * 劫持全局ajax
  2184. * @param methods {object} 劫持的方法
  2185. * @return {*|number} 劫持的id
  2186. */
  2187. hookAjax: function (methods) {
  2188. if (this.isHooked(_global, 'XMLHttpRequest')) {
  2189. return;
  2190. }
  2191. var _this = this;
  2192. var hookMethod = function (methodName) {
  2193. if (utils.isFunction(methods[methodName])) {
  2194. // 在执行方法之前hook原方法
  2195. _this.hookBefore(this.xhr, methodName, methods[methodName]);
  2196. }
  2197. // 返回方法调用内部的xhr
  2198. return this.xhr[methodName].bind(this.xhr);
  2199. };
  2200. var getProperty = function (attr) {
  2201. return function () {
  2202. return this.hasOwnProperty(attr + "_") ? this[attr + "_"] : this.xhr[attr];
  2203. };
  2204. };
  2205. var setProperty = function (attr) {
  2206. return function (f) {
  2207. var xhr = this.xhr;
  2208. var that = this;
  2209. if (attr.indexOf("on") !== 0) {
  2210. this[attr + "_"] = f;
  2211. return;
  2212. }
  2213. if (methods[attr]) {
  2214. xhr[attr] = function () {
  2215. f.apply(xhr, arguments);
  2216. };
  2217. // on方法在set时劫持
  2218. _this.hookBefore(xhr, attr, methods[attr]);
  2219. // console.log(1,attr);
  2220. // xhr[attr] = function () {
  2221. // methods[attr](that) || f.apply(xhr, arguments);
  2222. // }
  2223. } else {
  2224. xhr[attr] = f;
  2225. }
  2226. };
  2227. };
  2228. return this.hookReplace(_global, 'XMLHttpRequest', function (XMLHttpRequest) {
  2229. var resFunc = function () {
  2230. this.xhr = new XMLHttpRequest();
  2231. for (var propertyName in this.xhr) {
  2232. var property = this.xhr[propertyName];
  2233. if (utils.isFunction(property)) {
  2234. // hook 原方法
  2235. this[propertyName] = hookMethod.bind(this)(propertyName);
  2236. } else {
  2237. Object.defineProperty(this, propertyName, {
  2238. get: getProperty(propertyName),
  2239. set: setProperty(propertyName)
  2240. });
  2241. }
  2242. }
  2243. // 定义外部xhr可以在内部访问
  2244. this.xhr.xhr = this;
  2245. };
  2246. _this.hookedToProperties(XMLHttpRequest, resFunc, true);
  2247. _this.hookedToString(XMLHttpRequest, resFunc);
  2248. return resFunc
  2249. });
  2250. },
  2251. /**
  2252. * 劫持全局ajax
  2253. * @param methods {object} 劫持的方法
  2254. * @return {*|number} 劫持的id
  2255. */
  2256. hookAjaxV2: function (methods) {
  2257. this.hookClass(window, 'XMLHttpRequest', function () {
  2258.  
  2259. });
  2260. utils.ergodicObject(this, methods, function (method) {
  2261.  
  2262. });
  2263. },
  2264. /**
  2265. * 解除劫持
  2266. * @param context 上下文
  2267. * @param methodName 方法名
  2268. * @param isDeeply {boolean=} 是否深度解除[默认为false]
  2269. * @param eqId {number=} 解除指定id的劫持[可选]
  2270. */
  2271. unHook: function (context, methodName, isDeeply, eqId) {
  2272. if (!context[methodName] || !utils.isFunction(context[methodName])) {
  2273. return;
  2274. }
  2275. var methodTask = this._getHookedMethodTask(context, methodName);
  2276. if (eqId) {
  2277. if (this.unHookById(eqId)) {
  2278. return;
  2279. }
  2280. }
  2281. if (!methodTask.original) {
  2282. delete this._getHookedMethodMap(context)[methodName];
  2283. return;
  2284. }
  2285. context[methodName] = methodTask.original;
  2286. if (isDeeply) {
  2287. delete this._getHookedMethodMap(context)[methodName];
  2288. }
  2289. },
  2290. /**
  2291. * 通过Id解除劫持
  2292. * @param eqId
  2293. * @returns {boolean}
  2294. */
  2295. unHookById: function (eqId) {
  2296. var hasEq = false;
  2297. if (eqId) {
  2298. var hookedMap = this._getHookedMap();
  2299. utils.ergodicObject(this, hookedMap, function (contextMap) {
  2300. utils.ergodicObject(this, contextMap, function (methodTask) {
  2301. methodTask.task.before = methodTask.task.before.filter(function (before) {
  2302. hasEq = hasEq || before.id === eqId;
  2303. return before.id !== eqId;
  2304. });
  2305. methodTask.task.after = methodTask.task.after.filter(function (after) {
  2306. hasEq = hasEq || after.id === eqId;
  2307. return after.id !== eqId;
  2308. });
  2309. if (methodTask.task.current && methodTask.task.current.id === eqId) {
  2310. methodTask.task.current = undefined;
  2311. hasEq = true;
  2312. }
  2313. if (methodTask.replace && methodTask.replace.id === eqId) {
  2314. methodTask.replace = undefined;
  2315. hasEq = true;
  2316. }
  2317. })
  2318. });
  2319. }
  2320. return hasEq;
  2321. },
  2322. /**
  2323. * 移除所有劫持相关的方法
  2324. * @param context 上下文
  2325. * @param methodName 方法名
  2326. */
  2327. removeHookMethod: function (context, methodName) {
  2328. if (!context[methodName] || !utils.isFunction(context[methodName])) {
  2329. return;
  2330. }
  2331. this._getHookedMethodMap(context)[methodName] = {
  2332. original: undefined,
  2333. replace: undefined,
  2334. task: {
  2335. before: [],
  2336. current: undefined,
  2337. after: []
  2338. }
  2339. };
  2340. },
  2341. /**
  2342. * 判断一个方法是否被劫持过
  2343. * @param context
  2344. * @param methodName
  2345. */
  2346. isHooked: function (context, methodName) {
  2347. var hookMap = this._getHookedMap(context);
  2348. return hookMap[methodName] !== undefined ? (hookMap[methodName].original !== undefined) : false;
  2349. },
  2350. /**
  2351. * 保护一个对象使之不会被篡改
  2352. * @param parent
  2353. * @param methodName
  2354. */
  2355. protect: function (parent, methodName) {
  2356. Object.defineProperty(parent, methodName, {
  2357. configurable: false,
  2358. writable: false
  2359. });
  2360. },
  2361. /**
  2362. * 装载插件
  2363. * @param option
  2364. */
  2365. plugins: function (option) {
  2366. if (utils.isFunction(option.mount)) {
  2367. var result = option.mount.call(this, utils);
  2368. if (typeof option.name === 'string') {
  2369. _global[option.name] = result;
  2370. }
  2371. }
  2372. }
  2373. };
  2374. if (_global.eHook && (_global.eHook instanceof EHook)) {
  2375. return;
  2376. }
  2377. var eHook = new EHook();
  2378. var AHook = function () {
  2379. this.isHooked = false;
  2380. var autoId = 1;
  2381. this._urlDispatcherList = [];
  2382. this._getAutoId = function () {
  2383. return autoId++;
  2384. };
  2385. };
  2386. AHook.prototype = {
  2387. /**
  2388. * 执行配置列表中的指定方法组
  2389. * @param xhr
  2390. * @param methodName
  2391. * @param args
  2392. * @private
  2393. */
  2394. _invokeAimMethods: function (xhr, methodName, args) {
  2395. var configs = utils.parseArrayByProperty(xhr.patcherList, 'config');
  2396. var methods = [];
  2397. utils.ergodicArrayObject(xhr, configs, function (config) {
  2398. if (utils.isFunction(config[methodName])) {
  2399. methods.push(config[methodName]);
  2400. }
  2401. });
  2402. return utils.invokeMethods(xhr, methods, args);
  2403. },
  2404. /**
  2405. * 根据url获取配置列表
  2406. * @param url
  2407. * @return {Array}
  2408. * @private
  2409. */
  2410. _urlPatcher: function (url) {
  2411. var patcherList = [];
  2412. utils.ergodicArrayObject(this, this._urlDispatcherList, function (patcherMap, i) {
  2413. if (utils.UrlUtils.urlMatching(url, patcherMap.patcher)) {
  2414. patcherList.push(patcherMap);
  2415. }
  2416. });
  2417. return patcherList;
  2418. },
  2419. /**
  2420. * 根据xhr对象分发回调请求
  2421. * @param xhr
  2422. * @param fullUrl
  2423. * @private
  2424. */
  2425. _xhrDispatcher: function (xhr, fullUrl) {
  2426. var url = utils.UrlUtils.getUrlWithoutParam(fullUrl);
  2427. xhr.patcherList = this._urlPatcher(url);
  2428. },
  2429. /**
  2430. * 转换响应事件
  2431. * @param e
  2432. * @param xhr
  2433. * @private
  2434. */
  2435. _parseEvent: function (e, xhr) {
  2436. try {
  2437. Object.defineProperties(e, {
  2438. target: {
  2439. get: function () {
  2440. return xhr;
  2441. }
  2442. },
  2443. srcElement: {
  2444. get: function () {
  2445. return xhr;
  2446. }
  2447. }
  2448. });
  2449. } catch (error) {
  2450. console.warn('重定义返回事件失败,劫持响应可能失败');
  2451. }
  2452. return e;
  2453. },
  2454. /**
  2455. * 解析open方法的参数
  2456. * @param args
  2457. * @private
  2458. */
  2459. _parseOpenArgs: function (args) {
  2460. return {
  2461. method: args[0],
  2462. fullUrl: args[1],
  2463. url: utils.UrlUtils.getUrlWithoutParam(args[1]),
  2464. params: utils.UrlUtils.getParamFromUrl(args[1]),
  2465. async: args[2]
  2466. };
  2467. },
  2468. /**
  2469. * 劫持ajax 请求参数
  2470. * @param argsObject
  2471. * @param argsArray
  2472. * @private
  2473. */
  2474. _rebuildOpenArgs: function (argsObject, argsArray) {
  2475. argsArray[0] = argsObject.method;
  2476. argsArray[1] = utils.UrlUtils.margeUrlAndParams(argsObject.url, argsObject.params);
  2477. argsArray[2] = argsObject.async;
  2478. },
  2479. /**
  2480. * 获取劫持方法的参数 [原方法,原方法参数,原方法返回值],剔除原方法参数
  2481. * @param args
  2482. * @return {*|Array.<T>}
  2483. * @private
  2484. */
  2485. _getHookedArgs: function (args) {
  2486. // 将参数中'原方法'剔除
  2487. return Array.prototype.slice.call(args, 0).splice(1);
  2488. },
  2489. /**
  2490. * 响应被触发时调用的方法
  2491. * @param outerXhr
  2492. * @param funcArgs
  2493. * @private
  2494. */
  2495. _onResponse: function (outerXhr, funcArgs) {
  2496. // 因为参数是被劫持的参数为[method(原方法),args(参数)],该方法直接获取参数并转换为数组
  2497. var args = this._getHookedArgs(funcArgs);
  2498. args[0][0] = this._parseEvent(args[0][0], outerXhr.xhr); // 强制事件指向外部xhr
  2499. // 执行所有的名为hookResponse的方法组
  2500. var results = this._invokeAimMethods(outerXhr, 'hookResponse', args);
  2501. // 遍历结果数组并获取最后返回的有效的值作为响应值
  2502. var resultIndex = -1;
  2503. utils.ergodicArrayObject(outerXhr, results, function (res, i) {
  2504. if (res != null) {
  2505. resultIndex = i;
  2506. }
  2507. });
  2508. if (resultIndex !== -1) {
  2509. outerXhr.xhr.responseText_ = outerXhr.xhr.response_ = results[resultIndex];
  2510. }
  2511. },
  2512. /**
  2513. * 手动开始劫持
  2514. */
  2515. startHook: function () {
  2516. var _this = this;
  2517. var normalMethods = {
  2518. // 方法中的this指向内部xhr
  2519. // 拦截响应
  2520. onreadystatechange: function () {
  2521. if (this.readyState == 4 && this.status == 200 || this.status == 304) {
  2522. _this._onResponse(this, arguments);
  2523. }
  2524. },
  2525. onload: function () {
  2526. _this._onResponse(this, arguments);
  2527. },
  2528. // 拦截请求
  2529. open: function () {
  2530. var args = _this._getHookedArgs(arguments);
  2531. var fullUrl = args[0][1];
  2532. _this._xhrDispatcher(this, fullUrl);
  2533. var argsObject = _this._parseOpenArgs(args[0]);
  2534. this.openArgs = argsObject;
  2535. _this._invokeAimMethods(this, 'hookRequest', [argsObject]);
  2536. _this._rebuildOpenArgs(argsObject, args[0]);
  2537. },
  2538. send: function () {
  2539. var args = _this._getHookedArgs(arguments);
  2540. this.sendArgs = args;
  2541. _this._invokeAimMethods(this, 'hookSend', args);
  2542. }
  2543. };
  2544. // 设置总的hookId
  2545. this.___hookedId = _global.eHook.hookAjax(normalMethods);
  2546. this.isHooked = true;
  2547. },
  2548. /**
  2549. * 注册ajaxUrl拦截
  2550. * @param urlPatcher
  2551. * @param configOrRequest
  2552. * @param response
  2553. * @return {number}
  2554. */
  2555. register: function (urlPatcher, configOrRequest, response) {
  2556. if (!urlPatcher) {
  2557. return -1;
  2558. }
  2559. if (!utils.isExistObject(configOrRequest) && !utils.isFunction(response)) {
  2560. return -1;
  2561. }
  2562. var config = {};
  2563. if (utils.isFunction(configOrRequest)) {
  2564. config.hookRequest = configOrRequest;
  2565. }
  2566. if (utils.isFunction(response)) {
  2567. config.hookResponse = response;
  2568. }
  2569. if (utils.isExistObject(configOrRequest)) {
  2570. config = configOrRequest;
  2571. }
  2572. var id = this._getAutoId();
  2573. this._urlDispatcherList.push({
  2574. // 指定id便于后续取消
  2575. id: id,
  2576. patcher: urlPatcher,
  2577. config: config
  2578. });
  2579. // 当注册一个register时,自动开始运行劫持
  2580. if (!this.isHooked) {
  2581. this.startHook();
  2582. }
  2583. return id;
  2584. }
  2585. // todo 注销 cancellation: function (registerId){};
  2586. };
  2587.  
  2588. _global['eHook'] = eHook;
  2589. _global['aHook'] = new AHook();
  2590.  
  2591. }.bind(window)(
  2592. (function () {
  2593. var utils = {};
  2594. if (window.everyUtils) {
  2595. window.everyUtils(function (
  2596. ArrayUtils,
  2597. ObjectUtils,
  2598. BaseUtils,
  2599. FunctionUtils,
  2600. ColorUtils,
  2601. UrlUtils) {
  2602. utils = {
  2603. ArrayUtils: ArrayUtils,
  2604. ObjectUtils: ObjectUtils,
  2605. BaseUtils: BaseUtils,
  2606. ColorUtils: ColorUtils,
  2607. UrlUtils: UrlUtils,
  2608. urlUtils: UrlUtils,
  2609. FunctionUtils: FunctionUtils
  2610. };
  2611. });
  2612. }
  2613. var proxy = {};
  2614. Object.keys(utils).forEach(function (utilName) {
  2615. if (!utilName) {
  2616. return;
  2617. }
  2618. Object.defineProperty(proxy, utilName, {
  2619. get: function () {
  2620. return utils[utilName];
  2621. }
  2622. });
  2623. Object.keys(utils[utilName]).forEach(function (key) {
  2624. if (!key) {
  2625. return;
  2626. }
  2627. if (proxy[key]) {
  2628. return;
  2629. }
  2630. Object.defineProperty(proxy, key, {
  2631. get: function () {
  2632. return utils[utilName][key];
  2633. }
  2634. })
  2635. })
  2636. });
  2637. return proxy;
  2638. })()
  2639. );