Merge with @h5bp
authorDavid <bcldvd@gmail.com>
Sat, 5 May 2012 22:05:46 +0000 (00:05 +0200)
committerDavid <bcldvd@gmail.com>
Sat, 5 May 2012 22:05:46 +0000 (00:05 +0200)
Merge with HTML5 Boilerplate Mobile :)

Add of Bookmark bubble with cookie fallback instead of parameter, which
used to screw up with jQuery Mobile !
Add of Startup Images for iDevices.

images/startup-retina.png [new file with mode: 0755]
images/startup-tablet-landscape.png [new file with mode: 0755]
images/startup-tablet-portrait.png [new file with mode: 0755]
images/startup.png [new file with mode: 0755]
index.html
js/bookmark_bubble.js [new file with mode: 0644]
js/example.js [new file with mode: 0644]
js/jqm.autoComplete.min-1.3.js [new file with mode: 0644]
js/jquery.cookie.js [new file with mode: 0644]

diff --git a/images/startup-retina.png b/images/startup-retina.png
new file mode 100755 (executable)
index 0000000..752d8c7
Binary files /dev/null and b/images/startup-retina.png differ
diff --git a/images/startup-tablet-landscape.png b/images/startup-tablet-landscape.png
new file mode 100755 (executable)
index 0000000..b275185
Binary files /dev/null and b/images/startup-tablet-landscape.png differ
diff --git a/images/startup-tablet-portrait.png b/images/startup-tablet-portrait.png
new file mode 100755 (executable)
index 0000000..9ce4540
Binary files /dev/null and b/images/startup-tablet-portrait.png differ
diff --git a/images/startup.png b/images/startup.png
new file mode 100755 (executable)
index 0000000..d9bba03
Binary files /dev/null and b/images/startup.png differ
index f8ccdbe..a8ec171 100644 (file)
@@ -9,22 +9,44 @@
 
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
 
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
+       <meta name="apple-mobile-web-app-capable" content="yes">
+       <meta name="apple-mobile-web-app-status-bar-style" content="black">
+       <meta name="HandheldFriendly" content="True">
+       <meta name="MobileOptimized" content="320">
+
+<!-- Home screen icon  Mathias Bynens mathiasbynens.be/notes/touch-icons -->
+       <!-- For iPhone 4 with high-resolution Retina display: -->
+       <link rel="apple-touch-icon-precomposed" sizes="114x114" href="apple-touch-icon.png">
+       <!-- For first-generation iPad: -->
+       <link rel="apple-touch-icon-precomposed" sizes="72x72" href="apple-touch-icon.png">
+       <!-- For non-Retina iPhone, iPod Touch, and Android 2.1+ devices: -->
+       <link rel="apple-touch-icon-precomposed" href="apple-touch-icon-precomposed.png">
+       <!-- For nokia devices and desktop browsers : -->
+       <link rel="shortcut icon" href="favicon.ico" />
+       
+       <!-- Mobile IE allows us to activate ClearType technology for smoothing fonts for easy reading -->
+       <meta http-equiv="cleartype" content="on">
 
        <!-- jQuery Mobile CSS bits -->
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" />
 
 
        <!-- jQuery Mobile CSS bits -->
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" />
 
-       <!-- if you have a custom theme, add it here -->
-       <link rel="stylesheet"  href="/themes/jQuery-Mobile-Boilerplate.css" />
-
        <!-- Custom css -->
        <!-- Custom css -->
-       <link rel="stylesheet" href="/css/custom.css" />
+       <link rel="stylesheet" href="css/custom.css" />
 
        <!-- Javascript includes -->
        <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
 
        <!-- Javascript includes -->
        <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
-       <script src="/js/mobileinit.js"></script>
-       <script src="/js/ios-orientationchange-fix.min.js"></script>
+       <script src="js/mobileinit.js"></script>
+       <script src="js/ios-orientationchange-fix.min.js"></script>
        <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script>
        <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script>
