mirror of
https://github.com/fastmail/Squire.git
synced 2024-12-22 07:13:08 -05:00
Add IE10 compatibility.
* All UA detection moved into a separate file.
This commit is contained in:
parent
1d83790a57
commit
fe6ffb0ed5
9 changed files with 151 additions and 163 deletions
2
Makefile
2
Makefile
|
@ -9,7 +9,7 @@ build/ie8.js: source/ie8types.js source/ie8dom.js source/ie8range.js
|
|||
mkdir -p $(@D)
|
||||
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)
|
||||
cat $^ | uglifyjs > $@
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<title></title>
|
||||
<style type="text/css">
|
||||
html {
|
||||
|
@ -51,9 +52,6 @@
|
|||
<!--[if IE 8]>
|
||||
<script type="text/javascript" src="ie8.js"></script>
|
||||
<![endif]-->
|
||||
<!--[if IE 9]>
|
||||
<script type="text/javascript">window.ie = 9;</script>
|
||||
<![endif]-->
|
||||
<script type="text/javascript" src="squire.js"></script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,8 +1,9 @@
|
|||
/* 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";
|
||||
|
||||
|
@ -18,18 +19,15 @@
|
|||
var win = doc.defaultView;
|
||||
var body = doc.body;
|
||||
|
||||
// Browser sniffing. Unfortunately necessary.
|
||||
var ua = navigator.userAgent;
|
||||
var isOpera = !!win.opera;
|
||||
var isIE = !!win.ie;
|
||||
var isIE8 = ( win.ie === 8 );
|
||||
var isGecko = /Gecko\//.test( ua );
|
||||
var isWebKit = /WebKit/.test( ua );
|
||||
var isIOS = /iP(?:ad|hone|od)/.test( ua );
|
||||
var isOpera = UA.isOpera;
|
||||
var isGecko = UA.isGecko;
|
||||
var isIOS = UA.isIOS;
|
||||
var isIE = UA.isIE;
|
||||
var isIE8 = UA.isIE8;
|
||||
|
||||
var useTextFixer = isIE || isOpera;
|
||||
var cantFocusEmptyTextNodes = isIE || isWebKit;
|
||||
var losesSelectionOnBlur = isIE;
|
||||
var cantFocusEmptyTextNodes = UA.cantFocusEmptyTextNodes;
|
||||
var losesSelectionOnBlur = UA.losesSelectionOnBlur;
|
||||
var useTextFixer = UA.useTextFixer;
|
||||
|
||||
// --- DOM Sugar ---
|
||||
|
||||
|
@ -500,7 +498,7 @@
|
|||
|
||||
// Otherwise, check each text node at least partially contained within
|
||||
// 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 ) ?
|
||||
FILTER_ACCEPT : FILTER_SKIP;
|
||||
}, false );
|
||||
|
@ -534,7 +532,7 @@
|
|||
// Create an iterator to walk over all the text nodes under this
|
||||
// ancestor which are in the range and not already formatted
|
||||
// correctly.
|
||||
var walker = doc.createTreeWalker(
|
||||
var walker = new TreeWalker(
|
||||
range.commonAncestorContainer,
|
||||
SHOW_TEXT,
|
||||
function ( node ) {
|
||||
|
@ -947,7 +945,7 @@
|
|||
|
||||
var addLinks = function ( frag ) {
|
||||
var doc = frag.ownerDocument,
|
||||
walker = doc.createTreeWalker( frag, SHOW_TEXT,
|
||||
walker = new TreeWalker( frag, SHOW_TEXT,
|
||||
function ( node ) {
|
||||
return node.nearest( 'A' ) ? FILTER_SKIP : FILTER_ACCEPT;
|
||||
}, false ),
|
||||
|
@ -1958,4 +1956,4 @@
|
|||
win.onEditorLoad = null;
|
||||
}
|
||||
|
||||
}( document ) );
|
||||
}( document, UA, DOMTreeWalker ) );
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/* 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,
|
||||
editor */
|
||||
( function ( UA, TreeWalker ) {
|
||||
|
||||
"use strict";
|
||||
|
||||
|
@ -56,9 +56,6 @@ var ELEMENT_NODE = 1, // Node.ELEMENT_NODE,
|
|||
var isBlock = function ( el ) {
|
||||
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 ], {
|
||||
isInline: $False,
|
||||
|
@ -89,14 +86,14 @@ implement( window.Node ? [ Node ] : [ Text, Element, HTMLDocument ], {
|
|||
},
|
||||
getPreviousBlock: function () {
|
||||
var doc = this.ownerDocument,
|
||||
walker = doc.createTreeWalker(
|
||||
walker = new TreeWalker(
|
||||
doc.body, SHOW_ELEMENT, isBlock, false );
|
||||
walker.currentNode = this;
|
||||
return walker.previousNode();
|
||||
},
|
||||
getNextBlock: function () {
|
||||
var doc = this.ownerDocument,
|
||||
walker = doc.createTreeWalker(
|
||||
walker = new TreeWalker(
|
||||
doc.body, SHOW_ELEMENT, isBlock, false );
|
||||
walker.currentNode = this;
|
||||
return walker.nextNode();
|
||||
|
@ -379,7 +376,7 @@ implement([ Element ], {
|
|||
|
||||
if ( el.isInline() ) {
|
||||
if ( !el.firstChild ) {
|
||||
if ( cantFocusEmptyTextNodes ) {
|
||||
if ( UA.cantFocusEmptyTextNodes ) {
|
||||
fixer = doc.createTextNode( '\u200B' );
|
||||
editor._setPlaceholderTextNode( fixer );
|
||||
} else {
|
||||
|
@ -387,7 +384,7 @@ implement([ Element ], {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if ( useTextFixer ) {
|
||||
if ( UA.useTextFixer ) {
|
||||
while ( el.nodeType !== TEXT_NODE && !el.isLeaf() ) {
|
||||
child = el.firstChild;
|
||||
if ( !child ) {
|
||||
|
@ -452,4 +449,4 @@ if ( function () {
|
|||
};
|
||||
}
|
||||
|
||||
}() );
|
||||
}( UA, DOMTreeWalker ) );
|
||||
|
|
|
@ -1,18 +1,11 @@
|
|||
/* Copyright © 2011-2012 by Neil Jenkins. Licensed under the MIT license. */
|
||||
|
||||
( function () {
|
||||
/*global Range, Node, DOMTreeWalker */
|
||||
|
||||
/*global Range, Node */
|
||||
( function ( TreeWalker ) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var implement = function ( proto, props ) {
|
||||
var prop;
|
||||
for ( prop in props ) {
|
||||
proto[ prop ] = props[ prop ];
|
||||
}
|
||||
};
|
||||
|
||||
var indexOf = Array.prototype.indexOf;
|
||||
|
||||
var ELEMENT_NODE = 1, // Node.ELEMENT_NODE
|
||||
|
@ -49,7 +42,7 @@ var getNodeAfter = function ( node, offset ) {
|
|||
return node;
|
||||
};
|
||||
|
||||
implement( Range.prototype, {
|
||||
var RangePrototypeExtensions = {
|
||||
|
||||
forEachTextNode: function ( fn ) {
|
||||
var range = this.cloneRange();
|
||||
|
@ -58,7 +51,7 @@ implement( Range.prototype, {
|
|||
var startContainer = range.startContainer,
|
||||
endContainer = range.endContainer,
|
||||
root = range.commonAncestorContainer,
|
||||
walker = root.ownerDocument.createTreeWalker(
|
||||
walker = new TreeWalker(
|
||||
root, SHOW_TEXT, function ( node ) {
|
||||
return FILTER_ACCEPT;
|
||||
}, false ),
|
||||
|
@ -518,6 +511,11 @@ implement( Range.prototype, {
|
|||
|
||||
return this;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
}() );
|
||||
var prop;
|
||||
for ( prop in RangePrototypeExtensions ) {
|
||||
Range.prototype[ prop ] = RangePrototypeExtensions[ prop ];
|
||||
}
|
||||
|
||||
}( DOMTreeWalker ) );
|
||||
|
|
|
@ -1,131 +1,102 @@
|
|||
/* Copyright © 2011-2012 by Neil Jenkins. Licensed under the MIT license. */
|
||||
|
||||
( function ( doc ) {
|
||||
|
||||
/*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 DOMTreeWalker = (function () {
|
||||
|
||||
var needsReplacement = !doc.createTreeWalker;
|
||||
"use strict";
|
||||
|
||||
// IE9 sometimes throws errors when calling TreeWalker#nextNode or
|
||||
// TreeWalker#previousNode. No way to feature detect this.
|
||||
if ( window.ie === 9 ) {
|
||||
needsReplacement = true;
|
||||
}
|
||||
var typeToBitArray = {
|
||||
// ELEMENT_NODE
|
||||
1: 1,
|
||||
// ATTRIBUTE_NODE
|
||||
2: 2,
|
||||
// TEXT_NODE
|
||||
3: 4,
|
||||
// COMMENT_NODE
|
||||
8: 128,
|
||||
// DOCUMENT_NODE
|
||||
9: 256,
|
||||
// DOCUMENT_FRAGMENT_NODE
|
||||
11: 1024
|
||||
};
|
||||
|
||||
// Feature detect Opera bug in TreeWalker#previousNode
|
||||
if ( !needsReplacement ) {
|
||||
( function () {
|
||||
var div = doc.createElement( 'div' ),
|
||||
text = doc.createTextNode( '' );
|
||||
var FILTER_ACCEPT = 1;
|
||||
|
||||
div.appendChild( text );
|
||||
var TreeWalker = function ( root, nodeType, filter ) {
|
||||
this.root = this.currentNode = root;
|
||||
this.nodeType = nodeType;
|
||||
this.filter = filter;
|
||||
};
|
||||
|
||||
var div1 = div.cloneNode( true ),
|
||||
div2 = div.cloneNode( true ),
|
||||
div3 = div.cloneNode( true ),
|
||||
walker = doc.createTreeWalker( div, 1, function ( node ) {
|
||||
return 1;
|
||||
}, false );
|
||||
div.appendChild( div1 );
|
||||
div.appendChild( div2 );
|
||||
div.appendChild( div3 );
|
||||
walker.currentNode = div3;
|
||||
if ( walker.previousNode() !== div2 ) {
|
||||
needsReplacement = true;
|
||||
}
|
||||
}() );
|
||||
}
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
if ( !needsReplacement ) { return; }
|
||||
|
||||
// ---
|
||||
|
||||
var typeToBitArray = {
|
||||
// ELEMENT_NODE
|
||||
1: 1,
|
||||
// ATTRIBUTE_NODE
|
||||
2: 2,
|
||||
// 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 ) {
|
||||
TreeWalker.prototype.previousNode = function () {
|
||||
var current = this.currentNode,
|
||||
root = this.root,
|
||||
nodeType = this.nodeType,
|
||||
filter = this.filter,
|
||||
node;
|
||||
while ( true ) {
|
||||
if ( current === root ) {
|
||||
break;
|
||||
return null;
|
||||
}
|
||||
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,
|
||||
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;
|
||||
node = current.previousSibling;
|
||||
if ( node ) {
|
||||
while ( current = node.lastChild ) {
|
||||
node = current;
|
||||
}
|
||||
} else {
|
||||
node = current.parentNode;
|
||||
}
|
||||
} else {
|
||||
node = current.parentNode;
|
||||
if ( !node ) {
|
||||
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 new TreeWalker( root, nodeType, filter );
|
||||
};
|
||||
return TreeWalker;
|
||||
|
||||
}( document ) );
|
||||
})();
|
||||
|
|
29
source/UA.js
Normal file
29
source/UA.js
Normal 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 );
|
|
@ -52,9 +52,6 @@
|
|||
<!--[if IE 8]>
|
||||
<script type="text/javascript" src="ie8.js"></script>
|
||||
<![endif]-->
|
||||
<!--[if IE 9]>
|
||||
<script type="text/javascript">window.ie = 9;</script>
|
||||
<![endif]-->
|
||||
<script type="text/javascript" src="squire.js"></script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue