view release on metacpan or search on metacpan
0.58.0 2026-07-15 17:23:33 +0200 Tobias Oetiker <tobi@oetiker.ch>
- Session expiry now surfaces as a dedicated RPC code 7 ("session
expired"), distinct from code 6 ("login required"). allow_rpc_access
guards plugin instantiation so an expired session no longer escapes as
a generic error. CallBackery::User gains a per-request `sessionExpired`
flag for subclasses that enforce a cookie max-age.
- Frontend data.Server: session expiry shows a single deduplicated
"Session Expired -> Reload" prompt instead of a storm of error popups.
Communication failures (server unreachable / proxy returning garbage)
now retry silently for idempotent reads, then show one "Connection
problem" dialog with Retry / Reload. MsgBox gains reload/retry buttons.
0.57.0 2026-06-16 08:58:42 +0200 Tobias Oetiker <tobi@oetiker.ch>
- We are on JSON-RPC 2.0 now. callbackery.data.Server now uses
qx.io.jsonrpc.Client (qooxdoo 7.x) instead of the deprecated
qx.io.remote.Rpc.
0.55.3 2025-08-25 16:37:31 +0200 Tobias Oetiker <tobi@oetiker.ch>
- fix spelling Runnning -> Running
0.55.2 2025-06-12 17:35:56 +0200 Tobias Oetiker <tobi@oetiker.ch>
- fix fake login page format
0.55.1 2025-06-12 17:28:21 +0200 Tobias Oetiker <tobi@oetiker.ch>
- properly close the popup after download if so configured
0.55.0 2025-06-12 15:24:25 +0200 Tobias Oetiker <tobi@oetiker.ch>
- download displays a busy message which can be configured using
busyMessage property
- upon download completing popup will close if closeAfterDownload => true,
is set
0.54.0 2025-06-12 14:52:06 +0200 Tobias Oetiker <tobi@oetiker.ch>
- upload actions are now busy during upload
use the busyMessage property to display a custom message during upload
0.53.1 2025-06-04 18:04:46 +0200 Tobias Oetiker <tobi@oetiker.ch>
- only log slow getters
0.50.3 2024-09-19 16:02:07 +0200 Tobias Oetiker <tobi@oetiker.ch>
- filter menuButtonProperties to make card view work again
0.50.2 2024-09-18 16:42:18 +0200 Tobias Oetiker <tobi@oetiker.ch>
- fix regression with missing defaults for app and log in user object
0.50.1 2024-08-30 12:27:22 +0200 Tobias Oetiker <tobi@oetiker.ch>
- show a popup before reloading the page
0.50.0 2024-08-29 17:12:41 +0200 Tobias Oetiker <tobi@oetiker.ch>
- reload the browser window when an exception with status 7 is returned
- warn if trm() is called with undefined arguments
0.49.6 2024-07-17 17:25:39 +0200 Tobias Oetiker <tobi@oetiker.ch>
- fix some more memory loops
0.42.1 2022-05-12 22:56:43 +0200 Tobias Oetiker <tobi@oetiker.ch>
- Apply buttonSet hash on menu action button
0.42.0 2022-04-27 08:48:54 +0200 Tobias Oetiker <tobi@oetiker.ch>
- add btCfg.testingIdPostfix for action menues with generic Popup
(e.g. CredMgr OAuth)
- add check to enforce unique none-popup action keys
0.41.6 2022-04-05 14:28:48 +0200 Tobias Oetiker <tobi@oetiker.ch>
- make sure LC_TIME and LC_NUMERIC are C and not set to some local
variant as this will cause all sorts of fun effects with localized
numbers and date strings
0.41.5 2022-03-31 16:00:42 +0200 Tobias Oetiker <tobi@oetiker.ch>
- translate button labels
0.38.7 2021-06-24 08:11:49 +0200 Tobias Oetiker <tobi@oetiker.ch>
- make sure to set the the foreign key pragma before internal migrations
0.38.6 2021-06-02 22:15:24 +0200 Tobias Oetiker <tobi@oetiker.ch>
- fix access checker promise blocker
0.38.5 2021-05-27 11:37:03 +0200 Tobias Oetiker <tobi@oetiker.ch>
- fix binding for confirmation popup box
0.38.4 2021-05-21 08:42:39 +0200 Tobias Oetiker <tobi@oetiker.ch>
- allow for multiple actions to share the same plugin instance as long as they share the same config
0.38.3 2021-05-17 16:12:40 +0200 Tobias Oetiker <tobi@oetiker.ch>
- run the mayAnonymous check as a last ditch effort ...
0.38.2 2021-05-17 15:44:51 +0200 Tobias Oetiker <tobi@oetiker.ch>
0.37.0 2021-05-06 16:31:40 +0200 Tobias Oetiker <tobi@oetiker.ch>
New Features
- access registration app as app=registration
- access passwordreset app as app=passwordreset
- prefill form fields with set_{$key}=value
- cleanup hash url with cleanup=1
Bugfix
- do not close popup on showMessage
- emit selection event on change selection in popup
Example:
http://127.0.0.1:3626/#app=registration;set_email=dummy@address;set_token=ebc4g90d2;cleanup=1
0.36.9 2021-05-05 18:06:10 +0200 Tobias Oetiker <tobi@oetiker.ch>
- fix eventhandling in frontend code
0.36.8 2021-05-02 13:47:46 +0200 Tobias Oetiker <tobi@oetiker.ch>
- allow for incremental search in selectbox dropdowns
thanks to fritz zaucker for the contrib
0.35.15 2021-04-09 15:08:19 +0200 Tobias Oetiker <tobi@oetiker.ch>
- fix regression ; -> :
0.35.14 2021-04-09 14:36:56 +0200 Tobias Oetiker <tobi@oetiker.ch>
- no double translation
- support dataModified in popup.js
0.35.13 2021-04-09 13:31:23 +0200 Tobias Oetiker <tobi@oetiker.ch>
- fix msgbox regression
0.35.12 2021-03-31 18:24:31 +0200 Tobias Oetiker <tobi@oetiker.ch>
- make calls to postProcessCfg idempotent
- provid eq overload for tra objects
0.35.8 2021-03-22 16:21:48 +0100 Tobias Oetiker <tobi@oetiker.ch>
- Handle SelectBox as part of Cards
- Make updates work generically for every text field
- Add some checks for undefined data
0.35.7 2021-03-04 15:28:49 +0100 Tobias Oetiker <tobi@oetiker.ch>
- fix popup form regresson ... some debug code had made it into the releasse
0.35.6 2021-02-26 11:13:21 +0100 Tobias Oetiker <tobi@oetiker.ch>
- add path option to Config::getTranslations call ... allow to override
translation location
0.35.5 2021-01-26 13:28:43 +0100 Tobias Oetiker <tobi@oetiker.ch>
- fix form loading (regression from 0.35.4)
- only accept POST requests as the qx plugin is very
lax with handling GET requests regarding header security
0.34.17 2020-10-08 16:03:27 +0200 Tobias Oetiker <tobi@oetiker.ch>
- fix UserList range
0.34.16 2020-09-05 07:53:26 +0200 Tobias Oetiker <tobi@oetiker.ch>
- make sure the blocker overlays popup windows too
0.34.15 2020-08-24 14:10:23 +0200 Tobias Oetiker <tobi@oetiker.ch>
- mkerror not merror
0.34.14 2020-08-24 14:02:24 +0200 Tobias Oetiker <tobi@oetiker.ch>
- replace module loading code to prevent double loading modules
0.34.13 2020-08-19 01:05:57 +0200 Tobias Oetiker <tobi@oetiker.ch>
0.34.11 2020-08-19 00:16:55 +0200 Tobias Oetiker <tobi@oetiker.ch>
- fixed copy success message
0.34.10 2020-08-17 20:33:34 +0200 Tobias Oetiker <tobi@oetiker.ch>
- translate headers in excel export
0.34.9 2020-08-15 11:06:17 +0200 Tobias Oetiker <tobi@oetiker.ch>
- fix popup resizing regression
0.34.8 2020-08-13 10:34:13 +0200 Tobias Oetiker <tobi@oetiker.ch>
- placeholder translation in notes fixed
- add automatic response to available space on login and popup dialog
0.34.7 2020-08-12 14:35:31 +0200 Tobias Oetiker <tobi@oetiker.ch>
- fix regression in popup disposal code
0.34.6 2020-08-12 14:06:26 +0200 Tobias Oetiker <tobi@oetiker.ch>
- reposition login window as the logo loads
- move max size logic into the popup window code
0.34.5 2020-08-07 16:05:10 +0200 Tobias Oetiker <tobi@oetiker.ch>
- false was treated as null in the required field check ...
0.34.4 2020-08-06 14:52:40 +0200 Tobias Oetiker <tobi@oetiker.ch>
- make sure that no reconf requests get lost if data is entered into the form while it is still loading
0.34.3 2020-08-06 09:41:36 +0200 Tobias Oetiker <tobi@oetiker.ch>
- sync the visibility setting to 'note' properties
- allow visibility seting on header elements in forms
- improve left side spacing for forms with header sections and no side notes
0.34.2 2020-07-31 13:49:05 +0200 Tobias Oetiker <tobi@oetiker.ch>
- translate on selectbox content reconfiguration
0.34.1 2020-07-27 09:28:23 +0200 Tobias Oetiker <tobi@oetiker.ch>
- if popup windows have not set maxWidth/maxHeight, set according the
appliaction Root
0.34.0 2020-07-26 12:55:39 +0200 Tobias Oetiker <tobi@oetiker.ch>
- the AbstractTable module now contains an action generator called
makeExportAction which places an export button into the action row
of a table of your choice ... note that this addition also requires you to add the
modules Text::CSV and Excel::Writer::XLSX to your dependencies.
Contribution by @maettu
- make work when mounted 'non root'
0.31.0 2020-03-26 17:27:54 +0100 Tobias Oetiker <tobi@oetiker.ch>
- fix login save trick to work with new compiler
- GuiPlugins can now have an 'mayAnonymous' property which lets them display without login
this is used for implementing password reset and account creation plugins
- hide user comment from non admin users
- tag more error messages for translation
- frontend new config options registration_popup and registration_popup they must point to an entry in the PLUGINS section
- plugins can be hidden from the plugin list using the 'unlisted' property.
0.30.1 2020-03-05 13:54:01 +0100 Tobias Oetiker <tobi@oetiker.ch>
- make table context menu button track the changes
- do not execute default action if button is not enabled
0.30.0 2020-03-04 18:08:25 +0100 Tobias Oetiker <tobi@oetiker.ch>
- Table rows with an '_actionSet' key containing a hash with key
- stringify arguments in translation array objects
- translate invalid field messages
0.29.3 2020-02-28 09:57:50 +0100 Tobias Oetiker <tobi@oetiker.ch>
- do not translate empty strings
0.29.2 2020-02-27 14:14:03 +0100 Tobias Oetiker <tobi@oetiker.ch>
- fix popup instanciation with new YAML config
0.29.1 2020-02-21 16:55:09 +0100 Tobias Oetiker <tobi@oetiker.ch>
- callbackery.locale.MTranslation was missing from MANIFEST and
thus from distro
0.29.0 2020-02-21 15:37:33 +0100 Tobias Oetiker <tobi@oetiker.ch>
- trm with placeholder and arguments work now trm('Hello %1',$name)
- in qooxdoo frontend code, use this.xtr(backendData) to translate
0.26.2 2020-01-23 10:44:20 +0100 Tobias Oetiker <tobi@oetiker.ch>
- updated wording and translations
0.26.1 2020-01-20 15:59:33 +0100 Tobias Oetiker <tobi@oetiker.ch>
- fixed js syntax (excess ,)
0.26.0 2020-01-20 15:27:13 +0100 Tobias Oetiker <tobi@oetiker.ch>
- pop config option cancelLabel to override label on calcle button in popups
- form field option 'copyOnTap' added to copy readOnly field content to
clipboard on tap.
0.25.1 2019-12-16 09:50:38 +0100 Tobias Oetiker <tobi@oetiker.ch>
- merge translations
0.25.0 2019-12-16 09:44:32 +0100 Tobias Oetiker <tobi@oetiker.ch>
- pass the output of config.getUrlConfig under the key urlConfig to the getUserConfig backend call
* 5898387 - add a cache-control header for all requests but those going for the resource files. (1 year, 1 month ago) <Tobias Oetiker>
* bd53c60 - (tag: v0.12.0) v0.12.0 (1 year, 2 months ago) <Tobias Oetiker>
* 4e0dfba - additional types supported for table columns: - string - number including format option (1 year, 2 months ago) <Tobias Oetiker>
* 8d5425f - qxclass changes (1 year, 2 months ago) <Tobias Oetiker>
* 6494665 - local class (1 year, 2 months ago) <Tobias Oetiker>
* ae4f5ed - local class (1 year, 2 months ago) <Tobias Oetiker>
* 851f7d3 - add bin makefile handle qxpath seperately (1 year, 2 months ago) <Tobias Oetiker>
* 6c7450c - app names with - and not _ please (1 year, 2 months ago) <Tobias Oetiker>
* 603bd0e - update to latest CallBackery (1 year, 2 months ago) <Tobias Oetiker>
* 7c52763 - (tag: v0.11.2) handle text fields with 0 (numeric) content properly (1 year, 3 months ago) <Tobias Oetiker>
* 901ce64 - (tag: v0.11.1) fix popup regression (1 year, 4 months ago) <Tobias Oetiker>
* 683f147 - (tag: v0.11.0) make visibility propagation actually work (1 year, 5 months ago) <Tobias Oetiker>
* 8eb8770 - a bunch of changes to enable plugins to hide themselves if they want to (1 year, 5 months ago) <Tobias Oetiker>
* f3c697c - * improve handling of user objects * add support for #focusApp=xxx location argument (1 year, 5 months ago) <Tobias Oetiker>
* 874ba3c - (tag: v0.10.9) no more transitions for blocker (1 year, 9 months ago) <Tobias Oetiker>
* e1e5f4a - (tag: v0.10.8) 0.10.8 (1 year, 9 months ago) <Tobias Oetiker>
* a401b20 - make download work again (1 year, 9 months ago) <Tobias Oetiker>
* 8a9f180 - do not recursively define SHARE (1 year, 9 months ago) <Tobias Oetiker>
* d04d959 - move blocker tuneing into separate method, so that alternate implemenations are simple (1 year, 9 months ago) <Tobias Oetiker>
* 48146ac - (tag: v0.10.7) blurring blocker effect added (1 year, 9 months ago) <Tobias Oetiker>
* b61ada6 - (tag: v0.10.6) de-slurpify (1 year, 10 months ago) <Tobias Oetiker>
* 4275dcc - better readme (2 years, 3 months ago) <Tobias Oetiker>
* 0c6b5e6 - better readme (2 years, 3 months ago) <Tobias Oetiker>
* b7b4b10 - this.tr is not available in server.js. fix for #29 (2 years, 3 months ago) <Tobias Oetiker>
* 25418af - (tag: v0.8.4) v0.8.4 (2 years, 3 months ago) <Tobias Oetiker>
* 847b0b1 - allow html in header (2 years, 3 months ago) <Tobias Oetiker>
* 02d43ea - translate busy message (2 years, 3 months ago) <Tobias Oetiker>
* 762bf8e - fix loading animation (2 years, 3 months ago) <Tobias Oetiker>
* 2cd7746 - fix args regression (2 years, 4 months ago) <Tobias Oetiker>
* 9ec77b6 - 0.8.2 (2 years, 4 months ago) <Tobias Oetiker>
* 55cfdca - args should alwais at least contain a hash ... this is only a stop gap fix ... we realy have to pass the partenArgs every time we interact with the plugin (2 years, 4 months ago) <Tobias Oetiker>
* c28ab41 - (tag: v0.8.1) 0.8.1 * allow escape to cancle popupClosed (2 years, 4 months ago) <Tobias Oetiker>
* 7c674ff - (tag: v0.7.1) fix readme issue (2 years, 4 months ago) <Tobias Oetiker>
* 80ef5e1 - cpanmin.us seems unstable (2 years, 4 months ago) <Tobias Oetiker>
* 061b82c - (tag: v0.7.0) added context menu and default action to table widget (2 years, 4 months ago) <Tobias Oetiker>
* a23d65a - handle validation on selectboxes without content (2 years, 5 months ago) <Tobias Oetiker>
* b485eb7 - be more careful with the server handler (2 years, 5 months ago) <Tobias Oetiker>
* ca89896 - better sample build app (2 years, 5 months ago) <Tobias Oetiker>
* 02a4dea - re-indent (2 years, 5 months ago) <Tobias Oetiker>
* 17493a7 - improved build system (2 years, 5 months ago) <Tobias Oetiker>
* 2325ae2 - (tag: v0.6.5) release 0.6.5 (2 years, 6 months ago) <Tobias Oetiker>
* 84b7e2b - Merge pull request #28 from samoser/PopUpPopUp (2 years, 6 months ago) <Tobias Oetiker>
lib/CallBackery/Controller/RpcService.pm view on Meta::CPAN
if (not exists $allow{$method}){
return 0;
}
for ($allow{$method}){
/1/ && return 1; # public method
return 1 if ($self->user->isUserAuthenticated); # forces cookieConf (sets sessionExpired)
/3/ && do {
# Level-3: allowed only for plugins that opt into anonymous access.
# Guard the instantiation: for an unauthenticated user it commonly
# dies (plugins read user rights/config); that death must resolve to
# "not anonymous" here, never escape as a generic code-9999 popup.
my $plugin = $self->rpcParams->[0];
my $anon = eval {
$self->config->instantiatePlugin($plugin,$self->user)->mayAnonymous
};
return 1 if $anon;
};
# Method needs auth and the user is not authenticated. If a session was
# present and merely expired, signal that distinctly (code 7 -> reload);
# otherwise fall through to code 6 (login dialog).
die mkerror(RPC_SESSION_EXPIRED,
lib/CallBackery/GuiPlugin/AbstractAction.pm view on Meta::CPAN
=cut
has actionCfg => sub {
[];
};
=head2 actionCfgMap
Lookup table for action plugins.
NOTE: Unique keys are not checked for popup plugins as they don't have
action handlers.
This allows multiple popup actions using the same plugin instance.
In this case an additional cfg parameter C<testingIdPostfix> must be
used to make the QoxdooObjectIds unique used from frontend testing.
=cut
has actionCfgMap => sub {
my $self = shift;
my %map;
for my $row (@{$self->actionCfg}){
next unless $row->{action} =~ /^(submit|upload|download|display|autoSubmit|save)/;
lib/CallBackery/GuiPlugin/AbstractAction.pm view on Meta::CPAN
hash.
=cut
sub massageConfig {
my $self = shift;
my $cfg = shift;
$self->__fixActionCfg;
my $actionCfg = $self->actionCfg;
for my $button (@$actionCfg){
if ($button->{action} =~ /popup|wizzard/) {
my $name = $button->{name};
# allow same plugin multiple times
$button->{name} = $name;
if ($cfg->{PLUGIN}{prototype}{$name}) {
my $newCfg = encode_json($button->{backend});
my $oldCfg = encode_json($cfg->{PLUGIN}{prototype}{$name}{backend});
if ($oldCfg ne 'null' and $newCfg ne $oldCfg) {
$self->log->warn("oldCfg=" . dumper $oldCfg);
$self->log->warn("newCfg=", dumper $newCfg);
die "Not unique plugin instance name $name not allowed as backend config is different\n";
}
}
my $popup = $cfg->{PLUGIN}{prototype}{$name}
= $self->app->config->loadAndNewPlugin($button->{backend}{plugin});
$popup->config($button->{backend}{config});
$popup->name($name);
$popup->app($self->app);
$popup->massageConfig($cfg);
}
}
if (ref $self->user eq 'MockUser') {
# $self->log->debug("massageConfig is done. undefining user");
$self->user(undef);
}
return;
}
=head2 __fixActionCfg
lib/CallBackery/GuiPlugin/AbstractAction.pm view on Meta::CPAN
. " name=$action->{name}"
);
}
if (not $action->{key}) {
$self->log->warn(
$pkg . " action should have a key attribute,"
. " created a key from name=$action->{name} instead"
);
$action->{key} = $action->{name};
}
# popups and wizzards do need a name internally
if ($action->{action} =~ /popup|wizzard/) {
$action->{name} = "${name}_$action->{key}";
}
}
$self->{__action_cfg_fixed} = 1;
return $self;
}
1;
__END__
lib/CallBackery/GuiPlugin/Users.pm view on Meta::CPAN
=cut
has actionCfg => sub {
my $self = shift;
# we must be in admin mode if no user property is set to have be able to prototype all forms variants
my $admin = ( not $self->user or $self->user->may('admin'));
return [
$admin ? ({
label => trm('Add User'),
action => 'popup',
addToContextMenu => true,
key => 'add',
popupTitle => trm('New User'),
backend => {
plugin => 'UserForm',
config => {
type => 'add'
}
}
}) : (),
{
label => trm('Edit User'),
action => 'popup',
addToContextMenu => true,
defaultAction => true,
key => 'edit',
popupTitle => trm('Edit User'),
actionHandler => sub {
my $self = shift;
my $args = shift;
my $id = $args->{selection}{cbuser_id};
die mkerror(393,trm('You have to select a user first'))
if not $id;
},
set => {
height => 340,
width => 500
lib/CallBackery/Model/ConfigJsonSchema.pm view on Meta::CPAN
},
required => [ $name ],
additionalProperties => false,
};
}
$schema->{properties}{PLUGIN}{items} = {
anyOf => \@items
};
$schema->{properties}{FRONTEND}{properties}{$_.'_popup'}
{properties}{plugin}{enum} = \@fullPluginList
for qw(registration passwordreset);
# warn YAML::XS::Dump $schema;
# second pass with data structures from plugins integrated
if (my @errors = $self->validator->validate($cfg)){
Mojo::Exception->throw(join "\n",@errors);
}
$cfg->{PLUGIN} = {
prototype => \%pluginMap,
list => \@pluginList
};
for (qw(registration passwordreset)) {
if (my $popup = $cfg->{FRONTEND}{$_.'_popup'}){
my $plugin = delete $popup->{plugin};
my $obj = $pluginMap{$plugin};
$cfg->{FRONTEND}{$_.'_popup'} = {
popupTitle => $obj->config->{'tab-name'},
name => $plugin,
%$popup,
};
}
}
#warn YAML::XS::Dump($cfg->{FRONTEND})
for my $name (@fullPluginList) {
$pluginMap{$name}->massageConfig($cfg);
}
$cfg->{FRONTEND}{TRANSLATIONS} = $self->getTranslations();
return $cfg;
lib/CallBackery/Model/ConfigJsonSchema.pm view on Meta::CPAN
description: hide password dialog icon
default: false
hide_release:
type: boolean
description: hide release string on login screen
default: false
hide_company:
type: boolean
description: hide company string on login screen
default: false
registration_popup:
$ref: "#/definitions/plugin"
passwordreset_popup:
$ref: "#/definitions/plugin"
PLUGIN:
type: array
items:
type: object
maxProperties: 1
minProperties: 1
patternProperty:
^\S+$:
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/Login.js view on Meta::CPAN
alignX: 'right'
})
).set({
paddingTop: 10
});
this.add(extraActions, {
row: 5,
column: 0,
colSpan: 3
});
if (cfg.passwordreset_popup) {
let btn = this.__passwordresetBtn = this.__makeExtraButton(
cfg.passwordreset_popup,this.tr("Reset Password")
);
extraActions.add(btn);
}
if (cfg.registration_popup) {
let btn = this.__registrationBtn = this.__makeExtraButton(
cfg.registration_popup,this.tr("Register New Account")
);
extraActions.add(btn);
}
if ( cfg.company_name && !cfg.hide_company){
var who = '';
if (cfg.company_url){
who += '<a href="' + cfg.company_url + '" style="color: #444;" target="_blank">' + cfg.company_name + '</a>';
}
else {
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/Login.js view on Meta::CPAN
this.setEnabled(true);
}
},
__makeExtraButton: function(cfg,label) {
var ul = this.tr('<span style="text-decoration: underline;">%1</span>',label);
var button = new qx.ui.basic.Label(ul).set({
cursor: 'pointer',
rich: true
});
button.addListener('tap',function(e) {
var popup = new callbackery.ui.Popup(cfg);
popup.addListenerOnce('close', function(e) {
this.getApplicationRoot().remove(popup);
popup.dispose();
this.setModal(true);
},this);
this.setModal(false);
popup.open();
},this);
return button;
},
__setMaxWidth: function() {
let bounds = this.getApplicationRoot().getBounds();
// make sure the window does not get larger than the screen by default ...
if (bounds) {
this.setMaxWidth(bounds.width-20);
}
}
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/MsgBox.js view on Meta::CPAN
__setIcons: function(icons) {
if (icons && icons.caption) {
this.setIcon(icons.caption);
}
if (icons && icons.body) {
this.__body.setIcon(icons);
}
},
/**
* Open the Error popup
*
* @param title {String} title
* @param text {String} body
* @param html {Boolean} allow HTML if true
* @param icons {Map} of body, button, and title icon strings
* @param size {Map} of width and height
* @return {void}
*/
error : function(title, text, html, icons, size) {
this.__setIcons(icons);
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/MsgBox.js view on Meta::CPAN
// },this);
// }
// no HTML
this.__open(this.tr('RPC Error %1', exc.code), this.xtr(exc.message), false);
return this;
},
/**
* Open the Info popup
*
* @param title {String} title
* @param text {String} body
* @param html {Boolean} allow HTML if true
* @param icons {Map} of body, button, and title icon strings
* @return {void}
*/
info : function(title, text, html, icons, size) {
this.__setIcons(icons);
this.__show_btn(['ok'], icons);
this.__open(title, text, html, size);
return this;
},
/**
* Open the Warning popup with optional callback
*
* @param title {String} window title
* @param text {String} content
* @param html {Boolean} allow HTML if true
* @param icons {Map} of body, button, and title icon strings
* @param size {Map} of width and height
* @return {void}
*/
warn : function(title, text, html, icons, size) {
this.__setIcons(icons);
this.__show_btn(['cancel','apply'], icons);
this.__open(title, text, html, size);
return this;
},
/**
* Open the Warning popup with optional callback
*
* @param title {String} window title
* @param text {String} content
* @param html {Boolean} allow HTML if true
* @param icons {Map} of body, button, and title icon strings
* @param size {Map} of width and height
* @return {void}
*/
yesno : function(title, text, html, icons, size) {
this.__setIcons(icons);
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/Popup.js view on Meta::CPAN
qx.Class.define("callbackery.ui.Popup", {
extend : qx.ui.window.Window,
/**
* create a page for the View Tab with the given title
*
* @param vizWidget {Widget} visualization widget to embedd
*/
construct : function(cfg,getParentFormData) {
/* using syntax trick to not get a warning for translating
a variable */
this.base(arguments, this.xtr(cfg.popupTitle));
this.set({
layout: new qx.ui.layout.Grow(),
height: 600,
width: 800,
modal: true,
allowMinimize: false,
showMinimize: false,
showStatusbar: false,
centerOnContainerResize: true,
centerOnAppear: true
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/form/DateTime.js view on Meta::CPAN
Authors:
* Martin Wittemann (martinwittemann)
* Fritz Zaucker
************************************************************************ */
// FIX ME: should be derived from Qooxdoo DateField.
/**
* A *date field* is like a combo box with the date as popup. As button to
* open the calendar a calendar icon is shown at the right to the datefield.
*
* In addition a time textfield.
*
* To be conform with all form widgets, the {@link qx.ui.form.IForm} interface
* is implemented.
*
* The following example creates a date field and sets the current
* date as selected.
*
* <pre class='javascript'>
* var dateTimeField = new callbackery.ui.form.DateTime();
* this.getRoot().add(dateTimeField, {top: 20, left: 20});
* dateField.setValue(new Date());
* </pre>
*
* @childControl list {qx.ui.control.DateChooser} date chooser component
* @childControl popup {qx.ui.popup.Popup} popup which shows the list control
* @childControl datefield {qx.ui.form.TextField} text field for manual date entry
* @childControl timefield {qx.ui.form.TextField} text field for manual date entry
* @childControl button {qx.ui.form.Button} button that opens the list control
*/
qx.Class.define("callbackery.ui.form.DateTime",
{
extend : qx.ui.core.Widget,
include : [
qx.ui.core.MRemoteChildrenHandling,
qx.ui.form.MForm
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/form/DateTime.js view on Meta::CPAN
/*
---------------------------------------------------------------------------
PUBLIC METHODS
---------------------------------------------------------------------------
*/
/**
* This method sets the date, which will be formatted according to
* #dateFormat to the date field. It will also select the date in the
* calendar popup.
*
* @param value {Date} The date to set.
*/
setValue : function(value)
{
// set the date to the textfield
if (value != null) {
this.getChildControl("datefield").setValue(this.getDateFormat().format(value));
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/form/DateTime.js view on Meta::CPAN
},
/*
---------------------------------------------------------------------------
LIST STUFF
---------------------------------------------------------------------------
*/
/**
* Shows the date chooser popup.
*/
open : function()
{
var popup = this.getChildControl("popup");
popup.placeToWidget(this, true);
popup.show();
},
/**
* Hides the date chooser popup.
*/
close : function() {
this.getChildControl("popup").hide();
},
/**
* Toggles the date chooser popup visibility.
*/
toggle : function()
{
var isListOpen = this.getChildControl("popup").isVisible();
if (isListOpen) {
this.close();
} else {
this.open();
}
},
/*
---------------------------------------------------------------------------
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/form/DateTime.js view on Meta::CPAN
this._add(control);
break;
case "list":
control = new qx.ui.control.DateChooser();
control.setFocusable(false);
control.setKeepFocus(true);
control.addListener("execute", this._onChangeDate, this);
break;
case "popup":
control = new qx.ui.popup.Popup(new qx.ui.layout.VBox);
control.setAutoHide(false);
control.add(this.getChildControl("list"));
control.addListener("pointerup", this._onChangeDate, this);
control.addListener("changeVisibility", this._onPopupChangeVisibility, this);
break;
}
return control || this.base(arguments, id);
},
/*
---------------------------------------------------------------------------
EVENT LISTENERS
---------------------------------------------------------------------------
*/
/**
* Handler method which handles the tap on the calender popup.
*
* @param e {qx.event.type.Pointer} The pointer event.
*/
_onChangeDate : function(e)
{
var dateField = this.getChildControl("datefield");
var selectedDate = this.getChildControl("list").getValue();
var timefield = this.getChildControl("timefield");
var time = timefield.getValue();
var defaultTime = timefield.getPlaceholder();
dateField.setValue(this.getDateFormat().format(selectedDate));
if (time == null && defaultTime != null) {
timefield.setValue(defaultTime);
}
this.close();
},
/**
* Toggles the popup's visibility.
*
* @param e {qx.event.type.Pointer} Pointer tap event
*/
_onTap : function(e) {
this.close();
},
/**
* Handler for the blur event of the current widget.
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/form/DateTime.js view on Meta::CPAN
* @param e {qx.event.type.Focus} The blur event.
*/
_onBlur : function(e) {
this.close();
},
/**
* Handler method which handles the key press. It forwards all key event
* to the opened date chooser except the escape key event. Escape closes
* the popup.
* If the list is cloned, all key events will not be processed further.
*
* @param e {qx.event.type.KeySequence} Keypress event
*/
_onKeyPress : function(e)
{
// get the key identifier
var iden = e.getKeyIdentifier();
if (iden == "Down" && e.isAltPressed())
{
this.toggle();
e.stopPropagation();
return;
}
// if the popup is closed, ignore all
var popup = this.getChildControl("popup");
if (popup.getVisibility() == "hidden") {
return;
}
// hide the list always on escape
if (iden == "Escape")
{
this.close();
e.stopPropagation();
return;
}
// Stop navigation keys when popup is open
if (iden === "Left" || iden === "Right" || iden === "Down" || iden === "Up") {
e.preventDefault();
}
// forward the rest of the events to the date chooser
this.getChildControl("list").handleKeyPress(e);
},
/**
* Redirects changeVisibility event from the list to this widget.
*
* @param e {qx.event.type.Data} Property change event
*/
_onPopupChangeVisibility : function(e)
{
e.getData() == "visible" ? this.addState("popupOpen") : this.removeState("popupOpen");
// Synchronize the chooser with the current value on every
// opening of the popup. This is needed when the value has been
// modified and not saved yet (e.g. no blur)
var popup = this.getChildControl("popup");
var chooser = this.getChildControl("list");
if (popup.isVisible())
{
var date = this.getValue();
if (date != null) {
chooser.setValue(date);
}
}
},
/**
* Reacts on value changes of the text field and syncs the
* value to the combobox.
*
* @param e {qx.event.type.Data} Change event
*/
_onDateFieldChangeValue : function(e)
{
// Apply to popup
var date = e.getData();
if (date != null && date != '')
{
var timefield = this.getChildControl("timefield");
var time = timefield.getValue();
var defaultTime = timefield.getPlaceholder();
var today = new Date();
var dateValue;
try {
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/Action.js view on Meta::CPAN
button.execute();
// only do it once for the time being
config.removeUrlConfigEntry(urlAction.key);
}
});
}, this);
},
events: {
actionResponse: 'qx.event.type.Data',
popupClosed: 'qx.event.type.Event'
},
properties: {
selection: {}
},
members: {
_cfg: null,
_plugin: null,
_tableMenu: null,
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/Action.js view on Meta::CPAN
let mmBtnId = btCfg.key
+ (btCfg.testingIdPostfix ? btCfg.testingIdPostfix : '')
+ 'mmButton';
this.addOwnedQxObject(mmButton, mmBtnId);
}
this._bindButtonProperties(button, mmButton);
return;
case 'save':
case 'submitVerify':
case 'submit':
case 'popup':
case 'wizzard':
case 'logout':
case 'cancel':
case 'download':
case 'display':
mmButton = new qx.ui.menu.Button(menuLabel || label);
if (btCfg.addToMenu != null) {
button = new qx.ui.menu.Button(label);
}
else {
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/Action.js view on Meta::CPAN
case 'wizzard':
var parent = that.getLayoutParent();
while (!parent.classname.match(/Page|Popup/)) {
parent = parent.getLayoutParent();
}
// This could in principal work for Page although.
if (parent.classname.match(/Popup/)) { // parent already exists, replace content
parent.replaceContent(btCfg, getFormData);
break;
}
// fall through intended to create first popup content
case 'popup':
if (!btCfg.noValidation) { // backward incompatibility work around
var formData = getFormData();
if (formData === false) {
callbackery.ui.MsgBox.getInstance().error(
this.tr("Validation Error"),
this.tr("The form can only be submitted when all data fields have valid content.")
);
return;
}
}
var popup = new callbackery.ui.Popup(btCfg, getFormData, this);
var appRoot = that.getApplicationRoot();
popup.addListenerOnce('close', function () {
// wait for stuff to happen before we rush into
// disposing the popup
qx.event.Timer.once(function () {
appRoot.remove(popup);
popup.dispose();
this.fireEvent('popupClosed');
}, that, 100);
if (!(btCfg.options && btCfg.options.noReload)) {
this.fireDataEvent('actionResponse', { action: (btCfg.options && btCfg.options.reloadStatusOnClose) ? 'reloadStatus' : 'reload' });
}
}, that);
popup.open();
break;
case 'logout':
that.fireDataEvent('actionResponse', { action: 'logout' });
break;
default:
this.debug('Invalid execute action:' + btCfg.action);
}
}; // var action = function() { ... };
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/ActionForm.js view on Meta::CPAN
}
break;
default:
console.error('Unknown action:', data.action);
break;
}
},this);
},
events: {
actionResponse: 'qx.event.type.Data',
popupClosed: 'qx.event.type.Event'
},
properties: {
selection: {}
},
members: {
_cfg: null,
_form: null,
_grid : null,
_btnRow : null,
_tableMenu: null,
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/ActionForm.js view on Meta::CPAN
description = new qx.ui.basic.Label(this.xtr(btCfg.description));
description.setRich(true);
this._form.add(description, { row : row++, column : btCfg.descColumn || descColumn});
}
}
grid.addOwnedQxObject(button, btCfg.key + 'Button');
this._buttonMap[btCfg.key]=button;
return;
break;
case 'submit':
case 'popup':
case 'wizzard':
case 'logout':
case 'cancel':
if (btCfg.addToMenu != null) {
button = new qx.ui.menu.Button(label);
}
else {
button = new buttonClass(label);
}
if (btCfg.key){
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/ActionForm.js view on Meta::CPAN
callbackery.data.Server.getInstance().callAsyncSmartBusy(function(ret){
that.fireDataEvent('actionResponse',ret || {});
},'processPluginData',cfg.name,{ "key": key, "formData": formData });
};
asyncCall();
break;
case 'cancel':
this.fireDataEvent('actionResponse',{action: 'cancel'});
break;
case 'popup':
if (! btCfg.noValidation) { // backward incompatibility work around
var formData = getParentFormData();
if (formData === false){
callbackery.ui.MsgBox.getInstance().error(
this.tr("Validation Error"),
this.tr("The form can only be submitted when all data fields have valid content.")
);
return;
}
}
var popup = new callbackery.ui.Popup(btCfg,getParentFormData, this);
var appRoot = that.getApplicationRoot();
popup.addListenerOnce('close',function(){
// wait for stuff to happen before we rush into
// disposing the popup
qx.event.Timer.once(function(){
appRoot.remove(popup);
popup.dispose();
this.fireEvent('popupClosed');
},that,100);
},that);
popup.open();
break;
case 'logout':
that.fireDataEvent('actionResponse',{action: 'logout'});
break;
default:
this.debug('Invalid execute action:' + btCfg.action);
}
}; // var action = function() { ... };
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/CardList.js view on Meta::CPAN
}
else {
that.setInfo(null);
}
}
if (that._hasTrigger) {
that._reconfForm();
}
}
else {
if (exc.code != 2){ /* 2 is for aborted calls, this happens when the popup is closed */
callbackery.ui.MsgBox.getInstance().exc(exc);
}
}
busy.vanish();
that._loading--;
}, 'getPluginData', this._cfg.name, 'getAllCardData', parentFormData, { currentFormData: this._form.getData()});
},
// now special handling here
_loadDataReadOnly: function(){
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/Form.js view on Meta::CPAN
delete data[key];
}
}
that._form.setData(data,true);
if (that._hasTrigger) {
that._reconfForm();
}
}
}
else {
if (exc.code != 2){ /* 2 is for aborted calls, this happens when the popup is closed */
callbackery.ui.MsgBox.getInstance().exc(exc);
}
}
busy.vanish();
that._loading--;
// see _loadDataReadOnly: release reconfigurations parked
// while the form was loading (covers the error path too;
// on success _reconfForm above picks them up itself).
if (that._loading === 0) {
that._executeReconfPending();
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/Html.js view on Meta::CPAN
parentFormData = this._getParentFormData();
}
var busy = callbackery.ui.Busy.getInstance();
busy.manifest(this.tr('Loading HTML Data'));
var that = this;
rpc.callAsync(function(data,exc){
if (!exc){
html.setHtml(data);
}
else {
if (exc.code != 2){ /* 2 is for aborted calls, this happens when the popup is closed */
callbackery.ui.MsgBox.getInstance().exc(exc);
}
}
busy.vanish();
},'getPluginData',cfg.name,parentFormData);
}
}
});
t/session_expiry.t view on Meta::CPAN
like($@->message, qr/session/i, 'code 7 message mentions session');
}
# unauthenticated + NOT expired, level-2 method -> returns 0 (dispatcher -> code 6)
{
my $c = mk_ctrl(authed => 0, expired => 0);
is($c->allow_rpc_access('getSessionCookie'), 0, 'not-expired level-2 -> 0 (code 6)');
}
# unauthenticated + expired, level-3 method whose plugin instantiation dies ->
# code 7 (regression: must NOT escape as a generic code-9999 popup)
{
my $c = mk_ctrl(authed => 0, expired => 1, params => ['NoSuchPlugin']);
my $ok = eval { $c->allow_rpc_access('getPluginData'); 1 };
ok(!$ok, 'expired level-3 dies despite plugin-instantiation failure');
is($@->code, 7, 'expired level-3 -> code 7, not 9999');
}
# unauthenticated + NOT expired, level-3 non-anonymous plugin -> returns 0 (code 6)
{
my $c = mk_ctrl(authed => 0, expired => 0, params => ['NoSuchPlugin']);