-       <script src="/js/application.js"></script>
+       <script src="js/application.js"></script>
+       <!-- Add a Bookmark Bubble for iDevices, and adds a cookie if already shown -->
+       <script type="text/javascript" src="js/bookmark_bubble.js"></script>
+       <script type="text/javascript" src="js/example.js"></script>
+       <script src="js/jquery.cookie.js"></script>
+       <!-- Startup Images for iDevices -->
+       <script>(function(){var a;if(navigator.platform==="iPad"){a=window.orientation!==90||window.orientation===-90?"images/startup-tablet-landscape.png":"images/startup-tablet-portrait.png"}else{a=window.devicePixelRatio===2?"images/startup-retina.png":"images/startup.png"}document.write('<link rel="apple-touch-startup-image" href="'+a+'"/>')})()</script>
+       <!-- The script prevents links from opening in mobile safari. https://gist.github.com/1042026 -->
+       <script>(function(a,b,c){if(c in b&&b[c]){var d,e=a.location,f=/^(a|html)$/i;a.addEventListener("click",function(a){d=a.target;while(!f.test(d.nodeName))d=d.parentNode;"href"in d&&(d.href.indexOf("http")||~d.href.indexOf(e.host))&&(a.preventDefault(),e.href=d.href)},!1)}})(document,window.navigator,"standalone")</script>
 </head> 
 <body> 
        <div data-role="page">
 </head> 
 <body> 
        <div data-role="page">
