From 1cd9495bfcecf6b9bf5645cb3d2c889bfb806884 Mon Sep 17 00:00:00 2001 From: Oliver Pulges Date: Wed, 6 Jan 2016 14:32:03 +0200 Subject: [PATCH] Update to v0.5.5 --- lib/wysihtml/rails/version.rb | 2 +- vendor/assets/javascripts/wysihtml-toolbar.js | 156 ++++++++++++++---- vendor/assets/javascripts/wysihtml.js | 156 ++++++++++++++---- 3 files changed, 241 insertions(+), 73 deletions(-) diff --git a/lib/wysihtml/rails/version.rb b/lib/wysihtml/rails/version.rb index 82ac8d1..a11cbab 100644 --- a/lib/wysihtml/rails/version.rb +++ b/lib/wysihtml/rails/version.rb @@ -1,5 +1,5 @@ module Wysihtml module Rails - VERSION = "0.5.4" + VERSION = "0.5.5" end end diff --git a/vendor/assets/javascripts/wysihtml-toolbar.js b/vendor/assets/javascripts/wysihtml-toolbar.js index 0a349ad..26bafae 100644 --- a/vendor/assets/javascripts/wysihtml-toolbar.js +++ b/vendor/assets/javascripts/wysihtml-toolbar.js @@ -1,5 +1,5 @@ /** - * @license wysihtml v0.5.4 + * @license wysihtml v0.5.5 * https://github.com/Voog/wysihtml * * Author: Christopher Blum (https://github.com/tiff) @@ -10,7 +10,7 @@ * */ var wysihtml5 = { - version: "0.5.4", + version: "0.5.5", // namespaces commands: {}, @@ -7119,6 +7119,10 @@ wysihtml5.browser = (function() { return ("styleFloat" in document.createElement("div").style) ? "styleFloat" : "cssFloat"; } return key; + }, + + usesControlRanges: function() { + return document.body && "createControlRange" in document.body; } }; })(); @@ -8136,8 +8140,8 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) { transferContentTo: function(targetNode, removeOldWrapper) { if (node.nodeType === 1) { - if (wysihtml5.dom.domNode(targetNode).is.voidElement()) { - while (node.firstChild) { + if (wysihtml5.dom.domNode(targetNode).is.voidElement() || targetNode.nodeType === 3) { + while (node.lastChild) { targetNode.parentNode.insertBefore(node.lastChild, targetNode.nextSibling); } } else { @@ -11736,6 +11740,14 @@ wysihtml5.quirks.ensureProperClearing = (function() { return ret; } + function getRangeNode(node, offset) { + if (node.nodeType === 3) { + return node; + } else { + return node.childNodes[offset] || node; + } + } + function getWebkitSelectionFixNode(container) { var blankNode = document.createElement('span'); @@ -11806,7 +11818,7 @@ wysihtml5.quirks.ensureProperClearing = (function() { /** @scope wysihtml5.Selection.prototype */ { constructor: function(editor, contain, unselectableClass) { // Make sure that our external range library is initialized - window.rangy.init(); + rangy.init(); this.editor = editor; this.composer = editor.composer; @@ -12133,11 +12145,16 @@ wysihtml5.quirks.ensureProperClearing = (function() { range.deleteContents(); }, + getCaretNode: function () { + var selection = this.getSelection(); + return (selection && selection.anchorNode) ? getRangeNode(selection.anchorNode, selection.anchorOffset) : null; + }, + getPreviousNode: function(node, ignoreEmpty) { var displayStyle; if (!node) { var selection = this.getSelection(); - node = selection.anchorNode; + node = (selection && selection.anchorNode) ? getRangeNode(selection.anchorNode, selection.anchorOffset) : null; } if (node === this.contain) { @@ -12257,15 +12274,24 @@ wysihtml5.quirks.ensureProperClearing = (function() { return (/^\s*$/).test(endtxt); }, - caretIsFirstInSelection: function() { + caretIsFirstInSelection: function(includeLineBreaks) { var r = rangy.createRange(this.doc), s = this.getSelection(), range = this.getRange(), - startNode = range.startContainer; + startNode = getRangeNode(range.startContainer, range.startOffset); if (startNode) { if (startNode.nodeType === wysihtml5.TEXT_NODE) { - return this.isCollapsed() && (startNode.nodeType === wysihtml5.TEXT_NODE && (/^\s*$/).test(startNode.data.substr(0,range.startOffset))); + if (!startNode.parentNode) { + return false; + } + if (!this.isCollapsed() || (startNode.parentNode.firstChild !== startNode && !wysihtml5.dom.domNode(startNode.previousSibling).is.block())) { + return false; + } + var ws = this.win.getComputedStyle(startNode.parentNode).whiteSpace; + return (ws === "pre" || ws === "pre-wrap") ? range.startOffset === 0 : (/^\s*$/).test(startNode.data.substr(0,range.startOffset)); + } else if (includeLineBreaks && wysihtml5.dom.domNode(startNode).is.lineBreak()) { + return true; } else { r.selectNodeContents(this.getRange().commonAncestorContainer); r.collapse(true); @@ -17526,31 +17552,36 @@ wysihtml5.views.View = Base.extend( var selection = composer.selection, prevNode = selection.getPreviousNode(); - if (selection.caretIsFirstInSelection() && - prevNode && - prevNode.nodeType === 1 && - (/block/).test(composer.win.getComputedStyle(prevNode).display) && - !domNode(prevNode).test({ - query: "ol, ul, table, tr, dl" - }) - ) { - if ((/^\s*$/).test(prevNode.textContent || prevNode.innerText)) { - // If heading is empty remove the heading node - prevNode.parentNode.removeChild(prevNode); - return true; - } else { - if (prevNode.lastChild) { - var selNode = prevNode.lastChild, - selectedNode = selection.getSelectedNode(), - commonAncestorNode = domNode(prevNode).commonAncestor(selectedNode, composer.element), - curNode = wysihtml5.dom.getParentElement(selectedNode, { - query: "h1, h2, h3, h4, h5, h6, p, pre, div, blockquote" - }, false, commonAncestorNode || composer.element); - - if (curNode) { - domNode(curNode).transferContentTo(prevNode, true); - selection.setAfter(selNode); - return true; + if (selection.caretIsFirstInSelection(wysihtml5.browser.usesControlRanges()) && prevNode) { + if (prevNode.nodeType === 1 && + wysihtml5.dom.domNode(prevNode).is.block() && + !domNode(prevNode).test({ + query: "ol, ul, table, tr, dl" + }) + ) { + if ((/^\s*$/).test(prevNode.textContent || prevNode.innerText)) { + // If heading is empty remove the heading node + prevNode.parentNode.removeChild(prevNode); + return true; + } else { + if (prevNode.lastChild) { + var selNode = prevNode.lastChild, + selectedNode = selection.getSelectedNode(), + commonAncestorNode = domNode(prevNode).commonAncestor(selectedNode, composer.element), + curNode = wysihtml5.dom.getParentElement(selectedNode, { + query: "h1, h2, h3, h4, h5, h6, p, pre, div, blockquote" + }, false, commonAncestorNode || composer.element); + + if (curNode) { + domNode(curNode).transferContentTo(prevNode, true); + selection.setAfter(selNode); + return true; + } else if (wysihtml5.browser.usesControlRanges()) { + selectedNode = selection.getCaretNode(); + domNode(selectedNode).transferContentTo(prevNode, true); + selection.setAfter(selNode); + return true; + } } } } @@ -17601,6 +17632,26 @@ wysihtml5.views.View = Base.extend( return false; }, + fixDeleteInTheBeginningOfControlSelection: function(composer) { + var selection = composer.selection, + prevNode = selection.getPreviousNode(), + selectedNode = selection.getSelectedNode(), + afterCaretNode; + + if (selection.caretIsFirstInSelection()) { + if (selectedNode.nodeType === 3) { + selectedNode = selectedNode.parentNode; + } + afterCaretNode = selectedNode.firstChild; + domNode(selectedNode).transferContentTo(prevNode, true); + if (afterCaretNode) { + composer.selection.setBefore(afterCaretNode); + } + return true; + } + return false; + }, + // Table management // If present enableObjectResizing and enableInlineTableEditing command should be called with false to prevent native table handlers initTableHandling: function() { @@ -17713,6 +17764,12 @@ wysihtml5.views.View = Base.extend( event.preventDefault(); return; } + if (wysihtml5.browser.usesControlRanges()) { + if (actions.fixDeleteInTheBeginningOfControlSelection(composer)) { + event.preventDefault(); + return; + } + } } else { if (selection.containsUneditable()) { event.preventDefault(); @@ -17829,6 +17886,30 @@ wysihtml5.views.View = Base.extend( this.selection.selectNode(target); } } + + // Saves mousedown position for IE controlSelect fix + if (wysihtml5.browser.usesControlRanges()) { + this.selection.lastMouseDownPos = {x: event.clientX, y: event.clientY}; + setTimeout(function() { + delete this.selection.lastMouseDownPos; + }.bind(this), 0); + } + }; + + // IE has this madness of control selects of overflowed and some other elements (weird box around element on selection and second click selects text) + // This fix handles the second click problem by adding cursor to the right position under cursor inside when controlSelection is made + var handleIEControlSelect = function(event) { + var target = event.target, + pos = this.selection.lastMouseDownPos; + if (pos) { + var caretPosition = document.body.createTextRange(); + setTimeout(function() { + try { + caretPosition.moveToPoint(pos.x, pos.y); + caretPosition.select(); + } catch (e) {} + }.bind(this), 0); + } }; var handleClick = function(event) { @@ -17916,8 +17997,6 @@ wysihtml5.views.View = Base.extend( this.selection.getSelection().removeAllRanges(); }).bind(this), 0); }; - - // Testing requires actions to be accessible from out of scope wysihtml5.views.Composer.prototype.observeActions = actions; @@ -17961,6 +18040,11 @@ wysihtml5.views.View = Base.extend( this.element.addEventListener("keyup", handleKeyUp.bind(this), false); this.element.addEventListener("keydown", handleKeyDown.bind(this), false); + // IE controlselect madness fix + if (wysihtml5.browser.usesControlRanges()) { + this.element.addEventListener('mscontrolselect', handleIEControlSelect.bind(this), false); + } + this.element.addEventListener("dragenter", (function() { this.parent.fire("unset_placeholder"); }).bind(this), false); diff --git a/vendor/assets/javascripts/wysihtml.js b/vendor/assets/javascripts/wysihtml.js index 9c8bfe5..716cadc 100644 --- a/vendor/assets/javascripts/wysihtml.js +++ b/vendor/assets/javascripts/wysihtml.js @@ -1,5 +1,5 @@ /** - * @license wysihtml v0.5.4 + * @license wysihtml v0.5.5 * https://github.com/Voog/wysihtml * * Author: Christopher Blum (https://github.com/tiff) @@ -10,7 +10,7 @@ * */ var wysihtml5 = { - version: "0.5.4", + version: "0.5.5", // namespaces commands: {}, @@ -7119,6 +7119,10 @@ wysihtml5.browser = (function() { return ("styleFloat" in document.createElement("div").style) ? "styleFloat" : "cssFloat"; } return key; + }, + + usesControlRanges: function() { + return document.body && "createControlRange" in document.body; } }; })(); @@ -8136,8 +8140,8 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) { transferContentTo: function(targetNode, removeOldWrapper) { if (node.nodeType === 1) { - if (wysihtml5.dom.domNode(targetNode).is.voidElement()) { - while (node.firstChild) { + if (wysihtml5.dom.domNode(targetNode).is.voidElement() || targetNode.nodeType === 3) { + while (node.lastChild) { targetNode.parentNode.insertBefore(node.lastChild, targetNode.nextSibling); } } else { @@ -11736,6 +11740,14 @@ wysihtml5.quirks.ensureProperClearing = (function() { return ret; } + function getRangeNode(node, offset) { + if (node.nodeType === 3) { + return node; + } else { + return node.childNodes[offset] || node; + } + } + function getWebkitSelectionFixNode(container) { var blankNode = document.createElement('span'); @@ -11806,7 +11818,7 @@ wysihtml5.quirks.ensureProperClearing = (function() { /** @scope wysihtml5.Selection.prototype */ { constructor: function(editor, contain, unselectableClass) { // Make sure that our external range library is initialized - window.rangy.init(); + rangy.init(); this.editor = editor; this.composer = editor.composer; @@ -12133,11 +12145,16 @@ wysihtml5.quirks.ensureProperClearing = (function() { range.deleteContents(); }, + getCaretNode: function () { + var selection = this.getSelection(); + return (selection && selection.anchorNode) ? getRangeNode(selection.anchorNode, selection.anchorOffset) : null; + }, + getPreviousNode: function(node, ignoreEmpty) { var displayStyle; if (!node) { var selection = this.getSelection(); - node = selection.anchorNode; + node = (selection && selection.anchorNode) ? getRangeNode(selection.anchorNode, selection.anchorOffset) : null; } if (node === this.contain) { @@ -12257,15 +12274,24 @@ wysihtml5.quirks.ensureProperClearing = (function() { return (/^\s*$/).test(endtxt); }, - caretIsFirstInSelection: function() { + caretIsFirstInSelection: function(includeLineBreaks) { var r = rangy.createRange(this.doc), s = this.getSelection(), range = this.getRange(), - startNode = range.startContainer; + startNode = getRangeNode(range.startContainer, range.startOffset); if (startNode) { if (startNode.nodeType === wysihtml5.TEXT_NODE) { - return this.isCollapsed() && (startNode.nodeType === wysihtml5.TEXT_NODE && (/^\s*$/).test(startNode.data.substr(0,range.startOffset))); + if (!startNode.parentNode) { + return false; + } + if (!this.isCollapsed() || (startNode.parentNode.firstChild !== startNode && !wysihtml5.dom.domNode(startNode.previousSibling).is.block())) { + return false; + } + var ws = this.win.getComputedStyle(startNode.parentNode).whiteSpace; + return (ws === "pre" || ws === "pre-wrap") ? range.startOffset === 0 : (/^\s*$/).test(startNode.data.substr(0,range.startOffset)); + } else if (includeLineBreaks && wysihtml5.dom.domNode(startNode).is.lineBreak()) { + return true; } else { r.selectNodeContents(this.getRange().commonAncestorContainer); r.collapse(true); @@ -17526,31 +17552,36 @@ wysihtml5.views.View = Base.extend( var selection = composer.selection, prevNode = selection.getPreviousNode(); - if (selection.caretIsFirstInSelection() && - prevNode && - prevNode.nodeType === 1 && - (/block/).test(composer.win.getComputedStyle(prevNode).display) && - !domNode(prevNode).test({ - query: "ol, ul, table, tr, dl" - }) - ) { - if ((/^\s*$/).test(prevNode.textContent || prevNode.innerText)) { - // If heading is empty remove the heading node - prevNode.parentNode.removeChild(prevNode); - return true; - } else { - if (prevNode.lastChild) { - var selNode = prevNode.lastChild, - selectedNode = selection.getSelectedNode(), - commonAncestorNode = domNode(prevNode).commonAncestor(selectedNode, composer.element), - curNode = wysihtml5.dom.getParentElement(selectedNode, { - query: "h1, h2, h3, h4, h5, h6, p, pre, div, blockquote" - }, false, commonAncestorNode || composer.element); - - if (curNode) { - domNode(curNode).transferContentTo(prevNode, true); - selection.setAfter(selNode); - return true; + if (selection.caretIsFirstInSelection(wysihtml5.browser.usesControlRanges()) && prevNode) { + if (prevNode.nodeType === 1 && + wysihtml5.dom.domNode(prevNode).is.block() && + !domNode(prevNode).test({ + query: "ol, ul, table, tr, dl" + }) + ) { + if ((/^\s*$/).test(prevNode.textContent || prevNode.innerText)) { + // If heading is empty remove the heading node + prevNode.parentNode.removeChild(prevNode); + return true; + } else { + if (prevNode.lastChild) { + var selNode = prevNode.lastChild, + selectedNode = selection.getSelectedNode(), + commonAncestorNode = domNode(prevNode).commonAncestor(selectedNode, composer.element), + curNode = wysihtml5.dom.getParentElement(selectedNode, { + query: "h1, h2, h3, h4, h5, h6, p, pre, div, blockquote" + }, false, commonAncestorNode || composer.element); + + if (curNode) { + domNode(curNode).transferContentTo(prevNode, true); + selection.setAfter(selNode); + return true; + } else if (wysihtml5.browser.usesControlRanges()) { + selectedNode = selection.getCaretNode(); + domNode(selectedNode).transferContentTo(prevNode, true); + selection.setAfter(selNode); + return true; + } } } } @@ -17601,6 +17632,26 @@ wysihtml5.views.View = Base.extend( return false; }, + fixDeleteInTheBeginningOfControlSelection: function(composer) { + var selection = composer.selection, + prevNode = selection.getPreviousNode(), + selectedNode = selection.getSelectedNode(), + afterCaretNode; + + if (selection.caretIsFirstInSelection()) { + if (selectedNode.nodeType === 3) { + selectedNode = selectedNode.parentNode; + } + afterCaretNode = selectedNode.firstChild; + domNode(selectedNode).transferContentTo(prevNode, true); + if (afterCaretNode) { + composer.selection.setBefore(afterCaretNode); + } + return true; + } + return false; + }, + // Table management // If present enableObjectResizing and enableInlineTableEditing command should be called with false to prevent native table handlers initTableHandling: function() { @@ -17713,6 +17764,12 @@ wysihtml5.views.View = Base.extend( event.preventDefault(); return; } + if (wysihtml5.browser.usesControlRanges()) { + if (actions.fixDeleteInTheBeginningOfControlSelection(composer)) { + event.preventDefault(); + return; + } + } } else { if (selection.containsUneditable()) { event.preventDefault(); @@ -17829,6 +17886,30 @@ wysihtml5.views.View = Base.extend( this.selection.selectNode(target); } } + + // Saves mousedown position for IE controlSelect fix + if (wysihtml5.browser.usesControlRanges()) { + this.selection.lastMouseDownPos = {x: event.clientX, y: event.clientY}; + setTimeout(function() { + delete this.selection.lastMouseDownPos; + }.bind(this), 0); + } + }; + + // IE has this madness of control selects of overflowed and some other elements (weird box around element on selection and second click selects text) + // This fix handles the second click problem by adding cursor to the right position under cursor inside when controlSelection is made + var handleIEControlSelect = function(event) { + var target = event.target, + pos = this.selection.lastMouseDownPos; + if (pos) { + var caretPosition = document.body.createTextRange(); + setTimeout(function() { + try { + caretPosition.moveToPoint(pos.x, pos.y); + caretPosition.select(); + } catch (e) {} + }.bind(this), 0); + } }; var handleClick = function(event) { @@ -17916,8 +17997,6 @@ wysihtml5.views.View = Base.extend( this.selection.getSelection().removeAllRanges(); }).bind(this), 0); }; - - // Testing requires actions to be accessible from out of scope wysihtml5.views.Composer.prototype.observeActions = actions; @@ -17961,6 +18040,11 @@ wysihtml5.views.View = Base.extend( this.element.addEventListener("keyup", handleKeyUp.bind(this), false); this.element.addEventListener("keydown", handleKeyDown.bind(this), false); + // IE controlselect madness fix + if (wysihtml5.browser.usesControlRanges()) { + this.element.addEventListener('mscontrolselect', handleIEControlSelect.bind(this), false); + } + this.element.addEventListener("dragenter", (function() { this.parent.fire("unset_placeholder"); }).bind(this), false);