From 4910b0666edeeebb18ac9682cb898dba8f22962a Mon Sep 17 00:00:00 2001
From: Thomas Bruederli <thomas@roundcube.net>
Date: Thu, 15 Aug 2013 02:57:11 -0400
Subject: [PATCH] Distinguish mobile/tablet/touch devices

---
 program/js/common.js |  210 +++++++++++++++++-----------------------------------
 1 files changed, 69 insertions(+), 141 deletions(-)

diff --git a/program/js/common.js b/program/js/common.js
index fc2d10b..afaf916 100644
--- a/program/js/common.js
+++ b/program/js/common.js
@@ -12,8 +12,6 @@
  +-----------------------------------------------------------------------+
  | Author: Thomas Bruederli <roundcube@gmail.com>                        |
  +-----------------------------------------------------------------------+
- 
- $Id$
 */
 
 // Constants
@@ -55,15 +53,16 @@
   this.ie4 = (this.ie && !this.dom);
   this.ie5 = (this.dom && this.appver.indexOf('MSIE 5')>0);
   this.ie8 = (this.dom && this.appver.indexOf('MSIE 8')>0);
+  this.ie9 = (this.dom && this.appver.indexOf('MSIE 9')>0);
   this.ie7 = (this.dom && this.appver.indexOf('MSIE 7')>0);
   this.ie6 = (this.dom && !this.ie8 && !this.ie7 && this.appver.indexOf('MSIE 6')>0);
 
   this.ns = ((this.ver < 5 && this.name == 'Netscape') || (this.ver >= 5 && this.vendor.indexOf('Netscape') >= 0));
   this.chrome = (this.agent_lc.indexOf('chrome') > 0);
   this.safari = (!this.chrome && (this.agent_lc.indexOf('safari') > 0 || this.agent_lc.indexOf('applewebkit') > 0));
-  this.mz = (this.dom && !this.ie && !this.ns && !this.chrome && !this.safari && this.agent.indexOf('Mozilla') >= 0);
-  this.konq   = (this.agent_lc.indexOf('konqueror') > 0);
-  this.iphone = (this.safari && this.agent_lc.indexOf('iphone') > 0);
+  this.konq = (this.agent_lc.indexOf('konqueror') > 0);
+  this.mz = (this.dom && !this.ie && !this.ns && !this.chrome && !this.safari && !this.konq && this.agent.indexOf('Mozilla') >= 0);
+  this.iphone = (this.safari && (this.agent_lc.indexOf('iphone') > 0 || this.agent_lc.indexOf('ipod') > 0));
   this.ipad = (this.safari && this.agent_lc.indexOf('ipad') > 0);
   this.opera = window.opera ? true : false;
 
@@ -84,6 +83,9 @@
   if (this.safari && (/;\s+([a-z]{2})-[a-z]{2}\)/.test(this.agent_lc)))
     this.lang = RegExp.$1;
 
