Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'popup-widget' of https://github.com/jquery/jquery-mobile

…into popup-widget
  • Loading branch information...
commit ab8733b97cfc0b89469ba7e1899a0fb5f7558314 2 parents 668b5c5 + 2dc9cad
@toddparker toddparker authored
Showing with 1,783 additions and 1 deletion.
  1. +55 −0 css/structure/jquery.mobile.popup.css
  2. +1 −0  css/structure/jquery.mobile.structure.css
  3. +4 −1 docs/_assets/css/jqm-docs.css
  4. +1 −0  docs/pages/index.html
  5. +1 −0  docs/pages/page-anatomy.html
  6. +1 −0  docs/pages/page-cache.html
  7. +1 −0  docs/pages/page-dialogs.html
  8. +1 −0  docs/pages/page-dynamic.html
  9. +1 −0  docs/pages/page-links.html
  10. +1 −0  docs/pages/page-navmodel.html
  11. +1 −0  docs/pages/page-scripting.html
  12. +1 −0  docs/pages/page-titles.html
  13. +1 −0  docs/pages/page-transitions.html
  14. +1 −0  docs/pages/pages-themes.html
  15. +1 −0  docs/pages/phonegap.html
  16. +108 −0 docs/pages/popup/events.html
  17. +247 −0 docs/pages/popup/index.html
  18. +99 −0 docs/pages/popup/methods.html
  19. +126 −0 docs/pages/popup/options.html
  20. +1 −0  docs/pages/touchoverflow.html
  21. +1 −0  js/index.php
  22. +1 −0  js/jquery.mobile.js
  23. +622 −0 js/jquery.mobile.popup.js
  24. +53 −0 tests/unit/popup/index.html
  25. +9 −0 tests/unit/popup/other.html
  26. +396 −0 tests/unit/popup/popup_core.js
  27. +48 −0 tests/unit/popup/popup_interaction.js
