Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Paste rich text into content-editable div and only keep bold and italics formatting

Tags:

html

jquery

People also ask

How do I make a text field editable in HTML?

You can set the HTML5 contenteditable attribute with the value true (i.e. contentEditable="true" ) to make an element editable in HTML, such as <div> or <p> element.


Here's a working demo: http://jsfiddle.net/SJR3H/7/

$(document).ready(function(){

        $('[contenteditable]').on('paste',function(e) {

            e.preventDefault();

            var text = (e.originalEvent || e).clipboardData.getData('text/html') || prompt('Paste something..');
            var $result = $('<div></div>').append($(text));

            $(this).html($result.html());

            // replace all styles except bold and italic
            $.each($(this).find("*"), function(idx, val) {

                var $item = $(val);
                if ($item.length > 0){
                   var saveStyle = {
                        'font-weight': $item.css('font-weight'),
                        'font-style': $item.css('font-style')
                    };
                    $item.removeAttr('style')
                         .removeClass()
                         .css(saveStyle); 
                }
            });

            // remove unnecesary tags (if paste from word)
            $(this).children('style').remove();
            $(this).children('meta').remove()
            $(this).children('link').remove();

        });

    });

Later edit: http://jsfiddle.net/SJR3H/8/

i added the following lines:

$item.replaceWith(function(){
       return $("<span />", {html: $(this).html()});
});

It actually replaces all html tags with spans. There you can optionally choose to let some tags as they were in the original text (h1, p, etc), styling them as you desire.


Let begin with your code :

//on paste
var text = (e.originalEvent || e).clipboardData.getData('text/plain')


//html in clipboard are saved as Plain Unicode string , 

getData('text/plain') //return data as string,

//if MIME TYPE 'text/html' is used you will get data as html with style attributes

// insert text

document.execCommand('insertText', false, text);

//this will simply insert the text to contenteditable div.

//so there is no chance of knowing recieved text is bold / italics.

(1) we must get data as html,to get style properties: fontWeight, fontStyle.

(2) reduce html for needed style format,

(3) append to contenteditable div.

!important ::

we depend on Clipboard API, to get data.

it is not fully supported by newer browsers, please check links below:

https://developer.mozilla.org/en-US/docs/Web/Reference/Events/paste

http://caniuse.com/clipboard

so in IE Browser it wont work as expected.

the data format argument we pass in getData() is different in IE Browser:

http://msdn.microsoft.com/en-us/library/ie/ms536436(v=vs.85).aspx

so we get only plain string from getData() method, i checked in IE 9.0.8112.16421 ( not updated ) ,

i am not aware of version IE 10, 11.

I coded in a way, if getData("Html") supported in ie 10,11 code, requirements will get done.

Code works : Like @Cristi did, get all html elements.

iterate through them, instead of changing style attributes we use tags.

tags for bold & tag for italics.

Iterations are done asynchronously, because pasting large text content may hang browser.

I had Tested in Chrome, Firefox.

pasteArea.addEventListener('paste', function(e) {

    // prevent pasting text by default after event
    e.preventDefault(); 

    var clipboardData = {},
    rDataText,
    rDataHTML;

    clipboardData = e.clipboardData;
    rDataHTML = clipboardData.getData('text/html');
    rDataPText = clipboardData.getData('text/plain');


    if (rDataHTML && rDataHTML.trim().length != 0) {

        //Function Call to Handle HTML

        return false; // prevent returning text in clipboard
    }

    if (rDataPText && rDataPText.trim().length != 0) {

        //Function Call to Handle Plain String

        return false; // prevent returning text in clipboard
    }

}, false);

// Handle Plain Text
function PlainTextHandler(pText) {
    // Remove Line breaks
    // append to contenteditable div - using range.insertNode()
    // document.execCommand();  had issue in ie9 so i didn't used it 
}

// Handle HTML
function formatHtml(elem, complete) {
        var flag_italic = false;
        var flag_weight = false;
        var fontStyle;
        var fontWeight;

        if (elem.nodeType == 1) { // only pass html elements

            // get style in css 
            var CSSStyle = window.getComputedStyle(elem);
            fontStyle = CSSStyle.fontStyle;
            fontWeight = CSSStyle.fontWeight;

            // get style defined by inline
            var InlineStyle = elem.style;
            inlineFontStyle = InlineStyle['font-style'];
            inlineFontWeight = InlineStyle['font-weight'];
            if (inlineFontStyle && inlineFontStyle.trim() != '') fontStyle = inlineFontStyle;
            if (inlineFontWeight && inlineFontWeight.trim() != '') fontWeight = inlineFontWeight;

            // get style defined in MSword
            var msStyle = elem.getAttribute('style');
            if (/mso-bidi/.test(msStyle)) {
                var MSStyleObj = {};
                var styleStrArr = msStyle.split(";");
                for (i = 0; i < styleStrArr.length; i++) {
                    var temp = styleStrArr[i].split(":");
                    MSStyleObj[temp[0]] = temp[1];
                }
                fontStyle = MSStyleObj['mso-bidi-font-style'];
                fontWeight = MSStyleObj['mso-bidi-font-weight'];
            }

            if (fontStyle && fontStyle == 'italic') flag_italic = true; // flag true if italic

            if (fontWeight && (fontWeight == 'bold' || 600 <= (+fontWeight))) flag_weight = true;  // flag true if bold - 600 is semi bold

            // bold & italic are not applied via style
            // these styles are applied by appending contents in new tags string & bold
            if (flag_italic && flag_weight) {
                var strong = document.createElement('strong');
                var italic = document.createElement('i');
                strong.appendChild(italic);
                newtag = strong;
            } else {
                if (flag_italic) {
                    newtag = document.createElement('i');
                } else if (flag_weight) {
                    newtag = document.createElement('strong');
                } else {
                    // remove un wanted attributes & element
                    var tagName = elem.tagName;
                    // strong are not skipped because, by creating new unwanted attributes will be removed
                    if (tagName == 'STRONG' || tagName == 'B') {
                        newtag = document.createElement('strong');
                    } else if (tagName == 'I') {
                        newtag = document.createElement('i');
                    } else {
                        newtag = document.createElement('span');
                    }
                }
            }

            // content appended
            var elemHTML = elem.innerHTML;
            if (flag_italic && flag_weight) {
                newtag.childNodes[0].innerHTML = elemHTML;
            } else {
                newtag.innerHTML = elemHTML;
            }

            // curr element is replaced by new
            elem.parentNode.insertBefore(newtag, elem);
            elem.parentNode.removeChild(elem);
        }
        complete() // completed one iteration
    }

Fiddle: http://jsfiddle.net/aslancods/d9cfF/7/


I used this on my website for long time

$(document).on('paste','#tesc', function() {
                 setTimeout(function() {
                        asd = strip_tags( $('#tesc').html(), '<b><b/><i></i>');

                        $('#tesc').html( asd );
                },100);

        });

function strip_tags (input, allowed) {
    /* http://kevin.vanzonneveld.net*/

    if ( input == undefined ) { return ''; }

    allowed = (((allowed || "") + "").toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join(''); // making sure the allowed arg is a string containing only tags in lowercase (<a><b><c>)
    var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
        commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
    return input.replace(commentsAndPhpTags, '').replace(tags, function ($0, $1) {
        return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
    });
}