utils.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272
  1. /**
  2. * 工具函数包
  3. * @file
  4. * @module UE.utils
  5. * @since 1.2.6.1
  6. */
  7. /**
  8. * UEditor封装使用的静态工具函数
  9. * @module UE.utils
  10. * @unfile
  11. */
  12. var utils = (UE.utils = {
  13. /**
  14. * 用给定的迭代器遍历对象
  15. * @method each
  16. * @param { Object } obj 需要遍历的对象
  17. * @param { Function } iterator 迭代器, 该方法接受两个参数, 第一个参数是当前所处理的value, 第二个参数是当前遍历对象的key
  18. * @example
  19. * ```javascript
  20. * var demoObj = {
  21. * key1: 1,
  22. * key2: 2
  23. * };
  24. *
  25. * //output: key1: 1, key2: 2
  26. * UE.utils.each( demoObj, funciton ( value, key ) {
  27. *
  28. * console.log( key + ":" + value );
  29. *
  30. * } );
  31. * ```
  32. */
  33. /**
  34. * 用给定的迭代器遍历数组或类数组对象
  35. * @method each
  36. * @param { Array } array 需要遍历的数组或者类数组
  37. * @param { Function } iterator 迭代器, 该方法接受两个参数, 第一个参数是当前所处理的value, 第二个参数是当前遍历对象的key
  38. * @example
  39. * ```javascript
  40. * var divs = document.getElmentByTagNames( "div" );
  41. *
  42. * //output: 0: DIV, 1: DIV ...
  43. * UE.utils.each( divs, funciton ( value, key ) {
  44. *
  45. * console.log( key + ":" + value.tagName );
  46. *
  47. * } );
  48. * ```
  49. */
  50. each: function(obj, iterator, context) {
  51. if (obj == null) return;
  52. if (obj.length === +obj.length) {
  53. for (var i = 0, l = obj.length; i < l; i++) {
  54. if (iterator.call(context, obj[i], i, obj) === false) return false;
  55. }
  56. } else {
  57. for (var key in obj) {
  58. if (obj.hasOwnProperty(key)) {
  59. if (iterator.call(context, obj[key], key, obj) === false)
  60. return false;
  61. }
  62. }
  63. }
  64. },
  65. /**
  66. * 以给定对象作为原型创建一个新对象
  67. * @method makeInstance
  68. * @param { Object } protoObject 该对象将作为新创建对象的原型
  69. * @return { Object } 新的对象, 该对象的原型是给定的protoObject对象
  70. * @example
  71. * ```javascript
  72. *
  73. * var protoObject = { sayHello: function () { console.log('Hello UEditor!'); } };
  74. *
  75. * var newObject = UE.utils.makeInstance( protoObject );
  76. * //output: Hello UEditor!
  77. * newObject.sayHello();
  78. * ```
  79. */
  80. makeInstance: function(obj) {
  81. var noop = new Function();
  82. noop.prototype = obj;
  83. obj = new noop();
  84. noop.prototype = null;
  85. return obj;
  86. },
  87. /**
  88. * 将source对象中的属性扩展到target对象上
  89. * @method extend
  90. * @remind 该方法将强制把source对象上的属性复制到target对象上
  91. * @see UE.utils.extend(Object,Object,Boolean)
  92. * @param { Object } target 目标对象, 新的属性将附加到该对象上
  93. * @param { Object } source 源对象, 该对象的属性会被附加到target对象上
  94. * @return { Object } 返回target对象
  95. * @example
  96. * ```javascript
  97. *
  98. * var target = { name: 'target', sex: 1 },
  99. * source = { name: 'source', age: 17 };
  100. *
  101. * UE.utils.extend( target, source );
  102. *
  103. * //output: { name: 'source', sex: 1, age: 17 }
  104. * console.log( target );
  105. *
  106. * ```
  107. */
  108. /**
  109. * 将source对象中的属性扩展到target对象上, 根据指定的isKeepTarget值决定是否保留目标对象中与
  110. * 源对象属性名相同的属性值。
  111. * @method extend
  112. * @param { Object } target 目标对象, 新的属性将附加到该对象上
  113. * @param { Object } source 源对象, 该对象的属性会被附加到target对象上
  114. * @param { Boolean } isKeepTarget 是否保留目标对象中与源对象中属性名相同的属性
  115. * @return { Object } 返回target对象
  116. * @example
  117. * ```javascript
  118. *
  119. * var target = { name: 'target', sex: 1 },
  120. * source = { name: 'source', age: 17 };
  121. *
  122. * UE.utils.extend( target, source, true );
  123. *
  124. * //output: { name: 'target', sex: 1, age: 17 }
  125. * console.log( target );
  126. *
  127. * ```
  128. */
  129. extend: function(t, s, b) {
  130. if (s) {
  131. for (var k in s) {
  132. if (!b || !t.hasOwnProperty(k)) {
  133. t[k] = s[k];
  134. }
  135. }
  136. }
  137. return t;
  138. },
  139. /**
  140. * 将给定的多个对象的属性复制到目标对象target上
  141. * @method extend2
  142. * @remind 该方法将强制把源对象上的属性复制到target对象上
  143. * @remind 该方法支持两个及以上的参数, 从第二个参数开始, 其属性都会被复制到第一个参数上。 如果遇到同名的属性,
  144. * 将会覆盖掉之前的值。
  145. * @param { Object } target 目标对象, 新的属性将附加到该对象上
  146. * @param { Object... } source 源对象, 支持多个对象, 该对象的属性会被附加到target对象上
  147. * @return { Object } 返回target对象
  148. * @example
  149. * ```javascript
  150. *
  151. * var target = {},
  152. * source1 = { name: 'source', age: 17 },
  153. * source2 = { title: 'dev' };
  154. *
  155. * UE.utils.extend2( target, source1, source2 );
  156. *
  157. * //output: { name: 'source', age: 17, title: 'dev' }
  158. * console.log( target );
  159. *
  160. * ```
  161. */
  162. extend2: function(t) {
  163. var a = arguments;
  164. for (var i = 1; i < a.length; i++) {
  165. var x = a[i];
  166. for (var k in x) {
  167. if (!t.hasOwnProperty(k)) {
  168. t[k] = x[k];
  169. }
  170. }
  171. }
  172. return t;
  173. },
  174. /**
  175. * 模拟继承机制, 使得subClass继承自superClass
  176. * @method inherits
  177. * @param { Object } subClass 子类对象
  178. * @param { Object } superClass 超类对象
  179. * @warning 该方法只能让subClass继承超类的原型, subClass对象自身的属性和方法不会被继承
  180. * @return { Object } 继承superClass后的子类对象
  181. * @example
  182. * ```javascript
  183. * function SuperClass(){
  184. * this.name = "小李";
  185. * }
  186. *
  187. * SuperClass.prototype = {
  188. * hello:function(str){
  189. * console.log(this.name + str);
  190. * }
  191. * }
  192. *
  193. * function SubClass(){
  194. * this.name = "小张";
  195. * }
  196. *
  197. * UE.utils.inherits(SubClass,SuperClass);
  198. *
  199. * var sub = new SubClass();
  200. * //output: '小张早上好!
  201. * sub.hello("早上好!");
  202. * ```
  203. */
  204. inherits: function(subClass, superClass) {
  205. var oldP = subClass.prototype,
  206. newP = utils.makeInstance(superClass.prototype);
  207. utils.extend(newP, oldP, true);
  208. subClass.prototype = newP;
  209. return (newP.constructor = subClass);
  210. },
  211. /**
  212. * 用指定的context对象作为函数fn的上下文
  213. * @method bind
  214. * @param { Function } fn 需要绑定上下文的函数对象
  215. * @param { Object } content 函数fn新的上下文对象
  216. * @return { Function } 一个新的函数, 该函数作为原始函数fn的代理, 将完成fn的上下文调换工作。
  217. * @example
  218. * ```javascript
  219. *
  220. * var name = 'window',
  221. * newTest = null;
  222. *
  223. * function test () {
  224. * console.log( this.name );
  225. * }
  226. *
  227. * newTest = UE.utils.bind( test, { name: 'object' } );
  228. *
  229. * //output: object
  230. * newTest();
  231. *
  232. * //output: window
  233. * test();
  234. *
  235. * ```
  236. */
  237. bind: function(fn, context) {
  238. return function() {
  239. return fn.apply(context, arguments);
  240. };
  241. },
  242. /**
  243. * 创建延迟指定时间后执行的函数fn
  244. * @method defer
  245. * @param { Function } fn 需要延迟执行的函数对象
  246. * @param { int } delay 延迟的时间, 单位是毫秒
  247. * @warning 该方法的时间控制是不精确的,仅仅只能保证函数的执行是在给定的时间之后,
  248. * 而不能保证刚好到达延迟时间时执行。
  249. * @return { Function } 目标函数fn的代理函数, 只有执行该函数才能起到延时效果
  250. * @example
  251. * ```javascript
  252. * var start = 0;
  253. *
  254. * function test(){
  255. * console.log( new Date() - start );
  256. * }
  257. *
  258. * var testDefer = UE.utils.defer( test, 1000 );
  259. * //
  260. * start = new Date();
  261. * //output: (大约在1000毫秒之后输出) 1000
  262. * testDefer();
  263. * ```
  264. */
  265. /**
  266. * 创建延迟指定时间后执行的函数fn, 如果在延迟时间内再次执行该方法, 将会根据指定的exclusion的值,
  267. * 决定是否取消前一次函数的执行, 如果exclusion的值为true, 则取消执行,反之,将继续执行前一个方法。
  268. * @method defer
  269. * @param { Function } fn 需要延迟执行的函数对象
  270. * @param { int } delay 延迟的时间, 单位是毫秒
  271. * @param { Boolean } exclusion 如果在延迟时间内再次执行该函数,该值将决定是否取消执行前一次函数的执行,
  272. * 值为true表示取消执行, 反之则将在执行前一次函数之后才执行本次函数调用。
  273. * @warning 该方法的时间控制是不精确的,仅仅只能保证函数的执行是在给定的时间之后,
  274. * 而不能保证刚好到达延迟时间时执行。
  275. * @return { Function } 目标函数fn的代理函数, 只有执行该函数才能起到延时效果
  276. * @example
  277. * ```javascript
  278. *
  279. * function test(){
  280. * console.log(1);
  281. * }
  282. *
  283. * var testDefer = UE.utils.defer( test, 1000, true );
  284. *
  285. * //output: (两次调用仅有一次输出) 1
  286. * testDefer();
  287. * testDefer();
  288. * ```
  289. */
  290. defer: function(fn, delay, exclusion) {
  291. var timerID;
  292. return function() {
  293. if (exclusion) {
  294. clearTimeout(timerID);
  295. }
  296. timerID = setTimeout(fn, delay);
  297. };
  298. },
  299. /**
  300. * 获取元素item在数组array中首次出现的位置, 如果未找到item, 则返回-1
  301. * @method indexOf
  302. * @remind 该方法的匹配过程使用的是恒等“===”
  303. * @param { Array } array 需要查找的数组对象
  304. * @param { * } item 需要在目标数组中查找的值
  305. * @return { int } 返回item在目标数组array中首次出现的位置, 如果在数组中未找到item, 则返回-1
  306. * @example
  307. * ```javascript
  308. * var item = 1,
  309. * arr = [ 3, 4, 6, 8, 1, 1, 2 ];
  310. *
  311. * //output: 4
  312. * console.log( UE.utils.indexOf( arr, item ) );
  313. * ```
  314. */
  315. /**
  316. * 获取元素item数组array中首次出现的位置, 如果未找到item, 则返回-1。通过start的值可以指定搜索的起始位置。
  317. * @method indexOf
  318. * @remind 该方法的匹配过程使用的是恒等“===”
  319. * @param { Array } array 需要查找的数组对象
  320. * @param { * } item 需要在目标数组中查找的值
  321. * @param { int } start 搜索的起始位置
  322. * @return { int } 返回item在目标数组array中的start位置之后首次出现的位置, 如果在数组中未找到item, 则返回-1
  323. * @example
  324. * ```javascript
  325. * var item = 1,
  326. * arr = [ 3, 4, 6, 8, 1, 2, 8, 3, 2, 1, 1, 4 ];
  327. *
  328. * //output: 9
  329. * console.log( UE.utils.indexOf( arr, item, 5 ) );
  330. * ```
  331. */
  332. indexOf: function(array, item, start) {
  333. var index = -1;
  334. start = this.isNumber(start) ? start : 0;
  335. this.each(array, function(v, i) {
  336. if (i >= start && v === item) {
  337. index = i;
  338. return false;
  339. }
  340. });
  341. return index;
  342. },
  343. /**
  344. * 移除数组array中所有的元素item
  345. * @method removeItem
  346. * @param { Array } array 要移除元素的目标数组
  347. * @param { * } item 将要被移除的元素
  348. * @remind 该方法的匹配过程使用的是恒等“===”
  349. * @example
  350. * ```javascript
  351. * var arr = [ 4, 5, 7, 1, 3, 4, 6 ];
  352. *
  353. * UE.utils.removeItem( arr, 4 );
  354. * //output: [ 5, 7, 1, 3, 6 ]
  355. * console.log( arr );
  356. *
  357. * ```
  358. */
  359. removeItem: function(array, item) {
  360. for (var i = 0, l = array.length; i < l; i++) {
  361. if (array[i] === item) {
  362. array.splice(i, 1);
  363. i--;
  364. }
  365. }
  366. },
  367. /**
  368. * 删除字符串str的首尾空格
  369. * @method trim
  370. * @param { String } str 需要删除首尾空格的字符串
  371. * @return { String } 删除了首尾的空格后的字符串
  372. * @example
  373. * ```javascript
  374. *
  375. * var str = " UEdtior ";
  376. *
  377. * //output: 9
  378. * console.log( str.length );
  379. *
  380. * //output: 7
  381. * console.log( UE.utils.trim( " UEdtior " ).length );
  382. *
  383. * //output: 9
  384. * console.log( str.length );
  385. *
  386. * ```
  387. */
  388. trim: function(str) {
  389. return str.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, "");
  390. },
  391. /**
  392. * 将字符串str以','分隔成数组后,将该数组转换成哈希对象, 其生成的hash对象的key为数组中的元素, value为1
  393. * @method listToMap
  394. * @warning 该方法在生成的hash对象中,会为每一个key同时生成一个另一个全大写的key。
  395. * @param { String } str 该字符串将被以','分割为数组, 然后进行转化
  396. * @return { Object } 转化之后的hash对象
  397. * @example
  398. * ```javascript
  399. *
  400. * //output: Object {UEdtior: 1, UEDTIOR: 1, Hello: 1, HELLO: 1}
  401. * console.log( UE.utils.listToMap( 'UEdtior,Hello' ) );
  402. *
  403. * ```
  404. */
  405. /**
  406. * 将字符串数组转换成哈希对象, 其生成的hash对象的key为数组中的元素, value为1
  407. * @method listToMap
  408. * @warning 该方法在生成的hash对象中,会为每一个key同时生成一个另一个全大写的key。
  409. * @param { Array } arr 字符串数组
  410. * @return { Object } 转化之后的hash对象
  411. * @example
  412. * ```javascript
  413. *
  414. * //output: Object {UEdtior: 1, UEDTIOR: 1, Hello: 1, HELLO: 1}
  415. * console.log( UE.utils.listToMap( [ 'UEdtior', 'Hello' ] ) );
  416. *
  417. * ```
  418. */
  419. listToMap: function(list) {
  420. if (!list) return {};
  421. list = utils.isArray(list) ? list : list.split(",");
  422. for (var i = 0, ci, obj = {}; (ci = list[i++]); ) {
  423. obj[ci.toUpperCase()] = obj[ci] = 1;
  424. }
  425. return obj;
  426. },
  427. /**
  428. * 将str中的html符号转义,将转义“',&,<,",>,”,“”七个字符
  429. * @method unhtml
  430. * @param { String } str 需要转义的字符串
  431. * @return { String } 转义后的字符串
  432. * @example
  433. * ```javascript
  434. * var html = '<body>&</body>';
  435. *
  436. * //output: &lt;body&gt;&amp;&lt;/body&gt;
  437. * console.log( UE.utils.unhtml( html ) );
  438. *
  439. * ```
  440. */
  441. unhtml: function(str, reg) {
  442. return str
  443. ? str.replace(
  444. reg || /[&<">'](?:(amp|lt|ldquo|rdquo|quot|gt|#39|nbsp|#\d+);)?/g,
  445. function(a, b) {
  446. if (b) {
  447. return a;
  448. } else {
  449. return {
  450. "<": "&lt;",
  451. "&": "&amp;",
  452. '"': "&quot;",
  453. "“": "&ldquo;",
  454. "”": "&rdquo;",
  455. ">": "&gt;",
  456. "'": "&#39;"
  457. }[a];
  458. }
  459. }
  460. )
  461. : "";
  462. },
  463. /**
  464. * 将str中的转义字符还原成html字符
  465. * @see UE.utils.unhtml(String);
  466. * @method html
  467. * @param { String } str 需要逆转义的字符串
  468. * @return { String } 逆转义后的字符串
  469. * @example
  470. * ```javascript
  471. *
  472. * var str = '&lt;body&gt;&amp;&lt;/body&gt;';
  473. *
  474. * //output: <body>&</body>
  475. * console.log( UE.utils.html( str ) );
  476. *
  477. * ```
  478. */
  479. html: function(str) {
  480. return str
  481. ? str.replace(/&((g|l|quo|ldquo|rdquo)t|amp|#39|nbsp);/g, function(m) {
  482. return {
  483. "&lt;": "<",
  484. "&amp;": "&",
  485. "&quot;": '"',
  486. "&ldquo;": "“",
  487. "&rdquo;": "”",
  488. "&gt;": ">",
  489. "&#39;": "'",
  490. "&nbsp;": " "
  491. }[m];
  492. })
  493. : "";
  494. },
  495. /**
  496. * 将css样式转换为驼峰的形式
  497. * @method cssStyleToDomStyle
  498. * @param { String } cssName 需要转换的css样式名
  499. * @return { String } 转换成驼峰形式后的css样式名
  500. * @example
  501. * ```javascript
  502. *
  503. * var str = 'border-top';
  504. *
  505. * //output: borderTop
  506. * console.log( UE.utils.cssStyleToDomStyle( str ) );
  507. *
  508. * ```
  509. */
  510. cssStyleToDomStyle: (function() {
  511. var test = document.createElement("div").style,
  512. cache = {
  513. float: test.cssFloat != undefined
  514. ? "cssFloat"
  515. : test.styleFloat != undefined ? "styleFloat" : "float"
  516. };
  517. return function(cssName) {
  518. return (
  519. cache[cssName] ||
  520. (cache[cssName] = cssName.toLowerCase().replace(/-./g, function(match) {
  521. return match.charAt(1).toUpperCase();
  522. }))
  523. );
  524. };
  525. })(),
  526. /**
  527. * 动态加载文件到doc中
  528. * @method loadFile
  529. * @param { DomDocument } document 需要加载资源文件的文档对象
  530. * @param { Object } options 加载资源文件的属性集合, 取值请参考代码示例
  531. * @example
  532. * ```javascript
  533. *
  534. * UE.utils.loadFile( document, {
  535. * src:"test.js",
  536. * tag:"script",
  537. * type:"text/javascript",
  538. * defer:"defer"
  539. * } );
  540. *
  541. * ```
  542. */
  543. /**
  544. * 动态加载文件到doc中,加载成功后执行的回调函数fn
  545. * @method loadFile
  546. * @param { DomDocument } document 需要加载资源文件的文档对象
  547. * @param { Object } options 加载资源文件的属性集合, 该集合支持的值是script标签和style标签支持的所有属性。
  548. * @param { Function } fn 资源文件加载成功之后执行的回调
  549. * @warning 对于在同一个文档中多次加载同一URL的文件, 该方法会在第一次加载之后缓存该请求,
  550. * 在此之后的所有同一URL的请求, 将会直接触发回调。
  551. * @example
  552. * ```javascript
  553. *
  554. * UE.utils.loadFile( document, {
  555. * src:"test.js",
  556. * tag:"script",
  557. * type:"text/javascript",
  558. * defer:"defer"
  559. * }, function () {
  560. * console.log('加载成功');
  561. * } );
  562. *
  563. * ```
  564. */
  565. loadFile: (function() {
  566. var tmpList = [];
  567. function getItem(doc, obj) {
  568. try {
  569. for (var i = 0, ci; (ci = tmpList[i++]); ) {
  570. if (ci.doc === doc && ci.url == (obj.src || obj.href)) {
  571. return ci;
  572. }
  573. }
  574. } catch (e) {
  575. return null;
  576. }
  577. }
  578. return function(doc, obj, fn) {
  579. var item = getItem(doc, obj);
  580. if (item) {
  581. if (item.ready) {
  582. fn && fn();
  583. } else {
  584. item.funs.push(fn);
  585. }
  586. return;
  587. }
  588. tmpList.push({
  589. doc: doc,
  590. url: obj.src || obj.href,
  591. funs: [fn]
  592. });
  593. if (!doc.body) {
  594. var html = [];
  595. for (var p in obj) {
  596. if (p == "tag") continue;
  597. html.push(p + '="' + obj[p] + '"');
  598. }
  599. doc.write(
  600. "<" + obj.tag + " " + html.join(" ") + " ></" + obj.tag + ">"
  601. );
  602. return;
  603. }
  604. if (obj.id && doc.getElementById(obj.id)) {
  605. return;
  606. }
  607. var element = doc.createElement(obj.tag);
  608. delete obj.tag;
  609. for (var p in obj) {
  610. element.setAttribute(p, obj[p]);
  611. }
  612. element.onload = element.onreadystatechange = function() {
  613. if (!this.readyState || /loaded|complete/.test(this.readyState)) {
  614. item = getItem(doc, obj);
  615. if (item.funs.length > 0) {
  616. item.ready = 1;
  617. for (var fi; (fi = item.funs.pop()); ) {
  618. fi();
  619. }
  620. }
  621. element.onload = element.onreadystatechange = null;
  622. }
  623. };
  624. element.onerror = function() {
  625. throw Error(
  626. "The load " +
  627. (obj.href || obj.src) +
  628. " fails,check the url settings of file ueditor.config.js "
  629. );
  630. };
  631. doc.getElementsByTagName("head")[0].appendChild(element);
  632. };
  633. })(),
  634. /**
  635. * 判断obj对象是否为空
  636. * @method isEmptyObject
  637. * @param { * } obj 需要判断的对象
  638. * @remind 如果判断的对象是NULL, 将直接返回true, 如果是数组且为空, 返回true, 如果是字符串, 且字符串为空,
  639. * 返回true, 如果是普通对象, 且该对象没有任何实例属性, 返回true
  640. * @return { Boolean } 对象是否为空
  641. * @example
  642. * ```javascript
  643. *
  644. * //output: true
  645. * console.log( UE.utils.isEmptyObject( {} ) );
  646. *
  647. * //output: true
  648. * console.log( UE.utils.isEmptyObject( [] ) );
  649. *
  650. * //output: true
  651. * console.log( UE.utils.isEmptyObject( "" ) );
  652. *
  653. * //output: false
  654. * console.log( UE.utils.isEmptyObject( { key: 1 } ) );
  655. *
  656. * //output: false
  657. * console.log( UE.utils.isEmptyObject( [1] ) );
  658. *
  659. * //output: false
  660. * console.log( UE.utils.isEmptyObject( "1" ) );
  661. *
  662. * ```
  663. */
  664. isEmptyObject: function(obj) {
  665. if (obj == null) return true;
  666. if (this.isArray(obj) || this.isString(obj)) return obj.length === 0;
  667. for (var key in obj) if (obj.hasOwnProperty(key)) return false;
  668. return true;
  669. },
  670. /**
  671. * 把rgb格式的颜色值转换成16进制格式
  672. * @method fixColor
  673. * @param { String } rgb格式的颜色值
  674. * @param { String }
  675. * @example
  676. * rgb(255,255,255) => "#ffffff"
  677. */
  678. fixColor: function(name, value) {
  679. if (/color/i.test(name) && /rgba?/.test(value)) {
  680. var array = value.split(",");
  681. if (array.length > 3) return "";
  682. value = "#";
  683. for (var i = 0, color; (color = array[i++]); ) {
  684. color = parseInt(color.replace(/[^\d]/gi, ""), 10).toString(16);
  685. value += color.length == 1 ? "0" + color : color;
  686. }
  687. value = value.toUpperCase();
  688. }
  689. return value;
  690. },
  691. /**
  692. * 只针对border,padding,margin做了处理,因为性能问题
  693. * @public
  694. * @function
  695. * @param {String} val style字符串
  696. */
  697. optCss: function(val) {
  698. var padding, margin, border;
  699. val = val.replace(/(padding|margin|border)\-([^:]+):([^;]+);?/gi, function(
  700. str,
  701. key,
  702. name,
  703. val
  704. ) {
  705. if (val.split(" ").length == 1) {
  706. switch (key) {
  707. case "padding":
  708. !padding && (padding = {});
  709. padding[name] = val;
  710. return "";
  711. case "margin":
  712. !margin && (margin = {});
  713. margin[name] = val;
  714. return "";
  715. case "border":
  716. return val == "initial" ? "" : str;
  717. }
  718. }
  719. return str;
  720. });
  721. function opt(obj, name) {
  722. if (!obj) {
  723. return "";
  724. }
  725. var t = obj.top,
  726. b = obj.bottom,
  727. l = obj.left,
  728. r = obj.right,
  729. val = "";
  730. if (!t || !l || !b || !r) {
  731. for (var p in obj) {
  732. val += ";" + name + "-" + p + ":" + obj[p] + ";";
  733. }
  734. } else {
  735. val +=
  736. ";" +
  737. name +
  738. ":" +
  739. (t == b && b == l && l == r
  740. ? t
  741. : t == b && l == r
  742. ? t + " " + l
  743. : l == r
  744. ? t + " " + l + " " + b
  745. : t + " " + r + " " + b + " " + l) +
  746. ";";
  747. }
  748. return val;
  749. }
  750. val += opt(padding, "padding") + opt(margin, "margin");
  751. return val
  752. .replace(/^[ \n\r\t;]*|[ \n\r\t]*$/, "")
  753. .replace(/;([ \n\r\t]+)|\1;/g, ";")
  754. .replace(/(&((l|g)t|quot|#39))?;{2,}/g, function(a, b) {
  755. return b ? b + ";;" : ";";
  756. });
  757. },
  758. /**
  759. * 克隆对象
  760. * @method clone
  761. * @param { Object } source 源对象
  762. * @return { Object } source的一个副本
  763. */
  764. /**
  765. * 深度克隆对象,将source的属性克隆到target对象, 会覆盖target重名的属性。
  766. * @method clone
  767. * @param { Object } source 源对象
  768. * @param { Object } target 目标对象
  769. * @return { Object } 附加了source对象所有属性的target对象
  770. */
  771. clone: function(source, target) {
  772. var tmp;
  773. target = target || {};
  774. for (var i in source) {
  775. if (source.hasOwnProperty(i)) {
  776. tmp = source[i];
  777. if (typeof tmp == "object") {
  778. target[i] = utils.isArray(tmp) ? [] : {};
  779. utils.clone(source[i], target[i]);
  780. } else {
  781. target[i] = tmp;
  782. }
  783. }
  784. }
  785. return target;
  786. },
  787. /**
  788. * 把cm/pt为单位的值转换为px为单位的值
  789. * @method transUnitToPx
  790. * @param { String } 待转换的带单位的字符串
  791. * @return { String } 转换为px为计量单位的值的字符串
  792. * @example
  793. * ```javascript
  794. *
  795. * //output: 500px
  796. * console.log( UE.utils.transUnitToPx( '20cm' ) );
  797. *
  798. * //output: 27px
  799. * console.log( UE.utils.transUnitToPx( '20pt' ) );
  800. *
  801. * ```
  802. */
  803. transUnitToPx: function(val) {
  804. if (!/(pt|cm)/.test(val)) {
  805. return val;
  806. }
  807. var unit;
  808. val.replace(/([\d.]+)(\w+)/, function(str, v, u) {
  809. val = v;
  810. unit = u;
  811. });
  812. switch (unit) {
  813. case "cm":
  814. val = parseFloat(val) * 25;
  815. break;
  816. case "pt":
  817. val = Math.round(parseFloat(val) * 96 / 72);
  818. }
  819. return val + (val ? "px" : "");
  820. },
  821. /**
  822. * 在dom树ready之后执行给定的回调函数
  823. * @method domReady
  824. * @remind 如果在执行该方法的时候, dom树已经ready, 那么回调函数将立刻执行
  825. * @param { Function } fn dom树ready之后的回调函数
  826. * @example
  827. * ```javascript
  828. *
  829. * UE.utils.domReady( function () {
  830. *
  831. * console.log('123');
  832. *
  833. * } );
  834. *
  835. * ```
  836. */
  837. domReady: (function() {
  838. var fnArr = [];
  839. function doReady(doc) {
  840. //确保onready只执行一次
  841. doc.isReady = true;
  842. for (var ci; (ci = fnArr.pop()); ci()) {}
  843. }
  844. return function(onready, win) {
  845. win = win || window;
  846. var doc = win.document;
  847. onready && fnArr.push(onready);
  848. if (doc.readyState === "complete") {
  849. doReady(doc);
  850. } else {
  851. doc.isReady && doReady(doc);
  852. if (browser.ie && browser.version != 11) {
  853. (function() {
  854. if (doc.isReady) return;
  855. try {
  856. doc.documentElement.doScroll("left");
  857. } catch (error) {
  858. setTimeout(arguments.callee, 0);
  859. return;
  860. }
  861. doReady(doc);
  862. })();
  863. win.attachEvent("onload", function() {
  864. doReady(doc);
  865. });
  866. } else {
  867. doc.addEventListener(
  868. "DOMContentLoaded",
  869. function() {
  870. doc.removeEventListener(
  871. "DOMContentLoaded",
  872. arguments.callee,
  873. false
  874. );
  875. doReady(doc);
  876. },
  877. false
  878. );
  879. win.addEventListener(
  880. "load",
  881. function() {
  882. doReady(doc);
  883. },
  884. false
  885. );
  886. }
  887. }
  888. };
  889. })(),
  890. /**
  891. * 动态添加css样式
  892. * @method cssRule
  893. * @param { String } 节点名称
  894. * @grammar UE.utils.cssRule('添加的样式的节点名称',['样式','放到哪个document上'])
  895. * @grammar UE.utils.cssRule('body','body{background:#ccc}') => null //给body添加背景颜色
  896. * @grammar UE.utils.cssRule('body') =>样式的字符串 //取得key值为body的样式的内容,如果没有找到key值先关的样式将返回空,例如刚才那个背景颜色,将返回 body{background:#ccc}
  897. * @grammar UE.utils.cssRule('body',document) => 返回指定key的样式,并且指定是哪个document
  898. * @grammar UE.utils.cssRule('body','') =>null //清空给定的key值的背景颜色
  899. */
  900. cssRule: browser.ie && browser.version != 11
  901. ? function(key, style, doc) {
  902. var indexList, index;
  903. if (
  904. style === undefined ||
  905. (style && style.nodeType && style.nodeType == 9)
  906. ) {
  907. //获取样式
  908. doc = style && style.nodeType && style.nodeType == 9
  909. ? style
  910. : doc || document;
  911. indexList = doc.indexList || (doc.indexList = {});
  912. index = indexList[key];
  913. if (index !== undefined) {
  914. return doc.styleSheets[index].cssText;
  915. }
  916. return undefined;
  917. }
  918. doc = doc || document;
  919. indexList = doc.indexList || (doc.indexList = {});
  920. index = indexList[key];
  921. //清除样式
  922. if (style === "") {
  923. if (index !== undefined) {
  924. doc.styleSheets[index].cssText = "";
  925. delete indexList[key];
  926. return true;
  927. }
  928. return false;
  929. }
  930. //添加样式
  931. if (index !== undefined) {
  932. sheetStyle = doc.styleSheets[index];
  933. } else {
  934. sheetStyle = doc.createStyleSheet(
  935. "",
  936. (index = doc.styleSheets.length)
  937. );
  938. indexList[key] = index;
  939. }
  940. sheetStyle.cssText = style;
  941. }
  942. : function(key, style, doc) {
  943. var head, node;
  944. if (
  945. style === undefined ||
  946. (style && style.nodeType && style.nodeType == 9)
  947. ) {
  948. //获取样式
  949. doc = style && style.nodeType && style.nodeType == 9
  950. ? style
  951. : doc || document;
  952. node = doc.getElementById(key);
  953. return node ? node.innerHTML : undefined;
  954. }
  955. doc = doc || document;
  956. node = doc.getElementById(key);
  957. //清除样式
  958. if (style === "") {
  959. if (node) {
  960. node.parentNode.removeChild(node);
  961. return true;
  962. }
  963. return false;
  964. }
  965. //添加样式
  966. if (node) {
  967. node.innerHTML = style;
  968. } else {
  969. node = doc.createElement("style");
  970. node.id = key;
  971. node.innerHTML = style;
  972. doc.getElementsByTagName("head")[0].appendChild(node);
  973. }
  974. },
  975. sort: function(array, compareFn) {
  976. compareFn =
  977. compareFn ||
  978. function(item1, item2) {
  979. return item1.localeCompare(item2);
  980. };
  981. for (var i = 0, len = array.length; i < len; i++) {
  982. for (var j = i, length = array.length; j < length; j++) {
  983. if (compareFn(array[i], array[j]) > 0) {
  984. var t = array[i];
  985. array[i] = array[j];
  986. array[j] = t;
  987. }
  988. }
  989. }
  990. return array;
  991. },
  992. serializeParam: function(json) {
  993. var strArr = [];
  994. for (var i in json) {
  995. //忽略默认的几个参数
  996. if (i == "method" || i == "timeout" || i == "async") continue;
  997. //传递过来的对象和函数不在提交之列
  998. if (
  999. !(
  1000. (typeof json[i]).toLowerCase() == "function" ||
  1001. (typeof json[i]).toLowerCase() == "object"
  1002. )
  1003. ) {
  1004. strArr.push(encodeURIComponent(i) + "=" + encodeURIComponent(json[i]));
  1005. } else if (utils.isArray(json[i])) {
  1006. //支持传数组内容
  1007. for (var j = 0; j < json[i].length; j++) {
  1008. strArr.push(
  1009. encodeURIComponent(i) + "[]=" + encodeURIComponent(json[i][j])
  1010. );
  1011. }
  1012. }
  1013. }
  1014. return strArr.join("&");
  1015. },
  1016. formatUrl: function(url) {
  1017. var u = url.replace(/&&/g, "&");
  1018. u = u.replace(/\?&/g, "?");
  1019. u = u.replace(/&$/g, "");
  1020. u = u.replace(/&#/g, "#");
  1021. u = u.replace(/&+/g, "&");
  1022. return u;
  1023. },
  1024. isCrossDomainUrl: function(url) {
  1025. var a = document.createElement("a");
  1026. a.href = url;
  1027. if (browser.ie) {
  1028. a.href = a.href;
  1029. }
  1030. return !(
  1031. a.protocol == location.protocol &&
  1032. a.hostname == location.hostname &&
  1033. (a.port == location.port ||
  1034. (a.port == "80" && location.port == "") ||
  1035. (a.port == "" && location.port == "80"))
  1036. );
  1037. },
  1038. clearEmptyAttrs: function(obj) {
  1039. for (var p in obj) {
  1040. if (obj[p] === "") {
  1041. delete obj[p];
  1042. }
  1043. }
  1044. return obj;
  1045. },
  1046. str2json: function(s) {
  1047. if (!utils.isString(s)) return null;
  1048. if (window.JSON) {
  1049. return JSON.parse(s);
  1050. } else {
  1051. return new Function("return " + utils.trim(s || ""))();
  1052. }
  1053. },
  1054. json2str: (function() {
  1055. if (window.JSON) {
  1056. return JSON.stringify;
  1057. } else {
  1058. var escapeMap = {
  1059. "\b": "\\b",
  1060. "\t": "\\t",
  1061. "\n": "\\n",
  1062. "\f": "\\f",
  1063. "\r": "\\r",
  1064. '"': '\\"',
  1065. "\\": "\\\\"
  1066. };
  1067. function encodeString(source) {
  1068. if (/["\\\x00-\x1f]/.test(source)) {
  1069. source = source.replace(/["\\\x00-\x1f]/g, function(match) {
  1070. var c = escapeMap[match];
  1071. if (c) {
  1072. return c;
  1073. }
  1074. c = match.charCodeAt();
  1075. return (
  1076. "\\u00" + Math.floor(c / 16).toString(16) + (c % 16).toString(16)
  1077. );
  1078. });
  1079. }
  1080. return '"' + source + '"';
  1081. }
  1082. function encodeArray(source) {
  1083. var result = ["["],
  1084. l = source.length,
  1085. preComma,
  1086. i,
  1087. item;
  1088. for (i = 0; i < l; i++) {
  1089. item = source[i];
  1090. switch (typeof item) {
  1091. case "undefined":
  1092. case "function":
  1093. case "unknown":
  1094. break;
  1095. default:
  1096. if (preComma) {
  1097. result.push(",");
  1098. }
  1099. result.push(utils.json2str(item));
  1100. preComma = 1;
  1101. }
  1102. }
  1103. result.push("]");
  1104. return result.join("");
  1105. }
  1106. function pad(source) {
  1107. return source < 10 ? "0" + source : source;
  1108. }
  1109. function encodeDate(source) {
  1110. return (
  1111. '"' +
  1112. source.getFullYear() +
  1113. "-" +
  1114. pad(source.getMonth() + 1) +
  1115. "-" +
  1116. pad(source.getDate()) +
  1117. "T" +
  1118. pad(source.getHours()) +
  1119. ":" +
  1120. pad(source.getMinutes()) +
  1121. ":" +
  1122. pad(source.getSeconds()) +
  1123. '"'
  1124. );
  1125. }
  1126. return function(value) {
  1127. switch (typeof value) {
  1128. case "undefined":
  1129. return "undefined";
  1130. case "number":
  1131. return isFinite(value) ? String(value) : "null";
  1132. case "string":
  1133. return encodeString(value);
  1134. case "boolean":
  1135. return String(value);
  1136. default:
  1137. if (value === null) {
  1138. return "null";
  1139. } else if (utils.isArray(value)) {
  1140. return encodeArray(value);
  1141. } else if (utils.isDate(value)) {
  1142. return encodeDate(value);
  1143. } else {
  1144. var result = ["{"],
  1145. encode = utils.json2str,
  1146. preComma,
  1147. item;
  1148. for (var key in value) {
  1149. if (Object.prototype.hasOwnProperty.call(value, key)) {
  1150. item = value[key];
  1151. switch (typeof item) {
  1152. case "undefined":
  1153. case "unknown":
  1154. case "function":
  1155. break;
  1156. default:
  1157. if (preComma) {
  1158. result.push(",");
  1159. }
  1160. preComma = 1;
  1161. result.push(encode(key) + ":" + encode(item));
  1162. }
  1163. }
  1164. }
  1165. result.push("}");
  1166. return result.join("");
  1167. }
  1168. }
  1169. };
  1170. }
  1171. })()
  1172. });
  1173. /**
  1174. * 判断给定的对象是否是字符串
  1175. * @method isString
  1176. * @param { * } object 需要判断的对象
  1177. * @return { Boolean } 给定的对象是否是字符串
  1178. */
  1179. /**
  1180. * 判断给定的对象是否是数组
  1181. * @method isArray
  1182. * @param { * } object 需要判断的对象
  1183. * @return { Boolean } 给定的对象是否是数组
  1184. */
  1185. /**
  1186. * 判断给定的对象是否是一个Function
  1187. * @method isFunction
  1188. * @param { * } object 需要判断的对象
  1189. * @return { Boolean } 给定的对象是否是Function
  1190. */
  1191. /**
  1192. * 判断给定的对象是否是Number
  1193. * @method isNumber
  1194. * @param { * } object 需要判断的对象
  1195. * @return { Boolean } 给定的对象是否是Number
  1196. */
  1197. /**
  1198. * 判断给定的对象是否是一个正则表达式
  1199. * @method isRegExp
  1200. * @param { * } object 需要判断的对象
  1201. * @return { Boolean } 给定的对象是否是正则表达式
  1202. */
  1203. /**
  1204. * 判断给定的对象是否是一个普通对象
  1205. * @method isObject
  1206. * @param { * } object 需要判断的对象
  1207. * @return { Boolean } 给定的对象是否是普通对象
  1208. */
  1209. utils.each(
  1210. ["String", "Function", "Array", "Number", "RegExp", "Object", "Date"],
  1211. function(v) {
  1212. UE.utils["is" + v] = function(obj) {
  1213. return Object.prototype.toString.apply(obj) == "[object " + v + "]";
  1214. };
  1215. }
  1216. );