0
Fork 0
mirror of https://github.com/fastmail/Squire.git synced 2024-12-22 15:23:29 -05:00

Add IE10 compatibility.

* All UA detection moved into a separate file.
This commit is contained in:
Neil Jenkins 2012-11-12 17:48:24 +11:00
parent 1d83790a57
commit fe6ffb0ed5
9 changed files with 151 additions and 163 deletions

View file

@ -9,7 +9,7 @@ build/ie8.js: source/ie8types.js source/ie8dom.js source/ie8range.js
mkdir -p $(@D) mkdir -p $(@D)
cat $^ | uglifyjs > $@ cat $^ | uglifyjs > $@
build/squire.js: source/TreeWalker.js source/Node.js source/Range.js source/Editor.js build/squire.js: source/UA.js source/TreeWalker.js source/Node.js source/Range.js source/Editor.js
mkdir -p $(@D) mkdir -p $(@D)
cat $^ | uglifyjs > $@ cat $^ | uglifyjs > $@

View file

@ -2,6 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title></title> <title></title>
<style type="text/css"> <style type="text/css">
html { html {
@ -51,9 +52,6 @@
<!--[if IE 8]> <!--[if IE 8]>
<script type="text/javascript" src="ie8.js"></script> <script type="text/javascript" src="ie8.js"></script>
<![endif]--> <![endif]-->
<!--[if IE 9]>
<script type="text/javascript">window.ie = 9;</script>
<![endif]-->
<script type="text/javascript" src="squire.js"></script> <script type="text/javascript" src="squire.js"></script>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

View file

@ -1,8 +1,9 @@
/* Copyright © 2011-2012 by Neil Jenkins. Licensed under the MIT license. */ /* Copyright © 2011-2012 by Neil Jenkins. Licensed under the MIT license. */
/*global Range, navigator, top, window, document, setTimeout */ /*global UA, DOMTreeWalker, Range, navigator,
top, window, document, setTimeout */
( function ( doc ) { ( function ( doc, UA, TreeWalker ) {
"use strict"; "use strict";
@ -18,18 +19,15 @@
var win = doc.defaultView; var win = doc.defaultView;
var body = doc.body; var body = doc.body;
// Browser sniffing. Unfortunately necessary. var isOpera = UA.isOpera;
var ua = navigator.userAgent; var isGecko = UA.isGecko;
var isOpera = !!win.opera; var isIOS = UA.isIOS;
var isIE = !!win.ie; var isIE = UA.isIE;
var isIE8 = ( win.ie === 8 ); var isIE8 = UA.isIE8;
var isGecko = /Gecko\//.test( ua );
var isWebKit = /WebKit/.test( ua );
var isIOS = /iP(?:ad|hone|od)/.test( ua );
var useTextFixer = isIE || isOpera; var cantFocusEmptyTextNodes = UA.cantFocusEmptyTextNodes;
var cantFocusEmptyTextNodes = isIE || isWebKit; var losesSelectionOnBlur = UA.losesSelectionOnBlur;
var losesSelectionOnBlur = isIE; var useTextFixer = UA.useTextFixer;
// --- DOM Sugar --- // --- DOM Sugar ---
@ -500,7 +498,7 @@
// Otherwise, check each text node at least partially contained within // Otherwise, check each text node at least partially contained within
// the selection and make sure all of them have the format we want. // the selection and make sure all of them have the format we want.
walker = doc.createTreeWalker( root, SHOW_TEXT, function ( node ) { walker = new TreeWalker( root, SHOW_TEXT, function ( node ) {
return range.containsNode( node, true ) ? return range.containsNode( node, true ) ?
FILTER_ACCEPT : FILTER_SKIP; FILTER_ACCEPT : FILTER_SKIP;
}, false ); }, false );
@ -534,7 +532,7 @@
// Create an iterator to walk over all the text nodes under this // Create an iterator to walk over all the text nodes under this
// ancestor which are in the range and not already formatted // ancestor which are in the range and not already formatted
// correctly. // correctly.
var walker = doc.createTreeWalker( var walker = new TreeWalker(
range.commonAncestorContainer, range.commonAncestorContainer,
SHOW_TEXT, SHOW_TEXT,
function ( node ) { function ( node ) {
@ -947,7 +945,7 @@
var addLinks = function ( frag ) { var addLinks = function ( frag ) {
var doc = frag.ownerDocument, var doc = frag.ownerDocument,
walker = doc.createTreeWalker( frag, SHOW_TEXT, walker = new TreeWalker( frag, SHOW_TEXT,
function ( node ) { function ( node ) {
return node.nearest( 'A' ) ? FILTER_SKIP : FILTER_ACCEPT; return node.nearest( 'A' ) ? FILTER_SKIP : FILTER_ACCEPT;
}, false ), }, false ),
@ -1958,4 +1956,4 @@
win.onEditorLoad = null; win.onEditorLoad = null;
} }
}( document ) ); }( document, UA, DOMTreeWalker ) );

View file

@ -1,9 +1,9 @@
/* Copyright © 2011-2012 by Neil Jenkins. Licensed under the MIT license. */ /* Copyright © 2011-2012 by Neil Jenkins. Licensed under the MIT license. */
( function () { /*global Node, Text, Element, HTMLDocument, window, document,
editor, UA, DOMTreeWalker */
/*global Node, Text, Element, HTMLDocument, window, document, navigator, ( function ( UA, TreeWalker ) {
editor */
"use strict"; "use strict";
@ -56,9 +56,6 @@ var ELEMENT_NODE = 1, // Node.ELEMENT_NODE,
var isBlock = function ( el ) { var isBlock = function ( el ) {
return el.isBlock() ? FILTER_ACCEPT : FILTER_SKIP; return el.isBlock() ? FILTER_ACCEPT : FILTER_SKIP;
}; };
var useTextFixer = !!( window.opera || window.ie );
var cantFocusEmptyTextNodes =
/WebKit/.test( navigator.userAgent ) || !!window.ie;
implement( window.Node ? [ Node ] : [ Text, Element, HTMLDocument ], { implement( window.Node ? [ Node ] : [ Text, Element, HTMLDocument ], {
isInline: $False, isInline: $False,
@ -89,14 +86,14 @@ implement( window.Node ? [ Node ] : [ Text, Element, HTMLDocument ], {
}, },
getPreviousBlock: function () { getPreviousBlock: function () {
var doc = this.ownerDocument, var doc = this.ownerDocument,
walker = doc.createTreeWalker( walker = new TreeWalker(
doc.body, SHOW_ELEMENT, isBlock, false ); doc.body, SHOW_ELEMENT, isBlock, false );
walker.currentNode = this; walker.currentNode = this;
return walker.previousNode(); return walker.previousNode();
}, },
getNextBlock: function () { getNextBlock: function () {
var doc = this.ownerDocument, var doc = this.ownerDocument,
walker = doc.createTreeWalker( walker = new TreeWalker(
doc.body, SHOW_ELEMENT, isBlock, false ); doc.body, SHOW_ELEMENT, isBlock, false );
walker.currentNode = this; walker.currentNode = this;
return walker.nextNode(); return walker.nextNode();
@ -379,7 +376,7 @@ implement([ Element ], {
if ( el.isInline() ) { if ( el.isInline() ) {
if ( !el.firstChild ) { if ( !el.firstChild ) {
if ( cantFocusEmptyTextNodes ) { if ( UA.cantFocusEmptyTextNodes ) {
fixer = doc.createTextNode( '\u200B' ); fixer = doc.createTextNode( '\u200B' );
editor._setPlaceholderTextNode( fixer ); editor._setPlaceholderTextNode( fixer );
} else { } else {
@ -387,7 +384,7 @@ implement([ Element ], {
} }
} }
} else { } else {
if ( useTextFixer ) { if ( UA.useTextFixer ) {
while ( el.nodeType !== TEXT_NODE && !el.isLeaf() ) { while ( el.nodeType !== TEXT_NODE && !el.isLeaf() ) {
child = el.firstChild; child = el.firstChild;
if ( !child ) { if ( !child ) {
@ -452,4 +449,4 @@ if ( function () {
}; };
} }
}() ); }( UA, DOMTreeWalker ) );

View file

@ -1,18 +1,11 @@
/* Copyright © 2011-2012 by Neil Jenkins. Licensed under the MIT license. */ /* Copyright © 2011-2012 by Neil Jenkins. Licensed under the MIT license. */
( function () { /*global Range, Node, DOMTreeWalker */
/*global Range, Node */ ( function ( TreeWalker ) {
"use strict"; "use strict";
var implement = function ( proto, props ) {
var prop;
for ( prop in props ) {
proto[ prop ] = props[ prop ];
}
};
var indexOf = Array.prototype.indexOf; var indexOf = Array.prototype.indexOf;
var ELEMENT_NODE = 1, // Node.ELEMENT_NODE var ELEMENT_NODE = 1, // Node.ELEMENT_NODE
@ -49,7 +42,7 @@ var getNodeAfter = function ( node, offset ) {
return node; return node;
}; };
implement( Range.prototype, { var RangePrototypeExtensions = {
forEachTextNode: function ( fn ) { forEachTextNode: function ( fn ) {
var range = this.cloneRange(); var range = this.cloneRange();
@ -58,7 +51,7 @@ implement( Range.prototype, {
var startContainer = range.startContainer, var startContainer = range.startContainer,
endContainer = range.endContainer, endContainer = range.endContainer,
root = range.commonAncestorContainer, root = range.commonAncestorContainer,
walker = root.ownerDocument.createTreeWalker( walker = new TreeWalker(
root, SHOW_TEXT, function ( node ) { root, SHOW_TEXT, function ( node ) {
return FILTER_ACCEPT; return FILTER_ACCEPT;
}, false ), }, false ),
@ -518,6 +511,11 @@ implement( Range.prototype, {
return this; return this;
} }
}); };
}() ); var prop;
for ( prop in RangePrototypeExtensions ) {
Range.prototype[ prop ] = RangePrototypeExtensions[ prop ];
}
}( DOMTreeWalker ) );

View file

@ -1,131 +1,102 @@
/* Copyright © 2011-2012 by Neil Jenkins. Licensed under the MIT license. */ /* Copyright © 2011-2012 by Neil Jenkins. Licensed under the MIT license. */
( function ( doc ) {
/*global document, window */ /*global document, window */
"use strict"; /*
Native TreeWalker is buggy in IE and Opera:
* IE9/10 sometimes throw errors when calling TreeWalker#nextNode or
TreeWalker#previousNode. No way to feature detect this.
* Some versions of Opera have a bug in TreeWalker#previousNode which makes
it skip to the wrong node.
// --- Rather than risk further bugs, it's easiest just to implement our own
(subset) of the spec in all browsers.
*/
var needsReplacement = !doc.createTreeWalker; var DOMTreeWalker = (function () {
// IE9 sometimes throws errors when calling TreeWalker#nextNode or "use strict";
// TreeWalker#previousNode. No way to feature detect this.
if ( window.ie === 9 ) {
needsReplacement = true;
}
// Feature detect Opera bug in TreeWalker#previousNode var typeToBitArray = {
if ( !needsReplacement ) { // ELEMENT_NODE
( function () { 1: 1,
var div = doc.createElement( 'div' ), // ATTRIBUTE_NODE
text = doc.createTextNode( '' ); 2: 2,
// TEXT_NODE
3: 4,
// COMMENT_NODE
8: 128,
// DOCUMENT_NODE
9: 256,
// DOCUMENT_FRAGMENT_NODE
11: 1024
};
div.appendChild( text ); var FILTER_ACCEPT = 1;
var div1 = div.cloneNode( true ), var TreeWalker = function ( root, nodeType, filter ) {
div2 = div.cloneNode( true ), this.root = this.currentNode = root;
div3 = div.cloneNode( true ), this.nodeType = nodeType;
walker = doc.createTreeWalker( div, 1, function ( node ) { this.filter = filter;
return 1; };
}, false );
div.appendChild( div1 );
div.appendChild( div2 );
div.appendChild( div3 );
walker.currentNode = div3;
if ( walker.previousNode() !== div2 ) {
needsReplacement = true;
}
}() );
}
if ( !needsReplacement ) { return; } TreeWalker.prototype.nextNode = function () {
var current = this.currentNode,
root = this.root,
nodeType = this.nodeType,
filter = this.filter,
node;
while ( true ) {
node = current.firstChild;
while ( !node && current ) {
if ( current === root ) {
break;
}
node = current.nextSibling;
if ( !node ) { current = current.parentNode; }
}
if ( !node ) {
return null;
}
if ( ( typeToBitArray[ node.nodeType ] & nodeType ) &&
filter( node ) === FILTER_ACCEPT ) {
this.currentNode = node;
return node;
}
current = node;
}
};
// --- TreeWalker.prototype.previousNode = function () {
var current = this.currentNode,
var typeToBitArray = { root = this.root,
// ELEMENT_NODE nodeType = this.nodeType,
1: 1, filter = this.filter,
// ATTRIBUTE_NODE node;
2: 2, while ( true ) {
// TEXT_NODE
3: 4,
// COMMENT_NODE
8: 128,
// DOCUMENT_NODE
9: 256,
// DOCUMENT_FRAGMENT_NODE
11: 1024
};
var FILTER_ACCEPT = 1;
var TreeWalker = function ( root, nodeType, filter ) {
this.root = this.currentNode = root;
this.nodeType = nodeType;
this.filter = filter;
};
TreeWalker.prototype.nextNode = function () {
var current = this.currentNode,
root = this.root,
nodeType = this.nodeType,
filter = this.filter,
node;
while ( true ) {
node = current.firstChild;
while ( !node && current ) {
if ( current === root ) { if ( current === root ) {
break; return null;
} }
node = current.nextSibling; node = current.previousSibling;
if ( !node ) { current = current.parentNode; } if ( node ) {
} while ( current = node.lastChild ) {
if ( !node ) { node = current;
return null; }
} } else {
if ( ( typeToBitArray[ node.nodeType ] & nodeType ) && node = current.parentNode;
filter( node ) === FILTER_ACCEPT ) {
this.currentNode = node;
return node;
}
current = node;
}
};
TreeWalker.prototype.previousNode = function () {
var current = this.currentNode,
root = this.root,
nodeType = this.nodeType,
filter = this.filter,
node;
while ( true ) {
if ( current === root ) {
return null;
}
node = current.previousSibling;
if ( node ) {
while ( current = node.lastChild ) {
node = current;
} }
} else { if ( !node ) {
node = current.parentNode; return null;
}
if ( ( typeToBitArray[ node.nodeType ] & nodeType ) &&
filter( node ) === FILTER_ACCEPT ) {
this.currentNode = node;
return node;
}
current = node;
} }
if ( !node ) { };
return null;
}
if ( ( typeToBitArray[ node.nodeType ] & nodeType ) &&
filter( node ) === FILTER_ACCEPT ) {
this.currentNode = node;
return node;
}
current = node;
}
};
doc.createTreeWalker = function ( root, nodeType, filter ) { return TreeWalker;
return new TreeWalker( root, nodeType, filter );
};
}( document ) ); })();

29
source/UA.js Normal file
View file

@ -0,0 +1,29 @@
/* Copyright © 2011-2012 by Neil Jenkins. Licensed under the MIT license. */
/*global navigator, window */
var UA = (function ( win ) {
"use strict";
var ua = navigator.userAgent;
var isOpera = !!win.opera;
var isIE = /Trident\//.test( ua );
var isWebKit = /WebKit\//.test( ua );
return {
// Browser sniffing. Unfortunately necessary.
isOpera: isOpera,
isIE8: ( win.ie === 8 ),
isIE: isIE,
isGecko: /Gecko\//.test( ua ),
isWebKit: isWebKit,
isIOS: /iP(?:ad|hone|od)/.test( ua ),
// Browser quirks
useTextFixer: isIE || isOpera,
cantFocusEmptyTextNodes: isIE || isWebKit,
losesSelectionOnBlur: isIE
};
})( window );

View file

@ -52,9 +52,6 @@
<!--[if IE 8]> <!--[if IE 8]>
<script type="text/javascript" src="ie8.js"></script> <script type="text/javascript" src="ie8.js"></script>
<![endif]--> <![endif]-->
<!--[if IE 9]>
<script type="text/javascript">window.ie = 9;</script>
<![endif]-->
<script type="text/javascript" src="squire.js"></script> <script type="text/javascript" src="squire.js"></script>
</body> </body>
</html> </html>