2 * jQuery Mobile Widget @VERSION
4 * This software is licensed under the MIT licence (as defined by the OSI at
5 * http://www.opensource.org/licenses/mit-license.php)
7 * ***************************************************************************
8 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
9 * Copyright (c) 2011 by Intel Corporation Ltd.
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:
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
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 * ***************************************************************************
30 * Authors: Gabriel Schulhof <gabriel.schulhof@intel.com>
33 // This widget is implemented in an extremely ugly way. It should derive from $.tizen.popupwindow, but it doesn't
34 // because there's a bug in jquery.ui.widget.js which was fixed in jquery-ui commit
35 // b9153258b0f0edbff49496ed16d2aa93bec07d95. Once a version of jquery-ui containing that commit is released
36 // (probably >= 1.9m5), and jQuery Mobile picks up the widget from there, this widget needs to be rewritten properly.
37 // The problem is that, when a widget inherits from a superclass and declares an object in its prototype identical in key
38 // to one in the superclass, upon calling $.widget the object is overwritten in both the prototype of the superclass and
39 // the prototype of the subclass. The prototype of the superclass should remain unchanged.
41 (function ( $, undefined ) {
42 $.widget( "tizen.ctxpopup", $.tizen.widgetex, {
43 options: $.extend( {}, $.tizen.popupwindow.prototype.options, {
44 initSelector: ":not(:not(" + $.tizen.popupwindow.prototype.options.initSelector + ")):not(:not(:jqmData(show-arrow='true'), :jqmData(show-arrow)))"
50 container : "#container", // the key has to have the name "container"
52 all : ":jqmData(role='triangle')",
61 _create: function () {
62 if ( !this.element.data( "popupwindow" ) ) {
63 this.element.popupwindow();
66 this.element.data( "popupwindow" )
68 .removeClass( "ui-popupwindow-padding" )
69 .append( this._ui.outer );
70 this._ui.outer.trigger( "create" ); // Creates the triangle widgets
72 .addClass( "ui-popupwindow-padding" )
73 .append( this.element );
76 _setOption: function ( key, value ) {
77 $.tizen.popupwindow.prototype._setOption.apply( this.element.data( "popupwindow" ), arguments );
78 this.options[key] = value;
82 var origOpen = $.tizen.popupwindow.prototype.open,
83 orig_setOption = $.tizen.popupwindow.prototype._setOption,
84 orig_placementCoords = $.tizen.popupwindow.prototype._placementCoords;
86 $.tizen.popupwindow.prototype._setOption = function ( key, value ) {
87 var ctxpopup = this.element.data( "ctxpopup" ),
91 if ( "shadow" === key || "overlayTheme" === key || "corners" === key ) {
92 origContainer = this._ui.container;
94 this._ui.container = ctxpopup._ui.container;
95 orig_setOption.apply( this, arguments );
96 this._ui.container = origContainer;
97 needsApplying = false;
99 ctxpopup.options[key] = value;
102 if ( needsApplying ) {
103 orig_setOption.apply(this, arguments);
107 $.tizen.popupwindow.prototype._placementCoords = function ( x, y, cx, cy ) {
108 var ctxpopup = this.element.data( "ctxpopup" ),
114 function getCoords( arrow, x_factor, y_factor ) {
115 // Unhide the arrow we want to test to take it into account
116 ctxpopup._ui.arrow.all.hide();
117 ctxpopup._ui.arrow[arrow].show();
119 var isHorizontal = ( "b" === arrow || "t" === arrow ),
120 // Names of keys used in calculations depend on whether things are horizontal or not
121 coord = ( isHorizontal
122 ? { point: "x", size: "cx", beg: "left", outerSize: "outerWidth", niceSize: "width", triangleSize : "height" }
123 : { point: "y", size: "cy", beg: "top", outerSize: "outerHeight", niceSize: "height", triangleSize : "width" } ),
125 cx : self._ui.container.width(),
126 cy : self._ui.container.height()
133 "x" : x + halfSize.cx * x_factor,
134 "y" : y + halfSize.cy * y_factor
136 orig = orig_placementCoords.call( self, desired.x, desired.y, size.cx, size.cy ),
138 // The triangleOffset must be clamped to the range described below:
143 // ----+--+-,-----...
144 //lowerDiff -->____| |/ <-- possible rounded corner
145 //triangle size --> | /|
147 // ^ |\ | <-- lowest possible offset for triangle
148 // actual range of | | \|
149 // arrow offset | | |
150 // values due to | . . Payload table cell looks like
151 // possible rounded | . . a popup window, and it may have
152 // corners and arrow | . . arbitrary things like borders,
153 // triangle size - | | | shadows, and rounded corners.
154 // our clamp range | | /|
156 //triangle size --> |\ | <-- highest possible offset for triangle
158 //upperDiff --> | |\ <-- possible rounded corner
159 // ----+--+-'-----...
164 // We calculate lowerDiff and upperDiff by considering the offset and width of the payload (this.element)
165 // versus the offset and width of the element enclosing the triangle, because the payload is inside
166 // whatever decorations (such as borders, shadow, rounded corners) and thus can give a reliable indication
167 // of the thickness of the combined decorations
169 arrowBeg = ctxpopup._ui.arrow[arrow].offset()[coord.beg],
170 arrowSize = ctxpopup._ui.arrow[arrow][coord.outerSize]( true ),
171 payloadBeg = self.element.offset()[coord.beg],
172 payloadSize = self.element[coord.outerSize]( true ),
173 triangleSize = ctxpopup._ui.arrow[arrow][coord.triangleSize](),
176 triangleSize // triangle size
177 + Math.max( 0, payloadBeg - arrowBeg ), // lowerDiff
180 - triangleSize // triangle size
181 - Math.max( 0, arrowBeg + arrowSize - ( payloadBeg + payloadSize ) ), // upperDiff
182 arrowSize / 2 // arrow unrestricted offset
183 + desired[coord.point]
185 - halfSize[coord.size]
188 // Triangle points here
190 "x": orig.x + ( isHorizontal ? triangleOffset : 0) + ("r" === arrow ? size.cx : 0),
191 "y": orig.y + (!isHorizontal ? triangleOffset : 0) + ("b" === arrow ? size.cy : 0)
195 triangleOffset : triangleOffset,
196 absDiff : Math.abs( x - final.x ) + Math.abs( y - final.y )
200 ctxpopup._ui.arrow[arrow].hide();
209 // triangleOffset: int
210 // actual: { x: int, y: int }
214 l : getCoords( "l", 1, 0 ),
215 r : getCoords( "r", -1, 0 ),
216 t : getCoords( "t", 0, 1 ),
217 b : getCoords( "b", 0, -1 )
220 $.each( coords, function ( key, value ) {
221 if ( minDiff === undefined || value.absDiff < minDiff ) {
222 minDiff = value.absDiff;
227 // Side-effect: show the appropriate arrow and move it to the right offset
228 ctxpopup._ui.arrow[minDiffIdx]
230 .triangle( "option", "offset", coords[minDiffIdx].triangleOffset );
231 return coords[minDiffIdx].actual;
234 return orig_placementCoords.call( this, x, y, cx, cy );
237 $.tizen.popupwindow.prototype.open = function ( x, y ) {
238 var ctxpopup = this.element.data( "ctxpopup" );
241 this._setShadow( false );
242 this._setCorners( false );
243 this._setOverlayTheme( null );
244 this._setOption( "overlayTheme", ctxpopup.options.overlayTheme );
245 ctxpopup._ui.arrow.all.triangle( "option", "color", ctxpopup._ui.container.css( "background-color" ) );
248 $( '.ui-popupwindow' ).css( 'background', 'none' );
251 origOpen.call( this, x, y );
254 //auto self-init widgets
255 $( document ).bind( "pagecreate create", function ( e ) {
256 var ctxpopups = $( $.tizen.ctxpopup.prototype.options.initSelector, e.target );
257 $.tizen.ctxpopup.prototype.enhanceWithin( e.target );