1 /* block-jump.js is part of the Aloha Editor project http://aloha-editor.org 2 * 3 * Aloha Editor is a WYSIWYG HTML5 inline editing library and editor. 4 * Copyright (c) 2010-2012 Gentics Software GmbH, Vienna, Austria. 5 * Contributors http://aloha-editor.org/contribution.php 6 * 7 * Aloha Editor is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or any later version. 11 * 12 * Aloha Editor is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * As an additional permission to the GNU GPL version 2, you may distribute 22 * non-source (e.g., minimized or compacted) forms of the Aloha-Editor 23 * source code without the copy of the GNU GPL normally required, 24 * provided you include this license notice and a URL through which 25 * recipients can access the Corresponding Source. 26 */ 27 /** 28 * Implements some logic related to moving the cursor keys across blocks. 29 * 30 * In the following example 31 * 32 * "some text<span class="aloha-block ..." contenteditable="false" ...>...</span>[]some text" 33 * 34 * when one moves the cursor indicated by "[]" to the left, the entire 35 * non-contenteditable block is skipped. The same for moving the cursor 36 * right across the block. 37 * 38 * TODO: actually, the block shouldn't be skipped, it should be 39 * selected/highlighted first. 40 * TODO: this file currently doesn't contain all the code to implement 41 * block jumping. Some of it is currently implemented in markup.js. 42 */ 43 define(['aloha/core', 'jquery'], function(Aloha, $){ 44 45 var zeroWidthNode = null; 46 47 /** 48 * Removes a previously inserted zero width text node. 49 * See insertZeroWidthTextNodeFix(). 50 */ 51 function removeZeroWidthTextNodeFix() { 52 if (!zeroWidthNode) { 53 return; 54 } 55 // We want to only replace a single zero-width character to avoid 56 // interfering with the other zero-width whitespace hack that makes 57 // empty lines visible in IE7. 58 var text = zeroWidthNode.nodeValue.replace(/\u200b/, ''); 59 if (text === zeroWidthNode.nodeValue) { 60 console.warn('Expected to remove the zero width text node fix, but couldn\'t find it'); 61 } 62 replaceMergeTextNode(zeroWidthNode, text); 63 zeroWidthNode = null; 64 } 65 66 /** 67 * Replaces the text in given text with the given text. 68 * 69 * @param node 70 * A text node attached to the DOM. 71 * @param text 72 * A string that is to replace the text of the given text node. 73 */ 74 function replaceMergeTextNode(node, text) { 75 node.deleteData(0, node.length); 76 if ("" === text) { 77 // already deleted above 78 } else if (node.nextSibling && 3 === node.nextSibling.nodeType) { 79 node.nextSibling.insertData(0, text); 80 } else if (node.previousSibling && 3 === node.previousSibling.nodeType) { 81 node.previousSibling.insertData(node.previousSibling.length, text); 82 } else { 83 node.insertData(0, text); 84 } 85 // We don't remove the node immediately to avoid intefering with a 86 // caller's range object that may have a start or end containers 87 // equal to this node. Removing it in a timeout may still interfere 88 // with the selection, but that was not a problem during testing. 89 setTimeout(function () { 90 if (0 === node.length) { 91 $(node).remove(); 92 } 93 }, 0); 94 } 95 96 /** 97 * Inserts a zero width text node before or after a block. 98 * 99 * There is a problem where some browsers can't select the boundary 100 * between some contenteditable content and non-contenteditable 101 * content. For example, if in the example at the top of the file 102 * the selection were one step to the right "...</span>s[]ome..." 103 * and the left cursor key were pressed, then the selection would 104 * just disappear or be stuck between the span and the text node. 105 * 106 * To work around this problem a zero width text node is inserted 107 * before or after a block. 108 * 109 * The inserted zero width text node will be removed automatically 110 * when it isn't necessary any more (on selection change or on 111 * editable.getContents()). 112 * 113 * TODO: In retrospect, a better alternative may be to simply wrap 114 * every inlin-block with an editable span. 115 * @param block 116 * The DOM element for a block before or after which the zero 117 * width text node will be inserted. 118 * @param isGoingLeft 119 * True if the zero width text node is to be inserted after 120 * the block element, or false if the zero width text node is 121 * to be inserted before the block element. 122 * @return 123 * The text node that was inserted. 124 */ 125 function insertZeroWidthTextNodeFix(block, isGoingLeft) { 126 removeZeroWidthTextNodeFix(); 127 zeroWidthNode = document.createTextNode("\u200b"); 128 if (isGoingLeft) { 129 $(block).after(zeroWidthNode); 130 } else { 131 $(block).before(zeroWidthNode); 132 } 133 134 Aloha.bind('aloha-selection-changed', function(event){ 135 removeZeroWidthTextNodeFix(); 136 Aloha.unbind(event); 137 }); 138 return zeroWidthNode; 139 } 140 141 return { 142 removeZeroWidthTextNodeFix: removeZeroWidthTextNodeFix, 143 insertZeroWidthTextNodeFix: insertZeroWidthTextNodeFix 144 }; 145 }); 146