r52377 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r52376‎ | r52377 | r52378 >
Date:21:48, 24 June 2009
Author:tparscal
Status:ok (Comments)
Tags:
Comment:
Added IE only behavior for hover effect
Modified paths:
  • /trunk/phase3/skins/vector/csshover.htc (added) (history)

Diff [purge]

Index: trunk/phase3/skins/vector/csshover.htc
@@ -0,0 +1,262 @@
 2+<public:attach event="ondocumentready" onevent="CSSHover()" />
 3+<script>
 4+// <![CDATA[
 5+/**
 6+ * Whatever:hover - V3.00.081222
 7+ * ------------------------------------------------------------
 8+ * Author - Peter Nederlof, http://www.xs4all.nl/~peterned
 9+ * License - http://creativecommons.org/licenses/LGPL/2.1
 10+ *
 11+ * Whatever:hover is free software; you can redistribute it and/or
 12+ * modify it under the terms of the GNU Lesser General Public
 13+ * License as published by the Free Software Foundation; either
 14+ * version 2.1 of the License, or (at your option) any later version.
 15+ *
 16+ * Whatever:hover is distributed in the hope that it will be useful,
 17+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 19+ * Lesser General Public License for more details.
 20+ *
 21+ * howto: body { behavior:url("csshover3.htc"); }
 22+ * ------------------------------------------------------------
 23+ */
 24+
 25+window.CSSHover = (function(){
 26+
 27+ // regular expressions, used and explained later on.
 28+ var REG_INTERACTIVE = /(^|\s)((([^a]([^ ]+)?)|(a([^#.][^ ]+)+)):(hover|active|focus))/i,
 29+ REG_AFFECTED = /(.*?)\:(hover|active|focus)/i,
 30+ REG_PSEUDO = /[^:]+:([a-z-]+).*/i,
 31+ REG_SELECT = /(\.([a-z0-9_-]+):[a-z]+)|(:[a-z]+)/gi,
 32+ REG_CLASS = /\.([a-z0-9_-]*on(hover|active|focus))/i,
 33+ REG_MSIE = /msie (5|6|7)/i,
 34+ REG_COMPAT = /backcompat/i;
 35+
 36+ // css prefix, a leading dash would be nice (spec), but IE6 doesn't like that.
 37+ var CSSHOVER_PREFIX = 'csh-';
 38+
 39+ /**
 40+ * Local CSSHover object
 41+ * --------------------------
 42+ */
 43+
 44+ var CSSHover = {
 45+
 46+ // array of CSSHoverElements, used to unload created events
 47+ elements: [],
 48+
 49+ // buffer used for checking on duplicate expressions
 50+ callbacks: {},
 51+
 52+ // init, called once ondomcontentready via the exposed window.CSSHover function
 53+ init:function() {
 54+ // don't run in IE8 standards; expressions don't work in standards mode anyway,
 55+ // and the stuff we're trying to fix should already work properly
 56+ if(!REG_MSIE.test(navigator.userAgent) && !REG_COMPAT.test(window.document.compatMode)) return;
 57+
 58+ // start parsing the existing stylesheets
 59+ var sheets = window.document.styleSheets, l = sheets.length;
 60+ for(var i=0; i<l; i++) {
 61+ this.parseStylesheet(sheets[i]);
 62+ }
 63+ },
 64+
 65+ // called from init, parses individual stylesheets
 66+ parseStylesheet:function(sheet) {
 67+ // check sheet imports and parse those recursively
 68+ if(sheet.imports) {
 69+ try {
 70+ var imports = sheet.imports, l = imports.length;
 71+ for(var i=0; i<l; i++) {
 72+ this.parseStylesheet(sheet.imports[i]);
 73+ }
 74+ } catch(securityException){
 75+ // trycatch for various possible errors,
 76+ // todo; might need to be placed inside the for loop, since an error
 77+ // on an import stops following imports from being processed.
 78+ }
 79+ }
 80+
 81+ // interate the sheet's rules and send them to the parser
 82+ try {
 83+ var rules = sheet.rules, l = rules.length;
 84+ for(var j=0; j<l; j++) {
 85+ this.parseCSSRule(rules[j], sheet);
 86+ }
 87+ } catch(securityException){
 88+ // trycatch for various errors, most likely accessing the sheet's rules,
 89+ // don't see how individual rules would throw errors, but you never know.
 90+ }
 91+ },
 92+
 93+ // magic starts here ...
 94+ parseCSSRule:function(rule, sheet) {
 95+
 96+ // The sheet is used to insert new rules into, this must be the same sheet the rule
 97+ // came from, to ensure that relative paths keep pointing to the right location.
 98+
 99+ // only parse a rule if it contains an interactive pseudo.
 100+ var select = rule.selectorText;
 101+ if(REG_INTERACTIVE.test(select)) {
 102+ var style = rule.style.cssText,
 103+
 104+ // affected elements are found by truncating the selector after the interactive pseudo,
 105+ // eg: "div li:hover" >> "div li"
 106+ affected = REG_AFFECTED.exec(select)[1],
 107+
 108+ // that pseudo is needed for a classname, and defines the type of interaction (focus, hover, active)
 109+ // eg: "li:hover" >> "onhover"
 110+ pseudo = select.replace(REG_PSEUDO, 'on$1'),
 111+
 112+ // the new selector is going to use that classname in a new css rule,
 113+ // since IE6 doesn't support multiple classnames, this is merged into one classname
 114+ // eg: "li:hover" >> "li.onhover", "li.folder:hover" >> "li.folderonhover"
 115+ newSelect = select.replace(REG_SELECT, '.$2' + pseudo),
 116+
 117+ // the classname is needed for the events that are going to be set on affected nodes
 118+ // eg: "li.folder:hover" >> "folderonhover"
 119+ className = REG_CLASS.exec(newSelect)[1];
 120+
 121+ // no need to set the same callback more than once when the same selector uses the same classname
 122+ var hash = affected + className;
 123+ if(!this.callbacks[hash]) {
 124+
 125+ // affected elements are given an expression under a fake css property, the classname is used
 126+ // because a unique name (eg "behavior:") would be overruled (in IE6, not 7) by a following rule
 127+ // selecting the same element. The expression does a callback to CSSHover.patch, rerouted via the
 128+ // exposed window.CSSHover function.
 129+
 130+ // because the expression is added to the stylesheet, and styles are always applied to html that is
 131+ // dynamically added to the dom, the expression will also trigger for those new elements (provided
 132+ // they are selected by the affected selector).
 133+
 134+ sheet.addRule(affected, CSSHOVER_PREFIX + className + ':expression(CSSHover(this, "'+pseudo+'", "'+className+'"))');
 135+
 136+ // hash it, so an identical selector/class combo does not duplicate the expression
 137+ this.callbacks[hash] = true;
 138+ }
 139+
 140+ // duplicate expressions need not be set, but the style could differ
 141+ sheet.addRule(newSelect, style);
 142+ }
 143+ },
 144+
 145+ // called via the expression, patches individual nodes
 146+ patch:function(node, type, className) {
 147+
 148+ // the patch's type is returned to the expression. That way the expression property
 149+ // can be found and removed, to stop it from calling patch over and over.
 150+ // The if will fail the first time, since the expression has not yet received a value.
 151+ var property = CSSHOVER_PREFIX + className;
 152+ if(node.style[property]) {
 153+ node.style[property] = null;
 154+ }
 155+
 156+ // just to make sure, also keep track of patched classnames locally on the node
 157+ if(!node.csshover) node.csshover = [];
 158+
 159+ // and check for it to prevent duplicate events with the same classname from being set
 160+ if(!node.csshover[className]) {
 161+ node.csshover[className] = true;
 162+
 163+ // create an instance for the given type and class
 164+ var element = new CSSHoverElement(node, type, className);
 165+
 166+ // and store that instance for unloading later on
 167+ this.elements.push(element);
 168+ }
 169+
 170+ // returns a dummy value to the expression
 171+ return type;
 172+ },
 173+
 174+ // unload stuff onbeforeunload
 175+ unload:function() {
 176+ try {
 177+
 178+ // remove events
 179+ var l = this.elements.length;
 180+ for(var i=0; i<l; i++) {
 181+ this.elements[i].unload();
 182+ }
 183+
 184+ // and set properties to null
 185+ this.elements = [];
 186+ this.callbacks = {};
 187+
 188+ } catch (e) {
 189+ }
 190+ }
 191+ };
 192+
 193+ // add the unload to the onbeforeunload event
 194+ window.attachEvent('onbeforeunload', function(){
 195+ CSSHover.unload();
 196+ });
 197+
 198+ /**
 199+ * CSSHoverElement
 200+ * --------------------------
 201+ */
 202+
 203+ // the event types associated with the interactive pseudos
 204+ var CSSEvents = {
 205+ onhover: { activator: 'onmouseenter', deactivator: 'onmouseleave' },
 206+ onactive: { activator: 'onmousedown', deactivator: 'onmouseup' },
 207+ onfocus: { activator: 'onfocus', deactivator: 'onblur' }
 208+ };
 209+
 210+ // CSSHoverElement constructor, called via CSSHover.patch
 211+ function CSSHoverElement(node, type, className) {
 212+
 213+ // the CSSHoverElement patches individual nodes by manually applying the events that should
 214+ // have fired by the css pseudoclasses, eg mouseenter and mouseleave for :hover.
 215+
 216+ this.node = node;
 217+ this.type = type;
 218+ var replacer = new RegExp('(^|\\s)'+className+'(\\s|$)', 'g');
 219+
 220+ // store event handlers for removal onunload
 221+ this.activator = function(){ node.className += ' ' + className; };
 222+ this.deactivator = function(){ node.className = node.className.replace(replacer, ' '); };
 223+
 224+ // add the events
 225+ node.attachEvent(CSSEvents[type].activator, this.activator);
 226+ node.attachEvent(CSSEvents[type].deactivator, this.deactivator);
 227+ }
 228+
 229+ CSSHoverElement.prototype = {
 230+ // onbeforeunload, called via CSSHover.unload
 231+ unload:function() {
 232+
 233+ // remove events
 234+ this.node.detachEvent(CSSEvents[this.type].activator, this.activator);
 235+ this.node.detachEvent(CSSEvents[this.type].deactivator, this.deactivator);
 236+
 237+ // and set properties to null
 238+ this.activator = null;
 239+ this.deactivator = null;
 240+ this.node = null;
 241+ this.type = null;
 242+ }
 243+ };
 244+
 245+ /**
 246+ * Public hook
 247+ * --------------------------
 248+ */
 249+
 250+ return function(node, type, className) {
 251+ if(node) {
 252+ // called via the css expression; patches individual nodes
 253+ return CSSHover.patch(node, type, className);
 254+ } else {
 255+ // called ondomcontentready via the public:attach node
 256+ CSSHover.init();
 257+ }
 258+ };
 259+
 260+})();
 261+
 262+// ]]>
 263+</script>
\ No newline at end of file

Comments

#Comment by Tim Starling (talk | contribs)   11:23, 10 July 2009

Is this meant to be referenced from somewhere?

#Comment by Brion VIBBER (talk | contribs)   00:35, 24 August 2009

(it has since been referenced, yes)

Status & tagging log