2 * formatInline scenarios for tag "B" (| = caret, |foo| = selected text)
4 * #1 caret in unformatted text:
9 * #2 unformatted text selected:
14 * #3 unformatted text selected across boundaries:
15 * ab|c <span>defg|h</span>
17 * ab<b>|c </b><span><b>defg</b>|h</span>
19 * #4 formatted text entirely selected
24 * #5 formatted text partially selected
29 * #6 formatted text selected across boundaries
30 * <span>ab|c</span> <b>de|fgh</b>
32 * <span>ab|c</span> de|<b>fgh</b>
34 (function(wysihtml5) {
35 var // Treat <b> as <strong> and vice versa
44 function _getTagNames(tagName) {
45 var alias = ALIAS_MAPPING[tagName];
46 return alias ? [tagName.toLowerCase(), alias.toLowerCase()] : [tagName.toLowerCase()];
49 function _getApplier(tagName, className, classRegExp, cssStyle, styleRegExp, container) {
50 var identifier = tagName;
53 identifier += ":" + className;
56 identifier += ":" + cssStyle;
59 if (!htmlApplier[identifier]) {
60 htmlApplier[identifier] = new wysihtml5.selection.HTMLApplier(_getTagNames(tagName), className, classRegExp, true, cssStyle, styleRegExp, container);
63 return htmlApplier[identifier];
66 wysihtml5.commands.formatInline = {
67 exec: function(composer, command, tagName, className, classRegExp, cssStyle, styleRegExp, dontRestoreSelect, noCleanup) {
68 var range = composer.selection.createRange(),
69 ownRanges = composer.selection.getOwnRanges();
71 if (!ownRanges || ownRanges.length == 0) {
74 composer.selection.getSelection().removeAllRanges();
76 _getApplier(tagName, className, classRegExp, cssStyle, styleRegExp, composer.element).toggleRange(ownRanges);
78 if (!dontRestoreSelect) {
79 range.setStart(ownRanges[0].startContainer, ownRanges[0].startOffset);
81 ownRanges[ownRanges.length - 1].endContainer,
82 ownRanges[ownRanges.length - 1].endOffset
84 composer.selection.setSelection(range);
85 composer.selection.executeAndRestore(function() {
90 } else if (!noCleanup) {
95 // Executes so that if collapsed caret is in a state and executing that state it should unformat that state
96 // It is achieved by selecting the entire state element before executing.
97 // This works on built in contenteditable inline format commands
98 execWithToggle: function(composer, command, tagName, className, classRegExp, cssStyle, styleRegExp) {
101 if (this.state(composer, command, tagName, className, classRegExp, cssStyle, styleRegExp) &&
102 composer.selection.isCollapsed() &&
103 !composer.selection.caretIsLastInSelection() &&
104 !composer.selection.caretIsFirstInSelection()
106 var state_element = that.state(composer, command, tagName, className, classRegExp)[0];
107 composer.selection.executeAndRestoreRangy(function() {
108 var parent = state_element.parentNode;
109 composer.selection.selectNode(state_element, true);
110 wysihtml5.commands.formatInline.exec(composer, command, tagName, className, classRegExp, cssStyle, styleRegExp, true, true);
113 if (this.state(composer, command, tagName, className, classRegExp, cssStyle, styleRegExp) && !composer.selection.isCollapsed()) {
114 composer.selection.executeAndRestoreRangy(function() {
115 wysihtml5.commands.formatInline.exec(composer, command, tagName, className, classRegExp, cssStyle, styleRegExp, true, true);
118 wysihtml5.commands.formatInline.exec(composer, command, tagName, className, classRegExp, cssStyle, styleRegExp);
123 state: function(composer, command, tagName, className, classRegExp, cssStyle, styleRegExp) {
124 var doc = composer.doc,
125 aliasTagName = ALIAS_MAPPING[tagName] || tagName,
126 ownRanges, isApplied;
128 // Check whether the document contains a node with the desired tagName
129 if (!wysihtml5.dom.hasElementWithTagName(doc, tagName) &&
130 !wysihtml5.dom.hasElementWithTagName(doc, aliasTagName)) {
134 // Check whether the document contains a node with the desired className
135 if (className && !wysihtml5.dom.hasElementWithClassName(doc, className)) {
139 ownRanges = composer.selection.getOwnRanges();
141 if (!ownRanges || ownRanges.length === 0) {
145 isApplied = _getApplier(tagName, className, classRegExp, cssStyle, styleRegExp, composer.element).isAppliedToRange(ownRanges);
147 return (isApplied && isApplied.elements) ? isApplied.elements : false;