src/trumbowyg.js
function (force, full, keepRange) {
            var t = this;
            t.saveRange();
            t.syncCode(force);

            if (t.o.semantic) {
                t.semanticTag('b', t.o.semanticKeepAttributes);
                t.semanticTag('i', t.o.semanticKeepAttributes);
                t.semanticTag('s', t.o.semanticKeepAttributes);
                t.semanticTag('strike', t.o.semanticKeepAttributes);

                if (full) {
                    var inlineElementsSelector = t.o.inlineElementsSelector,
                        blockElementsSelector = ':not(' + inlineElementsSelector + ')';

                    // Wrap text nodes in span for easier processing
                    t.$ed.contents().filter(function () {
                        return this.nodeType === 3 && this.nodeValue.trim().length > 0;
                    }).wrap('<span data-tbw/>');

                    // Wrap groups of inline elements in paragraphs (recursive)
                    var wrapInlinesInParagraphsFrom = function ($from) {
                        if ($from.length !== 0) {
                            var $finalParagraph = $from.nextUntil(blockElementsSelector).addBack().wrapAll('<p/>').parent(),
                                $nextElement = $finalParagraph.nextAll(inlineElementsSelector).first();
                            $finalParagraph.next('br').remove();
                            wrapInlinesInParagraphsFrom($nextElement);
                        }
                    };
                    wrapInlinesInParagraphsFrom(t.$ed.children(inlineElementsSelector).first());

                    t.semanticTag('div', true);

                    // Unwrap paragraphs content, containing nothing useful
                    t.$ed.find('p').filter(function () {
                        // Don't remove currently being edited element
                        if (t.range && this === t.range.startContainer) {
                            return false;
                        }
                        return $(this).text().trim().length === 0 && $(this).children().not('br,span').length === 0;
                    }).contents().unwrap();

                    // Get rid of temporary span's
                    $('[data-tbw]', t.$ed).contents().unwrap();

                    // Remove empty <p>
                    t.$ed.find('p:empty').remove();
                }

                if (!keepRange) {
                    t.restoreRange();
                }

                t.syncTextarea();
            }
        }
function (force, full, keepRange) {
            var t = this;
            t.saveRange();
            t.syncCode(force);

            if (t.o.semantic) {
                t.semanticTag('b', t.o.semanticKeepAttributes);
                t.semanticTag('i', t.o.semanticKeepAttributes);
                t.semanticTag('s', t.o.semanticKeepAttributes);
                t.semanticTag('strike', t.o.semanticKeepAttributes);

                if (full) {
                    var inlineElementsSelector = t.o.inlineElementsSelector,
                        blockElementsSelector = ':not(' + inlineElementsSelector + ')';

                    // Wrap text nodes in span for easier processing
                    t.$ed.contents().filter(function () {
                        return this.nodeType === 3 && this.nodeValue.trim().length > 0;
                    }).wrap('<span data-tbw/>');

                    // Wrap groups of inline elements in paragraphs (recursive)
                    var wrapInlinesInParagraphsFrom = function ($from) {
                        if ($from.length !== 0) {
                            var $finalParagraph = $from.nextUntil(blockElementsSelector).addBack().wrapAll('<p/>').parent(),
                                $nextElement = $finalParagraph.nextAll(inlineElementsSelector).first();
                            $finalParagraph.next('br').remove();
                            wrapInlinesInParagraphsFrom($nextElement);
                        }
                    };
                    wrapInlinesInParagraphsFrom(t.$ed.children(inlineElementsSelector).first());

                    t.semanticTag('div', true);

                    // Unwrap paragraphs content, containing nothing useful
                    t.$ed.find('p').filter(function () {
                        // Don't remove currently being edited element
                        if (t.range && this === t.range.startContainer) {
                            return false;
                        }
                        return $(this).text().trim().length === 0 && $(this).children().not('br,span').length === 0;
                    }).contents().unwrap();

                    // Get rid of temporary span's
                    $('[data-tbw]', t.$ed).contents().unwrap();

                    // Remove empty <p>
                    t.$ed.find('p:empty').remove();
                }

                if (!keepRange) {
                    t.restoreRange();
                }

                t.syncTextarea();
            }
        }
function ( force , full , keepRange ) { var t = this ; t . saveRange ( ) ; t . syncCode ( force ) ; if ( t . o . semantic ) { t . semanticTag ( 'b' , t . o . semanticKeepAttributes ) ; t . semanticTag ( 'i' , t . o . semanticKeepAttributes ) ; t . semanticTag ( 's' , t . o . semanticKeepAttributes ) ; t . semanticTag ( 'strike' , t . o . semanticKeepAttributes ) ; if ( full ) { var inlineElementsSelector = t . o . inlineElementsSelector , blockElementsSelector = ':not(' + inlineElementsSelector + ')' ; // Wrap text nodes in span for easier processing t . $ed . contents ( ) . filter ( function ( ) { return this . nodeType === 3 && this . nodeValue . trim ( ) . length > 0 ; } ) . wrap ( '<span data-tbw/>' ) ; // Wrap groups of inline elements in paragraphs (recursive) var wrapInlinesInParagraphsFrom = function ( $from ) { if ( $from . length !== 0 ) { var $finalParagraph = $from . nextUntil ( blockElementsSelector ) . addBack ( ) . wrapAll ( '<p/>' ) . parent ( ) , $nextElement = $finalParagraph . nextAll ( inlineElementsSelector ) . first ( ) ; $finalParagraph . next ( 'br' ) . remove ( ) ; wrapInlinesInParagraphsFrom ( $nextElement ) ; } } ; wrapInlinesInParagraphsFrom ( t . $ed . children ( inlineElementsSelector ) . first ( ) ) ; t . semanticTag ( 'div' , true ) ; // Unwrap paragraphs content, containing nothing useful t . $ed . find ( 'p' ) . filter ( function ( ) { // Don't remove currently being edited element if ( t . range && this === t . range . startContainer ) { return false ; } return $ ( this ) . text ( ) . trim ( ) . length === 0 && $ ( this ) . children ( ) . not ( 'br,span' ) . length === 0 ; } ) . contents ( ) . unwrap ( ) ; // Get rid of temporary span's $ ( '[data-tbw]' , t . $ed ) . contents ( ) . unwrap ( ) ; // Remove empty <p> t . $ed . find ( 'p:empty' ) . remove ( ) ; } if ( ! keepRange ) { t . restoreRange ( ) ; } t . syncTextarea ( ) ; } }
Analyse and update to semantic code @param force : force to sync code from textarea @param full  : wrap text nodes in <p> @param keepRange  : leave selection range as it is
Analyse and update to semantic code