summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
authorPaul Arthur <paul.arthur@flowerysong.com>2013-01-25 17:09:04 -0500
committerPaul Arthur <paul.arthur@flowerysong.com>2013-01-25 18:01:15 -0500
commit34bc052426b194b39a88c831a4a2898230b170c8 (patch)
tree4370b67ccbb9f2770b3ac0dee13138331577cb1e /modules
parente371e27e0efda0e5e3bfd4f538006970cdfe97c9 (diff)
downloadampache-34bc052426b194b39a88c831a4a2898230b170c8.tar.gz
ampache-34bc052426b194b39a88c831a4a2898230b170c8.tar.bz2
ampache-34bc052426b194b39a88c831a4a2898230b170c8.zip
Update Whatever:hover to 3.11
http://peterned.home.xs4all.nl/csshover.html#changes Claims to fix a performance issue. Also move it out of templates/ into modules/ since it's external code.
Diffstat (limited to 'modules')
-rw-r--r--modules/whatever_hover/csshover3-source.htc284
-rw-r--r--modules/whatever_hover/csshover3.htc12
2 files changed, 296 insertions, 0 deletions
diff --git a/modules/whatever_hover/csshover3-source.htc b/modules/whatever_hover/csshover3-source.htc
new file mode 100644
index 00000000..99251920
--- /dev/null
+++ b/modules/whatever_hover/csshover3-source.htc
@@ -0,0 +1,284 @@
+<public:attach event="ondocumentready" onevent="CSSHover()" />
+<script>
+/**
+ * Whatever:hover - V3.11
+ * ------------------------------------------------------------
+ * Author - Peter Nederlof, http://www.xs4all.nl/~peterned
+ * License - http://creativecommons.org/licenses/LGPL/2.1
+ *
+ * Special thanks to Sergiu Dumitriu, http://purl.org/net/sergiu,
+ * for fixing the expression loop.
+ *
+ * Whatever:hover is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Whatever:hover is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * howto: body { behavior:url("csshover3.htc"); }
+ * ------------------------------------------------------------
+ */
+
+window.CSSHover = (function(){
+
+ // regular expressions, used and explained later on.
+ var REG_INTERACTIVE = /(^|\s)((([^a]([^ ]+)?)|(a([^#.][^ ]+)+)):(hover|active|focus))/i;
+ var REG_AFFECTED = /(.*?)\:(hover|active|focus)/i;
+ var REG_PSEUDO = /[^:]+:([a-z\-]+).*/i;
+ var REG_SELECT = /(\.([a-z0-9_\-]+):[a-z]+)|(:[a-z]+)/gi;
+ var REG_CLASS = /\.([a-z0-9_\-]*on(hover|active|focus))/i;
+ var REG_MSIE = /msie (5|6|7)/i;
+ var REG_COMPAT = /backcompat/i;
+
+ // property mapping, real css properties must be used in order to clear expressions later on...
+ // Uses obscure css properties that no-one is likely to use. The properties are borrowed to
+ // set an expression, and are then restored to the most likely correct value.
+ var Properties = {
+ index: 0,
+ list: ['text-kashida', 'text-kashida-space', 'text-justify'],
+ get: function() {
+ return this.list[(this.index++)%this.list.length];
+ }
+ };
+
+ // camelize is used to convert css properties from (eg) text-kashida to textKashida
+ var camelize = function(str) {
+ return str.replace(/-(.)/mg, function(result, match){
+ return match.toUpperCase();
+ });
+ };
+
+ /**
+ * Local CSSHover object
+ * --------------------------
+ */
+
+ var CSSHover = {
+
+ // array of CSSHoverElements, used to unload created events
+ elements: [],
+
+ // buffer used for checking on duplicate expressions
+ callbacks: {},
+
+ // init, called once ondomcontentready via the exposed window.CSSHover function
+ init:function() {
+ // don't run in IE8 standards; expressions don't work in standards mode anyway,
+ // and the stuff we're trying to fix should already work properly
+ if(!REG_MSIE.test(navigator.userAgent) && !REG_COMPAT.test(window.document.compatMode)) {
+ return;
+ }
+
+ // start parsing the existing stylesheets
+ var sheets = window.document.styleSheets, l = sheets.length;
+ for(var i=0; i<l; i++) {
+ this.parseStylesheet(sheets[i]);
+ }
+ },
+
+ // called from init, parses individual stylesheets
+ parseStylesheet:function(sheet) {
+ // check sheet imports and parse those recursively
+ if(sheet.imports) {
+ try {
+ var imports = sheet.imports;
+ var l = imports.length;
+ for(var i=0; i<l; i++) {
+ this.parseStylesheet(sheet.imports[i]);
+ }
+ } catch(securityException){
+ // trycatch for various possible errors
+ }
+ }
+
+ // interate the sheet's rules and send them to the parser
+ try {
+ var rules = sheet.rules;
+ var r = rules.length;
+ for(var j=0; j<r; j++) {
+ this.parseCSSRule(rules[j], sheet);
+ }
+ } catch(someException){
+ // trycatch for various errors, most likely accessing the sheet's rules.
+ }
+ },
+
+ // magic starts here ...
+ parseCSSRule:function(rule, sheet) {
+
+ // The sheet is used to insert new rules into, this must be the same sheet the rule
+ // came from, to ensure that relative paths keep pointing to the right location.
+
+ // only parse a rule if it contains an interactive pseudo.
+ var select = rule.selectorText;
+ if(REG_INTERACTIVE.test(select)) {
+ var style = rule.style.cssText;
+
+ // affected elements are found by truncating the selector after the interactive pseudo,
+ // eg: "div li:hover" >> "div li"
+ var affected = REG_AFFECTED.exec(select)[1];
+
+ // that pseudo is needed for a classname, and defines the type of interaction (focus, hover, active)
+ // eg: "li:hover" >> "onhover"
+ var pseudo = select.replace(REG_PSEUDO, 'on$1');
+
+ // the new selector is going to use that classname in a new css rule,
+ // since IE6 doesn't support multiple classnames, this is merged into one classname
+ // eg: "li:hover" >> "li.onhover", "li.folder:hover" >> "li.folderonhover"
+ var newSelect = select.replace(REG_SELECT, '.$2' + pseudo);
+
+ // the classname is needed for the events that are going to be set on affected nodes
+ // eg: "li.folder:hover" >> "folderonhover"
+ var className = REG_CLASS.exec(newSelect)[1];
+
+ // no need to set the same callback more than once when the same selector uses the same classname
+ var hash = affected + className;
+ if(!this.callbacks[hash]) {
+
+ // affected elements are given an expression under a borrowed css property, because fake properties
+ // can't have their expressions cleared. Different properties are used per pseudo, to avoid
+ // expressions from overwriting eachother. The expression does a callback to CSSHover.patch,
+ // rerouted via the exposed window.CSSHover function.
+ var property = Properties.get();
+ var atRuntime = camelize(property);
+
+ // because the expression is added to the stylesheet, and styles are always applied to html that is
+ // dynamically added to the dom, the expression will also trigger for those new elements (provided
+ // they are selected by the affected selector).
+ sheet.addRule(affected, property + ':expression(CSSHover(this, "'+pseudo+'", "'+className+'", "'+atRuntime+'"))');
+
+ // hash it, so an identical selector/class combo does not duplicate the expression
+ this.callbacks[hash] = true;
+ }
+
+ // duplicate expressions need not be set, but the style could differ
+ sheet.addRule(newSelect, style);
+ }
+ },
+
+ // called via the expression, patches individual nodes
+ patch:function(node, type, className, property) {
+
+ // restores the borrowed css property to the value of its immediate parent, clearing
+ // the expression so that it's not repeatedly called.
+ try {
+ var value = node.parentNode.currentStyle[property];
+ node.style[property] = value;
+ } catch(e) {
+ // the above reset should never fail, but just in case, clear the runtimeStyle if it does.
+ // this will also stop the expression.
+ node.runtimeStyle[property] = '';
+ }
+
+ // just to make sure, also keep track of patched classnames locally on the node
+ if(!node.csshover) {
+ node.csshover = [];
+ }
+
+ // and check for it to prevent duplicate events with the same classname from being set
+ if(!node.csshover[className]) {
+ node.csshover[className] = true;
+
+ // create an instance for the given type and class
+ var element = new CSSHoverElement(node, type, className);
+
+ // and store that instance for unloading later on
+ this.elements.push(element);
+ }
+
+ // returns a dummy value to the expression
+ return type;
+ },
+
+ // unload stuff onbeforeunload
+ unload:function() {
+ try {
+
+ // remove events
+ var l = this.elements.length;
+ for(var i=0; i<l; i++) {
+ this.elements[i].unload();
+ }
+
+ // and set properties to null
+ this.elements = [];
+ this.callbacks = {};
+
+ } catch (e) {
+ }
+ }
+ };
+
+ /**
+ * CSSHoverElement
+ * --------------------------
+ */
+
+ // the event types associated with the interactive pseudos
+ var CSSEvents = {
+ onhover: { activator: 'onmouseenter', deactivator: 'onmouseleave' },
+ onactive: { activator: 'onmousedown', deactivator: 'onmouseup' },
+ onfocus: { activator: 'onfocus', deactivator: 'onblur' }
+ };
+
+ // CSSHoverElement constructor, called via CSSHover.patch
+ function CSSHoverElement(node, type, className) {
+
+ // the CSSHoverElement patches individual nodes by manually applying the events that should
+ // have fired by the css pseudoclasses, eg mouseenter and mouseleave for :hover.
+
+ this.node = node;
+ this.type = type;
+ var replacer = new RegExp('(^|\\s)'+className+'(\\s|$)', 'g');
+
+ // store event handlers for removal onunload
+ this.activator = function(){ node.className += ' ' + className; };
+ this.deactivator = function(){ node.className = node.className.replace(replacer, ' '); };
+
+ // add the events
+ node.attachEvent(CSSEvents[type].activator, this.activator);
+ node.attachEvent(CSSEvents[type].deactivator, this.deactivator);
+ }
+
+ CSSHoverElement.prototype = {
+ // onbeforeunload, called via CSSHover.unload
+ unload:function() {
+
+ // remove events
+ this.node.detachEvent(CSSEvents[this.type].activator, this.activator);
+ this.node.detachEvent(CSSEvents[this.type].deactivator, this.deactivator);
+
+ // and set properties to null
+ this.activator = null;
+ this.deactivator = null;
+ this.node = null;
+ this.type = null;
+ }
+ };
+
+ // add the unload to the onbeforeunload event
+ window.attachEvent('onbeforeunload', function(){
+ CSSHover.unload();
+ });
+
+ /**
+ * Public hook
+ * --------------------------
+ */
+
+ return function(node, type, className, property) {
+ if(node) {
+ // called via the css expression; patches individual nodes
+ return CSSHover.patch(node, type, className, property);
+ } else {
+ // called ondomcontentready via the public:attach node
+ CSSHover.init();
+ }
+ };
+
+})();
+</script> \ No newline at end of file
diff --git a/modules/whatever_hover/csshover3.htc b/modules/whatever_hover/csshover3.htc
new file mode 100644
index 00000000..4fa021f5
--- /dev/null
+++ b/modules/whatever_hover/csshover3.htc
@@ -0,0 +1,12 @@
+<public:attach event="ondocumentready" onevent="CSSHover()" />
+<script>
+/**
+ * Whatever:hover - V3.11
+ * http://www.xs4all.nl/~peterned/
+ *
+ * Copyright (c) 2009 Peter Nederlof
+ * Licensed under the LGPL license
+ * http://creativecommons.org/licenses/LGPL/2.1
+ */
+window.CSSHover=(function(){var m=/(^|\s)((([^a]([^ ]+)?)|(a([^#.][^ ]+)+)):(hover|active|focus))/i;var n=/(.*?)\:(hover|active|focus)/i;var o=/[^:]+:([a-z\-]+).*/i;var p=/(\.([a-z0-9_\-]+):[a-z]+)|(:[a-z]+)/gi;var q=/\.([a-z0-9_\-]*on(hover|active|focus))/i;var s=/msie (5|6|7)/i;var t=/backcompat/i;var u={index:0,list:['text-kashida','text-kashida-space','text-justify'],get:function(){return this.list[(this.index++)%this.list.length]}};var v=function(c){return c.replace(/-(.)/mg,function(a,b){return b.toUpperCase()})};var w={elements:[],callbacks:{},init:function(){if(!s.test(navigator.userAgent)&&!t.test(window.document.compatMode)){return}var a=window.document.styleSheets,l=a.length;for(var i=0;i<l;i++){this.parseStylesheet(a[i])}},parseStylesheet:function(a){if(a.imports){try{var b=a.imports;var l=b.length;for(var i=0;i<l;i++){this.parseStylesheet(a.imports[i])}}catch(securityException){}}try{var c=a.rules;var r=c.length;for(var j=0;j<r;j++){this.parseCSSRule(c[j],a)}}catch(someException){}},parseCSSRule:function(a,b){var c=a.selectorText;if(m.test(c)){var d=a.style.cssText;var e=n.exec(c)[1];var f=c.replace(o,'on$1');var g=c.replace(p,'.$2'+f);var h=q.exec(g)[1];var i=e+h;if(!this.callbacks[i]){var j=u.get();var k=v(j);b.addRule(e,j+':expression(CSSHover(this, "'+f+'", "'+h+'", "'+k+'"))');this.callbacks[i]=true}b.addRule(g,d)}},patch:function(a,b,c,d){try{var f=a.parentNode.currentStyle[d];a.style[d]=f}catch(e){a.runtimeStyle[d]=''}if(!a.csshover){a.csshover=[]}if(!a.csshover[c]){a.csshover[c]=true;var g=new CSSHoverElement(a,b,c);this.elements.push(g)}return b},unload:function(){try{var l=this.elements.length;for(var i=0;i<l;i++){this.elements[i].unload()}this.elements=[];this.callbacks={}}catch(e){}}};var x={onhover:{activator:'onmouseenter',deactivator:'onmouseleave'},onactive:{activator:'onmousedown',deactivator:'onmouseup'},onfocus:{activator:'onfocus',deactivator:'onblur'}};function CSSHoverElement(a,b,c){this.node=a;this.type=b;var d=new RegExp('(^|\\s)'+c+'(\\s|$)','g');this.activator=function(){a.className+=' '+c};this.deactivator=function(){a.className=a.className.replace(d,' ')};a.attachEvent(x[b].activator,this.activator);a.attachEvent(x[b].deactivator,this.deactivator)}CSSHoverElement.prototype={unload:function(){this.node.detachEvent(x[this.type].activator,this.activator);this.node.detachEvent(x[this.type].deactivator,this.deactivator);this.activator=null;this.deactivator=null;this.node=null;this.type=null}};window.attachEvent('onbeforeunload',function(){w.unload()});return function(a,b,c,d){if(a){return w.patch(a,b,c,d)}else{w.init()}}})();
+</script> \ No newline at end of file