includes/clientside/tinymce/plugins/safari/editor_plugin_src.js
changeset 778 57ce13805b6f
parent 543 dffcbfbc4e59
child 1193 e3b94bd055dc
equal deleted inserted replaced
777:488665d49417 778:57ce13805b6f
     6  */
     6  */
     7 
     7 
     8 (function() {
     8 (function() {
     9 	var Event = tinymce.dom.Event, grep = tinymce.grep, each = tinymce.each, inArray = tinymce.inArray, isOldWebKit = tinymce.isOldWebKit;
     9 	var Event = tinymce.dom.Event, grep = tinymce.grep, each = tinymce.each, inArray = tinymce.inArray, isOldWebKit = tinymce.isOldWebKit;
    10 
    10 
       
    11 	function isEmpty(d, e, f) {
       
    12 		var w, n;
       
    13 
       
    14 		w = d.createTreeWalker(e, NodeFilter.SHOW_ALL, null, false);
       
    15 		while (n = w.nextNode()) {
       
    16 			// Filter func
       
    17 			if (f) {
       
    18 				if (!f(n))
       
    19 					return false;
       
    20 			}
       
    21 
       
    22 			// Non whitespace text node
       
    23 			if (n.nodeType == 3 && n.nodeValue && /[^\s\u00a0]+/.test(n.nodeValue))
       
    24 				return false;
       
    25 
       
    26 			// Is non text element byt still content
       
    27 			if (n.nodeType == 1 && /^(HR|IMG|TABLE)$/.test(n.nodeName))
       
    28 				return false;
       
    29 		}
       
    30 
       
    31 		return true;
       
    32 	};
       
    33 
    11 	tinymce.create('tinymce.plugins.Safari', {
    34 	tinymce.create('tinymce.plugins.Safari', {
    12 		init : function(ed) {
    35 		init : function(ed) {
    13 			var t = this, dom;
    36 			var t = this, dom;
    14 
    37 
    15 			// Ignore on non webkit
    38 			// Ignore on non webkit
    18 
    41 
    19 			t.editor = ed;
    42 			t.editor = ed;
    20 			t.webKitFontSizes = ['x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', '-webkit-xxx-large'];
    43 			t.webKitFontSizes = ['x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', '-webkit-xxx-large'];
    21 			t.namedFontSizes = ['xx-small', 'x-small','small','medium','large','x-large', 'xx-large'];
    44 			t.namedFontSizes = ['xx-small', 'x-small','small','medium','large','x-large', 'xx-large'];
    22 
    45 
    23 			// Safari will crash if the build in createlink command is used
    46 			// Safari CreateLink command will not work correctly on images that is aligned
    24 /*			ed.addCommand('CreateLink', function(u, v) {
    47 			ed.addCommand('CreateLink', function(u, v) {
    25 				ed.execCommand("mceInsertContent", false, '<a href="' + dom.encode(v) + '">' + ed.selection.getContent() + '</a>');
    48 				var n = ed.selection.getNode(), dom = ed.dom, a;
    26 			});*/
    49 
       
    50 				if (n && (/^(left|right)$/i.test(dom.getStyle(n, 'float', 1)) || /^(left|right)$/i.test(dom.getAttrib(n, 'align')))) {
       
    51 					a = dom.create('a', {href : v}, n.cloneNode());
       
    52 					n.parentNode.replaceChild(a, n);
       
    53 					ed.selection.select(a);
       
    54 				} else
       
    55 					ed.getDoc().execCommand("CreateLink", false, v);
       
    56 			});
    27 
    57 
    28 			ed.onPaste.add(function(ed, e) {
    58 			ed.onPaste.add(function(ed, e) {
    29 				function removeStyles(e) {
    59 				function removeStyles(e) {
    30 					e = e.target;
    60 					e = e.target;
    31 
    61 
    44 					Event.remove(ed.getDoc(), 'DOMNodeInserted', removeStyles);
    74 					Event.remove(ed.getDoc(), 'DOMNodeInserted', removeStyles);
    45 				}, 0);
    75 				}, 0);
    46 			});
    76 			});
    47 
    77 
    48 			ed.onKeyUp.add(function(ed, e) {
    78 			ed.onKeyUp.add(function(ed, e) {
    49 				var h, b;
    79 				var h, b, r, n, s;
    50 
    80 
    51 				// If backspace or delete key
    81 				// If backspace or delete key
    52 				if (e.keyCode == 46 || e.keyCode == 8) {
    82 				if (e.keyCode == 46 || e.keyCode == 8) {
    53 					b = ed.getBody();
    83 					b = ed.getBody();
    54 					h = b.innerHTML;
    84 					h = b.innerHTML;
       
    85 					s = ed.selection;
    55 
    86 
    56 					// If there is no text content or images or hr elements then remove everything
    87 					// If there is no text content or images or hr elements then remove everything
    57 					if (b.childNodes.length == 1 && !/<(img|hr)/.test(h) && tinymce.trim(h.replace(/<[^>]+>/g, '')).length == 0)
    88 					if (b.childNodes.length == 1 && !/<(img|hr)/.test(h) && tinymce.trim(h.replace(/<[^>]+>/g, '')).length == 0) {
    58 						ed.setContent('', {format : 'raw'});
    89 						// Inject paragrah and bogus br
       
    90 						ed.setContent('<p><br mce_bogus="1" /></p>', {format : 'raw'});
       
    91 
       
    92 						// Move caret before bogus br
       
    93 						n = b.firstChild;
       
    94 						r = s.getRng();
       
    95 						r.setStart(n, 0);
       
    96 						r.setEnd(n, 0);
       
    97 						s.setRng(r);
       
    98 					}
    59 				}
    99 				}
    60 			});
   100 			});
    61 
   101 
    62 			// Workaround for FormatBlock bug, http://bugs.webkit.org/show_bug.cgi?id=16004
   102 			// Workaround for FormatBlock bug, http://bugs.webkit.org/show_bug.cgi?id=16004
    63 			ed.addCommand('FormatBlock', function(u, v) {
   103 			ed.addCommand('FormatBlock', function(u, v) {
    70 			});
   110 			});
    71 
   111 
    72 			// Workaround for InsertHTML bug, http://bugs.webkit.org/show_bug.cgi?id=16382
   112 			// Workaround for InsertHTML bug, http://bugs.webkit.org/show_bug.cgi?id=16382
    73 			ed.addCommand('mceInsertContent', function(u, v) {
   113 			ed.addCommand('mceInsertContent', function(u, v) {
    74 				ed.getDoc().execCommand("InsertText", false, 'mce_marker');
   114 				ed.getDoc().execCommand("InsertText", false, 'mce_marker');
    75 				ed.getBody().innerHTML = ed.getBody().innerHTML.replace(/mce_marker/g, v + '<span id="_mce_tmp">XX</span>');
   115 				ed.getBody().innerHTML = ed.getBody().innerHTML.replace(/mce_marker/g, ed.dom.processHTML(v) + '<span id="_mce_tmp">XX</span>');
    76 				ed.selection.select(ed.dom.get('_mce_tmp'));
   116 				ed.selection.select(ed.dom.get('_mce_tmp'));
    77 				ed.getDoc().execCommand("Delete", false, ' ');
   117 				ed.getDoc().execCommand("Delete", false, ' ');
    78 			});
   118 			});
    79 
   119 
    80 			// Workaround for missing shift+enter support, http://bugs.webkit.org/show_bug.cgi?id=16973
       
    81 			ed.onKeyPress.add(function(ed, e) {
   120 			ed.onKeyPress.add(function(ed, e) {
    82 				if (e.keyCode == 13 && (e.shiftKey || ed.settings.force_br_newlines && ed.selection.getNode().nodeName != 'LI')) {
   121 				var se, li, lic, r1, r2, n, sel, doc, be, af, pa;
    83 					t._insertBR(ed);
   122 
    84 					Event.cancel(e);
   123 				if (e.keyCode == 13) {
       
   124 					sel = ed.selection;
       
   125 					se = sel.getNode();
       
   126 
       
   127 					// Workaround for missing shift+enter support, http://bugs.webkit.org/show_bug.cgi?id=16973
       
   128 					if (e.shiftKey || ed.settings.force_br_newlines && se.nodeName != 'LI') {
       
   129 						t._insertBR(ed);
       
   130 						Event.cancel(e);
       
   131 					}
       
   132 
       
   133 					// Workaround for DIV elements produced by Safari
       
   134 					if (li = dom.getParent(se, 'LI')) {
       
   135 						lic = dom.getParent(li, 'OL,UL');
       
   136 						doc = ed.getDoc();
       
   137 
       
   138 						pa = dom.create('p');
       
   139 						dom.add(pa, 'br', {mce_bogus : "1"});
       
   140 
       
   141 						if (isEmpty(doc, li)) {
       
   142 							// If list in list then use browser default behavior
       
   143 							if (n = dom.getParent(lic.parentNode, 'LI,OL,UL'))
       
   144 								return;
       
   145 
       
   146 							n = dom.getParent(lic, 'p,h1,h2,h3,h4,h5,h6,div') || lic;
       
   147 
       
   148 							// Create range from the start of block element to the list item
       
   149 							r1 = doc.createRange();
       
   150 							r1.setStartBefore(n);
       
   151 							r1.setEndBefore(li);
       
   152 
       
   153 							// Create range after the list to the end of block element
       
   154 							r2 = doc.createRange();
       
   155 							r2.setStartAfter(li);
       
   156 							r2.setEndAfter(n);
       
   157 
       
   158 							be = r1.cloneContents();
       
   159 							af = r2.cloneContents();
       
   160 
       
   161 							if (!isEmpty(doc, af))
       
   162 								dom.insertAfter(af, n);
       
   163 
       
   164 							dom.insertAfter(pa, n);
       
   165 
       
   166 							if (!isEmpty(doc, be))
       
   167 								dom.insertAfter(be, n);
       
   168 
       
   169 							dom.remove(n);
       
   170 
       
   171 							n = pa.firstChild;
       
   172 							r1 = doc.createRange();
       
   173 							r1.setStartBefore(n);
       
   174 							r1.setEndBefore(n);
       
   175 							sel.setRng(r1);
       
   176 
       
   177 							return Event.cancel(e);
       
   178 						}
       
   179 					}
    85 				}
   180 				}
    86 			});
   181 			});
    87 
   182 
    88 			// Safari returns incorrect values
   183 			// Safari doesn't place lists outside block elements
    89 			ed.addQueryValueHandler('FontSize', function(u, v) {
   184 			ed.onExecCommand.add(function(ed, cmd) {
    90 				var e, v;
   185 				var sel, dom, bl, bm;
    91 
   186 
    92 				// Check for the real font size at the start of selection
   187 				if (cmd == 'InsertUnorderedList' || cmd == 'InsertOrderedList') {
    93 				if ((e = ed.dom.getParent(ed.selection.getStart(), 'span')) && (v = e.style.fontSize))
   188 					sel = ed.selection;
    94 					return tinymce.inArray(t.namedFontSizes, v) + 1;
   189 					dom = ed.dom;
    95 
   190 
    96 				// Check for the real font size at the end of selection
   191 					if (bl = dom.getParent(sel.getNode(), function(n) {return /^(H[1-6]|P|ADDRESS|PRE)$/.test(n.nodeName);})) {
    97 				if ((e = ed.dom.getParent(ed.selection.getEnd(), 'span')) && (v = e.style.fontSize))
   192 						bm = sel.getBookmark();
    98 					return tinymce.inArray(t.namedFontSizes, v) + 1;
   193 						dom.remove(bl, 1);
    99 
   194 						sel.moveToBookmark(bm);
   100 				// Return default value it's better than nothing right!
   195 					}
   101 				return ed.getDoc().queryCommandValue('FontSize');
   196 				}
   102 			});
       
   103 
       
   104 			// Safari returns incorrect values
       
   105 			ed.addQueryValueHandler('FontName', function(u, v) {
       
   106 				var e, v;
       
   107 
       
   108 				// Check for the real font name at the start of selection
       
   109 				if ((e = ed.dom.getParent(ed.selection.getStart(), 'span')) && (v = e.style.fontFamily))
       
   110 					return v.replace(/, /g, ',');
       
   111 
       
   112 				// Check for the real font name at the end of selection
       
   113 				if ((e = ed.dom.getParent(ed.selection.getEnd(), 'span')) && (v = e.style.fontFamily))
       
   114 					return v.replace(/, /g, ',');
       
   115 
       
   116 				// Return default value it's better than nothing right!
       
   117 				return ed.getDoc().queryCommandValue('FontName');
       
   118 			});
   197 			});
   119 
   198 
   120 			// Workaround for bug, http://bugs.webkit.org/show_bug.cgi?id=12250
   199 			// Workaround for bug, http://bugs.webkit.org/show_bug.cgi?id=12250
   121 			ed.onClick.add(function(ed, e) {
   200 			ed.onClick.add(function(ed, e) {
   122 				e = e.target;
   201 				e = e.target;
   126 					ed.selection.select(e);
   205 					ed.selection.select(e);
   127 				} else
   206 				} else
   128 					t.selElm = null;
   207 					t.selElm = null;
   129 			});
   208 			});
   130 
   209 
   131 /*			ed.onBeforeExecCommand.add(function(ed, c, b) {
       
   132 				var r = t.bookmarkRng;
       
   133 
       
   134 				// Restore selection
       
   135 				if (r) {
       
   136 					ed.selection.setRng(r);
       
   137 					t.bookmarkRng = null;
       
   138 					//console.debug('restore', r.startContainer, r.startOffset, r.endContainer, r.endOffset);
       
   139 				}
       
   140 			});*/
       
   141 
       
   142 			ed.onInit.add(function() {
   210 			ed.onInit.add(function() {
   143 				t._fixWebKitSpans();
   211 				t._fixWebKitSpans();
   144 
       
   145 /*				ed.windowManager.onOpen.add(function() {
       
   146 					var r = ed.selection.getRng();
       
   147 
       
   148 					// Store selection if valid
       
   149 					if (r.startContainer != ed.getDoc()) {
       
   150 						t.bookmarkRng = r.cloneRange();
       
   151 						//console.debug('store', r.startContainer, r.startOffset, r.endContainer, r.endOffset);
       
   152 					}
       
   153 				});
       
   154 
       
   155 				ed.windowManager.onClose.add(function() {
       
   156 					t.bookmarkRng = null;
       
   157 				});*/
       
   158 
   212 
   159 				if (isOldWebKit)
   213 				if (isOldWebKit)
   160 					t._patchSafari2x(ed);
   214 					t._patchSafari2x(ed);
   161 			});
   215 			});
   162 
   216