+  this.tablet = /ipad|android|xoom|sch-i800|playbook|tablet|kindle/i.test(this.agent_lc);
+  this.mobile = /iphone|ipod|blackberry|iemobile|opera mini|opera mobi|mobile/i.test(this.agent_lc);
+  this.touch = this.mobile || this.tablet;
   this.dhtml = ((this.ie4 && this.win) || this.ie5 || this.ie6 || this.ns4 || this.mz);
   this.vml = (this.win && this.ie && this.dom && !this.opera);
   this.pngalpha = (this.mz || (this.opera && this.vendver >= 6) || (this.ie && this.mac && this.vendver >= 5) ||
@@ -105,30 +107,30 @@
   {
     var classname = ' js';
 
-    if (this.ie) {
-      classname += ' ie';
-      if (this.ie5)
-        classname += ' ie5';
-      else if (this.ie6)
-        classname += ' ie6';
-      else if (this.ie7)
-        classname += ' ie7';
-      else if (this.ie8)
-        classname += ' ie8';
-    }
+    if (this.ie)
+      classname += ' ie ie'+parseInt(this.vendver);
     else if (this.opera)
       classname += ' opera';
     else if (this.konq)
       classname += ' konqueror';
     else if (this.safari)
-      classname += ' safari';
-
-    if (this.chrome)
       classname += ' chrome';
-    else if (this.iphone)
+    else if (this.chrome)
+      classname += ' chrome';
+    else if (this.mz)
+      classname += ' mozilla';
+
+    if (this.iphone)
       classname += ' iphone';
     else if (this.ipad)
       classname += ' ipad';
+    else if (this.safari || this.chrome)
+      classname += ' webkit';
+
+    if (this.mobile)
+      classname += ' mobile';
+    if (this.tablet)
+      classname += ' tablet';
 
     if (document.documentElement)
       document.documentElement.className += classname;
@@ -253,7 +255,7 @@
 },
 
 /**
- * Prevent event propagation and bubbeling
+ * Prevent event propagation and bubbling
  */
 cancel: function(evt)
 {
@@ -300,8 +302,7 @@
   if (!this._events[evt])
     this._events[evt] = [];
 
-  var e = {func:func, obj:obj ? obj : window};
-  this._events[evt][this._events[evt].length] = e;
+  this._events[evt].push({func:func, obj:obj ? obj : window});
 },
 
 /**
@@ -374,117 +375,6 @@
 };  // end rcube_event_engine.prototype
 
 
-
-/**
- * Roundcube generic layer (floating box) class
- *
- * @constructor
- */
-function rcube_layer(id, attributes)
-{
-  this.name = id;
-
-  // create a new layer in the current document
-  this.create = function(arg)
-  {
-    var l = (arg.x) ? arg.x : 0,
-      t = (arg.y) ? arg.y : 0,
-      w = arg.width,
-      h = arg.height,
-      z = arg.zindex,
-      vis = arg.vis,
-      parent = arg.parent,
-      obj = document.createElement('DIV');
-
-    obj.id = this.name;
-    obj.style.position = 'absolute';
-    obj.style.visibility = (vis) ? (vis==2) ? 'inherit' : 'visible' : 'hidden';
-    obj.style.left = l+'px';
-    obj.style.top = t+'px';
-    if (w)
-	  obj.style.width = w.toString().match(/\%$/) ? w : w+'px';
-    if (h)
-	  obj.style.height = h.toString().match(/\%$/) ? h : h+'px';
-    if (z)
-      obj.style.zIndex = z;
-
-    if (parent)
-      parent.appendChild(obj);
-    else
-      document.body.appendChild(obj);
-
-    this.elm = obj;
-  };
-
-  // create new layer
-  if (attributes != null) {
-    this.create(attributes);
-    this.name = this.elm.id;
-  }
-  else  // just refer to the object
-    this.elm = document.getElementById(id);
-
-  if (!this.elm)
-    return false;
-
-
-  // ********* layer object properties *********
-
-  this.css = this.elm.style;
-  this.event = this.elm;
-  this.width = this.elm.offsetWidth;
-  this.height = this.elm.offsetHeight;
-  this.x = parseInt(this.elm.offsetLeft);
-  this.y = parseInt(this.elm.offsetTop);
-  this.visible = (this.css.visibility=='visible' || this.css.visibility=='show' || this.css.visibility=='inherit') ? true : false;
-
-
-  // ********* layer object methods *********
-
-  // move the layer to a specific position
-  this.move = function(x, y)
-  {
-    this.x = x;
-    this.y = y;
-    this.css.left = Math.round(this.x)+'px';
-    this.css.top = Math.round(this.y)+'px';
-  };
-
-  // change the layers width and height
-  this.resize = function(w,h)
-  {
-    this.css.width  = w+'px';
-    this.css.height = h+'px';
-    this.width = w;
-    this.height = h;
-  };
-
-  // show or hide the layer
-  this.show = function(a)
-  {
-    if(a == 1) {
-      this.css.visibility = 'visible';
-      this.visible = true;
-    }
-    else if(a == 2) {
-      this.css.visibility = 'inherit';
-      this.visible = true;
-    }
-    else {
-      this.css.visibility = 'hidden';
-      this.visible = false;
-    }
-  };
-
-  // write new content into a Layer
-  this.write = function(cont)
-  {
-    this.elm.innerHTML = cont;
-  };
-
-};
-
-
 // check if input is a valid email address
 // By Cal Henderson <cal@iamcal.com>
 // http://code.iamcal.com/php/rfc822/
@@ -496,12 +386,15 @@
       atom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+',
       quoted_pair = '\\x5c[\\x00-\\x7f]',
       quoted_string = '\\x22('+qtext+'|'+quoted_pair+')*\\x22',
+      ipv4 = '\\[(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}\\]',
+      ipv6 = '\\[IPv6:[0-9a-f:.]+\\]',
+      ip_addr = '(' + ipv4 + ')|(' + ipv6 + ')',
       // Use simplified domain matching, because we need to allow Unicode characters here
       // So, e-mail address should be validated also on server side after idn_to_ascii() use
       //domain_literal = '\\x5b('+dtext+'|'+quoted_pair+')*\\x5d',
       //sub_domain = '('+atom+'|'+domain_literal+')',
       // allow punycode/unicode top-level domain
-      domain = '([^@\\x2e]+\\x2e)+([^\\x00-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,})',
+      domain = '(('+ip_addr+')|(([^@\\x2e]+\\x2e)+([^\\x00-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,})))',
       // ICANN e-mail test (http://idn.icann.org/E-mail_test)
       icann_domains = [
         '\\u0645\\u062b\\u0627\\u0644\\x2e\\u0625\\u062e\\u062a\\u0628\\u0627\\u0631',
@@ -529,7 +422,6 @@
   return false;
 };
 
-
 // recursively copy an object
 function rcube_clone_object(obj)
 {
@@ -537,7 +429,7 @@
 
   for (var key in obj) {
     if (obj[key] && typeof obj[key] === 'object')
-      out[key] = clone_object(obj[key]);
+      out[key] = rcube_clone_object(obj[key]);
     else
       out[key] = obj[key];
   }
@@ -637,6 +529,7 @@
   return unescape(dc.substring(begin + prefix.length, end));
 };
 
+// deprecated aliases, to be removed, use rcmail.set_cookie/rcmail.get_cookie
 roundcube_browser.prototype.set_cookie = setCookie;
 roundcube_browser.prototype.get_cookie = getCookie;
 
@@ -700,11 +593,9 @@
 }
 
 // Make getElementById() case-sensitive on IE
