123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 |
- define("dojox/mobile/common", [
- "dojo/_base/kernel", // to test dojo.hash
- "dojo/_base/array",
- "dojo/_base/config",
- "dojo/_base/connect",
- "dojo/_base/lang",
- "dojo/_base/window",
- "dojo/dom-class",
- "dojo/dom-construct",
- "dojo/dom-style",
- // "dojo/hash", // optionally prereq'ed
- "dojo/ready",
- "dijit/registry", // registry.toArray
- "./sniff",
- "./uacss"
- ], function(dojo, array, config, connect, lang, win, domClass, domConstruct, domStyle, ready, registry, has, uacss){
- var dm = lang.getObject("dojox.mobile", true);
- /*=====
- var dm = dojox.mobile;
- =====*/
- // module:
- // dojox/mobile/common
- // summary:
- // A common module for dojox.mobile.
- // description:
- // This module includes common utility functions that are used by
- // dojox.mobile widgets. Also, it provides functions that are commonly
- // necessary for mobile web applications, such as the hide address bar
- // function.
- dm.getScreenSize = function(){
- // summary:
- // Returns the dimensions of the browser window.
- return {
- h: win.global.innerHeight || win.doc.documentElement.clientHeight,
- w: win.global.innerWidth || win.doc.documentElement.clientWidth
- };
- };
- dm.updateOrient = function(){
- // summary:
- // Updates the orientation specific css classes, 'dj_portrait' and
- // 'dj_landscape'.
- var dim = dm.getScreenSize();
- domClass.replace(win.doc.documentElement,
- dim.h > dim.w ? "dj_portrait" : "dj_landscape",
- dim.h > dim.w ? "dj_landscape" : "dj_portrait");
- };
- dm.updateOrient();
- dm.tabletSize = 500;
- dm.detectScreenSize = function(/*Boolean?*/force){
- // summary:
- // Detects the screen size and determines if the screen is like
- // phone or like tablet. If the result is changed,
- // it sets either of the following css class to <html>
- // - 'dj_phone'
- // - 'dj_tablet'
- // and it publishes either of the following events.
- // - '/dojox/mobile/screenSize/phone'
- // - '/dojox/mobile/screenSize/tablet'
- var dim = dm.getScreenSize();
- var sz = Math.min(dim.w, dim.h);
- var from, to;
- if(sz >= dm.tabletSize && (force || (!this._sz || this._sz < dm.tabletSize))){
- from = "phone";
- to = "tablet";
- }else if(sz < dm.tabletSize && (force || (!this._sz || this._sz >= dm.tabletSize))){
- from = "tablet";
- to = "phone";
- }
- if(to){
- domClass.replace(win.doc.documentElement, "dj_"+to, "dj_"+from);
- connect.publish("/dojox/mobile/screenSize/"+to, [dim]);
- }
- this._sz = sz;
- };
- dm.detectScreenSize();
- dm.setupIcon = function(/*DomNode*/iconNode, /*String*/iconPos){
- // summary:
- // Sets up CSS sprite for a foreground image.
- if(iconNode && iconPos){
- var arr = array.map(iconPos.split(/[ ,]/),function(item){return item-0});
- var t = arr[0]; // top
- var r = arr[1] + arr[2]; // right
- var b = arr[0] + arr[3]; // bottom
- var l = arr[1]; // left
- domStyle.set(iconNode, {
- clip: "rect("+t+"px "+r+"px "+b+"px "+l+"px)",
- top: (iconNode.parentNode ? domStyle.get(iconNode, "top") : 0) - t + "px",
- left: -l + "px"
- });
- }
- };
- // dojox.mobile.hideAddressBarWait: Number
- // The time in milliseconds to wait before the fail-safe hiding address
- // bar runs. The value must be larger than 800.
- dm.hideAddressBarWait = typeof(config["mblHideAddressBarWait"]) === "number" ?
- config["mblHideAddressBarWait"] : 1500;
- dm.hide_1 = function(force){
- // summary:
- // Internal function to hide the address bar.
- scrollTo(0, 1);
- var h = dm.getScreenSize().h + "px";
- if(has("android")){
- if(force){
- win.body().style.minHeight = h;
- }
- dm.resizeAll();
- }else{
- if(force || dm._h === h && h !== win.body().style.minHeight){
- win.body().style.minHeight = h;
- dm.resizeAll();
- }
- }
- dm._h = h;
- };
- dm.hide_fs = function(){
- // summary:
- // Internal function to hide the address bar for fail-safe.
- // description:
- // Resets the height of the body, performs hiding the address
- // bar, and calls resizeAll().
- // This is for fail-safe, in case of failure to complete the
- // address bar hiding in time.
- var t = win.body().style.minHeight;
- win.body().style.minHeight = (dm.getScreenSize().h * 2) + "px"; // to ensure enough height for scrollTo to work
- scrollTo(0, 1);
- setTimeout(function(){
- dm.hide_1(1);
- dm._hiding = false;
- }, 1000);
- };
- dm.hideAddressBar = function(/*Event?*/evt){
- // summary:
- // Hides the address bar.
- // description:
- // Tries hiding of the address bar a couple of times to do it as
- // quick as possible while ensuring resize is done after the hiding
- // finishes.
- if(dm.disableHideAddressBar || dm._hiding){ return; }
- dm._hiding = true;
- dm._h = 0;
- win.body().style.minHeight = (dm.getScreenSize().h * 2) + "px"; // to ensure enough height for scrollTo to work
- setTimeout(dm.hide_1, 0);
- setTimeout(dm.hide_1, 200);
- setTimeout(dm.hide_1, 800);
- setTimeout(dm.hide_fs, dm.hideAddressBarWait);
- };
- dm.resizeAll = function(/*Event?*/evt, /*Widget?*/root){
- // summary:
- // Call the resize() method of all the top level resizable widgets.
- // description:
- // Find all widgets that do not have a parent or the parent does not
- // have the resize() method, and call resize() for them.
- // If a widget has a parent that has resize(), call of the widget's
- // resize() is its parent's responsibility.
- // evt:
- // Native event object
- // root:
- // If specified, search the specified widget recursively for top level
- // resizable widgets.
- // root.resize() is always called regardless of whether root is a
- // top level widget or not.
- // If omitted, search the entire page.
- if(dm.disableResizeAll){ return; }
- connect.publish("/dojox/mobile/resizeAll", [evt, root]);
- dm.updateOrient();
- dm.detectScreenSize();
- var isTopLevel = function(w){
- var parent = w.getParent && w.getParent();
- return !!((!parent || !parent.resize) && w.resize);
- };
- var resizeRecursively = function(w){
- array.forEach(w.getChildren(), function(child){
- if(isTopLevel(child)){ child.resize(); }
- resizeRecursively(child);
- });
- };
- if(root){
- if(root.resize){ root.resize(); }
- resizeRecursively(root);
- }else{
- array.forEach(array.filter(registry.toArray(), isTopLevel),
- function(w){ w.resize(); });
- }
- };
- dm.openWindow = function(url, target){
- // summary:
- // Opens a new browser window with the given url.
- win.global.open(url, target || "_blank");
- };
- dm.createDomButton = function(/*DomNode*/refNode, /*Object?*/style, /*DomNode?*/toNode){
- // summary:
- // Creates a DOM button.
- // description:
- // DOM button is a simple graphical object that consists of one or
- // more nested DIV elements with some CSS styling. It can be used
- // in place of an icon image on ListItem, IconItem, and so on.
- // The kind of DOM button to create is given as a class name of
- // refNode. The number of DIVs to create is searched from the style
- // sheets in the page. However, if the class name has a suffix that
- // starts with an underscore, like mblDomButtonGoldStar_5, then the
- // suffixed number is used instead. A class name for DOM button
- // must starts with 'mblDomButton'.
- // refNode:
- // A node that has a DOM button class name.
- // style:
- // A hash object to set styles to the node.
- // toNode:
- // A root node to create a DOM button. If omitted, refNode is used.
- if(!dm._domButtons){
- if(has("webkit")){
- var findDomButtons = function(sheet, dic){
- // summary:
- // Searches the style sheets for DOM buttons.
- // description:
- // Returns a key-value pair object whose keys are DOM
- // button class names and values are the number of DOM
- // elements they need.
- var i, j;
- if(!sheet){
- var dic = {};
- var ss = dojo.doc.styleSheets;
- for (i = 0; i < ss.length; i++){
- ss[i] && findDomButtons(ss[i], dic);
- }
- return dic;
- }
- var rules = sheet.cssRules || [];
- for (i = 0; i < rules.length; i++){
- var rule = rules[i];
- if(rule.href && rule.styleSheet){
- findDomButtons(rule.styleSheet, dic);
- }else if(rule.selectorText){
- var sels = rule.selectorText.split(/,/);
- for (j = 0; j < sels.length; j++){
- var sel = sels[j];
- var n = sel.split(/>/).length - 1;
- if(sel.match(/(mblDomButton\w+)/)){
- var cls = RegExp.$1;
- if(!dic[cls] || n > dic[cls]){
- dic[cls] = n;
- }
- }
- }
- }
- }
- }
- dm._domButtons = findDomButtons();
- }else{
- dm._domButtons = {};
- }
- }
- var s = refNode.className;
- var node = toNode || refNode;
- if(s.match(/(mblDomButton\w+)/) && s.indexOf("/") === -1){
- var btnClass = RegExp.$1;
- var nDiv = 4;
- if(s.match(/(mblDomButton\w+_(\d+))/)){
- nDiv = RegExp.$2 - 0;
- }else if(dm._domButtons[btnClass] !== undefined){
- nDiv = dm._domButtons[btnClass];
- }
- var props = null;
- if(has("bb") && config["mblBBBoxShadowWorkaround"] !== false){
- // Removes box-shadow because BlackBerry incorrectly renders it.
- props = {style:"-webkit-box-shadow:none"};
- }
- for(var i = 0, p = node; i < nDiv; i++){
- p = p.firstChild || domConstruct.create("DIV", props, p);
- }
- if(toNode){
- setTimeout(function(){
- domClass.remove(refNode, btnClass);
- }, 0);
- domClass.add(toNode, btnClass);
- }
- }else if(s.indexOf(".") !== -1){ // file name
- domConstruct.create("IMG", {src:s}, node);
- }else{
- return null;
- }
- domClass.add(node, "mblDomButton");
- if(config["mblAndroidWorkaround"] !== false && has("android") >= 2.2){
- // Android workaround for the issue that domButtons' -webkit-transform styles sometimes invalidated
- // by applying -webkit-transform:translated3d(x,y,z) style programmatically to non-ancestor elements,
- // which results in breaking domButtons.
- domStyle.set(node, "webkitTransform", "translate3d(0,0,0)");
- }
- !!style && domStyle.set(node, style);
- return node;
- };
-
- dm.createIcon = function(/*String*/icon, /*String*/iconPos, /*DomNode*/node, /*String?*/title, /*DomNode?*/parent){
- // summary:
- // Creates or updates an icon node
- // description:
- // If node exists, updates the existing node. Otherwise, creates a new one.
- // icon:
- // Path for an image, or DOM button class name.
- if(icon && icon.indexOf("mblDomButton") === 0){
- // DOM button
- if(node && node.className.match(/(mblDomButton\w+)/)){
- domClass.remove(node, RegExp.$1);
- }else{
- node = domConstruct.create("DIV");
- }
- node.title = title;
- domClass.add(node, icon);
- dm.createDomButton(node);
- }else if(icon && icon !== "none"){
- // Image
- if(!node || node.nodeName !== "IMG"){
- node = domConstruct.create("IMG", {
- alt: title
- });
- }
- node.src = (icon || "").replace("${theme}", dm.currentTheme);
- dm.setupIcon(node, iconPos);
- if(parent && iconPos){
- var arr = iconPos.split(/[ ,]/);
- domStyle.set(parent, {
- width: arr[2] + "px",
- height: arr[3] + "px"
- });
- }
- }
- if(parent){
- parent.appendChild(node);
- }
- return node;
- };
- // flag for iphone flicker workaround
- dm._iw = config["mblIosWorkaround"] !== false && has("iphone");
- if(dm._iw){
- dm._iwBgCover = domConstruct.create("div"); // Cover to hide flicker in the background
- }
-
- if(config.parseOnLoad){
- ready(90, function(){
- // avoid use of query
- /*
- var list = query('[lazy=true] [dojoType]', null);
- list.forEach(function(node, index, nodeList){
- node.setAttribute("__dojoType", node.getAttribute("dojoType"));
- node.removeAttribute("dojoType");
- });
- */
-
- var nodes = win.body().getElementsByTagName("*");
- var i, len, s;
- len = nodes.length;
- for(i = 0; i < len; i++){
- s = nodes[i].getAttribute("dojoType");
- if(s){
- if(nodes[i].parentNode.getAttribute("lazy") == "true"){
- nodes[i].setAttribute("__dojoType", s);
- nodes[i].removeAttribute("dojoType");
- }
- }
- }
- });
- }
-
- ready(function(){
- dm.detectScreenSize(true);
- if(config["mblApplyPageStyles"] !== false){
- domClass.add(win.doc.documentElement, "mobile");
- }
- if(has("chrome")){
- // dojox.mobile does not load uacss (only _compat does), but we need dj_chrome.
- domClass.add(win.doc.documentElement, "dj_chrome");
- }
- if(config["mblAndroidWorkaround"] !== false && has("android") >= 2.2){ // workaround for android screen flicker problem
- if(config["mblAndroidWorkaroundButtonStyle"] !== false){
- // workaround to avoid buttons disappear due to the side-effect of the webkitTransform workaroud below
- domConstruct.create("style", {innerHTML:"BUTTON,INPUT[type='button'],INPUT[type='submit'],INPUT[type='reset'],INPUT[type='file']::-webkit-file-upload-button{-webkit-appearance:none;}"}, win.doc.head, "first");
- }
- if(has("android") < 3){ // for Android 2.2.x and 2.3.x
- domStyle.set(win.doc.documentElement, "webkitTransform", "translate3d(0,0,0)");
- // workaround for auto-scroll issue when focusing input fields
- connect.connect(null, "onfocus", null, function(e){
- domStyle.set(win.doc.documentElement, "webkitTransform", "");
- });
- connect.connect(null, "onblur", null, function(e){
- domStyle.set(win.doc.documentElement, "webkitTransform", "translate3d(0,0,0)");
- });
- }else{ // for Android 3.x
- if(config["mblAndroid3Workaround"] !== false){
- domStyle.set(win.doc.documentElement, {
- webkitBackfaceVisibility: "hidden",
- webkitPerspective: 8000
- });
- }
- }
- }
-
- // You can disable hiding the address bar with the following djConfig.
- // var djConfig = { mblHideAddressBar: false };
- var f = dm.resizeAll;
- if(config["mblHideAddressBar"] !== false &&
- navigator.appVersion.indexOf("Mobile") != -1 ||
- config["mblForceHideAddressBar"] === true){
- dm.hideAddressBar();
- if(config["mblAlwaysHideAddressBar"] === true){
- f = dm.hideAddressBar;
- }
- }
- connect.connect(null, (win.global.onorientationchange !== undefined && !has("android"))
- ? "onorientationchange" : "onresize", null, f);
-
- // avoid use of query
- /*
- var list = query('[__dojoType]', null);
- list.forEach(function(node, index, nodeList){
- node.setAttribute("dojoType", node.getAttribute("__dojoType"));
- node.removeAttribute("__dojoType");
- });
- */
-
- var nodes = win.body().getElementsByTagName("*");
- var i, len = nodes.length, s;
- for(i = 0; i < len; i++){
- s = nodes[i].getAttribute("__dojoType");
- if(s){
- nodes[i].setAttribute("dojoType", s);
- nodes[i].removeAttribute("__dojoType");
- }
- }
-
- if(dojo.hash){
- // find widgets under root recursively
- var findWidgets = function(root){
- if(!root){ return []; }
- var arr = registry.findWidgets(root);
- var widgets = arr;
- for(var i = 0; i < widgets.length; i++){
- arr = arr.concat(findWidgets(widgets[i].containerNode));
- }
- return arr;
- };
- connect.subscribe("/dojo/hashchange", null, function(value){
- var view = dm.currentView;
- if(!view){ return; }
- var params = dm._params;
- if(!params){ // browser back/forward button was pressed
- var moveTo = value ? value : dm._defaultView.id;
- var widgets = findWidgets(view.domNode);
- var dir = 1, transition = "slide";
- for(i = 0; i < widgets.length; i++){
- var w = widgets[i];
- if("#"+moveTo == w.moveTo){
- // found a widget that has the given moveTo
- transition = w.transition;
- dir = (w instanceof dm.Heading) ? -1 : 1;
- break;
- }
- }
- params = [ moveTo, dir, transition ];
- }
- view.performTransition.apply(view, params);
- dm._params = null;
- });
- }
-
- win.body().style.visibility = "visible";
- });
- // To search _parentNode first. TODO:1.8 reconsider this redefinition.
- registry.getEnclosingWidget = function(node){
- while(node){
- var id = node.getAttribute && node.getAttribute("widgetId");
- if(id){
- return registry.byId(id);
- }
- node = node._parentNode || node.parentNode;
- }
- return null;
- };
- return dm;
- });
|