0
Fork 0
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:
Neil Jenkins 2013-01-24 11:54:44 +11:00
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

View file

@ -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 );

View file

@ -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 */