-if (bw.ie)
-{
+if (bw.ie) {
   document._getElementById = document.getElementById;
-  document.getElementById = function(id)
-  {
+  document.getElementById = function(id) {
     var i = 0, obj = document._getElementById(id);
 
     if (obj && obj.id != id)
@@ -715,6 +606,43 @@
   }
 }
 
+// jQuery plugin to emulate HTML5 placeholder attributes on input elements
+jQuery.fn.placeholder = function(text) {
+  return this.each(function() {
+    var active = false, elem = $(this);
+    this.title = text;
+
+    // Try HTML5 placeholder attribute first
+    if ('placeholder' in this) {
+      elem.attr('placeholder', text);
+    }
+    // Fallback to Javascript emulation of placeholder
+    else {
+      this._placeholder = text;
+      elem.blur(function(e) {
+        if ($.trim(elem.val()) == "")
+          elem.val(text);
+        elem.triggerHandler('change');
+      })
+      .focus(function(e) {
+        if ($.trim(elem.val()) == text)
+          elem.val("");
+        elem.triggerHandler('change');
+      })
+      .change(function(e) {
+        var active = elem.val() == text;
+        elem[(active ? 'addClass' : 'removeClass')]('placeholder').attr('spellcheck', active);
+      });
+
+      // Do not blur currently focused element (catch exception: #1489008)
+      try { active = this == document.activeElement; } catch(e) {}
+      if (!active)
+        elem.blur();
+    }
+  });
+};
+
+
 // This code was written by Tyler Akins and has been placed in the
 // public domain.  It would be nice if you left this header intact.
 // Base64 code from Tyler Akins -- http://rumkin.com

--
Gitblit v1.9.1