Hidden features:
manipulating UI5 controls on the fly
Sebastian Wennemers, SAP
Pavel Kornev, SAP

June 28, 2019

Demo

Is it possible to implement this
with just a few lines of code?

Yes, indeed

OpenUI5 libraries

sap.f
sap.m
sap.tnt
sap.ui.codeeditor
sap.ui.commons
sap.ui.core
sap.ui.demokit
sap.ui.documentation
sap.ui.dt
sap.ui.fl
sap.ui.integration
sap.ui.layout
sap.ui.rta
sap.ui.suite
sap.ui.support
sap.ui.table
sap.ui.unified
sap.ui.ux3
sap.uxap

What is sap.ui.dt?

Key User Adaptation

Layout Editor
(in SAP Web IDE)

SAPUI5 Visual Editor
(in SAP Web IDE)

sap.ui.Design Time

sap.ui.dt helps developers to build outstanding tooling on top of UI5 apps

Basic concepts

Overlay concept

Overlays

— automatically calculate their geometry based on controls dimensions
— automatically calculate their position on the screen
— automatically calculate z-indexes
— handle overflows (scrollbars)
— ...and keep it all in sync during their life time!

Plugin concept

Plugins are responsible for actions

Available plugins

Drag & Drop
Cut & Paste
Context Menu
Mouse Selection
Tab Handling

Usage example

Creating a Design Time Instance


							sap.ui.require([
							    "sap/ui/dt/DesignTime",
							    "sap/ui/dt/plugin/MouseSelection",
							    "sap/ui/dt/plugin/ControlDragDrop",
							    "custom/ushell/plugin/shooter/designtime/Shooter"
							], function (
							    DesignTime,
							    MouseSelection,
							    ControlDragDrop,
							    Shooter
							) {
							    var oAppLifeCycle = sap.ushell.Container.getService("AppLifeCycle");
							    var oDesignTime = new DesignTime({
							        rootElements: oAppLifeCycle.getCurrentApplication().componentInstance,
							        plugins: [
							            new MouseSelection(),
							            new ControlDragDrop(),
							            new Shooter()
							        ]
							    });
							});
						
							sap.ui.require([
							    "sap/ui/dt/DesignTime",
							    "sap/ui/dt/plugin/MouseSelection",
							    "sap/ui/dt/plugin/ControlDragDrop",
							    "custom/ushell/plugin/shooter/designtime/Shooter"
							], function (
							    DesignTime,
							    MouseSelection,
							    ControlDragDrop,
							    Shooter
							) {
							    var oAppLifeCycle = sap.ushell.Container.getService("AppLifeCycle");
							    var oDesignTime = new DesignTime({
							        rootElements: oAppLifeCycle.getCurrentApplication().componentInstance,
							        plugins: [
							            new MouseSelection(),
							            new ControlDragDrop(),
							            new Shooter()
							        ]
							    });
							});
						
							sap.ui.require([
							    "sap/ui/dt/DesignTime",
							    "sap/ui/dt/plugin/MouseSelection",
							    "sap/ui/dt/plugin/ControlDragDrop",
							    "custom/ushell/plugin/shooter/designtime/Shooter"
							], function (
							    DesignTime,
							    MouseSelection,
							    ControlDragDrop,
							    Shooter
							) {
							    var oAppLifeCycle = sap.ushell.Container.getService("AppLifeCycle");
							    var oDesignTime = new DesignTime({
							        rootElements: oAppLifeCycle.getCurrentApplication().componentInstance,
							        plugins: [
							            new MouseSelection(),
							            new ControlDragDrop(),
							            new Shooter()
							        ]
							    });
							});
						

