PageRenderTime 268ms CodeModel.GetById 44ms RepoModel.GetById 11ms app.codeStats 4ms

/source/ueditor/umeditor.js

https://github.com/ywl890227/longphp
JavaScript | 9737 lines | 8379 code | 673 blank | 685 comment | 923 complexity | c1e751c883a0788646a35e7bd90903ad MD5 | raw file
Possible License(s): LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /*!
  2. * UEditor Mini版本
  3. * version: 1.0.0
  4. * build: Tue Sep 17 2013 15:57:30 GMT+0800 (CST)
  5. */
  6. (function(){
  7. UMEDITOR_CONFIG = window.UMEDITOR_CONFIG || {};
  8. window.UM = {
  9. plugins : {},
  10. commands : {},
  11. I18N : {},
  12. version : "1.0.0"
  13. };
  14. var dom = UM.dom = {};
  15. /**
  16. * @file
  17. * @name UM.browser
  18. * @short Browser
  19. * @desc UEditor中采用的浏览器判断模块
  20. */
  21. var browser = UM.browser = function(){
  22. var agent = navigator.userAgent.toLowerCase(),
  23. opera = window.opera,
  24. browser = {
  25. /**
  26. * 检测浏览器是否为IE
  27. * @name ie
  28. * @grammar UM.browser.ie => true|false
  29. */
  30. ie : !!window.ActiveXObject,
  31. /**
  32. * 检测浏览器是否为Opera
  33. * @name opera
  34. * @grammar UM.browser.opera => true|false
  35. */
  36. opera : ( !!opera && opera.version ),
  37. /**
  38. * 检测浏览器是否为webkit内核
  39. * @name webkit
  40. * @grammar UM.browser.webkit => true|false
  41. */
  42. webkit : ( agent.indexOf( ' applewebkit/' ) > -1 ),
  43. /**
  44. * 检测浏览器是否为mac系统下的浏览器
  45. * @name mac
  46. * @grammar UM.browser.mac => true|false
  47. */
  48. mac : ( agent.indexOf( 'macintosh' ) > -1 ),
  49. /**
  50. * 检测浏览器是否处于怪异模式
  51. * @name quirks
  52. * @grammar UM.browser.quirks => true|false
  53. */
  54. quirks : ( document.compatMode == 'BackCompat' )
  55. };
  56. /**
  57. * 检测浏览器是否处为gecko内核
  58. * @name gecko
  59. * @grammar UM.browser.gecko => true|false
  60. */
  61. browser.gecko =( navigator.product == 'Gecko' && !browser.webkit && !browser.opera );
  62. var version = 0;
  63. // Internet Explorer 6.0+
  64. if ( browser.ie ){
  65. version = parseFloat( agent.match( /msie (\d+)/ )[1] );
  66. /**
  67. * 检测浏览器是否为 IE9 模式
  68. * @name ie9Compat
  69. * @grammar UM.browser.ie9Compat => true|false
  70. */
  71. browser.ie9Compat = document.documentMode == 9;
  72. /**
  73. * 检测浏览器是否为 IE8 浏览器
  74. * @name ie8
  75. * @grammar UM.browser.ie8 => true|false
  76. */
  77. browser.ie8 = !!document.documentMode;
  78. /**
  79. * 检测浏览器是否为 IE8 模式
  80. * @name ie8Compat
  81. * @grammar UM.browser.ie8Compat => true|false
  82. */
  83. browser.ie8Compat = document.documentMode == 8;
  84. /**
  85. * 检测浏览器是否运行在 兼容IE7模式
  86. * @name ie7Compat
  87. * @grammar UM.browser.ie7Compat => true|false
  88. */
  89. browser.ie7Compat = ( ( version == 7 && !document.documentMode )
  90. || document.documentMode == 7 );
  91. /**
  92. * 检测浏览器是否IE6模式或怪异模式
  93. * @name ie6Compat
  94. * @grammar UM.browser.ie6Compat => true|false
  95. */
  96. browser.ie6Compat = ( version < 7 || browser.quirks );
  97. browser.ie9above = version > 8;
  98. browser.ie9below = version < 9
  99. }
  100. // Gecko.
  101. if ( browser.gecko ){
  102. var geckoRelease = agent.match( /rv:([\d\.]+)/ );
  103. if ( geckoRelease )
  104. {
  105. geckoRelease = geckoRelease[1].split( '.' );
  106. version = geckoRelease[0] * 10000 + ( geckoRelease[1] || 0 ) * 100 + ( geckoRelease[2] || 0 ) * 1;
  107. }
  108. }
  109. /**
  110. * 检测浏览器是否为chrome
  111. * @name chrome
  112. * @grammar UM.browser.chrome => true|false
  113. */
  114. if (/chrome\/(\d+\.\d)/i.test(agent)) {
  115. browser.chrome = + RegExp['\x241'];
  116. }
  117. /**
  118. * 检测浏览器是否为safari
  119. * @name safari
  120. * @grammar UM.browser.safari => true|false
  121. */
  122. if(/(\d+\.\d)?(?:\.\d)?\s+safari\/?(\d+\.\d+)?/i.test(agent) && !/chrome/i.test(agent)){
  123. browser.safari = + (RegExp['\x241'] || RegExp['\x242']);
  124. }
  125. // Opera 9.50+
  126. if ( browser.opera )
  127. version = parseFloat( opera.version() );
  128. // WebKit 522+ (Safari 3+)
  129. if ( browser.webkit )
  130. version = parseFloat( agent.match( / applewebkit\/(\d+)/ )[1] );
  131. /**
  132. * 浏览器版本判断
  133. * IE系列返回值为5,6,7,8,9,10等
  134. * gecko系列会返回10900,158900等.
  135. * webkit系列会返回其build号 (如 522等).
  136. * @name version
  137. * @grammar UM.browser.version => number
  138. * @example
  139. * if ( UM.browser.ie && UM.browser.version == 6 ){
  140. * alert( "Ouch!居然是万恶的IE6!" );
  141. * }
  142. */
  143. browser.version = version;
  144. /**
  145. * 是否是兼容模式的浏览器
  146. * @name isCompatible
  147. * @grammar UM.browser.isCompatible => true|false
  148. * @example
  149. * if ( UM.browser.isCompatible ){
  150. * alert( "你的浏览器相当不错哦!" );
  151. * }
  152. */
  153. browser.isCompatible =
  154. !browser.mobile && (
  155. ( browser.ie && version >= 6 ) ||
  156. ( browser.gecko && version >= 10801 ) ||
  157. ( browser.opera && version >= 9.5 ) ||
  158. ( browser.air && version >= 1 ) ||
  159. ( browser.webkit && version >= 522 ) ||
  160. false );
  161. return browser;
  162. }();
  163. //快捷方式
  164. var ie = browser.ie,
  165. webkit = browser.webkit,
  166. gecko = browser.gecko,
  167. opera = browser.opera;
  168. /**
  169. * @file
  170. * @name UM.Utils
  171. * @short Utils
  172. * @desc UEditor封装使用的静态工具函数
  173. * @import editor.js
  174. */
  175. var utils = UM.utils = {
  176. /**
  177. * 遍历数组,对象,nodeList
  178. * @name each
  179. * @grammar UM.utils.each(obj,iterator,[context])
  180. * @since 1.2.4+
  181. * @desc
  182. * * obj 要遍历的对象
  183. * * iterator 遍历的方法,方法的第一个是遍历的值,第二个是索引,第三个是obj
  184. * * context iterator的上下文
  185. * @example
  186. * UM.utils.each([1,2],function(v,i){
  187. * console.log(v)//值
  188. * console.log(i)//索引
  189. * })
  190. * UM.utils.each(document.getElementsByTagName('*'),function(n){
  191. * console.log(n.tagName)
  192. * })
  193. */
  194. each : function(obj, iterator, context) {
  195. if (obj == null) return;
  196. if (obj.length === +obj.length) {
  197. for (var i = 0, l = obj.length; i < l; i++) {
  198. if(iterator.call(context, obj[i], i, obj) === false)
  199. return false;
  200. }
  201. } else {
  202. for (var key in obj) {
  203. if (obj.hasOwnProperty(key)) {
  204. if(iterator.call(context, obj[key], key, obj) === false)
  205. return false;
  206. }
  207. }
  208. }
  209. },
  210. makeInstance:function (obj) {
  211. var noop = new Function();
  212. noop.prototype = obj;
  213. obj = new noop;
  214. noop.prototype = null;
  215. return obj;
  216. },
  217. /**
  218. * 将source对象中的属性扩展到target对象上
  219. * @name extend
  220. * @grammar UM.utils.extend(target,source) => Object //覆盖扩展
  221. * @grammar UM.utils.extend(target,source,true) ==> Object //保留扩展
  222. */
  223. extend:function (t, s, b) {
  224. if (s) {
  225. for (var k in s) {
  226. if (!b || !t.hasOwnProperty(k)) {
  227. t[k] = s[k];
  228. }
  229. }
  230. }
  231. return t;
  232. },
  233. extend2:function (t) {
  234. var a = arguments;
  235. for (var i = 1; i < a.length; i++) {
  236. var x = a[i];
  237. for (var k in x) {
  238. if (!t.hasOwnProperty(k)) {
  239. t[k] = x[k];
  240. }
  241. }
  242. }
  243. return t;
  244. },
  245. /**
  246. * 模拟继承机制,subClass继承superClass
  247. * @name inherits
  248. * @grammar UM.utils.inherits(subClass,superClass) => subClass
  249. * @example
  250. * function SuperClass(){
  251. * this.name = "小李";
  252. * }
  253. * SuperClass.prototype = {
  254. * hello:function(str){
  255. * console.log(this.name + str);
  256. * }
  257. * }
  258. * function SubClass(){
  259. * this.name = "小张";
  260. * }
  261. * UM.utils.inherits(SubClass,SuperClass);
  262. * var sub = new SubClass();
  263. * sub.hello("早上好!"); ==> "小张早上好!"
  264. */
  265. inherits:function (subClass, superClass) {
  266. var oldP = subClass.prototype,
  267. newP = utils.makeInstance(superClass.prototype);
  268. utils.extend(newP, oldP, true);
  269. subClass.prototype = newP;
  270. return (newP.constructor = subClass);
  271. },
  272. /**
  273. * 用指定的context作为fn上下文,也就是this
  274. * @name bind
  275. * @grammar UM.utils.bind(fn,context) => fn
  276. */
  277. bind:function (fn, context) {
  278. return function () {
  279. return fn.apply(context, arguments);
  280. };
  281. },
  282. /**
  283. * 创建延迟delay执行的函数fn
  284. * @name defer
  285. * @grammar UM.utils.defer(fn,delay) =>fn //延迟delay毫秒执行fn,返回fn
  286. * @grammar UM.utils.defer(fn,delay,exclusion) =>fn //延迟delay毫秒执行fn,若exclusion为真,则互斥执行fn
  287. * @example
  288. * function test(){
  289. * console.log("延迟输出!");
  290. * }
  291. * //非互斥延迟执行
  292. * var testDefer = UM.utils.defer(test,1000);
  293. * testDefer(); => "延迟输出!";
  294. * testDefer(); => "延迟输出!";
  295. * //互斥延迟执行
  296. * var testDefer1 = UM.utils.defer(test,1000,true);
  297. * testDefer1(); => //本次不执行
  298. * testDefer1(); => "延迟输出!";
  299. */
  300. defer:function (fn, delay, exclusion) {
  301. var timerID;
  302. return function () {
  303. if (exclusion) {
  304. clearTimeout(timerID);
  305. }
  306. timerID = setTimeout(fn, delay);
  307. };
  308. },
  309. /**
  310. * 查找元素item在数组array中的索引, 若找不到返回-1
  311. * @name indexOf
  312. * @grammar UM.utils.indexOf(array,item) => index|-1 //默认从数组开头部开始搜索
  313. * @grammar UM.utils.indexOf(array,item,start) => index|-1 //start指定开始查找的位置
  314. */
  315. indexOf:function (array, item, start) {
  316. var index = -1;
  317. start = this.isNumber(start) ? start : 0;
  318. this.each(array, function (v, i) {
  319. if (i >= start && v === item) {
  320. index = i;
  321. return false;
  322. }
  323. });
  324. return index;
  325. },
  326. /**
  327. * 移除数组array中的元素item
  328. * @name removeItem
  329. * @grammar UM.utils.removeItem(array,item)
  330. */
  331. removeItem:function (array, item) {
  332. for (var i = 0, l = array.length; i < l; i++) {
  333. if (array[i] === item) {
  334. array.splice(i, 1);
  335. i--;
  336. }
  337. }
  338. },
  339. /**
  340. * 删除字符串str的首尾空格
  341. * @name trim
  342. * @grammar UM.utils.trim(str) => String
  343. */
  344. trim:function (str) {
  345. return str.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, '');
  346. },
  347. /**
  348. * 将字符串list(以','分隔)或者数组list转成哈希对象
  349. * @name listToMap
  350. * @grammar UM.utils.listToMap(list) => Object //Object形如{test:1,br:1,textarea:1}
  351. */
  352. listToMap:function (list) {
  353. if (!list)return {};
  354. list = utils.isArray(list) ? list : list.split(',');
  355. for (var i = 0, ci, obj = {}; ci = list[i++];) {
  356. obj[ci.toUpperCase()] = obj[ci] = 1;
  357. }
  358. return obj;
  359. },
  360. /**
  361. * 将str中的html符号转义,默认将转义''&<">''四个字符,可自定义reg来确定需要转义的字符
  362. * @name unhtml
  363. * @grammar UM.utils.unhtml(str); => String
  364. * @grammar UM.utils.unhtml(str,reg) => String
  365. * @example
  366. * var html = '<body>You say:"你好!Baidu & UEditor!"</body>';
  367. * UM.utils.unhtml(html); ==> &lt;body&gt;You say:&quot;你好!Baidu &amp; UEditor!&quot;&lt;/body&gt;
  368. * UM.utils.unhtml(html,/[<>]/g) ==> &lt;body&gt;You say:"你好!Baidu & UEditor!"&lt;/body&gt;
  369. */
  370. unhtml:function (str, reg) {
  371. return str ? str.replace(reg || /[&<">'](?:(amp|lt|quot|gt|#39|nbsp);)?/g, function (a, b) {
  372. if (b) {
  373. return a;
  374. } else {
  375. return {
  376. '<':'&lt;',
  377. '&':'&amp;',
  378. '"':'&quot;',
  379. '>':'&gt;',
  380. "'":'&#39;'
  381. }[a]
  382. }
  383. }) : '';
  384. },
  385. /**
  386. * 将str中的转义字符还原成html字符
  387. * @name html
  388. * @grammar UM.utils.html(str) => String //详细参见<code><a href = '#unhtml'>unhtml</a></code>
  389. */
  390. html:function (str) {
  391. return str ? str.replace(/&((g|l|quo)t|amp|#39);/g, function (m) {
  392. return {
  393. '&lt;':'<',
  394. '&amp;':'&',
  395. '&quot;':'"',
  396. '&gt;':'>',
  397. '&#39;':"'"
  398. }[m]
  399. }) : '';
  400. },
  401. /**
  402. * 将css样式转换为驼峰的形式。如font-size => fontSize
  403. * @name cssStyleToDomStyle
  404. * @grammar UM.utils.cssStyleToDomStyle(cssName) => String
  405. */
  406. cssStyleToDomStyle:function () {
  407. var test = document.createElement('div').style,
  408. cache = {
  409. 'float':test.cssFloat != undefined ? 'cssFloat' : test.styleFloat != undefined ? 'styleFloat' : 'float'
  410. };
  411. return function (cssName) {
  412. return cache[cssName] || (cache[cssName] = cssName.toLowerCase().replace(/-./g, function (match) {
  413. return match.charAt(1).toUpperCase();
  414. }));
  415. };
  416. }(),
  417. /**
  418. * 动态加载文件到doc中,并依据obj来设置属性,加载成功后执行回调函数fn
  419. * @name loadFile
  420. * @grammar UM.utils.loadFile(doc,obj)
  421. * @grammar UM.utils.loadFile(doc,obj,fn)
  422. * @example
  423. * //指定加载到当前document中一个script文件,加载成功后执行function
  424. * utils.loadFile( document, {
  425. * src:"test.js",
  426. * tag:"script",
  427. * type:"text/javascript",
  428. * defer:"defer"
  429. * }, function () {
  430. * console.log('加载成功!')
  431. * });
  432. */
  433. loadFile:function () {
  434. var tmpList = [];
  435. function getItem(doc, obj) {
  436. try {
  437. for (var i = 0, ci; ci = tmpList[i++];) {
  438. if (ci.doc === doc && ci.url == (obj.src || obj.href)) {
  439. return ci;
  440. }
  441. }
  442. } catch (e) {
  443. return null;
  444. }
  445. }
  446. return function (doc, obj, fn) {
  447. var item = getItem(doc, obj);
  448. if (item) {
  449. if (item.ready) {
  450. fn && fn();
  451. } else {
  452. item.funs.push(fn)
  453. }
  454. return;
  455. }
  456. tmpList.push({
  457. doc:doc,
  458. url:obj.src || obj.href,
  459. funs:[fn]
  460. });
  461. if (!doc.body) {
  462. var html = [];
  463. for (var p in obj) {
  464. if (p == 'tag')continue;
  465. html.push(p + '="' + obj[p] + '"')
  466. }
  467. doc.write('<' + obj.tag + ' ' + html.join(' ') + ' ></' + obj.tag + '>');
  468. return;
  469. }
  470. if (obj.id && doc.getElementById(obj.id)) {
  471. return;
  472. }
  473. var element = doc.createElement(obj.tag);
  474. delete obj.tag;
  475. for (var p in obj) {
  476. element.setAttribute(p, obj[p]);
  477. }
  478. element.onload = element.onreadystatechange = function () {
  479. if (!this.readyState || /loaded|complete/.test(this.readyState)) {
  480. item = getItem(doc, obj);
  481. if (item.funs.length > 0) {
  482. item.ready = 1;
  483. for (var fi; fi = item.funs.pop();) {
  484. fi();
  485. }
  486. }
  487. element.onload = element.onreadystatechange = null;
  488. }
  489. };
  490. element.onerror = function () {
  491. throw Error('The load ' + (obj.href || obj.src) + ' fails,check the url settings of file umeditor.config.js ')
  492. };
  493. doc.getElementsByTagName("head")[0].appendChild(element);
  494. }
  495. }(),
  496. /**
  497. * 判断obj对象是否为空
  498. * @name isEmptyObject
  499. * @grammar UM.utils.isEmptyObject(obj) => true|false
  500. * @example
  501. * UM.utils.isEmptyObject({}) ==>true
  502. * UM.utils.isEmptyObject([]) ==>true
  503. * UM.utils.isEmptyObject("") ==>true
  504. */
  505. isEmptyObject:function (obj) {
  506. if (obj == null) return true;
  507. if (this.isArray(obj) || this.isString(obj)) return obj.length === 0;
  508. for (var key in obj) if (obj.hasOwnProperty(key)) return false;
  509. return true;
  510. },
  511. /**
  512. * 统一将颜色值使用16进制形式表示
  513. * @name fixColor
  514. * @grammar UM.utils.fixColor(name,value) => value
  515. * @example
  516. * rgb(255,255,255) => "#ffffff"
  517. */
  518. fixColor:function (name, value) {
  519. if (/color/i.test(name) && /rgba?/.test(value)) {
  520. var array = value.split(",");
  521. if (array.length > 3)
  522. return "";
  523. value = "#";
  524. for (var i = 0, color; color = array[i++];) {
  525. color = parseInt(color.replace(/[^\d]/gi, ''), 10).toString(16);
  526. value += color.length == 1 ? "0" + color : color;
  527. }
  528. value = value.toUpperCase();
  529. }
  530. return value;
  531. },
  532. /**
  533. * 深度克隆对象,从source到target
  534. * @name clone
  535. * @grammar UM.utils.clone(source) => anthorObj 新的对象是完整的source的副本
  536. * @grammar UM.utils.clone(source,target) => target包含了source的所有内容,重名会覆盖
  537. */
  538. clone:function (source, target) {
  539. var tmp;
  540. target = target || {};
  541. for (var i in source) {
  542. if (source.hasOwnProperty(i)) {
  543. tmp = source[i];
  544. if (typeof tmp == 'object') {
  545. target[i] = utils.isArray(tmp) ? [] : {};
  546. utils.clone(source[i], target[i])
  547. } else {
  548. target[i] = tmp;
  549. }
  550. }
  551. }
  552. return target;
  553. },
  554. /**
  555. * 转换cm/pt到px
  556. * @name transUnitToPx
  557. * @grammar UM.utils.transUnitToPx('20pt') => '27px'
  558. * @grammar UM.utils.transUnitToPx('0pt') => '0'
  559. */
  560. transUnitToPx:function (val) {
  561. if (!/(pt|cm)/.test(val)) {
  562. return val
  563. }
  564. var unit;
  565. val.replace(/([\d.]+)(\w+)/, function (str, v, u) {
  566. val = v;
  567. unit = u;
  568. });
  569. switch (unit) {
  570. case 'cm':
  571. val = parseFloat(val) * 25;
  572. break;
  573. case 'pt':
  574. val = Math.round(parseFloat(val) * 96 / 72);
  575. }
  576. return val + (val ? 'px' : '');
  577. },
  578. /**
  579. * DomReady方法,回调函数将在dom树ready完成后执行
  580. * @name domReady
  581. * @grammar UM.utils.domReady(fn) => fn //返回一个延迟执行的方法
  582. */
  583. domReady:function () {
  584. var fnArr = [];
  585. function doReady(doc) {
  586. //确保onready只执行一次
  587. doc.isReady = true;
  588. for (var ci; ci = fnArr.pop(); ci()) {
  589. }
  590. }
  591. return function (onready, win) {
  592. win = win || window;
  593. var doc = win.document;
  594. onready && fnArr.push(onready);
  595. if (doc.readyState === "complete") {
  596. doReady(doc);
  597. } else {
  598. doc.isReady && doReady(doc);
  599. if (browser.ie) {
  600. (function () {
  601. if (doc.isReady) return;
  602. try {
  603. doc.documentElement.doScroll("left");
  604. } catch (error) {
  605. setTimeout(arguments.callee, 0);
  606. return;
  607. }
  608. doReady(doc);
  609. })();
  610. win.attachEvent('onload', function () {
  611. doReady(doc)
  612. });
  613. } else {
  614. doc.addEventListener("DOMContentLoaded", function () {
  615. doc.removeEventListener("DOMContentLoaded", arguments.callee, false);
  616. doReady(doc);
  617. }, false);
  618. win.addEventListener('load', function () {
  619. doReady(doc)
  620. }, false);
  621. }
  622. }
  623. }
  624. }(),
  625. /**
  626. * 动态添加css样式
  627. * @name cssRule
  628. * @grammar UM.utils.cssRule('添加的样式的节点名称',['样式','放到哪个document上'])
  629. * @grammar UM.utils.cssRule('body','body{background:#ccc}') => null //给body添加背景颜色
  630. * @grammar UM.utils.cssRule('body') =>样式的字符串 //取得key值为body的样式的内容,如果没有找到key值先关的样式将返回空,例如刚才那个背景颜色,将返回 body{background:#ccc}
  631. * @grammar UM.utils.cssRule('body','') =>null //清空给定的key值的背景颜色
  632. */
  633. cssRule:browser.ie ? function (key, style, doc) {
  634. var indexList, index;
  635. doc = doc || document;
  636. if (doc.indexList) {
  637. indexList = doc.indexList;
  638. } else {
  639. indexList = doc.indexList = {};
  640. }
  641. var sheetStyle;
  642. if (!indexList[key]) {
  643. if (style === undefined) {
  644. return ''
  645. }
  646. sheetStyle = doc.createStyleSheet('', index = doc.styleSheets.length);
  647. indexList[key] = index;
  648. } else {
  649. sheetStyle = doc.styleSheets[indexList[key]];
  650. }
  651. if (style === undefined) {
  652. return sheetStyle.cssText
  653. }
  654. sheetStyle.cssText = style || ''
  655. } : function (key, style, doc) {
  656. doc = doc || document;
  657. var head = doc.getElementsByTagName('head')[0], node;
  658. if (!(node = doc.getElementById(key))) {
  659. if (style === undefined) {
  660. return ''
  661. }
  662. node = doc.createElement('style');
  663. node.id = key;
  664. head.appendChild(node)
  665. }
  666. if (style === undefined) {
  667. return node.innerHTML
  668. }
  669. if (style !== '') {
  670. node.innerHTML = style;
  671. } else {
  672. head.removeChild(node)
  673. }
  674. }
  675. };
  676. /**
  677. * 判断str是否为字符串
  678. * @name isString
  679. * @grammar UM.utils.isString(str) => true|false
  680. */
  681. /**
  682. * 判断array是否为数组
  683. * @name isArray
  684. * @grammar UM.utils.isArray(obj) => true|false
  685. */
  686. /**
  687. * 判断obj对象是否为方法
  688. * @name isFunction
  689. * @grammar UM.utils.isFunction(obj) => true|false
  690. */
  691. /**
  692. * 判断obj对象是否为数字
  693. * @name isNumber
  694. * @grammar UM.utils.isNumber(obj) => true|false
  695. */
  696. utils.each(['String', 'Function', 'Array', 'Number', 'RegExp', 'Object'], function (v) {
  697. UM.utils['is' + v] = function (obj) {
  698. return Object.prototype.toString.apply(obj) == '[object ' + v + ']';
  699. }
  700. });
  701. /**
  702. * @file
  703. * @name UM.EventBase
  704. * @short EventBase
  705. * @import editor.js,core/utils.js
  706. * @desc UE采用的事件基类,继承此类的对应类将获取addListener,removeListener,fireEvent方法。
  707. * 在UE中,Editor以及所有ui实例都继承了该类,故可以在对应的ui对象以及editor对象上使用上述方法。
  708. */
  709. var EventBase = UM.EventBase = function () {};
  710. EventBase.prototype = {
  711. /**
  712. * 注册事件监听器
  713. * @name addListener
  714. * @grammar editor.addListener(types,fn) //types为事件名称,多个可用空格分隔
  715. * @example
  716. * editor.addListener('selectionchange',function(){
  717. * console.log("选区已经变化!");
  718. * })
  719. * editor.addListener('beforegetcontent aftergetcontent',function(type){
  720. * if(type == 'beforegetcontent'){
  721. * //do something
  722. * }else{
  723. * //do something
  724. * }
  725. * console.log(this.getContent) // this是注册的事件的编辑器实例
  726. * })
  727. */
  728. addListener:function (types, listener) {
  729. types = utils.trim(types).split(' ');
  730. for (var i = 0, ti; ti = types[i++];) {
  731. getListener(this, ti, true).push(listener);
  732. }
  733. },
  734. /**
  735. * 移除事件监听器
  736. * @name removeListener
  737. * @grammar editor.removeListener(types,fn) //types为事件名称,多个可用空格分隔
  738. * @example
  739. * //changeCallback为方法体
  740. * editor.removeListener("selectionchange",changeCallback);
  741. */
  742. removeListener:function (types, listener) {
  743. types = utils.trim(types).split(' ');
  744. for (var i = 0, ti; ti = types[i++];) {
  745. utils.removeItem(getListener(this, ti) || [], listener);
  746. }
  747. },
  748. /**
  749. * 触发事件
  750. * @name fireEvent
  751. * @grammar editor.fireEvent(types) //types为事件名称,多个可用空格分隔
  752. * @example
  753. * editor.fireEvent("selectionchange");
  754. */
  755. fireEvent:function () {
  756. var types = arguments[0];
  757. types = utils.trim(types).split(' ');
  758. for (var i = 0, ti; ti = types[i++];) {
  759. var listeners = getListener(this, ti),
  760. r, t, k;
  761. if (listeners) {
  762. k = listeners.length;
  763. while (k--) {
  764. if(!listeners[k])continue;
  765. t = listeners[k].apply(this, arguments);
  766. if(t === true){
  767. return t;
  768. }
  769. if (t !== undefined) {
  770. r = t;
  771. }
  772. }
  773. }
  774. if (t = this['on' + ti.toLowerCase()]) {
  775. r = t.apply(this, arguments);
  776. }
  777. }
  778. return r;
  779. }
  780. };
  781. /**
  782. * 获得对象所拥有监听类型的所有监听器
  783. * @public
  784. * @function
  785. * @param {Object} obj 查询监听器的对象
  786. * @param {String} type 事件类型
  787. * @param {Boolean} force 为true且当前所有type类型的侦听器不存在时,创建一个空监听器数组
  788. * @returns {Array} 监听器数组
  789. */
  790. function getListener(obj, type, force) {
  791. var allListeners;
  792. type = type.toLowerCase();
  793. return ( ( allListeners = ( obj.__allListeners || force && ( obj.__allListeners = {} ) ) )
  794. && ( allListeners[type] || force && ( allListeners[type] = [] ) ) );
  795. }
  796. ///import editor.js
  797. ///import core/dom/dom.js
  798. ///import core/utils.js
  799. /**
  800. * dtd html语义化的体现类
  801. * @constructor
  802. * @namespace dtd
  803. */
  804. var dtd = dom.dtd = (function() {
  805. function _( s ) {
  806. for (var k in s) {
  807. s[k.toUpperCase()] = s[k];
  808. }
  809. return s;
  810. }
  811. var X = utils.extend2;
  812. var A = _({isindex:1,fieldset:1}),
  813. B = _({input:1,button:1,select:1,textarea:1,label:1}),
  814. C = X( _({a:1}), B ),
  815. D = X( {iframe:1}, C ),
  816. E = _({hr:1,ul:1,menu:1,div:1,blockquote:1,noscript:1,table:1,center:1,address:1,dir:1,pre:1,h5:1,dl:1,h4:1,noframes:1,h6:1,ol:1,h1:1,h3:1,h2:1}),
  817. F = _({ins:1,del:1,script:1,style:1}),
  818. G = X( _({b:1,acronym:1,bdo:1,'var':1,'#':1,abbr:1,code:1,br:1,i:1,cite:1,kbd:1,u:1,strike:1,s:1,tt:1,strong:1,q:1,samp:1,em:1,dfn:1,span:1}), F ),
  819. H = X( _({sub:1,img:1,embed:1,object:1,sup:1,basefont:1,map:1,applet:1,font:1,big:1,small:1}), G ),
  820. I = X( _({p:1}), H ),
  821. J = X( _({iframe:1}), H, B ),
  822. K = _({img:1,embed:1,noscript:1,br:1,kbd:1,center:1,button:1,basefont:1,h5:1,h4:1,samp:1,h6:1,ol:1,h1:1,h3:1,h2:1,form:1,font:1,'#':1,select:1,menu:1,ins:1,abbr:1,label:1,code:1,table:1,script:1,cite:1,input:1,iframe:1,strong:1,textarea:1,noframes:1,big:1,small:1,span:1,hr:1,sub:1,bdo:1,'var':1,div:1,object:1,sup:1,strike:1,dir:1,map:1,dl:1,applet:1,del:1,isindex:1,fieldset:1,ul:1,b:1,acronym:1,a:1,blockquote:1,i:1,u:1,s:1,tt:1,address:1,q:1,pre:1,p:1,em:1,dfn:1}),
  823. L = X( _({a:0}), J ),//a不能被切开,所以把他
  824. M = _({tr:1}),
  825. N = _({'#':1}),
  826. O = X( _({param:1}), K ),
  827. P = X( _({form:1}), A, D, E, I ),
  828. Q = _({li:1,ol:1,ul:1}),
  829. R = _({style:1,script:1}),
  830. S = _({base:1,link:1,meta:1,title:1}),
  831. T = X( S, R ),
  832. U = _({head:1,body:1}),
  833. V = _({html:1});
  834. var block = _({address:1,blockquote:1,center:1,dir:1,div:1,dl:1,fieldset:1,form:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,hr:1,isindex:1,menu:1,noframes:1,ol:1,p:1,pre:1,table:1,ul:1}),
  835. empty = _({area:1,base:1,basefont:1,br:1,col:1,command:1,dialog:1,embed:1,hr:1,img:1,input:1,isindex:1,keygen:1,link:1,meta:1,param:1,source:1,track:1,wbr:1});
  836. return _({
  837. // $ 表示自定的属性
  838. // body外的元素列表.
  839. $nonBodyContent: X( V, U, S ),
  840. //块结构元素列表
  841. $block : block,
  842. //内联元素列表
  843. $inline : L,
  844. $inlineWithA : X(_({a:1}),L),
  845. $body : X( _({script:1,style:1}), block ),
  846. $cdata : _({script:1,style:1}),
  847. //自闭和元素
  848. $empty : empty,
  849. //不是自闭合,但不能让range选中里边
  850. $nonChild : _({iframe:1,textarea:1}),
  851. //列表元素列表
  852. $listItem : _({dd:1,dt:1,li:1}),
  853. //列表根元素列表
  854. $list: _({ul:1,ol:1,dl:1}),
  855. //不能认为是空的元素
  856. $isNotEmpty : _({table:1,ul:1,ol:1,dl:1,iframe:1,area:1,base:1,col:1,hr:1,img:1,embed:1,input:1,link:1,meta:1,param:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1}),
  857. //如果没有子节点就可以删除的元素列表,像span,a
  858. $removeEmpty : _({a:1,abbr:1,acronym:1,address:1,b:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,q:1,s:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,'var':1}),
  859. $removeEmptyBlock : _({'p':1,'div':1}),
  860. //在table元素里的元素列表
  861. $tableContent : _({caption:1,col:1,colgroup:1,tbody:1,td:1,tfoot:1,th:1,thead:1,tr:1,table:1}),
  862. //不转换的标签
  863. $notTransContent : _({pre:1,script:1,style:1,textarea:1}),
  864. html: U,
  865. head: T,
  866. style: N,
  867. script: N,
  868. body: P,
  869. base: {},
  870. link: {},
  871. meta: {},
  872. title: N,
  873. col : {},
  874. tr : _({td:1,th:1}),
  875. img : {},
  876. embed: {},
  877. colgroup : _({thead:1,col:1,tbody:1,tr:1,tfoot:1}),
  878. noscript : P,
  879. td : P,
  880. br : {},
  881. th : P,
  882. center : P,
  883. kbd : L,
  884. button : X( I, E ),
  885. basefont : {},
  886. h5 : L,
  887. h4 : L,
  888. samp : L,
  889. h6 : L,
  890. ol : Q,
  891. h1 : L,
  892. h3 : L,
  893. option : N,
  894. h2 : L,
  895. form : X( A, D, E, I ),
  896. select : _({optgroup:1,option:1}),
  897. font : L,
  898. ins : L,
  899. menu : Q,
  900. abbr : L,
  901. label : L,
  902. table : _({thead:1,col:1,tbody:1,tr:1,colgroup:1,caption:1,tfoot:1}),
  903. code : L,
  904. tfoot : M,
  905. cite : L,
  906. li : P,
  907. input : {},
  908. iframe : P,
  909. strong : L,
  910. textarea : N,
  911. noframes : P,
  912. big : L,
  913. small : L,
  914. //trace:
  915. span :_({'#':1,br:1,b:1,strong:1,u:1,i:1,em:1,sub:1,sup:1,strike:1,span:1}),
  916. hr : L,
  917. dt : L,
  918. sub : L,
  919. optgroup : _({option:1}),
  920. param : {},
  921. bdo : L,
  922. 'var' : L,
  923. div : P,
  924. object : O,
  925. sup : L,
  926. dd : P,
  927. strike : L,
  928. area : {},
  929. dir : Q,
  930. map : X( _({area:1,form:1,p:1}), A, F, E ),
  931. applet : O,
  932. dl : _({dt:1,dd:1}),
  933. del : L,
  934. isindex : {},
  935. fieldset : X( _({legend:1}), K ),
  936. thead : M,
  937. ul : Q,
  938. acronym : L,
  939. b : L,
  940. a : X( _({a:1}), J ),
  941. blockquote :X(_({td:1,tr:1,tbody:1,li:1}),P),
  942. caption : L,
  943. i : L,
  944. u : L,
  945. tbody : M,
  946. s : L,
  947. address : X( D, I ),
  948. tt : L,
  949. legend : L,
  950. q : L,
  951. pre : X( G, C ),
  952. p : X(_({'a':1}),L),
  953. em :L,
  954. dfn : L
  955. });
  956. })();
  957. /**
  958. * @file
  959. * @name UM.dom.domUtils
  960. * @short DomUtils
  961. * @import editor.js, core/utils.js,core/browser.js,core/dom/dtd.js
  962. * @desc UEditor封装的底层dom操作库
  963. */
  964. var attrFix = ie && browser.version < 9 ? {
  965. tabindex: "tabIndex",
  966. readonly: "readOnly",
  967. "for": "htmlFor",
  968. "class": "className",
  969. maxlength: "maxLength",
  970. cellspacing: "cellSpacing",
  971. cellpadding: "cellPadding",
  972. rowspan: "rowSpan",
  973. colspan: "colSpan",
  974. usemap: "useMap",
  975. frameborder: "frameBorder"
  976. } : {
  977. tabindex: "tabIndex",
  978. readonly: "readOnly"
  979. },
  980. styleBlock = utils.listToMap([
  981. '-webkit-box', '-moz-box', 'block' ,
  982. 'list-item' , 'table' , 'table-row-group' ,
  983. 'table-header-group', 'table-footer-group' ,
  984. 'table-row' , 'table-column-group' , 'table-column' ,
  985. 'table-cell' , 'table-caption'
  986. ]);
  987. var domUtils = dom.domUtils = {
  988. //节点常量
  989. NODE_ELEMENT: 1,
  990. NODE_DOCUMENT: 9,
  991. NODE_TEXT: 3,
  992. NODE_COMMENT: 8,
  993. NODE_DOCUMENT_FRAGMENT: 11,
  994. //位置关系
  995. POSITION_IDENTICAL: 0,
  996. POSITION_DISCONNECTED: 1,
  997. POSITION_FOLLOWING: 2,
  998. POSITION_PRECEDING: 4,
  999. POSITION_IS_CONTAINED: 8,
  1000. POSITION_CONTAINS: 16,
  1001. //ie6使用其他的会有一段空白出现
  1002. fillChar: ie && browser.version == '6' ? '\ufeff' : '\u200B',
  1003. //-------------------------Node部分--------------------------------
  1004. keys: {
  1005. /*Backspace*/ 8: 1, /*Delete*/ 46: 1,
  1006. /*Shift*/ 16: 1, /*Ctrl*/ 17: 1, /*Alt*/ 18: 1,
  1007. 37: 1, 38: 1, 39: 1, 40: 1,
  1008. 13: 1 /*enter*/
  1009. },
  1010. breakParent:function (node, parent) {
  1011. var tmpNode,
  1012. parentClone = node,
  1013. clone = node,
  1014. leftNodes,
  1015. rightNodes;
  1016. do {
  1017. parentClone = parentClone.parentNode;
  1018. if (leftNodes) {
  1019. tmpNode = parentClone.cloneNode(false);
  1020. tmpNode.appendChild(leftNodes);
  1021. leftNodes = tmpNode;
  1022. tmpNode = parentClone.cloneNode(false);
  1023. tmpNode.appendChild(rightNodes);
  1024. rightNodes = tmpNode;
  1025. } else {
  1026. leftNodes = parentClone.cloneNode(false);
  1027. rightNodes = leftNodes.cloneNode(false);
  1028. }
  1029. while (tmpNode = clone.previousSibling) {
  1030. leftNodes.insertBefore(tmpNode, leftNodes.firstChild);
  1031. }
  1032. while (tmpNode = clone.nextSibling) {
  1033. rightNodes.appendChild(tmpNode);
  1034. }
  1035. clone = parentClone;
  1036. } while (parent !== parentClone);
  1037. tmpNode = parent.parentNode;
  1038. tmpNode.insertBefore(leftNodes, parent);
  1039. tmpNode.insertBefore(rightNodes, parent);
  1040. tmpNode.insertBefore(node, rightNodes);
  1041. domUtils.remove(parent);
  1042. return node;
  1043. },
  1044. trimWhiteTextNode:function (node) {
  1045. function remove(dir) {
  1046. var child;
  1047. while ((child = node[dir]) && child.nodeType == 3 && domUtils.isWhitespace(child)) {
  1048. node.removeChild(child);
  1049. }
  1050. }
  1051. remove('firstChild');
  1052. remove('lastChild');
  1053. },
  1054. /**
  1055. * 获取节点A相对于节点B的位置关系
  1056. * @name getPosition
  1057. * @grammar UM.dom.domUtils.getPosition(nodeA,nodeB) => Number
  1058. * @example
  1059. * switch (returnValue) {
  1060. * case 0: //相等,同一节点
  1061. * case 1: //无关,节点不相连
  1062. * case 2: //跟随,即节点A头部位于节点B头部的后面
  1063. * case 4: //前置,即节点A头部位于节点B头部的前面
  1064. * case 8: //被包含,即节点A被节点B包含
  1065. * case 10://组合类型,即节点A满足跟随节点B且被节点B包含。实际上,如果被包含,必定跟随,所以returnValue事实上不会存在8的情况。
  1066. * case 16://包含,即节点A包含节点B
  1067. * case 20://组合类型,即节点A满足前置节点A且包含节点B。同样,如果包含,必定前置,所以returnValue事实上也不会存在16的情况
  1068. * }
  1069. */
  1070. getPosition: function (nodeA, nodeB) {
  1071. // 如果两个节点是同一个节点
  1072. if (nodeA === nodeB) {
  1073. // domUtils.POSITION_IDENTICAL
  1074. return 0;
  1075. }
  1076. var node,
  1077. parentsA = [nodeA],
  1078. parentsB = [nodeB];
  1079. node = nodeA;
  1080. while (node = node.parentNode) {
  1081. // 如果nodeB是nodeA的祖先节点
  1082. if (node === nodeB) {
  1083. // domUtils.POSITION_IS_CONTAINED + domUtils.POSITION_FOLLOWING
  1084. return 10;
  1085. }
  1086. parentsA.push(node);
  1087. }
  1088. node = nodeB;
  1089. while (node = node.parentNode) {
  1090. // 如果nodeA是nodeB的祖先节点
  1091. if (node === nodeA) {
  1092. // domUtils.POSITION_CONTAINS + domUtils.POSITION_PRECEDING
  1093. return 20;
  1094. }
  1095. parentsB.push(node);
  1096. }
  1097. parentsA.reverse();
  1098. parentsB.reverse();
  1099. if (parentsA[0] !== parentsB[0]) {
  1100. // domUtils.POSITION_DISCONNECTED
  1101. return 1;
  1102. }
  1103. var i = -1;
  1104. while (i++, parentsA[i] === parentsB[i]) {
  1105. }
  1106. nodeA = parentsA[i];
  1107. nodeB = parentsB[i];
  1108. while (nodeA = nodeA.nextSibling) {
  1109. if (nodeA === nodeB) {
  1110. // domUtils.POSITION_PRECEDING
  1111. return 4
  1112. }
  1113. }
  1114. // domUtils.POSITION_FOLLOWING
  1115. return 2;
  1116. },
  1117. /**
  1118. * 返回节点node在父节点中的索引位置
  1119. * @name getNodeIndex
  1120. * @grammar UM.dom.domUtils.getNodeIndex(node) => Number //索引值从0开始
  1121. */
  1122. getNodeIndex: function (node, ignoreTextNode) {
  1123. var preNode = node,
  1124. i = 0;
  1125. while (preNode = preNode.previousSibling) {
  1126. if (ignoreTextNode && preNode.nodeType == 3) {
  1127. if (preNode.nodeType != preNode.nextSibling.nodeType) {
  1128. i++;
  1129. }
  1130. continue;
  1131. }
  1132. i++;
  1133. }
  1134. return i;
  1135. },
  1136. /**
  1137. * 检测节点node是否在节点doc的树上,实质上是检测是否被doc包含
  1138. * @name inDoc
  1139. * @grammar UM.dom.domUtils.inDoc(node,doc) => true|false
  1140. */
  1141. inDoc: function (node, doc) {
  1142. return domUtils.getPosition(node, doc) == 10;
  1143. },
  1144. /**
  1145. * 查找node节点的祖先节点
  1146. * @name findParent
  1147. * @grammar UM.dom.domUtils.findParent(node) => Element // 直接返回node节点的父节点
  1148. * @grammar UM.dom.domUtils.findParent(node,filterFn) => Element //filterFn为过滤函数,node作为参数,返回true时才会将node作为符合要求的节点返回
  1149. * @grammar UM.dom.domUtils.findParent(node,filterFn,includeSelf) => Element //includeSelf指定是否包含自身
  1150. */
  1151. findParent: function (node, filterFn, includeSelf) {
  1152. if (node && !domUtils.isBody(node)) {
  1153. node = includeSelf ? node : node.parentNode;
  1154. while (node) {
  1155. if (!filterFn || filterFn(node) || domUtils.isBody(node)) {
  1156. return filterFn && !filterFn(node) && domUtils.isBody(node) ? null : node;
  1157. }
  1158. node = node.parentNode;
  1159. }
  1160. }
  1161. return null;
  1162. },
  1163. /**
  1164. * 通过tagName查找node节点的祖先节点
  1165. * @name findParentByTagName
  1166. * @grammar UM.dom.domUtils.findParentByTagName(node,tagNames) => Element //tagNames支持数组,区分大小写
  1167. * @grammar UM.dom.domUtils.findParentByTagName(node,tagNames,includeSelf) => Element //includeSelf指定是否包含自身
  1168. * @grammar UM.dom.domUtils.findParentByTagName(node,tagNames,includeSelf,excludeFn) => Element //excludeFn指定例外过滤条件,返回true时忽略该节点
  1169. */
  1170. findParentByTagName: function (node, tagNames, includeSelf, excludeFn) {
  1171. tagNames = utils.listToMap(utils.isArray(tagNames) ? tagNames : [tagNames]);
  1172. return domUtils.findParent(node, function (node) {
  1173. return tagNames[node.tagName] && !(excludeFn && excludeFn(node));
  1174. }, includeSelf);
  1175. },
  1176. /**
  1177. * 查找节点node的祖先节点集合
  1178. * @name findParents
  1179. * @grammar UM.dom.domUtils.findParents(node) => Array //返回一个祖先节点数组集合,不包含自身
  1180. * @grammar UM.dom.domUtils.findParents(node,includeSelf) => Array //返回一个祖先节点数组集合,includeSelf指定是否包含自身
  1181. * @grammar UM.dom.domUtils.findParents(node,includeSelf,filterFn) => Array //返回一个祖先节点数组集合,filterFn指定过滤条件,返回true的node将被选取
  1182. * @grammar UM.dom.domUtils.findParents(node,includeSelf,filterFn,closerFirst) => Array //返回一个祖先节点数组集合,closerFirst为true的话,node的直接父亲节点是数组的第0个
  1183. */
  1184. findParents: function (node, includeSelf, filterFn, closerFirst) {
  1185. var parents = includeSelf && ( filterFn && filterFn(node) || !filterFn ) ? [node] : [];
  1186. while (node = domUtils.findParent(node, filterFn)) {
  1187. parents.push(node);
  1188. }
  1189. return closerFirst ? parents : parents.reverse();
  1190. },
  1191. /**
  1192. * 在节点node后面插入新节点newNode
  1193. * @name insertAfter
  1194. * @grammar UM.dom.domUtils.insertAfter(node,newNode) => newNode
  1195. */
  1196. insertAfter: function (node, newNode) {
  1197. return node.parentNode.insertBefore(newNode, node.nextSibling);
  1198. },
  1199. /**
  1200. * 删除节点node,并根据keepChildren指定是否保留子节点
  1201. * @name remove
  1202. * @grammar UM.dom.domUtils.remove(node) => node
  1203. * @grammar UM.dom.domUtils.remove(node,keepChildren) => node
  1204. */
  1205. remove: function (node, keepChildren) {
  1206. var parent = node.parentNode,
  1207. child;
  1208. if (parent) {
  1209. if (keepChildren && node.hasChildNodes()) {
  1210. while (child = node.firstChild) {
  1211. parent.insertBefore(child, node);
  1212. }
  1213. }
  1214. parent.removeChild(node);
  1215. }
  1216. return node;
  1217. },
  1218. /**
  1219. * 检测节点node是否属于bookmark节点
  1220. * @name isBookmarkNode
  1221. * @grammar UM.dom.domUtils.isBookmarkNode(node) => true|false
  1222. */
  1223. isBookmarkNode: function (node) {
  1224. return node.nodeType == 1 && node.id && /^_baidu_bookmark_/i.test(node.id);
  1225. },
  1226. /**
  1227. * 获取节点node所在的window对象
  1228. * @name getWindow
  1229. * @grammar UM.dom.domUtils.getWindow(node) => window对象
  1230. */
  1231. getWindow: function (node) {
  1232. var doc = node.ownerDocument || node;
  1233. return doc.defaultView || doc.parentWindow;
  1234. },
  1235. /**
  1236. * 将一个文本节点node拆分成两个文本节点,offset指定拆分位置
  1237. * @name split
  1238. * @grammar UM.dom.domUtils.split(node,offset) => TextNode //返回从切分位置开始的后一个文本节点
  1239. */
  1240. split: function (node, offset) {
  1241. var doc = node.ownerDocument;
  1242. if (browser.ie && offset == node.nodeValue.length) {
  1243. var next = doc.createTextNode('');
  1244. return domUtils.insertAfter(node, next);
  1245. }
  1246. var retval = node.splitText(offset);
  1247. //ie8下splitText不会跟新childNodes,我们手动触发他的更新
  1248. if (browser.ie8) {
  1249. var tmpNode = doc.createTextNode('');
  1250. domUtils.insertAfter(retval, tmpNode);
  1251. domUtils.remove(tmpNode);
  1252. }
  1253. return retval;
  1254. },
  1255. /**
  1256. * 检测节点node是否为空节点(包括空格、换行、占位符等字符)
  1257. * @name isWhitespace
  1258. * @grammar UM.dom.domUtils.isWhitespace(node) => true|false
  1259. */
  1260. isWhitespace: function (node) {
  1261. return !new RegExp('[^ \t\n\r' + domUtils.fillChar + ']').test(node.nodeValue);
  1262. },
  1263. /**
  1264. * 获取元素element相对于viewport的位置坐标
  1265. * @name getXY
  1266. * @grammar UM.dom.domUtils.getXY(element) => Object //返回坐标对象{x:left,y:top}
  1267. */
  1268. getXY: function (element) {
  1269. var x = 0, y = 0;
  1270. while (element.offsetParent) {
  1271. y += element.offsetTop;
  1272. x += element.offsetLeft;
  1273. element = element.offsetParent;
  1274. }
  1275. return { 'x': x, 'y': y};
  1276. },
  1277. /**
  1278. * 为元素element绑定原生DOM事件,type为事件类型,handler为处理函数
  1279. * @name on
  1280. * @grammar UM.dom.domUtils.on(element,type,handler) //type支持数组传入
  1281. * @example
  1282. * UM.dom.domUtils.on(document.body,"click",function(e){
  1283. * //e为事件对象,this为被点击元素对戏那个
  1284. * })
  1285. * @example
  1286. * UM.dom.domUtils.on(document.body,["click","mousedown"],function(evt){
  1287. * //evt为事件对象,this为被点击元素对象
  1288. * })
  1289. */
  1290. on: function (element, type, handler) {
  1291. var types = utils.isArray(type) ? type : [type],
  1292. k = types.length;
  1293. if (k) while (k--) {
  1294. type = types[k];
  1295. if (element.addEventListener) {
  1296. element.addEventListener(type, handler, false);
  1297. } else {
  1298. if (!handler._d) {
  1299. handler._d = {
  1300. els: []
  1301. };
  1302. }
  1303. var key = type + handler.toString(), index = utils.indexOf(handler._d.els, element);
  1304. if (!handler._d[key] || index == -1) {
  1305. if (index == -1) {
  1306. handler._d.els.push(element);
  1307. }
  1308. if (!handler._d[key]) {
  1309. handler._d[key] = function (evt) {
  1310. return handler.call(evt.srcElement, evt || window.event);
  1311. };
  1312. }
  1313. element.attachEvent('on' + type, handler._d[key]);
  1314. }
  1315. }
  1316. }
  1317. element = null;
  1318. },
  1319. /**
  1320. * 解除原生DOM事件绑定
  1321. * @name un
  1322. * @grammar UM.dom.donUtils.un(element,type,handler) //参见<code><a href="#on">on</a></code>
  1323. */
  1324. un: function (element, type, handler) {
  1325. var types = utils.isArray(type) ? type : [type],
  1326. k = types.length;
  1327. if (k) while (k--) {
  1328. type = types[k];
  1329. if (element.removeEventListener) {
  1330. element.removeEventListener(type, handler, false);
  1331. } else {
  1332. var key = type + handler.toString();
  1333. try {
  1334. element.detachEvent('on' + type, handler._d ? handler._d[key] : handler);
  1335. } catch (e) {
  1336. }
  1337. if (handler._d && handler._d[key]) {
  1338. var index = utils.indexOf(handler._d.els, element);
  1339. if (index != -1) {
  1340. handler._d.els.splice(index, 1);
  1341. }
  1342. handler._d.els.length == 0 && delete handler._d[key];
  1343. }
  1344. }
  1345. }
  1346. },
  1347. /**
  1348. * 检查节点node是否是空inline节点
  1349. * @name isEmptyInlineElement
  1350. * @grammar UM.dom.domUtils.isEmptyInlineElement(node) => 1|0
  1351. * @example
  1352. * <b><i></i></b> => 1
  1353. * <b><i></i><u></u></b> => 1
  1354. * <b></b> => 1
  1355. * <b>xx<i></i></b> => 0
  1356. */
  1357. isEmptyInlineElement: function (node) {
  1358. if (node.nodeType != 1 || !dtd.$removeEmpty[ node.tagName ]) {
  1359. return 0;
  1360. }
  1361. node = node.firstChild;
  1362. while (node) {
  1363. //如果是创建的bookmark就跳过
  1364. if (domUtils.isBookmarkNode(node)) {
  1365. return 0;
  1366. }
  1367. if (node.nodeType == 1 && !domUtils.isEmptyInlineElement(node) ||
  1368. node.nodeType == 3 && !domUtils.isWhitespace(node)
  1369. ) {
  1370. return 0;
  1371. }
  1372. node = node.nextSibling;
  1373. }
  1374. return 1;
  1375. },
  1376. /**
  1377. * 检查节点node是否为块元素
  1378. * @name isBlockElm
  1379. * @grammar UM.dom.domUtils.isBlockElm(node) => true|false
  1380. */
  1381. isBlockElm: function (node) {
  1382. return node.nodeType == 1 && (dtd.$block[node.tagName] || styleBlock[domUtils.getComputedStyle(node, 'display')]) && !dtd.$nonChild[node.tagName];
  1383. },
  1384. /**
  1385. * 原生方法getElementsByTagName的封装
  1386. * @name getElementsByTagName
  1387. * @grammar UM.dom.domUtils.getElementsByTagName(node,tagName) => Array //节点集合数组
  1388. */
  1389. getElementsByTagName: function (node, name, filter) {
  1390. if (filter && utils.isString(filter)) {
  1391. var className = filter;
  1392. filter = function (node) {
  1393. var result = false;
  1394. $.each(utils.trim(className).replace(/[ ]{2,}/g, ' ').split(' '), function (i, v) {
  1395. if ($(node).hasClass(v)) {
  1396. result = true;
  1397. return false;
  1398. }
  1399. })
  1400. return result;
  1401. }
  1402. }
  1403. name = utils.trim(name).replace(/[ ]{2,}/g, ' ').split(' ');
  1404. var arr = [];
  1405. for (var n = 0, ni; ni = name[n++];) {
  1406. var list = node.getElementsByTagName(ni);
  1407. for (var i = 0, ci; ci = list[i++];) {
  1408. if (!filter || filter(ci))
  1409. arr.push(ci);
  1410. }
  1411. }
  1412. return arr;
  1413. },
  1414. /**
  1415. * 设置节点node及其子…

Large files files are truncated, but you can click here to view the full file