2

I am looking to override element.styleSheet.cssText function

element = document.createElement("style");
element.styleSheet.cssText = ...

Object.prototype.styleSheet.cssText = function(){
    console.log('override');
}

I get an error that styleSheet is null or undefined. I am using Internet explorer so I expect stylesheet to exist.

Any help is appreciated

Decrypter
  • 2,784
  • 12
  • 38
  • 57
  • 1
    `stylesheet` probably does exist... just not on **every** JavaScript Object. Why not try `Element.prototype.styleSheet...` instead? – Scott Mermelstein Nov 04 '13 at 19:36
  • I get an error "object expected" doing that. I need to override the stylesheet object in an file so when it comes to do element.styleSheet.cssText it will use my new implementation – Decrypter Nov 04 '13 at 19:41
  • Also, you may want to look into this similar question: http://stackoverflow.com/questions/10653782/getting-the-style-prototype-cssstylerule-cssrule-mess – Scott Mermelstein Nov 04 '13 at 19:57

1 Answers1

3

As far as I know, there is no real way to override the native cssText getter on a CSSStyleDeclaration object.

Let's have a look why:

var s = document.createElement('style'),
    style = s.style;

style instanceof CSSStyleDeclaration; //true

So far so good, however when we try to set the cssText property:

style.cssText = 'something';
style.cssText; //(empty string), the native setter did not allow setting an invalid style

As we can see, the cssText property implements native getters/setters that are invoked when we try to get/set the cssText property.

Ok, fine! Let's just redefine the custom CSSStyleDeclaration.prototype.cssText getter/setter. Well that doesn't work because it seems the cssText property doesn't come from the prototype and even if it would there's no way to get custom getters/setters using Object.getOwnPropertyDescriptor so we would not be able to invoke the native setter from our custom function.

Let's have a look anyway:

Object.defineProperty(CSSStyleDeclaration.prototype, 'cssText', {
    get: function () { return 'overrided'; }
});

document.createElement('style').style.cssText; //(empty string)

Is there a solution then? Well there's probably no safe solution to do it yet, but your best bet would be to replace the style property with a custom accessor on the newly created element. That accessor would return an object that implements the same interface a CSSStyleDeclaration instance would, but all the accessors/functions would have been replaced to delegate the operations to the original style object.

The returned object would basically act as a proxy object for the real style object. That would be the only way since we cannot access native getters/setters functions, otherwise we could have redefined the cssText accessor only on the native style object of the element.

In the following example, I demonstrate the idea by only proxying the cssText property.

Note: The reason we create an instance of CSSStyleDeclaration.prototype is to make sure that styleProxy instanceof CSSStyleDeclaration remains true.

THE IMPLEMENTATION IS INCOMPLETE AND NOT SAFE TO USE

document.createElement = (function (doc, nativeCreateEl) {
    return function() {
        var el = nativeCreateEl.apply(doc, arguments),
            nativeStyle = el.style,
            styleProxy = Object.create(CSSStyleDeclaration.prototype);

        Object.defineProperty(el, 'style', {
            get: function () {
                return styleProxy;
            }
        });

        Object.defineProperty(styleProxy, 'cssText', {
            set: function (styles) {
                console.log('setting cssText');

                nativeStyle.cssText = styles;
            },
            get: function () {
                return nativeStyle.cssText;
            }
        });

        return el;
    };
})(document, document.createElement);

var el = document.createElement('div'),
    s = el.style;

s.cssText = 'test'; //logs setting cssText
s.cssText; //(empty string) -> this is expected
s.cssText = 'color: red;'; //logs setting cssText
s.cssText; //color: red;
plalx
  • 42,889
  • 6
  • 74
  • 90