Everything-Hook

it can hook everything

目前为 2025-01-20 提交的版本。查看 最新版本

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

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

QingJ © 2025

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