diff --git a/Demo.html b/Demo.html index da73d4e..8b5d6d3 100644 --- a/Demo.html +++ b/Demo.html @@ -128,7 +128,15 @@ return; } // Create Squire instance - editor = new Squire( doc ); + editor = new Squire( doc, { + blockTag: 'p', + blockAttributes: {'class': 'paragraph'}, + tagAttributes: { + ul: {'class': 'UL'}, + ol: {'class': 'OL'}, + li: {'class': 'listItem'} + } + }); // Add styles to frame var style = doc.createElement( 'style' ); style.type = 'text/css'; diff --git a/README.md b/README.md index 4001675..689802c 100644 --- a/README.md +++ b/README.md @@ -43,9 +43,16 @@ If you load the library into a top-level document (rather than an iframe), it wi ### Setting the default block style -By default, the editor will use a `
` for blank lines, as most users have been conditioned by Microsoft Word to expect Enter to act like pressing return on a typewriter. If you would like to use `

` 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';`. +By default, the editor will use a `

` for blank lines, as most users have been conditioned by Microsoft Word to expect Enter to act like pressing return on a typewriter. If you would like to use `

` tags (or anything else) for the default block type instead, you can pass a config object as the second parameter to the squire constructor. You can also +pass a set of attributes to apply to each default block: -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;' }`. + var editor = new Squire( document, { + blockTag: 'P', + blockAttributes: { style: 'font-size: 16px;' } + }) + +If using the simple setup, call `editor.setConfig(…);` with your +config object instead. Be sure to do this *before* calling `editor.setHTML()`. ### Determining button state diff --git a/build/squire-raw.js b/build/squire-raw.js index 5e62c10..2e25feb 100644 --- a/build/squire-raw.js +++ b/build/squire-raw.js @@ -222,7 +222,7 @@ function getNearest ( node, tag, attributes ) { function getPath ( node ) { var parent = node.parentNode, - path, id, className, classNames; + path, id, className, classNames, dir; if ( !parent || node.nodeType !== ELEMENT_NODE ) { path = parent ? getPath( parent ) : ''; } else { @@ -237,6 +237,9 @@ function getPath ( node ) { path += '.'; path += classNames.join( '.' ); } + if ( dir = node.dir ) { + path += '[dir=' + dir + ']'; + } } return path; } @@ -300,14 +303,11 @@ function fixCursor ( node ) { // cursor to appear. var doc = node.ownerDocument, root = node, - fixer, child, instance; + fixer, child; if ( node.nodeName === 'BODY' ) { if ( !( child = node.firstChild ) || child.nodeName === 'BR' ) { - instance = getSquireInstance( doc ); - fixer = instance ? - instance.createDefaultBlock() : - createElement( doc, 'DIV' ); + fixer = getSquireInstance( doc ).createDefaultBlock(); if ( child ) { node.replaceChild( fixer, child ); } @@ -373,17 +373,25 @@ function fixContainer ( container ) { var children = container.childNodes, doc = container.ownerDocument, wrapper = null, - i, l, child, isBR; + i, l, child, isBR, + config = getSquireInstance( doc )._config; + for ( i = 0, l = children.length; i < l; i += 1 ) { child = children[i]; isBR = child.nodeName === 'BR'; if ( !isBR && isInline( child ) ) { - if ( !wrapper ) { wrapper = createElement( doc, 'DIV' ); } + if ( !wrapper ) { + wrapper = createElement( doc, + config.blockTag, config.blockAttributes ); + } wrapper.appendChild( child ); i -= 1; l -= 1; } else if ( isBR || wrapper ) { - if ( !wrapper ) { wrapper = createElement( doc, 'DIV' ); } + if ( !wrapper ) { + wrapper = createElement( doc, + config.blockTag, config.blockAttributes ); + } fixCursor( wrapper ); if ( isBR ) { container.replaceChild( wrapper, child ); @@ -1438,6 +1446,20 @@ function getSquireInstance ( doc ) { return null; } +function mergeObjects ( base, extras ) { + var prop, value; + if ( !base ) { + base = {}; + } + for ( prop in extras ) { + value = extras[ prop ]; + base[ prop ] = ( value && value.constructor === Object ) ? + mergeObjects( base[ prop ], value ) : + value; + } + return base; +} + function Squire ( doc, config ) { var win = doc.defaultView; var body = doc.body; @@ -1489,9 +1511,6 @@ function Squire ( doc, config ) { this.addEventListener( 'keyup', this._keyUpDetectChange ); } - 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. this._awaitingPaste = false; @@ -1554,11 +1573,22 @@ function Squire ( doc, config ) { var proto = Squire.prototype; proto.setConfig = function ( config ) { - for ( var prop in config ) { - if ( config.hasOwnProperty( prop ) ) { - this[ prop ] = config[ prop ]; + config = mergeObjects({ + blockTag: 'DIV', + blockAttributes: null, + tagAttributes: { + blockquote: null, + ul: null, + ol: null, + li: null } - } + }, config ); + + // Users may specify block tag in lower case + config.blockTag = config.blockTag.toUpperCase(); + + this._config = config; + return this; }; @@ -1567,9 +1597,9 @@ proto.createElement = function ( tag, props, children ) { }; proto.createDefaultBlock = function ( children ) { + var config = this._config; return fixCursor( - this.createElement( - this.defaultBlockTag, this.defaultBlockProperties, children ) + this.createElement( config.blockTag, config.blockAttributes, children ) ); }; @@ -2352,11 +2382,12 @@ var tagAfterSplit = { var splitBlock = function ( self, block, node, offset ) { var splitTag = tagAfterSplit[ block.nodeName ], splitProperties = null, - nodeAfterSplit = split( node, offset, block.parentNode ); + nodeAfterSplit = split( node, offset, block.parentNode ), + config = self._config; if ( !splitTag ) { - splitTag = self.defaultBlockTag; - splitProperties = self.defaultBlockProperties; + splitTag = config.blockTag; + splitProperties = config.blockAttributes; } // Make sure the new node is the correct type. @@ -2364,7 +2395,6 @@ var splitBlock = function ( self, block, node, offset ) { block = createElement( nodeAfterSplit.ownerDocument, splitTag, splitProperties ); if ( nodeAfterSplit.dir ) { - block.className = nodeAfterSplit.dir === 'rtl' ? 'dir-rtl' : ''; block.dir = nodeAfterSplit.dir; } replaceWith( nodeAfterSplit, block ); @@ -2451,9 +2481,10 @@ proto.modifyBlocks = function ( modify, range ) { }; var increaseBlockQuoteLevel = function ( frag ) { - return this.createElement( 'BLOCKQUOTE', [ - frag - ]); + return this.createElement( 'BLOCKQUOTE', + this._config.tagAttributes.blockquote, [ + frag + ]); }; var decreaseBlockQuoteLevel = function ( frag ) { @@ -2481,15 +2512,19 @@ var removeBlockQuote = function (/* frag */) { var makeList = function ( self, frag, type ) { var walker = getBlockWalker( frag ), - node, tag, prev, newLi; + node, tag, prev, newLi, + tagAttributes = self._config.tagAttributes, + listAttrs = tagAttributes[ type.toLowerCase() ], + listItemAttrs = tagAttributes.li; while ( node = walker.nextNode() ) { tag = node.parentNode.nodeName; if ( tag !== 'LI' ) { - newLi = self.createElement( 'LI', { - 'class': node.dir === 'rtl' ? 'dir-rtl' : undefined, - dir: node.dir || undefined - }); + newLi = self.createElement( 'LI', listItemAttrs ); + if ( node.dir ) { + newLi.dir = node.dir; + } + // Have we replaced the previous block with a new