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