blob: 3619d8a366e15ed30e78eeba9212fba982ea6efe [file] [log] [blame]
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Shows popup at any place in the page content, with various styles
//>>label: Context popup
//>>group: Tizen:Widgets
define( [
'jquery',
'../jquery.mobile.tizen.core',
'./jquery.mobile.tizen.popupwindow',
'./jquery.mobile.tizen.triangle'
], function ( jQuery ) {
//>>excludeEnd("jqmBuildExclude");
/*
* jQuery Mobile Widget @VERSION
*
* This software is licensed under the MIT licence (as defined by the OSI at
* http://www.opensource.org/licenses/mit-license.php)
*
* ***************************************************************************
* Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
* Copyright (c) 2011 by Intel Corporation Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
* ***************************************************************************
*
* Authors: Gabriel Schulhof <gabriel.schulhof@intel.com>
* Hyunjung Kim <hjnim.kim@samsung.com>
*/
/*
* % ContextPopup widget do not use anymore(will be deprecated, internal use only)
*/
// This widget is implemented in an extremely ugly way. It should derive from $.tizen.popupwindow, but it doesn't
// because there's a bug in jquery.ui.widget.js which was fixed in jquery-ui commit
// b9153258b0f0edbff49496ed16d2aa93bec07d95. Once a version of jquery-ui containing that commit is released
// (probably >= 1.9m5), and jQuery Mobile picks up the widget from there, this widget needs to be rewritten properly.
// The problem is that, when a widget inherits from a superclass and declares an object in its prototype identical in key
// to one in the superclass, upon calling $.widget the object is overwritten in both the prototype of the superclass and
// the prototype of the subclass. The prototype of the superclass should remain unchanged.
/**
class ContextPopup
The context pop-up widget shows a list of options and automatically optimizes its size within the screen. This widget is intended for a small list of options for a larger list, use the List widget. <br/>The context pop-up widget requires a target button, which must be clicked to open the context pop-up. In the default application theme, an arrow pointer is displayed at the top-left corner of the context pop-up widget when it is opened.<br/><br/> To add a context pop-up widget to the application, use the following code:
// Target button
<a href="#pop_3_icons" id="btn_3_icons" data-role="button" data-inline="true" data-rel="popupwindow">3 Icons</a>
// Context pop-up
<div class="horizontal" id="pop_3_icons" data-role="popupwindow" data-show-arrow="true">
<ul>
<li class="icon">
<a href="#" data-role="button" data-icon="call"></a>
</li>
<li class="icon">
<a href="#" data-role="button" data-icon="favorite"></a>
</li>
<li class="text">
<a href="#">Function</a>
</li>
</ul>
</div>
The context pop-up can define callbacks for events as described in the [jQueryMobile documentation for pop-up events.][1]
You can use methods with the context pop-up as described in the [jQueryMobile documentation for pop-up methods.][2]
[1]: http://jquerymobile.com/demos/1.2.0-alpha.1/docs/pages/popup/events.html
[2]: http://jquerymobile.com/demos/1.2.0-alpha.1/docs/pages/popup/methods.html
@deprecated 2.0 verisons
*/
(function ( $, undefined ) {
$.widget( "tizen.ctxpopup", $.tizen.widgetex, {
options: $.extend( {}, $.tizen.popupwindow.prototype.options, {
initSelector: ":jqmData(show-arrow)"
} ),
_htmlProto: {
source:
[ "<div><div id='outer' class='ui-ctxpopup'>" ,
" <div id='top' class='ui-ctxpopup-row' data-role='triangle' data-location='top'></div>" ,
" <div class='ui-ctxpopup-row'>" ,
" <div id='left' class='ui-ctxpopup-cell' data-role='triangle' data-location='left'></div>" ,
" <div id='container' class='ui-ctxpopup-cell'></div>" ,
" <div id='right' class='ui-ctxpopup-cell' data-role='triangle' data-location='right'></div>" ,
" </div>" ,
" <div id='bottom' class='ui-ctxpopup-row' data-role='triangle' data-location='bottom'></div>" ,
"</div>" ,
"</div>" ].join("")
, ui: {
outer : "#outer",
container : "#container", // the key has to have the name "container"
arrow : {
all : ":jqmData(role='triangle')",
l : "#left",
t : "#top",
r : "#right",
b : "#bottom"
}
}
},
_create: function () {
console.warn("ctxpopup() was deprecated. use popup() instead.");
if ( !this.element.data( "popupwindow" ) ) {
this.element.popupwindow();
}
this.element.data( "popupwindow" )
._ui.container
.removeClass( "ui-popupwindow-padding" )
.append( this._ui.outer );
this._ui.outer.trigger( "create" ); // Creates the triangle widgets
this._ui.container
.addClass( "ui-popupwindow-padding" )
.append( this.element );
},
_setOption: function ( key, value ) {
$.tizen.popupwindow.prototype._setOption.apply( this.element.data( "popupwindow" ), arguments );
this.options[key] = value;
}
} );
var origOpen = $.tizen.popupwindow.prototype.open,
orig_setOption = $.tizen.popupwindow.prototype._setOption,
orig_placementCoords = $.tizen.popupwindow.prototype._placementCoords;
$.tizen.popupwindow.prototype._setOption = function ( key, value ) {
var ctxpopup = this.element.data( "ctxpopup" ),
needsApplying = true,
origContainer;
if ( ctxpopup ) {
if ( "shadow" === key || "overlayTheme" === key || "corners" === key ) {
origContainer = this._ui.container;
this._ui.container = ctxpopup._ui.container;
orig_setOption.apply( this, arguments );
this._ui.container = origContainer;
needsApplying = false;
}
ctxpopup.options[key] = value;
}
if ( needsApplying ) {
orig_setOption.apply(this, arguments);
}
};
$.tizen.popupwindow.prototype._placementCoords = function ( x, y, cx, cy ) {
var ctxpopup = this.element.data( "ctxpopup" ),
self = this,
coords = {},
minDiff,
minDiffIdx;
function getCoords( arrow, x_factor, y_factor ) {
// Unhide the arrow we want to test to take it into account
ctxpopup._ui.arrow.all.hide();
ctxpopup._ui.arrow[arrow].show();
var isHorizontal = ( "b" === arrow || "t" === arrow ),
// Names of keys used in calculations depend on whether things are horizontal or not
coord = ( isHorizontal
? { point: "x", size: "cx", beg: "left", outerSize: "outerWidth", niceSize: "width", triangleSize : "height" }
: { point: "y", size: "cy", beg: "top", outerSize: "outerHeight", niceSize: "height", triangleSize : "width" } ),
size = {
cx : self._ui.container.width(),
cy : self._ui.container.height()
},
halfSize = {
cx : size.cx / 2,
cy : size.cy / 2
},
desired = {
"x" : x + halfSize.cx * x_factor,
"y" : y + halfSize.cy * y_factor
},
orig = orig_placementCoords.call( self, desired.x, desired.y, size.cx, size.cy ),
// The triangleOffset must be clamped to the range described below:
//
// +-------...
// | /\
// | / \
// ----+--+-,-----...
//lowerDiff -->____| |/ <-- possible rounded corner
//triangle size --> | /|
// ____|/ |
// ^ |\ | <-- lowest possible offset for triangle
// actual range of | | \|
// arrow offset | | |
// values due to | . . Payload table cell looks like
// possible rounded | . . a popup window, and it may have
// corners and arrow | . . arbitrary things like borders,
// triangle size - | | | shadows, and rounded corners.
// our clamp range | | /|
// _v__|/ |
//triangle size --> |\ | <-- highest possible offset for triangle
// ____| \|
//upperDiff --> | |\ <-- possible rounded corner
// ----+--+-'-----...
// | \ /
// | \/
// +-------...
//
// We calculate lowerDiff and upperDiff by considering the offset and width of the payload (this.element)
// versus the offset and width of the element enclosing the triangle, because the payload is inside
// whatever decorations (such as borders, shadow, rounded corners) and thus can give a reliable indication
// of the thickness of the combined decorations
arrowBeg = ctxpopup._ui.arrow[arrow].offset()[coord.beg],
arrowSize = ctxpopup._ui.arrow[arrow][coord.outerSize]( true ),
payloadBeg = self.element.offset()[coord.beg],
payloadSize = self.element[coord.outerSize]( true ),
triangleSize = ctxpopup._ui.arrow[arrow][coord.triangleSize](),
triangleOffset,
finalposition,
ret;
if (isHorizontal) {
orig.x = 0;
} else {
orig.y = 0;
}
if (arrow == 'b' && self._target_height) {
orig.y -= self._target_height;
}
if (arrow == 'r' && self._target_width) {
orig.x -= self._target_width;
}
triangleOffset =
Math.max(
triangleSize // triangle size
+ Math.max( 0, payloadBeg - arrowBeg ), // lowerDiff
Math.min(
arrowSize // bottom
- triangleSize // triangle size
- Math.max( 0, arrowBeg + arrowSize - ( payloadBeg + payloadSize ) ), // upperDiff
arrowSize / 2 // arrow unrestricted offset
+ desired[coord.point]
- orig[coord.point]
- halfSize[coord.size]
)
);
// Triangle points here
finalposition = {
"x": orig.x + ( isHorizontal ? triangleOffset : 0) + ("r" === arrow ? size.cx : 0),
"y": orig.y + (!isHorizontal ? triangleOffset : 0) + ("b" === arrow ? size.cy : 0)
};
ret = {
actual : orig,
triangleOffset : triangleOffset,
absDiff : Math.abs( x - finalposition.x ) + Math.abs( y - finalposition.y )
};
// Hide it back
ctxpopup._ui.arrow[arrow].hide();
return ret;
}
if ( ctxpopup ) {
// Returns:
// {
// absDiff: int
// triangleOffset: int
// actual: { x: int, y: int }
// }
coords = {
l : getCoords( "l", 1, 0 ),
r : getCoords( "r", -1, 0 ),
t : getCoords( "t", 0, 1 ),
b : getCoords( "b", 0, -1 )
};
$.each( coords, function ( key, value ) {
if ( minDiff === undefined || value.absDiff < minDiff ) {
minDiff = value.absDiff;
minDiffIdx = key;
}
} );
// Side-effect: show the appropriate arrow and move it to the right offset
ctxpopup._ui.arrow[minDiffIdx]
.show()
.triangle( "option", "offset", coords[minDiffIdx].triangleOffset );
this.element.parents( ".ui-popupwindow" ).addClass( "ui-arrow-" + minDiffIdx );
return coords[minDiffIdx].actual;
}
return orig_placementCoords.call( this, x, y, cx, cy );
};
$.tizen.popupwindow.prototype.open = function ( x, y, target_width, target_height ) {
var ctxpopup = this.element.data( "ctxpopup" );
this._target_width = target_width;
this._target_height = target_height;
if ( ctxpopup ) {
this._setFade( false );
this._setShadow( false );
this._setCorners( false );
this._setOverlayTheme( null );
this._setOption( "overlayTheme", ctxpopup.options.overlayTheme );
ctxpopup._ui.arrow.all.triangle( "option", "color", ctxpopup._ui.container.css( "background-color" ) );
// temporary
$( '.ui-popupwindow' ).css( 'background', 'none' );
}
origOpen.call( this, x, y, true );
};
//auto self-init widgets
$( document ).bind( "pagecreate create", function ( e ) {
var ctxpopups = $( $.tizen.ctxpopup.prototype.options.initSelector, e.target );
$.tizen.ctxpopup.prototype.enhanceWithin( e.target );
} );
}( jQuery ) );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
} );
//>>excludeEnd("jqmBuildExclude");