CallBackery

 view release on metacpan or  search on metacpan

CHANGES  view on Meta::CPAN

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>

MANIFEST  view on Meta::CPAN

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) {



( run in 1.486 second using v1.01-cache-2.11-cpan-49f99fa48dc )