Implementing a Custom Plugin


						sap.ui.define(["sap/ui/dt/Plugin"], function (Plugin) {
						    var Shooter = Plugin.extend("custom.ushell.plugin.shooter.designtime.Shooter");

						    Shooter.prototype.registerElementOverlay = function (oOverlay) {
						        oOverlay.attachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype.deregisterElementOverlay = function (oOverlay) {
						        oOverlay.detachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype._onClick = function (e) {
						        this.setSelected(false);
						        this.addStyleClass("sapUiDtOverlayPoof");
						        this.attachBrowserEvent("animationend", function () {
						            this.getElement().setVisible(false);
						        }, this);
						        e.stopPropagation();
						    };

						    return Shooter;
						});
					
						sap.ui.define(["sap/ui/dt/Plugin"], function (Plugin) {
						    var Shooter = Plugin.extend("custom.ushell.plugin.shooter.designtime.Shooter");

						    Shooter.prototype.registerElementOverlay = function (oOverlay) {
						        oOverlay.attachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype.deregisterElementOverlay = function (oOverlay) {
						        oOverlay.detachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype._onClick = function (e) {
						        this.setSelected(false);
						        this.addStyleClass("sapUiDtOverlayPoof");
						        this.attachBrowserEvent("animationend", function () {
						            this.getElement().setVisible(false);
						        }, this);
						        e.stopPropagation();
						    };

						    return Shooter;
						});
					
						sap.ui.define(["sap/ui/dt/Plugin"], function (Plugin) {
						    var Shooter = Plugin.extend("custom.ushell.plugin.shooter.designtime.Shooter");

						    Shooter.prototype.registerElementOverlay = function (oOverlay) {
						        oOverlay.attachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype.deregisterElementOverlay = function (oOverlay) {
						        oOverlay.detachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype._onClick = function (e) {
						        this.setSelected(false);
						        this.addStyleClass("sapUiDtOverlayPoof");
						        this.attachBrowserEvent("animationend", function () {
						            this.getElement().setVisible(false);
						        }, this);
						        e.stopPropagation();
						    };

						    return Shooter;
						});
					
						sap.ui.define(["sap/ui/dt/Plugin"], function (Plugin) {
						    var Shooter = Plugin.extend("custom.ushell.plugin.shooter.designtime.Shooter");

						    Shooter.prototype.registerElementOverlay = function (oOverlay) {
						        oOverlay.attachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype.deregisterElementOverlay = function (oOverlay) {
						        oOverlay.detachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype._onClick = function (e) {
						        this.setSelected(false);
						        this.addStyleClass("sapUiDtOverlayPoof");
						        this.attachBrowserEvent("animationend", function () {
						            this.getElement().setVisible(false);
						        }, this);
						        e.stopPropagation();
						    };

						    return Shooter;
						});
					
						sap.ui.define(["sap/ui/dt/Plugin"], function (Plugin) {
						    var Shooter = Plugin.extend("custom.ushell.plugin.shooter.designtime.Shooter");

						    Shooter.prototype.registerElementOverlay = function (oOverlay) {
						        oOverlay.attachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype.deregisterElementOverlay = function (oOverlay) {
						        oOverlay.detachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype._onClick = function (e) {
						        this.setSelected(false);
						        this.addStyleClass("sapUiDtOverlayPoof");
						        this.attachBrowserEvent("animationend", function () {
						            this.getElement().setVisible(false);
						        }, this);
						        e.stopPropagation();
						    };

						    return Shooter;
						});
					
						sap.ui.define(["sap/ui/dt/Plugin"], function (Plugin) {
						    var Shooter = Plugin.extend("custom.ushell.plugin.shooter.designtime.Shooter");

						    Shooter.prototype.registerElementOverlay = function (oOverlay) {
						        oOverlay.attachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype.deregisterElementOverlay = function (oOverlay) {
						        oOverlay.detachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype._onClick = function (e) {
						        this.setSelected(false);
						        this.addStyleClass("sapUiDtOverlayPoof");
						        this.attachBrowserEvent("animationend", function () {
						            this.getElement().setVisible(false);
						        }, this);
						        e.stopPropagation();
						    };

						    return Shooter;
						});
					
						sap.ui.define(["sap/ui/dt/Plugin"], function (Plugin) {
						    var Shooter = Plugin.extend("custom.ushell.plugin.shooter.designtime.Shooter");

						    Shooter.prototype.registerElementOverlay = function (oOverlay) {
						        oOverlay.attachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype.deregisterElementOverlay = function (oOverlay) {
						        oOverlay.detachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype._onClick = function (e) {
						        this.setSelected(false);
						        this.addStyleClass("sapUiDtOverlayPoof");
						        this.attachBrowserEvent("animationend", function () {
						            this.getElement().setVisible(false);
						        }, this);
						        e.stopPropagation();
						    };

						    return Shooter;
						});
					
						sap.ui.define(["sap/ui/dt/Plugin"], function (Plugin) {
						    var Shooter = Plugin.extend("custom.ushell.plugin.shooter.designtime.Shooter");

						    Shooter.prototype.registerElementOverlay = function (oOverlay) {
						        oOverlay.attachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype.deregisterElementOverlay = function (oOverlay) {
						        oOverlay.detachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype._onClick = function (e) {
						        this.setSelected(false);
						        this.addStyleClass("sapUiDtOverlayPoof");
						        this.attachBrowserEvent("animationend", function () {
						            this.getElement().setVisible(false);
						        }, this);
						        e.stopPropagation();
						    };

						    return Shooter;
						});
					
						sap.ui.define(["sap/ui/dt/Plugin"], function (Plugin) {
						    var Shooter = Plugin.extend("custom.ushell.plugin.shooter.designtime.Shooter");

						    Shooter.prototype.registerElementOverlay = function (oOverlay) {
						        oOverlay.attachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype.deregisterElementOverlay = function (oOverlay) {
						        oOverlay.detachBrowserEvent("dblclick", this._onClick, oOverlay);
						    };

						    Shooter.prototype._onClick = function (e) {
						        this.setSelected(false);
						        this.addStyleClass("sapUiDtOverlayPoof");
						        this.attachBrowserEvent("animationend", function () {
						            this.getElement().setVisible(false);
						        }, this);
						        e.stopPropagation();
						    };

						    return Shooter;
						});
					

Summary

— UI5 has intruments to build WYSIWYG tooling
— Most UI5 controls have already pre-defined design time metadata
— Available since 1.30 (experimental, but stable enough)
— We need you feedback
— Stay curious, explore and don't reinvent the wheel!
Thank you.

Contact information:

Sebastian Wennemers, @S7nW7s (Twitter)
Pavel Kornev, @pavelkornev (Twitter, GitHub, LinkedIn)
Source code — https://pavelkornev.github.io/ui5con2019-designtime-example/
Slides — https://pavelkornev.github.io/ui5con2019-designtime-slides/