PDA

View Full Version : [CLOSED] Ext.fly strict mode incompatiblity



dfrederick
21 Apr 2014, 10:35 AM
Hello,
As implemented, Ext.fly is incapable of being called from a strict mode context as .caller is always null, causing Ext.fly.caller.$name to implode. This override stops it from blowing up.


Ext.define('Common.override.dom.Fly', (function () {
'use strict'; return { override: 'Ext.dom.Fly' };}()),function (Fly) { var flyweights = Fly.cache; Ext.fly = function (dom, named) { var fly = null; // name the flyweight after the calling method name if possible. named = named || Ext.fly.caller && Ext.fly.caller.$name //make safe for calling from strict context || '_global'; dom = Ext.getDom(dom); if (dom) { fly = Ext.cache[dom.id]; // If there's no Element cached, or the element cached is for another DOM node, return a Fly if (!fly || fly.dom !== dom) { fly = flyweights[named] || (flyweights[named] = new Fly()); fly.dom = dom; fly.isSynchronized = false; } } return fly; }; });

mitchellsimoens
21 Apr 2014, 12:16 PM
Thanks for the report! I have opened a bug in our bug tracker.

LesJ
21 Apr 2014, 12:26 PM
Is strict mode supported in Ext JS 5?

See this closed bug (http://www.sencha.com/forum/showthread.php?132503-INVALID-EXTJSIV-1859-callParent%28%29-breaks-Firefox-when-using-js-strict-mode).

dongryphon
24 Apr 2014, 1:17 PM
Reformatted code.



Hello,
As implemented, Ext.fly is incapable of being called from a strict mode context as .caller is always null, causing Ext.fly.caller.$name to implode. This override stops it from blowing up.



Ext.define('Common.override.dom.Fly', (function () {
'use strict';
return {
override: 'Ext.dom.Fly'
};
}()),
function (Fly) {
var flyweights = Fly.cache;
Ext.fly = function (dom, named) {
var fly = null;
// name the flyweight after the calling method name if possible.
named = named || Ext.fly.caller && Ext.fly.caller.$name
//make safe for calling from strict context
|| '_global';
dom = Ext.getDom(dom);

if (dom) {
fly = Ext.cache[dom.id];
// If there's no Element cached, or the element cached is for another DOM node, return a Fly
if (!fly || fly.dom !== dom) {
fly = flyweights[named] || (flyweights[named] = new Fly());
fly.dom = dom;
fly.isSynchronized = false;
}
}
return fly;
};
});

dongryphon
26 Apr 2014, 2:53 AM
The reason caller is now used in Ext.fly is to prevent fly "collisions" as methods of Element, CompositeElement, Layer and such call each other and often need fly instances. By using the caller's method name we prevent collisions and avoid more complex or costly solutions.

This safety improvement also translates to user code where fly instances are often (mistakenly) held in a local variable and used multiple times in that method.

The solution posted here, however, does not fix FF. Consider the new method:



Ext.fly = function(dom, named) {
var fly = null,
fn = Ext.fly,
nodeType;

// name the flyweight after the calling method name if possible.
named = named || (fn.caller && fn.caller.$name) || '_global';

dom = Ext.getDom(dom);

if (dom) {
nodeType = dom.nodeType;
// check if we have a valid node type or if the el is a window object before
// proceeding. This allows elements, document fragments, and document/window
// objects (even those inside iframes) to be wrapped.
if (Ext.Element.validNodeTypes[nodeType] || (!nodeType && (dom.window === dom))) {
fly = Ext.cache[dom.id];

// If there's no Element cached, or the element cached is for another DOM node, return a Fly
if (!fly || fly.dom !== dom) {
fly = flyweights[named] || (flyweights[named] = new Fly());
fly.dom = dom;
fly.isSynchronized = false;
}
}
}
return fly;
};


The issue is that the caller access does not return null - strict mode translates that into a TypeError preventing reasonable feature detection of the situation.

Even wrapping Ext.fly in a shim function does not work.



Ext.fly = (function (oldFly) {
return function (dom, named) {
return oldFly(dom, named);
}
}(Ext.fly));


That part is a bit of a mystery since the actual caller of Ext.fly is no longer a strict mode method.

In the end, this is the workaround if you are using strict mode:



Ext.fly = (function (oldFly) {
return function (dom, named) {
return oldFly(dom, named || '_global');
}
}(Ext.fly));