mirror of
https://github.com/fastmail/Squire.git
synced 2025-01-03 05:00:13 -05:00
Catch all errors to allow logging.
* All errors will be caught and passed to the editor.didError fn. This can be overridden to do something useful, like logging them to the server.
This commit is contained in:
parent
f08fe04bb2
commit
52e517b376
4 changed files with 99 additions and 77 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
170
source/Editor.js
170
source/Editor.js
|
@ -1,6 +1,6 @@
|
||||||
/* Copyright © 2011-2012 by Neil Jenkins. Licensed under the MIT license. */
|
/* Copyright © 2011-2012 by Neil Jenkins. Licensed under the MIT license. */
|
||||||
|
|
||||||
/*global UA, DOMTreeWalker, Range, top, document, setTimeout */
|
/*global UA, DOMTreeWalker, Range, top, document, setTimeout, console */
|
||||||
|
|
||||||
( function ( doc, UA, TreeWalker ) {
|
( function ( doc, UA, TreeWalker ) {
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
var win = doc.defaultView;
|
var win = doc.defaultView;
|
||||||
var body = doc.body;
|
var body = doc.body;
|
||||||
|
var editor;
|
||||||
|
|
||||||
var isOpera = UA.isOpera;
|
var isOpera = UA.isOpera;
|
||||||
var isGecko = UA.isGecko;
|
var isGecko = UA.isGecko;
|
||||||
|
@ -56,7 +57,7 @@
|
||||||
// document node, since these events are fired in a custom manner by the
|
// document node, since these events are fired in a custom manner by the
|
||||||
// editor code.
|
// editor code.
|
||||||
var customEvents = {
|
var customEvents = {
|
||||||
cut: 1, paste: 1, focus: 1, blur: 1,
|
focus: 1, blur: 1,
|
||||||
pathChange: 1, select: 1, input: 1, undoStateChange: 1
|
pathChange: 1, select: 1, input: 1, undoStateChange: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,10 +75,14 @@
|
||||||
}
|
}
|
||||||
for ( i = 0, l = handlers.length; i < l; i += 1 ) {
|
for ( i = 0, l = handlers.length; i < l; i += 1 ) {
|
||||||
obj = handlers[i];
|
obj = handlers[i];
|
||||||
if ( obj.handleEvent ) {
|
try {
|
||||||
obj.handleEvent( event );
|
if ( obj.handleEvent ) {
|
||||||
} else {
|
obj.handleEvent( event );
|
||||||
obj( event );
|
} else {
|
||||||
|
obj( event );
|
||||||
|
}
|
||||||
|
} catch ( error ) {
|
||||||
|
editor.didError( error );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1184,24 +1189,28 @@
|
||||||
// --- Cut and Paste ---
|
// --- Cut and Paste ---
|
||||||
|
|
||||||
var afterCut = function () {
|
var afterCut = function () {
|
||||||
// If all content removed, ensure div at start of body.
|
try {
|
||||||
body.fixCursor();
|
// If all content removed, ensure div at start of body.
|
||||||
|
body.fixCursor();
|
||||||
|
} catch ( error ) {
|
||||||
|
editor.didError( error );
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
doc.addEventListener( isIE ? 'beforecut' : 'cut', function () {
|
addEventListener( isIE ? 'beforecut' : 'cut', function () {
|
||||||
// Save undo checkpoint
|
// Save undo checkpoint
|
||||||
var range = getSelection();
|
var range = getSelection();
|
||||||
recordUndoState( range );
|
recordUndoState( range );
|
||||||
getRangeAndRemoveBookmark( range );
|
getRangeAndRemoveBookmark( range );
|
||||||
setSelection( range );
|
setSelection( range );
|
||||||
setTimeout( afterCut, 0 );
|
setTimeout( afterCut, 0 );
|
||||||
}, false );
|
});
|
||||||
|
|
||||||
// IE sometimes fires the beforepaste event twice; make sure it is not run
|
// IE sometimes fires the beforepaste event twice; make sure it is not run
|
||||||
// again before our after paste function is called.
|
// again before our after paste function is called.
|
||||||
var awaitingPaste = false;
|
var awaitingPaste = false;
|
||||||
|
|
||||||
doc.addEventListener( isIE ? 'beforepaste' : 'paste', function ( event ) {
|
addEventListener( isIE ? 'beforepaste' : 'paste', function ( event ) {
|
||||||
if ( awaitingPaste ) { return; }
|
if ( awaitingPaste ) { return; }
|
||||||
|
|
||||||
// Treat image paste as a drop of an image file.
|
// Treat image paste as a drop of an image file.
|
||||||
|
@ -1252,52 +1261,57 @@
|
||||||
// single javascript thread, so it will be executed after the
|
// single javascript thread, so it will be executed after the
|
||||||
// paste event.
|
// paste event.
|
||||||
setTimeout( function () {
|
setTimeout( function () {
|
||||||
// Get the pasted content and clean
|
try {
|
||||||
var frag = pasteArea.detach().empty(),
|
// Get the pasted content and clean
|
||||||
first = frag.firstChild,
|
var frag = pasteArea.detach().empty(),
|
||||||
range = createRange(
|
first = frag.firstChild,
|
||||||
startContainer, startOffset, endContainer, endOffset );
|
range = createRange(
|
||||||
|
startContainer, startOffset, endContainer, endOffset );
|
||||||
|
|
||||||
// Was anything actually pasted?
|
// Was anything actually pasted?
|
||||||
if ( first ) {
|
if ( first ) {
|
||||||
// Safari and IE like putting extra divs around things.
|
// Safari and IE like putting extra divs around things.
|
||||||
if ( first === frag.lastChild && first.nodeName === 'DIV' ) {
|
if ( first === frag.lastChild &&
|
||||||
frag.replaceChild( first.empty(), first );
|
first.nodeName === 'DIV' ) {
|
||||||
}
|
frag.replaceChild( first.empty(), first );
|
||||||
|
|
||||||
frag.normalize();
|
|
||||||
addLinks( frag );
|
|
||||||
cleanTree( frag, false );
|
|
||||||
cleanupBRs( frag );
|
|
||||||
|
|
||||||
var node = frag,
|
|
||||||
doPaste = true;
|
|
||||||
while ( node = node.getNextBlock() ) {
|
|
||||||
node.fixCursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
fireEvent( 'willPaste', {
|
|
||||||
fragment: frag,
|
|
||||||
preventDefault: function () {
|
|
||||||
doPaste = false;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// Insert pasted data
|
frag.normalize();
|
||||||
if ( doPaste ) {
|
addLinks( frag );
|
||||||
range.insertTreeFragment( frag );
|
cleanTree( frag, false );
|
||||||
docWasChanged();
|
cleanupBRs( frag );
|
||||||
|
|
||||||
range.collapse( false );
|
var node = frag,
|
||||||
|
doPaste = true;
|
||||||
|
while ( node = node.getNextBlock() ) {
|
||||||
|
node.fixCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
fireEvent( 'willPaste', {
|
||||||
|
fragment: frag,
|
||||||
|
preventDefault: function () {
|
||||||
|
doPaste = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Insert pasted data
|
||||||
|
if ( doPaste ) {
|
||||||
|
range.insertTreeFragment( frag );
|
||||||
|
docWasChanged();
|
||||||
|
|
||||||
|
range.collapse( false );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSelection( range );
|
||||||
|
updatePath( range, true );
|
||||||
|
|
||||||
|
awaitingPaste = false;
|
||||||
|
} catch ( error ) {
|
||||||
|
editor.didError( error );
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelection( range );
|
|
||||||
updatePath( range, true );
|
|
||||||
|
|
||||||
awaitingPaste = false;
|
|
||||||
}, 0 );
|
}, 0 );
|
||||||
}, false );
|
});
|
||||||
|
|
||||||
// --- Keyboard interaction ---
|
// --- Keyboard interaction ---
|
||||||
|
|
||||||
|
@ -1333,29 +1347,33 @@
|
||||||
// link in Opera, it won't delete the link. Let's make things consistent. If
|
// link in Opera, it won't delete the link. Let's make things consistent. If
|
||||||
// you delete all text inside an inline tag, remove the inline tag.
|
// you delete all text inside an inline tag, remove the inline tag.
|
||||||
var afterDelete = function () {
|
var afterDelete = function () {
|
||||||
var range = getSelection(),
|
try {
|
||||||
node = range.startContainer,
|
var range = getSelection(),
|
||||||
parent;
|
node = range.startContainer,
|
||||||
if ( node.nodeType === TEXT_NODE ) {
|
parent;
|
||||||
node = node.parentNode;
|
if ( node.nodeType === TEXT_NODE ) {
|
||||||
}
|
node = node.parentNode;
|
||||||
// If focussed in empty inline element
|
|
||||||
if ( node.isInline() && !node.textContent ) {
|
|
||||||
do {
|
|
||||||
parent = node.parentNode;
|
|
||||||
} while ( parent.isInline() &&
|
|
||||||
!parent.textContent && ( node = parent ) );
|
|
||||||
range.setStart( parent,
|
|
||||||
indexOf.call( parent.childNodes, node ) );
|
|
||||||
range.collapse( true );
|
|
||||||
parent.removeChild( node );
|
|
||||||
if ( !parent.isBlock() ) {
|
|
||||||
parent = parent.getPreviousBlock();
|
|
||||||
}
|
}
|
||||||
parent.fixCursor();
|
// If focussed in empty inline element
|
||||||
range.moveBoundariesDownTree();
|
if ( node.isInline() && !node.textContent ) {
|
||||||
setSelection( range );
|
do {
|
||||||
updatePath( range );
|
parent = node.parentNode;
|
||||||
|
} while ( parent.isInline() &&
|
||||||
|
!parent.textContent && ( node = parent ) );
|
||||||
|
range.setStart( parent,
|
||||||
|
indexOf.call( parent.childNodes, node ) );
|
||||||
|
range.collapse( true );
|
||||||
|
parent.removeChild( node );
|
||||||
|
if ( !parent.isBlock() ) {
|
||||||
|
parent = parent.getPreviousBlock();
|
||||||
|
}
|
||||||
|
parent.fixCursor();
|
||||||
|
range.moveBoundariesDownTree();
|
||||||
|
setSelection( range );
|
||||||
|
updatePath( range );
|
||||||
|
}
|
||||||
|
} catch ( error ) {
|
||||||
|
editor.didError( error );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1672,7 +1690,11 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
win.editor = {
|
win.editor = editor = {
|
||||||
|
|
||||||
|
didError: function ( error ) {
|
||||||
|
console.log( error );
|
||||||
|
},
|
||||||
|
|
||||||
_setPlaceholderTextNode: setPlaceholderTextNode,
|
_setPlaceholderTextNode: setPlaceholderTextNode,
|
||||||
|
|
||||||
|
@ -1957,7 +1979,7 @@
|
||||||
// --- Initialise ---
|
// --- Initialise ---
|
||||||
|
|
||||||
body.setAttribute( 'contenteditable', 'true' );
|
body.setAttribute( 'contenteditable', 'true' );
|
||||||
win.editor.setHTML( '' );
|
editor.setHTML( '' );
|
||||||
|
|
||||||
if ( win.onEditorLoad ) {
|
if ( win.onEditorLoad ) {
|
||||||
win.onEditorLoad( win.editor );
|
win.onEditorLoad( win.editor );
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* Copyright © 2011-2012 by Neil Jenkins. Licensed under the MIT license. */
|
/* Copyright © 2011-2012 by Neil Jenkins. Licensed under the MIT license. */
|
||||||
|
|
||||||
( function ( undefined ) {
|
( function () {
|
||||||
|
|
||||||
/*jshint strict: false */
|
/*jshint strict: false */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue