Using mootools Fx to modify the zoom of a div - javascript

I have a case where I'd like to animate the zoom style of a div (and it's entire contents). Legibility is not an issue, as this will be to 'pop' the element into view. Now I can get just about every other style aspect animating with Fx, but I can't seem to get this working for the zoom.
This is in chrome (though obviously I want to get it browser agnostic as well).
Using the Elements tab in the Chrome dev tools I can manually set the zoom style on the html element and it behaves accordingly, so I knew it must be possible to modify in code. Using the answer on this question: zoom css/javascript
I can get the element to zoom in and out with code:
dialog.setStyle('WebkitTransform', 'scale(0.1)')
Now I could write a 'native' function to do this, but then I'd lose out on all the great animation options in Fx. Can anyone suggest an elegent way to achieve this with Fx?

yes, you need to hack some of the CSS parsers in the mootools core to enable FX to work with them.
check this fun example I did a while back for another SO problem: http://jsfiddle.net/dimitar/ZwMUH/ - click on any 2 icons to swap them and it will transition them via scale.
or this light box base class I wrote that also uses it: http://jsfiddle.net/dimitar/6creP/
at its basic, start by modding the parsers:
Element.Styles.MozTransform = "rotate(#deg) scale(#)";
Element.Styles.MsTransform = "rotate(#deg) scale(#)";
Element.Styles.OTransform = "rotate(#deg) scale(#)";
Element.Styles.WebkitTransform = "rotate(#deg) scale(#)";
Object.append(Fx.CSS.Parsers, {
TransformScale: {
parse: function(value) {
return ((value = value.match(/^scale\((([0-9]*\.)?[0-9]+)\)$/i))) ? parseFloat(value[1]) : false;
},
compute: function(from, to, delta) {
return Fx.compute(from, to, delta);
},
serve: function(value) {
return 'scale(' + value + ')';
}
}
});
also relevant, define public and scripting vers of all styles cross browser:
transforms: {
computed: ['transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform'],
raw: ['transform', '-webkit-transform', '-moz-transform', '-o-transform', 'msTransform']
};
detection method which will loop through the transforms defined above and return the first one that the element supports as the definitive property to work with in the future, or opacity as fallback if unavailable:
var testEl = new Element("div"),
self = this;
this.scaleTransform = this.options.transforms.computed.some(function(el, index) {
var test = el in testEl.style;
if (test) {
self.prop = self.options.transforms.raw[index];
}
return test;
});
if (!this.prop) {
this.prop = "opacity";
}
then this.prop will refer to the correct browser property, vendor prefixed or opacity as fallback for tweening/morphing whereas this.scaleTransform will be a boolean that points to the ability to scale - you can then check against that to see if its supported when you are creating the morph object.
The object itself would be like this:
var morphObj = {};
morphObj[this.prop] = ["scale(0)", "scale(1)"]; // call it dynamically
el.morph(morphObj);
other solutions are available such as this plugin http://mootools.net/forge/p/fx_tween_css3, there's also one by Theiry Bela I know of: https://github.com/tbela99/Fx.css
its also going to be natively available in mootools 2.0
have fun.

Related

How to track a caller for native getters / setters of host objects in a browser?

Here is a use case:
Assume we have a web page that has an issue, which results in the page to be scrolled up on a mobile device at some point after DOMContentLoaded has fired.
We can legitimately assume there is something, which operates on document.documentElement.scrollTop (e.g. assigns it a value of 0).
Suppose we also know there are hundreds of places, where this can happen.
To debug the issue we can think of the following strategies:
check each event handler, which can set a value of 0 scrollTop, one by one
try to use debug function available in Chrome DevTools
Override a native scrollTop as:
var scrollTopOwner = document.documentElement.__proto__.__proto__.__proto__;
var oldDescr = Object.getOwnPropertyDescriptor(scrollTopOwner, 'scrollTop');
Object.defineProperty(scrollTopOwner, '_oldScrollTop_', oldDescr);
Object.defineProperty(scrollTopOwner, 'scrollTop', {
get:function(){
return this._oldScrollTop_;
},
set: function(v) {
debugger;
this._oldScrollTop_ = v;
}
});
function someMethodCausingAPageToScrollUp() {
document.scrollingElement.scrollTop = 1e3;
}
setTimeout(someMethodCausingAPageToScrollUp, 1000);
The issue with the second approach is that it doesn't work with native getters/setters.
The issue with the third approach is that even though now we can easily track what is assigning a value to the scrollTop property, we monkey patch a native getters/setters and risk to cause unnecessary side effects.
Hence the question: is there a more elegant solution to debug native getters and setters for web browser host objects (e.g. document, window, location, etc)?
const collector = [];
const originalScrollTop = Object.getOwnPropertyDescriptor(Element.prototype, 'scrollTop');
Object.defineProperty(Element.prototype, 'scrollTop', {
get: () => originalScrollTop.get.call(document.scrollingElement),
set: function(v) {
collector.push((new Error()).stack)
originalScrollTop.set.call(document.scrollingElement, v)
}
})
You can collect stacktraces and inspect them later. We don't log it immediately to not cause IO delays.
Works in Chrome.
Turns out it is possible to use debug function for set method on a scrollTop property descriptor.
The code is as follows:
debug(Object.getOwnPropertyDescriptor(Element.prototype, 'scrollTop').set);
After that, we'll automatically stop in any function that tries to set a value to scrollTop.
If you need to automatically stop only on those functions which assign a value within a certain threshold (for example, between 0 and 500), you can easily do that too since debug function accepts a second argument (condition) where you can specify your condition logic.
For example:
// In that case, we'll automatically stop only in those functions which assign scrollTop a value within a range of [1, 499] inclusively
debug(Object.getOwnPropertyDescriptor(Element.prototype, 'scrollTop').set, 'arguments[0] > 0 && arguments[0] < 500');
Pros:
easy to use and doesn't require a lot of boilerplate code
Cons:
you'll have to evaluate that js snippet above each time when you refresh your page
Many thanks to Aleksey Kozyatinskiy (former Googler on DevTools team) for the detailed explanation.

JavaScript Prototype Property Mirror Another Property

We have a bunch of forms on our Intranet coded for IE9 that contain code similar to this:
var dept = req.responseXML.selectNodes("//Dept")[0].text;
We just upgraded all of our PCs to IE10 and selectNodes is now obsolete and has been replaced with querySelectorAll, so the corrected bit of code would be:
var dept = req.responseXML.querySelectorAll("Dept")[0].textContent;
All these forms use a shared JS file for sending requests out so I thought if I could define some prototype functions/properties I could fix this incompatibility without touching every form. I made some progress and was able to map selectNodes to querySelectorAll using:
Document.prototype.selectNodes = function(param) {
return this.querySelectorAll(param.replace("//", ""));
}
However I am now running into issues mapping text to textContent. The following doesn't seem to work:
Element.prototype.text = function() {
return this.textContent;
};
If anyone has any adivce I would greatly appreciate it, I really don't want to track all these forms down. Thanks!
It really seems that you ought to fix your code rather than hack the DOM methods in order to avoid fixing your code. Imagine how this builds up over time and your code gets further and further away from programming to a standard DOM and then at some point, you'll probably even have a name collision with something that changes in a browser.
If you wanted to hack the code so that elem.text returns elem.textContent, then because these are properties references, not function calls you need to use a getter like this:
Object.defineProperty(HTMLElement.prototype, "text", {
get: function() {
return this.textContent || this.innerText;
},
set: function(txt) {
if (this.textContent) {
this.textContent = txt;
} else {
this.innerText = txt;
}
}
});

What is a proper way to detect the support of css "flex-box" and "flex-wrap"?

I'm looking for a solution how we can detect the support of css flex-box and flex-wrap by JavaScript.
I'm aware of modernizr which can do the job but my client does not allow us to load any scripts inside the head section, unfortunately this does not work when loading in the footer.
What is a proper way to achieve this detection on all kind of browsers / devices?
how we can detect the support of css flex-box and flex-wrap by
JavaScript.
Create an element and check the style property. If it is supported, it will return nothing i.e. '' else it will return undefined.
For example, if you run the below snippet in Chrome you will get undefined for columns and '' for flex-wrap.
Snippet:
console.log('flex = ' + document.createElement("p").style.flex);
console.log('columns = ' + document.createElement("p").style.columns);
console.log('flex-wrap = ' + document.createElement("p").style.flexWrap);
Although you have mentioned only Javascript in your question, but there is a CSS way of feature detection as well.
The #supports rule, also called CSS Feature Queries.
You provide the CSS declaration as the condition and the browser will execute that to return whether it supports or not. For example, the following CSS will apply green background color if flex is supported.
#supports (display: flex) {
div { background-color: #0f0; }
}
The browser support is good amongst all modern browsers, barring IE (as usual). For IE and (Safari < 9), you will need to keep a fallback option when #supports rule fails.
Combining the above two, there is an API around that as well which you can use in Javascript to do feature detection.
var isColumnSupported = CSS.supports('columns', '');
console.log('columns supported: ' + isColumnSupported);
var isFlexWrapSupported = CSS.supports('flex-wrap', 'wrap');
console.log('flex-wrap supported: ' + isFlexWrapSupported);
Since CSS.supports() is not supported on IE
This robust method can test any property:value support:
var cssPropertySupported = (function(){
var mem = {}; // save test results for efficient future calls with same parameters
return function cssPropertySupported(prop, values) {
if( mem[prop+values] )
return mem[prop+values];
var element = document.createElement('p'),
index = values.length,
name,
result = false;
try {
while (index--) {
name = values[index];
element.style.display = name;
if (element.style.display === name){
result = true;
break;
}
}
}
catch (pError) {}
mem[prop+values] = result;
return result;
}
})();
///////// TEST: ////////////////////
console.log(
cssPropertySupported('display', ['-ms-flexbox', '-webkit-box', 'flex'])
)
You manually need to provide the test function all the possible property names since the code cannot guess (too many possibilities). This keeps the test code slim instead of it have all possible property names already within it.

How to get the full list of Modernizr features

Is there any way to get a list of all features detected by Modernizr?
The current naming of features is very unintuitive, for example to check for feature "canvas" you just have to call Modernizr.canvas but in order to check for "forms-placeholder" or "forms_placeholder" (it depends on whether you check for the feature's name on the page or in the generated code) you have to call Modernizr.placeholder
There seems to be no rule in the naming of features. I couldn't even find a complete reference of all these features, especially the "non-core" ones. The documentation on modernizr.com is very poor. It also lacks a good tutorial. All I can do is simply guess it's names, since only some of them are included as the class names for the <html> tag (for example, you won't find "Input Types" or "Input Attributes" there).
All I need is to call some functions only when specific feature is supported, for example:
if(Modernizr.canvas){
// draw canvas
}
I tried to detect whether the browser supports .toDataURL('image/png') function, but the Modernizr script returns only "todataurljpeg" and "todataurlwebp", even though the "todataurlpng" is somwhere in there.
How can I retrieve all the Modernizer.features names via JavaScript? Any links to some good references or tutorials will be appreciated (obviously not the ones from the Modernizr home page).
I think your biggest problem is you're mixing up your versions. In the current stable tag, 2.8.1, this is the test for todataurl:
// canvas.toDataURL type support
// http://www.w3.org/TR/html5/the-canvas-element.html#dom-canvas-todataurl
// This test is asynchronous. Watch out.
(function () {
if (!Modernizr.canvas) {
return false;
}
var image = new Image(),
canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d');
image.onload = function() {
ctx.drawImage(image, 0, 0);
Modernizr.addTest('todataurljpeg', function() {
return canvas.toDataURL('image/jpeg').indexOf('data:image/jpeg') === 0;
});
Modernizr.addTest('todataurlwebp', function() {
return canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0;
});
};
image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==';
}());
(source: https://github.com/Modernizr/Modernizr/blob/v2.8.1/feature-detects/canvas-todataurl-type.js)
You'll notice in particular that 'todataurlpng' is not present.
Now, here's the test in master (3.0 beta):
/*!
{
"name": "canvas.toDataURL type support",
"property": ["todataurljpeg", "todataurlpng", "todataurlwebp"],
"tags": ["canvas"],
"builderAliases": ["canvas_todataurl_type"],
"async" : false,
"notes": [{
"name": "HTML5 Spec",
"href": "http://www.w3.org/TR/html5/the-canvas-element.html#dom-canvas-todataurl"
}]
}
!*/
define(['Modernizr', 'createElement', 'test/canvas'], function( Modernizr, createElement ) {
var canvas = createElement('canvas');
Modernizr.addTest('todataurljpeg', function() {
return !!Modernizr.canvas && canvas.toDataURL('image/jpeg').indexOf('data:image/jpeg') === 0;
});
Modernizr.addTest('todataurlpng', function() {
return !!Modernizr.canvas && canvas.toDataURL('image/png').indexOf('data:image/png') === 0;
});
Modernizr.addTest('todataurlwebp', function() {
return !!Modernizr.canvas && canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0;
});
});
(source: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/canvas/todataurl.js)
There it is!
The docs are better than you think, but 3.0 beta is a major rewrite and the docs have not been updated (mostly because it hasn't actually been released, yet). Just keep in mind that if you see something you think should be there or isn't mentioned in the docs, it's probably something new in the beta.
As for a list of all the feature detections, there's the docs, which is still your safest bet. I also found this nifty site, but it appears that, despite what it says in the description, the tool is referencing the master branch, and is thus, pulling from 3.0 beta with all the new and changed detects. So it might be a little off-putting for now.

SYNTAX_ERR: DOM Exception 12 - Hmmm

I have been working on a small slideshow / public display for a client that uses HTML5 Rock's Slideshow code. I have run into a DOM Exception 12 - a syntax error that is supposedly related to CSS selectors - while monkeying around with it... but I can't trace it back to any changes I made in the code. I am thinking it might be something that was uncovered as I added features.
I have traced it down to this object (live version here):
var SlideShow = function(slides) {
this._slides = (slides || []).map(function(el, idx) {
return new Slide(el, idx);
});
var h = window.location.hash;
try {
this.current = h;
} catch (e) { /* squeltch */ }
this.current = (!this.current) ? "landing-slide" : this.current.replace('#', '');
if (!query('#' + this.current)) {
// if this happens is very likely that someone is coming from
// a link with the old permalink format, i.e. #slide24
alert('The format of the permalinks have recently changed. If you are coming ' +
'here from an old external link it\'s very likely you will land to the wrong slide');
this.current = "landing-slide";
}
var _t = this;
doc.addEventListener('keydown',
function(e) { _t.handleKeys(e); }, false);
doc.addEventListener('touchstart',
function(e) { _t.handleTouchStart(e); }, false);
doc.addEventListener('touchend',
function(e) { _t.handleTouchEnd(e); }, false);
window.addEventListener('popstate',
function(e) { if (e.state) { _t.go(e.state, true); } }, false);
};
Instantiation of SlideShow() (line 521 in main.js):
var slideshow = new SlideShow(queryAll('.slide'));
Calling queryAll('.slide') returns an array of all the slides with an class of .slide. However, when passing queryAll('.slide') as a parameter for instantiating SlideShow(), it returns a DOM Exception 12 error.
Has anybody seen this before?
You are using illegal id-attributes(illegal before HTML5) inside the document, e.g. 2-slide . Fix them.
To explain:
to solve the known misbehaviour of element.querySelectorAll() the selector .slide will be internally rewritten(by using the id of the element). This will result in something like that:
#2-slide .moreselectors
...and forces the error, because an ID may not start with a Number.
See the fiddle: http://jsfiddle.net/doktormolle/FGWhk/
If you are coming here after searching for this error in HTML5 rocks slides:
For some reason they remove the class 'to-build' with the following:
toBuild[0].classList.remove('to-build', '');
That breaks all slide decks the use build, even the Google demo right now is broken
Just change line 220 of default.js to
toBuild[0].classList.remove('to-build');
all is well!
In my case it was using self.postMessage(e.data); in the main thread while using web workers.
I know it's not related to the OP's issue, but it's an odd error so I'm leaving this here in hope it helps others.
Same problem to me but in my case a try to get elements from their attribute
document.querySelectorAll('input[name="path"]')
and SYNTAX_ERR: DOM Exception 12 occurred only on Safari. So i've change it to get the element directly from class and now work fine.
You can escape the quotes like in applescript then no issue on safari
do JavaScript "document.querySelector('span[" & attrName & "=\"" & attrValue & "\"]').click();"

Categories