Everything-Hook

it can hook everything

当前为 2020-07-08 提交的版本,查看 最新版本

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