view release on metacpan or search on metacpan
0.47.3 2023-08-29 16:20:30 +0200 Tobias Oetiker <tobi@oetiker.ch>
- make table columns with "flex" work on mobile devices
0.47.2 2023-08-29 14:14:54 +0200 Tobias Oetiker <tobi@oetiker.ch>
- connect mmButton properties to button propperties
0.47.1 2023-08-29 12:04:49 +0200 Tobias Oetiker <tobi@oetiker.ch>
- include callbackery.ui.form.FileSelectorMenuButton into distro
0.47.0 2023-08-29 11:01:09 +0200 Tobias Oetiker <tobi@oetiker.ch>
* make callbackery work better on mobile
- collapse navbar buttons into menu on mobile
- move labels over form fields on mobile
* cleanup indentation
0.46.5 2023-06-28 08:29:18 +0200 Tobias Oetiker <tobi@oetiker.ch>
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/theme/Font.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/theme/Theme.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/Busy.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/Card.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/Desktop.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/Footer.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/form/Auto.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/form/DateTime.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/form/renderer/HBox.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/form/renderer/NoteForm.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/form/FileSelectorMenuButton.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/form/VirtualSelectBox.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/Header.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/__init__.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/Login.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/MsgBox.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/HtmlBox.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/Page.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/Action.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/ActionForm.js
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/CardList.js
lib/CallBackery/GuiPlugin/AbstractTable.pm view on Meta::CPAN
my $self = shift;
my %args = @_;
my $type = $args{type} // 'XLSX';
my $label = $args{label} // trm("Export %1", $type);
my $filename = $args{filename}
// localtime->strftime('export-%Y-%m-%d-%H-%M-%S.').lc($type);
return {
label => $label,
action => 'download',
addToContextMenu => true,
key => 'export_csv',
actionHandler => sub {
my $self = shift;
my $args = shift;
my $data = $self->getTableData({
formData => $args,
firstRow => 0,
lastRow => $self->getTableRowCount({ formData=>$args })
});
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;
},
lib/CallBackery/GuiPlugin/Users.pm view on Meta::CPAN
backend => {
plugin => 'UserForm',
config => {
type => 'edit'
}
}
},
$admin ? ({
label => trm('Delete User'),
action => 'submitVerify',
addToContextMenu => true,
question => trm('Do you really want to delete the selected user ?'),
key => 'delete',
actionHandler => sub {
my $self = shift;
my $args = shift;
my $id = $args->{selection}{cbuser_id};
die mkerror(4992,trm("You have to select a user first"))
if not $id;
die mkerror(4993,trm("You can not delete the user you are logged in with"))
if $id == $self->user->userId;
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/Card.js view on Meta::CPAN
this._cardCfg = cfg.cardCfg;
this._updateAction = cfg.updateAction;
this.__pluginName = cfg.name;
this.__buttonMap = buttonMap;
this.__parentForm = parentForm;
this._formCfg = {};
this.__dataCache = {};
this.__actions = [];
cfg.action.forEach(action => {
if (action.addToContextMenu) {
this.__actions.push(action);
}
}, this);
this.__buildForm();
},
properties: {
appearance: {
refine: true,
init: "cred-card"
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/HtmlBox.js view on Meta::CPAN
width: 800,
layout: new qx.ui.layout.VBox(10),
centerOnAppear: true,
centerOnContainerResize: true
});
this.getChildControl('captionbar').exclude();
var html = new qx.ui.embed.Html(content).set({
overflowX: "hidden",
overflowY: "auto",
nativeContextMenu: true
});
html.addListenerOnce('appear', function() {
var h = html.getContentElement().getDomElement();
qx.lang.Array.fromCollection(h.getElementsByTagName("script")).forEach(function(el) {
var s = document.createElement('script');
s.type = 'text/javascript';
var parent = el.parentNode;
var code = parent.removeChild(el).innerHTML;
try {
s.appendChild(document.createTextNode(code));
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/form/FileSelectorMenuButton.js view on Meta::CPAN
/* ************************************************************************
After Qooxdoo FileSelectorMenuButton
Copyright:
2023 Oetiker+Partner AG
License:
LGPL: http://www.gnu.org/licenses/lgpl.html
See the LICENSE file in the project's top-level directory for details.
Authors:
* Tobias Oetiker
************************************************************************ */
qx.Class.define("callbackery.ui.form.FileSelectorMenuButton", {
extend: qx.ui.menu.Button,
statics: {
_fileInputElementIdCounter: 0
},
properties: {
/**
* What type of files should be offered in the fileselection dialog.
* Use a comma separated list of [Unique file type specifiers](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers). If you dont set anything, all files
* are allowed.
*
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/form/FileSelectorMenuButton.js view on Meta::CPAN
// [everyone](https://caniuse.com/?search=webkitdirectory).
attr = "webkitdirectory";
}
this.__inputObject.setAttribute(attr, value);
},
setEnabled(value) {
this.__inputObject.setEnabled(value);
super.setEnabled(value);
},
_createContentElement() {
let id = "qxMenuFileSelector_" + (++callbackery.ui.form.FileSelectorMenuButton._fileInputElementIdCounter);
let input = (this.__inputObject = new qx.html.Input(
"file",
null,
{ id: id }
));
let label = new qx.html.Element("label", {}, { for: id });
label.addListenerOnce("appear", e => {
label.add(input);
});
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/Action.js view on Meta::CPAN
popupClosed: 'qx.event.type.Event'
},
properties: {
selection: {}
},
members: {
_cfg: null,
_plugin: null,
_tableMenu: null,
_defaultAction: null,
_buttonMap: null,
_buttonSetMap: null,
_menuButtonSetMap: null,
_urlActions: null,
_mobileMenu: null,
_print(content, left, top) {
var win = window.open('', '_blank');
var doc = win.document;
doc.open();
doc.write(content);
doc.close();
win.onafterprint = function () {
win.close();
}
win.print();
},
_populate(cfg, buttonClass, getFormData) {
let tm = this._tableMenu = new qx.ui.menu.Menu;
let mm = this._mobileMenu = new qx.ui.menu.Menu;
let menues = {};
let mmMenues = {};
cfg.action.forEach(function (btCfg) {
let button, menuButton, mmButton;
// label for form and context menu buttons
let label = btCfg.label ? this.xtr(btCfg.label) : null;
// label for mobile menu buttons
let menuLabel = btCfg.menuLabel ? this.xtr(btCfg.menuLabel) : null;
let bs = btCfg.buttonSet,
mbs = btCfg.menuButtonSet;
if (bs) {
if (bs.label) {
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/Action.js view on Meta::CPAN
if (mbs.label) {
mbs.label = this.xtr(mbs.label);
}
}
else if (bs) { // use buttonSet as menuButtonSet if no menuButtonSet is given
mbs = bs;
}
switch (btCfg.action) {
case 'menu':
let menu = menues[btCfg.key] = new qx.ui.menu.Menu;
let mmMenu = mmMenues[btCfg.key] = new qx.ui.menu.Menu;
if (btCfg.addToMenu != null) { // add submenu to menu
button = new qx.ui.menu.Button(label, null, null, menu)
mmButton = new qx.ui.menu.Button(menuLabel || label, null, null, mmMenu)
menues[btCfg.addToMenu].add(button);
mmMenues[btCfg.addToMenu].add(mmButton);
}
else { // add menu to form
button = new qx.ui.form.MenuButton(label, null, menu);
mmButton = new qx.ui.menu.Button(menuLabel || label, null, null, mmMenu);
if (bs) {
button.set(bs);
if (btCfg.key) {
this._buttonSetMap[btCfg.key] = bs;
}
}
if (mbs) {
let mbsFiltered = Object.fromEntries(
['visibility', 'enabled', 'label', 'icon'].filter(key => key in mbs).map(key => [key, mbs[key]])
);
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/Action.js view on Meta::CPAN
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 {
button = new buttonClass(label);
}
if (btCfg.key) {
this._buttonMap[btCfg.key] = button;
let urlAction = btCfg.urlAction;
if (urlAction) {
this._urlActions.push({
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/Action.js view on Meta::CPAN
if (mbs) {
let mbsFiltered = Object.fromEntries(
['visibility', 'enabled', 'label', 'icon'].filter(key => key in mbs).map(key => [key, mbs[key]])
);
mmButton.set(mbsFiltered);
if (btCfg.key) {
this._menuButtonSetMap[btCfg.key] = mbsFiltered;
}
}
if (btCfg.addToContextMenu) {
menuButton = new qx.ui.menu.Button(label);
if (btCfg.key) {
let btnId = btCfg.key
+ (btCfg.testingIdPostfix ? btCfg.testingIdPostfix : '')
+ 'MenuButton';
this.addOwnedQxObject(menuButton, btnId);
}
[
'Enabled',
'Visibility',
'Icon',
'Label'
].forEach(function (Prop) {
var prop = Prop.toLowerCase();
button.addListener('change' + Prop, function (e) {
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/Action.js view on Meta::CPAN
autoTimerId = null;
}
}, this);
break;
case 'upload':
button = this._makeUploadButton(cfg, btCfg, getFormData,
buttonClass == qx.ui.toolbar.Button
? qx.ui.toolbar.FileSelectorButton
: qx.ui.form.FileSelectorButton);
mmButton = this._makeUploadButton(cfg, btCfg, getFormData,
callbackery.ui.form.FileSelectorMenuButton);
if (btCfg.key) {
this._buttonMap[btCfg.key] = button;
}
break;
case 'separator':
this.add(new qx.ui.core.Spacer(10, 10));
mm.add(new qx.ui.menu.Separator());
break;
default:
this.debug('Invalid execute action:' + btCfg.action + ' for button', btCfg);
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/Action.js view on Meta::CPAN
// so we need to do it manually, since this happens on different
// browsers, chances are this is not a bug but by design :)
// once https://github.com/qooxdoo/qooxdoo/pull/10632 is released
// this here can go away
button.addListenerOnce('appear',() => {
let el = button.getContentElement().getDomElement();
button.addListener('touchstart', () => { el.focus(); }, this);
});
button.addListener('execute', action, this);
if (btCfg.addToMenu) {
menues[btCfg.addToMenu].add(button);
}
else {
if (btCfg.addToToolBar !== false) {
this.add(button);
}
}
}
if (mmButton) {
mmButton.addListener('execute', action, this);
if (btCfg.addToMenu) {
mmMenues[btCfg.addToMenu].add(mmButton);
}
else {
if (btCfg.addToToolBar !== false) {
mm.add(mmButton);
}
}
}
if (menuButton) {
menuButton.addListener('execute', action, this);
tm.add(menuButton);
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/Action.js view on Meta::CPAN
callbackery.ui.MsgBox.getInstance().error(
this.tr("Upload Exception"),
this.xtr(response.exception.message)
+ " (" + response.exception.code + ")"
);
req.dispose();
});
req.send();
},
getTableContextMenu() {
return this._tableMenu;
},
getMobileMenu() {
return this._mobileMenu;
},
getDefaultAction() {
return this._defaultAction;
},
getButtonMap() {
return this._buttonMap;
},
getButtonSetMap() {
return this._buttonSetMap;
},
getMenuButtonSetMap() {
return this._menuButtonSetMap;
},
_bindButtonProperties(button, mmButton) {
['visibility', 'enabled', 'label', 'icon'].forEach((prop) => {
button.bind(prop, mmButton, prop);
});
}
},
destruct() {
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/ActionForm.js view on Meta::CPAN
popupClosed: 'qx.event.type.Event'
},
properties: {
selection: {}
},
members: {
_cfg: null,
_form: null,
_grid : null,
_btnRow : null,
_tableMenu: null,
_defaultAction: null,
_buttonMap: null,
_populate: function(cfg,buttonClass,getParentFormData){
var menues = {};
let row = 0, descColumn= 1, btnColumn = 0;
let gridCfg = cfg.gridCfg;
let grid = this._grid;
if (gridCfg && gridCfg.btnWidth) {
grid.setColumnWidth(btnColumn, gridCfg.btnWidth);
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/ActionForm.js view on Meta::CPAN
}
else {
grid.setColumnWidth(descColumn, 400);
}
cfg.action.forEach(function(btCfg){
grid.setRowAlign(row, 'right', 'middle');
var button, menuButton, description;
var label = btCfg.label ? this.xtr(btCfg.label) : null;
switch (btCfg.action) {
case 'menu':
var menu = menues[btCfg.key] = new qx.ui.menu.Menu;
if (btCfg.addToMenu != null) { // add submenu to menu
button = new qx.ui.menu.Button(label, null, null, menu)
menues[btCfg.addToMenu].add(button);
}
else { // add menu to form
grid.setRowAlign(row, 'left', 'middle');
button = new qx.ui.form.MenuButton(label, null, menu);
this._form.add(button, {row : row, column : btCfg.btnColumn || btnColumn});
if (btCfg.description) {
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){
this._buttonMap[btCfg.key]=button;
}
if (btCfg.buttonSet) {
var bs = btCfg.buttonSet;
if (bs.label) {
bs.label = this.xtr(bs.label);
}
button.set(bs);
if (btCfg.key){
this._buttonSetMap[btCfg.key]=bs;
}
}
if ( btCfg.addToContextMenu) {
menuButton = new qx.ui.menu.Button(label);
if (btCfg.key) {
grid.addOwnedQxObject(menuButton, btCfg.key + 'MenuButton');
}
[
'Enabled',
'Visibility',
'Icon',
'Label'
].forEach(function(Prop){
var prop = Prop.toLowerCase();
button.addListener('change'+Prop,function(e){
menuButton['set'+Prop](e.getData());
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/ActionForm.js view on Meta::CPAN
default:
this.debug('Invalid execute action:' + btCfg.action);
}
}; // var action = function() { ... };
if (btCfg.defaultAction){
this._defaultAction = action;
}
if (button){
button.addListener('execute',action,this);
if (btCfg.addToMenu) {
menues[btCfg.addToMenu].add(button);
}
else {
if (btCfg.addToToolBar !== false) {
if (btCfg.action == 'cancel') {
this._btnRow.add(button);
}
else {
grid.setRowAlign(row, 'left', 'middle');
this._form.add(button, {row : row, column : btCfg.btnColumn || btnColumn});
if (btCfg.description) {
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/ActionForm.js view on Meta::CPAN
description.setRich(true);
this._form.add(description, {row : row++, column : btCfg.descColumn || descColumn});
}
}
}
}
}
},this);
},
getTableContextMenu: function(){
return this._tableMenu;
},
getDefaultAction: function(){
return this._defaultAction;
},
getButtonMap: function(){
return this._buttonMap;
},
getButtonSetMap: function(){
return this._buttonSetMap;
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/Html.js view on Meta::CPAN
_getParentFormData: null,
_html: null,
_populate: function(){
this.setLayout(new qx.ui.layout.VBox(30));
this.add(this._createHtml(),{flex: 1});
},
_createHtml: function(){
var html = this._html = new qx.ui.embed.Html().set({
overflowX: "auto",
overflowY: "auto",
nativeContextMenu: true
});
return html;
},
_loadData: function(){
var html = this._html;
var cfg = this._cfg;
var rpc = callbackery.data.Server.getInstance();
var parentFormData = {};
if (this._getParentFormData){
lib/CallBackery/qooxdoo/callbackery/source/class/callbackery/ui/plugin/Table.js view on Meta::CPAN
}
else {
return false;
}
},
this
);
action.set({
paddingLeft: -10
});
let mobileMenu = new qx.ui.form.MenuButton(this.tr("Menu"), null, action.getMobileMenu());
toolbar.add(mobileMenu);
toolbar.setOverflowIndicator(mobileMenu);
toolbar.setOverflowHandling(true);
toolbar.add(action);
toolbar.setRemovePriority(action, 1);
toolbar.addSpacer();
var form = this._form = new callbackery.ui.form.Auto(cfg.form, null, callbackery.ui.form.renderer.HBox, this);
toolbar.add(form);
return toolbar;
},
_createTable() {
var cfg = this._cfg;
var model = this._model = new callbackery.data.RemoteTableModel(cfg, this._getParentFormData);
var table = this._table = new qx.ui.table.Table(model, {
tableColumnModel: function (obj) {
return new qx.ui.table.columnmodel.Resize(obj);
}
}).set({
showCellFocusIndicator: false
});
table.getDataRowRenderer().setHighlightFocusRow(false);
var ctxMenu = this._action.getTableContextMenu();
if (ctxMenu) {
table.setContextMenu(ctxMenu);
}
var defaultAction = this._action.getDefaultAction();
if (defaultAction) {
table.addListener('cellDbltap', defaultAction, this._action);
}
var tcm = table.getTableColumnModel();
var resizeBehavior = tcm.getBehavior();
cfg.table.forEach(function (col, i) {
var cr;
switch (col.type) {