WIP Mail REST API: change calendar to use new egw.openDialog():

- renamed app.dialogExec() to app.openDialog() or egw.openDialog()
- the later is the nicer place, but fails for lost window context with popups :(
This commit is contained in:
ralf 2023-07-13 15:22:21 +02:00
parent 6ce0abdb37
commit 3e27def4f9
7 changed files with 65 additions and 190 deletions

View File

@ -1573,7 +1573,7 @@ export class etemplate2
}
// handle framework.setSidebox calls
if(window.framework && jQuery.isArray(data.setSidebox))
if(!dialog && window.framework && Array.isArray(data.setSidebox))
{
if(data['fw-target'])
{

View File

@ -751,13 +751,15 @@ export abstract class EgwApp
/**
* Opens _menuaction in an Et2Dialog
*
* Equivalent to egw.openDialog, thought this one works in popups too.
*
* @param _menuaction
* @return Promise<any>
*/
dialogExec(_menuaction : string)
openDialog(_menuaction : string)
{
const ajax = this.egw.json(_menuaction.match(/^([^.:]+)/)[0] + '.jdots_framework.ajax_exec.template.' + _menuaction,
['index.php?menuaction=' + _menuaction], _response =>
return this.egw.json(_menuaction.match(/^([^.:]+)/)[0] + '.jdots_framework.ajax_exec.template.' + _menuaction,
['index.php?menuaction=' + _menuaction, true], _response =>
{
if (Array.isArray(_response) && typeof _response[0] === 'string')
{
@ -767,8 +769,7 @@ export abstract class EgwApp
{
console.log("Invalid response to dialogExec('"+_menuaction+"')", _response);
}
});
return ajax.sendRequest();
}).sendRequest();
}
/**

View File

@ -378,6 +378,32 @@ egw.extend('open', egw.MODULE_WND_LOCAL, function(_egw, _wnd)
}
},
/**
* Opens a menuaction in an Et2Dialog instead of a popup
*
* Please note:
* This method does NOT (yet) work in popups, only in the main EGroupware window!
* For popups you have to use the app.ts method openDialog(), which creates the dialog in the correct window / popup.
*
* @param string _menuaction
* @return Promise<any>
*/
openDialog: function(_menuaction)
{
return this.json(_menuaction.match(/^([^.:]+)/)[0] + '.jdots_framework.ajax_exec.template.' + _menuaction,
['index.php?menuaction=' + _menuaction, true], _response =>
{
if (Array.isArray(_response) && typeof _response[0] === 'string')
{
jQuery(_response[0]).appendTo(_wnd.document.body);
}
else
{
console.log("Invalid response to dialogExec('"+_menuaction+"')", _response);
}
}).sendRequest();
},
/**
* Open a (centered) popup window with given size and url
*
@ -690,4 +716,4 @@ try {
}
} catch (e) {}
});
*/
*/

View File

@ -1083,11 +1083,12 @@ abstract class Ajax extends Api\Framework
/**
* Run a link via ajax, returning content via egw_json_response->data()
*
* This behavies like /index.php, but returns the content via json.
* This behaves like /index.php, but returns the content via json.
*
* @param string $link
* @param bool $dialog=false true ajax_exec is called to execute a popup in a dialog
*/
public static function ajax_exec($link)
public static function ajax_exec($link, bool $dialog=false)
{
$parts = parse_url($link);
$_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] = $parts['path'];
@ -1130,20 +1131,23 @@ abstract class Ajax extends Api\Framework
// dont send header and footer
self::$header_done = self::$footer_done = true;
// flag to indicate target of output e.g. _tab
if ($_GET['fw_target'])
if (!$dialog)
{
Api\Cache::unsetSession(__CLASS__,'sidebox_md5'); // sideboxes need to be send again
$GLOBALS['egw']->framework->set_extra('fw','target',$_GET['fw_target']);
// flag to indicate target of output e.g. _tab
if ($_GET['fw_target'])
{
Api\Cache::unsetSession(__CLASS__,'sidebox_md5'); // sideboxes need to be send again
$GLOBALS['egw']->framework->set_extra('fw','target',$_GET['fw_target']);
}
// need to call do_sidebox, as header() with $header_done does NOT!
$GLOBALS['egw']->framework->do_sidebox();
// send Api\Preferences, so we dont need to request them in a second ajax request
$GLOBALS['egw']->framework->response->call('egw.set_preferences',
(array)$GLOBALS['egw_info']['user']['preferences'][$app], $app);
}
// need to call do_sidebox, as header() with $header_done does NOT!
$GLOBALS['egw']->framework->do_sidebox();
// send Api\Preferences, so we dont need to request them in a second ajax request
$GLOBALS['egw']->framework->response->call('egw.set_preferences',
(array)$GLOBALS['egw_info']['user']['preferences'][$app], $app);
// call application menuaction
ob_start();
$obj->$method();

View File

@ -671,10 +671,13 @@ class calendar_uiforms extends calendar_ui
case 'exception': // create an exception in a recuring event
$msg = $this->_create_exception($event,$preserv);
break;
case 'edit':
// Going from add dialog to full edit dialog
unset($preserv['template']);
unset($event['template']);
Api\Json\Response::get()->call('egw.open', '', 'calendar', 'edit', $event);
Framework::window_close();
break;
case 'copy': // create new event with copied content, some content need to be unset to make a "new" event
@ -1151,12 +1154,7 @@ class calendar_uiforms extends calendar_ui
$button == 'save' && $client_updated ? ($content['id'] ? $update_type : 'add') : 'delete'
);
}
// Don't try to close quick add, it's not in a popup
if($content['template'] !== 'calendar.add')
{
Framework::window_close();
}
exit();
Framework::window_close();
}
unset($event['no_notifications']);
return $this->edit($event,$preserv,$msg,$event['id'] ? $event['id'] : $content['link_to']['to_id']);
@ -1562,8 +1560,8 @@ class calendar_uiforms extends calendar_ui
if (!is_array($event))
{
$preserv = array(
'no_popup' => isset($_GET['no_popup']),
'template' => isset($_GET['template']) ? $_GET['template'] : (isset($_REQUEST['print']) ? 'calendar.print' : 'calendar.edit'),
'no_popup' => !empty($_GET['no_popup']),
'template' => $_GET['template'] ?? (isset($_REQUEST['print']) ? 'calendar.print' : 'calendar.edit'),
);
if(!isset($_REQUEST['print']) && !empty($preserv['template']) && $this->cal_prefs['new_event_dialog'] == 'edit')
{

View File

@ -2057,170 +2057,16 @@ export class CalendarApp extends EgwApp
//options.template = 'calendar.add';
return this.egw.open(null, 'calendar', 'edit', options, '_blank', 'calendar');
}
// Hold on to options, may have to pass them into edit (rather than all, just send what the programmer wanted)
this.quick_add = options;
// Open dialog to use as target
let add_dialog;
// Call the server, get it into the dialog
options = jQuery.extend({menuaction: 'calendar.calendar_uiforms.ajax_add', template: 'calendar.add'}, options);
this.egw.json(
this.egw.link('/json.php', options),
[options],
(data) =>
{
if(Array.isArray(data) && typeof data[0] === 'string')
{
jQuery(data[0]).appendTo(document.body);
}
add_dialog = document.body.querySelector("et2-dialog");
add_dialog.id = "quick-add";
}
).sendRequest();
add_dialog.addEventListener("close", (ev) =>
let menuaction = 'calendar.calendar_uiforms.edit&template=calendar.add';
for(const name in options)
{
// Wait a bit to make sure etemplate button finishes processing, or it will error
window.setTimeout(function()
{
if(event && event.destroy)
{
event.destroy();
}
let template = etemplate2.getById('calendar-add');
if(template && template.name === 'calendar.add')
{
template.clear();
delete app.calendar.quick_add;
}
else if(template || (template = etemplate2.getById("calendar-conflicts")))
{
// Open conflicts
var data = jQuery.extend(
{menuaction: 'calendar.calendar_uiforms.ajax_conflicts'},
template.widgetContainer.getArrayMgr('content').data,
app.calendar.quick_add
);
egw.openPopup(
egw.link(
'/index.php',
data
),
850, 300,
'conflicts', 'calendar'
);
delete app.calendar.quick_add;
// Do not submit this etemplate
return false;
}
}.bind({dialog: add_dialog, event: ev}), 1000);
});
}
/**
* Callback for save button in add dialog
*
* @param {Event} event
* @param {et2_button} widget
* @returns {Boolean}
*/
add_dialog_save(event, widget)
{
// Include all sent values so we can pass on things that we don't have UI widgets for
this.quick_add = this._add_dialog_values(widget);
widget.getInstanceManager().isInvalid().then((invalid) =>
{
if(invalid.filter((widget) => widget).length == 0)
{
// Close the dialog, if everything is OK
(<Et2Dialog><unknown>document.querySelector('et2-dialog')).hide();
}
});
// Mess with opener so update opener in response works
window.opener = window;
window.setTimeout(function() {window.opener = null;}, 1000);
// Proceed with submit, though it will fail if something is invalid
return true;
}
/**
* Callback for edit button in add dialog
*
* @param {Event} event
* @param {et2_button} widget
* @returns {Boolean}
*/
add_dialog_edit(event, widget)
{
var title=widget.getRoot().getWidgetById('title');
let options = jQuery.extend(this.quick_add, this._add_dialog_values(widget));
// Open regular edit
egw.open(null,'calendar','edit',options);
// Close the dialog
(<Et2Dialog><unknown>document.querySelector('et2-dialog#quick_add')).close()
// Do not submit this etemplate
return false;
}
/**
* Include some additional values so we can pass on things that we don't have
* UI widgets for in the add template
*
* @param {et2_widget} widget
* @returns {Object}
*/
_add_dialog_values(widget)
{
// Some select things to pass on, since not everything will fit
var mgr = widget.getRoot().getArrayMgr('content');
var values : any = {
owner: typeof mgr.getEntry('owner') == 'object' ? mgr.getEntry('owner') : (mgr.getEntry('owner')+'').split(','),
participants: [],
whole_day: mgr.getEntry('whole_day')
};
if(mgr.getEntry('link_to') && typeof mgr.getEntry('link_to').to_id === 'object')
{
var links = mgr.getEntry('link_to').to_id;
values.link_app = [];
values.link_id = [];
for( var id in links)
{
values.link_app.push(links[id].app);
values.link_id.push(links[id].id);
}
menuaction += '&'+name+'='+encodeURIComponent(options[name]);
}
for(var id in mgr.getEntry('participants'))
{
var participant = mgr.getEntry('participants')[id];
if (participant && participant.uid)
{
values.participants.push(participant.uid);
}
}
let send = jQuery.extend(
values,
widget.getInstanceManager().getValues(widget.getRoot())
);
// Don't need the checkbox
delete send.new_event_dialog;
return send;
return this.egw.openDialog(menuaction);
}
/**
* Open calendar entry, taking into accout the calendar integration of other apps
* Open calendar entry, taking into account the calendar integration of other apps
*
* calendar_uilist::get_rows sets var js_calendar_integration object
*

View File

@ -24,9 +24,9 @@
</row>
</rows>
</grid>
<et2-button statustext="saves the changes made" label="Save" id="button[save]" image="save" onclick="return app.calendar.add_dialog_save(ev, widget); " slot="footer" default="true"></et2-button>
<et2-button statustext="Full edit dialog" label="Edit" id="button[edit]" image="edit" onclick="return app.calendar.add_dialog_edit(ev, widget);" slot="footer"></et2-button>
<et2-button statustext="Close the window" label="Cancel" id="button[cancel]" onclick="document.querySelector('et2-dialog').hide()" image="cancel" slot="footer"></et2-button>
<et2-button statustext="saves the changes made" label="Save" id="button[save]" slot="footer" default="true"></et2-button>
<et2-button statustext="Full edit dialog" label="Edit" id="button[edit]" slot="footer"></et2-button>
<et2-button statustext="Close the window" label="Cancel" id="button[cancel]" slot="footer"></et2-button>
<et2-checkbox label="Always use full edit dialog" id="new_event_dialog" statustext="Always use the full edit dialog, not this little dialog" onchange="egw.set_preference('calendar',widget.id,widget.get_value() ? 'edit' : 'add');" slot="footer" align="right"></et2-checkbox>
</template>
</overlay>