0
Fork 0
mirror of https://github.com/fastmail/Squire.git synced 2024-12-22 07:13:08 -05:00

If all text in inline tag deleted, remove tag.

This commit is contained in:
Neil Jenkins 2012-07-02 12:41:38 +10:00
parent 819ddb296e
commit e4b5ea6ee8
5 changed files with 84 additions and 44 deletions

View file

@ -1,10 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HTML Editor Test</title>
<style type="text/css" media="screen">
body {
<meta charset="UTF-8">
<title>HTML Editor Test</title>
<style type="text/css" media="screen">
body {
position: relative;
margin: 0 auto;
padding: 50px;
@ -15,33 +15,33 @@
h1 {
font-size: 1.95em;
}
iframe {
border: 1px solid #888;
}
span {
cursor: pointer;
text-decoration: underline;
}
p {
margin: 5px 0;
}
</style>
<!--[if IE 8]>
iframe {
border: 1px solid #888;
}
span {
cursor: pointer;
text-decoration: underline;
}
p {
margin: 5px 0;
}
</style>
<!--[if IE 8]>
<script type="text/javascript" src="build/ie8.js"></script>
<![endif]-->
<script type="text/javascript" charset="utf-8">
var editor;
document.addEventListener( 'click', function ( e ) {
var id = e.target.id,
value;
if ( id && editor && editor[ id ] ) {
if ( e.target.className === 'prompt' ) {
value = prompt( 'Value:' );
}
editor[ id ]( value );
}
}, false );
</script>
<script type="text/javascript" charset="utf-8">
var editor;
document.addEventListener( 'click', function ( e ) {
var id = e.target.id,
value;
if ( id && editor && editor[ id ] ) {
if ( e.target.className === 'prompt' ) {
value = prompt( 'Value:' );
}
editor[ id ]( value );
}
}, false );
</script>
</head>
<body>
<h1>HTML Editor Test</h1>
@ -65,17 +65,17 @@
<span id="makeLink" class="prompt">Link</span>
</p>
<p>
<span id="increaseQuoteLevel">Quote</span>
<span id="decreaseQuoteLevel">Dequote</span>
<span id="increaseQuoteLevel">Quote</span>
<span id="decreaseQuoteLevel">Dequote</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span id="makeUnorderedList">List</span>
<span id="removeList">Unlist</span>
<span id="makeUnorderedList">List</span>
<span id="removeList">Unlist</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span id="insertImage" class="prompt">Insert image</span>
<span id="setHTML" class="prompt">Set HTML</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span id="undo">Undo</span>
<span id="redo">Redo</span>
<span id="undo">Undo</span>
<span id="redo">Redo</span>
</p>
</header>
<iframe src="build/document.html" onload="top.editor=this.contentWindow.editor" width="500" height="500"></iframe>

View file

@ -19,7 +19,7 @@ Unlike other HTML5 rich text editors, Squire was written as a component for writ
### Powerful ###
Squire provides an engine that handles the heavy work for you, making it easy to
Squire provides an engine that handles the heavy work for you, making it easy to
add extra features. With the `changeFormat` method you can easily add or remove any inline formatting you wish. And the `modifyBlocks` method can be used to make complicated block-level changes in a relatively easy manner.
If you need more commands than in the simple API, I suggest you check out the source code (it's not very long), and see how a lot of the other API methods are implemented in terms of these two methods.
@ -37,7 +37,7 @@ Installation and usage
4. In your JS, attach an event listener to the `load` event of the iframe. When
this fires you can grab a reference to the editor object through
`iframe.contentWindow.editor`.
5. Use the API below with the `editor` object to set and get data and integrate
5. Use the API below with the `editor` object to set and get data and integrate
with your application or framework.
License
@ -66,7 +66,7 @@ Attach an event listener to the editor. The handler can be either a function or
#### Parameters ####
* **type**: The event to listen for. e.g. 'focus'.
* **handler**: The callback function to invoke
* **handler**: The callback function to invoke
#### Returns ####

File diff suppressed because one or more lines are too long

View file

@ -354,7 +354,7 @@
range.setStart( _range.startContainer, _range.startOffset );
range.setEnd( _range.endContainer, _range.endOffset );
collapsed = range.collapsed;
range.moveBoundariesDownTree();
if ( collapsed ) {
range.collapse( true );
@ -1235,7 +1235,7 @@
while ( node = node.getNextBlock() ) {
node.fixCursor();
}
fireEvent( 'willPaste', {
fragment: frag,
preventDefault: function () {
@ -1288,6 +1288,38 @@
};
};
// If you delete the content inside a span with a font styling, Webkit will
// replace it with a <font> tag (!). If you delete all the text inside a
// 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.
var afterDelete = function () {
var range = getSelection(),
node = range.startContainer,
parent;
node = node.nodeType === TEXT_NODE ?
node.length ? null : node.parentNode :
node.isInline() && !node.textContent ? node : null;
// If focussed in empty inline element
if ( node ) {
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();
range.moveBoundariesDownTree();
setSelection( range );
updatePath( range );
}
};
var keyHandlers = {
enter: function ( event ) {
// We handle this ourselves
@ -1469,7 +1501,11 @@
updatePath( range, true );
}
}
// All other cases can be safely left to the browser (I hope!).
// Otherwise, leave to browser but check afterwards whether it has
// left behind an empty inline tag.
else {
setTimeout( afterDelete, 0 );
}
},
'delete': function ( event ) {
var range = getSelection();
@ -1501,7 +1537,11 @@
updatePath( range, true );
}
}
// All other cases can be safely left to the browser (I hope!).
// Otherwise, leave to browser but check afterwards whether it has
// left behind an empty inline tag.
else {
setTimeout( afterDelete, 0 );
}
},
space: function () {
var range = getSelection();

View file

@ -31,7 +31,7 @@ var every = function ( nodeList, fn ) {
var $False = function () { return false; };
var $True = function () { return true; };
var inlineNodeNames = /^(?:A(?:BBR|CRONYM)?|B(?:R|D[IO])?|C(?:ITE|ODE)|D(?:FN|EL)|EM|HR|I(?:NPUT|MG|NS)?|KBD|Q|R(?:P|T|UBY)|S(?:U[BP]|PAN|TRONG|AMP)|U)$/;
var inlineNodeNames = /^(?:A(?:BBR|CRONYM)?|B(?:R|D[IO])?|C(?:ITE|ODE)|D(?:FN|EL)|EM|FONT|HR|I(?:NPUT|MG|NS)?|KBD|Q|R(?:P|T|UBY)|S(?:U[BP]|PAN|TRONG|AMP)|U)$/;
var leafNodeNames = {
BR: 1,