2013-04-16 20:50:43 +02:00
/ * *
* EGroupware eTemplate2 - JS Dialog Widget class
*
* @ license http : //opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @ package etemplate
2021-06-07 17:33:53 +02:00
* @ link https : //www.egroupware.org
2013-04-16 20:50:43 +02:00
* @ author Nathan Gray
* @ copyright Nathan Gray 2013
* /
2020-01-22 16:08:34 +01:00
/ * e g w : u s e s
et2 _core _widget ;
/ 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 ;
* /
2021-06-07 17:33:53 +02:00
import { et2 _createWidget , et2 _register _widget } from "./et2_core_widget" ;
import { et2 _widget } from "./et2_core_widget" ;
import { et2 _button } from "./et2_widget_button" ;
import { ClassWithAttributes } from "./et2_core_inheritance" ;
import { etemplate2 } from "./etemplate2" ;
import { egw } from "../jsapi/egw_global" ;
import { et2 _no _init } from "./et2_core_common" ;
2013-04-16 20:50:43 +02:00
/ * *
* A common dialog widget that makes it easy to imform users or prompt for information .
*
2013-12-05 09:53:11 +01:00
* It is possible to have a custom dialog by using a template , but you can also use
2013-04-16 20:50:43 +02:00
* the static method et2 _dialog . show _dialog ( ) . At its simplest , you can just use :
* < code >
* et2 _dialog . show _dialog ( false , "Operation completed" ) ;
* < / c o d e >
* Or a more complete example :
* < code >
* var callback = function ( button _id )
* {
* if ( button _id == et2 _dialog . YES _BUTTON )
* {
* // Do stuff
* }
* else if ( button _id == et2 _dialog . NO _BUTTON )
* {
* // Other stuff
* }
* else if ( button _id == et2 _dialog . CANCEL _BUTTON )
* {
* // Abort
* }
* } .
* var dialog = et2 _dialog . show _dialog (
2013-05-21 22:23:35 +02:00
* callback , "Erase the entire database?" , "Break things" , { } // value
2013-04-16 20:50:43 +02:00
* et2 _dialog . BUTTONS _YES _NO _CANCEL , et2 _dialog . WARNING _MESSAGE
* ) ;
* < / c o d e >
2013-12-05 09:53:11 +01:00
*
2013-04-16 20:50:43 +02:00
*
* The parameters for the above are all optional , except callback and message :
* callback - function called when the dialog closes , or false / null .
* The ID of the button will be passed . Button ID will be one of the et2 _dialog . * _BUTTON constants .
* The callback is _not _ called if the user closes the dialog with the X in the corner , or presses ESC .
2013-10-03 17:27:00 +02:00
* message - ( plain ) text to display
2013-04-16 20:50:43 +02:00
* title - Dialog title
2013-05-21 22:23:35 +02:00
* value ( for prompt )
2013-04-16 20:50:43 +02:00
* buttons - et2 _dialog BUTTONS _ * constant , or an array of button settings
2013-05-21 22:23:35 +02:00
* dialog _type - et2 _dialog * _MESSAGE constant
2013-04-16 20:50:43 +02:00
* icon - URL of icon
*
2013-12-05 09:53:11 +01:00
* Note that these methods will _not _ block program flow while waiting for user input .
2013-04-16 20:50:43 +02:00
* The user ' s input will be provided to the callback .
*
* You can also use the standard et2 _createWidget ( ) to create a custom dialog using an etemplate , even setting all
* the buttons yourself .
* < code >
* var dialog = et2 _createWidget ( "dialog" , {
* // If you use a template, the second parameter will be the value of the template, as if it were submitted.
2016-03-15 22:59:42 +01:00
* callback : function ( button _id , value ) { ... } , // return false to prevent dialog closing
2013-04-16 20:50:43 +02:00
* buttons : [
* // These ones will use the callback, just like normal
* { text : egw . lang ( "OK" ) , id : "OK" , class = "ui-priority-primary" , default : true } ,
* { text : egw . lang ( "Yes" ) , id : "Yes" } ,
* { text : egw . lang ( "Sure" ) , id : "Sure" } ,
* { text : egw . lang ( "Maybe" ) , click : function ( ) {
* // If you override, 'this' will be the dialog DOMNode.
* // Things get more complicated.
* // Do what you like, but don't forget this line:
2016-06-02 16:51:15 +02:00
* jQuery ( this ) . dialog ( "close" )
2013-04-16 20:50:43 +02:00
* } , class = "ui-state-error" } ,
2013-12-05 09:53:11 +01:00
*
2013-04-16 20:50:43 +02:00
* ] ,
2013-08-26 21:10:26 +02:00
* title : 'Why would you want to do this?' ,
2013-04-16 20:50:43 +02:00
* template : "/egroupware/addressbook/templates/default/edit.xet" ,
* value : { content : { ... default values } , sel _options : { ... } ... }
* } ) ;
* < / c o d e >
* @ augments et2 _widget
* @ see http : //api.jqueryui.com/dialog/
* /
2021-06-07 17:33:53 +02:00
export class et2 _dialog extends et2 _widget {
constructor ( _parent , _attrs , _child ) {
super ( _parent , _attrs , ClassWithAttributes . extendAttributes ( et2 _dialog . _attributes , _child || { } ) ) ;
2020-01-21 19:22:54 +01:00
/ * *
* Details for dialog type options
* /
2021-06-07 17:33:53 +02:00
this . _dialog _types = [
2020-01-21 19:22:54 +01:00
//PLAIN_MESSAGE: 0
"" ,
//INFORMATION_MESSAGE: 1,
"dialog_info" ,
//QUESTION_MESSAGE: 2,
"dialog_help" ,
//WARNING_MESSAGE: 3,
"dialog_warning" ,
//ERROR_MESSAGE: 4,
"dialog_error"
] ;
2021-06-07 17:33:53 +02:00
this . _buttons = [
2020-01-21 19:22:54 +01:00
/ *
Pre - defined Button combos
- button ids copied from et2 _dialog static , since the constants are not defined yet
- image get replaced by 'style="background-image: url(' + egw . image ( image ) + ')' for an image prefixing text
* /
//BUTTONS_OK: 0,
[ { "button_id" : 1 , "text" : 'ok' , id : 'dialog[ok]' , image : 'check' , "default" : true } ] ,
//BUTTONS_OK_CANCEL: 1,
[
{ "button_id" : 1 , "text" : 'ok' , id : 'dialog[ok]' , image : 'check' , "default" : true } ,
{ "button_id" : 0 , "text" : 'cancel' , id : 'dialog[cancel]' , image : 'cancel' }
] ,
//BUTTONS_YES_NO: 2,
[
{ "button_id" : 2 , "text" : 'yes' , id : 'dialog[yes]' , image : 'check' , "default" : true } ,
{ "button_id" : 3 , "text" : 'no' , id : 'dialog[no]' , image : 'cancelled' }
] ,
//BUTTONS_YES_NO_CANCEL: 3,
[
{ "button_id" : 2 , "text" : 'yes' , id : 'dialog[yes]' , image : 'check' , "default" : true } ,
{ "button_id" : 3 , "text" : 'no' , id : 'dialog[no]' , image : 'cancelled' } ,
{ "button_id" : 0 , "text" : 'cancel' , id : 'dialog[cancel]' , image : 'cancel' }
]
] ;
2021-06-07 17:33:53 +02:00
this . div = null ;
this . template = null ;
2020-01-21 19:22:54 +01:00
// Define this as null to avoid breaking any hierarchies (eg: destroy())
2021-06-07 17:33:53 +02:00
if ( this . getParent ( ) != null )
this . getParent ( ) . removeChild ( this ) ;
2020-01-21 19:22:54 +01:00
// Button callbacks need a reference to this
2021-06-07 17:33:53 +02:00
let self = this ;
for ( let i = 0 ; i < this . _buttons . length ; i ++ ) {
for ( let j = 0 ; j < this . _buttons [ i ] . length ; j ++ ) {
this . _buttons [ i ] [ j ] . click = ( function ( id ) {
2020-01-21 19:22:54 +01:00
return function ( event ) {
self . click ( event . target , id ) ;
} ;
2021-06-07 17:33:53 +02:00
} ) ( this . _buttons [ i ] [ j ] . button _id ) ;
2020-01-21 19:22:54 +01:00
// translate button texts, as translations are not available before
2021-06-07 17:33:53 +02:00
this . _buttons [ i ] [ j ] . text = egw . lang ( this . _buttons [ i ] [ j ] . text ) ;
2020-01-21 19:22:54 +01:00
}
}
2021-06-07 17:33:53 +02:00
this . div = jQuery ( document . createElement ( "div" ) ) ;
this . _createDialog ( ) ;
2020-01-21 19:22:54 +01:00
}
/ * *
* Clean up dialog
* /
2021-06-07 17:33:53 +02:00
destroy ( ) {
2020-01-21 19:22:54 +01:00
if ( this . div != null ) {
// Un-dialog the dialog
this . div . dialog ( "destroy" ) ;
if ( this . template ) {
2021-04-20 15:30:46 +02:00
this . template . clear ( true ) ;
2020-01-21 19:22:54 +01:00
this . template = null ;
}
this . div = null ;
}
// Call the inherited constructor
2021-06-07 17:33:53 +02:00
super . destroy ( ) ;
}
2020-01-21 19:22:54 +01:00
/ * *
* Internal callback registered on all standard buttons .
* The provided callback is called after the dialog is closed .
*
* @ param target DOMNode The clicked button
* @ param button _id integer The ID of the clicked button
* /
2021-06-07 17:33:53 +02:00
click ( target , button _id ) {
2020-01-21 19:22:54 +01:00
if ( this . options . callback ) {
if ( this . options . callback . call ( this , button _id , this . get _value ( ) ) === false )
return ;
}
// Triggers destroy too
this . div . dialog ( "close" ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-21 19:22:54 +01:00
/ * *
* Returns the values of any widgets in the dialog . This does not include
* the buttons , which are only supplied for the callback .
* /
2021-06-07 17:33:53 +02:00
get _value ( ) {
2020-01-21 19:22:54 +01:00
var value = this . options . value ;
if ( this . template ) {
value = this . template . getValues ( this . template . widgetContainer ) ;
}
return value ;
2021-06-07 17:33:53 +02:00
}
2020-01-21 19:22:54 +01:00
/ * *
* Set the displayed prompt message
*
* @ param { string } message New message for the dialog
* /
2021-06-07 17:33:53 +02:00
set _message ( message ) {
2020-01-21 19:22:54 +01:00
this . options . message = message ;
this . div . empty ( )
. append ( "<img class='dialog_icon' />" )
. append ( jQuery ( '<div/>' ) . text ( message ) ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-21 19:22:54 +01:00
/ * *
* Set the dialog type to a pre - defined type
*
* @ param { integer } type constant from et2 _dialog
* /
2021-06-07 17:33:53 +02:00
set _dialog _type ( type ) {
2020-01-21 19:22:54 +01:00
if ( this . options . dialog _type != type && typeof this . _dialog _types [ type ] == "string" ) {
this . options . dialog _type = type ;
}
this . set _icon ( this . _dialog _types [ type ] ? egw . image ( this . _dialog _types [ type ] ) : "" ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-21 19:22:54 +01:00
/ * *
* Set the icon for the dialog
*
* @ param { string } icon _url
* /
2021-06-07 17:33:53 +02:00
set _icon ( icon _url ) {
2020-01-21 19:22:54 +01:00
if ( icon _url == "" ) {
jQuery ( "img.dialog_icon" , this . div ) . hide ( ) ;
}
else {
jQuery ( "img.dialog_icon" , this . div ) . show ( ) . attr ( "src" , icon _url ) ;
}
2021-06-07 17:33:53 +02:00
}
2020-01-21 19:22:54 +01:00
/ * *
* Set the dialog buttons
*
* Use either the pre - defined options in et2 _dialog , or an array
* @ see http : //api.jqueryui.com/dialog/#option-buttons
* @ param { array } buttons
* /
2021-06-07 17:33:53 +02:00
set _buttons ( buttons ) {
2020-01-21 19:22:54 +01:00
this . options . buttons = buttons ;
if ( buttons instanceof Array ) {
for ( var i = 0 ; i < buttons . length ; i ++ ) {
var button = buttons [ i ] ;
if ( ! button . click ) {
button . click = jQuery . proxy ( this . click , this , null , button . id ) ;
}
// set a default background image and css class based on buttons id
if ( button . id && typeof button . class == 'undefined' ) {
2021-06-07 17:33:53 +02:00
for ( var name in et2 _button . default _classes ) {
if ( button . id . match ( et2 _button . default _classes [ name ] ) ) {
2020-01-21 19:22:54 +01:00
button . class = ( typeof button . class == 'undefined' ? '' : button . class + ' ' ) + name ;
break ;
}
}
}
if ( button . id && typeof button . image == 'undefined' && typeof button . style == 'undefined' ) {
2021-06-07 17:33:53 +02:00
for ( var name in et2 _button . default _background _images ) {
if ( button . id . match ( et2 _button . default _background _images [ name ] ) ) {
2020-01-21 19:22:54 +01:00
button . image = name ;
break ;
}
}
}
if ( button . image ) {
2021-03-11 12:09:53 +01:00
button . style = 'background-image: url(' +
( button . image . match ( '^http|\/' ) ?
button . image : this . egw ( ) . image ( button . image , 'api' ) )
+ ')' ;
2020-01-21 19:22:54 +01:00
delete button . image ;
}
}
}
// If dialog already created, update buttons
if ( this . div . data ( 'ui-dialog' ) ) {
this . div . dialog ( "option" , "buttons" , buttons ) ;
// Focus default button so enter works
jQuery ( '.ui-dialog-buttonpane button[default]' , this . div . parent ( ) ) . focus ( ) ;
}
2021-06-07 17:33:53 +02:00
}
2020-01-21 19:22:54 +01:00
/ * *
* Set the dialog title
*
* @ param { string } title New title for the dialog
* /
2021-06-07 17:33:53 +02:00
set _title ( title ) {
2020-01-21 19:22:54 +01:00
this . options . title = title ;
this . div . dialog ( "option" , "title" , title ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-21 19:22:54 +01:00
/ * *
* Block interaction with the page behind the dialog
*
* @ param { boolean } modal Block page behind dialog
* /
2021-06-07 17:33:53 +02:00
set _modal ( modal ) {
2020-01-21 19:22:54 +01:00
this . options . modal = modal ;
this . div . dialog ( "option" , "modal" , modal ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-21 19:22:54 +01:00
/ * *
* Load an etemplate into the dialog
*
* @ param template String etemplate file name
* /
2021-06-07 17:33:53 +02:00
set _template ( template ) {
2020-01-21 19:22:54 +01:00
if ( this . template && this . options . template != template ) {
this . template . clear ( ) ;
}
2021-06-07 17:33:53 +02:00
this . template = new etemplate2 ( this . div [ 0 ] ) ;
2020-01-21 19:22:54 +01:00
if ( template . indexOf ( '.xet' ) > 0 ) {
// File name provided, fetch from server
this . template . load ( "" , template , this . options . value || { content : { } } , jQuery . proxy ( function ( ) {
// Set focus to the first input
jQuery ( 'input' , this . div ) . first ( ) . focus ( ) ;
} , this ) ) ;
}
else {
// Just template name, it better be loaded already
this . template . load ( template , '' , this . options . value || { } ,
// true: do NOT call et2_ready, as it would overwrite this.et2 in app.js
undefined , undefined , true ) ;
}
2020-07-08 19:01:05 +02:00
// Don't let dialog closing destroy the parent session
if ( this . template . etemplate _exec _id && this . template . app ) {
2021-06-07 17:33:53 +02:00
for ( let et of etemplate2 . getByApplication ( this . template . app ) ) {
2020-07-08 19:01:05 +02:00
if ( et !== this . template && et . etemplate _exec _id === this . template . etemplate _exec _id ) {
// Found another template using that exec_id, don't destroy when dialog closes.
this . template . unbind _unload ( ) ;
break ;
}
}
}
2020-01-21 19:22:54 +01:00
// set template-name as id, to allow to style dialogs
this . div . children ( ) . attr ( 'id' , template . replace ( /^(.*\/)?([^/]+)(\.xet)?$/ , '$2' ) . replace ( /\./g , '-' ) ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-21 19:22:54 +01:00
/ * *
* Actually create and display the dialog
* /
2021-06-07 17:33:53 +02:00
_createDialog ( ) {
2020-01-21 19:22:54 +01:00
if ( this . options . template ) {
this . set _template ( this . options . template ) ;
}
else {
this . set _message ( this . options . message ) ;
this . set _dialog _type ( this . options . dialog _type ) ;
}
this . set _buttons ( typeof this . options . buttons == "number" ? this . _buttons [ this . options . buttons ] : this . options . buttons ) ;
2021-06-07 17:33:53 +02:00
let position _my , position _at = '' ;
2020-04-07 14:51:46 +02:00
if ( this . options . position ) {
2021-06-07 17:33:53 +02:00
let positions = this . options . position . split ( ',' ) ;
2020-04-07 14:51:46 +02:00
position _my = positions [ 0 ] ? positions [ 0 ] . trim ( ) : 'center' ;
position _at = positions [ 1 ] ? positions [ 1 ] . trim ( ) : position _my ;
}
2021-06-07 17:33:53 +02:00
let options = {
2020-01-21 19:22:54 +01:00
// Pass the internal object, not the option
buttons : this . options . buttons ,
modal : this . options . modal ,
resizable : this . options . resizable ,
minWidth : this . options . minWidth ,
minHeight : this . options . minHeight ,
maxWidth : 640 ,
height : this . options . height ,
title : this . options . title ,
open : function ( ) {
// Focus default button so enter works
jQuery ( this ) . parents ( '.ui-dialog-buttonpane button[default]' ) . focus ( ) ;
window . setTimeout ( function ( ) {
jQuery ( this ) . dialog ( 'option' , 'position' , {
2020-04-07 14:51:46 +02:00
my : position _my ,
at : position _at ,
2020-01-21 19:22:54 +01:00
of : window
} ) ;
} . bind ( this ) , 0 ) ;
} ,
close : jQuery . proxy ( function ( ) {
this . destroy ( ) ;
} , this ) ,
beforeClose : this . options . beforeClose ,
closeText : this . egw ( ) . lang ( 'close' ) ,
2021-01-14 16:57:28 +01:00
position : { my : "center" , at : "center" , of : window } ,
appendTo : this . options . appendTo ,
draggable : this . options . draggable ,
closeOnEscape : this . options . closeOnEscape ,
dialogClass : this . options . dialogClass ,
2020-01-21 19:22:54 +01:00
} ;
// Leaving width unset lets it size itself according to contents
if ( this . options . width ) {
2020-01-22 11:45:20 +01:00
options [ 'width' ] = this . options . width ;
2020-01-21 19:22:54 +01:00
}
this . div . dialog ( options ) ;
// Make sure dialog is wide enough for the title
// Arbitrary numbers that seem to work nicely.
2021-06-07 17:33:53 +02:00
let title _width = 20 + 10 * this . options . title . length ;
2020-01-21 19:22:54 +01:00
if ( this . div . width ( ) < title _width && this . options . title . trim ( ) ) {
// Auto-sizing chopped the title
this . div . dialog ( 'option' , 'width' , title _width ) ;
}
2021-06-07 17:33:53 +02:00
}
2020-01-21 19:22:54 +01:00
/ * *
* Create a parent to inject application specific egw object with loaded translations into et2 _dialog
*
2020-01-22 11:45:20 +01:00
* @ param { string | egw } _egw _or _appname egw object with already loaded translations or application name to load translations for
2020-01-21 19:22:54 +01:00
* /
2021-06-07 17:33:53 +02:00
static _create _parent ( _egw _or _appname ) {
2020-01-21 19:22:54 +01:00
if ( typeof _egw _or _appname == 'undefined' ) {
2020-01-22 11:45:20 +01:00
// @ts-ignore
2020-01-21 19:22:54 +01:00
_egw _or _appname = egw _appName ;
}
// create a dummy parent with a correct reference to an application specific egw object
2021-06-07 17:33:53 +02:00
let parent = new et2 _widget ( ) ;
2020-01-21 19:22:54 +01:00
// if egw object is passed in because called from et2, just use it
if ( typeof _egw _or _appname != 'string' ) {
2020-01-22 11:45:20 +01:00
parent . setApiInstance ( _egw _or _appname ) ;
2020-01-21 19:22:54 +01:00
}
// otherwise use given appname to create app-specific egw instance and load default translations
else {
2020-01-22 11:45:20 +01:00
parent . setApiInstance ( egw ( _egw _or _appname ) ) ;
parent . egw ( ) . langRequireApp ( parent . egw ( ) . window , _egw _or _appname ) ;
2020-01-21 19:22:54 +01:00
}
return parent ;
2021-06-07 17:33:53 +02:00
}
2020-01-21 19:22:54 +01:00
/ * *
* Show a confirmation dialog
*
* @ param { function } _callback Function called when the user clicks a button . The context will be the et2 _dialog widget , and the button constant is passed in .
* @ param { string } _message Message to be place in the dialog .
* @ param { string } _title Text in the top bar of the dialog .
* @ param _value passed unchanged to callback as 2. parameter
* @ param { integer | array } _buttons One of the BUTTONS _ constants defining the set of buttons at the bottom of the box
* @ param { integer } _type One of the message constants . This defines the style of the message .
* @ param { string } _icon URL of an icon to display . If not provided , a type - specific icon will be used .
* @ param { string | egw } _egw _or _appname egw object with already laoded translations or application name to load translations for
* /
2021-06-07 17:33:53 +02:00
static show _dialog ( _callback , _message , _title , _value , _buttons , _type , _icon , _egw _or _appname ) {
let parent = et2 _dialog . _create _parent ( _egw _or _appname ) ;
2020-01-21 19:22:54 +01:00
// Just pass them along, widget handles defaults & missing
2021-06-07 17:33:53 +02:00
return et2 _createWidget ( "dialog" , {
2020-01-21 19:22:54 +01:00
callback : _callback || function ( ) {
} ,
message : _message ,
2020-01-22 11:45:20 +01:00
title : _title || parent . egw ( ) . lang ( 'Confirmation required' ) ,
2020-01-21 19:22:54 +01:00
buttons : typeof _buttons != 'undefined' ? _buttons : et2 _dialog . BUTTONS _YES _NO ,
dialog _type : typeof _type != 'undefined' ? _type : et2 _dialog . QUESTION _MESSAGE ,
icon : _icon ,
value : _value ,
width : 'auto'
} , parent ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-21 19:22:54 +01:00
;
/ * *
* Show an alert message with OK button
*
* @ param { string } _message Message to be place in the dialog .
* @ param { string } _title Text in the top bar of the dialog .
* @ param { integer } _type One of the message constants . This defines the style of the message .
* /
2021-06-07 17:33:53 +02:00
static alert ( _message , _title , _type ) {
let parent = et2 _dialog . _create _parent ( et2 _dialog . _create _parent ( ) . egw ( ) ) ;
et2 _createWidget ( "dialog" , {
2020-01-21 19:22:54 +01:00
callback : function ( ) {
} ,
message : _message ,
title : _title ,
buttons : et2 _dialog . BUTTONS _OK ,
dialog _type : _type || et2 _dialog . INFORMATION _MESSAGE
} , parent ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-21 19:22:54 +01:00
/ * *
* Show a prompt dialog
*
* @ param { function } _callback Function called when the user clicks a button . The context will be the et2 _dialog widget , and the button constant is passed in .
* @ param { string } _message Message to be place in the dialog .
* @ param { string } _title Text in the top bar of the dialog .
* @ param { string } _value for prompt , passed to callback as 2. parameter
* @ param { integer | array } _buttons One of the BUTTONS _ constants defining the set of buttons at the bottom of the box
* @ param { string | egw } _egw _or _appname egw object with already laoded translations or application name to load translations for
* /
2021-06-07 17:33:53 +02:00
static show _prompt ( _callback , _message , _title , _value , _buttons , _egw _or _appname ) {
2020-01-21 19:22:54 +01:00
var callback = _callback ;
// Just pass them along, widget handles defaults & missing
2021-06-07 17:33:53 +02:00
return et2 _createWidget ( "dialog" , {
2020-01-21 19:22:54 +01:00
callback : function ( _button _id , _value ) {
if ( typeof callback == "function" ) {
callback . call ( this , _button _id , _value . value ) ;
}
} ,
title : _title || egw . lang ( 'Input required' ) ,
buttons : _buttons || et2 _dialog . BUTTONS _OK _CANCEL ,
value : {
content : {
value : _value ,
message : _message
}
} ,
template : egw . webserverUrl + '/api/templates/default/prompt.xet' ,
class : "et2_prompt"
} , et2 _dialog . _create _parent ( _egw _or _appname ) ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-21 19:22:54 +01:00
/ * *
* Method to build a confirmation dialog only with
* YES OR NO buttons and submit content back to server
*
* @ param { widget } _senders widget that has been clicked
* @ param { String } _dialogMsg message shows in dialog box
* @ param { String } _titleMsg message shows as a title of the dialog box
* @ param { Bool } _postSubmit true : use postSubmit instead of submit
*
* @ description submit the form contents including the button that has been pressed
* /
2021-06-07 17:33:53 +02:00
static confirm ( _senders , _dialogMsg , _titleMsg , _postSubmit ) {
2020-01-21 19:22:54 +01:00
var senders = _senders ;
var buttonId = _senders . id ;
var dialogMsg = ( typeof _dialogMsg != "undefined" ) ? _dialogMsg : '' ;
var titleMsg = ( typeof _titleMsg != "undefined" ) ? _titleMsg : '' ;
2021-06-07 17:33:53 +02:00
var egw = _senders instanceof et2 _widget ? _senders . egw ( ) : et2 _dialog . _create _parent ( ) . egw ( ) ;
2020-01-21 19:22:54 +01:00
var callbackDialog = function ( button _id ) {
if ( button _id == et2 _dialog . YES _BUTTON ) {
if ( _postSubmit ) {
senders . getRoot ( ) . getInstanceManager ( ) . postSubmit ( buttonId ) ;
}
2021-06-07 17:33:53 +02:00
else if ( senders . instanceOf ( et2 _button ) && senders . getType ( ) !== "buttononly" ) {
2021-04-19 18:09:49 +02:00
senders . clicked = true ;
senders . getInstanceManager ( ) . submit ( senders , false , senders . options . novalidate ) ;
senders . clicked = false ;
}
2020-01-21 19:22:54 +01:00
else {
senders . getRoot ( ) . getInstanceManager ( ) . submit ( buttonId ) ;
}
}
} ;
2020-01-22 11:45:20 +01:00
et2 _dialog . show _dialog ( callbackDialog , egw . lang ( dialogMsg ) , egw . lang ( titleMsg ) , { } , et2 _dialog . BUTTONS _YES _NO , et2 _dialog . WARNING _MESSAGE , undefined , egw ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-21 19:22:54 +01:00
;
/ * *
* Show a dialog for a long - running , multi - part task
*
* Given a server url and a list of parameters , this will open a dialog with
* a progress bar , asynchronously call the url with each parameter , and update
* the progress bar .
* Any output from the server will be displayed in a box .
*
* When all tasks are done , the callback will be called with boolean true . It will
* also be called if the user clicks a button ( OK or CANCEL ) , so be sure to
* check to avoid executing more than intended .
*
* @ param { function } _callback Function called when the user clicks a button ,
* or when the list is done processing . The context will be the et2 _dialog
* widget , and the button constant is passed in .
* @ param { string } _message Message to be place in the dialog . Usually just
* text , but DOM nodes will work too .
* @ param { string } _title Text in the top bar of the dialog .
* @ param { string } _menuaction the menuaction function which should be called and
* which handles the actual request . If the menuaction is a full featured
* url , this one will be used instead .
* @ param { Array [ ] } _list - List of parameters , one for each call to the
* address . Multiple parameters are allowed , in an array .
* @ param { string | egw } _egw _or _appname egw object with already laoded translations or application name to load translations for
*
* @ return { et2 _dialog }
* /
2021-06-07 17:33:53 +02:00
static long _task ( _callback , _message , _title , _menuaction , _list , _egw _or _appname ) {
let parent = et2 _dialog . _create _parent ( _egw _or _appname ) ;
let egw = parent . egw ( ) ;
2020-01-21 19:22:54 +01:00
// Special action for cancel
2021-06-07 17:33:53 +02:00
let buttons = [
2020-01-21 19:22:54 +01:00
{ "button_id" : et2 _dialog . OK _BUTTON , "text" : egw . lang ( 'ok' ) , "default" : true , "disabled" : true } ,
{
"button_id" : et2 _dialog . CANCEL _BUTTON , "text" : egw . lang ( 'cancel' ) , click : function ( ) {
// Cancel run
cancel = true ;
jQuery ( "button[button_id=" + et2 _dialog . CANCEL _BUTTON + "]" , dialog . div . parent ( ) ) . button ( "disable" ) ;
update . call ( _list . length , '' ) ;
}
}
] ;
2021-06-07 17:33:53 +02:00
let dialog = et2 _createWidget ( "dialog" , {
2020-01-21 19:22:54 +01:00
template : egw . webserverUrl + '/api/templates/default/long_task.xet' ,
value : {
content : {
message : _message
}
} ,
callback : function ( _button _id , _value ) {
if ( _button _id == et2 _dialog . CANCEL _BUTTON ) {
cancel = true ;
}
if ( typeof _callback == "function" ) {
_callback . call ( this , _button _id , _value . value ) ;
}
} ,
title : _title || egw . lang ( 'please wait...' ) ,
buttons : buttons
} , parent ) ;
// OK starts disabled
jQuery ( "button[button_id=" + et2 _dialog . OK _BUTTON + "]" , dialog . div . parent ( ) ) . button ( "disable" ) ;
2021-06-07 17:33:53 +02:00
let log = null ;
let progressbar = null ;
let cancel = false ;
let totals = {
2020-01-21 19:22:54 +01:00
success : 0 ,
skipped : 0 ,
failed : 0 ,
widget : null
} ;
// Updates progressbar & log, calls next step
2021-06-07 17:33:53 +02:00
let update = function ( response ) {
2020-01-21 19:22:54 +01:00
// context is index
2021-06-07 17:33:53 +02:00
let index = this || 0 ;
2020-01-21 19:22:54 +01:00
progressbar . set _value ( 100 * ( index / _list . length ) ) ;
progressbar . set _label ( index + ' / ' + _list . length ) ;
// Display response information
switch ( response . type ) {
case 'error' :
jQuery ( "<div class='message error'></div>" )
. text ( response . data )
. appendTo ( log ) ;
totals . failed ++ ;
// Ask to retry / ignore / abort
2021-06-07 17:33:53 +02:00
et2 _createWidget ( "dialog" , {
2020-01-21 19:22:54 +01:00
callback : function ( button ) {
switch ( button ) {
case 'dialog[cancel]' :
cancel = true ;
return update . call ( index , '' ) ;
case 'dialog[skip]' :
// Continue with next index
totals . skipped ++ ;
return update . call ( index , '' ) ;
default :
// Try again with previous index
return update . call ( index - 1 , '' ) ;
}
} ,
message : response . data ,
title : '' ,
buttons : [
// These ones will use the callback, just like normal
{ text : egw . lang ( "Abort" ) , id : 'dialog[cancel]' } ,
{ text : egw . lang ( "Retry" ) , id : 'dialog[retry]' } ,
{ text : egw . lang ( "Skip" ) , id : 'dialog[skip]' , class : "ui-priority-primary" , default : true }
] ,
dialog _type : et2 _dialog . ERROR _MESSAGE
} , parent ) ;
// Early exit
return ;
default :
2020-06-29 22:08:02 +02:00
if ( response && typeof response === "string" ) {
2020-01-21 19:22:54 +01:00
totals . success ++ ;
jQuery ( "<div class='message'></div>" )
. text ( response )
. appendTo ( log ) ;
}
2020-06-29 22:08:02 +02:00
else {
jQuery ( "<div class='message error'></div>" )
. text ( JSON . stringify ( response ) )
. appendTo ( log ) ;
}
2020-01-21 19:22:54 +01:00
}
// Scroll to bottom
2021-06-07 17:33:53 +02:00
let height = log [ 0 ] . scrollHeight ;
2020-01-21 19:22:54 +01:00
log . scrollTop ( height ) ;
// Update totals
totals . widget . set _value ( egw . lang ( "Total: %1 Successful: %2 Failed: %3 Skipped: %4" , _list . length , totals . success , totals . failed , totals . skipped ) ) ;
// Fire next step
if ( ! cancel && index < _list . length ) {
var parameters = _list [ index ] ;
if ( typeof parameters != 'object' )
parameters = [ parameters ] ;
// Async request, we'll take the next step in the callback
// We can't pass index = 0, it looks like false and causes issues
egw . json ( _menuaction , parameters , update , index + 1 , true , index + 1 ) . sendRequest ( ) ;
}
else {
// All done
if ( ! cancel )
progressbar . set _value ( 100 ) ;
jQuery ( "button[button_id=" + et2 _dialog . CANCEL _BUTTON + "]" , dialog . div . parent ( ) ) . button ( "disable" ) ;
jQuery ( "button[button_id=" + et2 _dialog . OK _BUTTON + "]" , dialog . div . parent ( ) ) . button ( "enable" ) ;
if ( ! cancel && typeof _callback == "function" ) {
_callback . call ( dialog , true , response ) ;
}
}
} ;
jQuery ( dialog . template . DOMContainer ) . on ( 'load' , function ( ) {
// Get access to template widgets
log = jQuery ( dialog . template . widgetContainer . getWidgetById ( 'log' ) . getDOMNode ( ) ) ;
progressbar = dialog . template . widgetContainer . getWidgetById ( 'progressbar' ) ;
progressbar . set _label ( '0 / ' + _list . length ) ;
totals . widget = dialog . template . widgetContainer . getWidgetById ( 'totals' ) ;
// Start
window . setTimeout ( function ( ) {
update . call ( 0 , '' ) ;
} , 0 ) ;
} ) ;
return dialog ;
2021-06-07 17:33:53 +02:00
}
}
et2 _dialog . _attributes = {
callback : {
name : "Callback" ,
type : "js" ,
description : "Callback function is called with the value when the dialog is closed" ,
"default" : function ( button _id ) {
egw . debug ( "log" , "Button ID: %d" , button _id ) ;
2020-01-21 19:22:54 +01:00
}
2021-06-07 17:33:53 +02:00
} ,
beforeClose : {
name : "before close callback" ,
type : "js" ,
description : "Callback function before dialog is closed, return false to prevent that" ,
"default" : function ( ) {
}
} ,
message : {
name : "Message" ,
type : "string" ,
description : "Dialog message (plain text, no html)" ,
"default" : "Somebody forgot to set this..."
} ,
dialog _type : {
name : "Dialog type" ,
type : "integer" ,
description : "To use a pre-defined dialog style, use et2_dialog.ERROR_MESSAGE, INFORMATION_MESSAGE,WARNING_MESSAGE,QUESTION_MESSAGE,PLAIN_MESSAGE constants. Default is et2_dialog.PLAIN_MESSAGE" ,
"default" : 0 //this.PLAIN_MESSAGE
} ,
buttons : {
name : "Buttons" ,
type : "any" ,
"default" : 0 ,
description : "Buttons that appear at the bottom of the dialog. You can use the constants et2_dialog.BUTTONS_OK, BUTTONS_YES_NO, BUTTONS_YES_NO_CANCEL, BUTTONS_OK_CANCEL, or pass in an array for full control"
} ,
icon : {
name : "Icon" ,
type : "string" ,
description : "URL of an icon for the dialog. If omitted, an icon based on dialog_type will be used." ,
"default" : ""
} ,
title : {
name : "Title" ,
type : "string" ,
description : "Title for the dialog box (plain text, no html)" ,
"default" : ""
} ,
modal : {
name : "Modal" ,
type : "boolean" ,
description : "Prevent the user from interacting with the page" ,
"default" : true
} ,
resizable : {
name : "Resizable" ,
type : "boolean" ,
description : "Allow the user to resize the dialog" ,
"default" : true
} ,
value : {
"name" : "Value" ,
"description" : "The (default) value of the dialog. Use with template." ,
"type" : "any" ,
"default" : et2 _no _init
} ,
template : {
"name" : "Template" ,
"description" : "Instead of displaying a simple message, a full template can be loaded instead. Set defaults with value." ,
"type" : "string" ,
"default" : et2 _no _init
} ,
minWidth : {
name : "minimum width" ,
type : "integer" ,
description : "Define minimum width of dialog" ,
"default" : 0
} ,
minHeight : {
name : "minimum height" ,
type : "integer" ,
description : "Define minimum height of dialog" ,
"default" : 0
} ,
width : {
name : "width" ,
type : "string" ,
description : "Define width of dialog, the default is auto" ,
"default" : et2 _no _init
} ,
height : {
name : "height" ,
type : "string" ,
description : "Define width of dialog, the default is auto" ,
"default" : 'auto'
} ,
position : {
name : "position" ,
type : "string" ,
description : "Define position of dialog in the main window" ,
default : "center"
} ,
appendTo : {
name : "appendTo" ,
type : "string" ,
description : "Defines the dialog parent context" ,
default : ''
} ,
draggable : {
name : "Draggable" ,
type : "boolean" ,
description : "Allow the user to drag the dialog" ,
default : true
} ,
closeOnEscape : {
name : "close on escape" ,
type : "boolean" ,
description : "Allow the user to close the dialog by hiting escape" ,
default : true
} ,
dialogClass : {
name : "dialog class" ,
type : "string" ,
description : "Add css classed into dialog container" ,
default : ''
}
} ;
/ * *
* Types
* @ constant
* /
et2 _dialog . PLAIN _MESSAGE = 0 ;
et2 _dialog . INFORMATION _MESSAGE = 1 ;
et2 _dialog . QUESTION _MESSAGE = 2 ;
et2 _dialog . WARNING _MESSAGE = 3 ;
et2 _dialog . ERROR _MESSAGE = 4 ;
/* Pre-defined Button combos */
et2 _dialog . BUTTONS _OK = 0 ;
et2 _dialog . BUTTONS _OK _CANCEL = 1 ;
et2 _dialog . BUTTONS _YES _NO = 2 ;
et2 _dialog . BUTTONS _YES _NO _CANCEL = 3 ;
/* Button constants */
et2 _dialog . CANCEL _BUTTON = 0 ;
et2 _dialog . OK _BUTTON = 1 ;
et2 _dialog . YES _BUTTON = 2 ;
et2 _dialog . NO _BUTTON = 3 ;
2021-06-10 14:21:41 +02:00
// make et2_dialog publicly available as we need to call it from templates
window [ 'et2_dialog' ] = et2 _dialog ;
2021-06-07 17:33:53 +02:00
et2 _register _widget ( et2 _dialog , [ "dialog" ] ) ;
2020-01-22 11:45:20 +01:00
//# sourceMappingURL=et2_widget_dialog.js.map