Index: branches/resourceloader/phase3/resources/mw/utilities/mw.utilities.client.js |
— | — | @@ -0,0 +1,185 @@ |
| 2 | +/* |
| 3 | + * User-agent detection |
| 4 | + */ |
| 5 | + |
| 6 | +( function( $, mw ) { |
| 7 | + |
| 8 | +/* Extension */ |
| 9 | + |
| 10 | +$.extend( mw.utilities, { |
| 11 | + 'client': { |
| 12 | + /** |
| 13 | + * Returns an object containing information about the browser |
| 14 | + * |
| 15 | + * The resulting client object will be in the following format: |
| 16 | + * { |
| 17 | + * 'name': 'firefox', |
| 18 | + * 'layout': 'gecko', |
| 19 | + * 'os': 'linux' |
| 20 | + * 'version': '3.5.1', |
| 21 | + * 'versionBase': '3', |
| 22 | + * 'versionNumber': 3.5, |
| 23 | + * } |
| 24 | + */ |
| 25 | + this.profile = function() { |
| 26 | + // Use the cached version if possible |
| 27 | + if ( typeof this.profile === 'undefined' ) { |
| 28 | + |
| 29 | + /* Configuration */ |
| 30 | + |
| 31 | + // Name of browsers or layout engines we don't recognize |
| 32 | + var uk = 'unknown'; |
| 33 | + // Generic version digit |
| 34 | + var x = 'x'; |
| 35 | + // Strings found in user agent strings that need to be conformed |
| 36 | + var wildUserAgents = [ 'Opera', 'Navigator', 'Minefield', 'KHTML', 'Chrome', 'PLAYSTATION 3']; |
| 37 | + // Translations for conforming user agent strings |
| 38 | + var userAgentTranslations = [ |
| 39 | + // Tons of browsers lie about being something they are not |
| 40 | + [/(Firefox|MSIE|KHTML,\slike\sGecko|Konqueror)/, ''], |
| 41 | + // Chrome lives in the shadow of Safari still |
| 42 | + ['Chrome Safari', 'Chrome'], |
| 43 | + // KHTML is the layout engine not the browser - LIES! |
| 44 | + ['KHTML', 'Konqueror'], |
| 45 | + // Firefox nightly builds |
| 46 | + ['Minefield', 'Firefox'], |
| 47 | + // This helps keep differnt versions consistent |
| 48 | + ['Navigator', 'Netscape'], |
| 49 | + // This prevents version extraction issues, otherwise translation would happen later |
| 50 | + ['PLAYSTATION 3', 'PS3'], |
| 51 | + ]; |
| 52 | + // Strings which precede a version number in a user agent string - combined and used as match 1 in |
| 53 | + // version detectection |
| 54 | + var versionPrefixes = [ |
| 55 | + 'camino', 'chrome', 'firefox', 'netscape', 'netscape6', 'opera', 'version', 'konqueror', 'lynx', |
| 56 | + 'msie', 'safari', 'ps3' |
| 57 | + ]; |
| 58 | + // Used as matches 2, 3 and 4 in version extraction - 3 is used as actual version number |
| 59 | + var versionSuffix = '(\/|\;?\s|)([a-z0-9\.\+]*?)(\;|dev|rel|\\)|\s|$)'; |
| 60 | + // Names of known browsers |
| 61 | + var browserNames = [ |
| 62 | + 'camino', 'chrome', 'firefox', 'netscape', 'konqueror', 'lynx', 'msie', 'opera', 'safari', 'ipod', |
| 63 | + 'iphone', 'blackberry', 'ps3' |
| 64 | + ]; |
| 65 | + // Tanslations for conforming browser names |
| 66 | + var browserTranslations = []; |
| 67 | + // Names of known layout engines |
| 68 | + var layoutNames = ['gecko', 'konqueror', 'msie', 'opera', 'webkit']; |
| 69 | + // Translations for conforming layout names |
| 70 | + var layoutTranslations = [['konqueror', 'khtml'], ['msie', 'trident'], ['opera', 'presto']]; |
| 71 | + // Names of known operating systems |
| 72 | + var osNames = ['win', 'mac', 'linux', 'sunos', 'solaris', 'iphone']; |
| 73 | + // Translations for conforming operating system names |
| 74 | + var osTranslations = [['sunos', 'solaris']]; |
| 75 | + |
| 76 | + /* Methods */ |
| 77 | + |
| 78 | + // Performs multiple replacements on a string |
| 79 | + function translate( source, translations ) { |
| 80 | + for ( var i = 0; i < translations.length; i++ ) { |
| 81 | + source = source.replace( translations[i][0], translations[i][1] ); |
| 82 | + } |
| 83 | + return source; |
| 84 | + }; |
| 85 | + |
| 86 | + /* Pre-processing */ |
| 87 | + |
| 88 | + var userAgent = navigator.userAgent, match, browser = uk, layout = uk, os = uk, version = x; |
| 89 | + if ( match = new RegExp( '(' + wildUserAgents.join( '|' ) + ')' ).exec( userAgent ) ) { |
| 90 | + // Takes a userAgent string and translates given text into something we can more easily work with |
| 91 | + userAgent = translate( userAgent, userAgentTranslations ); |
| 92 | + } |
| 93 | + // Everything will be in lowercase from now on |
| 94 | + userAgent = userAgent.toLowerCase(); |
| 95 | + |
| 96 | + /* Extraction */ |
| 97 | + |
| 98 | + if ( match = new RegExp( '(' + browserNames.join( '|' ) + ')' ).exec( userAgent ) ) { |
| 99 | + browser = translate( match[1], browserTranslations ); |
| 100 | + } |
| 101 | + if ( match = new RegExp( '(' + layoutNames.join( '|' ) + ')' ).exec( userAgent ) ) { |
| 102 | + layout = translate( match[1], layoutTranslations ); |
| 103 | + } |
| 104 | + if ( match = new RegExp( '(' + osNames.join( '|' ) + ')' ).exec( navigator.platform.toLowerCase() ) ) { |
| 105 | + var os = translate( match[1], osTranslations ); |
| 106 | + } |
| 107 | + if ( match = new RegExp( '(' + versionPrefixes.join( '|' ) + ')' + versionSuffix ).exec( userAgent ) ) { |
| 108 | + version = match[3]; |
| 109 | + } |
| 110 | + |
| 111 | + /* Edge Cases -- did I mention about how user agent string lie? */ |
| 112 | + |
| 113 | + // Decode Safari's crazy 400+ version numbers |
| 114 | + if ( name.match( /safari/ ) && version > 400 ) { |
| 115 | + version = '2.0'; |
| 116 | + } |
| 117 | + // Expose Opera 10's lies about being Opera 9.8 |
| 118 | + if ( name === 'opera' && version >= 9.8) { |
| 119 | + version = userAgent.match( /version\/([0-9\.]*)/i )[1] || 10; |
| 120 | + } |
| 121 | + |
| 122 | + /* Caching */ |
| 123 | + |
| 124 | + this.profile = { |
| 125 | + 'browser': browser, |
| 126 | + 'layout': layout, |
| 127 | + 'os': os, |
| 128 | + 'version': version, |
| 129 | + 'versionBase': ( version !== x ? new String( version ).substr( 0, 1 ) : x ), |
| 130 | + 'versionNumber': ( parseFloat( version, 10 ) || 0.0 ) |
| 131 | + }; |
| 132 | + } |
| 133 | + return this.profile; |
| 134 | + }; |
| 135 | + /** |
| 136 | + * Checks the current browser against a support map object to determine if the browser has been black-listed or |
| 137 | + * not. If the browser was not configured specifically it is assumed to work. It is assumed that the body |
| 138 | + * element is classified as either "ltr" or "rtl". If neither is set, "ltr" is assumed. |
| 139 | + * |
| 140 | + * A browser map is in the following format: |
| 141 | + * { |
| 142 | + * 'ltr': { |
| 143 | + * // Multiple rules with configurable operators |
| 144 | + * 'msie': [['>=', 7], ['!=', 9]], |
| 145 | + * // Blocked entirely |
| 146 | + * 'iphone': false |
| 147 | + * }, |
| 148 | + * 'rtl': { |
| 149 | + * // Test against a string |
| 150 | + * 'msie': [['!==', '8.1.2.3']], |
| 151 | + * // RTL rules do not fall through to LTR rules, you must explicity set each of them |
| 152 | + * 'iphone': false |
| 153 | + * } |
| 154 | + * } |
| 155 | + * |
| 156 | + * @param map Object of browser support map |
| 157 | + * |
| 158 | + * @return Boolean true if browser known or assumed to be supported, false if blacklisted |
| 159 | + */ |
| 160 | + this.test = function( map ) { |
| 161 | + var client = this.client(); |
| 162 | + // Check over each browser condition to determine if we are running in a compatible client |
| 163 | + var browser = map[$( 'body' ).is( '.rtl' ) ? 'rtl' : 'ltr'][client.browser]; |
| 164 | + if ( typeof browser !== 'object' ) { |
| 165 | + // Unknown, so we assume it's working |
| 166 | + return true; |
| 167 | + } |
| 168 | + for ( var condition in browser ) { |
| 169 | + var op = browser[condition][0]; |
| 170 | + var val = browser[condition][1]; |
| 171 | + if ( val === false ) { |
| 172 | + return false; |
| 173 | + } else if ( typeof val == 'string' ) { |
| 174 | + if ( !( eval( 'client.version' + op + '"' + val + '"' ) ) ) { |
| 175 | + return false; |
| 176 | + } |
| 177 | + } else if ( typeof val == 'number' ) { |
| 178 | + if ( !( eval( 'client.versionNumber' + op + val ) ) ) { |
| 179 | + return false; |
| 180 | + } |
| 181 | + } |
| 182 | + } |
| 183 | + return true; |
| 184 | + }; |
| 185 | + } |
| 186 | +} ); |
\ No newline at end of file |
Property changes on: branches/resourceloader/phase3/resources/mw/utilities/mw.utilities.client.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 187 | + native |
Index: branches/resourceloader/phase3/resources/mw/utilities/mw.utilities.url.js |
— | — | @@ -0,0 +1,76 @@ |
| 2 | +/* |
| 3 | + * |
| 4 | + */ |
| 5 | + |
| 6 | +( function( $, mw ) { |
| 7 | + |
| 8 | +/* Extension */ |
| 9 | + |
| 10 | +$.extend( mw.utilities, { |
| 11 | + 'url': { |
| 12 | + /** |
| 13 | + * Builds a url string from an object containing any of the following components: |
| 14 | + * |
| 15 | + * Component Example |
| 16 | + * scheme "http" |
| 17 | + * server "www.domain.com" |
| 18 | + * path "path/to/my/file.html" |
| 19 | + * query "this=thåt" or { 'this': 'thåt' } |
| 20 | + * fragment "place_on_the_page" |
| 21 | + * |
| 22 | + * Results in: "http://www.domain.com/path/to/my/file.html?this=th%C3%A5t#place_on_the_page" |
| 23 | + * |
| 24 | + * All arguments to this function are assumed to be URL-encoded already, except for the |
| 25 | + * query parameter if provided in object form. |
| 26 | + */ |
| 27 | + 'buildUrlString': function( components ) { |
| 28 | + var url = ''; |
| 29 | + if ( typeof components.scheme === 'string' ) { |
| 30 | + url += components.scheme + '://'; |
| 31 | + } |
| 32 | + if ( typeof components.server === 'string' ) { |
| 33 | + url += components.server + '/'; |
| 34 | + } |
| 35 | + if ( typeof components.path === 'string' ) { |
| 36 | + url += components.path; |
| 37 | + } |
| 38 | + if ( typeof components.query === 'string' ) { |
| 39 | + url += '?' + components.query; |
| 40 | + } else if ( typeof components.query === 'object' ) { |
| 41 | + url += '?' + that.buildQueryString( components.query ); |
| 42 | + } |
| 43 | + if ( typeof components.fragment === 'string' ) { |
| 44 | + url += '#' + components.fragment; |
| 45 | + } |
| 46 | + return url; |
| 47 | + }, |
| 48 | + /** |
| 49 | + * RFC 3986 compliant URI component encoder - with identical behavior as PHP's urlencode function. Note: PHP's |
| 50 | + * urlencode function prior to version 5.3 also escapes tildes, this does not. The naming here is not the same |
| 51 | + * as PHP because PHP can't decide out to name things (underscores sometimes?), much less set a reasonable |
| 52 | + * precedence for how things should be named in other environments. We use camelCase and action-subject here. |
| 53 | + */ |
| 54 | + 'encodeUrlComponent': function( string ) { |
| 55 | + return encodeURIComponent( new String( string ) ) |
| 56 | + .replace(/!/g, '%21') |
| 57 | + .replace(/'/g, '%27') |
| 58 | + .replace(/\(/g, '%28') |
| 59 | + .replace(/\)/g, '%29') |
| 60 | + .replace(/\*/g, '%2A') |
| 61 | + .replace(/%20/g, '+'); |
| 62 | + }, |
| 63 | + /** |
| 64 | + * Builds a query string from an object with key and values |
| 65 | + */ |
| 66 | + 'buildQueryString': function( parameters ) { |
| 67 | + if ( typeof parameters === 'object' ) { |
| 68 | + var parts = []; |
| 69 | + for ( var p in parameters ) { |
| 70 | + parts[parts.length] = that.encodeUrlComponent( p ) + '=' + that.encodeUrlComponent( parameters[p] ); |
| 71 | + } |
| 72 | + return parts.join( '&' ); |
| 73 | + } |
| 74 | + return ''; |
| 75 | + } |
| 76 | + } |
| 77 | +} ); |
\ No newline at end of file |
Property changes on: branches/resourceloader/phase3/resources/mw/utilities/mw.utilities.url.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 78 | + native |
Index: branches/resourceloader/phase3/resources/mw/mw.js |
— | — | @@ -387,10 +387,7 @@ |
388 | 388 | var html = ''; |
389 | 389 | for ( r in requests ) { |
390 | 390 | // Build out the HTML |
391 | | - var src = mw.util.buildUrlString( { |
392 | | - 'path': mw.config.get( 'wgScriptPath' ) + '/load.php', |
393 | | - 'query': requests[r] |
394 | | - } ); |
| 391 | + var src = mw.config.get( 'wgScriptPath' ) + '/load.php?' + jQuery.param( requests[r] ); |
395 | 392 | html += '<script type="text/javascript" src="' + src + '"></script>'; |
396 | 393 | } |
397 | 394 | // Append script to head |
— | — | @@ -495,257 +492,11 @@ |
496 | 493 | that.work(); |
497 | 494 | } ); |
498 | 495 | } )(); |
499 | | - /** |
500 | | - * General purpose utilities |
501 | | - */ |
502 | | - this.util = new ( function() { |
503 | | - |
504 | | - /* Private Members */ |
505 | | - |
506 | | - var that = this; |
507 | | - // Decoded user agent string cache |
508 | | - var client = null; |
509 | | - |
510 | | - /* Public Methods */ |
511 | | - |
512 | | - /** |
513 | | - * Builds a url string from an object containing any of the following components: |
514 | | - * |
515 | | - * Component Example |
516 | | - * scheme "http" |
517 | | - * server "www.domain.com" |
518 | | - * path "path/to/my/file.html" |
519 | | - * query "this=thåt" or { 'this': 'thåt' } |
520 | | - * fragment "place_on_the_page" |
521 | | - * |
522 | | - * Results in: "http://www.domain.com/path/to/my/file.html?this=th%C3%A5t#place_on_the_page" |
523 | | - * |
524 | | - * All arguments to this function are assumed to be URL-encoded already, except for the |
525 | | - * query parameter if provided in object form. |
526 | | - */ |
527 | | - this.buildUrlString = function( components ) { |
528 | | - var url = ''; |
529 | | - if ( typeof components.scheme === 'string' ) { |
530 | | - url += components.scheme + '://'; |
531 | | - } |
532 | | - if ( typeof components.server === 'string' ) { |
533 | | - url += components.server + '/'; |
534 | | - } |
535 | | - if ( typeof components.path === 'string' ) { |
536 | | - url += components.path; |
537 | | - } |
538 | | - if ( typeof components.query === 'string' ) { |
539 | | - url += '?' + components.query; |
540 | | - } else if ( typeof components.query === 'object' ) { |
541 | | - url += '?' + that.buildQueryString( components.query ); |
542 | | - } |
543 | | - if ( typeof components.fragment === 'string' ) { |
544 | | - url += '#' + components.fragment; |
545 | | - } |
546 | | - return url; |
547 | | - }; |
548 | | - /** |
549 | | - * RFC 3986 compliant URI component encoder - with identical behavior as PHP's urlencode function. Note: PHP's |
550 | | - * urlencode function prior to version 5.3 also escapes tildes, this does not. The naming here is not the same |
551 | | - * as PHP because PHP can't decide out to name things (underscores sometimes?), much less set a reasonable |
552 | | - * precedence for how things should be named in other environments. We use camelCase and action-subject here. |
553 | | - */ |
554 | | - this.encodeUrlComponent = function( string ) { |
555 | | - return encodeURIComponent( new String( string ) ) |
556 | | - .replace(/!/g, '%21') |
557 | | - .replace(/'/g, '%27') |
558 | | - .replace(/\(/g, '%28') |
559 | | - .replace(/\)/g, '%29') |
560 | | - .replace(/\*/g, '%2A') |
561 | | - .replace(/%20/g, '+'); |
562 | | - }; |
563 | | - /** |
564 | | - * Builds a query string from an object with key and values |
565 | | - */ |
566 | | - this.buildQueryString = function( parameters ) { |
567 | | - if ( typeof parameters === 'object' ) { |
568 | | - var parts = []; |
569 | | - for ( var p in parameters ) { |
570 | | - parts[parts.length] = that.encodeUrlComponent( p ) + '=' + that.encodeUrlComponent( parameters[p] ); |
571 | | - } |
572 | | - return parts.join( '&' ); |
573 | | - } |
574 | | - return ''; |
575 | | - }; |
576 | | - /** |
577 | | - * Returns an object containing information about the browser |
578 | | - * |
579 | | - * The resulting client object will be in the following format: |
580 | | - * { |
581 | | - * 'name': 'firefox', |
582 | | - * 'layout': 'gecko', |
583 | | - * 'os': 'linux' |
584 | | - * 'version': '3.5.1', |
585 | | - * 'versionBase': '3', |
586 | | - * 'versionNumber': 3.5, |
587 | | - * } |
588 | | - */ |
589 | | - this.client = function() { |
590 | | - // Use the cached version if possible |
591 | | - if ( client === null ) { |
592 | | - |
593 | | - /* Configuration */ |
594 | | - |
595 | | - // Name of browsers or layout engines we don't recognize |
596 | | - var uk = 'unknown'; |
597 | | - // Generic version digit |
598 | | - var x = 'x'; |
599 | | - // Strings found in user agent strings that need to be conformed |
600 | | - var wildUserAgents = [ 'Opera', 'Navigator', 'Minefield', 'KHTML', 'Chrome', 'PLAYSTATION 3']; |
601 | | - // Translations for conforming user agent strings |
602 | | - var userAgentTranslations = [ |
603 | | - // Tons of browsers lie about being something they are not |
604 | | - [/(Firefox|MSIE|KHTML,\slike\sGecko|Konqueror)/, ''], |
605 | | - // Chrome lives in the shadow of Safari still |
606 | | - ['Chrome Safari', 'Chrome'], |
607 | | - // KHTML is the layout engine not the browser - LIES! |
608 | | - ['KHTML', 'Konqueror'], |
609 | | - // Firefox nightly builds |
610 | | - ['Minefield', 'Firefox'], |
611 | | - // This helps keep differnt versions consistent |
612 | | - ['Navigator', 'Netscape'], |
613 | | - // This prevents version extraction issues, otherwise translation would happen later |
614 | | - ['PLAYSTATION 3', 'PS3'], |
615 | | - ]; |
616 | | - // Strings which precede a version number in a user agent string - combined and used as match 1 in |
617 | | - // version detectection |
618 | | - var versionPrefixes = [ |
619 | | - 'camino', 'chrome', 'firefox', 'netscape', 'netscape6', 'opera', 'version', 'konqueror', 'lynx', |
620 | | - 'msie', 'safari', 'ps3' |
621 | | - ]; |
622 | | - // Used as matches 2, 3 and 4 in version extraction - 3 is used as actual version number |
623 | | - var versionSuffix = '(\/|\;?\s|)([a-z0-9\.\+]*?)(\;|dev|rel|\\)|\s|$)'; |
624 | | - // Names of known browsers |
625 | | - var browserNames = [ |
626 | | - 'camino', 'chrome', 'firefox', 'netscape', 'konqueror', 'lynx', 'msie', 'opera', 'safari', 'ipod', |
627 | | - 'iphone', 'blackberry', 'ps3' |
628 | | - ]; |
629 | | - // Tanslations for conforming browser names |
630 | | - var browserTranslations = []; |
631 | | - // Names of known layout engines |
632 | | - var layoutNames = ['gecko', 'konqueror', 'msie', 'opera', 'webkit']; |
633 | | - // Translations for conforming layout names |
634 | | - var layoutTranslations = [['konqueror', 'khtml'], ['msie', 'trident'], ['opera', 'presto']]; |
635 | | - // Names of known operating systems |
636 | | - var osNames = ['win', 'mac', 'linux', 'sunos', 'solaris', 'iphone']; |
637 | | - // Translations for conforming operating system names |
638 | | - var osTranslations = [['sunos', 'solaris']]; |
639 | | - |
640 | | - /* Methods */ |
641 | | - |
642 | | - // Performs multiple replacements on a string |
643 | | - function translate( source, translations ) { |
644 | | - for ( var i = 0; i < translations.length; i++ ) { |
645 | | - source = source.replace( translations[i][0], translations[i][1] ); |
646 | | - } |
647 | | - return source; |
648 | | - }; |
649 | | - |
650 | | - /* Pre-processing */ |
651 | | - |
652 | | - var userAgent = navigator.userAgent, match, browser = uk, layout = uk, os = uk, version = x; |
653 | | - if ( match = new RegExp( '(' + wildUserAgents.join( '|' ) + ')' ).exec( userAgent ) ) { |
654 | | - // Takes a userAgent string and translates given text into something we can more easily work with |
655 | | - userAgent = translate( userAgent, userAgentTranslations ); |
656 | | - } |
657 | | - // Everything will be in lowercase from now on |
658 | | - userAgent = userAgent.toLowerCase(); |
659 | | - |
660 | | - /* Extraction */ |
661 | | - |
662 | | - if ( match = new RegExp( '(' + browserNames.join( '|' ) + ')' ).exec( userAgent ) ) { |
663 | | - browser = translate( match[1], browserTranslations ); |
664 | | - } |
665 | | - if ( match = new RegExp( '(' + layoutNames.join( '|' ) + ')' ).exec( userAgent ) ) { |
666 | | - layout = translate( match[1], layoutTranslations ); |
667 | | - } |
668 | | - if ( match = new RegExp( '(' + osNames.join( '|' ) + ')' ).exec( navigator.platform.toLowerCase() ) ) { |
669 | | - var os = translate( match[1], osTranslations ); |
670 | | - } |
671 | | - if ( match = new RegExp( '(' + versionPrefixes.join( '|' ) + ')' + versionSuffix ).exec( userAgent ) ) { |
672 | | - version = match[3]; |
673 | | - } |
674 | | - |
675 | | - /* Edge Cases -- did I mention about how user agent string lie? */ |
676 | | - |
677 | | - // Decode Safari's crazy 400+ version numbers |
678 | | - if ( name.match( /safari/ ) && version > 400 ) { |
679 | | - version = '2.0'; |
680 | | - } |
681 | | - // Expose Opera 10's lies about being Opera 9.8 |
682 | | - if ( name === 'opera' && version >= 9.8) { |
683 | | - version = userAgent.match( /version\/([0-9\.]*)/i )[1] || 10; |
684 | | - } |
685 | | - |
686 | | - /* Caching */ |
687 | | - |
688 | | - client = { |
689 | | - 'browser': browser, |
690 | | - 'layout': layout, |
691 | | - 'os': os, |
692 | | - 'version': version, |
693 | | - 'versionBase': ( version !== x ? new String( version ).substr( 0, 1 ) : x ), |
694 | | - 'versionNumber': ( parseFloat( version, 10 ) || 0.0 ) |
695 | | - }; |
696 | | - } |
697 | | - return client; |
698 | | - }; |
699 | | - /** |
700 | | - * Checks the current browser against a support map object to determine if the browser has been black-listed or |
701 | | - * not. If the browser was not configured specifically it is assumed to work. It is assumed that the body |
702 | | - * element is classified as either "ltr" or "rtl". If neither is set, "ltr" is assumed. |
703 | | - * |
704 | | - * A browser map is in the following format: |
705 | | - * { |
706 | | - * 'ltr': { |
707 | | - * // Multiple rules with configurable operators |
708 | | - * 'msie': [['>=', 7], ['!=', 9]], |
709 | | - * // Blocked entirely |
710 | | - * 'iphone': false |
711 | | - * }, |
712 | | - * 'rtl': { |
713 | | - * // Test against a string |
714 | | - * 'msie': [['!==', '8.1.2.3']], |
715 | | - * // RTL rules do not fall through to LTR rules, you must explicity set each of them |
716 | | - * 'iphone': false |
717 | | - * } |
718 | | - * } |
719 | | - * |
720 | | - * @param map Object of browser support map |
721 | | - * |
722 | | - * @return Boolean true if browser known or assumed to be supported, false if blacklisted |
723 | | - */ |
724 | | - this.testClient = function( map ) { |
725 | | - var client = this.client(); |
726 | | - // Check over each browser condition to determine if we are running in a compatible client |
727 | | - var browser = map[$( 'body' ).is( '.rtl' ) ? 'rtl' : 'ltr'][client.browser]; |
728 | | - if ( typeof browser !== 'object' ) { |
729 | | - // Unknown, so we assume it's working |
730 | | - return true; |
731 | | - } |
732 | | - for ( var condition in browser ) { |
733 | | - var op = browser[condition][0]; |
734 | | - var val = browser[condition][1]; |
735 | | - if ( val === false ) { |
736 | | - return false; |
737 | | - } else if ( typeof val == 'string' ) { |
738 | | - if ( !( eval( 'client.version' + op + '"' + val + '"' ) ) ) { |
739 | | - return false; |
740 | | - } |
741 | | - } else if ( typeof val == 'number' ) { |
742 | | - if ( !( eval( 'client.versionNumber' + op + val ) ) ) { |
743 | | - return false; |
744 | | - } |
745 | | - } |
746 | | - } |
747 | | - return true; |
748 | | - }; |
749 | | - } )(); |
| 496 | + |
| 497 | + /* Extension points */ |
| 498 | + |
| 499 | + this.utilities = {}; |
| 500 | + |
750 | 501 | // Attach to window |
751 | 502 | window.MediaWiki = window.mw = $.extend( 'mw' in window ? window.mw : {}, this ); |
752 | 503 | } )(); |
\ No newline at end of file |