View Single Post
Old 01-09-2013, 09:09 AM   PM User | #11
rnd me
Senior Coder

 
rnd me's Avatar
 
Join Date: Jun 2007
Location: Urbana
Posts: 3,468
Thanks: 9
Thanked 466 Times in 450 Posts
rnd me is a jewel in the roughrnd me is a jewel in the roughrnd me is a jewel in the rough
I had to think about this for a min or two; nice.


i think your code would be more managble in a re-usable function, which isn't that difficult to work-up. the question, is do you wan't power or compatibility? if you can re-use the existing style object, all tools for animation should drop right in. That's power. If this isn't something that needs a bevy of existing tools, having a new element property by which to manipulate style isn't a big deal. Indeed, you code uses object.display instead of object.style.display.

the power version works in webkit, but not in FF:, which is sad because this version is invisible: it replaces element.style with a stand-in shadow.

Code:
function watchStyle(element, property, changeCallback){

    if(!element.style2){
	element.style2=element.style;
	delete element.style;
	element.style={};	
   }

 delete element.style[property];

 Object.defineProperty( element.style, property, { configurable: true,
   get: function(){return element.style2[property]; },
   set: function(val){ 
	var cStyle=element.style2[property];
	if( val==cStyle){return false;} // throw away duplicates
	element.style2[property]=val; // set actual style object

	 changeCallback.call(element, property, val);  
   },
 });

}


// Let's test it:
watchStyle(document.body, "color", function demoCB(prop, value){
  alert(prop +" changed to "+value);
});


// invoke watcher
document.body.style.color="blue";

// invoke watcher
document.body.style.color="red";

// invoke watcher (NOT!)
document.body.style.color="red";

// invoke watcher
document.body.style.color="blue";
there reason firefox rejects it is becasue it won't allow element.style to be deleted or replaced in whole, but webkit does...

giving up the cool factor, we can still accomplish the goal cross browser by using a property other than style. let's call it style2 for lack of imagination.

once you setup the subscription using watchStyle(), you then set style2.display instead of style.display, or whatever property you are monitoring:

Code:
function watchStyle(element, property, changeCallback){
  var pool= (element.style2=element.style2||{});
  delete pool[property];
 Object.defineProperty(pool, property, { configurable: true,
   get: function(){return element.style[property]; },
   set: function(val){ 
	var cStyle=element.style[property];
	if(val==cStyle){return false;} // throw away duplicates
	element.style[property]=val;
	changeCallback.call(element, property, val, cStyle);  
   },
 });

}

watchStyle(document.body, "color", function demoCB(prop, value, previousValue){
  alert(prop +" changed to "+value+" on "+this.outerHTML.split(">")[0].slice(0,25));
});

//demo test: should alert "red", then "blue", then be done.
document.body.style2.color="red";
document.body.style2.color="blue";
document.body.style2.color="blue"; // but not this time, it's a duplicate...
tested ff, ch, ie9
__________________
my site (updated 5/13)
STATS (2013/5) HTML5:90.2% MOB:14% IE7:0.5% IE8:8.6% IE9:9.8% IE10:10%
rnd me is offline   Reply With Quote