1 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
2 //>>description: Loader doing theme loading, viewport setting, globalize loading, etc.
6 define( [ 'jquery.mobile.tizen.core' ], function ( ) {
7 //>>excludeEnd("jqmBuildExclude");
13 * Youmin Ha <youmin.ha@samsung.com>
18 Web UI scaling concept in Tizen Web UI
20 Generally, web applications must be designed to be showed acceptable on various size and resolution of screens, and web winsets have to be scaled well. Tizen Web UI Framework supports various viewport settings, and Tizen Web UI widgets are designed to be scalable on various screen sizes. In order to make web applications scalable on many devices which have different screen size, it is necessary to understand how mobile web browsers deal with screen resolution, and how Tizen Web UI Framework supports scaling for web applications.
23 * Viewport on mobile web browser
25 Viewport is an area showing web content on the browser. Unlike desktop browsers, mobile browsers support logical viewport seting, which means that application can set viewport width/height and zoom level by itself.
26 The very important thing that to be remembered is that the viewport resolution in pixel is 'Logical', not physical. For example, if the viewport width is set to 480 on a mobile device having 720px screen width, the viewport width is considered to 480px logically. All elements put on right side from 480px horizontal position will not be shown on the viewport.
27 Most mobile browsers set viewport with given content attribute with <meta name="viewport" content="..."> tag in <head> section in the application source html, whereas desktop browsers ignore the tag.
28 Detailed usage of viewport meta tag is found in here: http://www.w3.org/TR/mwabp/#bp-viewport
31 * Viewport setting by application developers
33 When developers write <meta name="viewport" content="..."> in the <head> section of the web application HTML file, Tizen Web UI Framework does not add another viewport meta tag, nor modify developer-defined viewport.
36 * Automatic viewport setting by Tizen Web UI Framework
38 If developers do not give a viewport meta tag, Tizen Web UI Framework automatically add a viewport meta tag with default viewport setting.
41 * Portrait/landscape mode
44 * Tizen Web UI widgets scaling
48 ( function ($, Globalize, window, undefined) {
51 libFileName : "tizen-web-ui-fw(.min)?.js",
54 rootDir: '/usr/lib/tizen-web-ui-fw',
57 viewportWidth: "device-width",
67 debug : function ( msg ) {
68 if ( tizen.frameworkData.debug ) {
72 warn : function ( msg ) {
75 error : function ( msg ) {
78 alert : function ( msg ) {
85 loadScriptSync : function ( scriptPath, successCB, errorCB ) {
92 error: function ( jqXHR, textStatus, errorThrown ) {
94 errorCB( jqXHR, textStatus, errorThrown );
96 var ignoreStatusList = [ 404 ], // 404: not found
97 errmsg = ( 'Error while loading ' + scriptPath + '\n' + jqXHR.status + ':' + jqXHR.statusText );
98 if ( -1 == $.inArray( jqXHR.status, ignoreStatusList ) ) {
99 tizen.log.alert( errmsg );
101 tizen.log.warn( errmsg );
107 isMobileBrowser: function ( ) {
108 var mobileIdx = window.navigator.appVersion.indexOf("Mobile"),
109 isMobile = -1 < mobileIdx;
115 cacheBust: ( document.location.href.match( /debug=true/ ) ) ?
116 '?cacheBust=' + ( new Date( ) ).getTime( ) :
118 addElementToHead : function ( elem ) {
119 var head = document.getElementsByTagName( 'head' )[0];
121 $( head ).prepend( elem );
124 makeLink : function ( href ) {
125 var cssLink = document.createElement( 'link' );
126 cssLink.setAttribute( 'rel', 'stylesheet' );
127 cssLink.setAttribute( 'href', href );
128 cssLink.setAttribute( 'name', 'tizen-theme' );
131 load: function ( path ) {
132 var head = document.getElementsByTagName( 'head' )[0],
133 cssLinks = head.getElementsByTagName( 'link' ),
136 // Find css link element
137 for ( idx = 0; idx < cssLinks.length; idx++ ) {
138 if ( cssLinks[idx].getAttribute( 'rel' ) != "stylesheet" ) {
141 if ( cssLinks[idx].getAttribute( 'name' ) == "tizen-theme"
142 || cssLinks[idx].getAttribute( 'href' ) == path ) {
147 if ( l ) { // Found the link element!
148 if ( l.getAttribute( 'href' ) == path ) {
149 tizen.log.warn( "Theme is already loaded. Skip theme loading in the framework." );
151 l.setAttribute( 'href', path );
154 this.addElementToHead( this.makeLink( path ) );
159 getParams: function ( ) {
160 /* Get data-* params from <script> tag, and set tizen.frameworkData.* values
161 * Returns true if proper <script> tag is found, or false if not.
163 // Find current <script> tag element
164 var scriptElems = document.getElementsByTagName( 'script' ),
166 foundScriptTag = false,
173 function getTizenTheme( ) {
174 var t = navigator.theme ? navigator.theme.split( ':' )[0] : null;
176 t = t.replace('-hd', '');
177 if ( ! t.match( /^tizen-/ ) ) {
184 for ( idx in scriptElems ) {
185 elem = scriptElems[idx];
186 src = elem.src ? elem.getAttribute( 'src' ) : undefined;
187 if (src && src.match( this.libFileName )) {
188 // Set framework data, only when they are given.
189 tokens = src.split(/[\/\\]/);
191 this.frameworkData.rootDir = ( elem.getAttribute( 'data-framework-root' )
192 || tokens.slice( 0, tokens.length + version_idx ).join( '/' )
193 || this.frameworkData.rootDir ).replace( /^file:(\/\/)?/, '' );
194 this.frameworkData.version = elem.getAttribute( 'data-framework-version' )
195 || tokens[ tokens.length + version_idx ]
196 || this.frameworkData.version;
197 this.frameworkData.theme = elem.getAttribute( 'data-framework-theme' )
199 || this.frameworkData.theme;
200 this.frameworkData.viewportWidth = elem.getAttribute( 'data-framework-viewport-width' )
201 || this.frameworkData.viewportWidth;
202 this.frameworkData.viewportScale =
203 "true" === elem.getAttribute( 'data-framework-viewport-scale' ) ? true
204 : this.frameworkData.viewportScale;
205 this.frameworkData.minified = src.search(/\.min\.js$/) > -1 ? true : false;
206 this.frameworkData.debug = "true" === elem.getAttribute( 'data-framework-debug' ) ? true
207 : this.frameworkData.debug;
208 foundScriptTag = true;
212 return foundScriptTag;
215 loadTheme: function ( theme ) {
221 theme = tizen.frameworkData.theme;
224 tizen.frameworkData.rootDir,
225 tizen.frameworkData.version,
230 jsPath = [ themePath, 'theme.js' ].join( '/' );
232 if ( tizen.frameworkData.minified ) {
233 cssPath = [themePath, 'tizen-web-ui-fw-theme.min.css'].join( '/' );
235 cssPath = [themePath, 'tizen-web-ui-fw-theme.css'].join( '/' );
237 tizen.css.load( cssPath );
238 tizen.util.loadScriptSync( jsPath );
241 /** Load Globalize culture file, and set default culture.
242 * @param[in] language (optional) Language code. ex) en-US, en, ko-KR, ko
243 * If language is not given, read language from html 'lang' attribute,
244 * or from system setting.
245 * @param[in] cultureDic (optional) Dictionary having language code->
247 loadGlobalizeCulture: function ( language, cultureDic ) {
253 function getLang ( language ) {
255 || $( 'html' ).attr( 'lang' )
256 || window.navigator.language.split( '.' )[0] // Webkit, Safari + workaround for Tizen
257 || window.navigator.userLanguage // IE
260 countryCodeIdx = lang.lastIndexOf('-'),
261 ignoreCodes = ['Cyrl', 'Latn', 'Mong']; // Not country code!
262 if ( countryCodeIdx != -1 ) { // Found country code!
263 countryCode = lang.substr( countryCodeIdx + 1 );
264 if ( ignoreCodes.join( '-' ).indexOf( countryCode ) < 0 ) {
265 // countryCode is not found from ignoreCodes.
266 // Make countryCode to uppercase.
267 lang = [ lang.substr( 0, countryCodeIdx ), countryCode.toUpperCase( ) ].join( '-' );
270 // NOTE: 'en' to 'en-US', because globalize has no 'en' culture file.
271 lang = lang == 'en' ? 'en-US' : lang;
275 function getNeutralLang ( lang ) {
276 var neutralLangIdx = lang.lastIndexOf( '-' ),
278 if ( neutralLangIdx != -1 ) {
279 neutralLang = lang.substr( 0, neutralLangIdx );
284 function getCultureFilePath ( lang, cFDic ) {
285 var cFPath = null; // error value
287 if ( "string" != typeof lang ) {
290 if ( cFDic && cFDic[lang] ) {
291 cFPath = cFDic[lang];
293 // Default Globalize culture file path
295 self.frameworkData.rootDir,
296 self.frameworkData.version,
299 ['globalize.culture.', lang, '.js'].join( '' ),
305 function printLoadError( cFPath, jqXHR ) {
306 tizen.log.error( "Error " + jqXHR.status + ": " + jqXHR.statusText
307 + "::Culture file (" + cFPath + ") is failed to load.");
310 function loadCultureFile ( cFPath, errCB ) {
311 function _successCB ( ) {
312 tizen.log.debug( "Culture file (" + cFPath + ") is loaded successfully." );
314 function _errCB ( jqXHR, textStatus, err ) {
316 errCB( jqXHR, textStatus, err );
318 printLoadError( cFPath, jqXHR );
322 if ( ! cFPath ) { // Invalid cFPath -> Regard it as '404 Not Found' error.
325 statusText: "Not Found"
327 _errCB( mockJSXHR, null, null );
340 lang = getLang( language );
341 cFPath = getCultureFilePath( lang, cultureDic );
342 loadCultureFile( cFPath,
343 function ( jqXHR, textStatus, err ) {
344 if ( jqXHR.status == 404 ) {
345 // If culture file is not found, try once more with neutral lang.
346 var nLang = getNeutralLang( lang ),
347 ncFPath = getCultureFilePath( nLang, cultureDic );
348 loadCultureFile( ncFPath, null );
350 printLoadError( cFPath, jqXHR );
356 setGlobalize: function ( ) {
357 var lang = this.loadGlobalizeCulture( );
360 // NOTE: It is not needed to set with neutral lang.
361 // Globalize automatically deals with it.
362 Globalize.culture( lang );
365 * Load custom globalize culture file
366 * Find current system language, and load appropriate culture file from given colture file list.
368 * @param[in] cultureDic collection of 'language':'culture file path' key-val pair.
371 * "en" : "culture/en.js",
372 * "fr" : "culture/fr.js",
373 * "ko-KR" : "culture/ko-KR.js"
375 * loadCultomGlobalizeCulture( myCultures );
378 * -------------------------------
379 * Globalize.addCultureInfo( "fr", {
381 * "hello" : "bonjour",
382 * "translate" : "traduire"
385 * -------------------------------
387 loadCustomGlobalizeCulture: function ( cultureDic ) {
388 tizen.loadGlobalizeCulture( null, cultureDic );
391 /** Set viewport meta tag for mobile devices.
393 * @param[in] viewportWidth viewport width. "device-width" is OK.
395 setViewport: function ( viewportWidth ) {
400 // Do nothing if viewport setting code is already in the code.
401 $( "meta[name=viewport]" ).each( function ( ) {
405 if ( meta ) { // Found custom viewport!
406 content = $( meta ).prop( "content" );
407 viewportWidth = content.replace( /.*width=(device-width|\d+)\s*,?.*$/gi, "$1" );
408 tizen.log.warn( "Viewport is set to '" + viewportWidth + "' in a meta tag. Framework skips viewport setting." );
411 meta = document.createElement( "meta" );
413 meta.name = "viewport";
414 content = [ "width=", viewportWidth, ", user-scalable=no" ].join( "" );
415 if ( ! isNaN( viewportWidth ) ) {
416 // Fix scale to 1.0, if viewport width is set to fixed value.
417 // NOTE: Works wrong in Tizen browser!
418 //content = [ content, ", initial-scale=1.0, maximum-scale=1.0" ].join( "" );
420 meta.content = content;
421 tizen.log.debug( content );
422 head = document.getElementsByTagName( 'head' ).item( 0 );
423 head.insertBefore( meta, head.firstChild );
426 return viewportWidth;
429 /** Read body's font-size, scale it, and reset it.
430 * param[in] desired font-size / base font-size.
432 scaleBaseFontSize: function ( themeDefaultFontSize, ratio ) {
433 tizen.log.debug( "themedefaultfont size: " + themeDefaultFontSize + ", ratio: " + ratio );
434 var scaledFontSize = Math.round( themeDefaultFontSize * ratio );
436 $( 'html.ui-mobile' ).css( { 'font-size': scaledFontSize + "px" } );
437 tizen.log.debug( 'html:font size is set to ' + scaledFontSize );
438 $( document ).ready( function ( ) {
439 $( '.ui-mobile' ).children( 'body' ).css( { 'font-size': scaledFontSize + "px" } );
443 setScaling: function ( ) {
444 var viewportWidth = this.frameworkData.viewportWidth,
445 themeDefaultFontSize = this.frameworkData.defaultFontSize, // comes from theme.js
448 // Keep original font size
449 $( 'body' ).attr( 'data-tizen-theme-default-font-size', themeDefaultFontSize );
451 // Legacy support: tizen.frameworkData.viewportScale
452 if ( this.frameworkData.viewportScale == true ) {
453 viewportWidth = "screen-width";
456 if ( "screen-width" == viewportWidth ) {
457 viewportWidth = document.documentElement.clientWidth;
460 viewportWidth = this.setViewport( viewportWidth ); // If custom viewport setting exists, get viewport width
461 if ( ! isNaN( viewportWidth ) ) { // fixed width!
462 ratio = parseFloat( viewportWidth / this.frameworkData.defaultViewportWidth );
464 this.scaleBaseFontSize( themeDefaultFontSize, ratio );
468 function export2TizenNS ( $, tizen ) {
473 $.tizen.frameworkData = tizen.frameworkData;
474 $.tizen.loadCustomGlobalizeCulture = tizen.loadCustomGlobalizeCulture;
475 $.tizen.loadTheme = tizen.loadTheme;
477 $.tizen.__tizen__ = tizen; // for unit-test
480 export2TizenNS( $, tizen );
484 tizen.setScaling( ); // Run after loadTheme(), for the default font size.
485 tizen.setGlobalize( );
487 // Turn off JQM's auto initialization option.
488 // NOTE: This job must be done before domready.
489 $.mobile.autoInitializePage = false;
491 $(document).ready( function ( ) {
492 $.mobile.initializePage( );
495 } ( jQuery, window.Globalize, window ) );
497 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
499 //>>excludeEnd("jqmBuildExclude");