2012-07-14 17:38:02 +02:00
/ * *
2013-04-13 21:00:13 +02:00
* EGroupware eTemplate2 - JS Itempicker object
2012-07-14 17:38:02 +02:00
* derived from et2 _link _entry widget @ copyright 2011 Nathan Gray
*
* @ license http : //opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @ package etemplate
* @ subpackage api
* @ link http : //www.egroupware.org
* @ author Christian Binder
* @ author Nathan Gray
* @ copyright 2012 Christian Binder
* @ copyright 2011 Nathan Gray
* @ version $Id : et2 _widget _itempicker . js 38623 2012 - 03 - 26 23 : 27 : 53 Z jaytraxx $
* /
/ * e g w : u s e s
2016-06-06 17:38:20 +02:00
/ v e n d o r / b o w e r - a s s e t / j q u e r y / d i s t / j q u e r y . j s ;
2012-07-14 17:38:02 +02:00
et2 _core _inputWidget ;
et2 _core _valueWidget ;
2012-09-29 12:23:03 +02:00
et2 _extension _itempicker _actions ;
2012-08-25 14:58:28 +02:00
egw _action . egw _action _common ;
2012-07-14 17:38:02 +02:00
* /
/ * *
* Class which implements the "itempicker" XET - Tag
2016-02-29 21:40:43 +01:00
*
2013-04-13 21:00:13 +02:00
* @ augments et2 _inputWidget
2016-02-29 21:40:43 +01:00
* /
var et2 _itempicker = ( function ( ) { "use strict" ; return et2 _inputWidget . extend (
2013-04-13 21:00:13 +02:00
{
2012-07-14 17:38:02 +02:00
attributes : {
2012-08-25 14:58:28 +02:00
"action" : {
"name" : "Action callback" ,
"type" : "string" ,
"default" : false ,
"description" : "Callback for action. Must be a function(context, data)"
} ,
2012-08-02 22:53:37 +02:00
"action_label" : {
"name" : "Action label" ,
"type" : "string" ,
"default" : "Action" ,
"description" : "Label for action button"
} ,
2012-07-14 17:38:02 +02:00
"application" : {
"name" : "Application" ,
"type" : "string" ,
"default" : "" ,
2012-08-02 22:39:39 +02:00
"description" : "Limit to the listed application or applications (comma separated)"
2012-07-14 17:38:02 +02:00
} ,
"blur" : {
"name" : "Placeholder" ,
"type" : "string" ,
"default" : et2 _no _init ,
"description" : "This text get displayed if an input-field is empty and does not have the input-focus (blur). It can be used to show a default value or a kind of help-text."
} ,
2012-09-29 12:23:03 +02:00
"value" : {
"name" : "value" ,
"type" : "any" ,
"default" : "" ,
"description" : "Optional itempicker value(s) - can be used for e.g. environmental information"
} ,
2012-07-14 17:38:02 +02:00
"query" : {
"name" : "Query callback" ,
"type" : "any" ,
"default" : false ,
"description" : "Callback before query to server. Must return true, or false to abort query."
2016-02-29 21:40:43 +01:00
}
2012-07-14 17:38:02 +02:00
} ,
legacyOptions : [ "application" ] ,
search _timeout : 200 , //ms after change to send query
minimum _characters : 2 , // Don't send query unless there's at least this many chars
2012-07-21 12:50:04 +02:00
last _search : "" , // Remember last search value
2012-08-25 14:58:28 +02:00
action : null , // Action function for button
2012-07-21 12:50:04 +02:00
current _app : "" , // Remember currently chosen application
2012-07-14 17:38:02 +02:00
2013-04-13 21:00:13 +02:00
/ * *
* Constructor
2016-02-29 21:40:43 +01:00
*
2013-04-13 21:00:13 +02:00
* @ memberOf et2 _itempicker
* /
2012-07-14 17:38:02 +02:00
init : function ( ) {
this . _super . apply ( this , arguments ) ;
this . div = null ;
this . left = null ;
this . right = null ;
2012-07-21 12:50:04 +02:00
this . right _container = null ;
2012-07-14 17:38:02 +02:00
this . app _select = null ;
this . search = null ;
2012-07-28 13:56:06 +02:00
this . button _action = null ;
2012-07-14 17:38:02 +02:00
this . itemlist = null ;
2016-02-29 21:40:43 +01:00
2012-08-25 14:58:28 +02:00
if ( this . options . action !== null && typeof this . options . action == "string" )
{
this . action = new egwFnct ( this , "javaScript:" + this . options . action ) ;
}
else
{
console . log ( "itempicker widget: no action provided for button" ) ;
}
2012-07-14 17:38:02 +02:00
this . createInputWidget ( ) ;
} ,
2016-02-29 21:40:43 +01:00
2012-07-28 13:56:06 +02:00
clearSearchResults : function ( ) {
this . search . val ( "" ) ;
this . itemlist . html ( "" ) ;
this . search . focus ( ) ;
this . clear . hide ( ) ;
} ,
2012-07-14 17:38:02 +02:00
createInputWidget : function ( ) {
2012-07-21 12:50:04 +02:00
var _self = this ;
2016-02-29 21:40:43 +01:00
2016-06-02 16:51:15 +02:00
this . div = jQuery ( document . createElement ( "div" ) ) ;
this . left = jQuery ( document . createElement ( "div" ) ) ;
this . right = jQuery ( document . createElement ( "div" ) ) ;
this . right _container = jQuery ( document . createElement ( "div" ) ) ;
this . app _select = jQuery ( document . createElement ( "ul" ) ) ;
this . search = jQuery ( document . createElement ( "input" ) ) ;
this . clear = jQuery ( document . createElement ( "span" ) ) ;
this . itemlist = jQuery ( document . createElement ( "div" ) ) ;
2016-02-29 21:40:43 +01:00
2012-07-14 17:38:02 +02:00
// Container elements
this . div . addClass ( "et2_itempicker" ) ;
this . left . addClass ( "et2_itempicker_left" ) ;
this . right . addClass ( "et2_itempicker_right" ) ;
2012-07-21 12:50:04 +02:00
this . right _container . addClass ( "et2_itempicker_right_container" ) ;
2016-02-29 21:40:43 +01:00
2012-07-14 17:38:02 +02:00
// Application select
this . app _select . addClass ( "et2_itempicker_app_select" ) ;
var item _count = 0 ;
for ( var key in this . options . select _options ) {
var img _icon = this . egw ( ) . image ( key + "/navbar" ) ;
if ( img _icon === null ) {
continue ;
}
2016-06-02 16:51:15 +02:00
var img = jQuery ( document . createElement ( "img" ) ) ;
2012-07-14 17:38:02 +02:00
img . attr ( "src" , img _icon ) ;
2016-06-02 16:51:15 +02:00
var item = jQuery ( document . createElement ( "li" ) ) ;
2012-07-14 17:38:02 +02:00
item . attr ( "id" , key )
2012-07-28 13:56:06 +02:00
. click ( function ( ) {
2016-06-02 16:51:15 +02:00
_self . selectApplication ( jQuery ( this ) ) ;
2012-07-14 17:38:02 +02:00
} )
. append ( img ) ;
if ( item _count == 0 ) {
2012-08-25 14:58:28 +02:00
this . selectApplication ( item ) ; // select first item by default
2012-07-14 17:38:02 +02:00
}
this . app _select . append ( item ) ;
item _count ++ ;
}
2016-02-29 21:40:43 +01:00
2012-07-14 17:38:02 +02:00
// Search input field
this . search . addClass ( "et2_itempicker_search" ) ;
2012-07-21 12:50:04 +02:00
this . search . keyup ( function ( ) {
var request = { } ;
2016-06-02 16:51:15 +02:00
request . term = jQuery ( this ) . val ( ) ;
2012-07-21 12:50:04 +02:00
_self . query ( request ) ;
} ) ;
2012-08-02 22:39:39 +02:00
this . set _blur ( this . options . blur , this . search ) ;
2016-02-29 21:40:43 +01:00
2012-07-21 12:50:04 +02:00
// Clear button for search
this . clear
2012-07-28 13:56:06 +02:00
. addClass ( "et2_itempicker_clear ui-icon ui-icon-close" )
2012-07-21 12:50:04 +02:00
. click ( function ( e ) {
2012-07-28 13:56:06 +02:00
_self . clearSearchResults ( ) ;
2012-07-21 12:50:04 +02:00
} )
. hide ( ) ;
2016-02-29 21:40:43 +01:00
2012-07-28 13:56:06 +02:00
// Action button
this . button _action = et2 _createWidget ( "button" ) ;
2016-06-02 16:51:15 +02:00
jQuery ( this . button _action . getDOMNode ( ) ) . addClass ( "et2_itempicker_button_action" ) ;
2012-08-02 22:53:37 +02:00
this . button _action . set _label ( this . egw ( ) . lang ( this . options . action _label ) ) ;
2012-08-25 14:58:28 +02:00
this . button _action . click = function ( ) { _self . doAction ( ) ; } ;
2016-02-29 21:40:43 +01:00
2012-07-14 17:38:02 +02:00
// Itemlist
this . itemlist . attr ( "id" , "itempicker_itemlist" ) ;
this . itemlist . addClass ( "et2_itempicker_itemlist" ) ;
2016-02-29 21:40:43 +01:00
2012-07-14 17:38:02 +02:00
// Put everything together
this . left . append ( this . app _select ) ;
2012-07-21 12:50:04 +02:00
this . right _container . append ( this . search ) ;
this . right _container . append ( this . clear ) ;
2012-07-28 13:56:06 +02:00
this . right _container . append ( this . button _action . getDOMNode ( ) ) ;
2012-07-21 12:50:04 +02:00
this . right _container . append ( this . itemlist ) ;
this . right . append ( this . right _container ) ;
2016-02-29 21:40:43 +01:00
this . div . append ( this . right ) ; // right before left to have a natural
2012-07-14 17:38:02 +02:00
this . div . append ( this . left ) ; // z-index for left div over right div
this . setDOMNode ( this . div [ 0 ] ) ;
} ,
2016-02-29 21:40:43 +01:00
2012-08-25 14:58:28 +02:00
doAction : function ( )
2012-07-14 17:38:02 +02:00
{
2012-08-25 14:58:28 +02:00
if ( this . action !== null )
{
var data = { } ;
data . app = this . current _app ;
2012-09-29 12:23:03 +02:00
data . value = this . options . value ;
data . checked = this . getSelectedItems ( ) ;
2012-08-25 14:58:28 +02:00
return this . action . exec ( this , data ) ;
}
2016-02-29 21:40:43 +01:00
2012-08-25 14:58:28 +02:00
return false ;
} ,
2016-02-29 21:40:43 +01:00
2012-08-25 14:58:28 +02:00
getSelectedItems : function ( )
{
2012-09-29 12:23:03 +02:00
var items = [ ] ;
2016-06-02 16:51:15 +02:00
jQuery ( this . itemlist ) . children ( "ul" ) . children ( "li.selected" ) . each ( function ( index ) {
items [ index ] = jQuery ( this ) . attr ( "id" ) ;
2012-08-25 14:58:28 +02:00
} ) ;
return items ;
2012-07-14 17:38:02 +02:00
} ,
2016-02-29 21:40:43 +01:00
2012-07-21 12:50:04 +02:00
/ * *
* Ask server for entries matching selected app / type and filtered by search string
* /
query : function ( request ) {
if ( request . term . length < 3 ) {
return true ;
}
// Remember last search
this . last _search = request . term ;
// Allow hook / tie in
if ( this . options . query && typeof this . options . query == 'function' )
{
if ( ! this . options . query ( request , response ) ) return false ;
}
//if(request.term in this.cache) {
// return response(this.cache[request.term]);
//}
this . itemlist . addClass ( "loading" ) ;
2012-07-28 13:56:06 +02:00
this . clear . css ( "display" , "inline-block" ) ;
2016-03-19 17:16:59 +01:00
egw . _json ( "EGroupware\\Api\\Etemplate\\Widget\\ItemPicker::ajax_item_search" ,
2012-07-21 12:50:04 +02:00
[ this . current _app , '' , request . term , request . options ] ,
2013-09-10 20:56:50 +02:00
this . queryResults ,
this , true , this
) . sendRequest ( ) ;
2012-07-21 12:50:04 +02:00
} ,
2016-02-29 21:40:43 +01:00
2012-07-21 12:50:04 +02:00
/ * *
2012-08-25 14:58:28 +02:00
* Server found some results for query
2012-07-21 12:50:04 +02:00
* /
2012-08-25 14:58:28 +02:00
queryResults : function ( data ) {
2012-07-21 12:50:04 +02:00
this . itemlist . removeClass ( "loading" ) ;
this . updateItemList ( data ) ;
} ,
2016-02-29 21:40:43 +01:00
2012-08-25 14:58:28 +02:00
selectApplication : function ( app ) {
this . clearSearchResults ( ) ;
2016-06-02 16:51:15 +02:00
jQuery ( ".et2_itempicker_app_select li" ) . removeClass ( "selected" ) ;
2012-08-25 14:58:28 +02:00
app . addClass ( "selected" ) ;
this . current _app = app . attr ( "id" ) ;
return true ;
} ,
2016-02-29 21:40:43 +01:00
2012-08-02 22:39:39 +02:00
set _blur : function ( _value , input ) {
if ( typeof input == 'undefined' ) input = this . search ;
if ( _value ) {
input . attr ( "placeholder" , _value ) ; // HTML5
if ( ! input [ 0 ] . placeholder ) {
// Not HTML5
if ( input . val ( ) == "" ) input . val ( _value ) ;
input . focus ( input , function ( e ) {
var placeholder = _value ;
if ( e . data . val ( ) == placeholder ) e . data . val ( "" ) ;
} ) . blur ( input , function ( e ) {
var placeholder = _value ;
if ( e . data . val ( ) == "" ) e . data . val ( placeholder ) ;
} ) ;
if ( input . val ( ) == "" ) input . val ( _value ) ;
}
} else {
this . search . removeAttr ( "placeholder" ) ;
}
} ,
2016-02-29 21:40:43 +01:00
2012-07-14 17:38:02 +02:00
transformAttributes : function ( _attrs ) {
this . _super . apply ( this , arguments ) ;
_attrs [ "select_options" ] = { } ;
if ( _attrs [ "application" ] )
{
var apps = et2 _csvSplit ( _attrs [ "application" ] , null , "," ) ;
for ( var i = 0 ; i < apps . length ; i ++ )
{
_attrs [ "select_options" ] [ apps [ i ] ] = this . egw ( ) . lang ( apps [ i ] ) ;
}
}
else
{
_attrs [ "select_options" ] = this . egw ( ) . link _app _list ( 'query' ) ;
}
// Check whether the options entry was found, if not read it from the
// content array.
if ( _attrs [ "select_options" ] == null )
{
_attrs [ "select_options" ] = this . getArrayMgr ( 'content' )
2016-02-29 21:40:43 +01:00
. getEntry ( "options-" + this . id ) ;
2012-07-14 17:38:02 +02:00
}
// Default to an empty object
if ( _attrs [ "select_options" ] == null )
{
_attrs [ "select_options" ] = { } ;
}
} ,
2016-02-29 21:40:43 +01:00
2012-07-21 12:50:04 +02:00
updateItemList : function ( data ) {
2016-06-02 16:51:15 +02:00
var list = jQuery ( document . createElement ( "ul" ) ) ;
2012-07-21 12:50:04 +02:00
var item _count = 0 ;
2012-07-22 20:37:17 +02:00
var _self = this ;
2012-07-21 12:50:04 +02:00
for ( var id in data ) {
2016-06-02 16:51:15 +02:00
var item = jQuery ( document . createElement ( "li" ) ) ;
2012-07-21 12:50:04 +02:00
if ( item _count % 2 == 0 ) {
item . addClass ( "row_on" ) ;
} else {
item . addClass ( "row_off" ) ;
}
2012-07-22 20:37:17 +02:00
item . attr ( "id" , id )
. html ( data [ id ] )
. click ( function ( e ) {
if ( e . ctrlKey || e . metaKey ) {
// add to selection
2016-06-02 16:51:15 +02:00
jQuery ( this ) . addClass ( "selected" ) ;
2012-07-22 20:37:17 +02:00
} else if ( e . shiftKey ) {
// select range
2016-06-02 16:51:15 +02:00
var start = jQuery ( this ) . siblings ( ".selected" ) . first ( ) ;
2012-07-22 20:37:17 +02:00
if ( start == 0 ) {
// no start item - cannot select range - select single item
2016-06-02 16:51:15 +02:00
jQuery ( this ) . addClass ( "selected" ) ;
2012-07-22 20:37:17 +02:00
return true ;
}
2016-06-02 16:51:15 +02:00
var end = jQuery ( this ) ;
2012-07-22 20:37:17 +02:00
// swap start and end if start appears after end in dom hierarchy
if ( start . index ( ) > end . index ( ) ) {
var startOld = start ;
start = end ;
end = startOld ;
}
// select start to end
start . addClass ( "selected" ) ;
start . nextUntil ( end ) . addClass ( "selected" ) ;
end . addClass ( "selected" ) ;
} else {
// select single item
2016-06-02 16:51:15 +02:00
jQuery ( this ) . siblings ( ".selected" ) . removeClass ( "selected" ) ;
jQuery ( this ) . addClass ( "selected" ) ;
2012-07-22 20:37:17 +02:00
}
} ) ;
2012-07-21 12:50:04 +02:00
list . append ( item ) ;
item _count ++ ;
}
this . itemlist . html ( list ) ;
}
2012-07-14 17:38:02 +02:00
2016-02-29 21:40:43 +01:00
} ) ; } ) . call ( this ) ;
2012-07-14 17:38:02 +02:00
et2 _register _widget ( et2 _itempicker , [ "itempicker" ] ) ;
2012-08-25 14:58:28 +02:00