1. #1
    Sencha User jagadeesha's Avatar
    Join Date
    Jan 2011
    Location
    Bangalore , Trianz
    Posts
    10
    Vote Rating
    0
    jagadeesha has a little shameless behaviour in the past

      0  

    Default Plugin : Smart selection of text

    Plugin : Smart selection of text


    Below plugin helps you to search and highlight the selected text by mouse.

    1. User can use shortcut key's / buttons to enable/disable this feature
    2. User can configure the highlight class that needs to be applied for selected text

    check out. there are many more configurable features included.!!!!!!!!!

    Below are the screenshots for Example usage of this plugin and this plugin in action .
    exampleUsage.pngselect_highlight.jpg
    Code:
    /** * Class which performs the select functionality on user selected text
     * @class UTP.ux.smartTextHighlight
     * @extends Object
     */
    UTP.ux.smartTextHighlight = Ext.extend(Object, {
                /**
                 * @cfg highlightCls highlight class which should be added to highlight the selected text
                 * @type String
                 * @default smartTextHighlight
                 */
                highlightCls : 'smartTextHighlight',
                
                compRef : '',
                
                /**
                 * shortCutKey
                 * short cut key used for enable/disabling smartSelction
                 * @type array
                 */
                shortCutKey : [83],
                
                
                /**
                 * smartButtons
                 * buttons which enables /disables smartSelctions
                 * @type Boolean
                 */
                smartButtons : true,
                
                disableSmartButtonText : "Disable Smart Selction",
                
                enableSmartButtonText :  "Enable Smart Selection",
                
    //            enableShortCutKeys : {
    //                enableSmartSelectionShortCuts: [83],
    //                disableSmartSelectionShortCuts : [83]
    //            },
                
                /**
                 * removedMouseUp
                 * which holds the value whether the plugin is enabled/disabled.
                 * @type Boolean
                 */
                removedMouseUp : false,
                
                /**
                 * smartPluginRef
                 * which holds the plugin ref
                 * @type String
                 */
                smartPluginRef : "",
                
                /**
                 * maxLengthOfStringAllowedForSearch
                 * max string length allowed for search becuase we cant have big string to create regEx
                 * @type Number
                 */
                maxLengthOfStringAllowedForSearch: 12000,
                
                /**
                 * mandatory method for extjs plugin
                 * which binds the mouse up event after the rendering of parent component  
                 * @param {} cmp
                 */
                init : function(cmp) {
                    var me = this;
                    me.compRef = cmp;
                    cmp.smartPluginRef = this;
                    cmp.onRender = cmp.onRender.createSequence(function(name){
                        if(me.shortCutKey){
                            me.bindKeyShortCuts(me.shortCutKey);
                        }
                        if(me.smartButtons){
                            me.addSmartButtons(cmp);
                        }
                        cmp.getEl().on('mouseup',me.startSelectionProcess,me,{buffer:100});
                    });
                },
                
                
                /**
                 * which sets the enable /disable button text
                 * @param {} but
                 */
                smartButtonHandler : function(but){
                    var me = this;
                    if(but){
                        if(!me.removedMouseUp){
                           but.setText(me.disableSmartButtonText);
                        }else{
                           but.setText(me.enableSmartButtonText);
                        }
                    }
                },
                
                /**
                 * returns the smartselction button
                 * @return {}
                 */
                getSmartButton : function(){
                    var me = this;
                    var button = ['-',{
                     text : this.disableSmartButtonText,
                     id : 'smartButton',
                     handler : function(but){
                         me.toggleSmartSelction();
                     }
                    }]
                    return button;
                },
                
                /**
                 * adds the smartselction button
                 * @param {} cmp
                 */
                addSmartButtons : function(cmp) {
                    var added = false;
                    if (cmp) {
                        var toolbar = cmp.getTopToolbar();
                        if (toolbar) {
                            toolbar.addFill();
                            toolbar.add(this.getSmartButton());
                            added = true;
                            toolbar.doLayout();
                        } else {
                            this.addSmartButtons(cmp.ownerCt)
    
    
                        }
                    }else{
                 if(!added){
                     if(typeof console == 'object'){
                       console.log("No top toolbar defined, please define a empty toolbar if not defined example tbar : []");
                     }
                    }
                    }
                    
                
                    
                },
                
                /**
                 * @method bindKeyShortCuts which binds shortCut keys to enable
                 *         /disable selection
                 * @param {}
                 *            shortCutKey
                 */
                bindKeyShortCuts : function(shortCutKey){
                    var me = this;
                    if(shortCutKey.length > 0){
                    new Ext.KeyMap(document, [
                        {
                            key : shortCutKey,
                            ctrl:false,
                            shift:false,
                            alt:false,
                            fn : this.toggleSmartSelction,
                            scope : me,
                            stopEvent : true
                        }
                        ]);
                    }
                },
                
                
                /**
                 * @method toggleSmartSelction
                 * which toggles enabling/disabling of smart selection
                 * @param {} key
                 */
                toggleSmartSelction : function(key){
                    if(this.removedMouseUp){
                       this.enableSmartSelection()
                    }else{
                        alert("yes");
                       this.disableSmartSelection()
                    }
                    
                    this.smartButtonHandler(Ext.getCmp('smartButton'));
                    
                },
                
                /**
                 * @method selectText method that should be used to preserve the selection made by the user
                 * To-do - it's not functioning yet :(.need to include logic to find out on which item out of many similler items to preserve the 
                 * selection 
                 * @param {} element
                 */
                
             /*  selectText : function(element) {
                    var doc = document;
                    var text = element; 
                    if (doc.body.createTextRange) { // ms
                        var range = doc.body.createTextRange();
                        range.moveToElementText(text);
                        range.select();
                    } else if (window.getSelection) { // moz, opera, webkit
                        var selection = window.getSelection();            
                        var range = doc.createRange();
                        range.selectNodeContents(text);
                        selection.removeAllRanges();
                        selection.addRange(range);
                    }
                },
       */
                /**
                 * @method getCursorPosition
                 * @param {} e
                 * used with selectText function
                 * @return {}
                 */
               /* getCursorPosition : function(e)
                    {
                        var x = 0, y = 0, range;
                        if (window.getSelection) {
                            var sel = window.getSelection();
                            if (sel.rangeCount) {
                                range = sel.getRangeAt(sel.rangeCount - 1);
                                range.collapse(false);
                                var dummy = document.createElement("span");
                                range.insertNode(dummy);
                                var rect = dummy.getBoundingClientRect();
                                x = rect.left;
                                y = rect.top;
                                dummy.parentNode.removeChild(dummy);
                            }
                        } else if (document.selection && document.selection.type != "Control") {
                            range = document.selection.createRange();
                            range.collapse(false);
                            x = range.boundingLeft;
                            y = range.boundingTop;
                        }
                        return {x: x, y: y};
                 },
                 
                 
                */
                /**
                 * @method disableSelection
                 * which unbinds the mouse up event listener
                 */
                disableSmartSelection : function(){
                     var me = this;
                     if(!me.removedMouseUp){
                        var selectedText = (this.getSelectedText()).toString();
                        //if (selectedText) {
                            this.removeHighlight(this.highlightCls,this.compRef.getEl().dom);
                       // }
                         me.compRef.getEl().un('mouseup',me.startSelectionProcess,me);
                         me.removedMouseUp = true;
                     }else{
                         this.removeHighlight(this.highlightCls,this.compRef.getEl().dom);
                     }
                },
                
                
                /**
                 * @method enableSelection
                 * which binds the mouse up event listener
                 */
                enableSmartSelection : function(){
                     var me = this;
                     if(me.removedMouseUp){
                        me.compRef.getEl().on('mouseup',me.startSelectionProcess,me);
                        me.removedMouseUp = false;
                     }
                },
                
                /**
                 * @method getSelectedText
                 * which returns the selected string
                 * @return {String}
                 */
                getSelectedText : function() {
                    if (window.getSelection) {
                        return window.getSelection().toString();
                    } else if (document.selection) {
                        return document.selection.createRange().text;
                    }
                    return '';
                },
                
                       
                /**
                 * @method startSelectionProcess
                 * which starts the selection process by validating(empty) the selected text
                 */
                startSelectionProcess : function() {
                    //this.cords = this.getCursorPosition();
                    var selectedText = (this.getSelectedText()).toString();
                    if(selectedText.length >= this.maxLengthOfStringAllowedForSearch){
                        return;
                    }
                    
                    if (selectedText) {
                        this.removeHighlight(this.highlightCls,this.compRef.getEl().dom);
                        selectedText =  Ext.escapeRe(selectedText);
                        
                        try{
                            new RegExp((selectedText).trim()+'\\s?', "gi");
                        }catch(e){
                        alert("gh")
                        }
                        
                        this.highlightText(this.compRef.getEl().dom,new RegExp((selectedText).trim()+'\\s?', "gi"), this.highlightCls, true);
                    }
                },
                
                /**
                 * @method removeHighlight
                 * which checks for spans with highlightClass and try to replace those with normal text node
                 * normalize is for better performance by removing empty text nodes and combining adjacent text nodes and created one
                 * @param {} highlightClass
                 * @param {} node
                 */
                removeHighlight : function(highlightClass, node) {
                    var me = this;
                    var h = Ext.DomQuery.select("span." + highlightClass, node);
                    for (var i = 0; i < h.length; i++) {
                        var s = h[i], sp = s.parentNode;
                        sp.replaceChild(document.createTextNode(s.firstChild.data),s);
                        sp.normalize();
                    }
                    //me.selectText( document.elementFromPoint(me.cords.x, me.cords.y));
                },
                
                /**
                 * @method highlightText
                 * which runs the regex exec method which wil find all the matches
                 * using 
                 * @param {} node
                 * @param {} regex
                 * @param {} cls
                 * @param {} deep
                 */
                highlightText : function(node, regex, cls, deep) {
                    var me = this;
                    var me = this;
                    if (typeof(regex) == 'string') {
                        regex = new RegExp((regex), "gi");
                    } else if (!regex.global) {
                         if(typeof console == 'object'){
                             console.log("RegExp to highlight must use the global qualifier");
                         }
                    }
                    var value, df, m, l, start = 0, highlightSpan;
                    if ((node.nodeType == 3) && (value = (node.data))) {
                        // Loop through creating a document DocumentFragment
                        // containing text nodes interspersed with
                        // <span class={cls}> elements wrapping the matched text.
                        while (m = regex.exec(value)) {
                            if (!df) {
                                df = document.createDocumentFragment();
                            }
                            if (l = m.index - start) {
                                df.appendChild(document.createTextNode(value.substr(start, l)));
                            }
                            highlightSpan = document.createElement('span');
                            highlightSpan.className = cls;
                            highlightSpan.appendChild(document.createTextNode(m[0]));
                            df.appendChild(highlightSpan);
                            start = m.index + m[0].length;
                        }
                        // If there is a resulting DocumentFragment, replace the
                        // original text node with the fragment
                        if (df) {
                            if (l = value.length - start) {
                                df.appendChild(document.createTextNode(value
                                        .substr(start, l)));
                            }
                            node.parentNode.replaceChild(df, node);
                        }
                    } else {
                        if (deep) {
                            Ext.each(node.childNodes, function(child) {
                                        me.highlightText(child, regex, cls, deep);
                                    });
                        }
                    }
                }
    
    
            });
    
    
    
    
    Ext.preg('smartTextHighlight',UTP.ux.smartTextHighlight);

    Please do get back for any bugs /query.

    Also help to improve this article with your valuable suggestions.

  2. #2
    Sencha - Support Team scottmartin's Avatar
    Join Date
    Jul 2010
    Location
    Houston, Tx
    Posts
    9,197
    Vote Rating
    482
    scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future scottmartin has a brilliant future

      0  

    Default


    Thank you for the contribution.

    Scott.