Export 0.1.63
[platform/framework/web/web-ui-fw.git] / src / widgets / popupwindow / js / jquery.mobile.tizen.popupwindow.js
1 /*
2  * jQuery Mobile Widget @VERSION
3  *
4  * This software is licensed under the MIT licence (as defined by the OSI at
5  * http://www.opensource.org/licenses/mit-license.php)
6  *
7  * ***************************************************************************
8  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
9  * Copyright (c) 2011 by Intel Corporation Ltd.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  * ***************************************************************************
29  *
30  * Authors: Gabriel Schulhof <gabriel.schulhof@intel.com>,
31  *          Elliot Smith <elliot.smith@intel.com>
32  */
33
34 /*
35  * Shows other elements inside a popup window.
36  *
37  * To apply, add the attribute data-role="popupwindow" to a <div> element inside
38  * a page. Alternatively, call popupwindow()
39  * on an element, eg :
40  *
41  *     $("#mypopupwindowContent").popupwindow();
42  * where the html might be :
43  *     <div id="mypopupwindowContent"></div>
44  *
45  * To trigger the popupwindow to appear, it is necessary to make a call to its
46  * 'open()' method. This is typically done by binding a function to an event
47  * emitted by an input element, such as a the clicked event emitted by a button
48  * element. The open() method takes two arguments, specifying the x and y
49  * screen coordinates of the center of the popup window.
50
51  * You can associate a button with a popup window like this:
52  *      <div id="mypopupContent" style="display: table;" data-role="popupwindow">
53  *          <table>
54  *              <tr> <td>Eenie</td>   <td>Meenie</td>  <td>Mynie</td>   <td>Mo</td>  </tr>
55  *              <tr> <td>Catch-a</td> <td>Tiger</td>   <td>By-the</td>  <td>Toe</td> </tr>
56  *              <tr> <td>If-he</td>   <td>Hollers</td> <td>Let-him</td> <td>Go</td>  </tr>
57  *              <tr> <td>Eenie</td>   <td>Meenie</td>  <td>Mynie</td>   <td>Mo</td>  </tr>
58  *          </table>
59  *      </div>
60  * <a href="#myPopupContent" data-rel="popupwindow" data-role="button">Show popup</a>
61  *
62  * Options:
63  *
64  *     theme: String; the theme for the popupwindow contents
65  *                   Default: null
66  *
67  *     overlayTheme: String; the theme for the popupwindow
68  *                   Default: null
69  *
70  *     shadow: Boolean; display a shadow around the popupwindow
71  *             Default: true
72  *
73  *     corners: Boolean; display a shadow around the popupwindow
74  *             Default: true
75  *
76  *     fade: Boolean; fades the opening and closing of the popupwindow
77  *
78  *     transition: String; the transition to use when opening or closing
79  *                 a popupwindow
80  *                 Default: $.mobile.defaultDialogTransition
81  *
82  * Events:
83  *      popupbeforeposition: triggered after a popup has completed preparations for opening, but has not yet opened
84  *      popupafteropen: triggered after a popup has completely opened
85  *      popupafterclose triggered when a popup has completely closed
86 */
87
88 /**
89         @class Popup
90         The pop-up widget shows a list of items in a pop-up window in the middle of the screen. It automatically optimizes the pop-up window size within the screen.
91         To add a pop-up widget to the application, use the following code:
92
93                 // Basic pop-up
94                 <div id="center_info" data-role="popup" data-style="center_info">
95                         <div data-role="text">
96                                 <p>
97                                 Pop-up dialog box, a child window that blocks user interaction in the parent window
98                                 </p>
99                         </div>
100                 </div>
101                 // Pop-up with a title and button
102                 <div id="center_title_1btn" data-role="popup" data-style="center_title_1btn">
103                         <p data-role="title">
104                                 Pop-up title
105                         </p>
106                         <p data-role="text">
107                                 Pop-up dialog box
108                         </p>
109                 <div data-role="button-bg">
110                         <input type="button" value="Text Button" />
111                 </div>
112                 </div>
113
114         The pop-up can define callbacks for events as described in the jQueryMobile documentation for pop-up events. <br/>You can use methods with the pop-up as described in the jQueryMobile documentation for pop-up methods.
115 */
116
117 /**
118         @property {String} data-style
119         Defines the pop-up window style.
120         The following styles are available:
121
122         center_info: basic pop-up message
123         center_title: pop-up message with a title
124         center_basic_1btn: pop-up message with 1 button
125         center_basic_2btn: pop-up message with 2 horizontal buttons
126         center_title_1btn: pop-up message with a title and 1 button
127         center_title_2btn: pop-up message with a title and 2 horizontal buttons
128         center_title_3btn: pop-up message with a title and 3 horizontal buttons
129         center_button_vertical: pop-up message with vertical buttons
130         center_checkbox: pop-up message with a check box
131         center_liststyle_1btn>: pop-up message with a list and 1 button
132         center_liststyle_2btn: pop-up message with a list and 2 horizontal buttons
133         center_liststyle_3btn: pop-up message with a list and 3 horizontal buttons
134 */
135
136 (function ( $, undefined ) {
137         $.widget( "tizen.popupwindow", $.tizen.widgetex, {
138                 options: {
139                         theme: null,
140                         overlayTheme: "s",
141                         style: "custom",
142                         disabled: false,
143                         shadow: true,
144                         corners: true,
145                         fade: false,
146                         opacity: 0.7,
147                         widthRatio: 0.8612,
148                         transition: $.mobile.defaultDialogTransition,
149                         initSelector: ":jqmData(role='popupwindow')"
150                 },
151
152                 _htmlProto: {
153                         ui: {
154                                 screen: "#popupwindow-screen",
155                                 container: "#popupwindow-container"
156                         }
157                 },
158
159                 _setStyle: function () {
160                         var popup = this.element,
161                                 style = popup.attr( 'data-style' );
162
163                         if ( style ) {
164                                 this.options.style = style;
165                         }
166
167                         popup.addClass( this.options.style );
168                         popup.find( ":jqmData(role='title')" )
169                                         .wrapAll( "<div class='popup-title'></div>" );
170                         popup.find( ":jqmData(role='text')" )
171                                         .wrapAll( "<div class='popup-text'></div>" );
172                         popup.find( ":jqmData(role='button-bg')" )
173                                         .wrapAll( "<div class='popup-button-bg'></div>" );
174                         popup.find( ":jqmData(role='check-bg')" )
175                                         .wrapAll( "<div class='popup-check-bg'></div>" );
176                         popup.find( ":jqmData(role='scroller-bg')" )
177                                         .addClass( "popup-scroller-bg" );
178                         popup.find( ":jqmData(role='text-bottom-bg')" )
179                                         .wrapAll( "<div class='popup-text-bottom-bg'></div>" );
180                         popup.find( ":jqmData(role='text-left')" )
181                                         .wrapAll( "<div class='popup-text-left'></div>" );
182                         popup.find( ":jqmData(role='text-right')" )
183                                         .wrapAll( "<div class='popup-text-right'></div>" );
184                         popup.find( ":jqmData(role='progress-bg')" )
185                                         .wrapAll( "<div class='popup-progress-bg'></div>" );
186                 },
187
188                 _create: function () {
189                         console.warn("popupwindow() was deprecated. use popup() instead.");
190                         var thisPage = this.element.closest(":jqmData(role='page')"),
191                                 self = this;
192
193                         if ( thisPage.length === 0 ) {
194                                 thisPage = $("body");
195                         }
196
197                         this._ui.placeholder =
198                                         $( "<div><!-- placeholder for " + this.element.attr("id") + " --></div>" )
199                                         .css("display", "none")
200                                         .insertBefore( this.element );
201
202                         thisPage.append( this._ui.screen );
203                         this._ui.container.insertAfter( this._ui.screen );
204                         this._ui.container.append( this.element );
205
206                         this._setStyle();
207
208                         this._isOpen = false;
209
210                         this._ui.screen.bind( "vclick", function ( e ) {
211                                 self.close();
212                                 return false;
213                         } );
214
215                         this.element.bind( "vclick", function( e ) {
216                                 if ( $( e.target ).is("ui-btn-ctxpopup-close") ) {
217                                         self.close();
218                                 }
219                         } );
220                 },
221
222                 destroy: function () {
223                         this.element.insertBefore( this._ui.placeholder );
224
225                         this._ui.placeholder.remove();
226                         this._ui.container.remove();
227                         this._ui.screen.remove();
228                         this.element.triggerHandler("destroyed");
229                         $.Widget.prototype.destroy.call( this );
230                 },
231
232                 _placementCoords: function ( x, y, cw, ch ) {
233                         var screenHeight = $( window ).height(),
234                                 screenWidth = $( window ).width(),
235                                 halfheight = ch / 2,
236                                 maxwidth = parseFloat( this._ui.container.css( "max-width" ) ),
237                                 roomtop = y,
238                                 roombot = screenHeight - y,
239                                 newtop,
240                                 newleft;
241
242                         if ( roomtop > ch / 2 && roombot > ch / 2 ) {
243                                 newtop = y - halfheight;
244                         } else {
245                                 newtop = roomtop > roombot ? screenHeight - ch - 30 : 30;
246                         }
247
248                         if ( cw < maxwidth ) {
249                                 newleft = ( screenWidth - cw ) / 2;
250                         } else {
251                                 newleft = x - cw / 2;
252
253                                 if ( newleft < 10 ) {
254                                         newleft = 10;
255                                 } else if ( ( newleft + cw ) > screenWidth ) {
256                                         newleft = screenWidth - cw - 10;
257                                 }
258                         }
259
260                         return { x : newleft, y : newtop };
261                 },
262
263                 _setPosition: function ( x_where, y_where ) {
264                         var x = ( undefined === x_where ? $( window ).width()  / 2 : x_where ),
265                                 y = ( undefined === y_where ? $( window ).height() / 2 : y_where ),
266                                 coords,
267                                 ctxpopup = this.element.data("ctxpopup"),
268                                 popupWidth,
269                                 menuHeight,
270                                 menuWidth,
271                                 screenHeight,
272                                 screenWidth,
273                                 roomtop,
274                                 roombot,
275                                 halfheight,
276                                 maxwidth,
277                                 newtop,
278                                 newleft;
279
280                         if ( !ctxpopup ) {
281                                 popupWidth = $( window ).width() * this.options.widthRatio;
282                                 this._ui.container.css( "width", popupWidth );
283
284                                 if ( this._ui.container.outerWidth() > $( window ).width() ) {
285                                         this._ui.container.css( {"max-width" : $( window ).width() - 30} );
286                                 }
287                         }
288
289                         coords = this._placementCoords( x, y,
290                                         this._ui.container.outerWidth(),
291                                         this._ui.container.outerHeight() );
292
293                         menuHeight = this._ui.container.innerHeight();
294                         menuWidth = this._ui.container.innerWidth();
295                         screenHeight = $( window ).height();
296                         screenWidth = $( window ).width();
297                         roomtop = y;
298                         roombot = screenHeight - y;
299                         halfheight = menuHeight / 2;
300                         maxwidth = parseFloat( this._ui.container.css( "max-width" ) );
301                         newtop = ( screenHeight - menuHeight ) / 2;
302
303                         if ( !maxwidth || menuWidth < maxwidth ) {
304                                 newleft = ( screenWidth - menuWidth ) / 2;
305                         } else {
306                                 newleft = x - menuWidth / 2;
307
308                                 if ( newleft < 30 ) {
309                                         newleft = 30;
310                                 } else if ( ( newleft + menuWidth ) > screenWidth ) {
311                                         newleft = screenWidth - menuWidth - 30;
312                                 }
313                         }
314
315                         if ( ctxpopup ) {
316                                 newtop = coords.y;
317                                 newleft = coords.x;
318                         }
319
320                         this._ui.container.css({
321                                 top: newtop,
322                                 left: newleft
323                         });
324
325                         this._ui.screen.css( "height", screenHeight );
326                 },
327                 open: function ( x_where, y_where, backgroundclose ) {
328                         var self = this,
329                                 zIndexMax = 0;
330
331                         if ( this._isOpen || this.options.disabled ) {
332                                 return;
333                         }
334
335                         $( document ).find("*").each( function () {
336                                 var el = $( this ),
337                                         zIndex = parseInt( el.css("z-index"), 10 );
338
339                                 if ( !( el.is( self._ui.container ) ||
340                                                 el.is( self._ui.screen ) ||
341                                                 isNaN( zIndex ))) {
342                                         zIndexMax = Math.max( zIndexMax, zIndex );
343                                 }
344                         } );
345
346                         this._ui.screen.css( "height", $( window ).height() );
347
348                         if( backgroundclose ) {
349                                 this._ui.screen.css( "opacity", 0 )
350                                                 .removeClass("ui-screen-hidden");
351                         } else {
352                                 this._ui.removeClass("ui-screen-hidden");
353
354                                 if ( this.options.fade ) {
355                                         this._ui.screen.animate( {opacity: this.options.opacity}, "fast" );
356                                 } else {
357                                         this._ui.screen.css( {opacity: this.options.opacity} );
358                                 }
359                         }
360
361                         this._setPosition( x_where, y_where );
362
363                         this.element.trigger("popupbeforeposition");
364
365                         this._ui.container
366                                 .removeClass("ui-selectmenu-hidden")
367                                 .addClass("in")
368                                 .animationComplete( function () {
369                                         self.element.trigger("popupafteropen");
370                                 } );
371
372                         this._isOpen = true;
373
374                         if ( !this._reflow ) {
375                                 this._reflow = function () {
376                                         if ( !self._isOpen ) {
377                                                 return;
378                                         }
379
380                                         self._setPosition( x_where, y_where );
381                                 };
382
383                                 $( window ).bind( "resize", this._reflow );
384                         }
385                 },
386
387                 close: function () {
388                         if ( !this._isOpen ) {
389                                 return;
390                         }
391
392                         if ( this._reflow ) {
393                                 $( window ).unbind( "resize", this._reflow );
394                                 this._reflow = null;
395                         }
396
397                         var self = this,
398                                 hideScreen = function () {
399                                         self._ui.screen.addClass("ui-screen-hidden");
400                                         self._isOpen = false;
401                                 };
402
403                         this._ui.container.removeClass("in").addClass("reverse out");
404
405                         if ( this.options.transition === "none" ) {
406                                 this._ui.container
407                                         .addClass("ui-selectmenu-hidden")
408                                         .removeAttr("style");
409                                 this.element.trigger("popupafterclose");
410                         } else {
411                                 this._ui.container.animationComplete( function () {
412                                         self._ui.container
413                                                 .removeClass("reverse out")
414                                                 .addClass("ui-selectmenu-hidden")
415                                                 .removeAttr("style");
416                                         self.element.trigger("popupafterclose");
417                                 } );
418                         }
419
420                         if ( this.options.fade ) {
421                                 this._ui.screen.animate( {opacity: 0}, "fast", hideScreen );
422                         } else {
423                                 hideScreen();
424                         }
425                 },
426
427                 _realSetTheme: function ( dst, theme ) {
428                         var classes = ( dst.attr("class") || "" ).split(" "),
429                                 alreadyAdded = true,
430                                 currentTheme = null,
431                                 matches;
432
433                         while ( classes.length > 0 ) {
434                                 currentTheme = classes.pop();
435                                 matches = currentTheme.match(/^ui-body-([a-z])$/);
436
437                                 if ( matches && matches.length > 1 ) {
438                                         currentTheme = matches[1];
439                                         break;
440                                 } else {
441                                         currentTheme = null;
442                                 }
443                         }
444
445                         dst.removeClass( "ui-body-" + currentTheme );
446                         if ( ( theme || "" ).match(/[a-z]/) ) {
447                                 dst.addClass( "ui-body-" + theme );
448                         }
449                 },
450
451                 _setTheme: function ( value ) {
452                         this._realSetTheme( this.element, value );
453                         this.options.theme = value;
454                         this.element.attr( "data-" + ( $.mobile.ns || "" ) + "theme", value );
455                 },
456
457                 _setOverlayTheme: function ( value ) {
458                         this._realSetTheme( this._ui.container, value );
459                         this.options.overlayTheme = value;
460                         this.element.attr( "data-" + ( $.mobile.ns || "" ) + "overlay-theme", value );
461                 },
462
463                 _setShadow: function ( value ) {
464                         this.options.shadow = value;
465                         this.element.attr( "data-" + ( $.mobile.ns || "" ) + "shadow", value );
466                         this._ui.container[value ? "addClass" : "removeClass"]("ui-overlay-shadow");
467                 },
468
469                 _setCorners: function ( value ) {
470                         this.options.corners = value;
471                         this.element.attr( "data-" + ( $.mobile.ns || "" ) + "corners", value );
472                         this._ui.container[value ? "addClass" : "removeClass"]("ui-corner-all");
473                 },
474
475                 _setFade: function ( value ) {
476                         this.options.fade = value;
477                         this.element.attr( "data-" + ( $.mobile.ns || "" ) + "fade", value );
478                 },
479
480                 _setTransition: function ( value ) {
481                         this._ui.container
482                                 .removeClass( this.options.transition || "" )
483                                 .addClass( value );
484                         this.options.transition = value;
485                         this.element.attr( "data-" + ( $.mobile.ns || "" ) + "transition", value );
486                 },
487
488                 _setDisabled: function ( value ) {
489                         $.Widget.prototype._setOption.call( this, "disabled", value );
490                         if ( value ) {
491                                 this.close();
492                         }
493                 }
494         });
495
496         $.tizen.popupwindow.bindPopupToButton = function ( btn, popup ) {
497                 if ( btn.length === 0 || popup.length === 0 ) {
498                         return;
499                 }
500
501                 var btnVClickHandler = function ( e ) {
502                         if ( !popup.jqmData("overlay-theme-set") ) {
503                                 popup.popupwindow( "option", "overlayTheme", btn.jqmData("theme") );
504                         }
505
506                         popup.popupwindow( "open",
507                                 btn.offset().left + btn.outerWidth()  / 2,
508                                 btn.offset().top  + btn.outerHeight() / 2 );
509
510                         return false;
511                 };
512
513                 if ( ( popup.popupwindow("option", "overlayTheme") || "" ).match(/[a-z]/) ) {
514                         popup.jqmData( "overlay-theme-set", true );
515                 }
516
517                 btn
518                         .attr({
519                                 "aria-haspopup": true,
520                                 "aria-owns": btn.attr("href")
521                         })
522                         .removeAttr("href")
523                         .bind( "vclick", btnVClickHandler );
524
525                 popup.bind( "destroyed", function () {
526                         btn.unbind( "vclick", btnVClickHandler );
527                 } );
528         };
529
530         $( document ).bind( "pagecreate create", function ( e ) {
531                 $( $.tizen.popupwindow.prototype.options.initSelector, e.target )
532                         .not(":jqmData(role='none'), :jqmData(role='nojs')")
533                         .popupwindow();
534
535                 $( "a[href^='#']:jqmData(rel='popupwindow')", e.target ).each( function () {
536                         $.tizen.popupwindow.bindPopupToButton( $( this ), $( $( this ).attr("href") ) );
537                 });
538         });
539 }( jQuery ));