Etemplate: Add a callback so apps can decide where to put new push rows

This commit is contained in:
nathangray 2020-07-21 15:32:13 -06:00
parent 8e213a7de5
commit f0b924008b
8 changed files with 185 additions and 112 deletions

View File

@ -453,7 +453,8 @@ var et2_nextmatch = /** @class */ (function (_super) {
jQuery(this.getInstanceManager().DOMContainer.parentNode).one('show.et2_nextmatch', jQuery(this.getInstanceManager().DOMContainer.parentNode).one('show.et2_nextmatch',
// Important to use anonymous function instead of just 'this.refresh' because // Important to use anonymous function instead of just 'this.refresh' because
// of the parameters passed // of the parameters passed
jQuery.proxy(function () { this.refresh(); }, this)); function () { this.nm.refresh(this.ids, this.type); }
.bind({ nm: this, ids: _row_ids, type: _type }));
return; return;
} }
if (typeof _type == 'undefined') if (typeof _type == 'undefined')
@ -528,14 +529,20 @@ var et2_nextmatch = /** @class */ (function (_super) {
* @param uid * @param uid
*/ */
et2_nextmatch.prototype.refresh_add = function (uid) { et2_nextmatch.prototype.refresh_add = function (uid) {
var entry = this.controller._selectionMgr._getRegisteredRowsEntry(uid); var index = 0;
// Insert at the top of the list var appname = this._get_appname();
entry.idx = 0; if (appname && this.egw().window.app[appname] && typeof this.egw().window.app[appname].nm_refresh_add == "function") {
this.controller._insertDataRow(entry, true); var sort = Object.values(this.controller._indexMap).map(function (e) { return ({ index: e.idx, uid: e.uid }); });
if (this.onadd && !this.onadd(entry)) { index = this.egw().window.app[appname].nm_refresh_add(this, uid, sort);
this.controller._grid.deleteRow(entry.idx); }
// App cancelled the add
if (index === false) {
return; return;
} }
// Insert at the top of the list, or where app said
var entry = this.controller._selectionMgr._getRegisteredRowsEntry(uid);
entry.idx = typeof index == "number" ? index : 0;
this.controller._insertDataRow(entry, true);
// Set "new entry" class - but it has to stay so register and re-add it after the data is there // Set "new entry" class - but it has to stay so register and re-add it after the data is there
entry.row.tr.addClass("new_entry"); entry.row.tr.addClass("new_entry");
var callback = function (data) { var callback = function (data) {
@ -544,6 +551,18 @@ var et2_nextmatch = /** @class */ (function (_super) {
}; };
this.egw().dataRegisterUID(uid, callback, this, this.getInstanceManager().etemplate_exec_id, this.id); this.egw().dataRegisterUID(uid, callback, this, this.getInstanceManager().etemplate_exec_id, this.id);
}; };
et2_nextmatch.prototype._get_appname = function () {
var app = '';
var list = [];
list = et2_csvSplit(this.options.settings.columnselection_pref, 2, ".");
if (this.options.settings.columnselection_pref.indexOf('nextmatch') == 0) {
app = list[0].substring('nextmatch'.length + 1);
}
else {
app = list[0];
}
return app;
};
/** /**
* Gets the selection * Gets the selection
* *
@ -1385,9 +1404,9 @@ var et2_nextmatch = /** @class */ (function (_super) {
et2_nextmatch.prototype._set_autorefresh = function (time) { et2_nextmatch.prototype._set_autorefresh = function (time) {
// Store preference // Store preference
var refresh_preference = "nextmatch-" + this.options.settings.columnselection_pref + "-autorefresh"; var refresh_preference = "nextmatch-" + this.options.settings.columnselection_pref + "-autorefresh";
var app = this.options.template.split("."); var app = this._get_appname();
if (this._get_autorefresh() != time) { if (this._get_autorefresh() != time) {
this.egw().set_preference(app[0], refresh_preference, time); this.egw().set_preference(app, refresh_preference, time);
} }
// Start / update timer // Start / update timer
if (this._autorefresh_timer) { if (this._autorefresh_timer) {
@ -1427,8 +1446,7 @@ var et2_nextmatch = /** @class */ (function (_super) {
*/ */
et2_nextmatch.prototype._get_autorefresh = function () { et2_nextmatch.prototype._get_autorefresh = function () {
var refresh_preference = "nextmatch-" + this.options.settings.columnselection_pref + "-autorefresh"; var refresh_preference = "nextmatch-" + this.options.settings.columnselection_pref + "-autorefresh";
var app = this.options.template.split("."); return this.egw().preference(refresh_preference, this._get_appname());
return this.egw().preference(refresh_preference, app[0]);
}; };
/** /**
* When the template attribute is set, the nextmatch widget tries to load * When the template attribute is set, the nextmatch widget tries to load

View File

@ -703,7 +703,8 @@ export class et2_nextmatch extends et2_DOMWidget implements et2_IResizeable, et2
jQuery(this.getInstanceManager().DOMContainer.parentNode).one('show.et2_nextmatch', jQuery(this.getInstanceManager().DOMContainer.parentNode).one('show.et2_nextmatch',
// Important to use anonymous function instead of just 'this.refresh' because // Important to use anonymous function instead of just 'this.refresh' because
// of the parameters passed // of the parameters passed
jQuery.proxy(function() {this.refresh();},this) function() {this.nm.refresh(this.ids, this.type);}
.bind({nm: this, ids: _row_ids, type: _type})
); );
return; return;
} }
@ -796,17 +797,25 @@ export class et2_nextmatch extends et2_DOMWidget implements et2_IResizeable, et2
*/ */
protected refresh_add(uid:string) protected refresh_add(uid:string)
{ {
var entry = this.controller._selectionMgr._getRegisteredRowsEntry(uid); let index = 0;
// Insert at the top of the list let appname = this._get_appname();
entry.idx = 0; if(appname && this.egw().window.app[appname] && typeof this.egw().window.app[appname].nm_refresh_add == "function")
this.controller._insertDataRow(entry,true); {
let sort = Object.values(this.controller._indexMap).map(e => ({index:e.idx, uid:e.uid}));
if(this.onadd && !this.onadd(entry)) index = this.egw().window.app[appname].nm_refresh_add(this, uid, sort)
}
// App cancelled the add
if(index === false)
{ {
this.controller._grid.deleteRow(entry.idx);
return; return;
} }
// Insert at the top of the list, or where app said
var entry = this.controller._selectionMgr._getRegisteredRowsEntry(uid);
entry.idx = typeof index == "number" ? index : 0;
this.controller._insertDataRow(entry,true);
// Set "new entry" class - but it has to stay so register and re-add it after the data is there // Set "new entry" class - but it has to stay so register and re-add it after the data is there
entry.row.tr.addClass("new_entry"); entry.row.tr.addClass("new_entry");
let callback = function(data) { let callback = function(data) {
@ -816,6 +825,23 @@ export class et2_nextmatch extends et2_DOMWidget implements et2_IResizeable, et2
this.egw().dataRegisterUID(uid, callback, this, this.getInstanceManager().etemplate_exec_id, this.id); this.egw().dataRegisterUID(uid, callback, this, this.getInstanceManager().etemplate_exec_id, this.id);
} }
private _get_appname()
{
let app = '';
let list = [];
list = et2_csvSplit(this.options.settings.columnselection_pref, 2, ".");
if(this.options.settings.columnselection_pref.indexOf('nextmatch') == 0)
{
app = list[0].substring('nextmatch'.length + 1);
}
else
{
app = list[0];
}
return app;
}
/** /**
* Gets the selection * Gets the selection
* *
@ -1902,10 +1928,10 @@ export class et2_nextmatch extends et2_DOMWidget implements et2_IResizeable, et2
{ {
// Store preference // Store preference
const refresh_preference = "nextmatch-" + this.options.settings.columnselection_pref + "-autorefresh"; const refresh_preference = "nextmatch-" + this.options.settings.columnselection_pref + "-autorefresh";
const app = this.options.template.split("."); const app = this._get_appname();
if(this._get_autorefresh() != time) if(this._get_autorefresh() != time)
{ {
this.egw().set_preference(app[0],refresh_preference,time); this.egw().set_preference(app,refresh_preference,time);
} }
// Start / update timer // Start / update timer
@ -1953,8 +1979,7 @@ export class et2_nextmatch extends et2_DOMWidget implements et2_IResizeable, et2
_get_autorefresh( ) _get_autorefresh( )
{ {
const refresh_preference = "nextmatch-" + this.options.settings.columnselection_pref + "-autorefresh"; const refresh_preference = "nextmatch-" + this.options.settings.columnselection_pref + "-autorefresh";
const app = this.options.template.split("."); return this.egw().preference(refresh_preference,this._get_appname());
return this.egw().preference(refresh_preference,app[0]);
} }
/** /**

View File

@ -239,38 +239,41 @@ var AppJS = (function(){ "use strict"; return Class.extend(
} }
}, },
/**
* Callback from nextmatch so application can have some control over
* where new rows (added via push) are added. This is only called when
* the type is "add".
*
* @param nm Nextmatch the entry is going to be added to
* @param uid
* @param current_order
*/
nm_refresh_add: function(nm, uid, current_order)
{
// Do we have a modified field so we can check nm sort order?
if(this.modification_field_name)
{
let value = nm.getValue();
let sort = value.sort || {};
if(sort && sort.id == this.modification_field_name && sort.asc == false)
{
// Sorting by modification time, DESC. Put it at the top.
return 0;
}
}
// Don't actually add it in.
return false;
},
/** /**
* Get (possible) app-specific uid * Get (possible) app-specific uid
* *
* @param {object} pushData see push method for individual attributes * @param {object} pushData see push method for individual attributes
*/ */
uid(pushData) uid: function(pushData)
{ {
return pushData.app + '::' + pushData.id; return pushData.app + "::" + pushData.id;
},
/**
* Method called after apps push implementation checked visibility
*
* @param {et2_nextmatch} nm
* @param pushData see push method for individual attributes
* @todo implement better way to update nextmatch widget without disturbing the user / state
* @todo show indicator that an update has happend
* @todo rate-limit update frequency
*/
updateList: function(nm, pushData)
{
switch (pushData.type)
{
case 'add':
case 'unknown':
nm.applyFilters();
break;
default:
egw.dataRefreshUID(this.uid(pushData));
break;
}
}, },
/** /**

View File

@ -15,6 +15,9 @@ require("jquery");
require("jqueryui"); require("jqueryui");
require("../jsapi/egw_global"); require("../jsapi/egw_global");
var etemplate2_1 = require("../etemplate/etemplate2"); var etemplate2_1 = require("../etemplate/etemplate2");
var et2_extension_nextmatch_1 = require("../etemplate/et2_extension_nextmatch");
var et2_widget_dialog_1 = require("../etemplate/et2_widget_dialog");
var et2_core_widget_1 = require("../etemplate/et2_core_widget");
/** /**
* Common base class for application javascript * Common base class for application javascript
* Each app should extend as needed. * Each app should extend as needed.
@ -50,12 +53,14 @@ var EgwApp = /** @class */ (function () {
* Initialization and setup goes here, but the etemplate2 object * Initialization and setup goes here, but the etemplate2 object
* is not yet ready. * is not yet ready.
*/ */
function EgwApp(appname) { function EgwApp(appname, modified_field) {
if (modified_field === void 0) { modified_field = ""; }
/** /**
* Mailvelope "egroupware" Keyring * Mailvelope "egroupware" Keyring
*/ */
this.mailvelope_keyring = undefined; this.mailvelope_keyring = undefined;
this.appname = appname; this.appname = appname;
this.modification_field_name = modified_field;
this.egw = egw(this.appname, window); this.egw = egw(this.appname, window);
// Initialize sidebox for non-popups. // Initialize sidebox for non-popups.
// ID set server side // ID set server side
@ -172,26 +177,29 @@ var EgwApp = /** @class */ (function () {
return pushData.app + '::' + pushData.id; return pushData.app + '::' + pushData.id;
}; };
/** /**
* Method called after apps push implementation checked visibility * Callback from nextmatch so application can have some control over
* where new rows (added via push) are added. This is only called when
* the type is "add".
* *
* @param {et2_nextmatch} nm * @param nm Nextmatch the entry is going to be added to
* @param pushData see push method for individual attributes * @param uid
* @todo implement better way to update nextmatch widget without disturbing the user / state * @param current_order
* @todo show indicator that an update has happend
* @todo rate-limit update frequency
*/ */
EgwApp.prototype.updateList = function (nm, pushData) { EgwApp.prototype.nm_refresh_add = function (nm, uid, current_order) {
switch (pushData.type) { var _a;
case 'add': // Do we have a modified field so we can check nm sort order?
nm.refresh(this.uid(pushData), 'add'); if (this.modification_field_name) {
break; var value = nm.getValue();
case 'unknown': var sort = ((_a = value) === null || _a === void 0 ? void 0 : _a.sort) || {};
nm.applyFilters(); if (sort && sort.id == this.modification_field_name && sort.asc == false) {
break; // Sorting by modification time, DESC. Put it at the top.
default: return 0;
egw.dataRefreshUID(this.uid(pushData));
break;
} }
// Don't actually add it in.
return false;
}
// Just put it in at the top
return 0;
}; };
/** /**
* Open an entry. * Open an entry.
@ -228,11 +236,11 @@ var EgwApp = /** @class */ (function () {
if (typeof confirm_msg != 'undefined') { if (typeof confirm_msg != 'undefined') {
var that = this; var that = this;
var action_id = _action.id; var action_id = _action.id;
et2_dialog.show_dialog(function (button_id, value) { et2_widget_dialog_1.et2_dialog.show_dialog(function (button_id, value) {
if (button_id != et2_dialog.NO_BUTTON) { if (button_id != et2_widget_dialog_1.et2_dialog.NO_BUTTON) {
that._do_action(action_id, _elems); that._do_action(action_id, _elems);
} }
}, confirm_msg, egw.lang('Confirmation required'), et2_dialog.BUTTONS_YES_NO, et2_dialog.QUESTION_MESSAGE); }, confirm_msg, egw.lang('Confirmation required'), et2_widget_dialog_1.et2_dialog.BUTTONS_YES_NO, et2_widget_dialog_1.et2_dialog.QUESTION_MESSAGE);
} }
else if (typeof this._do_action == 'function') { else if (typeof this._do_action == 'function') {
this._do_action(_action.id, _elems); this._do_action(_action.id, _elems);
@ -305,7 +313,7 @@ var EgwApp = /** @class */ (function () {
} }
_widget.applyFilters(state.state || state.filter || {}); _widget.applyFilters(state.state || state.filter || {});
nextmatched = true; nextmatched = true;
}, this, et2_nextmatch); }, this, et2_extension_nextmatch_1.et2_nextmatch);
if (nextmatched) if (nextmatched)
return false; return false;
} }
@ -342,7 +350,7 @@ var EgwApp = /** @class */ (function () {
for (var i = 0; i < et2.length; i++) { for (var i = 0; i < et2.length; i++) {
et2[i].widgetContainer.iterateOver(function (_widget) { et2[i].widgetContainer.iterateOver(function (_widget) {
state = _widget.getValue(); state = _widget.getValue();
}, this, et2_nextmatch); }, this, et2_extension_nextmatch_1.et2_nextmatch);
} }
return state; return state;
}; };
@ -646,7 +654,7 @@ var EgwApp = /** @class */ (function () {
var apps = egw().user('apps'); var apps = egw().user('apps');
var is_admin = (typeof apps['admin'] != "undefined"); var is_admin = (typeof apps['admin'] != "undefined");
if (is_admin) { if (is_admin) {
this.favorite_popup.group = et2_createWidget("select-account", { this.favorite_popup.group = et2_core_widget_1.et2_createWidget("select-account", {
id: "favorite[group]", id: "favorite[group]",
account_type: "groups", account_type: "groups",
empty_label: "Groups", empty_label: "Groups",
@ -762,7 +770,7 @@ var EgwApp = /** @class */ (function () {
line.addClass('loading'); line.addClass('loading');
// Make sure first // Make sure first
var do_delete = function (button_id) { var do_delete = function (button_id) {
if (button_id != et2_dialog.YES_BUTTON) { if (button_id != et2_widget_dialog_1.et2_dialog.YES_BUTTON) {
line.removeClass('loading'); line.removeClass('loading');
return; return;
} }
@ -785,7 +793,7 @@ var EgwApp = /** @class */ (function () {
}, jQuery(trash).parentsUntil("li").parent(), true, jQuery(trash).parentsUntil("li").parent()); }, jQuery(trash).parentsUntil("li").parent(), true, jQuery(trash).parentsUntil("li").parent());
request.sendRequest(true); request.sendRequest(true);
}; };
et2_dialog.show_dialog(do_delete, (egw.lang("Delete") + " " + name + "?"), egw.lang("Delete"), et2_dialog.YES_NO, et2_dialog.QUESTION_MESSAGE); et2_widget_dialog_1.et2_dialog.show_dialog(do_delete, (egw.lang("Delete") + " " + name + "?"), egw.lang("Delete"), et2_widget_dialog_1.et2_dialog.YES_NO, et2_widget_dialog_1.et2_dialog.QUESTION_MESSAGE);
return false; return false;
}; };
/** /**
@ -1271,15 +1279,15 @@ var EgwApp = /** @class */ (function () {
*/ */
EgwApp.prototype.mailvelopeDeleteBackup = function () { EgwApp.prototype.mailvelopeDeleteBackup = function () {
var self = this; var self = this;
et2_dialog.show_dialog(function (_button_id) { et2_widget_dialog_1.et2_dialog.show_dialog(function (_button_id) {
if (_button_id == et2_dialog.YES_BUTTON) { if (_button_id == et2_widget_dialog_1.et2_dialog.YES_BUTTON) {
self._mailvelopeBackupFileOperator(undefined, 'DELETE', function () { self._mailvelopeBackupFileOperator(undefined, 'DELETE', function () {
self.egw.message(self.egw.lang('The backup key has been deleted.')); self.egw.message(self.egw.lang('The backup key has been deleted.'));
}, function (_err) { }, function (_err) {
self.egw.message(self.egw.lang('Was not able to delete the backup key because %1', _err)); self.egw.message(self.egw.lang('Was not able to delete the backup key because %1', _err));
}); });
} }
}, self.egw.lang('Are you sure, you would like to delete the backup key?'), self.egw.lang('Delete backup key'), {}, et2_dialog.BUTTONS_YES_CANCEL, et2_dialog.QUESTION_MESSAGE, undefined, self.egw); }, self.egw.lang('Are you sure, you would like to delete the backup key?'), self.egw.lang('Delete backup key'), {}, et2_widget_dialog_1.et2_dialog.BUTTONS_YES_CANCEL, et2_widget_dialog_1.et2_dialog.QUESTION_MESSAGE, undefined, self.egw);
}; };
/** /**
* Create mailvelope restore dialog * Create mailvelope restore dialog
@ -1335,7 +1343,7 @@ var EgwApp = /** @class */ (function () {
{ label: "Backup Key", image: "save", onclick: "app." + appname + ".mailvelopeCreateBackupDialog('#_mvelo', false)" } { label: "Backup Key", image: "save", onclick: "app." + appname + ".mailvelopeCreateBackupDialog('#_mvelo', false)" }
]; ];
var dialog = function (_content, _callback) { var dialog = function (_content, _callback) {
return et2_createWidget("dialog", { return et2_core_widget_1.et2_createWidget("dialog", {
callback: function (_button_id, _value) { callback: function (_button_id, _value) {
if (typeof _callback == "function") { if (typeof _callback == "function") {
_callback.call(this, _button_id, _value.value); _callback.call(this, _button_id, _value.value);
@ -1381,7 +1389,7 @@ var EgwApp = /** @class */ (function () {
{ "text": egw.lang('Close'), id: 'close', image: 'cancelled' } { "text": egw.lang('Close'), id: 'close', image: 'cancelled' }
]; ];
var dialog = function (_content, _callback) { var dialog = function (_content, _callback) {
return et2_createWidget("dialog", { return et2_core_widget_1.et2_createWidget("dialog", {
callback: function (_button_id, _value) { callback: function (_button_id, _value) {
if (typeof _callback == "function") { if (typeof _callback == "function") {
_callback.call(this, _button_id, _value.value); _callback.call(this, _button_id, _value.value);
@ -1416,11 +1424,11 @@ var EgwApp = /** @class */ (function () {
else if (typeof InstallTrigger != 'undefined' && InstallTrigger.enabled()) { else if (typeof InstallTrigger != 'undefined' && InstallTrigger.enabled()) {
InstallTrigger.install({ mailvelope: "https://download.mailvelope.com/releases/latest/mailvelope.firefox.xpi" }, function (_url, _status) { InstallTrigger.install({ mailvelope: "https://download.mailvelope.com/releases/latest/mailvelope.firefox.xpi" }, function (_url, _status) {
if (_status == 0) { if (_status == 0) {
et2_dialog.alert(egw.lang('Mailvelope addon installation succeded. Now you may configure the options.')); et2_widget_dialog_1.et2_dialog.alert(egw.lang('Mailvelope addon installation succeded. Now you may configure the options.'));
return; return;
} }
else { else {
et2_dialog.alert(egw.lang('Mailvelope addon installation failed! Please try again.')); et2_widget_dialog_1.et2_dialog.alert(egw.lang('Mailvelope addon installation failed! Please try again.'));
} }
}); });
} }
@ -1483,16 +1491,16 @@ var EgwApp = /** @class */ (function () {
}); });
delete buttons[1].default; delete buttons[1].default;
} }
et2_dialog.show_dialog(function (_button_id) { et2_widget_dialog_1.et2_dialog.show_dialog(function (_button_id) {
if (_button_id != et2_dialog.NO_BUTTON) { if (_button_id != et2_widget_dialog_1.et2_dialog.NO_BUTTON) {
var keys = {}; var keys = {};
keys[self.egw.user('account_id')] = _pubKey; keys[self.egw.user('account_id')] = _pubKey;
self.egw.json('addressbook.addressbook_bo.ajax_set_pgp_keys', [keys, _button_id != et2_dialog.YES_BUTTON ? true : undefined]).sendRequest() self.egw.json('addressbook.addressbook_bo.ajax_set_pgp_keys', [keys, _button_id != et2_widget_dialog_1.et2_dialog.YES_BUTTON ? true : undefined]).sendRequest()
.then(function (_data) { .then(function (_data) {
self.egw.message(_data.response['0'].data); self.egw.message(_data.response['0'].data);
}); });
} }
}, self.egw.lang('It is recommended to store your public key in addressbook, so other users can write you encrypted mails.'), self.egw.lang('Store your public key in Addressbook?'), {}, buttons, et2_dialog.QUESTION_MESSAGE, undefined, self.egw); }, self.egw.lang('It is recommended to store your public key in addressbook, so other users can write you encrypted mails.'), self.egw.lang('Store your public key in Addressbook?'), {}, buttons, et2_widget_dialog_1.et2_dialog.QUESTION_MESSAGE, undefined, self.egw);
}, function (_err) { }, function (_err) {
self.egw.message(_err.message + "\n\n" + self.egw.message(_err.message + "\n\n" +
self.egw.lang("You will NOT be able to send or receive encrypted mails before completing that step!"), 'error'); self.egw.lang("You will NOT be able to send or receive encrypted mails before completing that step!"), 'error');
@ -1665,7 +1673,7 @@ var EgwApp = /** @class */ (function () {
egw.message('Failed to copy the link!'); egw.message('Failed to copy the link!');
}; };
jQuery("body").on("click", "[name=share_link]", copy_link_to_clipboard); jQuery("body").on("click", "[name=share_link]", copy_link_to_clipboard);
et2_createWidget("dialog", { et2_core_widget_1.et2_createWidget("dialog", {
callback: function (button_id, value) { callback: function (button_id, value) {
jQuery("body").off("click", "[name=share_link]", copy_link_to_clipboard); jQuery("body").off("click", "[name=share_link]", copy_link_to_clipboard);
return true; return true;

View File

@ -15,6 +15,9 @@ import 'jqueryui';
import '../jsapi/egw_global'; import '../jsapi/egw_global';
import {etemplate2} from "../etemplate/etemplate2"; import {etemplate2} from "../etemplate/etemplate2";
import {et2_container} from "../etemplate/et2_core_baseWidget"; import {et2_container} from "../etemplate/et2_core_baseWidget";
import {et2_nextmatch} from "../etemplate/et2_extension_nextmatch";
import {et2_dialog} from "../etemplate/et2_widget_dialog";
import {et2_createWidget} from "../etemplate/et2_core_widget";
/** /**
* Type for push-message * Type for push-message
@ -62,10 +65,15 @@ export interface PushData
export abstract class EgwApp export abstract class EgwApp
{ {
/** /**
* Internal application name - override this * Internal application name - pass this in constructor
*/ */
readonly appname: string; readonly appname: string;
/**
* Name of the modification timestamp in entry data
*/
readonly modification_field_name : string;
/** /**
* Internal reference to the most recently loaded etemplate2 widget tree * Internal reference to the most recently loaded etemplate2 widget tree
* *
@ -91,7 +99,7 @@ export abstract class EgwApp
* *
* @example <caption>Access via etemplate2 object</caption> * @example <caption>Access via etemplate2 object</caption>
* // Instead of this.et2, using it's unique ID * // Instead of this.et2, using it's unique ID
* var et2 = etemplate2.getById('myapp-index) * var et2 = etemplate2.getById("myapp-index")
* if(et2) * if(et2)
* { * {
* et2.widgetContainer. ... * et2.widgetContainer. ...
@ -132,9 +140,10 @@ export abstract class EgwApp
* Initialization and setup goes here, but the etemplate2 object * Initialization and setup goes here, but the etemplate2 object
* is not yet ready. * is not yet ready.
*/ */
constructor(appname: string) constructor(appname: string, modified_field:string = "")
{ {
this.appname = appname; this.appname = appname;
this.modification_field_name = modified_field;
this.egw = egw(this.appname, window); this.egw = egw(this.appname, window);
// Initialize sidebox for non-popups. // Initialize sidebox for non-popups.
@ -271,29 +280,34 @@ export abstract class EgwApp
} }
/** /**
* Method called after apps push implementation checked visibility * Callback from nextmatch so application can have some control over
* where new rows (added via push) are added. This is only called when
* the type is "add".
* *
* @param {et2_nextmatch} nm * @param nm Nextmatch the entry is going to be added to
* @param pushData see push method for individual attributes * @param uid
* @todo implement better way to update nextmatch widget without disturbing the user / state * @param current_order
* @todo show indicator that an update has happend
* @todo rate-limit update frequency
*/ */
updateList(nm, pushData : PushData) nm_refresh_add(nm: et2_nextmatch, uid: string, current_order: string[]) : number|boolean
{ {
switch (pushData.type) // Do we have a modified field so we can check nm sort order?
if(this.modification_field_name)
{ {
case 'add': let value = nm.getValue();
nm.refresh(this.uid(pushData), 'add'); let sort = value?.sort || {};
break;
case 'unknown':
nm.applyFilters();
break;
default: if(sort && sort.id == this.modification_field_name && sort.asc == false)
egw.dataRefreshUID(this.uid(pushData)); {
break; // Sorting by modification time, DESC. Put it at the top.
return 0;
} }
// Don't actually add it in.
return false;
}
// Just put it in at the top
return 0;
} }
/** /**

View File

@ -14,6 +14,8 @@
/api/js/jquery/jquery.base64.js; /api/js/jquery/jquery.base64.js;
*/ */
import {etemplate2} from "../../api/js/etemplate/etemplate2";
/** /**
* UI for mail * UI for mail
* *
@ -406,7 +408,8 @@ app.classes.mail = AppJS.extend(
let profile_id = pushData.id.split('::')[1]; let profile_id = pushData.id.split('::')[1];
if (nm_value && nm_value.col_filter && nm_value.selectedFolder.split("::")[0] == profile_id) if (nm_value && nm_value.col_filter && nm_value.selectedFolder.split("::")[0] == profile_id)
{ {
this.updateList(nm, pushData); // Just update the nm
nm.refresh(pushData.id, pushData.type);
} }
// update unseen counter in folder-tree // update unseen counter in folder-tree
if (pushData.type === 'add' && pushData.acl.folder && pushData.acl.unseen) if (pushData.type === 'add' && pushData.acl.folder && pushData.acl.unseen)

View File

@ -30,6 +30,7 @@ require("jqueryui");
require("../jsapi/egw_global"); require("../jsapi/egw_global");
require("../etemplate/et2_types"); require("../etemplate/et2_types");
var egw_app_1 = require("../../api/js/jsapi/egw_app"); var egw_app_1 = require("../../api/js/jsapi/egw_app");
var etemplate2_1 = require("../../api/js/etemplate/etemplate2");
/** /**
* UI for timesheet * UI for timesheet
* *
@ -38,7 +39,7 @@ var egw_app_1 = require("../../api/js/jsapi/egw_app");
var TimesheetApp = /** @class */ (function (_super) { var TimesheetApp = /** @class */ (function (_super) {
__extends(TimesheetApp, _super); __extends(TimesheetApp, _super);
function TimesheetApp() { function TimesheetApp() {
return _super.call(this, 'timesheet') || this; return _super.call(this, 'timesheet', "ts_start") || this;
} }
/** /**
* This function is called when the etemplate2 object is loaded * This function is called when the etemplate2 object is loaded
@ -206,7 +207,7 @@ var TimesheetApp = /** @class */ (function (_super) {
if (nm && nm_value && ((_c = nm_value.col_filter) === null || _c === void 0 ? void 0 : _c.ts_owner) && nm_value.col_filter.ts_owner != pushData.acl) { if (nm && nm_value && ((_c = nm_value.col_filter) === null || _c === void 0 ? void 0 : _c.ts_owner) && nm_value.col_filter.ts_owner != pushData.acl) {
return; return;
} }
this.updateList(nm, pushData); etemplate2_1.etemplate2.app_refresh("", pushData.app, pushData.id, pushData.type);
}; };
return TimesheetApp; return TimesheetApp;
}(egw_app_1.EgwApp)); }(egw_app_1.EgwApp));

View File

@ -19,6 +19,7 @@ import '../etemplate/et2_types';
import {EgwApp} from '../../api/js/jsapi/egw_app'; import {EgwApp} from '../../api/js/jsapi/egw_app';
import {et2_nextmatch} from "../../api/js/etemplate/et2_extension_nextmatch"; import {et2_nextmatch} from "../../api/js/etemplate/et2_extension_nextmatch";
import {etemplate2} from "../../api/js/etemplate/etemplate2";
/** /**
* UI for timesheet * UI for timesheet
@ -30,7 +31,7 @@ class TimesheetApp extends EgwApp
constructor() constructor()
{ {
super('timesheet'); super('timesheet',"ts_start");
} }
/** /**
@ -239,7 +240,7 @@ class TimesheetApp extends EgwApp
{ {
return; return;
} }
this.updateList(nm, pushData); etemplate2.app_refresh("",pushData.app, pushData.id, pushData.type);
} }
} }