From a7b5eec335f280fca4432bee9793f948f646a1cc Mon Sep 17 00:00:00 2001 From: Tim Date: Sun, 10 May 2015 15:30:56 +0100 Subject: [PATCH] Update lib files --- lib/rangy-classapplier.js | 16 +++-- lib/rangy-core.js | 97 ++++++++++++++++++++----------- lib/rangy-highlighter.js | 10 ++-- lib/rangy-selectionsaverestore.js | 14 +++-- lib/rangy-serializer.js | 4 +- lib/rangy-textrange.js | 92 ++++++++++++++++------------- 6 files changed, 140 insertions(+), 93 deletions(-) diff --git a/lib/rangy-classapplier.js b/lib/rangy-classapplier.js index f4a06090..a7bafb71 100644 --- a/lib/rangy-classapplier.js +++ b/lib/rangy-classapplier.js @@ -9,8 +9,8 @@ * * Copyright 2015, Tim Down * Licensed under the MIT license. - * Version: 1.3.0-beta.2 - * Build date: 22 March 2015 + * Version: 1.3.0 + * Build date: 10 May 2015 */ (function(factory, root) { if (typeof define == "function" && define.amd) { @@ -28,11 +28,12 @@ var dom = api.dom; var DomPosition = dom.DomPosition; var contains = dom.arrayContains; - var forEach = api.util.forEach; + var util = api.util; + var forEach = util.forEach; var defaultTagName = "span"; - var createElementNSSupported = api.util.isHostMethod(document, "createElementNS"); + var createElementNSSupported = util.isHostMethod(document, "createElementNS"); function each(obj, func) { for (var i in obj) { @@ -553,8 +554,10 @@ applier.attrExceptions = []; var el = document.createElement(applier.elementTagName); applier.elementProperties = applier.copyPropertiesToElement(elementPropertiesFromOptions, el, true); - each(elementAttributes, function(attrName) { + each(elementAttributes, function(attrName, attrValue) { applier.attrExceptions.push(attrName); + // Ensure each attribute value is a string + elementAttributes[attrName] = "" + attrValue; }); applier.elementAttributes = elementAttributes; @@ -1092,7 +1095,8 @@ }; api.CssClassApplier = api.ClassApplier = ClassApplier; - api.createCssClassApplier = api.createClassApplier = createClassApplier; + api.createClassApplier = createClassApplier; + util.createAliasForDeprecatedMethod(api, "createCssClassApplier", "createClassApplier", module); }); return rangy; diff --git a/lib/rangy-core.js b/lib/rangy-core.js index e0070f67..69e95bfa 100644 --- a/lib/rangy-core.js +++ b/lib/rangy-core.js @@ -4,8 +4,8 @@ * * Copyright 2015, Tim Down * Licensed under the MIT license. - * Version: 1.3.0-beta.2 - * Build date: 22 March 2015 + * Version: 1.3.0 + * Build date: 10 May 2015 */ (function(factory, root) { @@ -109,7 +109,7 @@ }; var api = { - version: "1.3.0-beta.2", + version: "1.3.0", initialized: false, isBrowser: isBrowser, supported: true, @@ -306,6 +306,24 @@ } } + function deprecationNotice(deprecated, replacement, module) { + if (module) { + deprecated += " in module " + module.name; + } + api.warn("DEPRECATED: " + deprecated + " is deprecated. Please use " + + replacement + " instead."); + } + + function createAliasForDeprecatedMethod(owner, deprecated, replacement, module) { + owner[deprecated] = function() { + deprecationNotice(deprecated, replacement, module); + return owner[replacement].apply(owner, util.toArray(arguments)); + }; + } + + util.deprecationNotice = deprecationNotice; + util.createAliasForDeprecatedMethod = createAliasForDeprecatedMethod; + // Allow external scripts to initialize this library in case it's loaded after the document has loaded api.init = init; @@ -336,6 +354,7 @@ if (isBrowser) { api.shim = api.createMissingNativeApi = shim; + createAliasForDeprecatedMethod(api, "createMissingNativeApi", "shim"); } function Module(name, dependencies, initializer) { @@ -379,7 +398,7 @@ }, deprecationNotice: function(deprecated, replacement) { - api.warn("DEPRECATED: " + deprecated + " in module " + this.name + "is deprecated. Please use " + + api.warn("DEPRECATED: " + deprecated + " in module " + this.name + " is deprecated. Please use " + replacement + " instead"); }, @@ -800,7 +819,7 @@ }; } else if (typeof document.documentElement.currentStyle != UNDEF) { getComputedStyleProperty = function(el, propName) { - return el.currentStyle[propName]; + return el.currentStyle ? el.currentStyle[propName] : ""; }; } else { module.fail("No means of obtaining computed style properties found"); @@ -980,6 +999,10 @@ return range.document || getDocument(range.startContainer); } + function getRangeRoot(range) { + return getRootContainer(range.startContainer); + } + function getBoundaryBeforeNode(node) { return new DomPosition(node.parentNode, getNodeIndex(node)); } @@ -1317,26 +1340,21 @@ } } - function isOrphan(node) { - return (crashyTextNodes && dom.isBrokenNode(node)) || - !arrayContains(rootContainerNodeTypes, node.nodeType) && !getDocumentOrFragmentContainer(node, true); - } - function isValidOffset(node, offset) { return offset <= (isCharacterDataNode(node) ? node.length : node.childNodes.length); } function isRangeValid(range) { return (!!range.startContainer && !!range.endContainer && - !isOrphan(range.startContainer) && - !isOrphan(range.endContainer) && + !(crashyTextNodes && (dom.isBrokenNode(range.startContainer) || dom.isBrokenNode(range.endContainer))) && + getRootContainer(range.startContainer) == getRootContainer(range.endContainer) && isValidOffset(range.startContainer, range.startOffset) && isValidOffset(range.endContainer, range.endOffset)); } function assertRangeValid(range) { if (!isRangeValid(range)) { - throw new Error("Range error: Range is no longer valid after DOM mutation (" + range.inspect() + ")"); + throw new Error("Range error: Range is not valid. This usually happens after DOM mutation. Range: (" + range.inspect() + ")"); } } @@ -1630,13 +1648,14 @@ // with it (as in WebKit) or not (as in Gecko pre-1.9, and the default) intersectsNode: function(node, touchingIsIntersecting) { assertRangeValid(this); - assertNode(node, "NOT_FOUND_ERR"); - if (getDocument(node) !== getRangeDocument(this)) { + if (getRootContainer(node) != getRangeRoot(this)) { return false; } var parent = node.parentNode, offset = getNodeIndex(node); - assertNode(parent, "NOT_FOUND_ERR"); + if (!parent) { + return true; + } var startComparison = comparePoints(parent, offset, this.endContainer, this.endOffset), endComparison = comparePoints(parent, offset + 1, this.startContainer, this.startOffset); @@ -2047,10 +2066,22 @@ }; var normalizeStart = true; + var sibling; if (isCharacterDataNode(ec)) { - if (ec.length == eo) { + if (eo == ec.length) { mergeForward(ec); + } else if (eo == 0) { + sibling = ec.previousSibling; + if (sibling && sibling.nodeType == ec.nodeType) { + eo = sibling.length; + if (sc == ec) { + normalizeStart = false; + } + sibling.appendData(ec.data); + removeNode(ec); + ec = sibling; + } } } else { if (eo > 0) { @@ -2066,6 +2097,16 @@ if (isCharacterDataNode(sc)) { if (so == 0) { mergeBackward(sc); + } else if (so == sc.length) { + sibling = sc.nextSibling; + if (sibling && sibling.nodeType == sc.nodeType) { + if (ec == sibling) { + ec = sc; + eo += sc.length; + } + sc.appendData(sibling.data); + removeNode(sibling); + } } } else { if (so < sc.childNodes.length) { @@ -2735,15 +2776,8 @@ return new DomRange(doc); }; - api.createIframeRange = function(iframeEl) { - module.deprecationNotice("createIframeRange()", "createRange(iframeEl)"); - return api.createRange(iframeEl); - }; - - api.createIframeRangyRange = function(iframeEl) { - module.deprecationNotice("createIframeRangyRange()", "createRangyRange(iframeEl)"); - return api.createRangyRange(iframeEl); - }; + util.createAliasForDeprecatedMethod(api, "createIframeRange", "createRange"); + util.createAliasForDeprecatedMethod(api, "createIframeRangyRange", "createRangyRange"); api.addShimListener(function(win) { var doc = win.document; @@ -2781,8 +2815,8 @@ var rangesEqual = DomRange.rangesEqual; - // Utility function to support direction parameters in the API that may be a string ("backward" or "forward") or a - // Boolean (true for backwards). + // Utility function to support direction parameters in the API that may be a string ("backward", "backwards", + // "forward" or "forwards") or a Boolean (true for backwards). function isDirectionBackward(dir) { return (typeof dir == "string") ? /^backward(s)?$/i.test(dir) : !!dir; } @@ -3198,10 +3232,7 @@ api.getSelection = getSelection; - api.getIframeSelection = function(iframeEl) { - module.deprecationNotice("getIframeSelection()", "getSelection(iframeEl)"); - return api.getSelection(dom.getIframeWindow(iframeEl)); - }; + util.createAliasForDeprecatedMethod(api, "getIframeSelection", "getSelection"); var selProto = WrappedSelection.prototype; @@ -3621,7 +3652,7 @@ selProto.callMethodOnEachRange = function(methodName, params) { var results = []; this.eachRange( function(range) { - results.push( range[methodName].apply(range, params) ); + results.push( range[methodName].apply(range, params || []) ); } ); return results; }; diff --git a/lib/rangy-highlighter.js b/lib/rangy-highlighter.js index d3b1d20d..bb71d8d2 100644 --- a/lib/rangy-highlighter.js +++ b/lib/rangy-highlighter.js @@ -6,8 +6,8 @@ * * Copyright 2015, Tim Down * Licensed under the MIT license. - * Version: 1.3.0-beta.2 - * Build date: 22 March 2015 + * Version: 1.3.0 + * Build date: 10 May 2015 */ (function(factory, root) { if (typeof define == "function" && define.amd) { @@ -460,7 +460,7 @@ options = createOptions(options, { containerElementId: null, - selection: api.getSelection(), + selection: api.getSelection(this.doc), exclusive: true }); @@ -495,7 +495,7 @@ }, unhighlightSelection: function(selection) { - selection = selection || api.getSelection(); + selection = selection || api.getSelection(this.doc); var intersectingHighlights = this.getIntersectingHighlights( selection.getAllRanges() ); this.removeHighlights(intersectingHighlights); selection.removeAllRanges(); @@ -503,7 +503,7 @@ }, getHighlightsInSelection: function(selection) { - selection = selection || api.getSelection(); + selection = selection || api.getSelection(this.doc); return this.getIntersectingHighlights(selection.getAllRanges()); }, diff --git a/lib/rangy-selectionsaverestore.js b/lib/rangy-selectionsaverestore.js index 4d553e4a..f5705514 100644 --- a/lib/rangy-selectionsaverestore.js +++ b/lib/rangy-selectionsaverestore.js @@ -9,8 +9,8 @@ * * Copyright 2015, Tim Down * Licensed under the MIT license. - * Version: 1.3.0-beta.2 - * Build date: 22 March 2015 + * Version: 1.3.0 + * Build date: 10 May 2015 */ (function(factory, root) { if (typeof define == "function" && define.amd) { @@ -27,7 +27,7 @@ rangy.createModule("SaveRestore", ["WrappedRange"], function(api, module) { var dom = api.dom; var removeNode = dom.removeNode; - + var isDirectionBackward = api.Selection.isDirectionBackward; var markerTextChar = "\ufeff"; function gEBI(id, doc) { @@ -69,8 +69,9 @@ return r2.compareBoundaryPoints(r1.START_TO_START, r1); } - function saveRange(range, backward) { + function saveRange(range, direction) { var startEl, endEl, doc = api.DomRange.getRangeDocument(range), text = range.toString(); + var backward = isDirectionBackward(direction); if (range.collapsed) { endEl = insertRangeBoundaryMarker(range, false); @@ -131,8 +132,9 @@ return range; } - function saveRanges(ranges, backward) { + function saveRanges(ranges, direction) { var rangeInfos = [], range, doc; + var backward = isDirectionBackward(direction); // Order the ranges by position within the DOM, latest first, cloning the array to leave the original untouched ranges = ranges.slice(0); @@ -171,7 +173,7 @@ // Ensure current selection is unaffected if (backward) { - sel.setSingleRange(ranges[0], "backward"); + sel.setSingleRange(ranges[0], backward); } else { sel.setRanges(ranges); } diff --git a/lib/rangy-serializer.js b/lib/rangy-serializer.js index 13827223..f2d57593 100644 --- a/lib/rangy-serializer.js +++ b/lib/rangy-serializer.js @@ -10,8 +10,8 @@ * * Copyright 2015, Tim Down * Licensed under the MIT license. - * Version: 1.3.0-beta.2 - * Build date: 22 March 2015 + * Version: 1.3.0 + * Build date: 10 May 2015 */ (function(factory, root) { if (typeof define == "function" && define.amd) { diff --git a/lib/rangy-textrange.js b/lib/rangy-textrange.js index c071c66f..49b3dc25 100644 --- a/lib/rangy-textrange.js +++ b/lib/rangy-textrange.js @@ -26,8 +26,8 @@ * * Copyright 2015, Tim Down * Licensed under the MIT license. - * Version: 1.3.0-beta.2 - * Build date: 22 March 2015 + * Version: 1.3.0 + * Build date: 10 May 2015 */ /** @@ -127,21 +127,10 @@ // This function must create word and non-word tokens for the whole of the text supplied to it function defaultTokenizer(chars, wordOptions) { - var word = chars.join(""), result, tokens = []; - - function createTokenFromRange(start, end, isWord) { - var tokenChars = chars.slice(start, end); - var token = { - isWord: isWord, - chars: tokenChars, - toString: function() { - return tokenChars.join(""); - } - }; - for (var i = 0, len = tokenChars.length; i < len; ++i) { - tokenChars[i].token = token; - } - tokens.push(token); + var word = chars.join(""), result, tokenRanges = []; + + function createTokenRange(start, end, isWord) { + tokenRanges.push( { start: start, end: end, isWord: isWord } ); } // Match words and mark characters @@ -152,24 +141,48 @@ // Create token for non-word characters preceding this word if (wordStart > lastWordEnd) { - createTokenFromRange(lastWordEnd, wordStart, false); + createTokenRange(lastWordEnd, wordStart, false); } // Get trailing space characters for word if (wordOptions.includeTrailingSpace) { - while (nonLineBreakWhiteSpaceRegex.test(chars[wordEnd])) { + while ( nonLineBreakWhiteSpaceRegex.test(chars[wordEnd]) ) { ++wordEnd; } } - createTokenFromRange(wordStart, wordEnd, true); + createTokenRange(wordStart, wordEnd, true); lastWordEnd = wordEnd; } // Create token for trailing non-word characters, if any exist if (lastWordEnd < chars.length) { - createTokenFromRange(lastWordEnd, chars.length, false); + createTokenRange(lastWordEnd, chars.length, false); + } + + return tokenRanges; + } + + function convertCharRangeToToken(chars, tokenRange) { + var tokenChars = chars.slice(tokenRange.start, tokenRange.end); + var token = { + isWord: tokenRange.isWord, + chars: tokenChars, + toString: function() { + return tokenChars.join(""); + } + }; + for (var i = 0, len = tokenChars.length; i < len; ++i) { + tokenChars[i].token = token; } + return token; + } + function tokenize(chars, wordOptions, tokenizer) { + var tokenRanges = tokenizer(chars, wordOptions); + var tokens = []; + for (var i = 0, tokenRange; tokenRange = tokenRanges[i++]; ) { + tokens.push( convertCharRangeToToken(chars, tokenRange) ); + } return tokens; } @@ -280,8 +293,6 @@ body.removeChild(table); })(); - api.features.tableCssDisplayBlock = tableCssDisplayBlock; - var defaultDisplayValueForTag = { table: "table", caption: "table-caption", @@ -529,7 +540,8 @@ TRAILING_SPACE_IN_BLOCK = "TRAILING_SPACE_IN_BLOCK", TRAILING_SPACE_BEFORE_BR = "TRAILING_SPACE_BEFORE_BR", PRE_LINE_TRAILING_SPACE_BEFORE_LINE_BREAK = "PRE_LINE_TRAILING_SPACE_BEFORE_LINE_BREAK", - TRAILING_LINE_BREAK_AFTER_BR = "TRAILING_LINE_BREAK_AFTER_BR"; + TRAILING_LINE_BREAK_AFTER_BR = "TRAILING_LINE_BREAK_AFTER_BR", + INCLUDED_TRAILING_LINE_BREAK_AFTER_BR = "INCLUDED_TRAILING_LINE_BREAK_AFTER_BR"; extend(nodeProto, { isCharacterDataNode: createCachingGetter("isCharacterDataNode", dom.isCharacterDataNode, "node"), @@ -676,7 +688,6 @@ /*----------------------------------------------------------------------------------------------------------------*/ - function Position(nodeWrapper, offset) { this.offset = offset; this.nodeWrapper = nodeWrapper; @@ -833,7 +844,7 @@ return cachedChar; } - // We need to actually get the character + // We need to actually get the character now var character = ""; var collapsible = (this.characterType == COLLAPSIBLE_SPACE); @@ -851,9 +862,14 @@ // Disallow a collapsible space that is followed by a line break or is the last character if (collapsible) { - // Disallow a collapsible space that follows a trailing space or line break, or is the first character - if (thisChar == " " && - (!getPreviousPos() || previousPos.isTrailingSpace || previousPos.character == "\n")) { + // Allow a trailing space that we've previously determined should be included + if (this.type == INCLUDED_TRAILING_LINE_BREAK_AFTER_BR) { + character = "\n"; + } + // Disallow a collapsible space that follows a trailing space or line break, or is the first character, + // or follows a collapsible included space + else if (thisChar == " " && + (!getPreviousPos() || previousPos.isTrailingSpace || previousPos.character == "\n" || (previousPos.character == " " && previousPos.characterType == COLLAPSIBLE_SPACE))) { } // Allow a leading line break unless it follows a line break else if (thisChar == "\n" && this.isLeadingSpace) { @@ -883,9 +899,10 @@ } else if (this.isBr) { nextPos.type = TRAILING_LINE_BREAK_AFTER_BR; - if (getPreviousPos() && previousPos.isLeadingSpace && previousPos.character == "\n") { + if (getPreviousPos() && previousPos.isLeadingSpace && !previousPos.isTrailingSpace && previousPos.character == "\n") { nextPos.character = ""; } else { + nextPos.type = INCLUDED_TRAILING_LINE_BREAK_AFTER_BR; } } } else { @@ -903,11 +920,6 @@ } } - // Collapse a br element that is followed by a trailing space - else if (thisChar == "\n" && - (!(nextPos = this.nextUncollapsed()) || nextPos.isTrailingSpace)) { - } - if (ignoredChars.indexOf(character) > -1) { character = ""; } @@ -1282,7 +1294,7 @@ // Get initial word surrounding initial position and tokenize it var forwardChars = consumeWord(true); var backwardChars = consumeWord(false).reverse(); - var tokens = tokenizer(backwardChars.concat(forwardChars), wordOptions); + var tokens = tokenize(backwardChars.concat(forwardChars), wordOptions, tokenizer); // Create initial token buffers var forwardTokensBuffer = forwardChars.length ? @@ -1311,7 +1323,7 @@ (forwardChars = consumeWord(true)).length > 0) { // Merge trailing non-word into next word and tokenize - forwardTokensBuffer = tokenizer(lastToken.chars.concat(forwardChars), wordOptions); + forwardTokensBuffer = tokenize(lastToken.chars.concat(forwardChars), wordOptions, tokenizer); } return forwardTokensBuffer.shift(); @@ -1327,7 +1339,7 @@ (backwardChars = consumeWord(false)).length > 0) { // Merge leading non-word into next word and tokenize - backwardTokensBuffer = tokenizer(backwardChars.reverse().concat(lastToken.chars), wordOptions); + backwardTokensBuffer = tokenize(backwardChars.reverse().concat(lastToken.chars), wordOptions, tokenizer); } return backwardTokensBuffer.pop(); @@ -1375,7 +1387,7 @@ if (backward) { newPos = newPos.previousVisible(); unitsMoved = -unitsMoved; - } else if (newPos && newPos.isLeadingSpace) { + } else if (newPos && newPos.isLeadingSpace && !newPos.isTrailingSpace) { // Tweak the position for the case of a leading space. The problem is that an uncollapsed leading space // before a block element (for example, the line break between "1" and "2" in the following HTML: // "1

2

") is considered to be attached to the position immediately before the block element, which @@ -1464,8 +1476,6 @@ text += currentChar; } - //console.log("text " + text) - if (isRegex) { result = searchTerm.exec(text); if (result) {