Everything-Hook

it can hook everything

当前为 2018-09-30 提交的版本,查看 最新版本

此脚本不应直接安装,它是供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/372672/632910/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.8045
  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. ~function (_global) {
  23.  
  24. // base
  25. var BaseUtils = {
  26. /**
  27. * 对象是否为数组
  28. * @param arr
  29. */
  30. isArray: function (arr) {
  31. return Array.isArray(arr) || Object.prototype.toString.call(arr) === "[object Array]";
  32. },
  33. /**
  34. * 判断是否为方法
  35. * @param func
  36. * @return {boolean}
  37. */
  38. isFunction: function (func) {
  39. if (!func) {
  40. return false;
  41. }
  42. return typeof func === 'function';
  43. },
  44. /**
  45. * 判断是否是一个有效的对象
  46. * @param obj
  47. * @return {*|boolean}
  48. */
  49. isExistObject: function (obj) {
  50. return obj && (typeof obj === 'object');
  51. },
  52. isString: function (str) {
  53. if (str === null) {
  54. return false;
  55. }
  56. return typeof str === 'string';
  57. }
  58. };
  59.  
  60. //
  61. var serviceProvider = {
  62. _parseDepends: function (depends) {
  63. var dependsArr = [];
  64. if (!BaseUtils.isArray(depends)) {
  65. return;
  66. }
  67. depends.forEach(function (depend) {
  68. if (BaseUtils.isString(depend)) {
  69. dependsArr.push(serviceProvider[depend.toLowerCase()]);
  70. }
  71. });
  72. return dependsArr;
  73. }
  74. };
  75.  
  76. //
  77. var factory = function (name, depends, construction) {
  78. if (!BaseUtils.isFunction(construction)) {
  79. return;
  80. }
  81. serviceProvider[name.toLowerCase()] = construction.apply(this, serviceProvider._parseDepends(depends));
  82. };
  83.  
  84. var depend = function (depends, construction) {
  85. if (!BaseUtils.isFunction(construction)) {
  86. return;
  87. }
  88. construction.apply(this, serviceProvider._parseDepends(depends));
  89. };
  90.  
  91. factory('BaseUtils', [], function () {
  92. return BaseUtils;
  93. });
  94.  
  95. // logger
  96. factory('logger', [], function () {
  97. return console;
  98. });
  99.  
  100. // DateTimeUtils
  101. factory('DateTimeUtils', ['logger'], function (logger) {
  102. return {
  103. /**
  104. * 打印当前时间
  105. */
  106. printNowTime: function () {
  107. var date = new Date();
  108. console.log(this.pattern(date, 'hh:mm:ss:S'));
  109. },
  110. /**
  111. * 格式化日期
  112. * @param date
  113. * @param fmt
  114. * @returns {*}
  115. */
  116. pattern: function (date, fmt) {
  117. var o = {
  118. "M+": date.getMonth() + 1, //月份
  119. "d+": date.getDate(), //日
  120. "h+": date.getHours() % 12 === 0 ? 12 : date.getHours() % 12, //小时
  121. "H+": date.getHours(), //小时
  122. "m+": date.getMinutes(), //分
  123. "s+": date.getSeconds(), //秒
  124. "q+": Math.floor((date.getMonth() + 3) / 3), //季度
  125. "S": date.getMilliseconds() //毫秒
  126. };
  127. var week = {
  128. "0": "/u65e5",
  129. "1": "/u4e00",
  130. "2": "/u4e8c",
  131. "3": "/u4e09",
  132. "4": "/u56db",
  133. "5": "/u4e94",
  134. "6": "/u516d"
  135. };
  136. if (/(y+)/.test(fmt)) {
  137. fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
  138. }
  139. if (/(E+)/.test(fmt)) {
  140. fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? "/u661f/u671f" : "/u5468") : "") + week[date.getDay() + ""]);
  141. }
  142. for (var k in o) {
  143. if (new RegExp("(" + k + ")").test(fmt)) {
  144. fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
  145. }
  146. }
  147. return fmt;
  148. },
  149. /**
  150. * 以当前时间获取id
  151. * @returns {number}
  152. */
  153. getCurrentId: function () {
  154. var date = new Date();
  155. return date.getTime();
  156. },
  157. /**
  158. * 获取指定时间距离现在相差多久
  159. * @param date {number|Date}
  160. * @param isCeil{boolean=} 是否对结果向上取整,默认[false]
  161. * @param type {string=} 单位可取值['day','month','year']默认'day'
  162. * @returns {number}
  163. */
  164. getNowBetweenADay: function (date, isCeil, type) {
  165. if (!type) {
  166. type = 'day'
  167. }
  168. if (typeof date === 'number') {
  169. date = new Date(date);
  170. }
  171. if (!(date instanceof Date)) {
  172. throw new TypeError('该参数类型必须是Date')
  173. }
  174. var time = date.getTime();
  175. var now = new Date();
  176. var nowTime = now.getTime();
  177. if (nowTime - time < 0) {
  178. logger.warn('需要计算的时间必须在当前时间之前');
  179. }
  180. var result = 0;
  181. switch (type) {
  182. default:
  183. case 'day':
  184. result = (nowTime - time) / (1000 * 60 * 60 * 24);
  185. break;
  186. case 'month':
  187. var yearDifference = now.getFullYear() - date.getFullYear();
  188. if (yearDifference > 0) {
  189. result += yearDifference * 12;
  190. }
  191. result += now.getMonth() - date.getMonth();
  192. break;
  193. case 'year':
  194. result += now.getFullYear() - date.getFullYear();
  195. break;
  196. }
  197. if (!isCeil) {
  198. return Math.floor(result);
  199. } else {
  200. if (result === 0 && isCeil) {
  201. result = 1;
  202. }
  203. return Math.ceil(result);
  204. }
  205. }
  206. }
  207. });
  208.  
  209. // ArrayUtils
  210. factory('ArrayUtils', ['BaseUtils'], function (BaseUtils) {
  211. return {
  212. isArrayObject: function (arr) {
  213. return BaseUtils.isArray(arr);
  214. },
  215. /**
  216. * 遍历数组
  217. * @param context {Object}
  218. * @param arr {Array}
  219. * @param cb {Function} 回调函数
  220. */
  221. ergodicArrayObject: function (context, arr, cb) {
  222. if (!context) {
  223. context = window;
  224. }
  225. if (!BaseUtils.isArray(arr) || !BaseUtils.isFunction(cb)) {
  226. return;
  227. }
  228. for (var i = 0; i < arr.length; i++) {
  229. var result = cb.call(context, arr[i], i);
  230. if (result && result === -1) {
  231. break;
  232. }
  233. }
  234. },
  235. /**
  236. * 获取数组对象的一个属性发起动作
  237. * @param context {Object}
  238. * @param arr {Array}
  239. * @param propertyName {String}
  240. * @param cb {Function}
  241. * @param checkProperty {boolean} 是否排除不拥有该属性的对象[default:true]
  242. */
  243. getPropertyDo: function (context, arr, propertyName, cb, checkProperty) {
  244. if (checkProperty === null) {
  245. checkProperty = true;
  246. }
  247. this.ergodicArrayObject(context, arr, function (ele) {
  248. if (!checkProperty || ele.hasOwnProperty(propertyName)) {
  249. cb.call(context, ele[propertyName], ele);
  250. }
  251. })
  252. },
  253. /**
  254. * [私有方法]将多个键值对对象转换为map
  255. * @param arr {Array}
  256. * @returns {{}}
  257. */
  258. parseKeyValue: function (arr) {
  259. var map = {};
  260. if (!(BaseUtils.isArray(arr))) {
  261. return map;
  262. }
  263. this.ergodicArrayObject(this, arr, function (ele) {
  264. if (ele.key === null) {
  265. return;
  266. }
  267. if (!map.hasOwnProperty(ele.key)) {
  268. map[ele.key] = ele.value;
  269. }
  270. });
  271. return map;
  272. },
  273. /**
  274. * 获取数组的哈希码
  275. * @param arr {Array}
  276. * @returns {number}
  277. */
  278. getHashCode: function (arr) {
  279. var str = arr.toString();
  280. var hash = 31;
  281. if (str.length === 0) return hash;
  282. for (var i = 0; i < str.length; i++) {
  283. var char = str.charCodeAt(i);
  284. hash = ((hash << 5) - hash) + char;
  285. hash = hash & hash; // Convert to 32bit integer
  286. }
  287. return hash;
  288. },
  289. /**
  290. * 通过数组中每个对象的指定属性生成一个新数组
  291. * @param arr {Array}
  292. * @param propertyName {String}
  293. */
  294. parseArrayByProperty: function (arr, propertyName) {
  295. var result = [];
  296. if (!this.isArrayObject(arr)) {
  297. return result;
  298. }
  299. this.getPropertyDo(this, arr, propertyName, function (value) {
  300. result.push(value);
  301. }, true);
  302. return result;
  303. },
  304. /**
  305. * 数组对象是否包含一个对象
  306. * @param arr {Array}
  307. * @param obj
  308. * @param cb {function=}
  309. * @returns {boolean}
  310. */
  311. isContainsObject: function (arr, obj, cb) {
  312. var isContainsObject = false;
  313. this.ergodicArrayObject(this, arr, function (value, i) {
  314. if (obj === value) {
  315. isContainsObject = true;
  316. if (BaseUtils.isFunction(cb)) {
  317. cb.call(window, i);
  318. }
  319. return -1;
  320. }
  321. });
  322. return isContainsObject;
  323. },
  324. /**
  325. * 获取数组中的最大值
  326. * @param arr 若数组中的对象还是数组,则按里面数组的每个对象进行多级比较
  327. * @param cb
  328. * @returns {*}
  329. */
  330. getMaxInArray: function (arr, cb) {
  331. var maxObject = null;
  332. var maxIndex = -1;
  333. while (maxObject === null && maxIndex < arr.length) {
  334. maxObject = arr[++maxIndex]
  335. }
  336. for (var i = maxIndex + 1; i < arr.length; i++) {
  337. // 若是比较对象都是数组,则对每个数组的第一个元素进行比较,若相同,则比较第二个元素
  338. if (maxObject !== null && this.isArrayObject(maxObject) && this.isArrayObject(arr[i])) {
  339. var classLength = maxObject.length;
  340. var classLevel = 0;
  341. // console.log(maxObject[classLevel],arr[i][classLevel]);
  342. while (maxObject[classLevel] === arr[i][classLevel] && classLevel < classLength) {
  343. classLevel++
  344. }
  345. if (maxObject[classLevel] !== null && maxObject[classLevel] < arr[i][classLevel]) {
  346. maxObject = arr[i];
  347. maxIndex = i;
  348. }
  349. continue;
  350. }
  351. if (maxObject !== null && maxObject < arr[i]) {
  352. maxObject = arr[i];
  353. maxIndex = i;
  354. }
  355. }
  356. if (BaseUtils.isFunction(cb)) {
  357. cb.call(this, maxObject, maxIndex);
  358. }
  359. return maxObject;
  360. },
  361. /**
  362. * 获取数组中的总值
  363. * @param arr{Array<number>}
  364. * @param cb {function=}
  365. */
  366. getSumInArray: function (arr, cb) {
  367. if (!this.isArrayObject(arr)) {
  368. return;
  369. }
  370. var sum = 0;
  371. var count = 0;
  372. this.ergodicArrayObject(this, arr, function (value) {
  373. if (typeof value === 'number' && !Number.isNaN(value)) {
  374. sum += value;
  375. count += 1;
  376. }
  377. });
  378. if (BaseUtils.isFunction(cb)) {
  379. cb.call(window, sum, count);
  380. }
  381. return sum;
  382. },
  383. /**
  384. * 获取数组中的平均值
  385. * @param arr{Array<number>}
  386. */
  387. getAverageInArray: function (arr) {
  388. var average = 0;
  389. this.getSumInArray(arr, function (sum, i) {
  390. i === 0 || (average = sum / i);
  391. });
  392. return average;
  393. },
  394. /**
  395. * 为数组排序
  396. * @param arr
  397. * @param order
  398. * @param sortSetting {object=}
  399. */
  400. sortingArrays: function (arr, order, sortSetting) {
  401. if (!this.isArrayObject(arr)) {
  402. return;
  403. }
  404. var DESC = 0;
  405. var ASC = 1;
  406. var thisArr = arr.slice(0);
  407. var _thisAction = null;
  408. // 解析配置
  409. var isSetting = sortSetting && sortSetting.getComparedProperty &&
  410. BaseUtils.isFunction(sortSetting.getComparedProperty);
  411. if (isSetting) {
  412. thisArr = sortSetting.getComparedProperty(arr);
  413. }
  414. switch (order) {
  415. default :
  416. case DESC:
  417. _thisAction = thisArr.push;
  418. break;
  419. case ASC:
  420. _thisAction = thisArr.unshift;
  421. break;
  422. }
  423. var resultArr = [];
  424. for (var j = 0; j < thisArr.length; j++) {
  425. this.getMaxInArray(thisArr, function (max, i) {
  426. delete thisArr[i];
  427. _thisAction.call(resultArr, arr[i]);
  428. });
  429. }
  430. if (sortSetting && sortSetting.createNewData) {
  431. return resultArr.slice(0);
  432. }
  433. return resultArr;
  434. }
  435. }
  436. });
  437.  
  438. // ObjectUtils
  439. factory('ObjectUtils', ['ArrayUtils', 'BaseUtils'], function (ArrayUtils, BaseUtils) {
  440. return {
  441. /**
  442. * 获取对象属性[支持链式表达式,如获取学生所在班级所在的学校(student.class.school):'class.school']
  443. * @param obj
  444. * @param linkProperty {string|Array} 属性表达式,获取多个属性则用数组
  445. * @param cb {function=}
  446. * @return 对象属性
  447. */
  448. readLinkProperty: function (obj, linkProperty, cb) {
  449. var callback = null;
  450. if (BaseUtils.isFunction(cb)) {
  451. callback = cb;
  452. }
  453. if (typeof linkProperty === 'string') {
  454. // 除去所有的空格
  455. linkProperty = linkProperty.replace(/ /g, '');
  456. // 不判断为空的值
  457. if (linkProperty === '') {
  458. return null;
  459. }
  460. // 若是以','隔开的伪数组,则转化为数组再进行操作
  461. if (linkProperty.indexOf(',') !== -1) {
  462. var propertyNameArr = linkProperty.split(',');
  463. return this.readLinkProperty(obj, propertyNameArr, callback);
  464. }
  465. if (linkProperty.indexOf('.') !== -1) {
  466. var names = linkProperty.split('.');
  467. var iterationObj = obj;
  468. var result = null;
  469. ArrayUtils.ergodicArrayObject(this, names, function (name, i) {
  470. iterationObj = this.readLinkProperty(iterationObj, name);
  471. if (names[names.length - 1] === name && names.length - 1 === i) {
  472. result = iterationObj;
  473. if (callback) {
  474. callback.call(window, result, linkProperty);
  475. }
  476. }
  477. // 终止对接下来的属性的遍历
  478. if (typeof iterationObj === 'undefined') {
  479. return -1;
  480. }
  481. });
  482. return result;
  483. }
  484. var normalResult = null;
  485. if (linkProperty.slice(linkProperty.length - 2) === '()') {
  486. var func = linkProperty.slice(0, linkProperty.length - 2);
  487. normalResult = obj[func]();
  488. } else {
  489. normalResult = obj[linkProperty];
  490. }
  491. if (normalResult === null) {
  492. console.warn(obj, '的属性[\'' + linkProperty + '\']值未找到');
  493. }
  494. if (callback) {
  495. callback.call(window, normalResult, linkProperty);
  496. }
  497. return normalResult;
  498. }
  499. if (BaseUtils.isArray(linkProperty)) {
  500. var results = [];
  501. ArrayUtils.ergodicArrayObject(this, linkProperty, function (name) {
  502. var value = this.readLinkProperty(obj, name);
  503. results.push(value);
  504. if (callback && name !== '') {
  505. return callback.call(window, value, name);
  506. }
  507. });
  508. results.isMultipleResults = true;
  509. return results;
  510. }
  511. },
  512. /**
  513. * 为对象属性赋值
  514. * (同一个对象中不能够既有数字开头的属性名和普通属性名)
  515. * @param obj
  516. * @param linkProperty {string|Array} 属性表达式,多个属性则用数组
  517. * @param value
  518. */
  519. createLinkProperty: function (obj, linkProperty, value) {
  520. if (obj === null) {
  521. obj = {};
  522. }
  523. if (typeof linkProperty === 'string') {
  524. // 除去所有的空格
  525. linkProperty = linkProperty.replace(/ /g, '');
  526. // 不判断为空的值
  527. if (linkProperty === '') {
  528. throw new TypeError('对象属性名不能为空')
  529. }
  530. if (linkProperty.indexOf(',') !== -1) {
  531. var propertyNameArr = linkProperty.split(',');
  532. this.createLinkProperty(obj, propertyNameArr, value);
  533. return obj;
  534. }
  535. if (linkProperty.indexOf('.') !== -1) {
  536. var names = linkProperty.split('.');
  537. if (!obj.hasOwnProperty(names[0])) {
  538. obj[names[0]] = {}
  539. }
  540. // 判断属性名是否以数字开头(若是代表是一个数组)
  541. if (!Number.isNaN(parseInt(names[0]))) {
  542. if (!ArrayUtils.isArrayObject(obj)) {
  543. obj = [];
  544. }
  545. }
  546. var propertyObj = obj[names[0]];
  547. var newProperties = names.slice(1, names.length);
  548. var newLinkProperty = '';
  549. ArrayUtils.ergodicArrayObject(this, newProperties, function (property, i) {
  550. if (i < newProperties.length - 1) {
  551. newLinkProperty = newLinkProperty + property + '.'
  552. } else {
  553. newLinkProperty = newLinkProperty + property;
  554. }
  555. });
  556. obj[names[0]] = this.createLinkProperty(propertyObj, newLinkProperty, value);
  557. return obj;
  558. }
  559. // 判断属性名是否以数字开头(若是代表是一个数组)
  560. if (!Number.isNaN(parseInt(linkProperty))) {
  561. if (!ArrayUtils.isArrayObject(obj)) {
  562. obj = [];
  563. }
  564. }
  565. obj[linkProperty] = value;
  566. return obj;
  567. } else if (BaseUtils.isArray(linkProperty)) {
  568. ArrayUtils.ergodicArrayObject(this, linkProperty, function (link) {
  569. obj = this.createLinkProperty(obj, link, value);
  570. });
  571. return obj;
  572. }
  573. },
  574. /**
  575. * 遍历对象属性
  576. * @param context {object} 上下文
  577. * @param obj {object} 遍历对象
  578. * @param cb {function} 回调函数
  579. * @param isReadInnerObject {boolean=} 是否遍历内部对象的属性
  580. */
  581. ergodicObject: function (context, obj, cb, isReadInnerObject) {
  582. var keys = Object.keys(obj);
  583. ArrayUtils.ergodicArrayObject(this, keys, function (propertyName) {
  584. // 若内部对象需要遍历
  585. var _propertyName = propertyName;
  586. if (isReadInnerObject && obj[propertyName] !== null && typeof obj[propertyName] === 'object') {
  587. this.ergodicObject(this, obj[propertyName], function (value, key) {
  588. return cb.call(context, value, _propertyName + '.' + key);
  589. }, true)
  590. } else {
  591. return cb.call(context, obj[propertyName], propertyName);
  592. }
  593. })
  594. },
  595. /**
  596. * 当指定属性为空或不存在时执行回到函数;
  597. * @param context {object} 上下文
  598. * @param obj {object} 检测对象
  599. * @param propertyNames{Array|string} 需要检测的属性名
  600. * 可以检查多级属性如:'a.b.c.e',
  601. * 多个属性使用数组,支持纯字符串多个属性用','隔开
  602. * @param cb {function} 回调函数[参数:为空或不存在的属性名,返回值为'-1'时,跳过之后的回调函数]
  603. */
  604. whileEmptyObjectProperty: function (context, obj, propertyNames, cb) {
  605. // 解析单个属性名
  606. if (typeof propertyNames === 'string') {
  607. // 除去所有的空格
  608. propertyNames = propertyNames.replace(/ /g, '');
  609. // 不判断为空的值
  610. if (propertyNames === '') {
  611. return;
  612. }
  613. // 若是以','隔开的伪数组,则转化为数组再进行操作
  614. if (propertyNames.indexOf(',') !== -1) {
  615. var propertyNameArr = propertyNames.split(',');
  616. return this.whileEmptyObjectProperty(context, obj, propertyNameArr, cb);
  617. }
  618. // 若指定级联属性
  619. if (propertyNames.indexOf('.') !== -1) {
  620. var names = propertyNames.split('.');
  621. var iterationObj = obj;
  622. var result = null;
  623. ArrayUtils.ergodicArrayObject(this, names, function (name) {
  624. if (iterationObj && iterationObj.hasOwnProperty(name)) {
  625. iterationObj = iterationObj[name];
  626. } else {
  627. result = cb.call(window, propertyNames);
  628. // 终止对接下来的属性的遍历
  629. return -1;
  630. }
  631. });
  632. return result;
  633. }
  634. // 正常流程
  635. if (!obj.hasOwnProperty(propertyNames)) {
  636. return cb.call(context, propertyNames);
  637. }
  638. if (obj[propertyNames] === null || obj[propertyNames] === '') {
  639. return cb.call(context, propertyNames);
  640. }
  641. } else if (BaseUtils.isArray(propertyNames)) {
  642. // 解析数组
  643. ArrayUtils.ergodicArrayObject(this, propertyNames, function (propertyName) {
  644. // 递归调用
  645. return this.whileEmptyObjectProperty(context, obj, propertyName, cb);
  646. })
  647. }
  648. },
  649. whileEmptyObjectPropertyV2: function (context, obj, propertyNames, cb) {
  650. this.readLinkProperty(obj, propertyNames, function (value, propertyName) {
  651. if (value === null || value === '' || parseInt(value) < 0) {
  652. return cb.call(context, propertyName);
  653. }
  654. })
  655. },
  656. /**
  657. * 克隆对象[只克隆属性,不克隆原型链]
  658. * @param obj {*}
  659. */
  660. cloneObject: function (obj) {
  661. var newObj = {};
  662. // 判断是否为基本数据类型,若是则直接返回
  663. if (typeof obj === 'string' ||
  664. typeof obj === 'number' ||
  665. typeof obj === 'undefined' ||
  666. typeof obj === 'boolean') {
  667. return obj;
  668. }
  669. // 判断是否是数组
  670. if (BaseUtils.isArray(obj)) {
  671. newObj = [];
  672. // 遍历数组并递归调用该方法获取数组内部对象的克隆对象并push到新数组
  673. ArrayUtils.ergodicArrayObject(this, obj, function (arrObjValue) {
  674. newObj.push(this.cloneObject(arrObjValue));
  675. })
  676. } else if (typeof obj === 'object') {
  677. // 当目标为一般对象时即 typeof 为 object
  678. if (obj === null) {
  679. // 当克隆对象为空时,返回空
  680. return null;
  681. }
  682. // 遍历对象的属性并调用递归方法获得该属性对应的对象的克隆对象并将其重新赋值到该属性
  683. this.ergodicObject(this, obj, function (value, key) {
  684. newObj[key] = this.cloneObject(value);
  685. });
  686. }
  687. return newObj;
  688. },
  689. /**
  690. * 扩展对象属性
  691. * @param obj 原对象
  692. * @param extendedObj 被扩展的对象
  693. * @param isCover {boolean=} 扩展的属性和原来属性冲突时是否覆盖 默认[false]
  694. * @param isClone {boolean=} 是否返回一个新的对象,默认[false]返回扩展后的原对象
  695. */
  696. expandObject: function (obj, extendedObj, isCover, isClone) {
  697. var resultObj = obj;
  698. if (isClone) {
  699. resultObj = this.cloneObject(obj);
  700. }
  701. this.ergodicObject(this, extendedObj, function (value, key) {
  702. if (isCover && this.readLinkProperty(resultObj, key) !== null) {
  703. return;
  704. }
  705. resultObj = this.createLinkProperty(resultObj, key, value);
  706. }, true);
  707. return resultObj;
  708. },
  709. /**
  710. * 为数组排序,当数组中的元素为对象时,根据指定对象的属性名进行排序
  711. * @param arr 数组
  712. * @param propertyName 属性名(当有多个属性名时,为多级排序)
  713. * @param order 升降序
  714. * @returns {*}
  715. */
  716. sortingArrayByProperty: function (arr, propertyName, order) {
  717. var _this = this;
  718. var sortSetting = {
  719. // 是否创建新数据
  720. createNewData: false,
  721. // 通过该方法获取数组中每个对象中用来比较的属性
  722. getComparedProperty: function (arr) {
  723. var compareArr = [];
  724. ArrayUtils.ergodicArrayObject(_this, arr, function (obj, i) {
  725. if (typeof obj !== 'object') {
  726. compareArr.push(obj);
  727. } else {
  728. var compareValue = this.readLinkProperty(obj, propertyName);
  729. if (compareValue !== null) {
  730. compareArr.push(compareValue);
  731. } else {
  732. compareArr.push(obj);
  733. }
  734. }
  735. });
  736. return compareArr.slice(0);
  737. }
  738. };
  739. return ArrayUtils.sortingArrays(arr, order, sortSetting);
  740. },
  741. /**
  742. * 转话为目标的实例
  743. * @param constructor {function} 构造函数
  744. * @param obj {object|Array}判断的对象
  745. * @param defaultProperty {object=}
  746. */
  747. toAimObject: function (obj, constructor, defaultProperty) {
  748. if (BaseUtils.isArray(obj)) {
  749. var originArr = [];
  750. ArrayUtils.ergodicArrayObject(this, obj, function (value) {
  751. originArr.push(this.toAimObject(value, constructor, defaultProperty));
  752. });
  753. return originArr;
  754. } else if (typeof obj === 'object') {
  755. if (defaultProperty) {
  756. this.ergodicObject(this, defaultProperty, function (value, key) {
  757. if (obj[key] === null) {
  758. obj[key] = value;
  759. }
  760. });
  761. }
  762. if (obj instanceof constructor) {
  763. return obj;
  764. }
  765. var originObj = obj;
  766. while (originObj.__proto__ !== null && originObj.__proto__ !== Object.prototype) {
  767. originObj = originObj.__proto__;
  768. }
  769. originObj.__proto__ = constructor.prototype;
  770. return originObj;
  771. }
  772. },
  773. /**
  774. * 将数组中结构类似对象指定属性融合为一个数组
  775. * @param arr {Array}
  776. * @param propertyNames
  777. */
  778. parseTheSameObjectPropertyInArray: function (arr, propertyNames) {
  779. var result = {};
  780. var temp = {};
  781. ArrayUtils.ergodicArrayObject(this, arr, function (obj) {
  782. // 获取想要得到的所有属性,以属性名为键值存储到temp中
  783. this.readLinkProperty(obj, propertyNames, function (value, property) {
  784. if (!temp.hasOwnProperty(property) || !(BaseUtils.isArray(temp[property]))) {
  785. temp[property] = [];
  786. }
  787. temp[property].push(value);
  788. });
  789. });
  790. // 遍历temp获取每个键值中的值,并单独取出
  791. this.ergodicObject(this, temp, function (value, key) {
  792. result = this.createLinkProperty(result, key, value);
  793. });
  794. return this.cloneObject(result);
  795. },
  796. /**
  797. * 将数组中结构类似对象指定属性融合为一个数组
  798. * @param arr {Array}
  799. */
  800. parseTheSameObjectAllPropertyInArray: function (arr) {
  801. if (!ArrayUtils.isArrayObject(arr) || arr.length < 1) {
  802. return;
  803. }
  804. // 获取一个对象的所有属性,包括内部对象的属性
  805. var propertyNames = [];
  806. this.ergodicObject(this, arr[0], function (v, k) {
  807. propertyNames.push(k);
  808. }, true);
  809. return this.parseTheSameObjectPropertyInArray(arr, propertyNames);
  810. },
  811. /**
  812. * 获取对象属性,若为数组则计算其中数字的平均值或其它
  813. * @param obj
  814. * @param propertyNames{Array<string>|string}
  815. * @param type
  816. */
  817. getCalculationInArrayByLinkPropertyNames: function (obj, propertyNames, type) {
  818. var resultObject = {};
  819. var _this = this;
  820. switch (type) {
  821. default:
  822. case 'sum':
  823. this.readLinkProperty(obj, propertyNames, function (value, key) {
  824. if (ArrayUtils.isArrayObject(value)) {
  825. resultObject = _this.createLinkProperty(resultObject, key, ArrayUtils.getSumInArray(value));
  826. }
  827. });
  828. break;
  829. case 'average':
  830. this.readLinkProperty(obj, propertyNames, function (value, key) {
  831. if (ArrayUtils.isArrayObject(value)) {
  832. resultObject = _this.createLinkProperty(resultObject, key, ArrayUtils.getAverageInArray(value));
  833. }
  834. });
  835. break;
  836. }
  837. return resultObject;
  838. }
  839. }
  840. });
  841.  
  842. // ColorUtils
  843. factory('ColorUtils', [], function () {
  844. return {
  845. /**
  846. * 转换颜色rgb为16进制
  847. * @param r
  848. * @param g
  849. * @param b
  850. * @return {string}
  851. */
  852. rgbToHex: function (r, g, b) {
  853. var hex = ((r << 16) | (g << 8) | b).toString(16);
  854. return "#" + new Array(Math.abs(hex.length - 7)).join("0") + hex;
  855. },
  856. /**
  857. * 转换颜色16进制为rgb
  858. * @param hex
  859. * @return {Array}
  860. */
  861. hexToRgb: function (hex) {
  862. hex = hex.replace(/ /g, '');
  863. var length = hex.length;
  864. var rgb = [];
  865. switch (length) {
  866. case 4:
  867. rgb.push(parseInt(hex[1] + hex[1], 16));
  868. rgb.push(parseInt(hex[2] + hex[2], 16));
  869. rgb.push(parseInt(hex[3] + hex[3], 16));
  870. return rgb;
  871. case 7:
  872. for (var i = 1; i < 7; i += 2) {
  873. rgb.push(parseInt("0x" + hex.slice(i, i + 2)));
  874. }
  875. return rgb;
  876. default:
  877. break
  878. }
  879. },
  880. /**
  881. * 根据两个颜色以及之间的百分比获取渐进色
  882. * @param start
  883. * @param end
  884. * @param percentage
  885. * @return {*}
  886. */
  887. gradientColorsPercentage: function (start, end, percentage) {
  888. var resultRgb = [];
  889. var startRgb = this.hexToRgb(start);
  890. if (end == null) {
  891. return start;
  892. }
  893. var endRgb = this.hexToRgb(end);
  894. var totalR = endRgb[0] - startRgb[0];
  895. var totalG = endRgb[1] - startRgb[1];
  896. var totalB = endRgb[2] - startRgb[2];
  897. resultRgb.push(startRgb[0] + totalR * percentage);
  898. resultRgb.push(startRgb[1] + totalG * percentage);
  899. resultRgb.push(startRgb[2] + totalB * percentage);
  900. return this.rgbToHex(resultRgb[0], resultRgb[1], resultRgb[2])
  901. }
  902. }
  903. });
  904.  
  905. factory('FunctionUtils', [], function () {
  906. return {
  907. /**
  908. * 获取方法的名字
  909. * @param func
  910. * @returns {*}
  911. */
  912. getFunctionName: function (func) {
  913. if (typeof func === 'function' || typeof func === 'object') {
  914. var name = ('' + func).match(/function\s*([\w\$]*)\s*\(/);
  915. }
  916. return func.name || name[1];
  917. },
  918. /**
  919. * 获取方法的参数名
  920. * @param func
  921. * @returns {*}
  922. */
  923. getFunctionParams: function (func) {
  924. if (typeof func === 'function' || typeof func === 'object') {
  925. var name = ('' + func).match(/function.*\(([^)]*)\)/);
  926. return name[1].replace(/( )|(\n)/g, '').split(',');
  927. }
  928. return;
  929. },
  930. /**
  931. * 通过方法的arguments获取调用该方法的函数
  932. * @param func_arguments
  933. * @returns {string}
  934. */
  935. getCallerName: function (func_arguments) {
  936. var caller = func_arguments.callee.caller;
  937. var callerName = '';
  938. if (caller) {
  939. callerName = this.getFunctionName(caller);
  940. }
  941. return callerName;
  942. },
  943. FunctionBuilder: function (func) {
  944. var _this = this;
  945. var fs = [];
  946. fs.push(func);
  947. var properties = ['push', 'unshift', 'slice', 'map', 'forEach', 'keys', 'find', 'concat', 'fill', 'shift', 'values'];
  948. properties.map(function (property) {
  949. if (typeof Array.prototype[property] === 'function') {
  950. Object.defineProperty(_this, property, {
  951. get: function () {
  952. return function () {
  953. fs[property].apply(fs, arguments);
  954. return this;
  955. }
  956. }
  957. });
  958. }
  959. });
  960. this.result = function (context) {
  961. var rfs = [];
  962. fs.map(function (f, index) {
  963. if (typeof f === 'function') {
  964. rfs.push(f);
  965. }
  966. });
  967. return function () {
  968. var declareVar = {
  969. arguments: arguments,
  970. this: this
  971. };
  972. rfs.map(function (f) {
  973. var dv = f.apply(context || this, [declareVar]);
  974. if (dv) {
  975. Object.keys(dv).map(function (key) {
  976. declareVar[key] = dv[key];
  977. });
  978. }
  979. });
  980. return declareVar.returnValue;
  981. }
  982. }
  983. },
  984. invokeMethods: function (context, methods, args) {
  985. if (!this.isArray(methods)) {
  986. return;
  987. }
  988. var results = [];
  989. var _this = this;
  990. this.ergodicArrayObject(context, methods, function (method) {
  991. if (!_this.isFunction(method)) {
  992. return;
  993. }
  994. results.push(
  995. method.apply(context, args)
  996. );
  997. });
  998. return results;
  999. }
  1000. }
  1001. });
  1002.  
  1003. factory('UrlUtils', [], function () {
  1004. return {
  1005. urlMatching: function (url, matchUrl) {
  1006. var pattern = new RegExp(matchUrl);
  1007. return pattern.test(url);
  1008. },
  1009. getUrlWithoutParam: function (url) {
  1010. return url.split('?')[0];
  1011. },
  1012. getParamFromUrl: function (url) {
  1013. var params = [];
  1014. var parts = url.split('?');
  1015. if (parts.length < 2) {
  1016. return params;
  1017. }
  1018. var paramsStr = parts[1].split('&');
  1019. for (var i = 0; i < paramsStr.length; i++) {
  1020. var index = paramsStr[i].indexOf('=');
  1021. var ps = new Array(2);
  1022. if (index !== -1) {
  1023. ps = [
  1024. paramsStr[i].substring(0, index),
  1025. paramsStr[i].substring(index + 1),
  1026. ];
  1027. } else {
  1028. ps[0] = paramsStr[i];
  1029. }
  1030. params.push({
  1031. key: ps[0],
  1032. value: ps[1]
  1033. });
  1034. }
  1035. return params;
  1036. },
  1037. margeUrlAndParams: function (url, params) {
  1038. if (url.indexOf('?') !== -1 || !(params instanceof Array)) {
  1039. return url;
  1040. }
  1041. var paramsStr = [];
  1042. for (var i = 0; i < params.length; i++) {
  1043. if (params[i].key !== null && params[i].value !== null) {
  1044. paramsStr.push(params[i].key + '=' + params[i].value);
  1045. }
  1046. }
  1047. var paramsPart = paramsStr.join('&');
  1048.  
  1049. return url + (paramsPart ? '?' + paramsPart : '');
  1050. }
  1051. }
  1052. });
  1053.  
  1054. _global.everyUtils = function () {
  1055. if (BaseUtils.isArray(arguments[0])) {
  1056. depend.call(arguments[2] || this, arguments[0], arguments[1]);
  1057. } else if (BaseUtils.isFunction(arguments[0])) {
  1058. var args = arguments;
  1059. depend.call(arguments[1] || this, ['FunctionUtils'], function (FunctionUtils) {
  1060. var depends = FunctionUtils.getFunctionParams(args[0]);
  1061. depend.bind(this)(depends, args[0]);
  1062. })
  1063. }
  1064. };
  1065.  
  1066. _global.p = serviceProvider;
  1067.  
  1068. }(window);
  1069.  
  1070.  
  1071. ~function (utils) {
  1072. var _global = this;
  1073. var EHook = function () {
  1074. var _autoId = 1;
  1075. var _hookedMap = {};
  1076. this._getHookedMap = function () {
  1077. return _hookedMap;
  1078. };
  1079. this._getAutoStrId = function () {
  1080. return '__auto__' + _autoId++;
  1081. };
  1082. this._getAutoId = function () {
  1083. return _autoId++;
  1084. };
  1085. };
  1086. EHook.prototype = {
  1087. /**
  1088. * 获取一个对象的劫持id,若没有则创建一个
  1089. * @param context
  1090. * @return {*}
  1091. * @private
  1092. */
  1093. _getHookedId: function (context) {
  1094. var hookedId = context.___hookedId;
  1095. if (hookedId == null) {
  1096. hookedId = context.___hookedId = this._getAutoStrId();
  1097. }
  1098. return hookedId;
  1099. },
  1100. /**
  1101. * 获取一个对象的劫持方法映射,若没有则创建一个
  1102. * @param context
  1103. * @return {*}
  1104. * @private
  1105. */
  1106. _getHookedMethodMap: function (context) {
  1107. var hookedId = this._getHookedId(context);
  1108. var hookedMap = this._getHookedMap();
  1109. var thisTask = hookedMap[hookedId];
  1110. if (!utils.isExistObject(thisTask)) {
  1111. thisTask = hookedMap[hookedId] = {};
  1112. }
  1113. return thisTask;
  1114. },
  1115. /**
  1116. * 获取对应方法的hook原型任务对象,若没有则初始化一个。
  1117. * @param context
  1118. * @param methodName
  1119. * @private
  1120. */
  1121. _getHookedMethodTask: function (context, methodName) {
  1122. var thisMethodMap = this._getHookedMethodMap(context);
  1123. var thisMethod = thisMethodMap[methodName];
  1124. if (!utils.isExistObject(thisMethod)) {
  1125. thisMethod = thisMethodMap[methodName] = {
  1126. original: undefined,
  1127. replace: undefined,
  1128. task: {
  1129. before: [],
  1130. current: undefined,
  1131. after: []
  1132. }
  1133. };
  1134. }
  1135. return thisMethod;
  1136. },
  1137. /**
  1138. * 执行多个方法并注入一个方法和参数集合
  1139. * @param context
  1140. * @param methods
  1141. * @param args
  1142. * @return result 最后一次执行方法的有效返回值
  1143. * @private
  1144. */
  1145. _invokeMethods: function (context, methods, args) {
  1146. if (!utils.isArray(methods)) {
  1147. return;
  1148. }
  1149. var result = null;
  1150. utils.ergodicArrayObject(context, methods, function (_method) {
  1151. if (!utils.isFunction(_method.method)) {
  1152. return;
  1153. }
  1154. var r = _method.method.apply(this, args);
  1155. if (r != null) {
  1156. result = r;
  1157. }
  1158. });
  1159. return result;
  1160. },
  1161. /**
  1162. * 生成和替换劫持方法
  1163. * @param parent
  1164. * @param context
  1165. * @param methodName {string}
  1166. * @private
  1167. */
  1168. _hook: function (parent, methodName, context) {
  1169. if (context === undefined) {
  1170. context = parent;
  1171. }
  1172. var method = parent[methodName];
  1173. var methodTask = this._getHookedMethodTask(parent, methodName);
  1174. if (!methodTask.original) {
  1175. methodTask.original = method;
  1176. }
  1177. if (utils.isExistObject(methodTask.replace) && utils.isFunction(methodTask.replace.method)) {
  1178. parent[methodName] = methodTask.replace.method(methodTask.original);
  1179. return;
  1180. }
  1181. var invokeMethods = this._invokeMethods;
  1182. // 组装劫持函数
  1183. var builder = new utils.FunctionBuilder(function (v) {
  1184. return {
  1185. result: undefined
  1186. };
  1187. });
  1188. if (methodTask.task.before.length > 0) {
  1189. builder.push(function (v) {
  1190. invokeMethods(context || v.this, methodTask.task.before, [methodTask.original, v.arguments]);
  1191. });
  1192. }
  1193. if (utils.isExistObject(methodTask.task.current) && utils.isFunction(methodTask.task.current.method)) {
  1194. builder.push(function (v) {
  1195. return {
  1196. result: methodTask.task.current.method.call(context || v.this, parent, methodTask.original, v.arguments)
  1197. }
  1198. });
  1199. } else {
  1200. builder.push(function (v) {
  1201. return {
  1202. result: methodTask.original.apply(context || v.this, v.arguments)
  1203. }
  1204. });
  1205. }
  1206. if (methodTask.task.after.length > 0) {
  1207. builder.push(function (v) {
  1208. var args = [];
  1209. args.push(methodTask.original);
  1210. args.push(v.arguments);
  1211. args.push(v.result);
  1212. var r = invokeMethods(context || this, methodTask.task.after, args);
  1213. return {
  1214. result: (r != null ? r : v.result)
  1215. };
  1216. });
  1217. }
  1218. builder.push(function (v) {
  1219. return {
  1220. returnValue: v.result
  1221. };
  1222. });
  1223. // var methodStr = '(function(){\n';
  1224. // methodStr = methodStr + 'var result = undefined;\n';
  1225. // if (methodTask.task.before.length > 0) {
  1226. // methodStr = methodStr + 'invokeMethods(context, methodTask.task.before,[methodTask.original, arguments]);\n';
  1227. // }
  1228. // if (utils.isExistObject(methodTask.task.current) && utils.isFunction(methodTask.task.current.method)) {
  1229. // methodStr = methodStr + 'result = methodTask.task.current.method.call(context, parent, methodTask.original, arguments);\n';
  1230. // } else {
  1231. // methodStr = methodStr + 'result = methodTask.original.apply(context, arguments);\n';
  1232. // }
  1233. // if (methodTask.task.after.length > 0) {
  1234. // methodStr = methodStr + 'var args = [];args.push(methodTask.original);args.push(arguments);args.push(result);\n';
  1235. // methodStr = methodStr + 'var r = invokeMethods(context, methodTask.task.after, args);result = (r!=null?r:result);\n';
  1236. // }
  1237. // methodStr = methodStr + 'return result;\n})';
  1238. // 绑定劫持函数
  1239. var resultFunc = builder.result();
  1240. for (var proxyName in methodTask.original) {
  1241. Object.defineProperty(resultFunc, proxyName, {
  1242. get: function () {
  1243. return methodTask.original[proxyName];
  1244. },
  1245. set: function (v) {
  1246. methodTask.original[proxyName] = v;
  1247. }
  1248. })
  1249. }
  1250. resultFunc.prototype = methodTask.original.prototype;
  1251. parent[methodName] = resultFunc;
  1252. },
  1253. /**
  1254. * 劫持一个方法
  1255. * @param parent
  1256. * @param methodName {string}
  1257. * @param config
  1258. */
  1259. hook: function (parent, methodName, config) {
  1260. var hookedFailure = -1;
  1261. // 调用方法的上下文
  1262. var context = config.context !== undefined ? config.context : parent;
  1263. if (parent[methodName] == null) {
  1264. parent[methodName] = function () {
  1265. }
  1266. }
  1267. if (!utils.isFunction(parent[methodName])) {
  1268. return hookedFailure;
  1269. }
  1270. var methodTask = this._getHookedMethodTask(parent, methodName);
  1271. var id = this._getAutoId();
  1272. if (utils.isFunction(config.replace)) {
  1273. methodTask.replace = {
  1274. id: id,
  1275. method: config.replace
  1276. };
  1277. hookedFailure = 0;
  1278. }
  1279. if (utils.isFunction(config.before)) {
  1280. methodTask.task.before.push({
  1281. id: id,
  1282. method: config.before
  1283. });
  1284. hookedFailure = 0;
  1285. }
  1286. if (utils.isFunction(config.current)) {
  1287. methodTask.task.current = {
  1288. id: id,
  1289. method: config.current
  1290. };
  1291. hookedFailure = 0;
  1292. }
  1293. if (utils.isFunction(config.after)) {
  1294. methodTask.task.after.push({
  1295. id: id,
  1296. method: config.after
  1297. });
  1298. hookedFailure = 0;
  1299. }
  1300. if (hookedFailure === 0) {
  1301. this._hook(parent, methodName, context);
  1302. return id;
  1303. } else {
  1304. return hookedFailure;
  1305. }
  1306.  
  1307. },
  1308. /**
  1309. * 劫持替换一个方法
  1310. * @param parent
  1311. * @param context
  1312. * @param methodName {string}
  1313. * @param replace {function}
  1314. * @return {number} 该次劫持的id
  1315. */
  1316. hookReplace: function (parent, methodName, replace, context) {
  1317. return this.hook(parent, methodName, {
  1318. replace: replace,
  1319. context: context
  1320. });
  1321. },
  1322. hookBefore: function (parent, methodName, before, context) {
  1323. return this.hook(parent, methodName, {
  1324. before: before,
  1325. context: context
  1326. });
  1327. },
  1328. hookCurrent: function (parent, methodName, current, context) {
  1329. return this.hook(parent, methodName, {
  1330. current: current,
  1331. context: context
  1332. });
  1333. },
  1334. hookAfter: function (parent, methodName, after, context) {
  1335. return this.hook(parent, methodName, {
  1336. after: after,
  1337. context: context
  1338. });
  1339. },
  1340. /**
  1341. * 劫持全局ajax
  1342. * @param methods {object} 劫持的方法
  1343. * @return {*|number} 劫持的id
  1344. */
  1345. hookAjax: function (methods) {
  1346. if (this.isHooked(_global, 'XMLHttpRequest')) {
  1347. return;
  1348. }
  1349. var _this = this;
  1350. var hookMethod = function (methodName) {
  1351. if (utils.isFunction(methods[methodName])) {
  1352. // 在执行方法之前hook原方法
  1353. _this.hookBefore(this.xhr, methodName, methods[methodName]);
  1354. }
  1355. // 返回方法调用内部的xhr
  1356. return this.xhr[methodName].bind(this.xhr);
  1357. };
  1358. var getProperty = function (attr) {
  1359. return function () {
  1360. return this.hasOwnProperty(attr + "_") ? this[attr + "_"] : this.xhr[attr];
  1361. };
  1362. };
  1363. var setProperty = function (attr) {
  1364. return function (f) {
  1365. var xhr = this.xhr;
  1366. var that = this;
  1367. if (attr.indexOf("on") !== 0) {
  1368. this[attr + "_"] = f;
  1369. return;
  1370. }
  1371. if (methods[attr]) {
  1372. xhr[attr] = function () {
  1373. f.apply(xhr, arguments);
  1374. };
  1375. // on方法在set时劫持
  1376. _this.hookBefore(xhr, attr, methods[attr]);
  1377. // console.log(1,attr);
  1378. // xhr[attr] = function () {
  1379. // methods[attr](that) || f.apply(xhr, arguments);
  1380. // }
  1381. } else {
  1382. xhr[attr] = f;
  1383. }
  1384. };
  1385. };
  1386. return this.hookReplace(_global, 'XMLHttpRequest', function (XMLHttpRequest) {
  1387. return function () {
  1388. this.xhr = new XMLHttpRequest();
  1389. for (var propertyName in this.xhr) {
  1390. var property = this.xhr[propertyName];
  1391. if (utils.isFunction(property)) {
  1392. // hook 原方法
  1393. this[propertyName] = hookMethod.bind(this)(propertyName);
  1394. } else {
  1395. Object.defineProperty(this, propertyName, {
  1396. get: getProperty(propertyName),
  1397. set: setProperty(propertyName)
  1398. });
  1399. }
  1400. }
  1401. // 定义外部xhr可以在内部访问
  1402. this.xhr.xhr = this;
  1403. };
  1404. });
  1405. },
  1406. /**
  1407. * 解除劫持
  1408. * @param context 上下文
  1409. * @param methodName 方法名
  1410. * @param isDeeply {boolean=} 是否深度解除[默认为false]
  1411. * @param eqId {number=} 解除指定id的劫持[可选]
  1412. */
  1413. unHook: function (context, methodName, isDeeply, eqId) {
  1414. if (!context[methodName] || !utils.isFunction(context[methodName])) {
  1415. return;
  1416. }
  1417. var methodTask = this._getHookedMethodTask(context, methodName);
  1418. if (eqId) {
  1419. if (this.unHookById(eqId)) {
  1420. return;
  1421. }
  1422. }
  1423. if (!methodTask.original) {
  1424. delete this._getHookedMethodMap(context)[methodName];
  1425. return;
  1426. }
  1427. context[methodName] = methodTask.original;
  1428. if (isDeeply) {
  1429. delete this._getHookedMethodMap(context)[methodName];
  1430. }
  1431. },
  1432. /**
  1433. * 通过Id解除劫持
  1434. * @param eqId
  1435. * @returns {boolean}
  1436. */
  1437. unHookById: function (eqId) {
  1438. var hasEq = false;
  1439. if (eqId) {
  1440. var hookedMap = this._getHookedMap();
  1441. utils.ergodicObject(this, hookedMap, function (contextMap) {
  1442. utils.ergodicObject(this, contextMap, function (methodTask) {
  1443. methodTask.task.before = methodTask.task.before.filter(function (before) {
  1444. hasEq = hasEq || before.id === eqId;
  1445. return before.id !== eqId;
  1446. });
  1447. methodTask.task.after = methodTask.task.after.filter(function (after) {
  1448. hasEq = hasEq || after.id === eqId;
  1449. return after.id !== eqId;
  1450. });
  1451. if (methodTask.task.current && methodTask.task.current.id === eqId) {
  1452. methodTask.task.current = undefined;
  1453. hasEq = true;
  1454. }
  1455. if (methodTask.replace && methodTask.replace.id === eqId) {
  1456. methodTask.replace = undefined;
  1457. hasEq = true;
  1458. }
  1459. })
  1460. });
  1461. }
  1462. return hasEq;
  1463. },
  1464. /**
  1465. * 移除所有劫持相关的方法
  1466. * @param context 上下文
  1467. * @param methodName 方法名
  1468. */
  1469. removeHookMethod: function (context, methodName) {
  1470. if (!context[methodName] || !utils.isFunction(context[methodName])) {
  1471. return;
  1472. }
  1473. this._getHookedMethodMap(context)[methodName] = {
  1474. original: undefined,
  1475. replace: undefined,
  1476. task: {
  1477. before: [],
  1478. current: undefined,
  1479. after: []
  1480. }
  1481. };
  1482. },
  1483. /**
  1484. * 判断一个方法是否被劫持过
  1485. * @param context
  1486. * @param methodName
  1487. */
  1488. isHooked: function (context, methodName) {
  1489. var hookMap = this._getHookedMap(context);
  1490. return hookMap[methodName] !== undefined ? (hookMap[methodName].original !== undefined) : false;
  1491. },
  1492. /**
  1493. * 保护一个对象使之不会被篡改
  1494. * @param parent
  1495. * @param methodName
  1496. */
  1497. protect: function (parent, methodName) {
  1498. Object.defineProperty(parent, methodName, {
  1499. configurable: false,
  1500. writable: false
  1501. });
  1502. },
  1503. /**
  1504. * 装载插件
  1505. * @param option
  1506. */
  1507. plugins: function (option) {
  1508. if (utils.isFunction(option.mount)) {
  1509. var result = option.mount.call(this, utils);
  1510. if (typeof option.name === 'string') {
  1511. _global[option.name] = result;
  1512. }
  1513. }
  1514. }
  1515. };
  1516. if (_global.eHook && (_global.eHook instanceof EHook)) {
  1517. return;
  1518. }
  1519. var eHook = new EHook();
  1520. var AHook = function () {
  1521. this.isHooked = false;
  1522. var autoId = 1;
  1523. this._urlDispatcherList = [];
  1524. this._getAutoId = function () {
  1525. return autoId++;
  1526. };
  1527. };
  1528. AHook.prototype = {
  1529. /**
  1530. * 执行配置列表中的指定方法组
  1531. * @param xhr
  1532. * @param methodName
  1533. * @param args
  1534. * @private
  1535. */
  1536. _invokeAimMethods: function (xhr, methodName, args) {
  1537. var configs = utils.parseArrayByProperty(xhr.patcherList, 'config');
  1538. var methods = [];
  1539. utils.ergodicArrayObject(xhr, configs, function (config) {
  1540. if (utils.isFunction(config[methodName])) {
  1541. methods.push(config[methodName]);
  1542. }
  1543. });
  1544. return utils.invokeMethods(xhr, methods, args);
  1545. },
  1546. /**
  1547. * 根据url获取配置列表
  1548. * @param url
  1549. * @return {Array}
  1550. * @private
  1551. */
  1552. _urlPatcher: function (url) {
  1553. var patcherList = [];
  1554. utils.ergodicArrayObject(this, this._urlDispatcherList, function (patcherMap, i) {
  1555. if (utils.UrlUtils.urlMatching(url, patcherMap.patcher)) {
  1556. patcherList.push(patcherMap);
  1557. }
  1558. });
  1559. return patcherList;
  1560. },
  1561. /**
  1562. * 根据xhr对象分发回调请求
  1563. * @param xhr
  1564. * @param fullUrl
  1565. * @private
  1566. */
  1567. _xhrDispatcher: function (xhr, fullUrl) {
  1568. var url = utils.UrlUtils.getUrlWithoutParam(fullUrl);
  1569. xhr.patcherList = this._urlPatcher(url);
  1570. },
  1571. /**
  1572. * 转换响应事件
  1573. * @param e
  1574. * @param xhr
  1575. * @private
  1576. */
  1577. _parseEvent: function (e, xhr) {
  1578. try {
  1579. Object.defineProperties(e, {
  1580. target: {
  1581. get: function () {
  1582. return xhr;
  1583. }
  1584. },
  1585. srcElement: {
  1586. get: function () {
  1587. return xhr;
  1588. }
  1589. }
  1590. });
  1591. } catch (error) {
  1592. console.warn('重定义返回事件失败,劫持响应可能失败');
  1593. }
  1594. return e;
  1595. },
  1596. /**
  1597. * 解析open方法的参数
  1598. * @param args
  1599. * @private
  1600. */
  1601. _parseOpenArgs: function (args) {
  1602. return {
  1603. method: args[0],
  1604. fullUrl: args[1],
  1605. url: utils.UrlUtils.getUrlWithoutParam(args[1]),
  1606. params: utils.UrlUtils.getParamFromUrl(args[1]),
  1607. async: args[2]
  1608. };
  1609. },
  1610. /**
  1611. * 劫持ajax 请求参数
  1612. * @param argsObject
  1613. * @param argsArray
  1614. * @private
  1615. */
  1616. _rebuildOpenArgs: function (argsObject, argsArray) {
  1617. argsArray[0] = argsObject.method;
  1618. argsArray[1] = utils.UrlUtils.margeUrlAndParams(argsObject.url, argsObject.params);
  1619. argsArray[2] = argsObject.async;
  1620. },
  1621. /**
  1622. * 获取劫持方法的参数 [原方法,原方法参数,原方法返回值],剔除原方法参数
  1623. * @param args
  1624. * @return {*|Array.<T>}
  1625. * @private
  1626. */
  1627. _getHookedArgs: function (args) {
  1628. // 将参数中'原方法'剔除
  1629. return Array.prototype.slice.call(args, 0).splice(1);
  1630. },
  1631. /**
  1632. * 响应被触发时调用的方法
  1633. * @param outerXhr
  1634. * @param funcArgs
  1635. * @private
  1636. */
  1637. _onResponse: function (outerXhr, funcArgs) {
  1638. // 因为参数是被劫持的参数为[method(原方法),args(参数)],该方法直接获取参数并转换为数组
  1639. var args = this._getHookedArgs(funcArgs);
  1640. args[0][0] = this._parseEvent(args[0][0], outerXhr.xhr); // 强制事件指向外部xhr
  1641. // 执行所有的名为hookResponse的方法组
  1642. var results = this._invokeAimMethods(outerXhr, 'hookResponse', args);
  1643. // 遍历结果数组并获取最后返回的有效的值作为响应值
  1644. var resultIndex = -1;
  1645. utils.ergodicArrayObject(outerXhr, results, function (res, i) {
  1646. if (res != null) {
  1647. resultIndex = i;
  1648. }
  1649. });
  1650. if (resultIndex !== -1) {
  1651. outerXhr.xhr.responseText_ = outerXhr.xhr.response_ = results[resultIndex];
  1652. }
  1653. },
  1654. /**
  1655. * 手动开始劫持
  1656. */
  1657. startHook: function () {
  1658. var _this = this;
  1659. var normalMethods = {
  1660. // 方法中的this指向内部xhr
  1661. // 拦截响应
  1662. onreadystatechange: function () {
  1663. if (this.readyState == 4 && this.status == 200 || this.status == 304) {
  1664. _this._onResponse(this, arguments);
  1665. }
  1666. },
  1667. onload: function () {
  1668. _this._onResponse(this, arguments);
  1669. },
  1670. // 拦截请求
  1671. open: function () {
  1672. var args = _this._getHookedArgs(arguments);
  1673. var fullUrl = args[0][1];
  1674. _this._xhrDispatcher(this, fullUrl);
  1675. var argsObject = _this._parseOpenArgs(args[0]);
  1676. this.openArgs = argsObject;
  1677. _this._invokeAimMethods(this, 'hookRequest', [argsObject]);
  1678. _this._rebuildOpenArgs(argsObject, args[0]);
  1679. },
  1680. send: function () {
  1681. var args = _this._getHookedArgs(arguments);
  1682. this.sendArgs = args;
  1683. _this._invokeAimMethods(this, 'hookSend', args);
  1684. }
  1685. };
  1686. // 设置总的hookId
  1687. this.___hookedId = _global.eHook.hookAjax(normalMethods);
  1688. this.isHooked = true;
  1689. },
  1690. /**
  1691. * 注册ajaxUrl拦截
  1692. * @param urlPatcher
  1693. * @param configOrRequest
  1694. * @param response
  1695. * @return {number}
  1696. */
  1697. register: function (urlPatcher, configOrRequest, response) {
  1698. if (!urlPatcher) {
  1699. return -1;
  1700. }
  1701. if (!utils.isExistObject(configOrRequest) && !utils.isFunction(response)) {
  1702. return -1;
  1703. }
  1704. var config = {};
  1705. if (utils.isFunction(configOrRequest)) {
  1706. config.hookRequest = configOrRequest;
  1707. }
  1708. if (utils.isFunction(response)) {
  1709. config.hookResponse = response;
  1710. }
  1711. if (utils.isExistObject(configOrRequest)) {
  1712. config = configOrRequest;
  1713. }
  1714. var id = this._getAutoId();
  1715. this._urlDispatcherList.push({
  1716. // 指定id便于后续取消
  1717. id: id,
  1718. patcher: urlPatcher,
  1719. config: config
  1720. });
  1721. // 当注册一个register时,自动开始运行劫持
  1722. if (!this.isHooked) {
  1723. this.startHook();
  1724. }
  1725. return id;
  1726. }
  1727. // todo 注销 cancellation: function (registerId){};
  1728. };
  1729.  
  1730. _global['eHook'] = eHook;
  1731. _global['aHook'] = new AHook();
  1732.  
  1733. }.bind(window)(
  1734. (function () {
  1735. var utils = {};
  1736. if (window.everyUtils) {
  1737. window.everyUtils(function (
  1738. ArrayUtils,
  1739. ObjectUtils,
  1740. BaseUtils,
  1741. FunctionUtils,
  1742. ColorUtils,
  1743. UrlUtils) {
  1744. utils = {
  1745. ArrayUtils: ArrayUtils,
  1746. ObjectUtils: ObjectUtils,
  1747. BaseUtils: BaseUtils,
  1748. ColorUtils: ColorUtils,
  1749. UrlUtils: UrlUtils,
  1750. urlUtils: UrlUtils,
  1751. FunctionUtils: FunctionUtils
  1752. };
  1753. });
  1754. }
  1755. var proxy = {};
  1756. Object.keys(utils).forEach(function (utilName) {
  1757. if (!utilName) {
  1758. return;
  1759. }
  1760. Object.defineProperty(proxy, utilName, {
  1761. get: function () {
  1762. return utils[utilName];
  1763. }
  1764. });
  1765. Object.keys(utils[utilName]).forEach(function (key) {
  1766. if (!key) {
  1767. return;
  1768. }
  1769. if (proxy[key]) {
  1770. return;
  1771. }
  1772. Object.defineProperty(proxy, key, {
  1773. get: function () {
  1774. return utils[utilName][key];
  1775. }
  1776. })
  1777. })
  1778. });
  1779. return proxy;
  1780. })()
  1781. );