View
55 css/structure/jquery.mobile.popup.css
@@ -0,0 +1,55 @@
+.ui-popup-container {
+ z-index: 1100;
+ display: inline-block;
+ position: absolute;
+ padding: 0px;
+}
+
+.ui-popup-screen {
+ left: 0px;
+ top: 0px;
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ opacity: 0;
+ border: 0px;
+ z-index: 1099;
+}
+
+@-webkit-keyframes popup-fadein {
+ from { opacity: 0; }
+ to { opacity: 0.5; }
+}
+
+@-moz-keyframes popup-fadein {
+ from { opacity: 0; }
+ to { opacity: 0.5; }
+}
+
+@-webkit-keyframes popup-fadeout {
+ from { opacity: 0.5; }
+ to { opacity: 0; }
+}
+
+@-moz-keyframes popup-fadeout {
+ from { opacity: 0.5; }
+ to { opacity: 0; }
+}
+
+.ui-popup-screen.fade.in {
+ opacity: 0.5;
+ -webkit-animation-name: popup-fadein;
+ -moz-animation-name: popup-fadein;
+}
+
+.ui-popup-screen.fade.out {
+ opacity: 0;
+ -webkit-animation-name: popup-fadeout;
+ -moz-animation-name: popup-fadeout;
+}
+
+.ui-popup-btn-close {
+ position:absolute;
+ top:-15px;
+ right:-15px;
+}
View
1  css/structure/jquery.mobile.structure.css
@@ -16,6 +16,7 @@
@import url( "jquery.mobile.collapsible.css" );
@import url( "jquery.mobile.controlgroup.css" );
@import url( "jquery.mobile.dialog.css" );
+@import url( "jquery.mobile.popup.css" );
@import url( "jquery.mobile.forms.checkboxradio.css" );
@import url( "jquery.mobile.forms.fieldcontain.css" );
@import url( "jquery.mobile.forms.select.css" );
View
5 docs/_assets/css/jqm-docs.css
@@ -31,7 +31,6 @@ body { background: #dddddd; }
-moz-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
-
-webkit-box-shadow: 0 0 6px rgba(0,0,0,.40);
-moz-box-shadow: 0 0 6px rgba(0,0,0,.40);
-o-box-shadow: 0 0 6px rgba(0,0,0,.40);
@@ -271,6 +270,10 @@ dd h4 { margin:15px 0 0 0; }
padding: 0;
background: url(../images/px-ccc.gif) 50% 0 repeat-y;
}
+ .ui-popup-container .ui-content {
+ padding: 15px;
+ background-image: none;
+ }
.type-interior .ui-content {
background-position: 45%;
overflow: hidden;
View
1  docs/pages/index.html
@@ -36,6 +36,7 @@
<li><a href="page-transitions.html">Page transitions</a></li>
<li><a href="loader.html">Page loading widget</a></li>
<li><a href="page-dialogs.html">Dialogs</a></li>
+ <li><a href="popup/index.html">Popups</a></li>
<li><a href="page-cache.html">Prefetching &amp; caching pages</a></li>
<li><a href="page-navmodel.html">Ajax, hashes &amp; history</a></li>
<li><a href="page-dynamic.html">Dynamically injecting pages</a></li>
View
1  docs/pages/page-anatomy.html
@@ -202,6 +202,7 @@
<li><a href="page-transitions.html">Page transitions</a></li>
<li><a href="loader.html">Page loading widget</a></li>
<li><a href="page-dialogs.html">Dialogs</a></li>
+ <li><a href="popup/index.html">Popups</a></li>
<li><a href="page-cache.html">Prefetching &amp; caching pages</a></li>
<li><a href="page-navmodel.html">Ajax, hashes &amp; history</a></li>
<li><a href="page-dynamic.html">Dynamically injecting pages</a></li>
View
1  docs/pages/page-cache.html
@@ -102,6 +102,7 @@
<li><a href="page-transitions.html">Page transitions</a></li>
<li><a href="loader.html">Page loading widget</a></li>
<li><a href="page-dialogs.html">Dialogs</a></li>
+ <li><a href="popup/index.html">Popups</a></li>
<li data-theme="a"><a href="page-cache.html">Prefetching &amp; caching pages</a></li>
<li><a href="page-navmodel.html">Ajax, hashes &amp; history</a></li>
<li><a href="page-dynamic.html">Dynamically injecting pages</a></li>
View
1  docs/pages/page-dialogs.html
@@ -107,6 +107,7 @@
<li><a href="page-transitions.html">Page transitions</a></li>
<li><a href="loader.html">Page loading widget</a></li>
<li data-theme="a"><a href="page-dialogs.html">Dialogs</a></li>
+ <li><a href="popup/index.html">Popups</a></li>
<li><a href="page-cache.html">Prefetching &amp; caching pages</a></li>
<li><a href="page-navmodel.html">Ajax, hashes &amp; history</a></li>
<li><a href="page-dynamic.html">Dynamically injecting pages</a></li>
View
1  docs/pages/page-dynamic.html
@@ -278,6 +278,7 @@
<li><a href="page-transitions.html">Page transitions</a></li>
<li><a href="loader.html">Page loading widget</a></li>
<li><a href="page-dialogs.html">Dialogs</a></li>
+ <li><a href="popup/index.html">Popups</a></li>
<li><a href="page-cache.html">Prefetching &amp; caching pages</a></li>
<li><a href="page-navmodel.html">Ajax, hashes &amp; history</a></li>
<li data-theme="a"><a href="page-dynamic.html">Dynamically injecting pages</a></li>
View
1  docs/pages/page-links.html
@@ -125,6 +125,7 @@
<li><a href="page-transitions.html">Page transitions</a></li>
<li><a href="loader.html">Page loading widget</a></li>
<li><a href="page-dialogs.html">Dialogs</a></li>
+ <li><a href="popup/index.html">Popups</a></li>
<li><a href="page-cache.html">Prefetching &amp; caching pages</a></li>
<li><a href="page-navmodel.html">Ajax, hashes &amp; history</a></li>
<li><a href="page-dynamic.html">Dynamically injecting pages</a></li>
View
1  docs/pages/page-navmodel.html
@@ -160,6 +160,7 @@ <h4 style="margin:.5em 0">Important: rel="external" and $.mobile.ajaxEnabled=fal
<li><a href="page-transitions.html">Page transitions</a></li>
<li><a href="loader.html">Page loading widget</a></li>
<li><a href="page-dialogs.html">Dialogs</a></li>
+ <li><a href="popup/index.html">Popups</a></li>
<li><a href="page-cache.html">Prefetching &amp; caching pages</a></li>
<li data-theme="a"><a href="page-navmodel.html">Ajax, hashes &amp; history</a></li>
<li><a href="page-dynamic.html">Dynamically injecting pages</a></li>
View
1  docs/pages/page-scripting.html
@@ -138,6 +138,7 @@ <h4 style="margin:.5em 0">Important note: <code>pageCreate()</code> vs <code>pag
<li><a href="page-transitions.html">Page transitions</a></li>
<li><a href="loader.html">Page loading widget</a></li>
<li><a href="page-dialogs.html">Dialogs</a></li>
+ <li><a href="popup/index.html">Popups</a></li>
<li><a href="page-cache.html">Prefetching &amp; caching pages</a></li>
<li><a href="page-navmodel.html">Ajax, hashes &amp; history</a></li>
<li><a href="page-dynamic.html">Dynamically injecting pages</a></li>
View
1  docs/pages/page-titles.html
@@ -60,6 +60,7 @@
<li><a href="page-transitions.html">Page transitions</a></li>
<li><a href="loader.html">Page loading widget</a></li>
<li><a href="page-dialogs.html">Dialogs</a></li>
+ <li><a href="popup/index.html">Popups</a></li>
<li><a href="page-cache.html">Prefetching &amp; caching pages</a></li>
<li><a href="page-navmodel.html">Ajax, hashes &amp; history</a></li>
<li><a href="page-dynamic.html">Dynamically injecting pages</a></li>
View
1  docs/pages/page-transitions.html
@@ -151,6 +151,7 @@
<li data-theme="a"><a href="page-transitions.html">Page transitions</a></li>
<li><a href="loader.html">Page loading widget</a></li>
<li><a href="page-dialogs.html">Dialogs</a></li>
+ <li><a href="popup/index.html">Popups</a></li>
<li><a href="page-cache.html">Prefetching &amp; caching pages</a></li>
<li><a href="page-navmodel.html">Ajax, hashes &amp; history</a></li>
<li><a href="page-dynamic.html">Dynamically injecting pages</a></li>
View
1  docs/pages/pages-themes.html
@@ -128,6 +128,7 @@
<li><a href="page-transitions.html">Page transitions</a></li>
<li><a href="loader.html">Page loading widget</a></li>
<li><a href="page-dialogs.html">Dialogs</a></li>
+ <li><a href="popup/index.html">Popups</a></li>
<li><a href="page-cache.html">Prefetching &amp; caching pages</a></li>
<li><a href="page-navmodel.html">Ajax, hashes &amp; history</a></li>
<li><a href="page-dynamic.html">Dynamically injecting pages</a></li>
View
1  docs/pages/phonegap.html
@@ -93,6 +93,7 @@
<li><a href="page-transitions.html">Page transitions</a></li>
<li><a href="loader.html">Page loading widget</a></li>
<li><a href="page-dialogs.html">Dialogs</a></li>
+ <li><a href="popup/index.html">Popups</a></li>
<li><a href="page-cache.html">Prefetching &amp; caching pages</a></li>
<li><a href="page-navmodel.html">Ajax, hashes &amp; history</a></li>
<li><a href="page-dynamic.html">Dynamically injecting pages</a></li>
View
108 docs/pages/popup/events.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>jQuery Mobile Docs - Popup</title>
+ <link rel="stylesheet" href="../../../css/themes/default/jquery.mobile.css" />
+ <link rel="stylesheet" href="../../_assets/css/jqm-docs.css"/>
+
+ <script src="../../../js/jquery.js"></script>
+ <script src="../../../docs/_assets/js/jqm-docs.js"></script>
+ <script src="../../../js/"></script>
+
+</head>
+<body>
+
+ <div data-role="page" class="type-interior">
+
+ <div data-role="header" data-theme="f">
+ <h1>Popup</h1>
+ <a href="../../../" data-icon="home" data-iconpos="notext" data-direction="reverse">Home</a>
+ <a href="../../nav.html" data-icon="search" data-iconpos="notext" data-rel="dialog" data-transition="fade">Search</a>
+ </div><!-- /header -->
+
+ <div data-role="content" class="ui-body">
+ <div class="content-primary">
+
+ <form action="#" method="get">
+
+ <h2>Popup</h2>
+
+ <ul data-role="controlgroup" data-type="horizontal" class="localnav">
+ <li><a href="index.html" data-role="button" data-transition="fade">Basics</a></li>
+ <li><a href="options.html" data-role="button" data-transition="fade">Options</a></li>
+ <li><a href="methods.html" data-role="button" data-transition="fade">Methods</a></li>
+ <li><a href="events.html" data-role="button" data-transition="fade" class="ui-btn-active">Events</a></li>
+ </ul>
+
+ <p>The popup plugin has the following custom events:</p>
+
+ <dl>
+
+ <dt><code>opened</code> triggered when a popup is opened</dt>
+ <dd>
+
+ <pre><code>
+$( ".selector" ).popup({
+ opened: function(event, ui) { ... }
+});
+ </code></pre>
+ <p>This event is triggered when the popup has completely appeared on the screen, meaning that all associated animations have completed.</p>
+ </dd>
+
+ <dt><code>closed</code> triggered when a popup is closed (by clicking outside of it)</dt>
+ <dd>
+
+ <pre><code>
+$( ".selector" ).popup({
+ closed: function(event, ui) { ... }
+});
+ </code></pre>
+ <p>This event is triggered when the popup has completely disappeared from the screen, meaning that all associated animations have completed.</p>
+ </dd>
+
+ </dl>
+
+ </form>
+ </div><!--/content-primary -->
+
+ <div class="content-secondary">
+
+ <div data-role="collapsible" data-collapsed="true" data-theme="b" data-content-theme="d">
+
+ <h3>More in this section</h3>
+
+ <ul data-role="listview" data-theme="c" data-dividertheme="d">
+
+ <li data-role="list-divider">Pages &amp; Dialogs</li>
+ <li><a href="../page-anatomy.html">Anatomy of a page</a></li>
+ <li><a href="../page-template.html" data-ajax="false">Single page template</a></li>
+ <li><a href="../multipage-template.html" data-ajax="false">Multi-page template</a></li>
+ <li><a href="../page-titles.html">Page titles</a></li>
+ <li><a href="../page-links.html">Linking pages</a></li>
+ <li><a href="../page-transitions.html" data-ajax="false">Page transitions</a></li>
+ <li><a href="../page-dialogs.html">Dialogs</a></li>
+ <li data-theme="a"><a href="index.html">Popups</a></li>
+ <li><a href="../page-cache.html">Prefetching &amp; caching pages</a></li>
+ <li><a href="../page-navmodel.html">Ajax, hashes &amp; history</a></li>
+ <li><a href="../page-dynamic.html">Dynamically Injecting Pages</a></li>
+ <li><a href="../page-scripting.html">Scripting pages</a></li>
+ <li><a href="../phonegap.html">PhoneGap apps</a></li>
+ <li><a href="../touchoverflow.html">touchOverflow feature</a></li>
+ <li><a href="../pages-themes.html">Theming pages</a></li>
+
+ </ul>
+ </div>
+ </div>
+
+</div><!-- /content -->
+
+<div data-role="footer" class="footer-docs" data-theme="c">
+ <p>&copy; 2011 The jQuery Project</p>
+</div>
+
+</div><!-- /page -->
+
+</body>
+</html>
View
247 docs/pages/popup/index.html
@@ -0,0 +1,247 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>jQuery Mobile Docs - Popup</title>
+ <link rel="stylesheet" href="../../../css/themes/default/jquery.mobile.css" />
+ <link rel="stylesheet" href="../../_assets/css/jqm-docs.css"/>
+
+ <script src="../../../js/jquery.js"></script>
+ <script src="../../../docs/_assets/js/jqm-docs.js"></script>
+ <script src="../../../js/"></script>
+
+</head>
+<body>
+
+ <div data-role="page" class="type-interior">
+
+ <div data-role="header" data-theme="f">
+ <h1>Popup</h1>
+ <a href="../../../" data-icon="home" data-iconpos="notext" data-direction="reverse">Home</a>
+ <a href="../../nav.html" data-icon="search" data-iconpos="notext" data-rel="dialog" data-transition="fade">Search</a>
+ </div><!-- /header -->
+
+ <div data-role="content" class="ui-body">
+ <div class="content-primary">
+
+ <h2>Popup</h2>
+
+ <ul data-role="controlgroup" data-type="horizontal" class="localnav">
+ <li><a href="index.html" data-role="button" data-transition="fade" class="ui-btn-active">Basics</a></li>
+ <li><a href="options.html" data-role="button" data-transition="fade">Options</a></li>
+ <li><a href="methods.html" data-role="button" data-transition="fade">Methods</a></li>
+ <li><a href="events.html" data-role="button" data-transition="fade">Events</a></li>
+ </ul>
+
+ <p>To turn any div into a popup, add the <code>data-role="popup"</code> attribute to the div. If you would like the popup to appear when the user clicks on a link, create a link such that its <code>href</code> attribute is set to the id of the popup, and the link has the attribute <code>data-rel="popup"</code>. </p>
+
+<pre><code>
+&lt;a href=&quot;#popupBasic&quot; data-rel=&quot;popup&quot;&gt;Tooltip&lt;/a&gt;
+
+&lt;div data-role=&quot;popup&quot; id=&quot;popupBasic&quot;&gt;
+ This is a completely basic popup, no options set.
+&lt;/div&gt;
+</code></pre>
+
+ <p>This will result in the following <a href="#popupBasic" data-rel="popup">popup</a>. Note that we shouldn't set any padding on the popup so widgets will fit cleanly inside.</p>
+ <div data-role="popup" id="popupBasic">
+ <p>This is a completely basic popup, no options set.</p>
+ </div>
+
+ <a href="#basic" data-rel="popup" data-role="button">Default popup</a>
+ <div id="basic" data-role="popup" class="ui-content">
+ <p>I am a default popup</p>
+ </div>
+
+
+
+ <p>Now on to some cool examples:</p>
+ <a href="#popupInfo" data-rel="popup" data-role="button" data-inline="true">Tooltip</a>
+ <a href="#popupMenu" data-rel="popup" data-role="button" data-inline="true" data-transition="fade">Menu</a>
+ <a href="#popupLogin" data-rel="popup" data-role="button" data-inline="true">Form</a>
+ <a href="#popupPhoto" data-rel="popup" data-role="button" data-inline="true">Photo</a>
+ <a href="#popupDialog" data-rel="popup" data-role="button" data-inline="true">Dialog</a>
+ <a href="#popupAccordion" data-rel="popup" data-role="button" data-inline="true">Accordion</a>
+
+ <div data-role="popup" id="popupInfo" data-overlay-theme="b">
+ <div class="ui-corner-all ui-body-e" style="padding:5px 15px;">
+ <p>Here is a <strong>tiny popup</strong> being used like a <a href="#popupPhoto" data-rel="popup">tooltip</a>.</p>
+ </div>
+ </div>
+
+ <div data-role="popup" id="popupMenu" data-overlay-theme="b">
+ <ul data-role="listview" data-inset="true" style="width:180px;" data-theme="b">
+ <li><a data-rel="popup" href="#popupMenuLevel1">Add</a></li>
+ <li><a data-rel="popup" href="#popupMenuLevel1">Edit</a></li>
+ <li><a data-rel="popup" href="#popupMenuLevel1">Manage</a></li>
+ <li><a data-rel="popup" href="#popupMenuLevel1">Delete</a></li>
+ </ul>
+ </div>
+
+ <div data-role="popup" id="popupMenuLevel1" data-overlay-theme="b">
+ <ul data-role="listview" data-inset="true" style="width:180px;" data-theme="b">
+ <li><a data-rel="popup" href="#popupMenuLevel2">Remove</a></li>
+ <li><a data-rel="popup" href="#popupMenuLevel2">Undo</a></li>
+ <li><a data-rel="popup" href="#popupMenuLevel2">Splice</a></li>
+ <li><a data-rel="popup" href="#popupMenuLevel2">Reticulate</a></li>
+ </ul>
+ </div>
+
+ <div data-role="popup" id="popupMenuLevel2" data-overlay-theme="b">
+ <ul data-role="listview" data-inset="true" style="width:180px;" data-theme="b">
+ <li><a href="index.html">Basics</a></li>
+ <li><a href="options.html">Options</a></li>
+ <li><a href="methods.html">Methods</a></li>
+ <li><a href="events.html">Events</a></li>
+ </ul>
+ </div>
+
+ <div data-role="popup" id="popupLogin" data-overlay-theme="b" data-theme="a" class="ui-corner-all">
+ <form>
+ <div style="padding:10px 20px;">
+ <h3>Please sign in</h3>
+ <label for="un" class="ui-hidden-accessible">Username:</label>
+ <input type="text" name="user" id="un" value="" placeholder="username" data-theme="a" />
+
+ <label for="pw" class="ui-hidden-accessible">Password:</label>
+ <input type="password" name="pw" id="pass" value="" placeholder="password" data-theme="a" />
+
+ <button type="submit" data-theme="b">Sign in</button>
+ </div>
+ </form>
+ </div>
+
+ <div data-role="popup" id="popupPhoto" data-overlay-theme="a" data-corners="false">
+ <a href="#" data-rel="back" data-role="button" data-theme="a" data-icon="delete" data-iconpos="notext" class="ui-popup-btn-close">Close</a><img src="../../toolbars/images/photo-run.jpeg" alt="Photo Run">
+ </div>
+
+ <div data-role="popup" id="popupDialog" data-overlay-theme="d" data-theme="c" style="max-width:500px;" class="ui-corner-all">
+ <div data-role="header" data-theme="d" class="ui-corner-top">
+ <h1>Dialog</h1>
+ </div>
+ <div data-role="content" data-theme="d" style="padding:15px;" class="ui-corner-bottom">
+ <h1>Delete page?</h1>
+ <p>This is a regular page, styled as a dialog. To create a dialog, just link to a normal page and include a transition and <code>data-rel="dialog"</code> attribute.</p>
+ <a href="docs-dialogs.html" data-role="button" data-rel="back" data-theme="b">Sounds good</a>
+ <a href="docs-dialogs.html" data-role="button" data-rel="back" data-theme="c">Cancel</a>
+ </div>
+ </div>
+
+ <div data-role="popup" id="popupAccordion" data-overlay-theme="a" data-theme="c" style="width:300px;">
+ <div data-role="collapsible-set" data-theme="c" data-content-theme="d" style="margin:0;">
+ <div data-role="collapsible">
+ <h3>Section 1</h3>
+ <p>Collapsible content</p>
+ </div>
+ <div data-role="collapsible">
+ <h3>Section 2</h3>
+ <p>Collapsible content</p>
+
+ </div>
+ <div data-role="collapsible">
+ <h3>Section 3</h3>
+ <p>Collapsible content</p>
+ </div>
+ </div>
+ </div>
+
+ <p>Popup windows can have various transitions:</p>
+ <a href="#transitionExample" data-transition="none" data-role="button" data-inline="true" data-rel="popup">No transition</a>
+ <a href="#transitionExample" data-transition="pop" data-role="button" data-inline="true" data-rel="popup">Pop</a>
+ <a href="#transitionExample" data-transition="slideup" data-role="button" data-inline="true" data-rel="popup">Slide up</a>
+ <a href="#transitionExample" data-transition="slidedown" data-role="button" data-inline="true" data-rel="popup">Slide down</a>
+ <div id="transitionExample" data-role="popup" data-transition="flip">
+ <p>This is some text for the transition example</p>
+ </div>
+ <p>
+ You can add a <code>data-transition</code> attribute to the popup itself to assign it a default transition other than the system-wide <code>$.mobile.defaultDialogTransition</code>. This assignment can then be overriden by a <code>data-transition</code> attribute specified on a link that opens the popup. The transition examples have the following code:
+ </p>
+ <pre><code>
+&lt;a href=&quot;#transitionExample&quot; <strong>data-transition=&quot;none&quot;</strong> data-role=&quot;button&quot; data-inline=&quot;true&quot; data-rel=&quot;popup&quot;&gt;No transition&lt;/a&gt;
+&lt;a href=&quot;#transitionExample&quot; <strong>data-transition=&quot;pop&quot;</strong> data-role=&quot;button&quot; data-inline=&quot;true&quot; data-rel=&quot;popup&quot;&gt;Pop&lt;/a&gt;
+&lt;a href=&quot;#transitionExample&quot; <strong>data-transition=&quot;slideup&quot;</strong> data-role=&quot;button&quot; data-inline=&quot;true&quot; data-rel=&quot;popup&quot;&gt;Slide up&lt;/a&gt;
+&lt;a href=&quot;#transitionExample&quot; <strong>data-transition=&quot;slidedown&quot;</strong> data-role=&quot;button&quot; data-inline=&quot;true&quot; data-rel=&quot;popup&quot;&gt;Slide down&lt;/a&gt;
+&lt;div id=&quot;transitionExample&quot; data-role=&quot;popup&quot; <strong>data-transition=&quot;flip&quot;</strong>&gt;
+ &lt;p&gt;This is some text for the transition example&lt;/p&gt;
+&lt;/div&gt;
+ </code></pre>
+ <p>
+ When you launch the popup from any of the buttons, the <code>data-transition</code> given for that button will be used. However, if you launch the popup by other means, such as, for example, via <code>$("#transitionExample").popup("open")</code>, the <code>data-transition</code> given for the popup will be used (the flip transition).
+ </p>
+
+ <h2>Calling the popup plugin</h2>
+
+<p>This plugin will autoinitialize on any page that contains a div with the attribute <code>data-role="popup"</code>. However, if needed you can directly call the <code>popup</code> plugin on any selector, just like any jQuery plugin:</p>
+<pre><code>
+$('#myPopupDiv').popup();
+</code></pre>
+
+ <h2>Theming the popup</h2>
+<p>The <code>popup</code> plugin provides two theme-related options: <code>data-theme</code> and <code>data-overlay-theme</code>. The <code>data-theme</code> option refers to the theme of the popup itself, whereas <code>data-overlay-theme</code> refers to the theme of the popup's background, which covers the entire window behind the popup.</p>
+<p><code>data-theme</code> will be inherited from the page, and will always have a valid value when the popup opens, unless you explicitly specify <code>data-theme='none'</code>, in which case the popup will have no theme at all.</p>
+<p>The <code>data-overlay-theme</code> will never be set, and the popup's background, although it will always be present when the popup is shown, will be completely transparent, unless you explicitly set, for example, <code>data-overlay-theme='a'</code>. In this case, the background will fade in, partially obscuring the rest of the window, to further direct attention to the popup. Here is an example of an explicitly themed popup:</p>
+
+<pre><code>
+&lt;a href=&quot;#both&quot; data-rel=&quot;popup&quot; data-role=&quot;button&quot;&gt;Theme + overlay set&lt;/a&gt;
+&lt;div id=&quot;both&quot; data-role=&quot;popup&quot; <strong>data-overlay-theme=&quot;a&quot; data-theme=&quot;e&quot;</strong> class=&quot;ui-content&quot;&gt;
+ &lt;p&gt;I have &lt;code&gt;data-overlay-theme=&quot;a&quot;&lt;/code&gt; and &lt;code&gt;data-theme=&quot;e&quot;&lt;/code&gt; set on me&lt;/p&gt;
+&lt;/div&gt;
+</code></pre>
+
+<a href="#theme" data-rel="popup" data-role="button">Theme set to A</a>
+<div id="theme" data-role="popup" data-theme="a" class="ui-content">
+ <p>I have <code>data-theme="a"</code> set on me</p>
+</div>
+
+<a href="#overlay" data-rel="popup" data-role="button">Overlay set to A</a>
+<div id="overlay" data-role="popup" data-overlay-theme="a" class="ui-content">
+ <p>I have a <code>data-overlay-theme="a"</code> set on me</p>
+</div>
+
+<a href="#both" data-rel="popup" data-role="button">Theme + overlay set</a>
+<div id="both" data-role="popup" data-overlay-theme="a" data-theme="e" class="ui-content">
+ <p>I have <code>data-overlay-theme="a"</code> and <code>data-theme="e"</code> set on me</p>
+</div>
+
+ </div><!--/content-primary -->
+
+ <div class="content-secondary">
+
+ <div data-role="collapsible" data-collapsed="true" data-theme="b" data-content-theme="d">
+
+ <h3>More in this section</h3>
+
+ <ul data-role="listview" data-theme="c" data-dividertheme="d">
+
+ <li data-role="list-divider">Pages &amp; Dialogs</li>
+ <li><a href="../page-anatomy.html">Anatomy of a page</a></li>
+ <li><a href="../page-template.html" data-ajax="false">Single page template</a></li>
+ <li><a href="../multipage-template.html" data-ajax="false">Multi-page template</a></li>
+ <li><a href="../page-titles.html">Page titles</a></li>
+ <li><a href="../page-links.html">Linking pages</a></li>
+ <li><a href="../page-transitions.html" data-ajax="false">Page transitions</a></li>
+ <li><a href="../page-dialogs.html">Dialogs</a></li>
+ <li data-theme="a"><a href="index.html">Popups</a></li>
+ <li><a href="../page-cache.html">Prefetching &amp; caching pages</a></li>
+ <li><a href="../page-navmodel.html">Ajax, hashes &amp; history</a></li>
+ <li><a href="../page-dynamic.html">Dynamically Injecting Pages</a></li>
+ <li><a href="../page-scripting.html">Scripting pages</a></li>
+ <li><a href="../phonegap.html">PhoneGap apps</a></li>
+ <li><a href="../touchoverflow.html">touchOverflow feature</a></li>
+ <li><a href="../pages-themes.html">Theming pages</a></li>
+
+ </ul>
+ </div>
+ </div>
+
+</div><!-- /content -->
+
+<div data-role="footer" class="footer-docs" data-theme="c">
+ <p>&copy; 2011 The jQuery Project</p>
+</div>
+
+</div><!-- /page -->
+
+</body>
+</html>
View
99 docs/pages/popup/methods.html
@@ -0,0 +1,99 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>jQuery Mobile Docs - Popup</title>
+ <link rel="stylesheet" href="../../../css/themes/default/jquery.mobile.css" />
+ <link rel="stylesheet" href="../../_assets/css/jqm-docs.css"/>
+
+ <script src="../../../js/jquery.js"></script>
+ <script src="../../../docs/_assets/js/jqm-docs.js"></script>
+ <script src="../../../js/"></script>
+
+</head>
+<body>
+
+ <div data-role="page" class="type-interior">
+
+ <div data-role="header" data-theme="f">
+ <h1>Popup</h1>
+ <a href="../../../" data-icon="home" data-iconpos="notext" data-direction="reverse">Home</a>
+ <a href="../../../nav.html" data-icon="search" data-iconpos="notext" data-rel="dialog" data-transition="fade">Search</a>
+ </div><!-- /header -->
+
+ <div data-role="content">
+ <div class="content-primary">
+
+ <form action="#" method="get">
+
+ <h2>Popup</h2>
+
+ <ul data-role="controlgroup" data-type="horizontal" class="localnav">
+ <li><a href="index.html" data-role="button" data-transition="fade">Basics</a></li>
+ <li><a href="options.html" data-role="button" data-transition="fade">Options</a></li>
+ <li><a href="methods.html" data-role="button" data-transition="fade" class="ui-btn-active">Methods</a></li>
+ <li><a href="events.html" data-role="button" data-transition="fade">Events</a></li>
+ </ul>
+
+ <p>The popup plugin has the following methods:</p>
+
+ <dl>
+ <dt><code>open(x, y)</code> display the popup centered at coordinates (x, y)</dt>
+ <dd>
+ <pre><code>
+$('.selector').popup('open', x, y);
+ </code></pre>
+ <p>If <code>x</code> or <code>y</code> is missing, the middle of the window will be used.
+ </dd>
+
+ <dt><code>close</code> close an open popup</dt>
+ <dd>
+ <pre><code>
+$('.selector').popup('close');
+ </code></pre>
+ </dd>
+ </dl>
+
+ </form>
+ </div><!--/content-primary -->
+
+ <div class="content-secondary">
+
+ <div data-role="collapsible" data-collapsed="true" data-theme="b" data-content-theme="d">
+
+ <h3>More in this section</h3>
+
+ <ul data-role="listview" data-theme="c" data-dividertheme="d">
+
+ <li data-role="list-divider">Pages &amp; Dialogs</li>
+ <li><a href="../page-anatomy.html">Anatomy of a page</a></li>
+ <li><a href="../page-template.html" data-ajax="false">Single page template</a></li>
+ <li><a href="../multipage-template.html" data-ajax="false">Multi-page template</a></li>
+ <li><a href="../page-titles.html">Page titles</a></li>
+ <li><a href="../page-links.html">Linking pages</a></li>
+ <li><a href="../page-transitions.html" data-ajax="false">Page transitions</a></li>
+ <li><a href="../page-dialogs.html">Dialogs</a></li>
+ <li data-theme="a"><a href="index.html">Popups</a></li>
+ <li><a href="../page-cache.html">Prefetching &amp; caching pages</a></li>
+ <li><a href="../page-navmodel.html">Ajax, hashes &amp; history</a></li>
+ <li><a href="../page-dynamic.html">Dynamically Injecting Pages</a></li>
+ <li><a href="../page-scripting.html">Scripting pages</a></li>
+ <li><a href="../phonegap.html">PhoneGap apps</a></li>
+ <li><a href="../touchoverflow.html">touchOverflow feature</a></li>
+ <li><a href="../pages-themes.html">Theming pages</a></li>
+
+ </ul>
+ </div>
+ </div>
+
+</div><!-- /content -->
+
+<div data-role="footer" class="footer-docs" data-theme="c">
+ <p>&copy; 2011 The jQuery Project</p>
+</div>
+
+</div><!-- /page -->
+
+</body>
+</html>
View
126 docs/pages/popup/options.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>jQuery Mobile Docs - Popup</title>
+ <link rel="stylesheet" href="../../../css/themes/default/jquery.mobile.css" />
+ <link rel="stylesheet" href="../../_assets/css/jqm-docs.css"/>
+
+ <script src="../../../js/jquery.js"></script>
+ <script src="../../../docs/_assets/js/jqm-docs.js"></script>
+ <script src="../../../js/"></script>
+
+</head>
+<body>
+
+ <div data-role="page" class="type-interior">
+
+ <div data-role="header" data-theme="f">
+ <h1>Popup</h1>
+ <a href="../../../" data-icon="home" data-iconpos="notext" data-direction="reverse">Home</a>
+ <a href="../../nav.html" data-icon="search" data-iconpos="notext" data-rel="dialog" data-transition="fade">Search</a>
+ </div><!-- /header -->
+
+ <div data-role="content" class="ui-body">
+ <div class="content-primary">
+
+ <form action="#" method="get">
+
+ <h2>Popup</h2>
+
+ <ul data-role="controlgroup" data-type="horizontal" class="localnav">
+ <li><a href="index.html" data-role="button" data-transition="fade">Basics</a></li>
+ <li><a href="options.html" data-role="button" data-transition="fade" class="ui-btn-active">Options</a></li>
+ <li><a href="methods.html" data-role="button" data-transition="fade">Methods</a></li>
+ <li><a href="events.html" data-role="button" data-transition="fade">Events</a></li>
+ </ul>
+
+ <p>The popup plugin has the following options:</p>
+
+ <dl>
+ <dt><code>overlayTheme</code> <em>string</em></dt>
+ <dd>
+ <p class="default">default: null</p>
+ <p>Sets the color scheme (swatch) for the popup background, which covers the entire window. If not explicitly set, the background will be transparent.</p>
+ <pre><code>$('.selector').popup(<strong>{ overlayTheme: "a" }</strong>);</code></pre>
+ <p>This option is also exposed as a data attribute: <code>data-overlay-theme=&quot;a&quot;</code></p>
+ </dd>
+
+ <dt><code>theme</code> <em>string</em></dt>
+ <dd>
+ <p class="default">default: null</p>
+ <p>Sets the color scheme (swatch) for the popup contents. Unless explicitly set to <code>'none'</code>, the
+ theme for the popup will be assigned the first time the popup is shown by inheriting the page theme or, failing that, by the hard-coded value <code>'c'</code>. If you set it to 'none', the popup will not have any theme at all, and will be transparent.</p>
+ <pre><code>$('.selector').popup(<strong>{ theme: "a" }</strong>);</code></pre>
+ <p>This option is also exposed as a data attribute: <code>data-theme=&quot;a&quot;</code></p>
+ </dd>
+
+ <dt><code>initSelector</code> <em>CSS selector string</em></dt>
+ <dd>
+ <p class="default">default: ":jqmData(role='popup')"</p>
+ <p>This is used to define the selectors (element types, data roles, etc.) that will automatically be initialized as popups. To change which elements are initialized, bind this option to the <a href="../../api/globalconfig.html">mobileinit event</a>:</p>
+<pre><code>$( document ).bind( "mobileinit", function(){
+ <strong>$.mobile.popup.prototype.options.initSelector = ".mypopup";</strong>
+});
+</code></pre>
+ </dd>
+
+ <dt><code>shadow</code> <em>boolean</em></dt>
+ <dd>
+ <p class="default">default: true</p>
+ <p>Sets whether to draw a shadow around the popup. This option is also exposed as a data attribute: <code>data-shadow=&quot;true&quot;</code></p>
+ <pre><code>$('.selector').popup(<strong>{ shadow: true }</strong>);</code></pre>
+ </dd>
+
+ <dt><code>corners</code> <em>boolean</em></dt>
+ <dd>
+ <p class="default">default: true</p>
+ <p>Sets whether to draw the popup with rounded corners. This option is also exposed as a data attribute: <code>data-corners=&quot;true&quot;</code></p>
+ <pre><code>$('.selector').popup(<strong>{ corners: true }</strong>);</code></pre>
+ </dd>
+
+ </dl>
+
+ </form>
+ </div><!--/content-primary -->
+
+ <div class="content-secondary">
+
+ <div data-role="collapsible" data-collapsed="true" data-theme="b" data-content-theme="d">
+
+ <h3>More in this section</h3>
+
+ <ul data-role="listview" data-theme="c" data-dividertheme="d">
+
+ <li data-role="list-divider">Pages &amp; Dialogs</li>
+ <li><a href="../page-anatomy.html">Anatomy of a page</a></li>
+ <li><a href="../page-template.html" data-ajax="false">Single page template</a></li>
+ <li><a href="../multipage-template.html" data-ajax="false">Multi-page template</a></li>
+ <li><a href="../page-titles.html">Page titles</a></li>
+ <li><a href="../page-links.html">Linking pages</a></li>
+ <li><a href="../page-transitions.html" data-ajax="false">Page transitions</a></li>
+ <li><a href="../page-dialogs.html">Dialogs</a></li>
+ <li data-theme="a"><a href="index.html">Popups</a></li>
+ <li><a href="../page-cache.html">Prefetching &amp; caching pages</a></li>
+ <li><a href="../page-navmodel.html">Ajax, hashes &amp; history</a></li>
+ <li><a href="../page-dynamic.html">Dynamically Injecting Pages</a></li>
+ <li><a href="../page-scripting.html">Scripting pages</a></li>
+ <li><a href="../phonegap.html">PhoneGap apps</a></li>
+ <li><a href="../touchoverflow.html">touchOverflow feature</a></li>
+ <li><a href="../pages-themes.html">Theming pages</a></li>
+
+ </ul>
+ </div>
+ </div>
+
+</div><!-- /content -->
+
+<div data-role="footer" class="footer-docs" data-theme="c">
+ <p>&copy; 2011 The jQuery Project</p>
+</div>
+
+</div><!-- /page -->
+
+</body>
+</html>
View
1  docs/pages/touchoverflow.html
@@ -105,6 +105,7 @@ <h2 id="ios5">touchOverflow: Improved page transitions and true fixed toolbars</
<li><a href="page-transitions.html">Page transitions</a></li>
<li><a href="loader.html">Page loading widget</a></li>
<li><a href="page-dialogs.html">Dialogs</a></li>
+ <li><a href="popup/index.html">Popups</a></li>
<li><a href="page-cache.html">Prefetching &amp; caching pages</a></li>
<li><a href="page-navmodel.html">Ajax, hashes &amp; history</a></li>
<li><a href="page-dynamic.html">Dynamically injecting pages</a></li>
View
1  js/index.php
@@ -48,6 +48,7 @@
'jquery.mobile.controlGroup.js',
'jquery.mobile.links.js',
'jquery.mobile.fixedToolbar.js',
+ 'jquery.mobile.popup.js',
'jquery.mobile.zoom.js',
'jquery.mobile.zoom.iosorientationfix.js',
'jquery.mobile.init.js'
View
1  js/jquery.mobile.js
@@ -35,6 +35,7 @@ define([
'./jquery.mobile.controlGroup',
'./jquery.mobile.links',
'./jquery.mobile.fixedToolbar',
+ './jquery.mobile.popup',
'./jquery.mobile.zoom',
'./jquery.mobile.zoom.iosorientationfix'
], function( require ) {
View
622 js/jquery.mobile.popup.js
@@ -0,0 +1,622 @@
+//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
+//>>description: Popup windows.
+//>>label: Popups
+//>>css: ../css/themes/default/jquery.mobile.theme.css,../css/structure/jquery.mobile.popup.css,../css/structure/jquery.mobile.transition.css,../css/structure/jquery.mobile.transition.fade.css
+
+define( [ "jquery",
+ "jquery.mobile.widget",
+ "jquery.mobile.navigation",
+ "../external/requirejs/depend!./jquery.hashchange[jquery]" ], function( $ ) {
+//>>excludeEnd("jqmBuildExclude");
+(function( $, undefined ) {
+
+ $.widget( "mobile.popup", $.mobile.widget, {
+ options: {
+ theme: null,
+ overlayTheme: null,
+ shadow: true,
+ corners: true,
+ transition: $.mobile.defaultDialogTransition,
+ initSelector: ":jqmData(role='popup')"
+ },
+
+ _create: function() {
+ var ui = {
+ screen: "#ui-popup-screen",
+ placeholder: "#placeholder",
+ container: "#ui-popup-container"
+ },
+ proto = $(
+ "<div>" +
+ " <div id='ui-popup-screen' class='ui-screen-hidden ui-popup-screen fade'></div>" +
+ " <div id='ui-popup-container' class='ui-popup-container ui-selectmenu-hidden'></div>" +
+ " <div id='placeholder' style='display: none;'><!-- placeholder --></div>" +
+ "</div>"
+ ),
+ thisPage = this.element.closest( ":jqmData(role='page')" ),
+ myId = this.element.attr( "id" ),
+ self = this;
+
+ if ( thisPage.length === 0 ) {
+ thisPage = $( "body" );
+ }
+
+ // Assign the relevant parts of the proto
+ for ( var key in ui ) {
+ ui[ key ] = proto.find( ui[ key ] ).removeAttr( "id" );
+ }
+
+ // Apply the proto
+ thisPage.append( ui.screen );
+ ui.container.insertAfter( ui.screen );
+ // Leave a placeholder where the element used to be
+ ui.placeholder.insertAfter( this.element );
+ if ( myId ) {
+ ui.placeholder.html( "<!-- placeholder for " + myId + " -->" );
+ }
+ ui.container.append( this.element );
+
+ // Define instance variables
+ $.extend( this, {
+ _page: thisPage,
+ _ui: ui,
+ _fallbackTransition: "",
+ _currentTransition: false,
+ _isOpen: false
+ });
+
+ $.each( this.options, function( key ) {
+ // Cause initial options to be applied by their handler by temporarily setting the option to undefined
+ // - the handler then sets it to the initial value
+ var value = self.options[ key ];
+
+ self.options[ key ] = undefined;
+ self._setOption( key, value, true );
+ });
+
+ ui.screen.bind( "vclick", function( e ) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ self.close();
+ });
+ $( window ).bind( "keyup", function( e ) {
+ if ( self._isOpen ) {
+ if ( e.keyCode === $.mobile.keyCode.ESCAPE ) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ self.close();
+ }
+ }
+ });
+ },
+
+ _realSetTheme: function( dst, theme ) {
+ var classes = ( dst.attr( "class" ) || "").split( " " ),
+ alreadyAdded = true,
+ currentTheme = null,
+ matches,
+ themeStr = String( theme );
+
+ while ( classes.length > 0 ) {
+ currentTheme = classes.pop();
+ matches = currentTheme.match( /^ui-body-([a-z])$/ );
+ if ( matches && matches.length > 1 ) {
+ currentTheme = matches[ 1 ];
+ break;
+ } else {
+ currentTheme = null;
+ }
+ }
+
+ if ( theme !== currentTheme ) {
+ dst.removeClass( "ui-body-" + currentTheme );
+ if ( ! ( theme === null || theme === "none" ) ) {
+ dst.addClass( "ui-body-" + themeStr );
+ }
+ }
+ },
+
+ _setTheme: function( value ) {
+ this._realSetTheme( this._ui.container, value );
+ this.options.theme = value;
+ this.element.attr( "data-" + ( $.mobile.ns || "" ) + "theme", value );
+ },
+
+ _setOverlayTheme: function( value ) {
+ this._realSetTheme( this._ui.screen, value );
+ this.options.overlayTheme = value;
+ this.element.attr( "data-" + ( $.mobile.ns || "" ) + "overlay-theme", value );
+ },
+
+ _setShadow: function( value ) {
+ this._ui.container[value ? "addClass" : "removeClass"]( "ui-overlay-shadow" );
+ this.options.shadow = value;
+ this.element.attr( "data-" + ( $.mobile.ns || "" ) + "shadow", value );
+ },
+
+ _setCorners: function( value ) {
+ this._ui.container[value ? "addClass" : "removeClass"]( "ui-corner-all" );
+ this.options.corners = value;
+ this.element.attr( "data-" + ( $.mobile.ns || "" ) + "corners", value );
+ },
+
+ _applyTransition: function( value ) {
+ this._ui.container.removeClass( this._fallbackTransition );
+ if ( value && value !== "none" ) {
+ this._fallbackTransition = $.mobile._maybeDegradeTransition( value );
+ this._ui.container.addClass( this._fallbackTransition );
+ }
+ },
+
+ _setTransition: function( value ) {
+ if ( !this._currentTransition ) {
+ this._applyTransition( value );
+ }
+ this.options.transition = value;
+ this.element.attr( "data-" + ( $.mobile.ns || "" ) + "transition", value );
+ },
+
+ _setOption: function( key, value ) {
+ var setter = "_set" + key.replace( /^[a-z]/, function(c) {
+ return c.toUpperCase();
+ });
+
+ if ( this[setter] !== undefined ) {
+ this[setter]( value );
+ } else {
+ $.mobile.widget.prototype._setOption.apply( this, arguments );
+ }
+ },
+
+ _placementCoords: function( x, y ) {
+ // Try and center the overlay over the given coordinates
+ var ret,
+ menuHeight = this._ui.container.outerHeight( true ),
+ menuWidth = this._ui.container.outerWidth( true ),
+ scrollTop = $( window ).scrollTop(),
+ screenHeight = $( window ).height(),
+ screenWidth = $( window ).width(),
+ halfheight = menuHeight / 2,
+ maxwidth = screenWidth - 20,
+ roomtop = y - scrollTop,
+ roombot = scrollTop + screenHeight - y,
+ newtop, newleft;
+
+ this._ui.container.css( "max-width", maxwidth );
+
+ menuWidth = this._ui.container.outerWidth( true );
+ menuHeight = this._ui.container.outerHeight( true );
+
+ if ( roomtop > menuHeight / 2 && roombot > menuHeight / 2 ) {
+ newtop = y - halfheight;
+ } else {
+ // 30px tolerance off the edges
+ newtop = roomtop > roombot ? scrollTop + screenHeight - menuHeight - 30 : scrollTop + 30;
+ }
+
+ // If the menuwidth is greater or equal to the max-width, center it on screen
+ if ( menuWidth >= maxwidth ) {
+ newleft = ( screenWidth - menuWidth ) / 2;
+ } else {
+ //otherwise insure a >= 30px offset from the left
+ newleft = x - menuWidth / 2;
+
+ // 10px tolerance off the edges
+ if ( newleft < 10 ) {
+ newleft = 10;
+ } else if ( ( newleft + menuWidth ) > screenWidth ) {
+ newleft = screenWidth - menuWidth - 10;
+ }
+ }
+
+ return { x: newleft, y: newtop };
+ },
+
+ _realOpen: function( x, y, transition ) {
+ var self = this,
+ // Count down to triggering "opened" - we have two prerequisits:
+ // 1. The popup window animation completes (onAnimationComplete())
+ // 2. The screen opacity animation completes (showScreen())
+ triggerPrereqs = 2,
+ maybeTriggerOpened = function() {
+ triggerPrereqs--;
+
+ if ( 0 === triggerPrereqs ) {
+ self._isOpen = true;
+ self.element.trigger( "opened" );
+ }
+ },
+ onAnimationComplete = function() {
+ self._ui.screen.height( $( document ).height() );
+ maybeTriggerOpened();
+ },
+ showScreen = function() {
+ maybeTriggerOpened();
+ },
+ coords = self._placementCoords(
+ ( undefined === x ? window.innerWidth / 2 : x ),
+ ( undefined === y ? window.innerHeight / 2 : y ) );
+
+ if ( transition ) {
+ self._currentTransition = transition;
+ self._applyTransition( transition );
+ }
+ else {
+ transition = self.options.transition;
+ }
+
+ if ( !self.options.theme ) {
+ self._setTheme( self._page.jqmData( "theme" ) || $.mobile.getInheritedTheme( self._page, "c" ) );
+ }
+
+ self._ui.screen
+ .height( $( document ).height() )
+ .removeClass( "ui-screen-hidden" );
+
+ if ( self.options.overlayTheme ) {
+ self._ui.screen
+ .addClass("in")
+ .animationComplete( showScreen );
+ }
+ else {
+ showScreen();
+ }
+
+ self._ui.container
+ .removeClass( "ui-selectmenu-hidden" )
+ .css( {
+ left: coords.x,
+ top: coords.y
+ });
+
+ if ( transition && transition !== "none" ) {
+ self._ui.container
+ .addClass( "in" )
+ .animationComplete( onAnimationComplete );
+ }
+ else {
+ onAnimationComplete();
+ }
+ },
+
+ _realClose: function() {
+ var self = this,
+ transition = ( self._currentTransition ? self._currentTransition : self.options.transition ),
+ // Count down to triggering "closed" - we have two prerequisits:
+ // 1. The popup window reverse animation completes (onAnimationComplete())
+ // 2. The screen opacity animation completes (hideScreen())
+ triggerPrereqs = 2,
+ maybeTriggerClosed = function() {
+ triggerPrereqs--;
+
+ if ( 0 === triggerPrereqs ) {
+ self._isOpen = false;
+ if ( self._currentTransition ) {
+ self._applyTransition( self.options.transition );
+ self._currentTransition = false;
+ }
+ self.element.trigger( "closed" );
+ }
+ },
+ onAnimationComplete = function() {
+ self._ui.container
+ .removeClass( "reverse out" )
+ .addClass( "ui-selectmenu-hidden" )
+ .removeAttr( "style" );
+ maybeTriggerClosed();
+ },
+ hideScreen = function() {
+ self._ui.screen.addClass( "ui-screen-hidden" );
+ self._ui.screen.removeClass( "out" );
+ maybeTriggerClosed();
+ };
+
+ if ( transition && transition !== "none" ) {
+ this._ui.container
+ .removeClass( "in" )
+ .addClass( "reverse out" )
+ .animationComplete( onAnimationComplete );
+ } else {
+ onAnimationComplete();
+ }
+
+ if ( this.options.overlayTheme && this._ui.screen.hasClass( "in" ) ) {
+ this._ui.screen
+ .removeClass( "in" )
+ .addClass( "out" )
+ .animationComplete( hideScreen );
+ } else {
+ hideScreen();
+ }
+ },
+
+ _destroy: function() {
+ // Put the element back to where the placeholder was
+ this.element.insertAfter( this._ui.placeholder );
+ this._ui.screen.remove();
+ this._ui.container.remove();
+ this._ui.placeholder.remove();
+ },
+
+ open: function( x, y, transition ) {
+ $.mobile.popup.popupManager.push( this, arguments );
+ },
+
+ close: function() {
+ $.mobile.popup.popupManager.pop( this );
+ }
+ });
+
+ $.mobile.popup.popupManager = {
+ // array of: {
+ // open: true/false
+ // popup: popup
+ // args: args for _realOpen
+ // }
+ _actionQueue: [],
+ _inProgress: false,
+ _haveNavHook: false,
+ _currentlyOpenPopup: null,
+ _myOwnHashChange: false,
+
+ // Call _onHashChange if the hash changes /after/ the popup is on the screen
+ // Note that placing the popup on the screen can itself cause a hashchange,
+ // because the dialogHashKey may need to be added to the URL.
+ _doNavHook: function( whenHooked ) {
+ var self = this;
+
+ if ( $.mobile.hashListeningEnabled ) {
+ var activeEntry = $.mobile.urlHistory.getActive(),
+ hasHash = ( activeEntry.url.indexOf( $.mobile.dialogHashKey ) > -1 );
+
+ function realInstallListener() {
+ $( window ).one( "hashchange.popup", function() {
+ self._onHashChange();
+ });
+ whenHooked();
+ }
+
+ if ( hasHash ) {
+ realInstallListener();
+ }
+ else {
+ $( window ).one( "hashchange.popupBinder", function() {
+ realInstallListener();
+ });
+ $.mobile.path.set( activeEntry.url + $.mobile.dialogHashKey );
+ $.mobile.urlHistory.addNew( activeEntry.url + $.mobile.dialogHashKey, activeEntry.transition, activeEntry.title, activeEntry.pageUrl, activeEntry.role );
+ }
+ }
+ else {
+ whenHooked();
+ }
+ },
+
+ _undoNavHook: function() {
+ if ( $.mobile.hashListeningEnabled ) {
+ window.history.back();
+ }
+ else {
+ this._onHashChange();
+ }
+ },
+
+ _inArray: function( action ) {
+ var self = this,
+ idx = -1;
+
+ $.each( self._actionQueue, function( arIdx, value ) {
+ if ( value.open === action.open && value.popup === action.popup ) {
+ idx = arIdx;
+ return false;
+ }
+ return true;
+ });
+
+ return idx;
+ },
+
+ _completeAction: function() {
+ var self = this,
+ current = self._actionQueue.shift();
+
+ self._currentlyOpenPopup = ( current.open ? current.popup : null );
+
+ if ( self._actionQueue.length === 0 ) {
+ if ( current.open ) {
+ self._inProgress = false;
+ }
+ else
+ if ( self._haveNavHook ) {
+ self._haveNavHook = false;
+ self._myOwnHashChange = true;
+ self._undoNavHook();
+ }
+ else {
+ self._inProgress = false;
+ }
+ }
+ else {
+ self._inProgress = false;
+ self._runSingleAction();
+ }
+ },
+
+ _continueWithAction: function() {
+ var self = this,
+ signal, fn, args;
+
+ if ( self._actionQueue[0].open ) {
+ if ( self._currentlyOpenPopup ) {
+ self._actionQueue.unshift( { open: false, popup: self._currentlyOpenPopup } );
+ self._inProgress = false;
+ self._runSingleAction();
+ return;
+ }
+ signal = "opened";
+ fn = "_realOpen";
+ args = self._actionQueue[0].args;
+ }
+ else {
+ signal = "closed";
+ fn = "_realClose";
+ args = [];
+ }
+
+ self._actionQueue[0].popup.element.one( signal, function() {
+ self._completeAction();
+ });
+ self._actionQueue[0].popup[fn].apply( self._actionQueue[0].popup, args );
+ },
+
+ _runSingleAction: function() {
+ var self = this;
+
+ if ( !self._inProgress ) {
+ self._inProgress = true;
+ if ( self._haveNavHook || !self._actionQueue[0].open ) {
+ self._continueWithAction();
+ }
+ else {
+ self._doNavHook( function() {
+ self._haveNavHook = true;
+ self._continueWithAction();
+ });
+ }
+ }
+ },
+
+ push: function( popup, args ) {
+ var self = this,
+ newAction = { open: true, popup: popup, args: args },
+ idx = self._inArray( newAction );
+
+ if ( -1 === idx ) {
+ if ( self._currentlyOpenPopup === popup ) {
+ var closeAction = { open: false, popup: popup },
+ cIdx = self._inArray( closeAction );
+
+ if ( cIdx !== -1 ) {
+ if ( 0 === cIdx && self._inProgress ) {
+ self._actionQueue.push( newAction );
+ }
+ else {
+ self._actionQueue.splice( cIdx, 1 );
+ }
+ self._runSingleAction();
+ }
+ }
+ else {
+ self._actionQueue.push( newAction );
+ self._runSingleAction();
+ }
+ }
+ },
+
+ pop: function( popup ) {
+ var self = this,
+ newAction = { open: false, popup: popup },
+ idx = self._inArray( newAction );
+
+ if ( -1 === idx ) {
+ var openAction = { open: true, popup: popup },
+ oIdx = self._inArray( openAction );
+
+ if ( oIdx !== -1 ) {
+ if ( 0 === oIdx ) {
+ self._actionQueue.splice( 1, 0, newAction );
+ self._runSingleAction();
+ }
+ else {
+ self._actionQueue.splice( oIdx, 1 );
+ }
+ }
+ else
+ if ( self._currentlyOpenPopup === popup ) {
+ if ( self._actionQueue.length === 0 ) {
+ self._actionQueue.push( newAction );
+ self._runSingleAction();
+ }
+ else {
+ self._actionQueue.splice( ( self._inProgress ? 1 : 0 ), 0, newAction );
+ self._runSingleAction();
+ }
+ }
+ }
+ },
+
+ _onHashChange: function() {
+ var self = this;
+
+ self._haveNavHook = false;
+
+ if ( self._myOwnHashChange ) {
+ self._myOwnHashChange = false;
+ self._inProgress = false;
+ if ( self._actionQueue.length > 0 ) {
+ self._runSingleAction() ;
+ }
+ }
+ else {
+ var popupToClose = null;
+ if ( self._inProgress ) {
+ self._actionQueue = [ self._actionQueue[0] ];
+ if ( self._actionQueue[0].open ) {
+ popupToClose = self._actionQueue[0].popup;
+ }
+ }
+ else {
+ self._actionQueue = [];
+ if ( self._currentlyOpenPopup ) {
+ popupToClose = self._currentlyOpenPopup;
+ }
+ }
+ if ( popupToClose ) {
+ self._actionQueue.push( { open: false, popup: popupToClose } );
+ self._runSingleAction();
+ }
+ }
+ }
+ }
+
+ $.mobile.popup.bindPopupToButton = function( btn, popup ) {
+ if ( btn.length === 0 || popup.length === 0 ) return;
+
+ var btnVClickHandler = function( e ) {
+ popup.popup( "open",
+ btn.offset().left + btn.outerWidth() / 2,
+ btn.offset().top + btn.outerHeight() / 2,
+ btn.jqmData( "transition" ) );
+
+ // Swallow event, because it might end up getting picked up by the popup window's screen handler, which
+ // will in turn cause the popup window to close - Thanks Sasha!
+ if ( e.stopPropagation ) {
+ e.stopPropagation();
+ }
+ if ( e.preventDefault ) {
+ e.preventDefault();
+ }
+ };
+
+ btn.attr( {
+ "aria-haspopup": true,
+ "aria-owns": btn.attr( "href" )
+ })
+ .removeAttr( "href" )
+ .bind( "vclick", btnVClickHandler );
+ };
+
+ $( document ).bind( "pagecreate create", function( e ) {
+ $( $.mobile.popup.prototype.options.initSelector, e.target )
+ .not( ":jqmData(role='none'), :jqmData(role='nojs')" )
+ .popup();
+
+ $( "a[href^='#']:jqmData(rel='popup')", e.target ).each( function() {
+ $.mobile.popup.bindPopupToButton( $( this ), $( $( this ).attr( "href" ) ) );
+ });
+ });
+
+})( jQuery );
+//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
+});
+//>>excludeEnd("jqmBuildExclude");
View
53 tests/unit/popup/index.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>jQuery Mobile Popup Test Suite</title>
+
+ <script src="../../../external/requirejs/require.js"></script>
+ <script src="../../../js/jquery.tag.inserter.js"></script>
+ <script src="../jquery.setNameSpace.js"></script>
+ <script src="../../../tests/jquery.testHelper.js"></script>
+
+
+ <link rel="stylesheet" href="../../../css/themes/default/jquery.mobile.css"/>
+ <link rel="stylesheet" href="../../../external/qunit.css"/>
+ <script src="../../../external/qunit.js"></script>
+ <script>
+ $.testHelper.asyncLoad([
+ [
+ "jquery.mobile.popup",
+ ],
+ [ "jquery.mobile.init" ],
+ [
+ "popup_core.js"
+ ],
+ [
+ "popup_interaction.js"
+ ]
+ ]);
+ </script>
+
+ <script src="../swarminject.js"></script>
+</head>
+<body>
+ <h1 id="qunit-header">jQuery Mobile Popup Test Suite</h1>
+ <h2 id="qunit-banner"></h2>
+ <h2 id="qunit-userAgent"></h2>
+ <ol id="qunit-tests">
+ </ol>
+
+ <div data-nstest-role="page">
+ <div data-nstest-role="content" id="page-content">
+ <div data-nstest-role="popup" id="test-popup">
+ <p>This is the test popup</p>
+ <a href="other.html">other.html</a>
+ </div>
+ <div data-nstest-role="popup" id="test-popup-2">
+ <p>This is another test popup</p>
+ </div>
+ </div>
+ </div>
+</body>
+</html>
View
9 tests/unit/popup/other.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8"></meta>
+ </head>
+ <body>
+ <div data-nstest-role="page" id="other-page"></div>
+ </body>
+</html>
View
396 tests/unit/popup/popup_core.js
@@ -0,0 +1,396 @@
+/*
+ * mobile popup unit tests
+ */
+(function($){
+
+ $.extend($.testHelper, {
+
+// detailedEventCascade: call a function and expect a series of events to be triggered (or not to be triggered), and guard
+// with a timeout against getting stood up. Record the result (timed out / was triggered) for each event, and the order
+// in which the event arrived wrt. any other events expected.
+// seq : [
+// fn(result),
+// { key: {
+// src: event source (is jQuery object),
+// event: event name (is string),
+// NB: It's a good idea to namespace your events, because the handler will be removed
+// based on the name you give here if a timeout occurs before the event fires.
+// userData1: value,
+// ...
+// userDatan: value
+// },
+// ...
+// ]
+// ...
+// ]
+// result: {
+// key: {
+// idx: order in which the event fired
+// src: event source (is jQuery object),
+// event: event name (is string)
+// timedOut: timed out (is boolean)
+// userData1: value,
+// ...
+// userDatan: value
+// }
+// ...
+// }
+ detailedEventCascade: function( seq, result ) {
+ // grab one step from the sequence
+ var fn = seq.shift(),
+ events = seq.shift(),
+ self = this;
+
+ // we're done
+ if ( fn === undefined ) {
+ return;
+ }
+
+ // Attach handlers to the various objects which are to be checked for correct event generation
+ if ( events ) {
+ var newResult = {},
+ nEventsDone = 0,
+ nEvents = 0,
+ // set a failsafe timer in case one of the events never happens
+ warnTimer = setTimeout( function() {
+ $.each( events, function( key, event ) {
+ if ( newResult[ key ] === undefined ) {
+ // clean up the unused handler
+ event.src.unbind( event.event );
+ newResult[ key ] = $.extend( {}, event, { timedOut: true } );
+ }
+ });
+
+ // Move on to the next step
+ self.detailedEventCascade( seq, newResult );
+ }, 2000);
+
+ function recordResult( key, event, result ) {
+ // Record the result
+ newResult[ key ] = $.extend( {}, event, result );
+ // Increment the number of received responses
+ nEventsDone++;
+ if ( nEventsDone === nEvents ) {
+ // clear the timeout and move on to the next step when all events have been received
+ clearTimeout( warnTimer );
+ setTimeout( function() {
+ self.detailedEventCascade( seq, newResult );
+ }, 0);
+ }
+ }
+
+ $.each( events, function( key, event ) {
+ // Count the events so that we may know how many responses to expect
+ nEvents++;
+ // If it's an event
+ if ( event.src ) {
+ // Hook up to the event
+ event.src.one( event.event, function() {
+ recordResult( key, event, { timedOut: false, idx: nEventsDone } );
+ });
+ }
+ // If it's a timeout
+ else {
+ setTimeout( function() {
+ recordResult( key, event, { timedOut: true, idx: -1 } );
+ }, event.length );
+ }
+ });
+ }
+
+ // Call the function with the result of the events
+ fn( result );
+ }
+ });
+
+ function popupEnhancementTests( prefix ) {
+ ok( $( "#test-popup" ).data( "popup" ), prefix + ", popup div is associated with a popup widget" );
+ ok( $( "#test-popup" ).parent().hasClass( "ui-popup-container" ), prefix + ", popup div parent has class ui-popup-container" );
+ ok( $( "#test-popup" ).parent().parent().hasClass( "ui-page" ), prefix + ", popup div grandparent is the page" );
+ ok( $( "#test-popup" ).parent().prev().hasClass( "ui-popup-screen" ), prefix + ", popup div is preceded by its screen" );
+ ok( $( "#page-content" ).children().first().html() === "<!-- placeholder for test-popup -->", prefix + ", there is a placeholder in the popup div's original location" );
+ }
+
+ test( "Popup is enhanced correctly", function() { popupEnhancementTests( "When autoenhanced" ); } );
+
+ test( "Popup rearranges DOM elements correctly when it is destroyed and again when it is re-created", function() {
+ $( "#test-popup" ).popup( "destroy" );
+
+ ok( $( "#page-content" ).children().first().attr( "id" ) === "test-popup", "After destroying a popup, its payload is returned to its original location" );
+ ok( $( "#page-content" ).children().first().prev().html() !== "<!-- placeholder for test-popup -->", "No placeholder precedes the restored popup" );
+ ok( $( "#page-content" ).children().first().next().html() !== "<!-- placeholder for test-popup -->", "No placeholder succeedes the restored popup" );
+
+ $( "#test-popup" ).popup();
+
+ popupEnhancementTests( "When re-created" );
+ });
+
+ asyncTest( "Popup opens and closes", function() {
+
+ expect( 5 );
+
+ $( "#test-popup" ).popup( "open" );
+ setTimeout(function() {
+ ok( $( "#test-popup" ).parent().hasClass( "in" ), "Open popup container has class 'in'" );
+ ok( !$( "#test-popup" ).parent().prev().hasClass( "ui-screen-hidden" ), "Open popup screen is not hidden" );
+ ok( $( "#test-popup" ).parent().attr( "class" ).match( /( |^)ui-body-[a-z]( |$)/ ), "Open popup has a valid overlay theme" );
+ $( "#test-popup" ).popup( "close" );
+ setTimeout(function() {
+ ok( !$( "#test-popup" ).parent().hasClass( "in" ), "Closed popup container does not have class 'in'" );
+ ok( $( "#test-popup" ).parent().prev().hasClass( "ui-screen-hidden" ), "Closed popup screen is hidden" );
+ setTimeout( function() { start(); }, 300 );
+ }, 1000);
+ }, 1000);
+ });
+
+ asyncTest( "Popup interacts correctly with hashchange", function() {
+ var baseUrl, activeIndex;
+
+ expect( 6 );
+
+ $.testHelper.detailedEventCascade([
+ function() {
+ baseUrl = location.href;
+ activeIndex = $.mobile.urlHistory.activeIndex;
+ $( "#test-popup" ).popup( "open" );
+ },
+
+ {
+ opened: { src: $( "#test-popup" ), event: "opened.hashInteractStep1" },
+ hashchange: { src: $( window ), event: "hashchange.hashInteractStep1" }
+ },
+
+ function( result ) {
+ ok( !result.hashchange.timedOut, "Opening a popup from a non-dialogHashKey location causes a hashchange event" );
+ ok( location.href === baseUrl + ( ( baseUrl.indexOf( "#" ) > -1 ) ? "" : "#" ) + $.mobile.dialogHashKey, "location.href has been updated correctly" );
+ ok( $.mobile.urlHistory.activeIndex === activeIndex + 1, "$.mobile.urlHistory has been advanced correctly" );
+ $( "#test-popup" ).popup( "close" );
+ },
+
+ {
+ closed: { src: $( "#test-popup" ), event: "closed.hashInteractStep2" },
+ hashchange: { src: $( window ), event: "hashchange.hashInteractStep2" }
+ },
+
+ function( result ) {
+ ok( !result.hashchange.timedOut, "Closing a popup from a non-dialogHashKey location causes a hashchange event" );
+ ok( location.href === baseUrl, "location.href has been restored after the popup" );
+ ok( $.mobile.urlHistory.activeIndex === activeIndex, "$.mobile.urlHistory has been restored correctly" );
+ setTimeout( function() { start(); }, 300 );
+ }
+ ]);
+ });
+
+ asyncTest( "When opening a popup from a dialogHashKey location the location is reused", function() {
+ var origUrl, origIndex, baseUrl, baseIndex;
+
+ expect( 4 );
+
+ $.testHelper.detailedEventCascade([
+ function() {
+ origUrl = location.href;
+ origIndex = $.mobile.urlHistory.activeIndex;
+ $( "#test-popup" ).popup( "open" );
+ },
+
+ {
+ opened: { src: $( "#test-popup" ), event: "opened.reuseStep1" },
+ hashchange: { src: $( window ), event: "hashchange.reuseStep1" }
+ },
+
+ function( result ) {
+ $( "#test-popup" ).popup( "close" );
+ },
+
+ {
+ closed: { src: $( "#test-popup" ), event: "closed.reuseStep2" },
+ hashchange: { src: $( window ), event: "hashchange.reuseStep2" },
+ timeout: { src: null, length: 300 }
+ },
+
+ function( result ) {
+ window.history.forward();
+ },
+
+ { hashchange: { src: $( window ), event: "hashchange.reuseStep3" } },
+
+ function( result ) {
+ baseUrl = location.href;
+ activeIndex = $.mobile.urlHistory.activeIndex;
+ $( "#test-popup" ).popup( "open" );
+ },
+
+ {
+ opened: { src: $( "#test-popup" ), event: "opened.reuseStep4" },
+ hashchange: { src: $( window ), event: "hashchange.reuseStep4" }
+ },
+
+ function( result ) {
+ ok( result.hashchange.timedOut, "Opening a popup from a dialogHashKey location does not cause a hashchange" );
+ ok( baseUrl === location.href, "Opening a popup from a dialogHashKey location does not cause the location to be modified" );
+ ok( activeIndex === $.mobile.urlHistory.activeIndex, "Opening a popup from a dialogHashKey location does not cause $.mobile.urlHistory to move" );
+ $( "#test-popup" ).popup( "close" );
+ },
+
+ {
+ closed: { src: $( "#test-popup" ), event: "closed.reuseStep5" },
+ hashchange: { src: $( window ), event: "hashchange.reuseStep5" }
+ },
+
+ function( result ) {
+ ok( !result.hashchange.timedOut, "Closing a popup from a dialogHashKey location causes a hashchange" );
+ setTimeout( function() { start(); }, 300 );
+ }
+ ]);
+ });
+
+ // This test assumes that the popup opens into a state that does not include dialogHashKey.
+ // This should be the case if the previous test has cleaned up correctly.
+ asyncTest( "Opening another page from the popup leaves no trace of the popup in history", function() {
+ var initialActive = $.extend( {}, {}, $.mobile.urlHistory.getActive()),
+ initialHRef = $.mobile.path.parseUrl( location.href ),
+ initialBase = initialHRef.protocol + initialHRef.doubleSlash + initialHRef.authority + initialHRef.directory;
+
+ expect( 6 );
+
+ $.testHelper.detailedEventCascade([
+ function() {
+ $( "#test-popup" ).popup( "open" );
+ },
+
+ {
+ opened: { src: $( "#test-popup" ), event: "opened.anotherPageStep1" },
+ hashchange: { src: $( window ), event: "hashchange.anotherPageStep1" }
+ },
+
+ function() {
+ $( "#test-popup a" ).click();
+ },
+
+ {
+ closed: { src: $( "#test-popup" ), event: "closed.anotherPageStep2" },
+ hashchange: { src: $( window ), event: "hashchange.anotherPageStep2" }
+ },
+
+ function( result ) {
+ var hRef = $.mobile.path.parseUrl( location.href );
+ ok( !result.closed.timedOut, "Popup closed" );
+ ok( !result.hashchange.timedOut, "hashchange did occur" );
+ ok( location.href === initialBase + hRef.filename, "New location is exactly the previous location (up to and including path) and the new filename" );
+ window.history.back();
+ },
+
+ {
+ hashchange: { src: $( window ), event: "hashchange.anotherPageStep3" },
+ pagechange: { src: $.mobile.pageContainer, event: "pagechange.anotherPageStep3" }
+ },
+
+ function( result ) {
+ var active = $.mobile.urlHistory.getActive(),
+ identical = true;
+
+ $.each( initialActive, function( key, value ) {
+ if ( active[key] !== value ) {
+ identical = false;
+ return false;
+ }
+ });
+
+ if ( identical ) {
+ $.each( active, function( key, value ) {
+ if ( initialActive[key] !== value ) {
+ identical = false;
+ return false;
+ }
+ });
+ }
+
+ ok( location.href === initialHRef.href, "Going back once places the browser on the initial page" );
+ ok( identical, "Going back returns $.mobile.urlHistory to its initial value" );
+ ok( $.mobile.urlHistory.activeIndex === $.mobile.urlHistory.stack.length - 3, "Going back leaves exactly two entries ahead in $.mobile.urlHistory" );
+
+ setTimeout( function() { start(); }, 300 );
+ },
+
+ ]);
+ });
+
+ asyncTest( "Opening and closing a closed popup in quick succession does not move the browser elsewhere in history", function() {
+ var initialHRef = location.href;
+
+ expect( 5 );
+
+ $.testHelper.detailedEventCascade([
+ function() {
+ $( "#test-popup" ).popup( "open" ); $( "#test-popup" ).popup( "close" );
+ },
+
+ {
+ opened: { src: $( "#test-popup" ), event: "opened.openCloseQuickStep1" },
+ closed: { src: $( "#test-popup" ), event: "closed.openCloseQuickStep1" },
+ hashchange1: { src: $( window ), event: "hashchange.openCloseQuickStep1a" },
+ hashchange2: { src: $( window ), event: "hashchange.openCloseQuickStep1b" },
+ timeout: { src: null, length: 600 }
+ },
+
+ function( result ) {
+ ok( !result.opened.timedOut, "'opened' signal arrived" );
+ ok( !result.closed.timedOut, "'closed' signal arrived" );
+ ok( !( result.hashchange1.timedOut || result.hashchange1.timedOut ), "Two 'hashchange' signals arrived" );
+ ok( location.href === initialHRef, "Location did not change" );
+ ok( result.opened.idx < result.closed.idx, "'opened' signal arrived before 'closed' signal" );
+ setTimeout( function() { start(); }, 300 );
+ }
+ ]);
+ });
+
+ asyncTest( "Closing and opening an open popup in quick succession does not move the browser elsewhere in history", function() {
+ var initialHRef, origHRef = location.href;
+
+ expect( 8 );
+
+ $.testHelper.detailedEventCascade([
+ function() {
+ $( "#test-popup" ).popup( "open" );
+ },
+
+ {
+ opened: { src: $( "#test-popup" ), event: "opened.closeOpenQuickStep1" },
+ hashchange: { src: $( window ), event: "hashchange.closeOpenQuickStep1" }
+ },
+
+ function() {
+ initialHRef = location.href;
+ $( "#test-popup" ).popup( "close" ); $( "#test-popup" ).popup( "open" );
+ },
+
+ {
+ opened: { src: $( "#test-popup" ), event: "opened.closeOpenQuickStep2" },
+ closed: { src: $( "#test-popup" ), event: "closed.closeOpenQuickStep2" },
+ hashchange: { src: $( window ), event: "hashchange.closeOpenQuickStep2" }
+ },
+
+ function( result ) {
+ ok( !result.opened.timedOut, "'opened' signal arrived" );
+ ok( !result.closed.timedOut, "'closed' signal arrived" );
+ ok( result.hashchange.timedOut, "No 'hashchange' signals arrived" );
+ ok( location.href === initialHRef, "Location did not change" );
+ ok( result.closed.idx < result.opened.idx, "'closed' signal arrived before 'opened' signal" );
+ $( "#test-popup" ).popup( "close" );
+ },
+
+ {
+ closed: { src: $( "#test-popup" ), event: "closed.closeOpenQuickStep3" },
+ hashchange: { src: $( window ), event: "hashchange.closeOpenQuickStep3" }
+ },
+
+ function( result ) {
+ ok( !result.closed.timedOut, "'closed' signal arrived" );
+ ok( !result.hashchange.timedOut, "'hashchnage' signal arrived" );
+ ok( location.href === origHRef, "Location is unchanged" );
+ setTimeout( function() { start(); }, 300 );
+ },
+ ]);
+ });
+
+})( jQuery );
View
48 tests/unit/popup/popup_interaction.js
@@ -0,0 +1,48 @@
+(function($){
+
+ asyncTest( "Opening a second popup causes the first one to close", function() {
+ var initialHRef = location.href;
+
+ expect( 5 );
+
+ $.testHelper.detailedEventCascade([
+ function() {
+ $( "#test-popup" ).popup( "open" );
+ },
+
+ {
+ opened: { src: $( "#test-popup" ), event: "opened.openAnotherStep1" },
+ hashchange: { src: $( window ), event: "hashchange.openAnotherStep1" }
+ },
+
+ function() {
+ $( "#test-popup-2" ).popup( "open" );
+ },
+
+ {
+ hashchange: { src: $( window ), event: "hashchange.openAnotherStep2" },
+ closed: { src: $( "#test-popup" ), event: "closed.openAnotherStep2" },
+ opened: { src: $( "#test-popup-2" ), event: "opened.openAnotherStep2" }
+ },
+
+ function( result ) {
+ ok( result.closed.idx < result.opened.idx && result.closed.idx !== -1, "'closed' signal arrived before 'opened' signal" );
+ ok( result.hashchange.timedOut, "There were no hashchange events" );
+ $( "#test-popup-2" ).popup( "close" );
+ },
+
+ {
+ closed: { src: $( "#test-popup-2" ), event: "closed.openAnotherStep3" },
+ hashchange: { src: $( window ), event: "hashchange.openAnotherStep3" }
+ },
+
+ function( result ) {
+ ok( !result.closed.timedOut, "'closed' signal was received" );
+ ok( !result.hashchange.timedOut, "'hashchange' signal was received" );
+ ok( initialHRef === location.href, "location is unchanged" );
+ start();
+ }
+ ]);
+ });
+
+})( jQuery );
Please sign in to comment.
Something went wrong with that request. Please try again.