This issue duplicates another issue.
  1. #1
    Sencha Premium Member
    Join Date
    Aug 2009
    Posts
    7
    Vote Rating
    1
    geenie98 is on a distinguished road

      1  

    Default #<SVGAnimatedString> has no method 'replace'

    #<SVGAnimatedString> has no method 'replace'


    I think this might be an old bug that resurfaced in newer browser versions.
    I'm trying to add a draggable Sprite to an Ext.draw.Component

    First problem :
    If I add a sprite with a config.draggable = true, I automatically get an error me.el.dom is undefined
    ( comes from the function applyZIndex where the DrawComponent i.e. "me" doesn't have a .el yet.

    Second problem :
    I wait for the DrawComponent to be rendered and then add a draggable sprite to it. Now, I get the error :
    #<SVGAnimatedString> has no method 'replace'. This comes from the AbstractElement addCls method where for some reason, dom.className doesn't have a replace function.

    I looked around the forums and found that there had been a bug fix a while back, but when I tried it on my machine, it didn't work. I would assume that dragging a sprite would have worked at some point, otherwise the bug wouldn't have been fixed.
    http://www.sencha.com/forum/showthread.php?143421-Draggable-Sprite-Doesn-t-Follow-Cursor

    Then today I discovered that the example works with Chrome (v22) but not with the latest version released for Windows (v26). I am guessing it stopped working at some point with FF as well and thus the bug that was once fixed has reappeared.

  2. #2
    Sencha - Support Team slemmon's Avatar
    Join Date
    Mar 2009
    Location
    Boise, ID
    Posts
    5,010
    Vote Rating
    183
    slemmon is a splendid one to behold slemmon is a splendid one to behold slemmon is a splendid one to behold slemmon is a splendid one to behold slemmon is a splendid one to behold slemmon is a splendid one to behold slemmon is a splendid one to behold slemmon is a splendid one to behold

      0  

    Default


    Thanks for the bug report!
    Looks like this issue is currently reported in our tracker.

  3. #3
    Sencha User
    Join Date
    Dec 2012
    Posts
    2
    Vote Rating
    0
    mlichmanov is on a distinguished road

      0  

    Default


    I guess there might be some improvement in Ext.AbstractElement#addCls?

    Code:
        if (classList) {
            /* replace everything under this condition by single classList#add method call */
            classList.add.apply(classList, className);
        }

  4. #4
    Sencha Premium Member
    Join Date
    Aug 2009
    Posts
    7
    Vote Rating
    1
    geenie98 is on a distinguished road

      0  

    Default


    After some poking around I have finally discovered that this seems to be something that was once fixed and then regressed recently, because I don't have the problem on Chrome v22, but I do on the latest version.

    It seems that what's happening is that they are trying to set a property (the one which they are calling replace on) to an SVG node, and the browser now rejects the assignment (but it doesn't throw any exception).

    I created a workaround (ugly but it does the job) to avoid the problem until this is fixed. I just "disable" the getDragEl function momentarily on my Sprite's drag component so that the addCls is never called on my dragEl (I don't really need the addCls). I would have fixed the addCls function itself but because of a few coding policies, I can't touch the library's code directly.

    I'll remove it when a fix is released, for the time being it's working in previous and current browsers. I didn't try your fix but correcting the addCls method does make sense (unfortunately, I would have to wait for sencha to fix it).

    Also, another possible temporary fix would be to avoid calling addCls on elements that can't handle it.

    This is the problematic code (From the DragDropManager) :
    Code:
                             startDrag: function(x, y) {
                                    var me = this,
                                        current = me.dragCurrent,
                                        dragEl;
    
    
                                    clearTimeout(me.clickTimeout);
                                    if (current) {
                                        current.b4StartDrag(x, y);
                                        current.startDrag(x, y);
                                        dragEl = current.getDragEl();
    
    
                                        // Add current drag class to dragged element
                                        if (dragEl) {
                                            Ext.fly(dragEl).addCls(me.dragCls);
                                        }
                                    }
                                    me.dragThreshMet = true;
                                },
    And this is how I momentarily disable it :
    Code:
     
             sprite.dd.b4StartDrag = function() {                            
                 this.returnElement = false;
             };
    
             sprite.dd.getDragEl = function(e) {
                 // If we don't return the drag el, we won't call addCls on it!
                 if (!this.returnElement) return false;
        
                  return this.el;
            };
    
            sprite.dd.onDrag = function(e) {
                    // Return to normal...
                     this.returnElement = true;
                        ....
            };

  5. #5
    Sencha User
    Join Date
    Dec 2012
    Posts
    2
    Vote Rating
    0
    mlichmanov is on a distinguished road

      0  

    Default


    Nice workaround. I ended up with the same place (DragDropManager#startDrag), though I didn't avoid dragCls assignment. Instead I applied monkey patch handling this issue. I didn't test it thoroughly, but I hope it should work in all cases Here is the code sample:

    HTML Code:
    Ext.onReady(function() {
        Ext.dd.DragDropManager.startDrag = function(x, y) {
            var me = this,
                current = me.dragCurrent,
                dragEl, classList;
            clearTimeout(me.clickTimeout);
            if (current) {
                current.b4StartDrag(x, y);
                current.startDrag(x, y);
                dragEl = current.getDragEl();
                // Add current drag class to dragged element
                if (dragEl) {
                    dragEl = Ext.fly(dragEl);
                    // WORKAROUND: handle addCls manually
                    if (dragEl.dom
                        && (classList = dragEl.dom.classList)
                        && !classList.contains(me.dragCls)) {
                        classList.add(me.dragCls);
                    }
                    else {
                        dragEl.addCls(me.dragCls);
                    }
                }
            }
            me.dragThreshMet = true;
        };
        Ext.create('Ext.container.Viewport', {
            layout: 'fit',
            items: {
                xtype: 'panel',
                style: 'background: #CCCCCC',
                border: true,
                layout: 'fit',
                items: {
                    xtype: 'draw',
                    viewBox: false,
                    border: false,
                    items: [{
                        type: 'rect',
                        x: 100,
                        y: 100,
                        width: 100,
                        height: 100,
                        fill: '#f00',
                        stroke: '#0f0',
                        'stroke-width': 1,
                        /*draggable: true,*/
                        listeners: {
                            // WORKAROUND: initDraggable, when sprite is rendered
                            render: function(sprite) {
                                sprite.draggable = true;
                                sprite.initDraggable();
                            }
                        }
                    }]
                }
            }
        })
    });

  6. #6
    Sencha User only_do@126.com's Avatar
    Join Date
    Jul 2008
    Posts
    14
    Vote Rating
    0
    only_do@126.com is on a distinguished road

      0  

    Default ths very much.

    ths very much.


    ,This problem track me long time.thanks very much for patch it.
    MSN:only_do@hotmail.com
    QQ:9768846

  7. #7
    Sencha User
    Join Date
    Jan 2012
    Location
    Moscow
    Posts
    10
    Vote Rating
    2
    odibo is on a distinguished road

      0  

    Default


    It seems, SVG elements and HTML elements must be treated differently when it comes to classes. Consider using overrides:

    Code:
    if (Ext.versions.extjs.shortVersion == "421883") {
        
        Ext.require('Ext.dd.DragDropManager');
        
        Ext.override(Ext.dd.DragDropManager, {
    
            startDrag: function(x, y) {
                
                var me = this,
                    current = me.dragCurrent,
                    dragEl;
    
                clearTimeout(me.clickTimeout);
                if (current) {
                    current.b4StartDrag(x, y);
                    current.startDrag(x, y);
                    dragEl = current.getDragEl();
    
                    //if (dragEl) {
                    if (dragEl && dragEl.dom.className.replace) { // svg elements have no css classes -- http://www.sencha.com/forum/showthread.php?261339-lt-SVGAnimatedString-gt-has-no-method-replace
                        Ext.fly(dragEl).addCls(me.dragCls);
                    }
                }
                me.dragThreshMet = true;
            }
    
        });
    
    }

  8. #8
    Sencha User
    Join Date
    Dec 2013
    Posts
    1
    Vote Rating
    0
    liub1989 is on a distinguished road

      0  

    Default


    Quote Originally Posted by odibo View Post
    It seems, SVG elements and HTML elements must be treated differently when it comes to classes. Consider using overrides:

    Code:
    if (Ext.versions.extjs.shortVersion == "421883") {
        
        Ext.require('Ext.dd.DragDropManager');
        
        Ext.override(Ext.dd.DragDropManager, {
    
            startDrag: function(x, y) {
                
                var me = this,
                    current = me.dragCurrent,
                    dragEl;
    
                clearTimeout(me.clickTimeout);
                if (current) {
                    current.b4StartDrag(x, y);
                    current.startDrag(x, y);
                    dragEl = current.getDragEl();
    
                    //if (dragEl) {
                    if (dragEl && dragEl.dom.className.replace) { // svg elements have no css classes -- http://www.sencha.com/forum/showthread.php?261339-lt-SVGAnimatedString-gt-has-no-method-replace
                        Ext.fly(dragEl).addCls(me.dragCls);
                    }
                }
                me.dragThreshMet = true;
            }
    
        });
    
    }
    this do not work;(Uncaught TypeError: Cannot read property 'className' of undefined)
    Above that can run;
    or
    Code:
    if (dragEl && dragEl.dom && dragEl.dom.className.replace) {