edit.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. function _iframeDoc(iframe) {
  2. iframe = _get(iframe);
  3. return iframe.contentDocument || iframe.contentWindow.document;
  4. }
  5. var html, _direction = '';
  6. if ((html = document.getElementsByTagName('html'))) {
  7. _direction = html[0].dir;
  8. }
  9. function _getInitHtml(themesPath, bodyClass, cssPath, cssData) {
  10. var arr = [
  11. (_direction === '' ? '<html>' : '<html dir="' + _direction + '">'),
  12. '<head><meta charset="utf-8" /><title></title>',
  13. '<style>',
  14. 'html {margin:0;padding:0;}',
  15. 'body {margin:0;padding:5px;}',
  16. 'body, td {font:12px/1.5 "sans serif",tahoma,verdana,helvetica;}',
  17. 'body, p, div {word-wrap: break-word;}',
  18. 'p {margin:5px 0;}',
  19. 'table {border-collapse:collapse;}',
  20. 'img {border:0;}',
  21. 'noscript {display:none;}',
  22. 'table.ke-zeroborder td {border:1px dotted #AAA;}',
  23. 'img.ke-flash {',
  24. ' border:1px solid #AAA;',
  25. ' background-image:url(' + themesPath + 'common/flash.gif);',
  26. ' background-position:center center;',
  27. ' background-repeat:no-repeat;',
  28. ' width:100px;',
  29. ' height:100px;',
  30. '}',
  31. 'img.ke-rm {',
  32. ' border:1px solid #AAA;',
  33. ' background-image:url(' + themesPath + 'common/rm.gif);',
  34. ' background-position:center center;',
  35. ' background-repeat:no-repeat;',
  36. ' width:100px;',
  37. ' height:100px;',
  38. '}',
  39. 'img.ke-media {',
  40. ' border:1px solid #AAA;',
  41. ' background-image:url(' + themesPath + 'common/media.gif);',
  42. ' background-position:center center;',
  43. ' background-repeat:no-repeat;',
  44. ' width:100px;',
  45. ' height:100px;',
  46. '}',
  47. 'img.ke-anchor {',
  48. ' border:1px dashed #666;',
  49. ' width:16px;',
  50. ' height:16px;',
  51. '}',
  52. '.ke-script, .ke-noscript, .ke-display-none {',
  53. ' display:none;',
  54. ' font-size:0;',
  55. ' width:0;',
  56. ' height:0;',
  57. '}',
  58. '.ke-pagebreak {',
  59. ' border:1px dotted #AAA;',
  60. ' font-size:0;',
  61. ' height:2px;',
  62. '}',
  63. '</style>'
  64. ];
  65. if (!_isArray(cssPath)) {
  66. cssPath = [cssPath];
  67. }
  68. _each(cssPath, function(i, path) {
  69. if (path) {
  70. arr.push('<link href="' + path + '" rel="stylesheet" />');
  71. }
  72. });
  73. if (cssData) {
  74. arr.push('<style>' + cssData + '</style>');
  75. }
  76. arr.push('</head><body ' + (bodyClass ? 'class="' + bodyClass + '"' : '') + '></body></html>');
  77. return arr.join('\n');
  78. }
  79. function _elementVal(knode, val) {
  80. if (knode.hasVal()) {
  81. if (val === undefined) {
  82. var html = knode.val();
  83. // 去除内容为空的p标签
  84. // https://github.com/kindsoft/kindeditor/pull/52
  85. html = html.replace(/(<(?:p|p\s[^>]*)>) *(<\/p>)/ig, '');
  86. return html;
  87. }
  88. return knode.val(val);
  89. }
  90. return knode.html(val);
  91. }
  92. // create KEdit class
  93. function KEdit(options) {
  94. this.init(options);
  95. }
  96. _extend(KEdit, KWidget, {
  97. init : function(options) {
  98. var self = this;
  99. KEdit.parent.init.call(self, options);
  100. self.srcElement = K(options.srcElement);
  101. self.div.addClass('ke-edit');
  102. self.designMode = _undef(options.designMode, true);
  103. self.beforeGetHtml = options.beforeGetHtml;
  104. self.beforeSetHtml = options.beforeSetHtml;
  105. self.afterSetHtml = options.afterSetHtml;
  106. var themesPath = _undef(options.themesPath, ''),
  107. bodyClass = options.bodyClass,
  108. cssPath = options.cssPath,
  109. cssData = options.cssData,
  110. isDocumentDomain = location.protocol != 'res:' && location.host.replace(/:\d+/, '') !== document.domain,
  111. srcScript = ('document.open();' +
  112. (isDocumentDomain ? 'document.domain="' + document.domain + '";' : '') +
  113. 'document.close();'),
  114. iframeSrc = _IE ? ' src="javascript:void(function(){' + encodeURIComponent(srcScript) + '}())"' : '';
  115. self.iframe = K('<iframe class="ke-edit-iframe" hidefocus="true" frameborder="0"' + iframeSrc + '></iframe>').css('width', '100%');
  116. self.textarea = K('<textarea class="ke-edit-textarea" hidefocus="true"></textarea>').css('width', '100%');
  117. self.tabIndex = isNaN(parseInt(options.tabIndex, 10)) ? self.srcElement.attr('tabindex') : parseInt(options.tabIndex, 10);
  118. self.iframe.attr('tabindex', self.tabIndex);
  119. self.textarea.attr('tabindex', self.tabIndex);
  120. if (self.width) {
  121. self.setWidth(self.width);
  122. }
  123. if (self.height) {
  124. self.setHeight(self.height);
  125. }
  126. if (self.designMode) {
  127. self.textarea.hide();
  128. } else {
  129. self.iframe.hide();
  130. }
  131. function ready() {
  132. var doc = _iframeDoc(self.iframe);
  133. doc.open();
  134. if (isDocumentDomain) {
  135. doc.domain = document.domain;
  136. }
  137. doc.write(_getInitHtml(themesPath, bodyClass, cssPath, cssData));
  138. doc.close();
  139. self.win = self.iframe[0].contentWindow;
  140. self.doc = doc;
  141. var cmd = _cmd(doc);
  142. // add events
  143. self.afterChange(function(e) {
  144. cmd.selection();
  145. });
  146. // [WEBKIT] select an image after click the image
  147. if (_WEBKIT) {
  148. K(doc).click(function(e) {
  149. if (K(e.target).name === 'img') {
  150. cmd.selection(true);
  151. cmd.range.selectNode(e.target);
  152. cmd.select();
  153. }
  154. });
  155. }
  156. if (_IE) {
  157. // Fix bug: https://github.com/kindsoft/kindeditor/issues/53
  158. self._mousedownHandler = function() {
  159. var newRange = cmd.range.cloneRange();
  160. newRange.shrink();
  161. if (newRange.isControl()) {
  162. self.blur();
  163. }
  164. };
  165. K(document).mousedown(self._mousedownHandler);
  166. // [IE] bug: clear iframe when press backspase key
  167. K(doc).keydown(function(e) {
  168. if (e.which == 8) {
  169. cmd.selection();
  170. var rng = cmd.range;
  171. if (rng.isControl()) {
  172. rng.collapse(true);
  173. K(rng.startContainer.childNodes[rng.startOffset]).remove();
  174. e.preventDefault();
  175. }
  176. }
  177. });
  178. }
  179. self.cmd = cmd;
  180. self.html(_elementVal(self.srcElement));
  181. if (_IE) {
  182. doc.body.disabled = true;
  183. doc.body.contentEditable = true;
  184. doc.body.removeAttribute('disabled');
  185. } else {
  186. doc.designMode = 'on';
  187. }
  188. if (options.afterCreate) {
  189. options.afterCreate.call(self);
  190. }
  191. }
  192. if (isDocumentDomain) {
  193. self.iframe.bind('load', function(e) {
  194. self.iframe.unbind('load');
  195. if (_IE) {
  196. ready();
  197. } else {
  198. setTimeout(ready, 0);
  199. }
  200. });
  201. }
  202. self.div.append(self.iframe);
  203. self.div.append(self.textarea);
  204. self.srcElement.hide();
  205. !isDocumentDomain && ready();
  206. },
  207. setWidth : function(val) {
  208. var self = this;
  209. val = _addUnit(val);
  210. self.width = val;
  211. self.div.css('width', val);
  212. return self;
  213. },
  214. setHeight : function(val) {
  215. var self = this;
  216. val = _addUnit(val);
  217. self.height = val;
  218. self.div.css('height', val);
  219. self.iframe.css('height', val);
  220. // 校正IE6和IE7的textarea高度
  221. if ((_IE && _V < 8) || _QUIRKS) {
  222. val = _addUnit(_removeUnit(val) - 2);
  223. }
  224. self.textarea.css('height', val);
  225. return self;
  226. },
  227. remove : function() {
  228. var self = this, doc = self.doc;
  229. // remove events
  230. K(doc.body).unbind();
  231. K(doc).unbind();
  232. K(self.win).unbind();
  233. if (self._mousedownHandler) {
  234. K(document).unbind('mousedown', self._mousedownHandler);
  235. }
  236. // remove elements
  237. _elementVal(self.srcElement, self.html());
  238. self.srcElement.show();
  239. // doc.write('');
  240. self.iframe.unbind();
  241. self.textarea.unbind();
  242. KEdit.parent.remove.call(self);
  243. },
  244. html : function(val, isFull) {
  245. var self = this, doc = self.doc;
  246. // design mode
  247. if (self.designMode) {
  248. var body = doc.body;
  249. // get
  250. if (val === undefined) {
  251. if (isFull) {
  252. val = '<!doctype html><html>' + body.parentNode.innerHTML + '</html>';
  253. } else {
  254. val = body.innerHTML;
  255. }
  256. if (self.beforeGetHtml) {
  257. val = self.beforeGetHtml(val);
  258. }
  259. // bugfix: Firefox自动生成一个br标签
  260. if (_GECKO && val == '<br />') {
  261. val = '';
  262. }
  263. return val;
  264. }
  265. // set
  266. if (self.beforeSetHtml) {
  267. val = self.beforeSetHtml(val);
  268. }
  269. // IE9 Bugfix: https://github.com/kindsoft/kindeditor/issues/62
  270. if (_IE && _V >= 9) {
  271. val = val.replace(/(<.*?checked=")checked(".*>)/ig, '$1$2');
  272. }
  273. K(body).html(val);
  274. if (self.afterSetHtml) {
  275. self.afterSetHtml();
  276. }
  277. return self;
  278. }
  279. // source mode
  280. if (val === undefined) {
  281. return self.textarea.val();
  282. }
  283. self.textarea.val(val);
  284. return self;
  285. },
  286. design : function(bool) {
  287. var self = this, val;
  288. if (bool === undefined ? !self.designMode : bool) {
  289. if (!self.designMode) {
  290. val = self.html();
  291. self.designMode = true;
  292. self.textarea.hide();
  293. self.html(val);
  294. // cache
  295. var iframe = self.iframe;
  296. var height = _removeUnit(self.height);
  297. iframe.height(height - 2);
  298. iframe.show();
  299. // safari iframe scrollbar hack
  300. setTimeout(function() {
  301. iframe.height(height);
  302. }, 0);
  303. }
  304. } else {
  305. if (self.designMode) {
  306. val = self.html();
  307. self.designMode = false;
  308. self.html(val);
  309. self.iframe.hide();
  310. self.textarea.show();
  311. }
  312. }
  313. return self.focus();
  314. },
  315. focus : function() {
  316. var self = this;
  317. self.designMode ? self.win.focus() : self.textarea[0].focus();
  318. return self;
  319. },
  320. blur : function() {
  321. var self = this;
  322. if (_IE) {
  323. var input = K('<input type="text" style="float:left;width:0;height:0;padding:0;margin:0;border:0;" value="" />', self.div);
  324. self.div.append(input);
  325. input[0].focus();
  326. input.remove();
  327. } else {
  328. self.designMode ? self.win.blur() : self.textarea[0].blur();
  329. }
  330. return self;
  331. },
  332. afterChange : function(fn) {
  333. var self = this, doc = self.doc, body = doc.body;
  334. K(doc).keyup(function(e) {
  335. if (!e.ctrlKey && !e.altKey && _CHANGE_KEY_MAP[e.which]) {
  336. fn(e);
  337. }
  338. });
  339. K(doc).mouseup(fn).contextmenu(fn);
  340. K(self.win).blur(fn);
  341. function timeoutHandler(e) {
  342. setTimeout(function() {
  343. fn(e);
  344. }, 1);
  345. }
  346. K(body).bind('paste', timeoutHandler);
  347. K(body).bind('cut', timeoutHandler);
  348. return self;
  349. }
  350. });
  351. function _edit(options) {
  352. return new KEdit(options);
  353. }
  354. K.EditClass = KEdit;
  355. K.edit = _edit;
  356. K.iframeDoc = _iframeDoc;