mirror of
https://github.com/fastmail/Squire.git
synced 2025-01-03 05:00:13 -05:00
parent
b69a1635de
commit
249ea93c13
4 changed files with 66 additions and 132 deletions
|
@ -41,6 +41,12 @@ Advanced usage
|
|||
|
||||
If you load the library into a top-level document (rather than an iframe), it will not turn the page into an editable document, but will instead add a function named `Squire` to the global scope. Call `new Squire( document )`, with the `document` from an iframe to instantiate multiple rich text areas on the same page efficiently.
|
||||
|
||||
### Setting the default block style
|
||||
|
||||
By default, the editor will use a `<div>` for blank lines, as most users have been conditioned by Microsoft Word to expect <kbd>Enter</kbd> to act like pressing <kbd>return</kbd> on a typewriter. If you would like to use `<p>` tags (or anything else) for the default block type instead, then after calling `var editor = new Squire( document )` (or getting your reference to the ready-made `editor` instance if using the simple setup), set `editor.defaultBlockTag = 'P';`.
|
||||
|
||||
You can also set an object of attributes to apply to each default block node by setting the *defaultBlockProperties* property, e.g. `editor.defaultBlockProperties = { style: 'font-size: 16px;' }`.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
|
|
|
@ -1131,7 +1131,8 @@ function Squire ( doc ) {
|
|||
this.addEventListener( 'keyup', this._keyUpDetectChange );
|
||||
}
|
||||
|
||||
this.defaultBlockProperties = undefined;
|
||||
this.defaultBlockTag = 'DIV';
|
||||
this.defaultBlockProperties = null;
|
||||
|
||||
// IE sometimes fires the beforepaste event twice; make sure it is not run
|
||||
// again before our after paste function is called.
|
||||
|
@ -1191,7 +1192,8 @@ proto.createElement = function ( tag, props, children ) {
|
|||
|
||||
proto.createDefaultBlock = function ( children ) {
|
||||
return fixCursor(
|
||||
this.createElement( 'DIV', this.defaultBlockProperties, children )
|
||||
this.createElement(
|
||||
this.defaultBlockTag, this.defaultBlockProperties, children )
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1902,29 +1904,29 @@ proto.changeFormat = function ( add, remove, range, partial ) {
|
|||
// --- Block formatting ---
|
||||
|
||||
var tagAfterSplit = {
|
||||
DIV: 'DIV',
|
||||
PRE: 'DIV',
|
||||
H1: 'DIV',
|
||||
H2: 'DIV',
|
||||
H3: 'DIV',
|
||||
H4: 'DIV',
|
||||
H5: 'DIV',
|
||||
H6: 'DIV',
|
||||
P: 'DIV',
|
||||
DT: 'DD',
|
||||
DD: 'DT',
|
||||
LI: 'LI'
|
||||
};
|
||||
|
||||
var splitBlock = function ( block, node, offset ) {
|
||||
var splitBlock = function ( self, block, node, offset ) {
|
||||
var splitTag = tagAfterSplit[ block.nodeName ],
|
||||
splitProperties = null,
|
||||
nodeAfterSplit = split( node, offset, block.parentNode );
|
||||
|
||||
if ( !splitTag ) {
|
||||
splitTag = self.defaultBlockTag;
|
||||
splitProperties = self.defaultBlockProperties;
|
||||
}
|
||||
|
||||
// Make sure the new node is the correct type.
|
||||
if ( nodeAfterSplit.nodeName !== splitTag ) {
|
||||
block = createElement( nodeAfterSplit.ownerDocument, splitTag );
|
||||
block.className = nodeAfterSplit.dir === 'rtl' ? 'dir-rtl' : '';
|
||||
block.dir = nodeAfterSplit.dir;
|
||||
if ( !hasTagAttributes( nodeAfterSplit, splitTag, splitProperties ) ) {
|
||||
block = createElement( nodeAfterSplit.ownerDocument,
|
||||
splitTag, splitProperties );
|
||||
if ( nodeAfterSplit.dir ) {
|
||||
block.className = nodeAfterSplit.dir === 'rtl' ? 'dir-rtl' : '';
|
||||
block.dir = nodeAfterSplit.dir;
|
||||
}
|
||||
replaceWith( nodeAfterSplit, block );
|
||||
block.appendChild( empty( nodeAfterSplit ) );
|
||||
nodeAfterSplit = block;
|
||||
|
@ -2533,8 +2535,8 @@ var cleanupBRs = function ( root ) {
|
|||
|
||||
proto._ensureBottomLine = function () {
|
||||
var body = this._body,
|
||||
div = body.lastChild;
|
||||
if ( !div || div.nodeName !== 'DIV' || !isBlock( div ) ) {
|
||||
last = body.lastChild;
|
||||
if ( !last || last.nodeName !== this.defaultBlockTag || !isBlock( last ) ) {
|
||||
body.appendChild( this.createDefaultBlock() );
|
||||
}
|
||||
};
|
||||
|
@ -2764,7 +2766,7 @@ var afterDelete = function ( self, range ) {
|
|||
|
||||
var keyHandlers = {
|
||||
enter: function ( self, event, range ) {
|
||||
var block, parent, tag, splitTag, nodeAfterSplit;
|
||||
var block, parent, nodeAfterSplit;
|
||||
|
||||
// We handle this ourselves
|
||||
event.preventDefault();
|
||||
|
@ -2784,15 +2786,10 @@ var keyHandlers = {
|
|||
}
|
||||
|
||||
block = getStartBlockOfRange( range );
|
||||
if ( block && ( parent = getNearest( block, 'LI' ) ) ) {
|
||||
block = parent;
|
||||
}
|
||||
tag = block ? block.nodeName : 'DIV';
|
||||
splitTag = tagAfterSplit[ tag ];
|
||||
|
||||
// If this is a malformed bit of document, just play it safe
|
||||
// and insert a <br>.
|
||||
if ( !block ) {
|
||||
// If this is a malformed bit of document or in a table;
|
||||
// just play it safe and insert a <br>.
|
||||
if ( !block || /^T[HD]$/.test( block.nodeName ) ) {
|
||||
insertNodeInRange( range, self.createElement( 'BR' ) );
|
||||
range.collapse( false );
|
||||
self.setSelection( range );
|
||||
|
@ -2800,43 +2797,9 @@ var keyHandlers = {
|
|||
return;
|
||||
}
|
||||
|
||||
// We need to wrap the contents in divs.
|
||||
var splitNode = range.startContainer,
|
||||
splitOffset = range.startOffset,
|
||||
replacement;
|
||||
if ( !splitTag ) {
|
||||
// If the selection point is inside the block, we're going to
|
||||
// rewrite it so our saved reference points won't be valid.
|
||||
// Pick a node at a deeper point in the tree to avoid this.
|
||||
if ( splitNode === block ) {
|
||||
splitNode = splitOffset ?
|
||||
splitNode.childNodes[ splitOffset - 1 ] : null;
|
||||
splitOffset = 0;
|
||||
if ( splitNode ) {
|
||||
if ( splitNode.nodeName === 'BR' ) {
|
||||
splitNode = splitNode.nextSibling;
|
||||
} else {
|
||||
splitOffset = getLength( splitNode );
|
||||
}
|
||||
if ( !splitNode || splitNode.nodeName === 'BR' ) {
|
||||
replacement = fixCursor( self.createElement( 'DIV' ) );
|
||||
if ( splitNode ) {
|
||||
block.replaceChild( replacement, splitNode );
|
||||
} else {
|
||||
block.appendChild( replacement );
|
||||
}
|
||||
splitNode = replacement;
|
||||
}
|
||||
}
|
||||
}
|
||||
fixContainer( block );
|
||||
splitTag = 'DIV';
|
||||
if ( !splitNode ) {
|
||||
splitNode = block.firstChild;
|
||||
}
|
||||
range.setStart( splitNode, splitOffset );
|
||||
range.setEnd( splitNode, splitOffset );
|
||||
block = getStartBlockOfRange( range );
|
||||
// If in a list, we'll split the LI instead.
|
||||
if ( parent = getNearest( block, 'LI' ) ) {
|
||||
block = parent;
|
||||
}
|
||||
|
||||
if ( !block.textContent ) {
|
||||
|
@ -2851,7 +2814,8 @@ var keyHandlers = {
|
|||
}
|
||||
|
||||
// Otherwise, split at cursor point.
|
||||
nodeAfterSplit = splitBlock( block, splitNode, splitOffset );
|
||||
nodeAfterSplit = splitBlock( self, block,
|
||||
range.startContainer, range.startOffset );
|
||||
|
||||
// Clean up any empty inlines if we hit enter at the beginning of the
|
||||
// block
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -53,7 +53,8 @@ function Squire ( doc ) {
|
|||
this.addEventListener( 'keyup', this._keyUpDetectChange );
|
||||
}
|
||||
|
||||
this.defaultBlockProperties = undefined;
|
||||
this.defaultBlockTag = 'DIV';
|
||||
this.defaultBlockProperties = null;
|
||||
|
||||
// IE sometimes fires the beforepaste event twice; make sure it is not run
|
||||
// again before our after paste function is called.
|
||||
|
@ -113,7 +114,8 @@ proto.createElement = function ( tag, props, children ) {
|
|||
|
||||
proto.createDefaultBlock = function ( children ) {
|
||||
return fixCursor(
|
||||
this.createElement( 'DIV', this.defaultBlockProperties, children )
|
||||
this.createElement(
|
||||
this.defaultBlockTag, this.defaultBlockProperties, children )
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -824,29 +826,29 @@ proto.changeFormat = function ( add, remove, range, partial ) {
|
|||
// --- Block formatting ---
|
||||
|
||||
var tagAfterSplit = {
|
||||
DIV: 'DIV',
|
||||
PRE: 'DIV',
|
||||
H1: 'DIV',
|
||||
H2: 'DIV',
|
||||
H3: 'DIV',
|
||||
H4: 'DIV',
|
||||
H5: 'DIV',
|
||||
H6: 'DIV',
|
||||
P: 'DIV',
|
||||
DT: 'DD',
|
||||
DD: 'DT',
|
||||
LI: 'LI'
|
||||
};
|
||||
|
||||
var splitBlock = function ( block, node, offset ) {
|
||||
var splitBlock = function ( self, block, node, offset ) {
|
||||
var splitTag = tagAfterSplit[ block.nodeName ],
|
||||
splitProperties = null,
|
||||
nodeAfterSplit = split( node, offset, block.parentNode );
|
||||
|
||||
if ( !splitTag ) {
|
||||
splitTag = self.defaultBlockTag;
|
||||
splitProperties = self.defaultBlockProperties;
|
||||
}
|
||||
|
||||
// Make sure the new node is the correct type.
|
||||
if ( nodeAfterSplit.nodeName !== splitTag ) {
|
||||
block = createElement( nodeAfterSplit.ownerDocument, splitTag );
|
||||
block.className = nodeAfterSplit.dir === 'rtl' ? 'dir-rtl' : '';
|
||||
block.dir = nodeAfterSplit.dir;
|
||||
if ( !hasTagAttributes( nodeAfterSplit, splitTag, splitProperties ) ) {
|
||||
block = createElement( nodeAfterSplit.ownerDocument,
|
||||
splitTag, splitProperties );
|
||||
if ( nodeAfterSplit.dir ) {
|
||||
block.className = nodeAfterSplit.dir === 'rtl' ? 'dir-rtl' : '';
|
||||
block.dir = nodeAfterSplit.dir;
|
||||
}
|
||||
replaceWith( nodeAfterSplit, block );
|
||||
block.appendChild( empty( nodeAfterSplit ) );
|
||||
nodeAfterSplit = block;
|
||||
|
@ -1455,8 +1457,8 @@ var cleanupBRs = function ( root ) {
|
|||
|
||||
proto._ensureBottomLine = function () {
|
||||
var body = this._body,
|
||||
div = body.lastChild;
|
||||
if ( !div || div.nodeName !== 'DIV' || !isBlock( div ) ) {
|
||||
last = body.lastChild;
|
||||
if ( !last || last.nodeName !== this.defaultBlockTag || !isBlock( last ) ) {
|
||||
body.appendChild( this.createDefaultBlock() );
|
||||
}
|
||||
};
|
||||
|
@ -1686,7 +1688,7 @@ var afterDelete = function ( self, range ) {
|
|||
|
||||
var keyHandlers = {
|
||||
enter: function ( self, event, range ) {
|
||||
var block, parent, tag, splitTag, nodeAfterSplit;
|
||||
var block, parent, nodeAfterSplit;
|
||||
|
||||
// We handle this ourselves
|
||||
event.preventDefault();
|
||||
|
@ -1706,15 +1708,10 @@ var keyHandlers = {
|
|||
}
|
||||
|
||||
block = getStartBlockOfRange( range );
|
||||
if ( block && ( parent = getNearest( block, 'LI' ) ) ) {
|
||||
block = parent;
|
||||
}
|
||||
tag = block ? block.nodeName : 'DIV';
|
||||
splitTag = tagAfterSplit[ tag ];
|
||||
|
||||
// If this is a malformed bit of document, just play it safe
|
||||
// and insert a <br>.
|
||||
if ( !block ) {
|
||||
// If this is a malformed bit of document or in a table;
|
||||
// just play it safe and insert a <br>.
|
||||
if ( !block || /^T[HD]$/.test( block.nodeName ) ) {
|
||||
insertNodeInRange( range, self.createElement( 'BR' ) );
|
||||
range.collapse( false );
|
||||
self.setSelection( range );
|
||||
|
@ -1722,43 +1719,9 @@ var keyHandlers = {
|
|||
return;
|
||||
}
|
||||
|
||||
// We need to wrap the contents in divs.
|
||||
var splitNode = range.startContainer,
|
||||
splitOffset = range.startOffset,
|
||||
replacement;
|
||||
if ( !splitTag ) {
|
||||
// If the selection point is inside the block, we're going to
|
||||
// rewrite it so our saved reference points won't be valid.
|
||||
// Pick a node at a deeper point in the tree to avoid this.
|
||||
if ( splitNode === block ) {
|
||||
splitNode = splitOffset ?
|
||||
splitNode.childNodes[ splitOffset - 1 ] : null;
|
||||
splitOffset = 0;
|
||||
if ( splitNode ) {
|
||||
if ( splitNode.nodeName === 'BR' ) {
|
||||
splitNode = splitNode.nextSibling;
|
||||
} else {
|
||||
splitOffset = getLength( splitNode );
|
||||
}
|
||||
if ( !splitNode || splitNode.nodeName === 'BR' ) {
|
||||
replacement = fixCursor( self.createElement( 'DIV' ) );
|
||||
if ( splitNode ) {
|
||||
block.replaceChild( replacement, splitNode );
|
||||
} else {
|
||||
block.appendChild( replacement );
|
||||
}
|
||||
splitNode = replacement;
|
||||
}
|
||||
}
|
||||
}
|
||||
fixContainer( block );
|
||||
splitTag = 'DIV';
|
||||
if ( !splitNode ) {
|
||||
splitNode = block.firstChild;
|
||||
}
|
||||
range.setStart( splitNode, splitOffset );
|
||||
range.setEnd( splitNode, splitOffset );
|
||||
block = getStartBlockOfRange( range );
|
||||
// If in a list, we'll split the LI instead.
|
||||
if ( parent = getNearest( block, 'LI' ) ) {
|
||||
block = parent;
|
||||
}
|
||||
|
||||
if ( !block.textContent ) {
|
||||
|
@ -1773,7 +1736,8 @@ var keyHandlers = {
|
|||
}
|
||||
|
||||
// Otherwise, split at cursor point.
|
||||
nodeAfterSplit = splitBlock( block, splitNode, splitOffset );
|
||||
nodeAfterSplit = splitBlock( self, block,
|
||||
range.startContainer, range.startOffset );
|
||||
|
||||
// Clean up any empty inlines if we hit enter at the beginning of the
|
||||
// block
|
||||
|
|
Loading…
Reference in a new issue