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
2021-06-07 17:33:53 +02:00
* @ link https : //www.egroupware.org
2012-07-14 17:38:02 +02:00
* @ author Christian Binder
* @ author Nathan Gray
* @ copyright 2012 Christian Binder
* @ copyright 2011 Nathan Gray
* /
/ * e g w : u s e s
2020-02-13 11:08:12 +01: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 ;
et2 _core _inputWidget ;
et2 _core _valueWidget ;
et2 _extension _itempicker _actions ;
egw _action . egw _action _common ;
2012-07-14 17:38:02 +02:00
* /
2021-06-07 17:33:53 +02:00
import { et2 _createWidget , et2 _register _widget } from "./et2_core_widget" ;
import { et2 _inputWidget } from "./et2_core_inputWidget" ;
import { ClassWithAttributes } from "./et2_core_inheritance" ;
import { et2 _csvSplit , et2 _no _init } from "./et2_core_common" ;
import { egw } from "../jsapi/egw_global" ;
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
* /
2021-06-07 17:33:53 +02:00
export class et2 _itempicker extends et2 _inputWidget {
2020-02-13 11:08:12 +01:00
/ * *
* Constructor
*
* @ memberOf et2 _itempicker
* /
2021-06-07 17:33:53 +02:00
constructor ( _parent , _attrs , _child ) {
2020-02-13 11:08:12 +01:00
// Call the inherited constructor
2021-06-07 17:33:53 +02:00
super ( _parent , _attrs , ClassWithAttributes . extendAttributes ( et2 _itempicker . _attributes , _child || { } ) ) ;
this . last _search = "" ; // Remember last search value
this . action = null ; // Action function for button
this . current _app = "" ; // Remember currently chosen application
this . div = null ;
this . left = null ;
this . right = null ;
this . right _container = null ;
this . app _select = null ;
this . search = null ;
this . button _action = null ;
this . itemlist = null ;
this . div = null ;
this . left = null ;
this . right = null ;
this . right _container = null ;
this . app _select = null ;
this . search = null ;
this . button _action = null ;
this . itemlist = null ;
if ( this . options . action !== null && typeof this . options . action == "string" ) {
this . action = new egwFnct ( this , "javaScript:" + this . options . action ) ;
2020-02-13 11:08:12 +01:00
}
else {
console . log ( "itempicker widget: no action provided for button" ) ;
}
2021-06-07 17:33:53 +02:00
this . createInputWidget ( ) ;
2020-02-13 11:08:12 +01:00
}
2021-06-07 17:33:53 +02:00
clearSearchResults ( ) {
2020-02-13 11:08:12 +01:00
this . search . val ( "" ) ;
this . itemlist . html ( "" ) ;
this . search . focus ( ) ;
this . clear . hide ( ) ;
2021-06-07 17:33:53 +02:00
}
createInputWidget ( ) {
let _self = this ;
2020-02-13 11:08:12 +01: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" ) ) ;
// Container elements
this . div . addClass ( "et2_itempicker" ) ;
this . left . addClass ( "et2_itempicker_left" ) ;
this . right . addClass ( "et2_itempicker_right" ) ;
this . right _container . addClass ( "et2_itempicker_right_container" ) ;
// Application select
this . app _select . addClass ( "et2_itempicker_app_select" ) ;
2021-06-07 17:33:53 +02:00
let item _count = 0 ;
for ( let key in this . options . select _options ) {
let img _icon = this . egw ( ) . image ( key + "/navbar" ) ;
2020-02-13 11:08:12 +01:00
if ( img _icon === null ) {
continue ;
}
2021-06-07 17:33:53 +02:00
let img = jQuery ( document . createElement ( "img" ) ) ;
2020-02-13 11:08:12 +01:00
img . attr ( "src" , img _icon ) ;
2021-06-07 17:33:53 +02:00
let item = jQuery ( document . createElement ( "li" ) ) ;
2020-02-13 11:08:12 +01:00
item . attr ( "id" , key )
. click ( function ( ) {
_self . selectApplication ( jQuery ( this ) ) ;
} )
. append ( img ) ;
if ( item _count == 0 ) {
this . selectApplication ( item ) ; // select first item by default
}
this . app _select . append ( item ) ;
item _count ++ ;
}
// Search input field
this . search . addClass ( "et2_itempicker_search" ) ;
this . search . keyup ( function ( ) {
2021-06-07 17:33:53 +02:00
let request = { } ;
2020-02-13 11:08:12 +01:00
request . term = jQuery ( this ) . val ( ) ;
_self . query ( request ) ;
} ) ;
this . set _blur ( this . options . blur , this . search ) ;
// Clear button for search
this . clear
. addClass ( "et2_itempicker_clear ui-icon ui-icon-close" )
. click ( function ( ) {
_self . clearSearchResults ( ) ;
} )
. hide ( ) ;
// Action button
2021-06-07 17:33:53 +02:00
this . button _action = et2 _createWidget ( "button" , { } ) ;
2020-02-13 11:08:12 +01:00
jQuery ( this . button _action . getDOMNode ( ) ) . addClass ( "et2_itempicker_button_action" ) ;
this . button _action . set _label ( this . egw ( ) . lang ( this . options . action _label ) ) ;
this . button _action . click = function ( ) { _self . doAction ( ) ; } ;
// Itemlist
this . itemlist . attr ( "id" , "itempicker_itemlist" ) ;
this . itemlist . addClass ( "et2_itempicker_itemlist" ) ;
// Put everything together
this . left . append ( this . app _select ) ;
this . right _container . append ( this . search ) ;
this . right _container . append ( this . clear ) ;
this . right _container . append ( this . button _action . getDOMNode ( ) ) ;
this . right _container . append ( this . itemlist ) ;
this . right . append ( this . right _container ) ;
this . div . append ( this . right ) ; // right before left to have a natural
this . div . append ( this . left ) ; // z-index for left div over right div
this . setDOMNode ( this . div [ 0 ] ) ;
2021-06-07 17:33:53 +02:00
}
doAction ( ) {
2020-02-13 11:08:12 +01:00
if ( this . action !== null ) {
2021-06-07 17:33:53 +02:00
let data = { } ;
2020-02-13 11:08:12 +01:00
data . app = this . current _app ;
data . value = this . options . value ;
data . checked = this . getSelectedItems ( ) ;
return this . action . exec ( this , data ) ;
}
return false ;
2021-06-07 17:33:53 +02:00
}
getSelectedItems ( ) {
let items = [ ] ;
2020-02-13 11:08:12 +01:00
jQuery ( this . itemlist ) . children ( "ul" ) . children ( "li.selected" ) . each ( function ( index ) {
items [ index ] = jQuery ( this ) . attr ( "id" ) ;
} ) ;
return items ;
2021-06-07 17:33:53 +02:00
}
2020-02-13 11:08:12 +01:00
/ * *
* Ask server for entries matching selected app / type and filtered by search string
* /
2021-06-07 17:33:53 +02:00
query ( request ) {
2020-02-13 11:08:12 +01:00
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" ) ;
this . clear . css ( "display" , "inline-block" ) ;
egw . json ( "EGroupware\\Api\\Etemplate\\Widget\\ItemPicker::ajax_item_search" , [ this . current _app , '' , request . term , request . options ] , this . queryResults , this , true , this ) . sendRequest ( ) ;
2021-06-07 17:33:53 +02:00
}
2020-02-13 11:08:12 +01:00
/ * *
* Server found some results for query
* /
2021-06-07 17:33:53 +02:00
queryResults ( data ) {
2020-02-13 11:08:12 +01:00
this . itemlist . removeClass ( "loading" ) ;
this . updateItemList ( data ) ;
2021-06-07 17:33:53 +02:00
}
selectApplication ( app ) {
2020-02-13 11:08:12 +01:00
this . clearSearchResults ( ) ;
jQuery ( ".et2_itempicker_app_select li" ) . removeClass ( "selected" ) ;
app . addClass ( "selected" ) ;
this . current _app = app . attr ( "id" ) ;
return true ;
2021-06-07 17:33:53 +02:00
}
set _blur ( _value , input ) {
2020-02-13 11:08:12 +01:00
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 ) {
2021-06-07 17:33:53 +02:00
let placeholder = _value ;
2020-02-13 11:08:12 +01:00
if ( e . data . val ( ) == placeholder )
e . data . val ( "" ) ;
} ) . blur ( input , function ( e ) {
2021-06-07 17:33:53 +02:00
let placeholder = _value ;
2020-02-13 11:08:12 +01:00
if ( e . data . val ( ) == "" )
e . data . val ( placeholder ) ;
} ) ;
if ( input . val ( ) == "" )
input . val ( _value ) ;
}
}
else {
this . search . removeAttr ( "placeholder" ) ;
}
2021-06-07 17:33:53 +02:00
}
transformAttributes ( _attrs ) {
super . transformAttributes ( _attrs ) ;
2020-02-13 11:08:12 +01:00
_attrs [ "select_options" ] = { } ;
if ( _attrs [ "application" ] ) {
2021-06-07 17:33:53 +02:00
let apps = et2 _csvSplit ( _attrs [ "application" ] , null , "," ) ;
for ( let i = 0 ; i < apps . length ; i ++ ) {
2020-02-13 11:08:12 +01:00
_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' )
. getEntry ( "options-" + this . id ) ;
}
// Default to an empty object
if ( _attrs [ "select_options" ] == null ) {
_attrs [ "select_options" ] = { } ;
}
2021-06-07 17:33:53 +02:00
}
updateItemList ( data ) {
let list = jQuery ( document . createElement ( "ul" ) ) ;
let item _count = 0 ;
for ( let id in data ) {
let item = jQuery ( document . createElement ( "li" ) ) ;
2020-02-13 11:08:12 +01:00
if ( item _count % 2 == 0 ) {
item . addClass ( "row_on" ) ;
}
else {
item . addClass ( "row_off" ) ;
}
item . attr ( "id" , id )
. html ( data [ id ] )
. click ( function ( e ) {
if ( e . ctrlKey || e . metaKey ) {
// add to selection
jQuery ( this ) . addClass ( "selected" ) ;
}
else if ( e . shiftKey ) {
// select range
2021-06-07 17:33:53 +02:00
let start = jQuery ( this ) . siblings ( ".selected" ) . first ( ) ;
2021-03-22 18:42:50 +01:00
if ( ( start === null || start === void 0 ? void 0 : start . length ) == 0 ) {
2020-02-13 11:08:12 +01:00
// no start item - cannot select range - select single item
jQuery ( this ) . addClass ( "selected" ) ;
return true ;
}
2021-06-07 17:33:53 +02:00
let end = jQuery ( this ) ;
2020-02-13 11:08:12 +01:00
// swap start and end if start appears after end in dom hierarchy
if ( start . index ( ) > end . index ( ) ) {
2021-06-07 17:33:53 +02:00
let startOld = start ;
2020-02-13 11:08:12 +01:00
start = end ;
end = startOld ;
}
// select start to end
start . addClass ( "selected" ) ;
start . nextUntil ( end ) . addClass ( "selected" ) ;
end . addClass ( "selected" ) ;
}
else {
// select single item
jQuery ( this ) . siblings ( ".selected" ) . removeClass ( "selected" ) ;
jQuery ( this ) . addClass ( "selected" ) ;
}
} ) ;
list . append ( item ) ;
item _count ++ ;
}
this . itemlist . html ( list ) ;
2021-06-07 17:33:53 +02:00
}
}
et2 _itempicker . _attributes = {
"action" : {
"name" : "Action callback" ,
"type" : "string" ,
"default" : false ,
"description" : "Callback for action. Must be a function(context, data)"
} ,
"action_label" : {
"name" : "Action label" ,
"type" : "string" ,
"default" : "Action" ,
"description" : "Label for action button"
} ,
"application" : {
"name" : "Application" ,
"type" : "string" ,
"default" : "" ,
"description" : "Limit to the listed application or applications (comma separated)"
} ,
"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."
} ,
"value" : {
"name" : "value" ,
"type" : "any" ,
"default" : "" ,
"description" : "Optional itempicker value(s) - can be used for e.g. environmental information"
} ,
"query" : {
"name" : "Query callback" ,
"type" : "any" ,
"default" : false ,
"description" : "Callback before query to server. Must return true, or false to abort query."
}
} ;
et2 _itempicker . legacyOptions = [ "application" ] ;
et2 _register _widget ( et2 _itempicker , [ "itempicker" ] ) ;
2020-02-13 11:08:12 +01:00
//# sourceMappingURL=et2_widget_itempicker.js.map