1. #1
    Sencha User
    Join Date
    Dec 2008
    Location
    Mainz
    Posts
    241
    Vote Rating
    1
    crp_spaeth is on a distinguished road

      0  

    Talking Nativ Ext.Clipboard Cut / Copy / Paste Plugin (ie, safari, ff)

    Nativ Ext.Clipboard Cut / Copy / Paste Plugin (ie, safari, ff)


    Hi there after the idea stucks in my head for a while now I just started to develop it for extjs.

    One most used features in applications are cut copy and paste. And after apple implemented it for the Iphone i ask my self why dont do that for Ext too.

    "because you do not have acces to the Clipboard" many of you will shout.
    Of cause not. But there is a way to use it anyhow!!!

    You would like to see it in action first? Here is a little demo:

    http://www.crp.de/Shared/extjs/examples/copyPasteExample/copyPasteExample.html


    After you have seen the demo you may whant to know how its been done




    I just pasted from Documentation.

    Represents the base Plugin for adding Cut/Copy/Paste capabilities to a component.


    The plugin Bases on a tricky little Bypass trick.
    The plugin adds two hidden native HTMLElements to the body.
    A Textarea for bypassing to clipboard. And a Iframe with editmode=On for bypassing from the Clipboard.

    After a Component that instanciates this Plugin gets renderd the plugin attaches the
    key events of ctrl+x ctrl+c ctrl+v two its own functions.

    Since the browser fires the javascript keyevent before it does the native cutting, copieing and pasting stuff
    we can use the time before the browser in example coping a text into the nativ System
    Clipboard to selecting the text we want to have in the Clipboard.

    This little hack makes the whole plugin possible.

    Lets Clarify by explaining what the copyHandler, attached to the ctrl+c does.

    First of all it saves a few states
    - what was the caret State (the selection range)
    - what was the marked Text (would normaly into the clipboard)

    Than it asks the plugins client to build the copyIdentifier (this is what actualy does it way into the clipboard)
    Than the the Magic Happens:
    -The Value you returnd in the buildCopyIdentifierString function becomes the value of the Textarea attached to this component
    -The Textarea gets its focus und all the text inside gets selected.
    -Wait for about 10 Milliseconds and the Browser will have done the rest for you
    -Woallla the value you just created via the buildCopyIdentifierString is now in the
    native System Clipboard.
    And the better thing about that: u exactly knwo about that string.
    After all that, the copyToClipboard function with the IdentifierString gets called.

    The cut Functionionalety is quiet similiar.

    The Paste Function works a bit different.
    First of all it saves a few states
    - what was the caret State (the selection range)

    Next Step is to focus the Iframe and set its innerHTML to '';
    no we just wait for about 10 Milliseconds to let the browser paste the value from the
    clipboard into the Iframe.
    Now we call the plugins client pasteFromClipboard function under the scope of the client with the string from the iframes innerHTML
    If this function retunrns undfined we simulate the default behavior.



    If you got any questions just ask. Maybe you could try the demo and send some feedback + ?bugs?.

    In the next Post I will place in the whole readable code for the plugin used in the Example

  2. #2
    Sencha User
    Join Date
    Dec 2008
    Location
    Mainz
    Posts
    241
    Vote Rating
    1
    crp_spaeth is on a distinguished road

      0  

    Talking


    First of all there is a litte Plugin i wrote that once it is instantiated, it registers the the component in a Singleton called Ext.ComponentFocusMgr automatically when it gets focused (indicated by contextmenu or click event).



    PHP Code:
    Ext.namespace('Ext''Ext.plugins');

    /**
     * @class Ext.ComponentFocusMgr
     *  
     * A global Manager that stores the information about the last focused Components. 
     * Since there is no bubling in the Ext events yet Focus just bases on the on Clickevent
     * and on the oncontextmenu. To make your component focusable just use the Focus detector Plugin
     *
     * @author  Martin Späth
     * @date    April 2, 2009
     * @singleton
     */
    Ext.ComponentFocusMgr = (function(){
        var 
    focusChain = new Ext.util.MixedCollection(false, function(item){return item.id});
        var 
    currentTarget null;
        
        return {
            
            
    /**
             * adds the passed cmpId to the focusChain if the currentTarget
             * is the same as the eventTarget otherwise it will clear the list
             * and add this cmpId to the list.
             * 
             * @param {eventTarget} indicator for a new focus Chain. If the eventTarget change the focus Chain gets resetet
             * @param {Ext.Component} the Component that been Focused
             */    
            
    addToFocusList: function(eventTargetcmp){
                if(
    currentTarget != eventTarget) {
                    
    focusChain.clear();
                    
    currentTarget eventTarget;
                } 
                
                if(!
    focusChain.contains(cmp)){
                    
    focusChain.add(cmp.idcmp);
                }
            },
            
            
    /**
             * Gets the first element of the Focus Chain
             * @returns {Ext.Component} The Top Element of the Focus Chain
             */
            
    getTopFocus: function(){        
                return 
    focusChain.itemAt(0);
            },
            
            
    /**
             * Get the whole Focus Chain 0 ist the uppest Element
             * @retunrs {Ext.util.MixedCollection} a mixed Collection with all the Elements of that have focus in it. 
             */
            
    getFocusChain: function(){
                return 
    focusChain;
            }
            
        }
    })();


    Ext.plugins.FocusDetector = function(config) {
        
    Ext.apply(thisconfig);
    };
     
    /**
     * A small Plugin that handles focusregistration for the component 
     * that implements this plugin
     * @class Ext.plugins.FocusDetector
     * @extends Ext.util.Observable
     */
    Ext.extend(Ext.plugins.FocusDetectorExt.util.Observable, {

        
    init:function(client) {
            
    this.client client;
            if(
    this.initFocus){           
                   
    Ext.ComponentFocusMgr.addToFocusList('',this.client);
            }
            
            
    client.on({
                
    'render'this.render,
                
    scopethis
            
    });
            
            
    client.on({
                
    'destroy'this.destroy,
                
    scopethis
            
    });
        }, 
    // end of function init // end of function init
        
        /**
         * gets called wenn this plugins child is rendered
         */
        
    render: function() {        
            
    this.client.el.on('click'this.clickHandlerthis);
            
    this.client.on('contextmenu',this.clickHandler this);
        },
        
            
        
        
    /**
         * gets called wenn this plugins child been destroyed
         */
        
    destroy: function(){
            
    this.client.el.un('click'this.clickHandler);
            
    this.client.un('contextmenu'this.clickHandler);
        },
        
     
        
    clickHandler:  function(ev){
                
    Ext.ComponentFocusMgr.addToFocusListev.targetthis.client);            
        }
    }); 
    // end of extend
     
    // end of file 

    overwrite the core Ext.Element to include a standardized "caret/Selection" Functionality:

    PHP Code:
    // adds caret Functionalety to an Ext.Element
    Ext.override(Ext.Element, {    
        
    _iCaretNative undefined,
        
    _isSupported undefined,
        
    /**
         * @private
         */
        
    isCaretNative: function(){
            if(
    typeof this._isCaretNative == 'undefined') {
                var 
    documentd.createElement("input");
                
    this._isCaretNative "selectionStart" in o
                
    this._isCaretSupported this._isCaretNative || (d.selection) && !!o.createRange;    
                
            }
            return 
    this._isCaretNative
        
    },
        
        
    /**
         * @private
         */
        
    isSupported: function(){
            if(
    typeof this._isCaretSupported == 'undefined') {
                
    this.isCaretNative();
            }
            return 
    this._isCaretSupported
        
    },
        
        
    /**
         * selects the text of the Element
         * @param {Mixed} start Start position of the selection 
         * @param {Number} end End position of the selection
         * @return {}
         */
        
    setCaret: function(startend){
            
            if(!(
    this.dom.nodeName.toLowerCase() == "textarea" || this.dom.nodeName.toLowerCase() == "input")){
                return;
            }
            if(
    typeof start.start != 'undefined') {
                    
    end start.end;
                    
    start start.start;                
            }
            if(
    this.isCaretNative()) {
                return 
    this.dom.setSelectionRange(startend
            } else {
                var 
    this.dom;
                var 
    o.createTextRange();
                
    end -= start o.value.slice(start 1end).split("\n").length 1;
                
    start -= o.value.slice(0start).split("\n").length 1;
                
    t.move("character"start), t.moveEnd("character"end), t.select();
            }        
        },
        
        
    /**
         * returns the current Selection of the Element
         * @return {Object} {start: startposition, end: endposition} of the selection
         */
        
    getCaret: function(){
            
            var 
    this.dom;
            if(
    this.isCaretNative()) {
                return { 
    starto.selectionStartendo.selectionEnd }
            } else {
                var 
    = (this.dom.focus(), document.selection.createRange()), rstartendvalue;
                
    // the current selection range is not part of the controll asking for the caret...
                
    if(s.parentElement() != o)
                    return {
    start0end0};
                        
                var 
    isTA o.nodeName.toLowerCase() == "textarea";
                if(
    isTA ? (s.duplicate()).moveToElementText(o) : o.createTextRange(), !isTA)
                    return 
    r.setEndPoint("EndToStart"s), {startr.text.lengthendr.text.length s.text.length};
                for(var $ = 
    "[###]"; (value o.value).indexOf($) + 1; $ += $);
                
    r.setEndPoint("StartToEnd"s), r.text = $ + r.textend o.value.indexOf($);
                
    s.text = $, start o.value.indexOf($);
                if(
    document.execCommand && document.queryCommandSupported("Undo"))
                    for(
    r in {0:00:0})
                        
    document.execCommand("Undo");
                return 
    o.value valuethis.setCaret(startend), {startstartendend};
            }
        },
        
    /**
         * Returns the caret Plus the Line, Column nummer and the position Number
         * @return {}
         */
        
    getCaretPosition : function(){
            
            if(!(
    this.dom.nodeName.toLowerCase() == "textarea" || this.dom.nodeName.toLowerCase() == "input")){
                return;
            }
            var 
    this.getCaret(), o=this.dom;
            if(
    c){
                  var 
    lines;// = (typeof o.value != 'undefined') ? o.value.split("\n") : o.innerText.split("\n");
                  
    if(typeof o.value != 'undefined') {
                      
    lines o.value.split("\n");
                  } else {
                      
    lines o.innerText.split("\n");
                  }
                      
    c.lines lines.length;
                  var 
    p=c.start,ll=c.lines,len=0,line=0;
                  for(;
    line<ll;line++) {
                    
    len lines[line].length 1;
                    if(
    p<len)break;
                    
    -= len;
             }
             
    line++;

             
    c.line=line;
             
    c.column p;
             
    c.position c.start;

            }
            return 
    c;
        },
        
    /**
         * sets the CaretPosition 
         * @param {Number} start the beginnig of the selection
         * @param {Number} end the end of the selection
         */
        
    setCaretPosition : function(startend) {
            
    // FIX start.start ? 
            
    if(typeof start.start != 'undefined') {
                    
    end start.end
                    start 
    start.start;    
            } 
            if(
    typeof start != 'undefined' ) {
                  
    this.setCaret(start,end || start);    
            }
        },
        
    /**
         * gets the current selected text
         * @return {}
         */
        
    getCaretText : function(){
            var 
    this.getCaret();
            return (
    typeof this.dom.value != 'undefined') ? this.dom.value.slice(o.starto.end):'';
        },
        
    /**
         * overrides the currently selected Text with an other text
         * @param {String} text
         */
        
    setCaretText : function(text){
            var 
    this.getCaret(), this.domi.value;
            if(
    typeof s == 'undefined') {
                return;
            }
            
    i.value s.slice(0o.start) + text s.slice(o.end);
            
    this.setCaret(o.start += text.lengtho.start);
        }
        
    }); 
    The nex Code represent a Clipboard Singletone that holds the data and representing string

    PHP Code:
    /**
     * @class ClipBoard
     *  
     * A global Clipboard implementation that stores the Clipboard information. 
     * Since there is no bubling in the Ext events yet Focus just bases on the on Clickevent
     * and on the oncontextmenu. To make your component focusable just use the Focus detector Plugin
     *
     * @author  Martin Späth
     * @date    April 2, 2009
     * @singleton
     */
    Ext.ClipBoard = (function(){
        var 
    lastInExtCopiedString false;
        var 
    dataObject null;
        
        return {
            
    /**
             * Sets the date of the Clipboard Object
             * @param {Object} dataObj the Object to store into the Clipboard
             * @param {String} identifierString (optional) the string which currently been stored into the System-Clipboard
             */
            
    setData: function(dataObjidentifierString){
                if(
    typeof identifieSring != 'undefined') {
                    
    lastInExtCopiedString identifieString;
                }
                
    dataObject dataObj;
            },
            
    /**
             * Gets the data stored into the Clipboard
             * @param {String} stringFromClipboard (optional) the String that represents the 
             * content of the current System-Clipboard. 
             * @returns {Object} if stringFromClipboard is undifined or it matches to the lastInExtCopiedString it returns the data Object.
             * Otherwise it'll return the stringFromClipboard parameter.
             */
            
    getData: function(stringFromClipboard){
                
                if(
    typeof identifieSring == 'undefined' || lastInExtCopiedString == identifieSring) {
                    return 
    dataObject;
                }
                return 
    stringFromClipboard;
            }
        } 
    Last but not Least there is the Code where the "Magic" happens

    The Base Plugin Ext.plugins.CopyPasteable

    PHP Code:
    /**
     * Ext.plugins.CopyPasteable plugin 
     *
     * @author  Martin Späth
     * @date    April 2, 2009
     *
     * @class Ext.plugins.CopyPasteable
     * @extends Ext.util.Observable
     */
    Ext.plugins.CopyPasteable = function(config) {
        
    Ext.apply(thisconfig);
    };


    /**
     * Represents the base Plugin for adding Cut/Copy/Paste capabilities to a component.
     * 
     * The plugin Bases on a tricky little Bypass trick.
     * The plugin adds two hidden native HTMLElements to the body.
     * A Textarea for bypassing to clipboard. And a Iframe with editmode=On for bypassing from the Clipboard.
     * 
     * After a Component that instanciates this Plugin gets renderd the plugin attaches the
     * key events of ctrl+x ctrl+c ctrl+v two its own functions.
     * 
     * Since the browser fires the javascript keyevent before it does the native cutting, copieing and pasting stuff
     * we can use the time before the browser in example coping a text into the nativ System
     * Clipboard to selecting the text we want to have in the Clipboard.
     * 
     * This little hack makes the whole plugin possible.
     * 
     * Lets Clarify by explaining what the copyHandler, attached to the ctrl+c does.
     * 
     * First of all it saves a few states 
     *     - what was the caret State (the selection range)
     *     - what was the marked Text (would normaly into the clipboard)
     * 
     * Than it asks the plugins client to build the copyIdentifier (this is what actualy does it way into the clipboard)
     * Than the the Magic Happens:
     *         -The Value you returnd in the buildCopyIdentifierString function becomes the value of the Textarea attached to this component
     *         -The Textarea gets its focus und all the text inside gets selected.
     *         -Wait for about 10 Milliseconds and the Browser will have done the rest for you
     *         -Woallla the value you just created via the buildCopyIdentifierString is now in the 
     *             native System Clipboard.
     *             And the better thing about that: u exactly knwo about that string.
     * After all that, the copyToClipboard function with the IdentifierString gets called.
     *
     * The cut Functionionalety is quiet similiar.
     * 
     * The Paste Function works a bit different.
     * First of all it saves a few states 
     *     - what was the caret State (the selection range)
     * 
     * Next Step is to focus the Iframe and set its innerHTML to '';
     * no we just wait for about 10 Milliseconds to let the browser paste the value from the
     * clipboard into the Iframe.
     * Now we call the plugins client pasteFromClipboard function under the scope of the client with the string from the iframes innerHTML
     * If this function retunrns undfined we simulate the default behavior.
     *
     * 
     * @author  Martin Späth
     * @date    April 2, 2009
     * @class Ext.plugins.CopyPasteable
     * @extends Ext.util.Observable
     */
    Ext.extend(Ext.plugins.CopyPasteableExt.util.Observable, {
        
    init:function(client) {
            
    this.client client;
            
            
    this.client.copyToClipboard this.copyToClipboard;
            
            
            
    this.client.pasteFromClipboard this.pasteFromClipboard;
            
            
    this.client.cutToClipboard this.cutToClipboard;
            
            
    // add the events to the client
            
    this.client.addEvents(
                
    /**
                 * @event beforeCopy
                 * Fires before the data gets filled into the clipboard
                 * @param {Ext.Component} this
                 */
                
    'beforeCopy',
                
    /**
                 * @event copy
                 * Fires after something from this component has been added to the Ext.ClipBoard
                 * @param {String} the accessor used to connect the System Clibboard with the Ext Clipboard
                 */
                
    'copy',
                
    /**
                 * @event beforePaste
                 * Fires before something gets pasted (return false when the standart browse Behavior)
                 */
                
    'beforePaste',
                
    /**
                 * @event paste
                 * Fires something when should get pasted
                 */
                
    'paste'
            
    );
            
            
    client.on({
                
    'render'this.render,
                
    scopethis
            
    });
            
            
    client.on({
                
    'destroy'this.destroy,
                
    scopethis
            
    });
        }, 
    // end of function init
        
        /**
         * gets called when the copy bypass was successfull Use this method for storing information in the
         * Ext.Clipboard
         * @param {string} identifierString (optional) Sting that links the clipboardData with the string in the system clipboard 
         */
        
    copyToClipboard: function(identifierString) {
            
    Ext.ClipBoard.setData(identifierStringidentifierString); 
        },
        
        
    /**
         * gets called when the cut bypass was successfull Use this method for storing information in the
         * Ext.Clipboard
         * @param {string} identifierString (optional) Sting that links the clipboardData with the string in the system clipboard 
         */
        
    cutToClipboard: function(identifierString){        
            
    Ext.ClipBoard.setData(identifierStringidentifierString); 
        },
        
        
    /**
         * gets called when the paste bypass was successfull 
         * @param {string} orginalString the Parameter that was pasted from the System-Clipboard. You can use this information to get Data form the Ext.Clipboard 
         * @return {String} the string with which the normal browser behavior should get simulated
         */
        
    pasteFromClipboard: function(orginalString){
            return 
    orginalString;
        },
       
        
    /**
         * builds the IdentifierString that gets copied into the System clipboard
         * you can override this with any string generating function you want.
         * @param {string} orginalValue the orginal selected text/content (to develop)
         * @return {string} the value that will get copied
         */
        
    buildCopyIdentifierString: function(orginalValue){
            
    // i didn't find a way to say what will make its way into the clipboad if i dont bypass it for all cases.
            // so by default i just fill it with a uniq key.
            
    if(typeof orginalValue == 'undefined' || orginalValue =='') {
                return 
    Ext.id();
            }
            return 
    orginalValue;
        },
        
        
    /**
         * builds the IdentifierString that gets cutted into the System clipboard
         * you can override this with any string generating function you want.
         * @param {string} orginalValue the orginal selected text/content (to develop)
         * @return {string} the value that will get cutted
         */
        
    buildCutIdentifierString: function(orginalValue){
            
    // i didn't find a way to say what will make its way into the clipboad if i dont bypass it for all cases.
            // so by default i just fill it with a uniq key.
            
    if(typeof orginalValue == 'undefined' || orginalValue =='') {
                return 
    Ext.id();
            }
            return 
    orginalValue;
        },
        
        
    elementSuportsPaste: function(el){
            return 
    el.nodeName && (el.nodeName.toLowerCase() == 'input' || el.nodeName.toLowerCase() == 'textarea');
        },
        
        
    /**
         * gets called when the user presses ctrl+c
         */
        
    cutHandler: function (keyevent){
            
            var 
    el event.target
            
    //var sh = false;
            
            //if(this.elementSuportsPaste(el)){
            //    sh = new Ext.util.SelectionHelper(el);
            //}
            
                    //Ext.fly(el).setCaretPosition(1,2);
            
            // save the caretState for later restore 
            
            
    var caretState Ext.fly(el).getCaret();        
            var 
    orginalCuttedText Ext.fly(el).getCaretText();
        
            if(
    this.client.fireEvent("beforeCopy"this.clienteventkey) !== false){
                
    // fix
                
    var value = (this.buildCutIdentifierString.createDelegate(this.client))(orginalCuttedText);
                if(
    value !== false) {
                    
    this.bypassToClipboard(value);
                    (function(
    el){
                        
    el.focus();
                        
                        
                        
    Ext.fly(el).setCaretPosition(caretState);
                    }).
    defer(10this, [el]);
                } else {
                    
    // if the bypass wasn't used, save the copied text into the lastExtCopyString for later purpose
                    
    value Ext.fly(el).getCaretText();
                }
             
                
    // now call the components copyToClipboard Function with the identifier value just created
                
    (this.cutToClipboard.createDelegate(this.client))(value);
            }
            return 
    true;
        },
        
        
        
    /**
         * gets called when the user presses ctrl+c
         */
        
    copyHandler: function (keyevent){
            
            var 
    el event.target
            
            
    // save the caretState for later restore 
            
    var caretState Ext.fly(el).getCaret();        
            var 
    orginalCopyText Ext.fly(el).getCaretText();
        
            if(
    this.client.fireEvent("beforeCopy"this.clienteventkey) !== false){
                
    // fix
                
    var value = (this.buildCopyIdentifierString.createDelegate(this.client))(orginalCopyText);
                if(
    value !== false) {
                    
    this.bypassToClipboard(value);
                    (function(
    el){
                        
    el.focus();
                        
                        
                        var 
    elfly Ext.fly(el); 
                         
    elfly.setCaretPosition(caretState);
                    
    // and do what the browser would do if you wouldn't have bypass
                         
    elfly.setCaretText();
                    }).
    defer(10this, [el]);
                } else {
                    
    // if the bypass wasn't used, save the copied text into the lastExtCopyString for later purpose
                    
    value Ext.fly(el).getCaretText();
                }
             
                
    // now call the components copyToClipboard Function with the identifier value just created
                
    (this.copyToClipboard.createDelegate(this.client))(value);
            }
            return 
    true;
        },
        
        
        
    /**
         * Bypasses the string in dataToByPass to the Clipboard
         * @param {String} dataToByPass the string that should get stored into the System Clipboard
         */
        
    bypassToClipboard: function(dataToByPass){
            
    // bypass over the textarea
            
    this.bypassTextarea.value dataToByPass;
            
    this.bypassTextarea.focus();
            
    this.bypassTextarea.select();
        },
          
        
        
    /**
         * gets called from the keyhandler when ctrl+v was pressed in the scope of the clients events
         */
        
    pasteHandler: function(keyevent){
            
    el event.target;
            
            
    // save the current caretState for later restore 
            
    var caretState Ext.fly(el).getCaretPosition();
            var 
    bp this.bypassIframe;
            
            
    // clear the bypassIframe and focus it to paste in to it.
            
    if (bp.contentWindow) {//ns6 syntax
                
    this.getIframeBody().innerHTML '';
                
    bp.contentWindow.focus();
            }
            else if (
    bp.Document) {//ie5+ syntax
                
    this.getIframeBody().innerHTML '';
                
                
    bp.contentDocument.focus();
            }
            
             
    // give the browser about 10ms to paste the stuff into the bypass area
            
    (function(el){
                
    // And Wholla we know what is in the Clipboard
                // call the paste manipulation function
                
    var pastVal = (this.pasteFromClipboard.createDelegate(this.client))(this.getIframeBody().innerHTML);
                
    // by returning nothing we let the plugin prevent to simulate the normal browser behavior 
                
    if(typeof pastVailue != 'undefined'){
                    
                    
    // re-set the caret of the field to the state before the bypass
                    
    el.focus();
                    
                    var 
    elfly Ext.fly(el); 
                     
    elfly.setCaretPosition(caretState);
                    
    // and do what the browser would do if you wouldn't have bypass
                     
    elfly.setCaretText(pastVal);
                    
                    
    // reselect the text just pasted
                     
    elfly.setCaretPosition(caretState.start+pastVal.lengthcaretState.start+pastVal.length);
                }
                
            }).
    defer(10this, [el]);
            
            
            
    // TODO fire paste event with the value
            //alert(pastVal);
            
        
    },    
        
        
    render: function(){        
            
    this.wrapper Ext.DomHelper.append(this.client.el, {
                   
    tag'div',
                   
    children: [{
                        
    tag'textarea'
                   
    }, {
                           
    tag'iframe',
                           
    nameExt.id(),
                           
                           
    frameBorder'1',
                           
    srcExt.isIE Ext.SSL_SECURE_URL "javascript:;"
                           
                   
    }
                   ],
                   
    //'class': 'x-hidden',
                   
    style'height:0; width:0; overflow:hidden'
           
    });
                 
           
    //this.wrapper.appendChild(iframe);
            
           
    this.bypassIframe this.wrapper.childNodes[1];
           
           
    this.initFrame();
           
    this.bypassTextarea this.wrapper.firstChild;
           
           
    // map the keystrokes ctrl+c and ctrl+v to its hanlders
           
           // FIX doesn't get fired if a normal text in the Panel was selected 
           // before presing ctrl+(v|c) 
           
    new Ext.KeyMap(this.client.el, [{
                
    key'c',
                
    ctrltrue,
                
    fnthis.copyHandler,
                
    scopethis
           
    },{
                
    key'v',
                
    ctrltrue,
                
    fnthis.pasteHandler,
                
    scopethis
           
    },{
                
    key'x',
                
    ctrltrue,
                
    fnthis.cutHandler,
                
    scopethis
           
    }]);  
            
        },
        
        
    /**
         * returns the body element of the bypass Iframe
         * @return {Element}
         * @private
         */
        
    getIframeBody: function() {
            
    this.doc this.getDoc();
            return 
    this.doc.body || this.doc.documentElement;
        
        },
        
         
    // private
        
    getDoc : function(){
            return 
    Ext.isIE this.getWin().document : (this.bypassIframe.contentDocument || this.getWin().document);
        },

        
    // private
        
    getWin : function(){
            return 
    Ext.isIE this.bypassIframe.contentWindow window.frames[this.bypassIframe.name];
        },
        
        
    /**
         * initializes the iframe (sets designMode=on and so..)
         */
        
    initFrame : function(){
            
    this.doc this.getDoc();
            
    this.win this.getWin();

            
    this.doc.open();
            
    this.doc.write('');
            
    this.doc.close();

            var 
    task = { // must defer to wait for browser to be ready
                
    run : function(){
                    if(
    this.doc.body || this.doc.readyState == 'complete'){
                        
    Ext.TaskMgr.stop(task);
                        
    this.doc.designMode="on";
                        
    //this.initEditor.defer(10, this);
                    
    }
                },
                
    interval 10,
                
    duration:10000,
                
    scopethis
            
    };
            
    Ext.TaskMgr.start(task);
        },
        
        
    destroy: function(){
        
            if(
    this.wrapper) {
                
    this.wrapper.remove();
            }
        
        }
    }); 
    // end of extend
     
    // end of file 

    For the demo I extend from Ext.plugins.CopyPasteable and I have just overwritten the methods for my needs

    PHP Code:
    Ext.plugins.CopyPasteableGrid = function(config) {
        
    Ext.apply(thisconfig);
    };
     
    /**
     * Example Subclass of the CopyPasteable Plugin. Created for the Grid.
     * 
     * it overwrites the buildCopyIdentifier to create a string that gets interpreted well by Excel
     * @class Ext.plugins.CopyPasteableGrid
     * @extends Ext.plugins.CopyPasteable
     */
    Ext.extend(Ext.plugins.CopyPasteableGridExt.plugins.CopyPasteable, {
        
        
        
    /**
         * Overwritten to create a string that gets well interpreted by Excel
         * @param {string} orgVal the Value that would go its way into the Clipboard if you wouldnt bypass
         * @return {string} the Value that should get bypassed into the Clipboard
         */
          
    buildCopyIdentifierString: function (orgVal) {
            
            
    // just format the output for excel
            
    var records this.getSelectionModel().getSelections();
            
            
    returnstring ""
            for(var 
    0records.lengthi++){
                var 
    currRec records[i];
                
                for(var 
    prop in currRec.data) {
                    
    returnstring returnstring currRec.data[prop] + '\t';                
                }
                
                
                
    returnstring returnstring '\n';
            }        
               
    //alert(returnstring);
            
    return returnstring;
        },
        
        
    /**
         * Overwritten to create a string that gets well interpreted by Excel
         * @param {string} orgVal the Value that would go its way into the Clipboard if you wouldnt bypass
         * @return {string} the Value that should get bypassed into the Clipboard
         */
        
    buildCutIdentifierString: function (orgVal) {
            
            
    // just format the output for excel
            
    var records this.getSelectionModel().getSelections();
            
            
    returnstring ""
            for(var 
    0records.lengthi++){
                var 
    currRec records[i];
                
                for(var 
    prop in currRec.data) {
                    
    returnstring returnstring currRec.data[prop] + '\t';                
                }
                
                
                
    returnstring returnstring '\n';
            }        
               
    //alert(returnstring);
            
    return returnstring;
        },
        
            
        
    /**
         * Overwritten to save a copy of the current selected Records into the Clipboard and remove those records from the grid
         * @param {string} identifierString
         */
        
    cutToClipboard: function(identifierString){
            
    /** @type  Ext.grid.GridPanel **/
            
    var cl this;
            var 
    records cl.getSelectionModel().getSelections();
            var 
    clipBoardObject = [];
            
            
    //returnstring = ""; 
            
    for(var 0records.lengthi++){
                var 
    currRec records[i];
                
                
    clipBoardObject[clipBoardObject.length] = currRec.copy();
                
    cl.getStore().remove(currRec);
            }        
            
            
    // store the created object in the clipboard
            
    Ext.ClipBoard.setData(clipBoardObjectidentifierString);
            
        },
        
        
    /**
         * Overwritten to save a copy of the current selected Records into the Clipboard
         * @param {string} identifierString
         */
        
    copyToClipboard: function(identifierString){
            
    /** @type  Ext.grid.GridPanel **/
            
    var cl this;
            var 
    records cl.getSelectionModel().getSelections();
            var 
    clipBoardObject = [];
            
            
    //returnstring = ""; 
            
    for(var 0records.lengthi++){
                var 
    currRec records[i];
                
                
    clipBoardObject[clipBoardObject.length] = currRec.copy();
                
            }        
            
            
    // store the created object in the clipboard
            
    Ext.ClipBoard.setData(clipBoardObjectidentifierString);
            
        },
            
        
    /**
         * Overwritten to get the data from the Clipboard and insert all the records found
         * into the Grid
         * @param {string} identifierString  
         */
        
    pasteFromClipboard: function(identifierString){
            var 
    clipboardObject Ext.ClipBoard.getData(identifierString);
            
            
    /** @type  Ext.grid.GridPanel **/
            
    var cl this;
            
    cl.getSelectionModel().clearSelections();
            for(var 
    0i<clipboardObject.lengthi++){
                
            
                
    /** @type  Ext.data.Store **/
                
    var cs this.getStore();
                
                
    /** @type Ext.data.Record  */
                
    var rec clipboardObject[i].copy(Ext.id());
                
                
    cs.insert(0,rec);
            }
            
    cl.getSelectionModel().clearSelections();
            
            
    cl.getSelectionModel().selectRecords(clipboardObject,false);
        }
       
       
    }); 
    // end of extend
     
    // end of file 

  3. #3
    Sencha User
    Join Date
    Dec 2008
    Location
    Mainz
    Posts
    241
    Vote Rating
    1
    crp_spaeth is on a distinguished road

      0  

    Red face


    Come on ext'perts tell me your experience

  4. #4
    Sencha Premium Member ajaxvador's Avatar
    Join Date
    Nov 2007
    Location
    PARIS, FRANCE
    Posts
    206
    Vote Rating
    0
    ajaxvador is on a distinguished road

      0  

    Default


    very nice
    Vador

  5. #5
    Sencha User TopKatz's Avatar
    Join Date
    Mar 2007
    Posts
    337
    Vote Rating
    2
    TopKatz is on a distinguished road

      0  

    Default


    This is neat.

    A suggestion would be to make the paste 'insert' the record where you select in the destination grid.

  6. #6
    Sencha User mxracer's Avatar
    Join Date
    Apr 2007
    Location
    Napoleon, OH
    Posts
    299
    Vote Rating
    0
    mxracer is on a distinguished road

      0  

    Default


    I tried it in FF 3 and IE 8 and worked nice.

    I did notice that in FF:
    1. I selected a row in grid A
    2. Clicked ctrl+c
    3. Now to paste into grid B ( by clicking ctrl+v ), I had to select a row first.

    In IE, I just had to click to focus grid B ( did not select a row ) and it still pasted fine.

    Bug Noticed:

    I copied from grid A by clicking ctrl+c then pasted in Notepad on my desktop... which works nice.
    I then refreshed the demo page and tried to copy from Notepad to grid B.

    This caused a error in Firebug for the copyPaste.js file on line # 746

    Code:
    clipboardObject is null
    pasteFromClipboard()("American Express Company&nbsp;&nbsp; &nbsp;52.55&nbsp;&nbsp; &nbsp;0.01&nbsp;&nbsp; &nbsp;0.02&nbsp;&nbsp; &nbsp;Tue Sep 01 2009 00:00:00 GMT-0400 (Eastern Daylight Time)")copyPaste.js (line 746)
    getViewWidth()()ext-base.js (line 9)
    (?)()(td.x-grid3-col)copyPaste.js (line 494)
    getViewWidth()()ext-base.js (line 9)
    [Break on this error] for(var i = 0; i<clipboardObject.length; i++){
    Todd Murdock

  7. #7
    Sencha User mxracer's Avatar
    Join Date
    Apr 2007
    Location
    Napoleon, OH
    Posts
    299
    Vote Rating
    0
    mxracer is on a distinguished road

      0  

    Default


    Are we free to use this code?
    Todd Murdock

  8. #8
    Sencha User
    Join Date
    Dec 2008
    Location
    Mainz
    Posts
    241
    Vote Rating
    1
    crp_spaeth is on a distinguished road

      0  

    Default


    of cause feel free to use it

  9. #9
    Ext User DigitalSkyline's Avatar
    Join Date
    Apr 2007
    Location
    Rochester, MI
    Posts
    461
    Vote Rating
    1
    DigitalSkyline is on a distinguished road

      0  

    Default


    Cool... could this also work with the HTML editor?

    _____________________________________________

    For ExtJS Consultation and Custom Development ->
    Contact Paul[at]digitalskyline.com

  10. #10
    Sencha User
    Join Date
    Dec 2008
    Location
    Mainz
    Posts
    241
    Vote Rating
    1
    crp_spaeth is on a distinguished road

      0  

    Default


    Sorry for the delay...

    I did not start to write real extensions of the plugin jet. I just implemented the base functionality and a proprietary example for the grid to let you guys see what can be done with this little trick.


    @mxracer: I know about this little issue in Firefox but this is a known Extjs - Bug see: Focus Bug

    I will give the Bug you came up with a try tomorrow.

    @TopKatz: Nice Idea but notice, the extension is just proprietary and written as easy as possible to give you the ability to write your own extension of my plugin for other components like the tree or dataview and so one. But btw. I would really love to see your Idea implemented! So give it a try!!


    @DigitalSkyline: Since the HTMLEditor bases on another iframe you will need to overwrite the bypass to work on an iframe but I dont think it is that hard.

    Since i been using an iframe to let the browser paste stuff in you could use the existing iframe from the HTMLEditor and you could compare the innerHTML before the browser finishes the native ctrl+v event and after it...

    @all: By the way did one of you try to paste into MS *duck* Excel after you copied a few rows via ctrl+c ?

    best regards

Turkiyenin en sevilen filmlerinin yer aldigi xnxx internet sitemiz olan ve porn sex tarzi bir site olan mobil porno izle sitemiz gercekten dillere destan bir durumda herkesin sevdigi bir site olarak tarihe gececege benziyor. Sitenin en belirgin ozelliklerinden birisi de Turkiyede gercekten kaliteli ve muntazam, duzenli porno izle siteleri olmamasidir. Bu yuzden iste. Ayrica en net goruntu kalitesine sahip adresinde yayinlanmaktadir. Mesela diğer sitelerimizden bahsedecek olursak, en iyi hd porno video arşivine sahip bir siteyiz. "The Best anal porn videos and slut anus, big asses movies set..."