2020-02-05 21:48:50 +01:00
"use strict" ;
/ * *
2020-02-16 11:31:32 +01:00
* EGroupware eTemplate2 - JS Link object
*
* @ license http : //opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @ package etemplate
* @ subpackage api
* @ link http : //www.egroupware.org
* @ author Nathan Gray
* @ copyright 2011 Nathan Gray
* /
2020-02-05 21:48:50 +01:00
var _ _extends = ( this && this . _ _extends ) || ( function ( ) {
var extendStatics = function ( d , b ) {
extendStatics = Object . setPrototypeOf ||
( { _ _proto _ _ : [ ] } instanceof Array && function ( d , b ) { d . _ _proto _ _ = b ; } ) ||
function ( d , b ) { for ( var p in b ) if ( b . hasOwnProperty ( p ) ) d [ p ] = b [ p ] ; } ;
return extendStatics ( d , b ) ;
} ;
return function ( d , b ) {
extendStatics ( d , b ) ;
function _ _ ( ) { this . constructor = d ; }
d . prototype = b === null ? Object . create ( b ) : ( _ _ . prototype = b . prototype , new _ _ ( ) ) ;
} ;
} ) ( ) ;
2020-02-19 17:14:44 +01:00
var _a ;
2020-02-05 21:48:50 +01:00
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
2021-03-22 18:18:16 +01:00
exports . et2 _link _add = exports . et2 _link _list = exports . et2 _link _string = exports . et2 _link = exports . et2 _link _entry = exports . et2 _link _apps = exports . et2 _link _to = void 0 ;
2011-09-08 01:32:24 +02:00
/ * e g w : u s e s
2020-02-05 21:48:50 +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 ;
/ v e n d o r / b o w e r - a s s e t / j q u e r y - u i / j q u e r y - u i . j s ;
et2 _core _inputWidget ;
et2 _core _valueWidget ;
2020-09-11 00:59:34 +02:00
et2 _widget _selectbox ;
expose ;
2012-06-19 20:59:53 +02:00
2020-02-05 21:48:50 +01:00
// Include menu system for list context menu
egw _action . egw _menu _dhtmlx ;
2011-09-08 01:32:24 +02:00
* /
2020-02-05 21:48:50 +01:00
var et2 _core _widget _1 = require ( "./et2_core_widget" ) ;
var et2 _core _inheritance _1 = require ( "./et2_core_inheritance" ) ;
var et2 _core _valueWidget _1 = require ( "./et2_core_valueWidget" ) ;
var et2 _core _inputWidget _1 = require ( "./et2_core_inputWidget" ) ;
var et2 _widget _selectbox _1 = require ( "./et2_widget_selectbox" ) ;
2020-12-21 21:53:24 +01:00
var et2 _widget _dialog _1 = require ( "./et2_widget_dialog" ) ;
2011-09-08 01:32:24 +02:00
/ * *
2020-04-21 23:36:17 +02:00
* UI widgets for Egroupware linking system
* /
2020-02-05 21:48:50 +01:00
var et2 _link _to = /** @class */ ( function ( _super ) {
_ _extends ( et2 _link _to , _super ) ;
/ * *
* Constructor
*
* @ memberOf et2 _link _to
* /
function et2 _link _to ( _parent , _attrs , _child ) {
2020-02-05 23:27:24 +01:00
var _this = _super . call ( this , _parent , _attrs , et2 _core _inheritance _1 . ClassWithAttributes . extendAttributes ( et2 _link _to . _attributes , _child || { } ) ) || this ;
2020-02-05 21:48:50 +01:00
_this . div = jQuery ( document . createElement ( "div" ) ) . addClass ( "et2_link_to et2_toolbar" ) ;
_this . link _button = null ;
_this . status _span = null ;
_this . link _entry = null ;
_this . file _upload = null ;
_this . createInputWidget ( ) ;
return _this ;
}
et2 _link _to . prototype . destroy = function ( ) {
this . link _button = null ;
this . status _span = null ;
if ( this . link _entry ) {
this . link _entry . destroy ( ) ;
this . link _entry = null ;
}
if ( this . file _upload ) {
this . file _upload . destroy ( ) ;
this . file _upload = null ;
}
this . div = null ;
_super . prototype . destroy . apply ( this , arguments ) ;
} ;
/ * *
* Override to provide proper node for sub widgets to go in
*
* @ param { Object } _sender
* /
et2 _link _to . prototype . getDOMNode = function ( _sender ) {
if ( _sender == this ) {
return this . div [ 0 ] ;
}
else if ( _sender . _type == 'link-entry' ) {
return this . link _div [ 0 ] ;
}
else if ( _sender . _type == 'file' ) {
return this . file _div [ 0 ] ;
}
else if ( _sender . _type == 'vfs-select' ) {
return this . filemanager _button [ 0 ] ;
}
} ;
et2 _link _to . prototype . createInputWidget = function ( ) {
// Need a div for file upload widget
this . file _div = jQuery ( document . createElement ( "div" ) ) . css ( { display : 'inline-block' } ) . appendTo ( this . div ) ;
// Filemanager link popup
this . filemanager _button = jQuery ( document . createElement ( "div" ) ) . css ( { display : 'inline-block' } ) . appendTo ( this . div ) ;
// Need a div for link-to widget
this . link _div = jQuery ( document . createElement ( "div" ) )
. addClass ( 'div_link' )
// Leave room for link button
. appendTo ( this . div ) ;
if ( ! this . options . readonly ) {
// One common link button
this . link _button = jQuery ( document . createElement ( "button" ) )
. text ( this . egw ( ) . lang ( this . options . link _label ) )
. appendTo ( this . div ) . hide ( )
. addClass ( 'link' )
. click ( this , this . createLink ) ;
// Span for indicating status
this . status _span = jQuery ( document . createElement ( "span" ) )
. appendTo ( this . div ) . addClass ( "status" ) . hide ( ) ;
}
this . setDOMNode ( this . div [ 0 ] ) ;
} ;
et2 _link _to . prototype . doLoadingFinished = function ( ) {
_super . prototype . doLoadingFinished . apply ( this , arguments ) ;
var self = this ;
if ( this . link _entry && this . vfs _select && this . file _upload ) {
// Already done
return false ;
}
// Link-to
var link _entry _attrs = {
id : this . id + '_link_entry' ,
only _app : this . options . only _app ,
application _list : this . options . application _list ,
blur : this . options . search _label ? this . options . search _label : this . egw ( ) . lang ( 'Search...' ) ,
query : function ( ) { self . link _button . hide ( ) ; return true ; } ,
select : function ( ) { self . link _button . show ( ) ; return true ; } ,
readonly : this . options . readonly
} ;
2020-12-21 21:53:24 +01:00
this . link _entry = et2 _core _widget _1 . et2 _createWidget ( "link-entry" , link _entry _attrs , this ) ;
2020-02-05 21:48:50 +01:00
// Filemanager select
var select _attrs = {
button _label : egw . lang ( 'Link' ) ,
button _caption : '' ,
button _icon : 'link' ,
readonly : this . options . readonly ,
dialog _title : egw . lang ( 'Link' ) ,
extra _buttons : [ { text : egw . lang ( "copy" ) , id : "copy" , image : "copy" } ,
{ text : egw . lang ( "move" ) , id : "move" , image : "move" } ] ,
onchange : function ( ) {
var values = true ;
// If entry not yet saved, store for linking on server
if ( ! self . options . value . to _id || typeof self . options . value . to _id == 'object' ) {
values = self . options . value . to _id || { } ;
var files = self . vfs _select . getValue ( ) ;
if ( typeof files !== 'undefined' ) {
for ( var i = 0 ; i < files . length ; i ++ ) {
values [ 'link:' + files [ i ] ] = {
app : 'link' ,
id : files [ i ] ,
type : 'unknown' ,
icon : 'link' ,
remark : '' ,
title : files [ i ]
} ;
}
}
}
self . _link _result ( values ) ;
}
} ;
// only set server-side callback, if we have a real application-id (not null or array)
// otherwise it only gives an error on server-side
if ( self . options . value && self . options . value . to _id && typeof self . options . value . to _id != 'object' ) {
select _attrs . method = 'EGroupware\\Api\\Etemplate\\Widget\\Link::ajax_link_existing' ;
select _attrs . method _id = self . options . value . to _app + ':' + self . options . value . to _id ;
}
2020-12-21 21:53:24 +01:00
this . vfs _select = et2 _core _widget _1 . et2 _createWidget ( "vfs-select" , select _attrs , this ) ;
2020-02-05 21:48:50 +01:00
this . vfs _select . set _readonly ( this . options . readonly ) ;
// File upload
var file _attrs = {
multiple : true ,
id : this . id + '_file' ,
label : '' ,
// Make the whole template a drop target
drop _target : this . getInstanceManager ( ) . DOMContainer . getAttribute ( "id" ) ,
readonly : this . options . readonly ,
// Change to this tab when they drop
onStart : function ( event , file _count ) {
// Find the tab widget, if there is one
var tabs = self ;
do {
tabs = tabs . getParent ( ) ;
} while ( tabs != self . getRoot ( ) && tabs . getType ( ) != 'tabbox' ) ;
if ( tabs != self . getRoot ( ) ) {
tabs . activateTab ( self ) ;
}
return true ;
} ,
onFinish : function ( event , file _count ) {
event . data = self ;
self . filesUploaded ( event ) ;
// Auto-link uploaded files
self . createLink ( event ) ;
}
} ;
2020-12-21 21:53:24 +01:00
this . file _upload = et2 _core _widget _1 . et2 _createWidget ( "file" , file _attrs , this ) ;
2020-02-05 21:48:50 +01:00
this . file _upload . set _readonly ( this . options . readonly ) ;
return true ;
} ;
et2 _link _to . prototype . getValue = function ( ) {
return this . options . value ;
} ;
et2 _link _to . prototype . filesUploaded = function ( event ) {
var self = this ;
this . link _button . show ( ) ;
} ;
/ * *
* Create a link using the current internal values
*
* @ param { Object } event
* /
et2 _link _to . prototype . createLink = function ( event ) {
// Disable link button
event . data . link _button . attr ( "disabled" , true ) ;
var values = event . data . options . value ;
var self = event . data ;
var links = [ ] ;
// Links to other entries
event . data = self . link _entry ;
self . link _entry . createLink ( event , links ) ;
// Files
if ( ! self . options . no _files ) {
for ( var file in self . file _upload . options . value ) {
links . push ( {
app : 'file' ,
id : file ,
name : self . file _upload . options . value [ file ] . name ,
type : self . file _upload . options . value [ file ] . type ,
remark : jQuery ( "li[file='" + self . file _upload . options . value [ file ] . name . replace ( /'/g , '"' ) + "'] > input" , self . file _upload . progress )
. filter ( function ( ) { return jQuery ( this ) . attr ( "placeholder" ) != jQuery ( this ) . val ( ) ; } ) . val ( )
} ) ;
}
}
if ( links . length == 0 ) {
return ;
}
var request = egw . json ( "EGroupware\\Api\\Etemplate\\Widget\\Link::ajax_link" , [ values . to _app , values . to _id , links ] , self . _link _result , self , true , self ) ;
request . sendRequest ( ) ;
} ;
/ * *
* Sent some links , server has a result
*
* @ param { Object } success
* /
et2 _link _to . prototype . _link _result = function ( success ) {
if ( success ) {
this . link _button . hide ( ) . attr ( "disabled" , false ) ;
this . status _span . removeClass ( "error" ) . addClass ( "success" ) ;
this . status _span . fadeIn ( ) . delay ( 1000 ) . fadeOut ( ) ;
delete this . options . value . app ;
delete this . options . value . id ;
for ( var file in this . file _upload . options . value ) {
delete this . file _upload . options . value [ file ] ;
}
this . file _upload . progress . empty ( ) ;
// Server says it's OK, but didn't store - we'll send this again on submit
// This happens if you link to something before it's saved to the DB
if ( typeof success == "object" ) {
// Save as appropriate in value
if ( typeof this . options . value != "object" ) {
this . options . value = { } ;
}
this . options . value . to _id = success ;
for ( var link in success ) {
// Icon should be in registry
if ( typeof success [ link ] . icon == 'undefined' ) {
success [ link ] . icon = egw . link _get _registry ( success [ link ] . app , 'icon' ) ;
// No icon, try by mime type - different place for un-saved entries
if ( success [ link ] . icon == false && success [ link ] . id . type ) {
// Triggers icon by mime type, not thumbnail or app
success [ link ] . type = success [ link ] . id . type ;
success [ link ] . icon = true ;
}
}
// Special handling for file - if not existing, we can't ask for title
if ( success [ link ] . app == 'file' && typeof success [ link ] . title == 'undefined' ) {
success [ link ] . title = success [ link ] . id . name || '' ;
}
}
}
// Look for a link-list with the same ID, refresh it
var self = this ;
var list _widget = null ;
this . getRoot ( ) . iterateOver ( function ( widget ) {
if ( widget . id == self . id ) {
list _widget = widget ;
if ( success === true ) {
widget . _get _links ( ) ;
}
}
} , this , et2 _link _list ) ;
// If there's an array of data (entry is not yet saved), updating the list will
// not work, so add them in explicitly.
if ( list _widget && success ) {
// Clear list
list _widget . set _value ( null ) ;
var _loop _1 = function ( ) {
var link = success [ link _id ] ;
if ( typeof link . title == 'undefined' ) {
// Callback to server for title
egw . link _title ( link . app , link . id , function ( title ) {
link . title = title ;
list _widget . _add _link ( link ) ;
} ) ;
}
else {
// Add direct
list _widget . _add _link ( link ) ;
}
} ;
// Add temp links in
for ( var link _id in success ) {
_loop _1 ( ) ;
}
}
}
else {
this . status _span . removeClass ( "success" ) . addClass ( "error" )
. fadeIn ( ) ;
}
this . div . trigger ( 'link.et2_link_to' , success ) ;
} ;
et2 _link _to . prototype . set _no _files = function ( no _files ) {
if ( this . options . readonly )
return ;
if ( no _files ) {
this . file _div . hide ( ) ;
this . filemanager _button . hide ( ) ;
}
else {
this . file _div . show ( ) ;
this . filemanager _button . show ( ) ;
}
this . options . no _files = no _files ;
} ;
et2 _link _to . _attributes = {
"only_app" : {
"name" : "Application" ,
"type" : "string" ,
"default" : "" ,
"description" : "Limit to just this one application - hides app selection"
} ,
"application_list" : {
"name" : "Application list" ,
"type" : "any" ,
"default" : "" ,
"description" : "Limit to the listed application or applications (comma seperated)"
} ,
"blur" : {
"name" : "Placeholder" ,
"type" : "string" ,
"default" : "" ,
"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." ,
translate : true
} ,
"no_files" : {
"name" : "No files" ,
"type" : "boolean" ,
"default" : false ,
"description" : "Suppress attach-files"
} ,
"search_label" : {
"name" : "Search label" ,
"type" : "string" ,
"default" : "" ,
"description" : "Label to use for search"
} ,
"link_label" : {
"name" : "Link label" ,
"type" : "string" ,
"default" : "Link" ,
"description" : "Label for the link button"
} ,
"value" : {
// Could be string or int if application is provided, or an Object
"type" : "any"
}
} ;
return et2 _link _to ;
} ( et2 _core _inputWidget _1 . et2 _inputWidget ) ) ;
exports . et2 _link _to = et2 _link _to ;
et2 _core _widget _1 . et2 _register _widget ( et2 _link _to , [ "link-to" ] ) ;
2013-04-13 21:00:13 +02:00
/ * *
2020-02-05 21:48:50 +01:00
* List of applications that support link
2013-04-13 21:00:13 +02:00
* /
2020-02-05 21:48:50 +01:00
var et2 _link _apps = /** @class */ ( function ( _super ) {
_ _extends ( et2 _link _apps , _super ) ;
/ * *
* Constructor
*
* /
function et2 _link _apps ( _parent , _attrs , _child ) {
2020-02-05 23:27:24 +01:00
var _this = _super . call ( this , _parent , _attrs , et2 _core _inheritance _1 . ClassWithAttributes . extendAttributes ( et2 _link _apps . _attributes , _child || { } ) ) || this ;
2020-02-05 21:48:50 +01:00
if ( _this . options . select _options != null ) {
// Preset to last application
if ( ! _this . options . value ) {
_this . set _value ( egw . preference ( 'link_app' , _this . egw ( ) . getAppName ( ) ) ) ;
}
// Register to update preference
var self = _this ;
_this . input . bind ( "click" , function ( ) {
if ( typeof self . options . value != 'undefined' )
var appname = self . options . value . to _app ;
egw . set _preference ( appname || self . egw ( ) . getAppName ( ) , 'link_app' , self . getValue ( ) ) ;
} ) ;
}
return _this ;
}
/ * *
* We get some minor speedups by overriding parent searching and directly setting select options
*
* @ param { Array } _attrs an array of attributes
* /
et2 _link _apps . prototype . transformAttributes = function ( _attrs ) {
var select _options = { } ;
// Limit to one app
if ( _attrs . only _app ) {
select _options [ _attrs . only _app ] = this . egw ( ) . lang ( _attrs . only _app ) ;
}
else if ( _attrs . application _list ) {
select _options = _attrs . application _list ;
}
else {
select _options = egw . link _app _list ( 'query' ) ;
if ( typeof select _options [ 'addressbook-email' ] !== 'undefined' ) {
delete select _options [ 'addressbook-email' ] ;
}
}
_attrs . select _options = select _options ;
_super . prototype . transformAttributes . call ( this , _attrs ) ;
} ;
2020-02-07 17:31:10 +01:00
et2 _link _apps . _attributes = {
2020-02-05 21:48:50 +01:00
"only_app" : {
"name" : "Application" ,
"type" : "string" ,
"default" : "" ,
"description" : "Limit to just this one application - hides app selection"
} ,
"application_list" : {
"name" : "Application list" ,
"type" : "any" ,
"default" : "" ,
"description" : "Limit to the listed application or applications (comma seperated)"
}
} ;
return et2 _link _apps ;
} ( et2 _widget _selectbox _1 . et2 _selectbox ) ) ;
exports . et2 _link _apps = et2 _link _apps ;
et2 _core _widget _1 . et2 _register _widget ( et2 _link _apps , [ "link-apps" ] ) ;
2013-04-13 21:00:13 +02:00
/ * *
2020-02-05 21:48:50 +01:00
* Search and select an entry for linking
2013-04-13 21:00:13 +02:00
* /
2020-02-05 21:48:50 +01:00
var et2 _link _entry = /** @class */ ( function ( _super ) {
_ _extends ( et2 _link _entry , _super ) ;
/ * *
* Constructor
*
* @ memberOf et2 _link _entry
* /
function et2 _link _entry ( _parent , _attrs , _child ) {
2020-02-05 23:27:24 +01:00
var _this = _super . call ( this , _parent , _attrs , et2 _core _inheritance _1 . ClassWithAttributes . extendAttributes ( et2 _link _entry . _attributes , _child || { } ) ) || this ;
2020-02-05 21:48:50 +01:00
_this . cache = { } ;
_this . processing = false ;
_this . search = null ;
_this . clear = null ;
_this . app _select = null ;
_this . _oldValue = {
id : null ,
app : _this . options . value && _this . options . value . app ? _this . options . value . app : _this . options . only _app
} ;
if ( typeof _this . options . value == 'undefined' || _this . options . value == null ) {
_this . options . value = { } ;
}
_this . cache = { } ;
_this . request = null ;
_this . createInputWidget ( ) ;
var self = _this ;
jQuery ( _this . getInstanceManager ( ) . DOMContainer ) . on ( 'clear' , function ( ) {
// We need to unbind events to prevent a second triggerd event handler
// (eg. setting a project in infolog edit dialog) when the widget gets cleared.
jQuery ( self . getDOMNode ( ) ) . off ( ) ;
} ) ;
return _this ;
}
et2 _link _entry . prototype . destroy = function ( ) {
_super . prototype . destroy . apply ( this , arguments ) ;
this . div = null ;
if ( this . search . data ( "ui-autocomplete" ) ) {
this . search . autocomplete ( "destroy" ) ;
}
this . search = null ;
this . clear = null ;
this . app _select = null ;
this . request = null ;
} ;
et2 _link _entry . prototype . createInputWidget = function ( ) {
var self = this ;
this . div = jQuery ( document . createElement ( "div" ) ) . addClass ( "et2_link_entry" ) ;
// Application selection
jQuery . widget ( "custom.iconselectmenu" , jQuery . ui . selectmenu , {
_setText : function ( element , value ) {
if ( element === this . buttonText ) {
this . _setButtonText ( value ) ;
}
else {
this . _superApply ( element , value ) ;
}
} ,
_setButtonText : function ( value ) {
var _value = this . focusIndex ;
if ( typeof this . focusIndex === 'undefined' ) {
_value = this . element . find ( "option:selected" ) . val ( ) ;
}
else {
var selected = this . items [ _value ] || { } ;
_value = selected . value ;
}
var url = self . egw ( ) . image ( 'navbar' , _value ) ;
var buttonItem = jQuery ( "<span>" , {
"class" : "ui-selectmenu-text" ,
title : value
} ) ;
jQuery ( '.ui-selectmenu-text' , this . button ) . replaceWith ( buttonItem ) ;
buttonItem . css ( 'background-image' , 'url(' + url + ')' ) ;
} ,
_renderItem : function ( ul , item ) {
2020-02-19 17:14:44 +01:00
var li = jQuery ( "<li>" , { class : "et2_link_entry_app_option" } ) , wrapper = jQuery ( "<div>" , { text : item . label } ) ;
2020-02-05 21:48:50 +01:00
if ( item . disabled ) {
li . addClass ( "ui-state-disabled" ) ;
}
ul . addClass ( self . div . attr ( "class" ) ) ;
var url = self . egw ( ) . image ( 'navbar' , item . value ) ;
jQuery ( "<span>" , {
style : 'background-image: url("' + url + '");' ,
"class" : "ui-icon " + item . element . attr ( "data-class" ) ,
title : item . label
} )
. appendTo ( wrapper ) ;
return li . append ( wrapper ) . appendTo ( ul ) ;
}
} ) ;
this . app _select = jQuery ( document . createElement ( "select" ) ) . appendTo ( this . div )
. change ( function ( e ) {
// Clear cache when app changes
self . cache = { } ;
// Update preference with new value
egw . set _preference ( self . options . value . to _app || self . egw ( ) . getAppName ( ) , 'link_app' , self . app _select . val ( ) ) ;
if ( typeof self . options . value != 'object' )
self . options . value = { } ;
self . options . value . app = self . app _select . val ( ) ;
} ) ;
var opt _count = 0 ;
for ( var key in this . options . select _options ) {
opt _count ++ ;
var option = jQuery ( document . createElement ( "option" ) )
. attr ( "value" , key )
. text ( this . options . select _options [ key ] ) ;
option . appendTo ( this . app _select ) ;
}
if ( this . options . only _app ) {
this . app _select . val ( this . options . only _app ) ;
this . app _select . hide ( ) ;
if ( this . options . app _icons && this . app _select . iconselectmenu ( 'instance' ) ) {
this . app _select . iconselectmenu ( 'widget' ) . hide ( ) ;
}
this . div . addClass ( "no_app" ) ;
}
else {
// Now that options are in, set to last used app
this . app _select . val ( this . options . value . app || '' ) ;
if ( this . app _select . iconselectmenu ( 'instance' ) ) {
this . app _select . iconselectmenu ( 'update' ) ;
}
}
// Search input
this . search = jQuery ( document . createElement ( "input" ) )
// .attr("type", "search") // Fake it for all browsers below
. focus ( function ( ) {
if ( ! self . options . only _app ) {
// Adjust width, leave room for app select & link button
self . div . removeClass ( "no_app" ) ;
if ( self . options . app _icons ) {
self . app _select . iconselectmenu ( 'widget' ) . show ( ) ;
}
else {
self . app _select . show ( ) ;
}
}
} )
. blur ( function ( e ) {
if ( self . div . has ( e . relatedTarget ) . length )
return ;
if ( self . options . app _icons ) {
// Adjust width, leave room for app select & link button
self . div . addClass ( "no_app" ) ;
self . app _select . iconselectmenu ( 'widget' ) . hide ( ) ;
}
else if ( self . search . val ( ) ) {
if ( self . options . only _app ) {
// Adjust width, leave room for app select & link button
self . div . addClass ( "no_app" ) ;
}
}
} )
. appendTo ( this . div ) ;
this . set _blur ( this . options . blur ? this . options . blur : this . egw ( ) . lang ( "search" ) , this . search ) ;
// Autocomplete
this . search . autocomplete ( {
source : function ( request , response ) {
return self . query ( request , response ) ;
} ,
select : function ( event , item ) {
event . data = self ;
// Correct changed value from server
2020-09-15 19:23:02 +02:00
if ( item . item . value ) {
item . item . value = ( "" + item . item . value ) . trim ( ) ;
}
2020-02-05 21:48:50 +01:00
self . select ( event , item ) ;
return false ;
} ,
focus : function ( event , item ) {
event . stopPropagation ( ) ;
self . search . val ( item . item . label ) ;
return false ;
} ,
minLength : et2 _link _entry . minimum _characters ,
delay : et2 _link _entry . search _timeout ,
disabled : self . options . disabled ,
appendTo : self . div
} ) ;
// Custom display (colors)
this . search . data ( "uiAutocomplete" ) . _renderItem = function ( ul , item ) {
var li = jQuery ( document . createElement ( 'li' ) )
. data ( "item.autocomplete" , item ) ;
var extra = { } ;
// Extra stuff
if ( typeof item . label == 'object' ) {
extra = item . label ;
item . label = extra . label ? extra . label : extra ;
if ( extra [ 'style.backgroundColor' ] || extra . color ) {
li . css ( { 'border-left' : '5px solid ' + ( extra . color ? extra . color : extra [ 'style.backgroundColor' ] ) } ) ;
}
// Careful with this, some browsers may have trouble loading all at once, which can slow display
if ( extra . icon ) {
var img = self . egw ( ) . image ( extra . icon ) ;
if ( img ) {
jQuery ( document . createElement ( "img" ) )
. attr ( "src" , img )
. css ( "float" , "right" )
. appendTo ( li ) ;
}
}
}
// Normal stuff
li . append ( jQuery ( "<a></a>" ) . text ( item . label ) )
. appendTo ( ul ) ;
window . setTimeout ( function ( ) { ul . css ( 'max-width' , jQuery ( '.et2_container' ) . width ( ) - ul . offset ( ) . left ) ; } , 300 ) ;
return li ;
} ;
// Bind to enter key to start search early
this . search . keydown ( function ( e ) {
var keycode = ( e . keyCode ? e . keyCode : e . which ) ;
if ( keycode == 13 && ! self . processing ) {
self . search . autocomplete ( "option" , "minLength" , 0 ) ;
self . search . autocomplete ( "search" ) ;
self . search . autocomplete ( "option" , "minLength" , self . minimum _characters ) ;
return false ;
}
} ) ;
// Clear / last button
this . clear = jQuery ( document . createElement ( "span" ) )
. addClass ( "ui-icon ui-icon-close" )
. click ( function ( e ) {
if ( ! self . search )
return ; // only gives an error, we should never get into that situation
// No way to tell if the results is open, so if they click the button while open, it clears
if ( self . last _search && self . last _search != self . search . val ( ) ) {
// Repeat last search (should be cached)
self . search . val ( self . last _search ) ;
self . last _search = "" ;
self . search . autocomplete ( "search" ) ;
}
else {
// Clear
self . search . autocomplete ( "close" ) ;
self . set _value ( null ) ;
self . search . val ( "" ) ;
// call trigger, after finishing this handler, not in the middle of it
window . setTimeout ( function ( ) {
self . search . trigger ( "change" ) ;
} , 0 ) ;
}
self . search . focus ( ) ;
} )
. appendTo ( this . div )
. hide ( ) ;
this . setDOMNode ( this . div [ 0 ] ) ;
} ;
et2 _link _entry . prototype . getDOMNode = function ( ) {
return this . div ? this . div [ 0 ] : null ;
} ;
et2 _link _entry . prototype . transformAttributes = function ( _attrs ) {
_super . prototype . transformAttributes . apply ( this , arguments ) ;
_attrs [ "select_options" ] = { } ;
if ( _attrs [ "application_list" ] ) {
var apps = ( typeof _attrs [ "application_list" ] == "string" ) ? et2 _csvSplit ( _attrs [ "application_list" ] , null , "," ) : _attrs [ "application_list" ] ;
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' ) ;
if ( typeof _attrs [ "select_options" ] [ "addressbook-email" ] != 'undefined' )
delete _attrs [ "select_options" ] [ "addressbook-email" ] ;
}
// 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" ] = { } ;
}
} ;
et2 _link _entry . prototype . doLoadingFinished = function ( ) {
if ( typeof this . options . value == 'object' && ! this . options . value . app ) {
this . options . value . app = egw . preference ( 'link_app' , this . options . value . to _app || this . egw ( ) . getAppName ( ) ) ;
// If there's no value set for app, then take the first one from the selectbox
if ( typeof this . options . value . app == 'undefined' || ! this . options . value . app ) {
this . options . value . app = Object . keys ( this . options . select _options ) [ 0 ] ;
}
this . app _select . val ( this . options . value . app ) ;
}
if ( this . options . app _icons ) {
var self = this ;
this . div . addClass ( 'app_icons' ) ;
this . app _select . iconselectmenu ( {
width : 50 ,
change : function ( ) {
window . setTimeout ( function ( ) {
self . app _select . trigger ( "change" ) ;
} , 0 ) ;
}
} )
. iconselectmenu ( "menuWidget" ) ;
this . app _select . iconselectmenu ( 'widget' ) . hide ( ) ;
}
return _super . prototype . doLoadingFinished . apply ( this , arguments ) ;
} ;
et2 _link _entry . prototype . getValue = function ( ) {
var value = this . options && this . options . only _app ? this . options . value . id : this . options ? this . options . value : null ;
if ( this . options && ! this . options . only _app && this . search ) {
value . search = this . search . val ( ) ;
}
return value ;
} ;
et2 _link _entry . prototype . set _value = function ( _value ) {
if ( typeof _value == 'string' || typeof _value == 'number' ) {
if ( typeof _value == 'string' && _value . indexOf ( "," ) > 0 )
_value = _value . replace ( "," , ":" ) ;
if ( typeof _value == 'string' && _value . indexOf ( ":" ) >= 0 ) {
var split = _value . split ( ":" ) ;
_value = {
app : split . shift ( ) ,
id : split . length == 1 ? split [ 0 ] : split
} ;
}
else if ( _value && this . options . only _app ) {
_value = {
app : this . options . only _app ,
id : _value
} ;
}
}
2021-08-23 15:11:04 +02:00
// display a search query, not a selected entry
else if ( _value !== null && typeof _value === 'object' && typeof _value . query === 'string' ) {
this . options . value = { app : _value . app || this . options . only _app , id : null } ;
this . search . val ( _value . query ) ;
return ;
}
2020-02-05 21:48:50 +01:00
this . _oldValue = this . options . value ;
if ( ! _value || _value . length == 0 || _value == null || jQuery . isEmptyObject ( _value ) ) {
this . search . val ( "" ) ;
this . clear . hide ( ) ;
this . options . value = _value = { 'id' : null } ;
}
if ( ! _value . app )
_value . app = this . options . only _app || this . app _select . val ( ) ;
if ( _value . id ) {
// Remove specific display and revert to CSS file
// show() would use inline, should be inline-block
this . clear . css ( 'display' , '' ) ;
}
else {
this . clear . hide ( ) ;
return ;
}
if ( typeof _value != 'object' || ( ! _value . app && ! _value . id ) ) {
console . warn ( "Bad value for link widget. Need an object with keys 'app', 'id', and optionally 'title'" , _value ) ;
return ;
}
if ( ! _value . title ) {
var title = this . egw ( ) . link _title ( _value . app , _value . id ) ;
if ( title != null ) {
_value . title = title ;
}
else {
// Title will be fetched from server and then set
var title = this . egw ( ) . link _title ( _value . app , _value . id , function ( title ) {
this . search . removeClass ( "loading" ) . val ( title + "" ) ;
// Remove specific display and revert to CSS file
// show() would use inline, should be inline-block
this . clear . css ( 'display' , '' ) ;
} , this ) ;
this . search . addClass ( "loading" ) ;
}
}
if ( _value . title ) {
this . search . val ( _value . title + "" ) ;
}
this . options . value = _value ;
jQuery ( "option[value='" + _value . app + "']" , this . app _select ) . prop ( "selected" , true ) ;
this . app _select . hide ( ) ;
if ( this . options . app _icons && this . app _select . iconselectmenu ( 'instance' ) ) {
this . app _select . iconselectmenu ( 'widget' ) . hide ( ) ;
}
this . div . addClass ( "no_app" ) ;
} ;
et2 _link _entry . prototype . 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" ) ;
}
} ;
/ * *
* Set the query callback
*
* @ param { function } f
* /
et2 _link _entry . prototype . set _query = function ( f ) {
this . options . query = f ;
} ;
/ * *
* Set the select callback
*
* @ param { function } f
* /
et2 _link _entry . prototype . set _select = function ( f ) {
this . options . select = f ;
} ;
/ * *
* Ask server for entries matching selected app / type and filtered by search string
*
* @ param { Object } request
* @ param { Object } response
* /
et2 _link _entry . prototype . query = function ( request , response ) {
// If there is a pending request, abort it
if ( this . request ) {
this . request . abort ( ) ;
this . request = null ;
}
// Remember last search
this . last _search = this . search . val ( ) ;
// Allow hook / tie in
if ( this . options . query && typeof this . options . query == 'function' ) {
if ( ! this . options . query ( request , this ) )
return false ;
}
if ( ( typeof request . no _cache == 'undefined' && ! request . no _cache ) && request . term in this . cache ) {
return response ( this . cache [ request . term ] ) ;
}
// Remember callback
this . response = response ;
this . search . addClass ( "loading" ) ;
// Remove specific display and revert to CSS file
// show() would use inline, should be inline-block
this . clear . css ( 'display' , '' ) ;
this . request = egw . json ( "EGroupware\\Api\\Etemplate\\Widget\\Link::ajax_link_search" , [ this . app _select . val ( ) , '' , request . term , request . options ] , this . _results , this , true , this ) . sendRequest ( ) ;
} ;
/ * *
* User selected a value
*
* @ param { Object } event
* @ param { Object } selected
*
* /
et2 _link _entry . prototype . select = function ( event , selected ) {
if ( selected . item . value !== null && typeof selected . item . value == "string" ) {
// Correct changed value from server
selected . item . value = selected . item . value . trim ( ) ;
}
if ( this . options . select && typeof this . options . select == 'function' ) {
if ( ! this . options . select ( event , selected ) )
return false ;
}
if ( typeof event . data . options . value != 'object' || event . data . options . value == null ) {
event . data . options . value = { } ;
}
event . data . options . value . id = selected . item . value ;
// Set a processing flag to filter some events
event . data . processing = true ;
// Remove specific display and revert to CSS file
// show() would use inline, should be inline-block
this . clear . css ( 'display' , '' ) ;
event . data . search . val ( selected . item . label ) ;
// Fire change event
this . search . change ( ) ;
// Turn off processing flag when done
window . setTimeout ( jQuery . proxy ( function ( ) { delete this . processing ; } , event . data ) ) ;
} ;
/ * *
* Server found some results
*
* @ param { Array } data
* /
et2 _link _entry . prototype . _results = function ( data ) {
if ( this . request ) {
this . request = null ;
}
this . search . removeClass ( "loading" ) ;
var result = [ ] ;
for ( var id in data ) {
result . push ( { "value" : id , "label" : data [ id ] } ) ;
}
this . cache [ this . search . val ( ) ] = result ;
this . response ( result ) ;
} ;
/ * *
* Create a link using the current internal values
*
* @ param { Object } event
* @ param { Object } _links
* /
et2 _link _entry . prototype . createLink = function ( event , _links ) {
var values = event . data . options . value ;
var self = event . data ;
var links = [ ] ;
if ( typeof _links == 'undefined' ) {
links = [ ] ;
}
else {
links = _links ;
}
// Links to other entries
if ( values . id ) {
links . push ( {
app : values . app ,
id : values . id
} ) ;
self . search . val ( "" ) ;
}
// If a link array was passed in, don't make the ajax call
if ( typeof _links == 'undefined' ) {
var request = egw . json ( "EGroupware\\Api\\Etemplate\\Widget\\Link::ajax_link" , [ values . to _app , values . to _id , links ] , self . _link _result , this , true ) ;
request . sendRequest ( ) ;
}
} ;
/ * *
* Sent some links , server has a result
*
* @ param { Object } success
*
* /
et2 _link _entry . prototype . _link _result = function ( success ) {
if ( success ) {
this . status _span . fadeIn ( ) . delay ( 1000 ) . fadeOut ( ) ;
delete this . options . value . app ;
delete this . options . value . id ;
}
} ;
2020-02-07 17:31:10 +01:00
et2 _link _entry . _attributes = {
2020-02-05 21:48:50 +01:00
"value" : {
"type" : "any" ,
"default" : { }
} ,
"only_app" : {
"name" : "Application" ,
"type" : "string" ,
"default" : "" ,
"description" : "Limit to just this one application - hides app selection"
} ,
"application_list" : {
"name" : "Application list" ,
"type" : "any" ,
"default" : "" ,
"description" : "Limit to the listed applications (comma seperated)"
} ,
"app_icons" : {
"name" : "Application icons" ,
"type" : "boolean" ,
"default" : false ,
"description" : "Show application icons instead of names"
} ,
"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." ,
translate : true
} ,
"query" : {
"name" : "Query callback" ,
"type" : "js" ,
"default" : et2 _no _init ,
"description" : "Callback before query to server. It will be passed the request & et2_link_entry objects. Must return true, or false to abort query."
} ,
"select" : {
"name" : "Select callback" ,
"type" : "js" ,
"default" : et2 _no _init ,
"description" : "Callback when user selects an option. Must return true, or false to abort normal action."
}
} ;
et2 _link _entry . legacyOptions = [ "only_app" , "application_list" ] ;
et2 _link _entry . search _timeout = 500 ; //ms after change to send query
et2 _link _entry . minimum _characters = 4 ; // Don't send query unless there's at least this many chars
return et2 _link _entry ;
} ( et2 _core _inputWidget _1 . et2 _inputWidget ) ) ;
exports . et2 _link _entry = et2 _link _entry ;
et2 _core _widget _1 . et2 _register _widget ( et2 _link _entry , [ "link-entry" ] ) ;
2011-09-13 01:43:39 +02:00
/ * *
* UI widget for a single ( read - only ) link
2014-02-11 13:17:08 +01:00
*
* /
2020-02-05 21:48:50 +01:00
var et2 _link = /** @class */ ( function ( _super ) {
_ _extends ( et2 _link , _super ) ;
/ * *
* Constructor
*
* @ memberOf et2 _link
* /
function et2 _link ( _parent , _attrs , _child ) {
2020-02-05 23:27:24 +01:00
var _this = _super . call ( this , _parent , _attrs , et2 _core _inheritance _1 . ClassWithAttributes . extendAttributes ( et2 _link . _attributes , _child || { } ) ) || this ;
2020-02-05 21:48:50 +01:00
_this . label _span = jQuery ( document . createElement ( "label" ) )
. addClass ( "et2_label" ) ;
_this . link = jQuery ( document . createElement ( "span" ) )
. addClass ( "et2_link" )
. appendTo ( _this . label _span ) ;
if ( _this . options [ 'class' ] )
_this . label _span . addClass ( _this . options [ 'class' ] ) ;
_this . setDOMNode ( _this . label _span [ 0 ] ) ;
return _this ;
}
et2 _link . prototype . destroy = function ( ) {
if ( this . link )
this . link . unbind ( ) ;
this . link = null ;
_super . prototype . destroy . apply ( this , arguments ) ;
} ;
et2 _link . prototype . set _label = function ( label ) {
// Remove current label
this . label _span . contents ( )
. filter ( function ( ) { return this . nodeType == 3 ; } ) . remove ( ) ;
var parts = et2 _csvSplit ( label , 2 , "%s" ) ;
this . label _span . prepend ( parts [ 0 ] ) ;
this . label _span . append ( parts [ 1 ] ) ;
this . label = label ;
// add class if label is empty
this . label _span . toggleClass ( 'et2_label_empty' , ! label || ! parts [ 0 ] ) ;
} ;
et2 _link . prototype . set _value = function ( _value ) {
if ( typeof _value != 'object' && _value && ! this . options . only _app ) {
if ( _value . indexOf ( ':' ) >= 0 ) {
var app = _value . split ( ':' , 1 ) ;
var id = _value . substr ( app [ 0 ] . length + 1 ) ;
_value = { 'app' : app [ 0 ] , 'id' : id } ;
}
else {
console . warn ( "Bad value for link widget. Need an object with keys 'app', 'id', and optionally 'title'" , _value ) ;
return ;
}
}
// Application set, just passed ID
else if ( typeof _value != "object" ) {
_value = {
app : this . options . only _app ,
id : _value
} ;
}
if ( ! _value || jQuery . isEmptyObject ( _value ) ) {
this . link . text ( "" ) . unbind ( ) ;
return ;
}
var self = this ;
this . link . unbind ( ) ;
if ( _value . id && _value . app ) {
this . link . addClass ( "et2_link" ) ;
this . link . click ( function ( e ) {
2020-12-03 18:19:25 +01:00
// try to fetch value.title if it wasn't fetched during initiation.
if ( ! _value . title )
_value . title = self . egw ( ) . link _title ( _value . app , _value . id ) ;
2020-02-05 21:48:50 +01:00
if ( ! self . options . target _app ) {
self . options . target _app = _value . app ;
}
2020-02-16 11:31:32 +01:00
var target = self . options . extra _link _target || _value . app ;
self . egw ( ) . open ( _value , "" , self . options . link _hook , _value . extra _args , target , self . options . target _app ) ;
2020-02-05 21:48:50 +01:00
e . stopImmediatePropagation ( ) ;
} ) ;
}
else {
this . link . removeClass ( "et2_link" ) ;
}
if ( ! _value . title ) {
var self = this ;
var node = this . link [ 0 ] ;
if ( _value . app && _value . id ) {
var title = this . egw ( ) . link _title ( _value . app , _value . id , function ( title ) { self . set _title ( node , title ) ; } , this ) ;
if ( title != null ) {
_value . title = title ;
}
else {
// Title will be fetched from server and then set
return ;
}
}
else {
_value . title = "" ;
}
}
this . set _title ( this . link , _value . title ) ;
} ;
/ * *
* Sets the text to be displayed .
* Used as a callback , so node is provided to make sure we get the right one
*
* @ param { Object } node
* @ param { String } _value description
* /
et2 _link . prototype . set _title = function ( node , _value ) {
if ( _value === false || _value === null )
_value = "" ;
2021-05-10 19:55:22 +02:00
if ( this . options . break _title ) {
// Set up title to optionally break on the provided character - replace all space with nbsp, add a
// zero-width space after the break string
_value = _value
. replace ( this . options . break _title , this . options . break _title + "\u200B" )
. replace ( / /g , '\u00a0' ) ;
}
2020-02-05 21:48:50 +01:00
jQuery ( node ) . text ( _value + "" ) ;
} ;
/ * *
* Creates a list of attributes which can be set when working in the
* "detached" mode . The result is stored in the _attrs array which is provided
* by the calling code .
*
* @ param { Array } _attrs an array of attributes
* /
et2 _link . prototype . getDetachedAttributes = function ( _attrs ) {
_attrs . push ( "label" , "value" ) ;
} ;
/ * *
* Returns an array of DOM nodes . The ( relatively ) same DOM - Nodes have to be
* passed to the "setDetachedAttributes" function in the same order .
* /
et2 _link . prototype . getDetachedNodes = function ( ) {
return [ this . node , this . link [ 0 ] ] ;
} ;
/ * *
* Sets the given associative attribute - > value array and applies the
* attributes to the given DOM - Node .
*
* @ param _nodes is an array of nodes which have to be in the same order as
* the nodes returned by "getDetachedNodes"
* @ param _values is an associative array which contains a subset of attributes
* returned by the "getDetachedAttributes" function and sets them to the
* given values .
* /
et2 _link . prototype . setDetachedAttributes = function ( _nodes , _values ) {
this . node = _nodes [ 0 ] ;
this . label _span = jQuery ( _nodes [ 0 ] ) ;
this . link = jQuery ( _nodes [ 1 ] ) ;
if ( typeof _values [ "id" ] !== "undefined" )
this . set _id ( _values [ 'id' ] ) ;
if ( typeof _values [ "label" ] !== "undefined" )
this . set _label ( _values [ 'label' ] ) ;
if ( typeof _values [ "value" ] !== "undefined" )
this . set _value ( _values [ "value" ] ) ;
} ;
et2 _link . _attributes = {
"only_app" : {
"name" : "Application" ,
"type" : "string" ,
"default" : "" ,
"description" : "Use the given application, so you can pass just the ID for value"
} ,
"value" : {
description : "Array with keys app, id, and optionally title" ,
type : "any"
} ,
"needed" : {
"ignore" : true
} ,
"link_hook" : {
"name" : "Type" ,
"type" : "string" ,
"default" : "view" ,
"description" : "Hook used for displaying link (view/edit/add)"
} ,
"target_app" : {
"name" : "Target application" ,
"type" : "string" ,
"default" : "" ,
"description" : "Optional parameter to be passed to egw().open in order to open links in specified application"
2020-02-16 11:31:32 +01:00
} ,
"extra_link_target" : {
"name" : "Link target" ,
"type" : "string" ,
"default" : null ,
"description" : "Optional parameter to be passed to egw().open in order to open links in specified target eg. _blank"
2021-02-03 14:14:22 +01:00
} ,
"break_title" : {
"name" : "break title" ,
"type" : "string" ,
"default" : null ,
"description" : "Breaks title into multiple lines based on selected delimiter by replacing it with '\r\n'"
2020-02-05 21:48:50 +01:00
}
} ;
2020-03-30 18:28:48 +02:00
et2 _link . legacyOptions = [ "only_app" ] ;
2020-02-05 21:48:50 +01:00
return et2 _link ;
} ( et2 _core _valueWidget _1 . et2 _valueWidget ) ) ;
exports . et2 _link = et2 _link ;
et2 _core _widget _1 . et2 _register _widget ( et2 _link , [ "link" , "link-entry_ro" ] ) ;
2011-09-13 01:43:39 +02:00
/ * *
* UI widget for one or more links , comma separated
2014-02-11 13:17:08 +01:00
*
2020-02-05 21:48:50 +01:00
* TODO : This one used to have expose
2014-02-11 13:17:08 +01:00
* /
2020-02-20 17:46:53 +01:00
var et2 _link _string = /** @class */ ( function ( _super ) {
_ _extends ( et2 _link _string , _super ) ;
function et2 _link _string ( ) {
return _super !== null && _super . apply ( this , arguments ) || this ;
}
return et2 _link _string ;
} ( expose ( ( _a = /** @class */ ( function ( _super ) {
2020-02-19 17:14:44 +01:00
_ _extends ( et2 _link _string , _super ) ;
/ * *
* Constructor
*
* @ memberOf et2 _link _string
* /
function et2 _link _string ( _parent , _attrs , _child ) {
var _this = _super . call ( this , _parent , _attrs , et2 _core _inheritance _1 . ClassWithAttributes . extendAttributes ( et2 _link _string . _attributes , _child || { } ) ) || this ;
_this . list = jQuery ( document . createElement ( "ul" ) )
. addClass ( "et2_link_string" ) ;
if ( _this . options [ 'class' ] )
_this . list . addClass ( _this . options [ 'class' ] ) ;
_this . setDOMNode ( _this . list [ 0 ] ) ;
return _this ;
}
et2 _link _string . prototype . destroy = function ( ) {
_super . prototype . destroy . apply ( this , arguments ) ;
if ( this . node != null ) {
jQuery ( this . node ) . children ( ) . unbind ( ) ;
2020-02-12 21:21:05 +01:00
}
2020-02-19 17:14:44 +01:00
} ;
et2 _link _string . prototype . set _value = function ( _value ) {
// Get data
if ( ! _value || _value == null || ! this . list ) {
// List can be missing if the AJAX call returns after the form is destroyed
if ( this . list ) {
this . list . empty ( ) ;
}
return ;
}
if ( typeof _value == "string" && _value . indexOf ( ',' ) > 0 ) {
_value = _value . split ( ',' ) ;
}
if ( ! _value . to _app && typeof _value == "object" && this . options . application ) {
_value . to _app = this . options . application ;
}
if ( typeof _value == 'object' && _value . to _app && _value . to _id ) {
this . value = _value ;
this . _get _links ( ) ;
return ;
}
this . list . empty ( ) ;
if ( typeof _value == 'object' && _value . length > 0 ) {
// Have full info
// Don't store new value, just update display
// Make new links
for ( var i = 0 ; i < _value . length ; i ++ ) {
if ( ! this . options . only _app || this . options . only _app && _value [ i ] . app == this . options . only _app ) {
this . _add _link ( _value [ i ] . id ? _value [ i ] : { id : _value [ i ] , app : _value . to _app } ) ;
}
}
}
else if ( this . options . application ) {
this . _add _link ( { id : _value , app : this . options . application } ) ;
}
} ;
et2 _link _string . prototype . _get _links = function ( ) {
var _value = this . value ;
// Just IDs - get from server
if ( this . options . only _app ) {
_value . only _app = this . options . only _app ;
}
this . egw ( ) . jsonq ( 'EGroupware\\Api\\Etemplate\\Widget\\Link::ajax_link_list' , [ _value ] , this . set _value , this ) ;
2020-02-05 21:48:50 +01:00
return ;
2020-02-19 17:14:44 +01:00
} ;
/ * *
* Function to get media content to feed the expose
* @ param { type } _value
* @ returns { Array | Array . getMedia . mediaContent }
* /
et2 _link _string . prototype . getMedia = function ( _value ) {
var base _url = egw . webserverUrl . match ( /^\// , 'ig' ) ? egw ( window ) . window . location . origin + egw . webserverUrl : egw . webserverUrl ;
var mediaContent = [ ] ;
2021-03-16 13:23:54 +01:00
if ( _value && typeof _value . type != 'undefined' && _value . type . match ( /video\/|audio\// , 'ig' ) ) {
2020-02-19 17:14:44 +01:00
mediaContent = [ {
title : _value . id ,
type : _value . type ,
poster : '' ,
href : base _url + egw ( ) . mime _open ( _value ) ,
download _href : base _url + egw ( ) . mime _open ( _value ) + '?download'
} ] ;
}
else if ( _value ) {
mediaContent = [ {
title : _value . id ,
href : base _url + egw ( ) . mime _open ( _value ) . url ,
download _href : base _url + egw ( ) . mime _open ( _value ) . url + '?download' ,
type : _value . type
} ] ;
}
if ( mediaContent [ 0 ] . href && mediaContent [ 0 ] . href . match ( /\/webdav.php/ , 'ig' ) )
mediaContent [ 0 ] [ "download_href" ] = mediaContent [ 0 ] . href + '?download' ;
return mediaContent ;
} ;
et2 _link _string . prototype . _add _link = function ( _link _data ) {
var self = this ;
var link = jQuery ( document . createElement ( "li" ) )
. appendTo ( this . list )
. addClass ( "et2_link loading" )
. click ( function ( e ) {
var fe = egw _get _file _editor _prefered _mimes ( _link _data . type ) ;
if ( self . options . expose _view && typeof _link _data . type != 'undefined'
2021-03-16 13:23:54 +01:00
&& _link _data . type . match ( self . mime _regexp , 'ig' ) && ! _link _data . type . match ( self . mime _audio _regexp , 'ig' ) ) {
2020-02-19 17:14:44 +01:00
self . _init _blueimp _gallery ( e , _link _data ) ;
}
2021-03-22 18:18:16 +01:00
else if ( _link _data . type && _link _data . type . match ( self . mime _audio _regexp , 'ig' ) ) {
2021-03-16 13:23:54 +01:00
self . _audio _player ( _link _data ) ;
}
2020-02-19 17:14:44 +01:00
else if ( typeof _link _data . type != 'undefined' && fe && fe . mime && fe . mime [ _link _data . type ] ) {
egw . open _link ( egw . link ( '/index.php' , {
menuaction : fe . edit . menuaction ,
path : egw ( ) . mime _open ( _link _data ) . url . replace ( '/webdav.php' , '' )
} ) , '' , fe . edit _popup ) ;
2020-02-05 21:48:50 +01:00
}
2020-02-19 17:14:44 +01:00
else {
self . egw ( ) . open ( _link _data , "" , "view" , null , _link _data . app , _link _data . app ) ;
}
e . stopImmediatePropagation ( ) ;
} ) ;
2021-05-10 19:00:41 +02:00
if ( _link _data . title ) {
link . text ( _link _data . title )
. removeClass ( "loading" ) ;
}
2020-02-19 17:14:44 +01:00
// Now that link is created, get title from server & update
2021-05-10 19:00:41 +02:00
else {
2020-02-19 17:14:44 +01:00
this . egw ( ) . link _title ( _link _data . app , _link _data . id , function ( title ) {
if ( title )
this . removeClass ( "loading" ) . text ( title ) ;
else
this . remove ( ) ; // no rights or not found
} , link ) ;
2020-02-05 21:48:50 +01:00
}
2020-02-19 17:14:44 +01:00
} ;
/ * *
* Creates a list of attributes which can be set when working in the
* "detached" mode . The result is stored in the _attrs array which is provided
* by the calling code .
*
* @ param { Array } _attrs an array of attributes
* /
et2 _link _string . prototype . getDetachedAttributes = function ( _attrs ) {
// Create the label container if it didn't exist yet
if ( this . _labelContainer == null ) {
this . _labelContainer = jQuery ( document . createElement ( "label" ) )
. addClass ( "et2_label" ) ;
this . getSurroundings ( ) . insertDOMNode ( this . _labelContainer [ 0 ] ) ;
this . getSurroundings ( ) . update ( ) ;
2020-02-05 21:48:50 +01:00
}
2020-02-19 17:14:44 +01:00
_attrs . push ( "value" , "label" ) ;
} ;
/ * *
* Returns an array of DOM nodes . The ( relatively ) same DOM - Nodes have to be
* passed to the "setDetachedAttributes" function in the same order .
* /
et2 _link _string . prototype . getDetachedNodes = function ( ) {
// Create the label container if it didn't exist yet
if ( this . _labelContainer == null ) {
this . _labelContainer = jQuery ( document . createElement ( "label" ) )
. addClass ( "et2_label" ) ;
this . getSurroundings ( ) . insertDOMNode ( this . _labelContainer [ 0 ] ) ;
2020-02-05 21:48:50 +01:00
}
2020-02-19 17:14:44 +01:00
return [ this . list [ 0 ] , this . _labelContainer [ 0 ] ] ;
} ;
/ * *
* Sets the given associative attribute - > value array and applies the
* attributes to the given DOM - Node .
*
* @ param _nodes is an array of nodes which have to be in the same order as
* the nodes returned by "getDetachedNodes"
* @ param _values is an associative array which contains a subset of attributes
* returned by the "getDetachedAttributes" function and sets them to the
* given values .
* /
et2 _link _string . prototype . setDetachedAttributes = function ( _nodes , _values ) {
this . list = jQuery ( _nodes [ 0 ] ) ;
this . set _value ( _values [ "value" ] ) ;
// Special detached, to prevent DOM node modification of the normal method
this . _labelContainer = _nodes . length > 1 ? jQuery ( _nodes [ 1 ] ) : null ;
if ( _values [ 'label' ] ) {
this . set _label ( _values [ 'label' ] ) ;
2020-02-05 21:48:50 +01:00
}
2020-02-19 17:14:44 +01:00
else if ( this . _labelContainer ) {
this . _labelContainer . contents ( ) . not ( this . list ) . remove ( ) ;
}
} ;
return et2 _link _string ;
} ( et2 _core _valueWidget _1 . et2 _valueWidget ) ) ,
_a . _attributes = {
2020-02-05 21:48:50 +01:00
"application" : {
"name" : "Application" ,
"type" : "string" ,
"default" : "" ,
"description" : "Use the given application, so you can pass just the ID for value"
} ,
"value" : {
"description" : "Either an array of link information (see egw_link::link()) or array with keys to_app and to_id" ,
"type" : "any"
} ,
"only_app" : {
"name" : "Application filter" ,
"type" : "string" ,
"default" : "" ,
"description" : "Appname, eg. 'projectmananager' to list only linked projects"
} ,
"link_type" : {
"name" : "Type filter" ,
"type" : "string" ,
"default" : "" ,
"description" : "Sub-type key to list only entries of that type"
} ,
"expose_view" : {
name : "Expose view" ,
type : "boolean" ,
2020-02-19 17:14:44 +01:00
default : true ,
2020-02-05 21:48:50 +01:00
description : "Clicking on description with href value would popup an expose view, and will show content referenced by href."
}
2020-02-19 17:14:44 +01:00
} ,
2020-02-20 17:46:53 +01:00
_a ) ) ) ) ;
exports . et2 _link _string = et2 _link _string ;
;
et2 _core _widget _1 . et2 _register _widget ( et2 _link _string , [ "link-string" ] ) ;
2011-09-14 02:06:04 +02:00
/ * *
* UI widget for one or more links in a list ( table )
2014-02-11 13:17:08 +01:00
* /
2020-02-05 21:48:50 +01:00
var et2 _link _list = /** @class */ ( function ( _super ) {
_ _extends ( et2 _link _list , _super ) ;
/ * *
* Constructor
*
* /
function et2 _link _list ( _parent , _attrs , _child ) {
2020-02-05 23:27:24 +01:00
var _this = _super . call ( this , _parent , _attrs , et2 _core _inheritance _1 . ClassWithAttributes . extendAttributes ( et2 _link _list . _attributes , _child || { } ) ) || this ;
2020-02-05 21:48:50 +01:00
_this . list = jQuery ( document . createElement ( "table" ) )
. addClass ( "et2_link_list" ) ;
if ( _this . options [ 'class' ] )
_this . list . addClass ( _this . options [ 'class' ] ) ;
_this . setDOMNode ( _this . list [ 0 ] ) ;
// Set up context menu
var self = _this ;
_this . context = new egwMenu ( ) ;
_this . context . addItem ( "comment" , _this . egw ( ) . lang ( "Comment" ) , "" , function ( ) {
var link _id = typeof self . context . data . link _id == 'number' ? self . context . data . link _id : self . context . data . link _id . replace ( /[:\.]/g , '_' ) ;
2020-12-21 21:53:24 +01:00
et2 _widget _dialog _1 . et2 _dialog . show _prompt ( function ( button , comment ) {
if ( button != et2 _widget _dialog _1 . et2 _dialog . OK _BUTTON )
2020-02-05 21:48:50 +01:00
return ;
var remark = jQuery ( '#link_' + ( self . context . data . dom _id ? self . context . data . dom _id : link _id ) , self . list ) . children ( '.remark' ) ;
if ( isNaN ( self . context . data . link _id ) ) // new entry, not yet stored
{
remark . text ( comment ) ;
// Look for a link-to with the same ID, refresh it
if ( self . context . data . link _id ) {
var _widget = link _id . widget || null ;
self . getRoot ( ) . iterateOver ( function ( widget ) {
if ( widget . id == self . id ) {
_widget = widget ;
}
} , self , et2 _link _to ) ;
var value = _widget != null ? _widget . getValue ( ) : false ;
if ( _widget && value && value . to _id ) {
value . to _id [ self . context . data . link _id ] . remark = comment ;
}
}
return ;
}
remark . addClass ( "loading" ) ;
var request = egw . json ( "EGroupware\\Api\\Etemplate\\Widget\\Link::ajax_link_comment" , [ link _id , comment ] , function ( ) {
if ( remark ) {
// Append "" to make sure it's a string, not undefined
remark . removeClass ( "loading" ) . text ( comment + "" ) ;
// Update internal data
self . context . data . remark = comment + "" ;
}
} , this , true ) . sendRequest ( ) ;
} , '' , self . egw ( ) . lang ( "Comment" ) , self . context . data . remark || '' ) ;
} ) ;
_this . context . addItem ( "file_info" , _this . egw ( ) . lang ( "File information" ) , _this . egw ( ) . image ( "edit" ) , function ( menu _item ) {
var link _data = self . context . data ;
if ( link _data . app == 'file' ) {
// File info is always the same
var url = '/apps/' + link _data . app2 + '/' + link _data . id2 + '/' + decodeURIComponent ( link _data . id ) ;
if ( typeof url == 'string' && url . indexOf ( 'webdav.php' ) ) {
// URL is url to file in webdav, so get rid of that part
url = url . replace ( '/webdav.php' , '' ) ;
}
self . egw ( ) . open ( url , "filemanager" , "edit" ) ;
}
} ) ;
_this . context . addItem ( "-" , "-" ) ;
_this . context . addItem ( "save" , _this . egw ( ) . lang ( "Save as" ) , _this . egw ( ) . image ( 'save' ) , function ( menu _item ) {
var link _data = self . context . data ;
// Download file
if ( link _data . download _url ) {
var url = link _data . download _url ;
if ( url [ 0 ] == '/' )
url = egw . link ( url ) ;
var a = document . createElement ( 'a' ) ;
if ( typeof a . download == "undefined" ) {
window . location . href = url + "?download" ;
return false ;
}
// Multiple file download for those that support it
a = jQuery ( a )
. prop ( 'href' , url )
. prop ( 'download' , link _data . title || "" )
. appendTo ( self . getInstanceManager ( ) . DOMContainer ) ;
var evt = document . createEvent ( 'MouseEvent' ) ;
evt . initMouseEvent ( 'click' , true , true , window , 1 , 0 , 0 , 0 , 0 , false , false , false , false , 0 , null ) ;
a [ 0 ] . dispatchEvent ( evt ) ;
a . remove ( ) ;
return false ;
}
self . egw ( ) . open ( link _data , "" , "view" , 'download' , link _data . target ? link _data . target : link _data . app , link _data . app ) ;
} ) ;
_this . context . addItem ( "zip" , _this . egw ( ) . lang ( "Save as Zip" ) , _this . egw ( ) . image ( 'save_zip' ) , function ( menu _item ) {
// Highlight files for nice UI indicating what will be in the zip.
// Files have negative IDs.
jQuery ( '[id^="link_-"]' , this . list ) . effect ( 'highlight' , { } , 2000 ) ;
// Download ZIP
window . location = self . egw ( ) . link ( '/index.php' , {
menuaction : 'api.EGroupware\\Api\\Etemplate\\Widget\\Link.download_zip' ,
app : self . value . to _app ,
id : self . value . to _id
} ) ;
} ) ;
2020-12-21 21:53:24 +01:00
// Only allow this option if the entry has been saved, and has a real ID
if ( self . options . value && self . options . value . to _id && typeof self . options . value . to _id != 'object' ) {
_this . context . addItem ( "copy_to" , _this . egw ( ) . lang ( "Copy to" ) , _this . egw ( ) . image ( 'copy' ) , function ( menu _item ) {
// Highlight files for nice UI indicating what will be copied
jQuery ( '[id="link_' + self . context . data . link _id + ']' , this . list ) . effect ( 'highlight' , { } , 2000 ) ;
// Get target
var select _attrs = {
mode : "select-dir" ,
button _caption : '' ,
button _icon : 'copy' ,
button _label : egw . lang ( "copy" ) ,
//extra_buttons: [{text: egw.lang("link"), id:"link", image: "link"}],
dialog _title : egw . lang ( 'Copy to' ) ,
method : "EGroupware\\Api\\Etemplate\\Widget\\Link::ajax_copy_to" ,
method _id : self . context . data
} ;
var vfs _select = et2 _core _widget _1 . et2 _createWidget ( "vfs-select" , select _attrs , self ) ;
// No button, just open it
vfs _select . button . hide ( ) ;
vfs _select . click ( null ) ;
} ) ;
}
2020-02-05 21:48:50 +01:00
_this . context . addItem ( "-" , "-" ) ;
_this . context . addItem ( "delete" , _this . egw ( ) . lang ( "Delete link" ) , _this . egw ( ) . image ( "delete" ) , function ( menu _item ) {
var link _id = isNaN ( self . context . data . link _id ) ? self . context . data : self . context . data . link _id ;
var row = jQuery ( '#link_' + ( self . context . data . dom _id ? self . context . data . dom _id : self . context . data . link _id ) , self . list ) ;
2020-12-21 21:53:24 +01:00
et2 _widget _dialog _1 . et2 _dialog . show _dialog ( function ( button ) { if ( button == et2 _widget _dialog _1 . et2 _dialog . YES _BUTTON )
2020-02-05 21:48:50 +01:00
self . _delete _link ( link _id , row ) ; } , egw . lang ( 'Delete link?' ) ) ;
} ) ;
// Native DnD - Doesn't play nice with jQueryUI Sortable
// Tell jQuery to include this property
jQuery . event . props . push ( 'dataTransfer' ) ;
return _this ;
}
et2 _link _list . prototype . destroy = function ( ) {
_super . prototype . destroy . apply ( this , arguments ) ;
if ( this . context ) {
this . context . clear ( ) ;
delete this . context ;
}
} ;
et2 _link _list . prototype . set _value = function ( _value ) {
this . list . empty ( ) ;
// Handle server passed a list of links that aren't ready yet
if ( _value && typeof _value == "object" ) {
var list = [ ] ;
if ( _value . to _id && typeof _value . to _id == "object" ) {
list = _value . to _id ;
}
else if ( _value . length ) {
list = _value ;
}
if ( list . length > 0 ) {
for ( var id in list ) {
var link = list [ id ] ;
if ( link . app ) {
// Temp IDs can cause problems since the ID includes the file name or :
if ( link . link _id && typeof link . link _id != 'number' ) {
link . dom _id = 'temp_' + egw . uid ( ) ;
}
// Icon should be in registry
if ( ! link . icon ) {
link . icon = egw . link _get _registry ( link . app , 'icon' ) ;
// No icon, try by mime type - different place for un-saved entries
if ( link . icon == false && link . id . type ) {
// Triggers icon by mime type, not thumbnail or app
link . type = link . id . type ;
link . icon = true ;
}
}
// Special handling for file - if not existing, we can't ask for title
if ( typeof link . id == 'object' && ! link . title ) {
link . title = link . id . name || '' ;
}
this . _add _link ( link ) ;
}
}
}
else {
_super . prototype . set _value . call ( this , _value ) ;
}
}
} ;
et2 _link _list . prototype . _add _link = function ( _link _data ) {
var row = jQuery ( document . createElement ( "tr" ) )
. attr ( "id" , "link_" + ( _link _data . dom _id ? _link _data . dom _id : ( typeof _link _data . link _id == "string" ? _link _data . link _id . replace ( /[:\.]/g , '_' ) : _link _data . link _id || _link _data . id ) ) )
. attr ( "draggable" , _link _data . app == 'file' ? "true" : "" )
. appendTo ( this . list ) ;
if ( ! _link _data . link _id ) {
for ( var k in _link _data ) {
row [ 0 ] . dataset [ k ] = _link _data [ k ] ;
}
}
// Icon
var icon = jQuery ( document . createElement ( "td" ) )
. appendTo ( row )
. addClass ( "icon" ) ;
if ( _link _data . icon ) {
2020-12-21 21:53:24 +01:00
var icon _widget = et2 _core _widget _1 . et2 _createWidget ( "image" , { } ) ;
2020-02-05 21:48:50 +01:00
var src = '' ;
// Creat a mime widget if the link has type
if ( _link _data . type ) {
// VFS - file
2020-12-21 21:53:24 +01:00
var vfs _widget = et2 _core _widget _1 . et2 _createWidget ( 'vfs-mime' , { } ) ;
2020-02-05 21:48:50 +01:00
vfs _widget . set _value ( {
download _url : _link _data . download _url ,
name : _link _data . title ,
mime : _link _data . type ,
path : _link _data . icon
} ) ;
icon . append ( vfs _widget . getDOMNode ( ) ) ;
}
else {
src = this . egw ( ) . image ( _link _data . icon ) ;
if ( src )
icon _widget . set _src ( src ) ;
icon . append ( icon _widget . getDOMNode ( ) ) ;
}
}
var columns = [ 'title' , 'remark' ] ;
var self = this ;
for ( var i = 0 ; i < columns . length ; i ++ ) {
var $td = jQuery ( document . createElement ( "td" ) )
. appendTo ( row )
. addClass ( columns [ i ] )
. text ( _link _data [ columns [ i ] ] ? _link _data [ columns [ i ] ] + "" : "" ) ;
var dirs = _link _data [ columns [ i ] ] ? _link _data [ columns [ i ] ] . split ( '/' ) : [ ] ;
if ( columns [ i ] == 'title' && _link _data . type && dirs . length > 1 ) {
this . _format _vfs ( $td , dirs , _link _data ) ;
}
//Bind the click handler if there is download_url
if ( _link _data && ( typeof _link _data . download _url != 'undefined' || _link _data . app != 'egw-data' ) ) {
$td . click ( function ( ) {
var fe _mime = egw _get _file _editor _prefered _mimes ( _link _data . type ) ;
// Check if the link entry is mime with media type, in order to open it in expose view
if ( typeof _link _data . type != 'undefined' &&
( _link _data . type . match ( self . mime _regexp , 'ig' ) || ( fe _mime && fe _mime . mime [ _link _data . type ] ) ) ) {
var $vfs _img _node = jQuery ( this ) . parent ( ) . find ( '.vfsMimeIcon' ) ;
if ( $vfs _img _node . length > 0 )
$vfs _img _node . click ( ) ;
}
else {
if ( ! self . options . target _app ) {
self . options . target _app = _link _data . app ;
}
self . egw ( ) . open ( _link _data , "" , "view" , null , _link _data . target ? _link _data . target : _link _data . app , self . options . target _app ) ;
}
} ) ;
}
}
if ( typeof _link _data . title == 'undefined' ) {
// Title will be fetched from server and then set
jQuery ( 'td.title' , row ) . addClass ( "loading" ) ;
var title = this . egw ( ) . link _title ( _link _data . app , _link _data . id , function ( title ) {
jQuery ( 'td.title' , this ) . removeClass ( "loading" ) . text ( title + "" ) ;
} , row ) ;
}
// Date
/ *
var date _row = jQuery ( document . createElement ( "td" ) )
. appendTo ( row ) ;
if ( _link _data . lastmod )
{
var date _widget = et2 _createWidget ( "date-since" ) ;
date _widget . set _value ( _link _data . lastmod ) ;
date _row . append ( date _widget . getDOMNode ( ) ) ;
}
* /
// Delete
// build delete button if the link is not readonly
if ( ! this . options . readonly ) {
var delete _button = jQuery ( document . createElement ( "td" ) )
. appendTo ( row ) ;
jQuery ( "<div />" )
. appendTo ( delete _button )
// We don't use ui-icon because it assigns a bg image
. addClass ( "delete icon" )
. bind ( 'click' , function ( ) {
2020-12-21 21:53:24 +01:00
et2 _widget _dialog _1 . et2 _dialog . show _dialog ( function ( button ) {
if ( button == et2 _widget _dialog _1 . et2 _dialog . YES _BUTTON ) {
2020-02-05 21:48:50 +01:00
self . _delete _link ( self . value && typeof self . value . to _id != 'object' && _link _data . link _id ? _link _data . link _id : _link _data , row ) ;
}
} , egw . lang ( 'Delete link?' ) ) ;
} ) ;
}
// Context menu
row . bind ( "contextmenu" , function ( e ) {
// Comment only available if link_id is there and not readonly
self . context . getItem ( "comment" ) . set _enabled ( typeof _link _data . link _id != 'undefined' && ! self . options . readonly ) ;
// File info only available for existing files
self . context . getItem ( "file_info" ) . set _enabled ( typeof _link _data . id != 'object' && _link _data . app == 'file' ) ;
self . context . getItem ( "save" ) . set _enabled ( typeof _link _data . id != 'object' && _link _data . app == 'file' ) ;
// Zip download only offered if there are at least 2 files
self . context . getItem ( "zip" ) . set _enabled ( jQuery ( '[id^="link_-"]' , this . list ) . length >= 2 ) ;
// Show delete item only if the widget is not readonly
self . context . getItem ( "delete" ) . set _enabled ( ! self . options . readonly ) ;
self . context . data = _link _data ;
self . context . showAt ( e . pageX , e . pageY , true ) ;
e . preventDefault ( ) ;
} ) ;
// Drag - adapted from egw_action_dragdrop, sidestepping action system
// so all linked files get it
// // Unfortunately, dragging files is currently only supported by Chrome
if ( navigator && navigator . userAgent . indexOf ( 'Chrome' ) >= 0 ) {
row . on ( "dragstart" , _link _data , function ( event ) {
if ( event . dataTransfer == null ) {
return ;
}
var data = event . data || { } ;
if ( data && data . type && data . download _url ) {
event . dataTransfer . dropEffect = "copy" ;
event . dataTransfer . effectAllowed = "copy" ;
var url = data . download _url ;
// NEED an absolute URL
if ( url [ 0 ] == '/' )
url = egw . link ( url ) ;
// egw.link adds the webserver, but that might not be an absolute URL - try again
if ( url [ 0 ] == '/' )
url = window . location . origin + url ;
// Unfortunately, dragging files is currently only supported by Chrome
if ( navigator && navigator . userAgent . indexOf ( 'Chrome' ) ) {
event . dataTransfer . setData ( "DownloadURL" , data . type + ':' + data . title + ':' + url ) ;
}
// Include URL as a fallback
event . dataTransfer . setData ( "text/uri-list" , url ) ;
}
if ( event . dataTransfer . types . length == 0 ) {
// No file data? Abort: drag does nothing
event . preventDefault ( ) ;
return ;
}
//event.dataTransfer.setDragImage(event.delegate.target,0,0);
var div = jQuery ( document . createElement ( "div" ) )
. attr ( 'id' , 'drag_helper' )
. css ( {
position : 'absolute' ,
top : '0px' ,
left : '0px' ,
width : '300px'
} ) ;
div . append ( event . target . cloneNode ( true ) ) ;
self . list . append ( div ) ;
event . dataTransfer . setDragImage ( div . get ( 0 ) , 0 , 0 ) ;
} )
. on ( 'drag' , function ( ) {
jQuery ( '#drag_helper' , self . list ) . remove ( ) ;
} ) ;
}
} ;
et2 _link _list . prototype . _delete _link = function ( link _id , row ) {
if ( row ) {
var delete _button = jQuery ( '.delete' , row ) ;
delete _button . removeClass ( "delete" ) . addClass ( "loading" ) ;
row . off ( ) ;
}
if ( this . onchange ) {
this . onchange ( this , link _id , row ) ;
}
if ( typeof link _id != "object" ) {
egw . json ( "EGroupware\\Api\\Etemplate\\Widget\\Link::ajax_delete" , [ link _id ] , function ( data ) { if ( data ) {
row . slideUp ( row . remove ) ;
} } ) . sendRequest ( ) ;
}
else if ( row ) {
// No link ID means a link on an unsaved entry.
// Just remove the row, but need to adjust the link_to value also
row . slideUp ( row . remove ) ;
// Look for a link-to with the same ID, refresh it
if ( link _id . link _id ) {
var self = this ;
var _widget = link _id . widget || null ;
this . getRoot ( ) . iterateOver ( function ( widget ) {
if ( widget . id == self . id ) {
_widget = widget ;
}
} , this , et2 _link _to ) ;
var value = _widget != null ? _widget . getValue ( ) : false ;
if ( _widget && value && value . to _id ) {
delete value . to _id [ link _id . link _id ] ;
_widget . set _value ( value ) ;
}
}
}
} ;
/ * *
* When the link is to a VFS file , we do some special formatting .
*
* Instead of listing the full path , we use
* Path : - filename
* When multiple files from the same directory are linked , we exclude
* the directory name from all but the first link to that directory
*
* @ param { JQuery } $td Current table data cell for the title
* @ param { String [ ] } dirs List of directories in the linked file ' s path
* @ param { String [ ] } _link _data Data for the egw _link
* @ returns { undefined }
* /
et2 _link _list . prototype . _format _vfs = function ( $td , dirs , _link _data ) {
// Keep it here for matching next row
$td . attr ( 'data-title' , _link _data [ 'title' ] ) ;
// VFS link - check for same dir as above, and hide dir
var reformat = false ;
var span _size = 1 ;
var prev = jQuery ( 'td.title' , $td . parent ( ) . prev ( 'tr' ) ) ;
if ( prev . length === 1 ) {
var prev _dirs = ( prev . attr ( 'data-title' ) || '' ) . split ( '/' ) ;
if ( prev _dirs . length > 1 && prev _dirs . length == dirs . length ) {
for ( var i = 0 ; i < dirs . length ; i ++ ) {
// Current is same as prev, blank it
if ( dirs [ i ] === prev _dirs [ i ] ) {
reformat = true ;
span _size += dirs [ i ] . length + 1 ;
dirs [ i ] = '' ;
}
else {
break ;
}
}
}
}
var filename = dirs . pop ( ) ;
if ( reformat && ( dirs . length - i ) === 0 ) {
$td . html ( '<span style="display: inline-block; width:' + span _size + 'ex;"></span> - ' + filename ) ;
}
else {
// Different format for directory
span _size += dirs . join ( '/' ) . length + 1 ;
$td . html ( '<span style="display: inline-block; text-align: right; width:' + span _size + 'ex;">' + dirs . join ( '/' ) + ':</span> - ' + filename ) ;
}
} ;
2020-02-07 17:31:10 +01:00
et2 _link _list . _attributes = {
2020-02-05 21:48:50 +01:00
"show_deleted" : {
"name" : "Show deleted" ,
"type" : "boolean" ,
"default" : false ,
"description" : "Show links that are marked as deleted, being held for purge"
} ,
"onchange" : {
"name" : "onchange" ,
"type" : "js" ,
"default" : et2 _no _init ,
"description" : "JS code which is executed when the links change."
} ,
readonly : {
name : "readonly" ,
type : "boolean" ,
"default" : false ,
description : "Does NOT allow user to enter data, just displays existing data"
} ,
"target_app" : {
"name" : "Target application" ,
"type" : "string" ,
"default" : "" ,
"description" : "Optional parameter to be passed to egw().open in order to open links in specified application "
}
} ;
return et2 _link _list ;
2020-02-20 17:46:53 +01:00
} ( et2 _link _string ) ) ;
2020-02-05 21:48:50 +01:00
exports . et2 _link _list = et2 _link _list ;
et2 _core _widget _1 . et2 _register _widget ( et2 _link _list , [ "link-list" ] ) ;
2011-09-14 22:36:39 +02:00
/ * *
2014-02-11 13:17:08 +01:00
*
2020-02-05 21:48:50 +01:00
*
2014-02-11 13:17:08 +01:00
* /
2020-02-05 21:48:50 +01:00
var et2 _link _add = /** @class */ ( function ( _super ) {
_ _extends ( et2 _link _add , _super ) ;
/ * *
* Constructor
* /
function et2 _link _add ( _parent , _attrs , _child ) {
2020-02-05 23:27:24 +01:00
var _this = _super . call ( this , _parent , _attrs , et2 _core _inheritance _1 . ClassWithAttributes . extendAttributes ( et2 _link _add . _attributes , _child || { } ) ) || this ;
2020-02-05 21:48:50 +01:00
_this . span = jQuery ( document . createElement ( "span" ) )
. text ( _this . egw ( ) . lang ( "Add new" ) )
. addClass ( 'et2_link_add_span' ) ;
_this . div = jQuery ( document . createElement ( "div" ) ) . append ( _this . span ) ;
_this . setDOMNode ( _this . div [ 0 ] ) ;
return _this ;
}
et2 _link _add . prototype . doLoadingFinished = function ( ) {
_super . prototype . doLoadingFinished . apply ( this , arguments ) ;
if ( this . app _select && this . button ) {
// Already done
return false ;
}
2020-12-21 21:53:24 +01:00
this . app _select = et2 _core _widget _1 . et2 _createWidget ( "link-apps" , jQuery . extend ( { } , this . options , {
2020-02-05 21:48:50 +01:00
'id' : this . options . id + 'app' ,
value : this . options . application ? this . options . application : this . options . value && this . options . value . add _app ? this . options . value . add _app : null ,
application _list : this . options . application ? this . options . application : null
} ) , this ) ;
this . div . append ( this . app _select . getDOMNode ( ) ) ;
2020-12-21 21:53:24 +01:00
this . button = et2 _core _widget _1 . et2 _createWidget ( "button" , { id : this . options . id + "_add" , label : this . egw ( ) . lang ( "add" ) } , this ) ;
2020-02-05 21:48:50 +01:00
this . button . set _label ( this . egw ( ) . lang ( "add" ) ) ;
var self = this ;
this . button . click = function ( ) {
self . egw ( ) . open ( self . options . value . to _app + ":" + self . options . value . to _id , self . app _select . get _value ( ) , 'add' ) ;
return false ;
} ;
this . div . append ( this . button . getDOMNode ( ) ) ;
return true ;
} ;
/ * *
* Should be handled client side .
* Return null to avoid overwriting other link values , in case designer used the same ID for multiple widgets
* /
et2 _link _add . prototype . getValue = function ( ) {
return null ;
} ;
et2 _link _add . _attributes = {
"value" : {
"description" : "Either an array of link information (see egw_link::link()) or array with keys to_app and to_id" ,
"type" : "any"
} ,
"application" : {
"name" : "Application" ,
"type" : "string" ,
"default" : "" ,
"description" : "Limit to the listed application or applications (comma seperated)"
}
} ;
return et2 _link _add ;
} ( et2 _core _inputWidget _1 . et2 _inputWidget ) ) ;
exports . et2 _link _add = et2 _link _add ;
et2 _core _widget _1 . et2 _register _widget ( et2 _link _add , [ "link-add" ] ) ;
2020-02-19 17:14:44 +01:00
//# sourceMappingURL=et2_widget_link.js.map