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);