summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/UniversalLanguageSelector/lib/jquery.webfonts/src/jquery.webfonts.js
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/extensions/UniversalLanguageSelector/lib/jquery.webfonts/src/jquery.webfonts.js')
-rw-r--r--www/wiki/extensions/UniversalLanguageSelector/lib/jquery.webfonts/src/jquery.webfonts.js517
1 files changed, 517 insertions, 0 deletions
diff --git a/www/wiki/extensions/UniversalLanguageSelector/lib/jquery.webfonts/src/jquery.webfonts.js b/www/wiki/extensions/UniversalLanguageSelector/lib/jquery.webfonts/src/jquery.webfonts.js
new file mode 100644
index 00000000..a28ca39d
--- /dev/null
+++ b/www/wiki/extensions/UniversalLanguageSelector/lib/jquery.webfonts/src/jquery.webfonts.js
@@ -0,0 +1,517 @@
+/**
+ * jQuery Webfonts.
+ *
+ * Copyright (C) 2012 Santhosh Thottingal
+ *
+ * UniversalLanguageSelector is dual licensed GPLv2 or later and MIT. You don't
+ * have to do anything special to choose one license or the other and you don't
+ * have to notify anyone which license you are using. You are free to use
+ * UniversalLanguageSelector in commercial projects as long as the copyright
+ * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
+ *
+ * @file
+ * @ingroup Extensions
+ * @licence GNU General Public Licence 2.0 or later
+ * @licence MIT License
+ */
+
+( function( $, window, document, undefined ) {
+ 'use strict';
+
+ var WebFonts = function( element, options ) {
+ // Load defaults
+ this.options = $.extend( {}, $.fn.webfonts.defaults, options );
+ this.$element = $( element );
+ this.repository = $.extend( WebFonts.repository, this.options.repository );
+ // List of loaded fonts
+ this.fonts = [];
+ this.originalFontFamily = this.$element.css( 'font-family' );
+ this.language = this.$element.attr( 'lang' ) || $( 'html' ).attr( 'lang' );
+
+ this.init();
+ };
+
+ WebFonts.repository = {
+ base: 'fonts', // Relative or absolute path to the font repository.
+ languages: {}, // languages to font mappings
+ fonts: {}, // Font name to font configuration mapping
+
+ // Utility methods to work on the repository.
+ defaultFont: function( language ) {
+ var defaultFont = null;
+
+ if ( this.languages[language] ) {
+ defaultFont = this.languages[language][0];
+ }
+
+ return defaultFont;
+ },
+
+ get: function( fontFamily ) {
+ return this.fonts[fontFamily];
+ }
+ };
+
+ WebFonts.prototype = {
+ constructor: WebFonts,
+
+ /**
+ * Get the default font family for given language.
+ * @param {String|undefined} language Language code.
+ * @param {array} classes
+ * @return {String} Font family name
+ */
+ getFont: function( language, classes ) {
+ language = ( language || this.language || '' ).toLowerCase();
+
+ if ( this.options.fontSelector && language ) {
+ return this.options.fontSelector( this.repository, language, classes );
+ } else {
+ return this.repository.defaultFont( language );
+ }
+ },
+
+ /**
+ * Initialize.
+ */
+ init: function() {
+ if ( this.language ) {
+ this.apply( this.getFont( this.language ) );
+ }
+
+ this.parse();
+ },
+
+ /**
+ * TODO: document
+ */
+ refresh: function() {
+ this.reset();
+ this.init();
+ },
+
+ /**
+ * Apply a font for given elements.
+ *
+ * @param {String} fontFamily Font family name
+ * @param {jQuery} $element One or more jQuery elements
+ */
+ apply: function( fontFamily, $element ) {
+ var fontStack = this.options.fontStack.slice( 0 );
+
+ $element = $element || this.$element;
+
+ // Loading an empty string is pointless.
+ // Putting an empty string into a font-family list doesn't work with
+ // jQuery.css().
+ if ( fontFamily ) {
+ this.load( fontFamily );
+ // Avoid duplicates
+ if ( $.inArray( fontFamily, fontStack ) < 0 ) {
+ fontStack.unshift( fontFamily );
+ }
+ }
+
+ if ( !fontFamily ) {
+ // We are resetting the font to original font.
+ fontStack = [];
+ // This will cause removing inline fontFamily style.
+ }
+
+ // Set the font of this element if it's not excluded.
+ // Add class webfonts-changed when webfonts are applied.
+ $element.not( this.options.exclude )
+ .css( 'font-family', fontStack.join() )
+ .addClass( 'webfonts-changed' );
+
+ // Set the font of this element's children if they are not excluded.
+ // font-family of <input>, <textarea> and <button> must be changed explicitly.
+ // Add class webfonts-changed when webfonts are applied.
+ $element.find( 'textarea, input, button' ).not( this.options.exclude )
+ .css( 'font-family', fontStack.join() )
+ .addClass( 'webfonts-changed' );
+ },
+
+ /**
+ * Load given font families if not loaded already. Creates the CSS rules
+ * and appends them to document.
+ *
+ * @param {Array|String} fontFamilies List of font families
+ */
+ load: function( fontFamilies ) {
+ var css, fontFamily, i,
+ fontFaceRule = '';
+
+ // Convert to array if string given (old signature)
+ if ( typeof fontFamilies === 'string' ) {
+ fontFamilies = [fontFamilies];
+ }
+
+ for ( i = 0; i < fontFamilies.length; i++ ) {
+ fontFamily = fontFamilies[i];
+ if ( $.inArray( fontFamily, this.fonts ) >= 0 ) {
+ continue;
+ }
+
+ css = this.getCSS( fontFamily, 'normal' );
+ if ( css !== false ) {
+ fontFaceRule += css;
+ this.fonts.push( fontFamily );
+ }
+ }
+
+ // In case the list contained only fonts that are already loaded
+ // or non-existing fonts.
+ if ( fontFaceRule !== '' ) {
+ injectCSS( fontFaceRule );
+ }
+
+ return true;
+ },
+
+ /**
+ * Parse the element for custom font-family styles and for nodes with
+ * different language than what the element itself has.
+ */
+ parse: function() {
+ var webfonts = this,
+ // Fonts can be added indirectly via classes, but also with
+ // style attributes. For lang attributes we will use our font
+ // if they don't have explicit font already.
+ $elements = webfonts.$element.find( '*[lang], [style], [class]' ),
+ // List of fonts to load in a batch
+ fontQueue = [],
+ // List of elements to apply a certain font family in a batch.
+ // Object keys are the font family, values are list of plain elements.
+ elementQueue = {};
+
+ // Add to the font queue(no dupes)
+ function addToFontQueue( value ) {
+ if ( $.inArray( value, fontQueue ) < 0 ) {
+ fontQueue.push( value );
+ }
+ }
+
+ // Add to the font queue
+ function addToElementQueue( element, fontFamily ) {
+ elementQueue[fontFamily] = elementQueue[fontFamily] || [];
+ elementQueue[fontFamily].push( element );
+ }
+
+ $elements.each( function( i, element ) {
+ var fontFamilyStyle, fontFamily,
+ $element = $( element );
+
+ if ( $element.is( webfonts.options.exclude ) ) {
+ return;
+ }
+
+ // Note: it depends on the browser whether this returns font names
+ // which don't exist. In Chrome it does, while in Opera it doesn't.
+ fontFamilyStyle = $element.css( 'fontFamily' );
+ // Note: It is unclear whether this can ever be falsy. Maybe also
+ // browser specific.
+ if ( fontFamilyStyle ) {
+ // if it is overridable, override. always.
+ if ( webfonts.isOverridable( fontFamilyStyle ) ) {
+ fontFamily = webfonts.getFont( element.lang || webfonts.language );
+ // We do not have fonts for all languages
+ if ( fontFamily ) {
+ addToFontQueue( fontFamily );
+ addToElementQueue( element, fontFamily );
+ }
+ return;
+ } else {
+ fontFamily = fontFamilyStyle.split( ',' )[0];
+ // Remove the ' and " characters if any.
+ fontFamily = $.trim( fontFamily.replace( /["']/g, '' ) );
+ addToFontQueue( fontFamily );
+ }
+ }
+
+ // Load and apply fonts for other language tagged elements (batched)
+ if ( element.lang && element.lang !== webfonts.language ) {
+ // language differs. We may want to apply a different font.
+ if ( webfonts.hasExplicitFontStyle ( $element ) &&
+ !webfonts.isOverridable( fontFamilyStyle ) ) {
+ // respect the explicit font family style. Do not override.
+ // This style may be from css, inheritance, or even from
+ // browser settings.
+ return;
+ } else {
+ fontFamily = webfonts.getFont( element.lang, element.className.split(/\s+/) );
+ }
+
+ if ( !fontFamily ) {
+ // No font preference for the language.
+ // Check if we need to reset for this language.
+ // If the font of the parent element, to which webfonts were applied,
+ // remained the same, there is no need to reset.
+ if ( webfonts.$element.css( 'fontFamily' ) !== webfonts.originalFontFamily ) {
+ // The parent font changed.
+ // Is there an inheritance?
+ // Is the font for this element the same as parent's font?
+ if ( fontFamilyStyle === webfonts.$element.css( 'fontFamily' ) ) {
+ // Break inheritance of the font from the parent element
+ // by applying the original font to this element
+ fontFamily = webfonts.originalFontFamily;
+ }
+ }
+ }
+
+ // We do not have fonts for all languages
+ if ( fontFamily ) {
+ addToFontQueue( fontFamily );
+ addToElementQueue( element, fontFamily );
+ }
+ }
+ } );
+
+ // Process in batch the accumulated fonts and elements
+ this.load( fontQueue );
+ $.each( elementQueue, function( fontFamily, elements ) {
+ webfonts.apply( fontFamily, $( elements ) );
+ } );
+ },
+
+ /**
+ * Find out whether an element has explicit non generic font family style
+ * For the practical purpose we check whether font is same as top element
+ * or having any of generic font family
+ * http://www.w3.org/TR/CSS2/fonts.html#generic-font-families
+ * @param {jQuery} $element
+ * @return {boolean}
+ */
+ hasExplicitFontStyle: function ( $element ) {
+ var elementFontFamily = $element.css( 'fontFamily' );
+
+ // whether the font is inherited from top element to which plugin applied
+ return this.$element.css( 'fontFamily' ) !== elementFontFamily
+ // whether the element has generic font family
+ && ( $.inArray( elementFontFamily,
+ [ 'monospace', 'serif', 'cursive', 'fantasy', 'sans-serif' ] ) < 0 );
+ },
+
+ /**
+ * Check whether the given font family is overridable or not. jquery.webfonts
+ * by default does not override any font-family styles other than generic
+ * font family styles (see hasExplicitFontStyle method).
+ * @param {string} fontFamily
+ * @return {boolean} Whether the given fontFamily is overridable or not.
+ */
+ isOverridable: function( fontFamily ) {
+ var overridableFontFamilies = [ 'monospace', 'serif', 'cursive', 'fantasy', 'sans-serif' ];
+ $.merge( overridableFontFamilies, this.options.overridableFontFamilies );
+ // Browsers like FF put space after comma in font stack. Chrome does not.
+ // Normalise it by removing the spaces and quotes
+ overridableFontFamilies = $.map( overridableFontFamilies, function( item ) {
+ return item.replace( /[\s'"]/g, '' );
+ } );
+ fontFamily = fontFamily.replace( /[\s'"]/g, '' );
+
+ return $.inArray( fontFamily, overridableFontFamilies ) >= 0;
+ },
+
+ /**
+ * List all fonts for the given language
+ *
+ * @param {String} [language] Language code. If undefined all fonts will be listed.
+ * @return {Array} List of font family names.
+ */
+ list: function( language ) {
+ var fontName,
+ fontNames = [];
+
+ if ( language ) {
+ fontNames = this.repository.languages[language] || [];
+ } else {
+ for ( fontName in this.repository.fonts ) {
+ if ( this.repository.fonts.hasOwnProperty( fontName ) ) {
+ fontNames.push( fontName );
+ }
+ }
+ }
+
+ return fontNames;
+ },
+
+ /**
+ * List all languages supported by the repository
+ *
+ * @return {Array} List of language codes
+ */
+ languages: function() {
+ var language,
+ languages = [];
+
+ for ( language in this.repository.languages ) {
+ if ( this.repository.languages.hasOwnProperty( language ) ) {
+ languages.push( language );
+ }
+ }
+
+ return languages;
+ },
+
+ /**
+ * Set the font repository
+ *
+ * @param {Object} repository The font repository.
+ */
+ setRepository: function( repository ) {
+ this.repository = $.extend( WebFonts.repository, repository );
+ },
+
+ /**
+ * Reset the font-family style.
+ */
+ reset: function() {
+ this.$element.find( '.webfonts-changed' )
+ .removeClass( '.webfonts-changed' )
+ .css( 'font-family', '' );
+ this.apply( this.originalFontFamily );
+ },
+
+ /**
+ * Unbind the plugin
+ */
+ unbind: function() {
+ this.$element.data( 'webfonts', null );
+ },
+
+ /**
+ * Construct the CSS required for the font-family.
+ *
+ * @param {String} fontFamily The font-family name
+ * @param {String} [variant] The font variant, eg: bold, italic etc. Default is normal.
+ * @return {String} CSS
+ */
+ getCSS: function( fontFamily, variant ) {
+ var webfonts, base,
+ fontFaceRule, userAgent, fontStyle, fontFormats, fullFontName,
+ fontconfig = this.repository.get( fontFamily );
+
+ variant = variant || 'normal';
+ fullFontName = fontFamily;
+
+ if ( variant !== 'normal' ) {
+ if ( fontconfig.variants !== undefined && fontconfig.variants[variant] ) {
+ fullFontName = fontconfig.variants[variant];
+ fontconfig = this.repository.get( fontconfig.variants[variant] );
+ }
+ }
+
+ if ( !fontconfig ) {
+ return false;
+ }
+
+ base = this.repository.base;
+ fontFaceRule = '@font-face { font-family: \'' + fontFamily + '\';\n';
+ userAgent = window.navigator.userAgent;
+ fontStyle = fontconfig.fontstyle || 'normal';
+ fontFormats = [];
+
+ if ( fontconfig.eot ) {
+ fontFaceRule += '\tsrc: url(\'' + base + fontconfig.eot + '\');\n';
+ }
+ fontFaceRule += '\tsrc: ';
+
+ // If the font is present locally, use it.
+ if ( userAgent.match( /Android 2\.3/ ) === null ) {
+ // Android 2.3.x does not respect local() syntax.
+ // http://code.google.com/p/android/issues/detail?id=10609
+ fontFaceRule += 'local(\'' + fullFontName + '\'),';
+ }
+
+ if ( fontconfig.woff2 ) {
+ fontFormats.push( '\t\turl(\'' + base + fontconfig.woff2
+ + '\') format(\'woff2\')' );
+ }
+
+ if ( fontconfig.woff ) {
+ fontFormats.push( '\t\turl(\'' + base + fontconfig.woff
+ + '\') format(\'woff\')' );
+ }
+
+ if ( fontconfig.svg ) {
+ fontFormats.push( '\t\turl(\'' + base + fontconfig.svg + '#'
+ + fontFamily + '\') format(\'svg\')' );
+ }
+
+ if ( fontconfig.ttf ) {
+ fontFormats.push( '\t\turl(\'' + base + fontconfig.ttf
+ + '\') format(\'truetype\')' );
+ }
+
+ fontFaceRule += fontFormats.join() + ';\n';
+
+ if ( fontconfig.fontweight ) {
+ fontFaceRule += '\tfont-weight:' + fontconfig.fontweight + ';';
+ }
+
+ if ( fontconfig.fontstyle !== undefined ) {
+ fontFaceRule += '\tfont-style:' + fontconfig.fontstyle + ';';
+ } else {
+ fontFaceRule += '\tfont-style: normal;';
+ }
+
+ fontFaceRule += '}\n';
+
+ webfonts = this;
+ if ( fontconfig.variants !== undefined ) {
+ $.each( fontconfig.variants, function ( variant ) {
+ fontFaceRule += webfonts.getCSS( fontFamily, variant );
+ } );
+ }
+
+ return fontFaceRule;
+ }
+ };
+
+ $.fn.webfonts = function( option ) {
+ return this.each( function() {
+ var $this = $( this ),
+ data = $this.data( 'webfonts' ),
+ options = typeof option === 'object' && option;
+
+ if ( !data ) {
+ $this.data( 'webfonts', ( data = new WebFonts( this, options ) ) );
+ }
+
+ if ( typeof option === 'string' ) {
+ data[option]();
+ }
+ } );
+ };
+
+ $.fn.webfonts.defaults = {
+ repository: WebFonts.repository, // Default font repository
+ fontStack: [ 'Helvetica', 'Arial', 'sans-serif' ], // Default font fallback
+ exclude: '', // jQuery selectors to exclude
+ overridableFontFamilies: []
+ };
+
+ $.fn.webfonts.Constructor = WebFonts;
+
+ // Private methods for the WebFonts prototype
+
+ /**
+ * Create a new style tag and add it to the DOM.
+ *
+ * @param {String} css
+ */
+ function injectCSS( css ) {
+ var s = document.createElement( 'style' );
+
+ // Insert into document before setting cssText
+ document.getElementsByTagName( 'head' )[0].appendChild( s );
+
+ if ( s.styleSheet ) {
+ s.styleSheet.cssText = css;
+ // IE
+ } else {
+ // Safari sometimes borks on null
+ s.appendChild( document.createTextNode( String( css ) ) );
+ }
+ }
+} )( jQuery, window, document );