diff --git a/js/bookmark_bubble.js b/js/bookmark_bubble.js
new file mode 100644 (file)
index 0000000..90c839e
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+  Copyright 2010 Google Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+*/
+
+/**
+ * @fileoverview Bookmark bubble library. This is meant to be included in the
+ * main JavaScript binary of a mobile web application.
+ *
+ * Supported browsers: iPhone / iPod / iPad Safari 3.0+
+ */
+
+var google = google || {};
+google.bookmarkbubble = google.bookmarkbubble || {};
+
+
+/**
+ * Binds a context object to the function.
+ * @param {Function} fn The function to bind to.
+ * @param {Object} context The "this" object to use when the function is run.
+ * @return {Function} A partially-applied form of fn.
+ */
+google.bind = function(fn, context) {
+  return function() {
+    return fn.apply(context, arguments);
+  };
+};
+
+
+/**
+ * Function used to define an abstract method in a base class. If a subclass
+ * fails to override the abstract method, then an error will be thrown whenever
+ * that method is invoked.
+ */
+google.abstractMethod = function() {
+  throw Error('Unimplemented abstract method.');
+};
+
+
+
+/**
+ * The bubble constructor. Instantiating an object does not cause anything to
+ * be rendered yet, so if necessary you can set instance properties before
+ * showing the bubble.
+ * @constructor
+ */
+google.bookmarkbubble.Bubble = function() {
+  /**
+   * Handler for the scroll event. Keep a reference to it here, so it can be
+   * unregistered when the bubble is destroyed.
+   * @type {function()}
+   * @private
+   */
+  this.boundScrollHandler_ = google.bind(this.setPosition, this);
+
+  /**
+   * The bubble element.
+   * @type {Element}
+   * @private
+   */
+  this.element_ = null;
+
+  /**
+   * Whether the bubble has been destroyed.
+   * @type {boolean}
+   * @private
+   */
+  this.hasBeenDestroyed_ = false;
+};
+
+
+/**
+ * Shows the bubble if allowed. It is not allowed if:
+ * - The browser is not Mobile Safari, or
+ * - The user has dismissed it too often already, or
+ * - The hash parameter is present in the location hash, or
+ * - The application is in fullscreen mode, which means it was already loaded
+ *   from a homescreen bookmark.
+ * @return {boolean} True if the bubble is being shown, false if it is not
+ *     allowed to show for one of the aforementioned reasons.
+ */
+google.bookmarkbubble.Bubble.prototype.showIfAllowed = function() {
+  if (!this.isAllowedToShow_()) {
+    return false;
+  }
+
+  this.show_();
+  return true;
+};
+
+
+/**
+ * Shows the bubble if allowed after loading the icon image. This method creates
+ * an image element to load the image into the browser's cache before showing
+ * the bubble to ensure that the image isn't blank. Use this instead of
+ * showIfAllowed if the image url is http and cacheable.
+ * This hack is necessary because Mobile Safari does not properly render
+ * image elements with border-radius CSS.
+ * @param {function()} opt_callback Closure to be called if and when the bubble
+ *        actually shows.
+ * @return {boolean} True if the bubble is allowed to show.
+ */
+google.bookmarkbubble.Bubble.prototype.showIfAllowedWhenLoaded =
+    function(opt_callback) {
+  if (!this.isAllowedToShow_()) {
+    return false;
+  }
+
+  var self = this;
+  // Attach to self to avoid garbage collection.
+  var img = self.loadImg_ = document.createElement('img');
+  img.src = self.getIconUrl_();
+  img.onload = function() {
+    if (img.complete) {
+      delete self.loadImg_;
+      img.onload = null;  // Break the circular reference.
+
+      self.show_();
+      opt_callback && opt_callback();
+    }
+  };
+  img.onload();
+
+  return true;
+};
+
+
+/**
+ * Sets the parameter in the location hash. As it is
+ * unpredictable what hash scheme is to be used, this method must be
+ * implemented by the host application.
+ *
+ * This gets called automatically when the bubble is shown. The idea is that if
+ * the user then creates a bookmark, we can later recognize on application
+ * startup whether it was from a bookmark suggested with this bubble.
+ */
+google.bookmarkbubble.Bubble.prototype.setHashParameter = google.abstractMethod;
+
+
+/**
+ * Whether the parameter is present in the location hash. As it is
+ * unpredictable what hash scheme is to be used, this method must be
+ * implemented by the host application.
+ *
+ * Call this method during application startup if you want to log whether the
+ * application was loaded from a bookmark with the bookmark bubble promotion
+ * parameter in it.
+ *
+ * @return {boolean} Whether the bookmark bubble parameter is present in the
+ *     location hash.
+ */
+google.bookmarkbubble.Bubble.prototype.hasHashParameter = google.abstractMethod;
+
+
+/**
+ * The number of times the user must dismiss the bubble before we stop showing
+ * it. This is a public property and can be changed by the host application if
+ * necessary.
+ * @type {number}
+ */
+google.bookmarkbubble.Bubble.prototype.NUMBER_OF_TIMES_TO_DISMISS = 2;
+
+
+/**
+ * Time in milliseconds. If the user does not dismiss the bubble, it will auto
+ * destruct after this amount of time.
+ * @type {number}
+ */
+google.bookmarkbubble.Bubble.prototype.TIME_UNTIL_AUTO_DESTRUCT = 15000;
+
+
+/**
+ * The prefix for keys in local storage. This is a public property and can be
+ * changed by the host application if necessary.
+ * @type {string}
+ */
+google.bookmarkbubble.Bubble.prototype.LOCAL_STORAGE_PREFIX = 'BOOKMARK_';
+
+
+/**
+ * The key name for the dismissed state.
+ * @type {string}
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.DISMISSED_ = 'DISMISSED_COUNT';
+
+
+/**
+ * The arrow image in base64 data url format.
+ * @type {string}
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.IMAGE_ARROW_DATA_URL_ = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAATCAMAAABSrFY3AAABKVBMVEUAAAD///8AAAAAAAAAAAAAAAAAAADf398AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD09PQAAAAAAAAAAAC9vb0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD19fUAAAAAAAAAAAAAAADq6uoAAAAAAAAAAAC8vLzU1NTT09MAAADg4OAAAADs7OwAAAAAAAAAAAD///+cueenwerA0vC1y+3a5fb5+/3t8vr4+v3w9PuwyOy3zO3h6vfh6vjq8Pqkv+mat+fE1fHB0/Cduuifu+iuxuuivemrxOvC1PDz9vzJ2fKpwuqmwOrb5vapw+q/0vDf6ffK2vLN3PPprJISAAAAQHRSTlMAAAEGExES7FM+JhUoQSxIRwMbNfkJUgXXBE4kDQIMHSA0Tw4xIToeTSc4Chz4OyIjPfI3QD/X5OZR6zzwLSUPrm1y3gAAAQZJREFUeF5lzsVyw0AURNE3IMsgmZmZgszQZoeZOf//EYlG5Yrhbs+im4Dj7slM5wBJ4OJ+undAUr68gK/Hyb6Bcp5yBR/w8jreNeAr5Eg2XE7g6e2/0z6cGw1JQhpmHP3u5aiPPnTTkIK48Hj9Op7bD3btAXTfgUdwYjwSDCVXMbizO0O4uDY/x4kYC5SWFnfC6N1a9RCO7i2XEmQJj2mHK1Hgp9Vq3QBRl9shuBLGhcNtHexcdQCnDUoUGetxDD+H2DQNG2xh6uAWgG2/17o1EmLqYH0Xej0UjHAaFxZIV6rJ/WK1kg7QZH8HU02zmdJinKZJaDV3TVMjM5Q9yiqYpUwiMwa/1apDXTNESjsAAAAASUVORK5CYII=';
+
+
+/**
+ * The close image in base64 data url format.
+ * @type {string}
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.IMAGE_CLOSE_DATA_URL_ = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEXM3fm+1Pfb5/rF2fjw9f23z/aavPOhwfTp8PyTt/L3+v7T4vqMs/K7zP////+qRWzhAAAAXElEQVQIW2O4CwUM996BwVskxtOqd++2rwMyPI+ve31GD8h4Madqz2mwms5jZ/aBGS/mHIDoen3m+DowY8/hOVUgxusz+zqPg7SvPA1UxQfSvu/du0YUK2AMmDMA5H1qhVX33T8AAAAASUVORK5CYII=';
+
+
+/**
+ * The link used to locate the application's home screen icon to display inside
+ * the bubble. The default link used here is for an iPhone home screen icon
+ * without gloss. If your application uses a glossy icon, change this to
+ * 'apple-touch-icon'.
+ * @type {string}
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.REL_ICON_ =
+    'apple-touch-icon-precomposed';
+
+
+/**
+ * Regular expression for detecting an iPhone or iPod or iPad.
+ * @type {!RegExp}
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.MOBILE_SAFARI_USERAGENT_REGEX_ =
+    /iPhone|iPod|iPad/;
+
+
+/**
+ * Regular expression for detecting an iPad.
+ * @type {!RegExp}
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.IPAD_USERAGENT_REGEX_ = /iPad/;
+
+
+/**
+ * Determines whether the bubble should be shown or not.
+ * @return {boolean} Whether the bubble should be shown or not.
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.isAllowedToShow_ = function() {
+  return this.isMobileSafari_() &&
+      !this.hasBeenDismissedTooManyTimes_() &&
+      !this.isFullscreen_() &&
+      !this.hasHashParameter();
+};
+
+
+/**
+ * Builds and shows the bubble.
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.show_ = function() {
+  this.element_ = this.build_();
+
+  document.body.appendChild(this.element_);
+  this.element_.style.WebkitTransform =
+      'translateY(' + this.getHiddenYPosition_() + 'px)';
+
+  this.setHashParameter();
+
+  window.setTimeout(this.boundScrollHandler_, 1);
+  window.addEventListener('scroll', this.boundScrollHandler_, false);
+
+  // If the user does not dismiss the bubble, slide out and destroy it after
+  // some time.
+  window.setTimeout(google.bind(this.autoDestruct_, this),
+      this.TIME_UNTIL_AUTO_DESTRUCT);
+};
+
+
+/**
+ * Destroys the bubble by removing its DOM nodes from the document.
+ */
+google.bookmarkbubble.Bubble.prototype.destroy = function() {
+  if (this.hasBeenDestroyed_) {
+    return;
+  }
+  window.removeEventListener('scroll', this.boundScrollHandler_, false);
+  if (this.element_ && this.element_.parentNode == document.body) {
+    document.body.removeChild(this.element_);
+    this.element_ = null;
+  }
+  this.hasBeenDestroyed_ = true;
+};
+
+
+/**
+ * Remember that the user has dismissed the bubble once more.
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.rememberDismissal_ = function() {
+  if (window.localStorage) {
+    try {
+      var key = this.LOCAL_STORAGE_PREFIX + this.DISMISSED_;
+      var value = Number(window.localStorage[key]) || 0;
+      window.localStorage[key] = String(value + 1);
+    } catch (ex) {
+      // Looks like we've hit the storage size limit. Currently we have no
+      // fallback for this scenario, but we could use cookie storage instead.
+      // This would increase the code bloat though.
+    }
+  }
+};
+
+
+/**
+ * Whether the user has dismissed the bubble often enough that we will not
+ * show it again.
+ * @return {boolean} Whether the user has dismissed the bubble often enough
+ *     that we will not show it again.
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.hasBeenDismissedTooManyTimes_ =
+    function() {
+  if (!window.localStorage) {
+    // If we can not use localStorage to remember how many times the user has
+    // dismissed the bubble, assume he has dismissed it. Otherwise we might end
+    // up showing it every time the host application loads, into eternity.
+    return true;
+  }
+  try {
+    var key = this.LOCAL_STORAGE_PREFIX + this.DISMISSED_;
+
+    // If the key has never been set, localStorage yields undefined, which
+    // Number() turns into NaN. In that case we'll fall back to zero for
+    // clarity's sake.
+    var value = Number(window.localStorage[key]) || 0;
+
+    return value >= this.NUMBER_OF_TIMES_TO_DISMISS;
+  } catch (ex) {
+    // If we got here, something is wrong with the localStorage. Make the same
+    // assumption as when it does not exist at all. Exceptions should only
+    // occur when setting a value (due to storage limitations) but let's be
+    // extra careful.
+    return true;
+  }
+};
+
+
+/**
+ * Whether the application is running in fullscreen mode.
+ * @return {boolean} Whether the application is running in fullscreen mode.
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.isFullscreen_ = function() {
+  return !!window.navigator.standalone;
+};
+
+
+/**
+ * Whether the application is running inside Mobile Safari.
+ * @return {boolean} True if the current user agent looks like Mobile Safari.
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.isMobileSafari_ = function() {
+  return this.MOBILE_SAFARI_USERAGENT_REGEX_.test(window.navigator.userAgent);
+};
+
+
+/**
+ * Whether the application is running on an iPad.
+ * @return {boolean} True if the current user agent looks like an iPad.
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.isIpad_ = function() {
+  return this.IPAD_USERAGENT_REGEX_.test(window.navigator.userAgent);
+};
+
+
+
+/**
+ * Positions the bubble at the bottom of the viewport using an animated
+ * transition.
+ */
+google.bookmarkbubble.Bubble.prototype.setPosition = function() {
+  this.element_.style.WebkitTransition = '-webkit-transform 0.7s ease-out';
+  this.element_.style.WebkitTransform =
+      'translateY(' + this.getVisibleYPosition_() + 'px)';
+};
+
+
+/**
+ * Destroys the bubble by removing its DOM nodes from the document, and
+ * remembers that it was dismissed.
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.closeClickHandler_ = function() {
+  this.destroy();
+  this.rememberDismissal_();
+};
+
+
+/**
+ * Gets called after a while if the user ignores the bubble.
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.autoDestruct_ = function() {
+  if (this.hasBeenDestroyed_) {
+    return;
+  }
+  this.element_.style.WebkitTransition = '-webkit-transform 0.7s ease-in';
+  this.element_.style.WebkitTransform =
+      'translateY(' + this.getHiddenYPosition_() + 'px)';
+  window.setTimeout(google.bind(this.destroy, this), 700);
+};
+
+
+/**
+ * Gets the y offset used to show the bubble (i.e., position it on-screen).
+ * @return {number} The y offset.
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.getVisibleYPosition_ = function() {
+  return this.isIpad_() ? window.pageYOffset + 17 :
+      window.pageYOffset - this.element_.offsetHeight + window.innerHeight - 17;
+};
+
+
+/**
+ * Gets the y offset used to hide the bubble (i.e., position it off-screen).
+ * @return {number} The y offset.
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.getHiddenYPosition_ = function() {
+  return this.isIpad_() ? window.pageYOffset - this.element_.offsetHeight :
+      window.pageYOffset + window.innerHeight;
+};
+
+
+/**
+ * The url of the app's bookmark icon.
+ * @type {string|undefined}
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.iconUrl_;
+
+
+/**
+ * Scrapes the document for a link element that specifies an Apple favicon and
+ * returns the icon url. Returns an empty data url if nothing can be found.
+ * @return {string} A url string.
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.getIconUrl_ = function() {
+  if (!this.iconUrl_) {
+    var link = this.getLink(this.REL_ICON_);
+    if (!link || !(this.iconUrl_ = link.href)) {
+      this.iconUrl_ = 'data:image/png;base64,';
+    }
+  }
+  return this.iconUrl_;
+};
+
+
+/**
+ * Gets the requested link tag if it exists.
+ * @param {string} rel The rel attribute of the link tag to get.
+ * @return {Element} The requested link tag or null.
+ */
+google.bookmarkbubble.Bubble.prototype.getLink = function(rel) {
+  rel = rel.toLowerCase();
+  var links = document.getElementsByTagName('link');
+  for (var i = 0; i < links.length; ++i) {
+    var currLink = /** @type {Element} */ (links[i]);
+    if (currLink.getAttribute('rel').toLowerCase() == rel) {
+      return currLink;
+    }
+  }
+  return null;
+};
+
+
+/**
+ * Creates the bubble and appends it to the document.
+ * @return {Element} The bubble element.
+ * @private
+ */
+google.bookmarkbubble.Bubble.prototype.build_ = function() {
+  var bubble = document.createElement('div');
+  var isIpad = this.isIpad_();
+
+  bubble.style.position = 'absolute';
+  bubble.style.zIndex = 1000;
+  bubble.style.width = '100%';
+  bubble.style.left = '0';
+  bubble.style.top = '0';
+
+  var bubbleInner = document.createElement('div');
+  bubbleInner.style.position = 'relative';
+  bubbleInner.style.width = '214px';
+  bubbleInner.style.margin = isIpad ? '0 0 0 82px' : '0 auto';
+  bubbleInner.style.border = '2px solid #fff';
+  bubbleInner.style.padding = '20px 20px 20px 10px';
+  bubbleInner.style.WebkitBorderRadius = '8px';
+  bubbleInner.style.WebkitBoxShadow = '0 0 8px rgba(0, 0, 0, 0.7)';
+  bubbleInner.style.WebkitBackgroundSize = '100% 8px';
+  bubbleInner.style.backgroundColor = '#b0c8ec';
+  bubbleInner.style.background = '#cddcf3 -webkit-gradient(linear, ' +
+      'left bottom, left top, ' + isIpad ?
+          'from(#cddcf3), to(#b3caed)) no-repeat top' :
+          'from(#b3caed), to(#cddcf3)) no-repeat bottom';
+  bubbleInner.style.font = '13px/17px sans-serif';
+  bubble.appendChild(bubbleInner);
+
+  // The "Add to Home Screen" text is intended to be the exact same size text
+  // that is displayed in the menu of Mobile Safari on iPhone.
+  bubbleInner.innerHTML = 'Install this web app on your phone: tap ' +
+      '<b style="font-size:15px">+</b> and then <b>\'Add to Home Screen\'</b>';
+
+  var icon = document.createElement('div');
+  icon.style['float'] = 'left';
+  icon.style.width = '55px';
+  icon.style.height = '55px';
+  icon.style.margin = '-2px 7px 3px 5px';
+  icon.style.background =
+      '#fff url(' + this.getIconUrl_() + ') no-repeat -1px -1px';
+  icon.style.WebkitBackgroundSize = '57px';
+  icon.style.WebkitBorderRadius = '10px';
+  icon.style.WebkitBoxShadow = '0 2px 5px rgba(0, 0, 0, 0.4)';
+  bubbleInner.insertBefore(icon, bubbleInner.firstChild);
+
+  var arrow = document.createElement('div');
+  arrow.style.backgroundImage = 'url(' + this.IMAGE_ARROW_DATA_URL_ + ')';
+  arrow.style.width = '25px';
+  arrow.style.height = '19px';
+  arrow.style.position = 'absolute';
+  arrow.style.left = '111px';
+  if (isIpad) {
+    arrow.style.WebkitTransform = 'rotate(180deg)';
+    arrow.style.top = '-19px';
+  } else {
+    arrow.style.bottom = '-19px';
+  }
+  bubbleInner.appendChild(arrow);
+
+  var close = document.createElement('a');
+  close.onclick = google.bind(this.closeClickHandler_, this);
+  close.style.position = 'absolute';
+  close.style.display = 'block';
+  close.style.top = '-3px';
+  close.style.right = '-3px';
+  close.style.width = '16px';
+  close.style.height = '16px';
+  close.style.border = '10px solid transparent';
+  close.style.background =
+      'url(' + this.IMAGE_CLOSE_DATA_URL_ + ') no-repeat';
+  bubbleInner.appendChild(close);
+
+  return bubble;
+};
diff --git a/js/example.js b/js/example.js
new file mode 100644 (file)
index 0000000..cf0a89d
--- /dev/null
@@ -0,0 +1,56 @@
+/*\r
+  Copyright 2010 Google Inc.\r
+\r
+  Licensed under the Apache License, Version 2.0 (the "License");\r
+  you may not use this file except in compliance with the License.\r
+  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+  Unless required by applicable law or agreed to in writing, software\r
+  distributed under the License is distributed on an "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  See the License for the specific language governing permissions and\r
+  limitations under the License.\r
+*/\r
+\r
+/** @fileoverview Example of how to use the bookmark bubble. */\r
+\r
+window.addEventListener('load', function() {\r
+  window.setTimeout(function() {\r
+    var bubble = new google.bookmarkbubble.Bubble();\r
+\r
+\r
+    bubble.hasHashParameter = function() {\r
+      return $.cookie('bubble');\r
+    };\r
+\r
+    bubble.setHashParameter = function() {\r
+      if (!this.hasHashParameter()) {\r
+        $.cookie('bubble', true, { expires: 365 });\r
+      }\r
+    };\r
+\r
+    bubble.getViewportHeight = function() {\r
+      window.console.log('Example of how to override getViewportHeight.');\r
+      return window.innerHeight;\r
+    };\r
+\r
+    bubble.getViewportScrollY = function() {\r
+      window.console.log('Example of how to override getViewportScrollY.');\r
+      return window.pageYOffset;\r
+    };\r
+\r
+    bubble.registerScrollHandler = function(handler) {\r
+      window.console.log('Example of how to override registerScrollHandler.');\r
+      window.addEventListener('scroll', handler, false);\r
+    };\r
+\r
+    bubble.deregisterScrollHandler = function(handler) {\r
+      window.console.log('Example of how to override deregisterScrollHandler.');\r
+      window.removeEventListener('scroll', handler, false);\r
+    };\r
+\r
+    bubble.showIfAllowed();\r
+  }, 1000);\r
+}, false);\r
diff --git a/js/jqm.autoComplete.min-1.3.js b/js/jqm.autoComplete.min-1.3.js
new file mode 100644 (file)
index 0000000..e9e2516
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+       Name: autoComplete
+       Author: Raymond Camden & Andy Matthews
+       Contributors: Jim Pease (@jmpease)
+       Website: http://raymondcamden.com/
+                        http://andyMatthews.net
+       Packed With: http://jsutility.pjoneil.net/
+       Version: 1.3
+ */
+(function($){"use strict";var defaults={target:$(),source:null,callback:null,link:null,minLength:0,transition:'fade'},buildItems=function($this,data,settings){var str=[];$.each(data,function(index,value){if($.isPlainObject(value)){str.push('<li><a href="'+settings.link+encodeURIComponent(value.value)+'" data-transition="'+settings.transition+'">'+value.label+'</a></li>')}else{str.push('<li><a href="'+settings.link+encodeURIComponent(value)+'" data-transition="'+settings.transition+'">'+value+'</a></li>')}});$(settings.target).html(str.join('')).listview("refresh");if(settings.callback!=null&&$.isFunction(settings.callback)){attachCallback(settings)}if(str.length>0){$this.trigger("targetUpdated.autocomplete")}else{$this.trigger("targetCleared.autocomplete")}},attachCallback=function(settings){$('li a',$(settings.target)).bind('click.autocomplete',function(e){e.stopPropagation();e.preventDefault();settings.callback(e)})},clearTarget=function($this,$target){$target.html('').listview('refresh');$this.trigger("targetCleared.autocomplete")},handleInput=function(e){var $this=$(this),text,data,settings=$this.jqmData("autocomplete");if(settings){text=$this.val();if(text.length<settings.minLength){clearTarget($this,$(settings.target))}else{if($.isArray(settings.source)){data=settings.source.sort().filter(function(element){var element_text,re=new RegExp('^'+text,'i');if($.isPlainObject(element)){element_text=element.label}else{element_text=element}return re.test(element_text)});buildItems($this,data,settings)}else{$.get(settings.source,{term:text},function(data){buildItems($this,data,settings)},"json")}}}},methods={init:function(options){this.jqmData("autocomplete",$.extend({},defaults,options));return this.unbind("input.autocomplete").bind("input.autocomplete",handleInput)},update:function(options){var settings=this.jqmData("autocomplete");if(settings){this.jqmData("autocomplete",$.extend(settings,options))}return this},clear:function(){var settings=this.jqmData("autocomplete");if(settings){clearTarget(this,$(settings.target))}return this},destroy:function(){var settings=this.jqmData("autocomplete");if(settings){clearTarget(this,$(settings.target));this.jqmRemoveData("autocomplete");this.unbind(".autocomplete")}return this}};$.fn.autocomplete=function(method){if(methods[method]){return methods[method].apply(this,Array.prototype.slice.call(arguments,1))}else if(typeof method==='object'||!method){return methods.init.apply(this,arguments)}}})(jQuery);
\ No newline at end of file
diff --git a/js/jquery.cookie.js b/js/jquery.cookie.js
new file mode 100644 (file)
index 0000000..6d5974a
--- /dev/null
@@ -0,0 +1,47 @@
+/*!
+ * jQuery Cookie Plugin
+ * https://github.com/carhartl/jquery-cookie
+ *
+ * Copyright 2011, Klaus Hartl
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.opensource.org/licenses/GPL-2.0
+ */
+(function($) {
+    $.cookie = function(key, value, options) {
+
+        // key and at least value given, set cookie...
+        if (arguments.length > 1 && (!/Object/.test(Object.prototype.toString.call(value)) || value === null || value === undefined)) {
+            options = $.extend({}, options);
+
+            if (value === null || value === undefined) {
+                options.expires = -1;
+            }
+
+            if (typeof options.expires === 'number') {
+                var days = options.expires, t = options.expires = new Date();
+                t.setDate(t.getDate() + days);
+            }
+
+            value = String(value);
+
+            return (document.cookie = [
+                encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value),
+                options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
+                options.path    ? '; path=' + options.path : '',
+                options.domain  ? '; domain=' + options.domain : '',
+                options.secure  ? '; secure' : ''
+            ].join(''));
+        }
+
+        // key and possibly options given, get cookie...
+        options = value || {};
+        var decode = options.raw ? function(s) { return s; } : decodeURIComponent;
+
+        var pairs = document.cookie.split('; ');
+        for (var i = 0, pair; pair = pairs[i] && pairs[i].split('='); i++) {
+            if (decode(pair[0]) === key) return decode(pair[1] || ''); // IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, thus pair[1] may be undefined
+        }
+        return null;
+    };
+})(jQuery);