From 953bf45ef303f8d05ab3a39e15e420a2ac94f61a Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Mon, 11 Dec 2017 12:10:36 +0100 Subject: [PATCH] Created How to port an app to et2 (markdown) --- How-to-port-an-app-to-et2.md | 164 +++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 How-to-port-an-app-to-et2.md diff --git a/How-to-port-an-app-to-et2.md b/How-to-port-an-app-to-et2.md new file mode 100644 index 0000000..c896d29 --- /dev/null +++ b/How-to-port-an-app-to-et2.md @@ -0,0 +1,164 @@ +## Introduction +Any EGroupware application running under any version below 14.1 uses an old etemplate system which needs to be adopted to new templating system called etemplate2 or et2. The et2 is EGroupware templating engine based on a particular xml template formats called xet, and it compiles and runs all widgets in client-side. + + +## Porting to et2 +As a show case scenario, we would like to port an app like Timesheet from epl 11.1 which uses etemplate to et2. + +### Step 1: Use new etemplate class +With all new api changes, first we need to add Etemplate namespace to the begining of our class. +``` +use EGroupware\Api\Etemplate; + +``` + +Then we should look for lines where we have old etemplate definitions and replace them with new Etemplate class definition. + +**Original Code:** +``` +function edit($content = null,$view = false) + { + $etpl = new etemplate ('timesheet.edit'); +``` +**New Code:** +``` +function edit($content = null,$view = false) + { + $etpl = new Etemplate ('timesheet.edit'); +``` +### Step 2: Add new version dependancy +We need to add new version dependency in our app dependency. For instance, add version 17.1 to our timesheet dependencies in setup: + +timesheet/setup/setup.inc.php + +**Original Code:** +``` +/* Dependencies for this app to work */ +$setup_info[TIMESHEET_APP]['depends'][] = array( + 'appname' => 'phpgwapi', + 'versions' => Array('1.7','1.8','1.9') +); +$setup_info[TIMESHEET_APP]['depends'][] = array( + 'appname' => 'etemplate', + 'versions' => Array('1.7','1.8','1.9') +); +``` +**New Code:** +``` +$setup_info[TIMESHEET_APP]['depends'][] = array( + 'appname' => 'api', + 'versions' => Array('17.1') +); +``` + +**Step 3: Add app.js in order to write application specific javaScript code** + +In order to actually get advantage of et2 technology and writing our own application javascript specific codes by using lots of powerful client-side APIs, its a good practice to define a app.js under AppFolder?/js folder. In this case we would create an app.js file under timesheet\js\app.js. + + +``` +app.classes.timesheet = AppJS.extend( +{ + appname: 'timesheet', + /** + * et2 widget container + */ + et2: null, + /** + * path widget + */ + + /** + * Constructor + * + * @memberOf app.timesheet + */ + init: function() + { + // call parent + this._super.apply(this, arguments); + }, + + /** + * Destructor + */ + destroy: function() + { + delete this.et2; + // call parent + this._super.apply(this, arguments); + }, + + /** + * This function is called when the etemplate2 object is loaded + * and ready. If you must store a reference to the et2 object, + * make sure to clean it up in destroy(). + * + * @param et2 etemplate2 Newly ready object + */ + et2_ready: function(et2) + { + // call parent + this._super.apply(this, arguments); + + }, + +}); + +``` +**Note: this is just a good practice example to show how to define an app.js for timesheet app. Options for defining new object and functions inside that app.js object is endless.** + +Inline Scripts and Content Security Policy (CSP): et2 uses CSP which is very restricted about inline scripts, therefore in order to take advantage of CSP we should make our code compatible with it by not using inline scripts and instead trying to implement them in our app.js. For instance in our timesheet scenario we do have couple of inline javascript statements which we need to port them, like: + +**Original Code** +``` +function index($content = null,$msg='') +{ + ... + ... + $content['nm'] = array( + ... + ... + + 'filter_onchange' => "set_style_by_class('table','custom_hide','visibility',this.value == 'custom' ? 'visible' : 'hidden'); if (this.value != 'custom') this.form.submit();", + ... + ... + + ); + +``` + +**New Code** +``` +function index($content = null,$msg='') +{ + ... + ... + $content['nm'] = array( + ... + ... + + 'filter_onchange' =>"app.timesheet.filter_change();", + ... + ... + + ); +``` + +And we need to implement our filter_change method in app.js file, like: +``` +filter_change: function() +{ + var filter = this.et2.getWidgetById('filter'); + var dates = this.et2.getWidgetById('timesheet.index.dates'); + if (filter && dates) + { + dates.set_disabled(filter.value !== "custom"); + } +}, +``` +As you see in filter_change method we used some API methods which may not be familiar for you. In order to get more information about et2 client-side APIs and widgets you may have a look at sources in api\js\etemplate files which contain all widgets. In addition, you may browse widgets by a widget browser located in etemplate->etemplate2 Reference (see fig.01) + + + +