Restrict access to 'style' property in JavaScript - javascript

I'm starting to develop a small JavaScript library and I want to make styling of HTML elements possible only through my API (because for some reason I need to have full control over styling).
So I want to make style property inaccessible (my API will access it through my style alias - not an ideal solution, but for other libraries like jQuery it will do the trick).
If I write this (inspired by this topic):
var box = document.getElementById('someElementId');
Object.defineProperty(box, 'style', {
get: function() {
throw 'you cant access style property';
}
});
box.style.color = 'red';
it works for box element only.
Is it possible to do this for all (existing and future) elements in Webkit, Firefox, and IE9+?
I've also tried this:
Object.defineProperty(HTMLElement, 'style', {...
but no luck.
Any help would be greatly appreciated!
Edit
As #Teemu suggested I can write HTMLElement.prototype instead of HTMLElement, and it works fine in FF and IE, but not in Chrome. And it looks like a Chrome bug. Sadly...
Edit2 - why do I need it
The main goal of a library I want to develop is to allow writing styles like:
element.setWidth('parent.width / 2 - 10');
In this case element's width should react on each changing of the parent's width.
But since onresize event is available only for window object (this article seems to be obsolete),
the only way I can "listen" modifying .style.width property is to perform my own API for styling.
And I want to restrict (or at least show warning) direct style modifying because it will break the elements' behavior.

From the comments you can tell that restricting access to the style property is probably not such a good route. But I understand from your question that your reason from trying to go this route is that the resize event only fires for the window object.
If you would be able to circumvent the whole restricting issue with a resize event on just any element, than may I suggest you look into Ben Alman's jQuery resize event plugin. I'm not sure whether you want to develop with jQuery, but even if you don't it may be worth it to read that plugin's code. Basically, what it does is make a hashtable of listeners mapped to the element(s) they are listening on and then in a polling loop (with setTimeout or setInterval) check the size of the elements in that map. If it has changed during the interval (250ms by default) it triggers the listeners itself. It works reasonably well. That specific plugin hooks into jQuery's event system, but you could just make your own addResizeEvent function or something to that effect.
Edit: Upon re-reading your question it dawns on me that it looks like you are trying to develop some mechanism to deal with the downsides of the CSS box model, e.g. that when you give an element 5px padding and a width of 50% it will end up being 10 pixels wider than half the parent container. Consider box-sizing: border-box if that is the case.

Related

Get property of DOM element the Angular 2 way

I need to get the width of a DOM element in pixles.
jQuery way...
var myWidth = $('.labels').width();
It looks like I need to get a hold of the ElementRef from within a #Component or Service and access the width property.
It also says that aside from security reasons, it can couple the app and the rendering layers therefore preventing future deployment to a web worker.
So what is the best way to access that div width? I am working with an image that fills its div horizontally. I am overlaying some elements and I make the calculation myHeight = aspectRatio * myWidth;
All of the related questions I see mention how to do it back while Angular2 was still in the release candidate stage. So many API changes in the stable release (a month and 4 days as of today) that I feel like some sort of #deprecated tag would be helpful.
Angular itself doesn't provide anything to read from the DOM.
If you want to read from the DOM you need to use ElementRef.
Using ElementRef is far less of a security concern than for example using jQuery.
It's correct that you prevent this application to work properly with server-side rendering or webworkers if you do.

listen to z-index change in Javascript? [duplicate]

I need an efficient mechanism for detecting changes to the DOM. Preferably cross-browser, but if there's any efficient means which are not cross browser, I can implement these with a fail-safe cross browser method.
In particular, I need to detect changes that would affect the text on a page, so any new, removed or modified elements, or changes to inner text (innerHTML) would be required.
I don't have control over the changes being made (they could be due to 3rd party javascript includes, etc), so it can't be approached from this angle - I need to "monitor" for changes somehow.
Currently I've implemented a "quick'n'dirty" method which checks body.innerHTML.length at intervals. This won't of course detect changes which result in the same length being returned, but in this case is "good enough" - the chances of this happening are extremely slim, and in this project, failing to detect a change won't result in lost data.
The problem with body.innerHTML.length is that it's expensive. It can take between 1 and 5 milliseconds on a fast browser, and this can bog things down a lot - I'm also dealing with a large-ish number of iframes and it all adds up. I'm pretty sure the expensiveness of doing this is because the innerHTML text is not stored statically by browsers, and needs to be calculated from the DOM every time it is read.
The types of answers I am looking for are anything from the "precise" (for example event) to the "good enough" - perhaps something as "quick'n'dirty" as the innerHTML.length method, but that executes faster.
EDIT:
I should also point out that whilst it would be "nice" to detect the precise element that has been modified, it is not an absolute necessity - just the fact that there has been any change would be good enough. Hopefully this broadens people's responses. I'm going to investigate Mutation Events, but I still need a fallback for IE support, so any whacky, creative, outside-of-the-square ideas would be very welcome.
To bring this up to date, the DOM4 standard does away with Mutation Events and replaces them with Mutation Observers: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
http://www.quirksmode.org/js/events/DOMtree.html
jQuery now supports a way to attach events to existing and future elements corresponding to a selector: http://docs.jquery.com/Events/live#typefn
Another interesting find - http://james.padolsey.com/javascript/monitoring-dom-properties/
Mutation events are the W3 recommendation of what you are looking for..
Not sure if they are supported all around.. (IE will most likely not support them..)
You could try using the DOMNodeInserted and DOMNodeRemoved events. Acording to Quirksmode, they kind of work in most browsers, with the notable exception of IE...
http://www.quirksmode.org/dom/events/index.html
I have recently written a plugin that does exactly that - jquery.initialize
You use it the same way as .each function
$(".some-element").initialize( function(){
$(this).css("color", "blue");
});
The difference from .each is - it takes your selector, in this case .some-element and wait for new elements with this selector in the future, if such element will be added, it will be initialized too.
In our case initialize function just change element color to blue. So if we'll add new element (no matter if with ajax or even F12 inspector or anything) like:
$("<div/>").addClass('some-element').appendTo("body"); //new element will have blue color!
Plugin will init it instantly. Also plugin makes sure one element is initialized only once. So if you add element, then .deatch() it from body and then add it again, it will not be initialized again.
$("<div/>").addClass('some-element').appendTo("body").detach()
.appendTo(".some-container");
//initialized only once
Plugin is based on MutationObserver - it will work on IE9 and 10 with dependencies as detailed on the readme page.
jQuery Mutate does this too, by default it supports like height, width, scrollHeight etc... but it also can be extended with a little bit of extra code to add new events like see if text has changed etc...
http://www.jqui.net/jquery-projects/jquery-mutate-official/
Hope it helps

How to find what javascript is acting on a DOM element on page load

I have red other answers however none of them cover my case.
I have a page (http://www.lacertussoftware.com/) and there is some javascript in one of my included files that is setting the min height and height of my page on the body tag. How can i figure out what javascript is doing this? I have 7 or so files that if i remove my parallax effect / nice scrolling / the gap all go away and don't know what is doing it. Breakpointing is not useful as its on page load (especially because the code i have included on the page is not minified.)
Have you considered simply searching the sources for /min-height/ or /body.{0,50}min-height/ (and the CSSOM equivalent minHeight)?
Alternatively you can add a getter/setters for the style property to the HTMLElement/Element prototype which logs accesses to the style property and then forwards calls them to the native browser implementation. If that doesn't work you may also have to instrument .setAttribute() since the style property can be modified that way too.
Obviously this has to be done as early as possible in the document.
You could also try chrome's "break on attributes modification" feature in the the elements view of the dev tools. Or the DOMEvent breakpoints under sources.
You could try inserting a debugger; statement as a first thing in the dom ready handler, all js will pause.
Now right click on the element in the source and add a break on -> attributes modifications

Updating skrollr dynamically

I'm looking for a way update the absolute position values of skrollr dynamically. Relative positioning is out of the question as the body tag is the parent element and extends the entire length of the page. The object in question is of fixed position inside the body tag.
1) Is there a way to dynamically update the absolute values on an element without needing to re-instantiate the entire plugin? For instance changing "data-8000-start" to "data-9000-start". Using jQuery to update these seems a bit inadequate.
2) Using constants seemed to almost get me there, but as noted, requires that I re-instantiate the plugin. Is there a way to pass a constant like this into the refresh method instead?
Let me start by saying thanks to #Prinzhorn for this amazing tool. It really is a nice piece and has been a huge asset. I've built custom solutions for this kind of thing before, but this really adds an element of ease to it.
It doesn't appear there is a supported method for dynamically updating data attributes with Skrollr right now though. But as noted in a comment above there is a request for it. However I managed to hack something together that is fairly inefficient. I only performed this action on resize so it was used as minimally as possible.
I used JS to remove all attributes from the element. This seems terribly inneficeint, but any attempts I made to just have it remove the data attributes didn't work very well at all.
I added the necessary attributes back on that were removed. Then changed my dynamic values and applied new data attributes.
Finally, I made a refresh call to Skrollr and only applied it to the element that I had updated. This helped to ensure that only the necessary parts were being updated.
Just to update the accepted answer, right now you just have to change it dinamically and then use the refresh method:
var sk = skrollr.init();
sk.refresh();

Are there mechanics in Javascript that can only be emitted by a real user?

I would like to find an interaction in Javascript that only a human can do, but javascript can track it if the user has done it.
Something like an only readable event but not writable.
You could use mouse-driven CSS pseudoclasses; I don't believe they can be triggered using Javascript: see Trigger css hover with JS for a little more information.
If you set some style aspect on the hover, for example, you might be able to detect that using javascript.
I don't know how well this approach would work cross-browser however, and you might need to use a visible element.
see also Activate an element's :active CSS pseudo-class using Javascript?

Categories