<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.open-xchange.com/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mattes</id>
	<title>Open-Xchange - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.open-xchange.com/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mattes"/>
	<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Special:Contributions/Mattes"/>
	<updated>2026-06-30T21:45:00Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Test_basics&amp;diff=17366</id>
		<title>AppSuite:Test basics</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Test_basics&amp;diff=17366"/>
		<updated>2014-04-03T19:54:10Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Lessons learned painfully while doing testing:&lt;br /&gt;
* PhantomJS thinks it is a '''touch''' device (Modernizr.touch === true)&lt;br /&gt;
* Almost no CSS is loaded. Don't rely on classes like &amp;quot;hidden&amp;quot; (bootstrap class)&lt;br /&gt;
* Turn off CSS transitions - any DOM-based test might fail (caused by random DOM reflow delay)&lt;br /&gt;
* Don't clear &amp;lt;body&amp;gt; (e.g. $(document.body).empty()). UI is not robust against that.&lt;br /&gt;
* The browser window is elastic. It has no fixed size. Usually affects scrolling tests.&lt;br /&gt;
* If weird things happen, try to check if your app/window/node is really still in the DOM.&lt;br /&gt;
* HTML fixtures cannot be loaded (don't know why yet); just rename your files to *.txt&lt;br /&gt;
* Please mind that your fake server only works inside &amp;quot;description&amp;quot; (not across specs)&lt;br /&gt;
* PhantomJS fails at: Date.parse(&amp;quot;2012-01-01&amp;quot;); (see https://code.google.com/p/phantomjs/issues/detail?id=267#c2)&lt;br /&gt;
* The fake server is global, if someone has registered your desired api/call already, your response will never get send&lt;br /&gt;
* Any checks for z-index will probably fail due to the lack of loaded CSS. If an element is not positioned (relative or absolute) the computed style is &amp;quot;auto&amp;quot;. Just reposition affected elements in your spec.&lt;br /&gt;
&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Testing]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Test_basics&amp;diff=17356</id>
		<title>AppSuite:Test basics</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Test_basics&amp;diff=17356"/>
		<updated>2014-03-31T20:05:10Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Lessons learned painfully while doing testing:&lt;br /&gt;
* PhantomJS thinks it is a '''touch''' device (Modernizr.touch === true)&lt;br /&gt;
* Almost no CSS is loaded. Don't rely on classes like &amp;quot;hidden&amp;quot; (bootstrap class)&lt;br /&gt;
* Turn off CSS transitions - any DOM-based test might fail (caused by random DOM reflow delay)&lt;br /&gt;
* Don't clear &amp;lt;body&amp;gt; (e.g. $(document.body).empty()). UI is not robust against that.&lt;br /&gt;
* The browser window is elastic. It has no fixed size. Usually affects scrolling tests.&lt;br /&gt;
* If weird things happen, try to check if your app/window/node is really still in the DOM.&lt;br /&gt;
* HTML fixtures cannot be loaded (don't know why yet); just rename your files to *.txt&lt;br /&gt;
* Please mind that your fake server only works inside &amp;quot;description&amp;quot; (not across specs)&lt;br /&gt;
* PhantomJS fails at: Date.parse(&amp;quot;2012-01-01&amp;quot;); (see https://code.google.com/p/phantomjs/issues/detail?id=267#c2)&lt;br /&gt;
* The fake server is global, if someone has registered your desired api/call already, your response will never get send&lt;br /&gt;
&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Testing]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Test_basics&amp;diff=17355</id>
		<title>AppSuite:Test basics</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Test_basics&amp;diff=17355"/>
		<updated>2014-03-31T20:04:57Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Lessons learned painfully while doing testing:&lt;br /&gt;
* PhantomJS thinks it is a '''touch''' device (Modernizr.touch === true)&lt;br /&gt;
* Almost no CSS is loaded. Don't rely on classes like &amp;quot;hidden&amp;quot; (bootstrap class)&lt;br /&gt;
* Turn off CSS transition - any DOM-based test might fail (caused by random DOM reflow delay)&lt;br /&gt;
* Don't clear &amp;lt;body&amp;gt; (e.g. $(document.body).empty()). UI is not robust against that.&lt;br /&gt;
* The browser window is elastic. It has no fixed size. Usually affects scrolling tests.&lt;br /&gt;
* If weird things happen, try to check if your app/window/node is really still in the DOM.&lt;br /&gt;
* HTML fixtures cannot be loaded (don't know why yet); just rename your files to *.txt&lt;br /&gt;
* Please mind that your fake server only works inside &amp;quot;description&amp;quot; (not across specs)&lt;br /&gt;
* PhantomJS fails at: Date.parse(&amp;quot;2012-01-01&amp;quot;); (see https://code.google.com/p/phantomjs/issues/detail?id=267#c2)&lt;br /&gt;
* The fake server is global, if someone has registered your desired api/call already, your response will never get send&lt;br /&gt;
&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Testing]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Embedding_your_settings_into_AppSuite_settings&amp;diff=17312</id>
		<title>AppSuite:Embedding your settings into AppSuite settings</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Embedding_your_settings_into_AppSuite_settings&amp;diff=17312"/>
		<updated>2014-03-21T08:21:58Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Declare the page you want to embed */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Embedding your settings into AppSuite settings&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Synopsis:'' This article explains how you can embed your own configuration page via iFrame into the AppSuite's settings and pass our session onto your implementation. This is a replacement for &amp;quot;Config Jump&amp;quot; of OX6. Not to be confused with [[AppSuite:Creating_a_settings_section_in_AppSuite_settings | simply adding new settings]] into AppSuite&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Declare the page you want to embed ==&lt;br /&gt;
&lt;br /&gt;
You can declare pages to embed via [[ConfigCascade|Config Cascade]] settings. There are several ways to do so, this example uses the most comfortable one, a YAML declaration:&lt;br /&gt;
&lt;br /&gt;
 ➜ /opt/open-xchange/etc/settings/configjump.yml&lt;br /&gt;
 io.ox/settings/configjump//changePlans:&lt;br /&gt;
    url: &amp;quot;http://localhost/~fla/changePlans.php?token=[token]&amp;quot;&lt;br /&gt;
    title: &amp;quot;Change Plan&amp;quot;&lt;br /&gt;
    after: &amp;quot;io.ox/mail&amp;quot;&lt;br /&gt;
&lt;br /&gt;
''io.ox/settings/configjump'' contains one object per embedded page (e.g. &amp;quot;changePlans&amp;quot;). If you want to add more pages, follow this pattern.&lt;br /&gt;
&lt;br /&gt;
An object of this type has the following properties:&lt;br /&gt;
&lt;br /&gt;
* '''url''': The URL to be branched to. The place holder [token] will be replaced by the token you get from the token login system&lt;br /&gt;
* '''title''': The title as to be seen on the settings page.&lt;br /&gt;
* '''after''', '''before''' or '''index''': Where the page is supposed to be positioned. ''Hint:'' If you want to name a page as reference (as opposed to using the index), you need to figure out the name. One way to do so is go to that page in the settings and check for the id parameter in the URL.&lt;br /&gt;
&lt;br /&gt;
It's also possible to provide custom translations for the title. Just add &amp;quot;title_&amp;quot; plus the locale:&lt;br /&gt;
 &lt;br /&gt;
 io.ox/settings/configjump//changePlans:&lt;br /&gt;
    url: &amp;quot;http://localhost/~fla/changePlans.php?token=[token]&amp;quot;&lt;br /&gt;
    title: &amp;quot;Change Plan&amp;quot;&lt;br /&gt;
    title_en_US: &amp;quot;Change plan&amp;quot;&lt;br /&gt;
    title_de_DE: &amp;quot;Plan ändern&amp;quot;&lt;br /&gt;
    title_fr_FR: &amp;quot;...&amp;quot;&lt;br /&gt;
    ...&lt;br /&gt;
    after: &amp;quot;io.ox/mail&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Create a secret ==&lt;br /&gt;
&lt;br /&gt;
Now you just need to declare the app your are about to embed in the backend and you are good to go:&lt;br /&gt;
&lt;br /&gt;
 ➜ cat /opt/open-xchange/etc/tokenlogin-secrets&lt;br /&gt;
 #&lt;br /&gt;
 # Listing of known Web Application secrets followed by an optional semicolon-separated parameter list&lt;br /&gt;
 #&lt;br /&gt;
 # e.g. 1254654698621354; accessPasword=true&lt;br /&gt;
 #&lt;br /&gt;
 &lt;br /&gt;
 # Dummy entry&lt;br /&gt;
 # 1234-56789-98765-4321; accessPassword=true&lt;br /&gt;
 12345-phpapp-54321&lt;br /&gt;
&lt;br /&gt;
This secret, combined with the token, can be traded for a login.&lt;br /&gt;
&lt;br /&gt;
== Redeem a token ==&lt;br /&gt;
&lt;br /&gt;
 GET /login?action=redeemToken&lt;br /&gt;
&lt;br /&gt;
* '''token''': The token you want to trade.&lt;br /&gt;
* '''secret''': A valid secret for your app.&lt;br /&gt;
&lt;br /&gt;
This request can be sent by the embedded app to the AppSuite backend to get authorisation info.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
&lt;br /&gt;
[[Category:UI]][[Category:Backend]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]][[Category:Developer]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Stuck somewhere? ==&lt;br /&gt;
You got stuck with a problem while developing? OXpedia might help you out with the article about [[AppSuite:Debugging_the_UI | debugging the UI]].&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Embedding_your_settings_into_AppSuite_settings&amp;diff=17311</id>
		<title>AppSuite:Embedding your settings into AppSuite settings</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Embedding_your_settings_into_AppSuite_settings&amp;diff=17311"/>
		<updated>2014-03-21T08:21:25Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Declare the page you want to embed */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Embedding your settings into AppSuite settings&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Synopsis:'' This article explains how you can embed your own configuration page via iFrame into the AppSuite's settings and pass our session onto your implementation. This is a replacement for &amp;quot;Config Jump&amp;quot; of OX6. Not to be confused with [[AppSuite:Creating_a_settings_section_in_AppSuite_settings | simply adding new settings]] into AppSuite&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Declare the page you want to embed ==&lt;br /&gt;
&lt;br /&gt;
You can declare pages to embed via [[ConfigCascade|Config Cascade]] settings. There are several ways to do so, this example uses the most comfortable one, a YAML declaration:&lt;br /&gt;
&lt;br /&gt;
 ➜ /opt/open-xchange/etc/settings/configjump.yml&lt;br /&gt;
 io.ox/settings/configjump//changePlans:&lt;br /&gt;
    url: &amp;quot;http://localhost/~fla/changePlans.php?token=[token]&amp;quot;&lt;br /&gt;
    title: &amp;quot;Change Plan&amp;quot;&lt;br /&gt;
    after: &amp;quot;io.ox/mail&amp;quot;&lt;br /&gt;
&lt;br /&gt;
''io.ox/settings/configjump'' contains one object per embedded page (e.g. &amp;quot;changePlans&amp;quot;). If you want to add more pages, follow this pattern.&lt;br /&gt;
&lt;br /&gt;
An object of this type has the following properties:&lt;br /&gt;
&lt;br /&gt;
* '''url''': The URL to be branched to. The place holder [token] will be replaced by the token you get from the token login system&lt;br /&gt;
* '''title''': The title as to be seen on the settings page.&lt;br /&gt;
* '''after''', '''before''' or '''index''': Where the page is supposed to be positioned. ''Hint:'' If you want to name a page as reference (as opposed to using the index), you need to figure out the name. One way to do so is go to that page in the settings and check for the id parameter in the URL.&lt;br /&gt;
&lt;br /&gt;
It's also possible to provide custom translations for the title. Just add &amp;quot;title_&amp;quot; plus the locale:&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
io.ox/settings/configjump//changePlans:&lt;br /&gt;
    url: &amp;quot;http://localhost/~fla/changePlans.php?token=[token]&amp;quot;&lt;br /&gt;
    title: &amp;quot;Change Plan&amp;quot;&lt;br /&gt;
    title_en_US: &amp;quot;Change plan&amp;quot;&lt;br /&gt;
    title_de_DE: &amp;quot;Plan ändern&amp;quot;&lt;br /&gt;
    title_fr_FR: &amp;quot;...&amp;quot;&lt;br /&gt;
    ...&lt;br /&gt;
    after: &amp;quot;io.ox/mail&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Create a secret ==&lt;br /&gt;
&lt;br /&gt;
Now you just need to declare the app your are about to embed in the backend and you are good to go:&lt;br /&gt;
&lt;br /&gt;
 ➜ cat /opt/open-xchange/etc/tokenlogin-secrets&lt;br /&gt;
 #&lt;br /&gt;
 # Listing of known Web Application secrets followed by an optional semicolon-separated parameter list&lt;br /&gt;
 #&lt;br /&gt;
 # e.g. 1254654698621354; accessPasword=true&lt;br /&gt;
 #&lt;br /&gt;
 &lt;br /&gt;
 # Dummy entry&lt;br /&gt;
 # 1234-56789-98765-4321; accessPassword=true&lt;br /&gt;
 12345-phpapp-54321&lt;br /&gt;
&lt;br /&gt;
This secret, combined with the token, can be traded for a login.&lt;br /&gt;
&lt;br /&gt;
== Redeem a token ==&lt;br /&gt;
&lt;br /&gt;
 GET /login?action=redeemToken&lt;br /&gt;
&lt;br /&gt;
* '''token''': The token you want to trade.&lt;br /&gt;
* '''secret''': A valid secret for your app.&lt;br /&gt;
&lt;br /&gt;
This request can be sent by the embedded app to the AppSuite backend to get authorisation info.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
&lt;br /&gt;
[[Category:UI]][[Category:Backend]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]][[Category:Developer]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Stuck somewhere? ==&lt;br /&gt;
You got stuck with a problem while developing? OXpedia might help you out with the article about [[AppSuite:Debugging_the_UI | debugging the UI]].&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Apache_Configuration&amp;diff=17255</id>
		<title>AppSuite:Apache Configuration</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Apache_Configuration&amp;diff=17255"/>
		<updated>2014-03-12T13:35:02Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stability-experimental}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Apache Configuration&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
To setup your development environment please follow these steps.&lt;br /&gt;
&lt;br /&gt;
==Setup build system==&lt;br /&gt;
# Check out the UI from git&lt;br /&gt;
# Figure out Apache's document root. Common places are:&amp;lt;br&amp;gt;MacOS: /Library/WebServer/Documents&amp;lt;br&amp;gt;Linux: /var/www&lt;br /&gt;
# Create a new folder appsuite in Apache's document root&lt;br /&gt;
# You need node.js to build the UI. For MacOS (use /var/www instead of /Library/WebServer/Documents for debian).&lt;br /&gt;
&lt;br /&gt;
===Installing node.js===&lt;br /&gt;
# Visit https://sites.google.com/site/nodejsmacosx/ and install stable version.&lt;br /&gt;
# Open terminal&lt;br /&gt;
# Set environment variable:&amp;lt;br&amp;gt;''export builddir=&amp;quot;/Library/WebServer/Documents/appsuite&amp;quot;''&lt;br /&gt;
# Build UI: '''./build.sh'''&lt;br /&gt;
# Note: Instead of exporting the builddir every time your want to build the ui or run the appserver, you can also create a file '''local.conf''' and set the directory in there. This way, every time the buildsystem or appserver runs, it automatically picks up the correct directory.&amp;lt;br&amp;gt;local.conf: ''export builddir=&amp;quot;/Library/WebServer/Documents/appsuite&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
===AppServer===&lt;br /&gt;
Run the app loading server: '''./appserver.sh''' Don't worry: If it doesn't tell you anything it's happily running.&lt;br /&gt;
&lt;br /&gt;
==Apache config==&lt;br /&gt;
Make sure Apache loads the following modules:&amp;lt;br&amp;gt;''mod_proxy, mod_proxy_ajp, mod_expires, mod_deflate, mod_rewrite, mod_headers, mod_mime, and mod_setenvif''&lt;br /&gt;
&lt;br /&gt;
Tell your Apache to process .htaccess files and how to connect to backend:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-conf&amp;quot;&amp;gt;&lt;br /&gt;
ProxyPass /appsuite/api/apps/load/ http://localhost:8337/apps/load/&lt;br /&gt;
ProxyPass /appsuite/api ajp://127.0.0.1:8009/ajax &lt;br /&gt;
# optional parameters: retry=0 connectiontimeout=5 timeout=10&lt;br /&gt;
&lt;br /&gt;
&amp;amp;lt;Directory /Library/WebServer/Documents/appsuite&amp;gt;&lt;br /&gt;
  Options None +FollowSymLinks&lt;br /&gt;
  AllowOverride Indexes FileInfo&lt;br /&gt;
&amp;amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use the proper document root depending on your OS or custom configuration! If backend does not run on localhost (127.0.0.1), you have to adjust the ProxyPass directive.&lt;br /&gt;
&lt;br /&gt;
'''Restart Apache''', e.g. sudo apachectl restart. And please double check everything you're doing!&lt;br /&gt;
&lt;br /&gt;
==Setup SSL support on MacOS==&lt;br /&gt;
&lt;br /&gt;
Based on: http://webdevstudios.com/2013/05/24/how-to-set-up-ssl-with-osx-mountain-lions-built-in-apache/&lt;br /&gt;
&lt;br /&gt;
* Open terminal and '''cd /private/etc/apache2'''&lt;br /&gt;
* Become root: '''sudo su'''&lt;br /&gt;
* '''mkdir ssl'''&lt;br /&gt;
* Open ''httpd.conf'' in your text editor, e.g. '''vim httpd.conf'''&lt;br /&gt;
** Make sure the SSL module is enabled if it’s not. Do this by uncommenting (aka, remove the ‘#’ symbol in front) the line that looks like: ''LoadModule ssl_module libexec/apache2/mod_ssl.so''&lt;br /&gt;
** In the same file search for and uncomment (remove the #) this line: ''Include /private/etc/apache2/extra/httpd-ssl.conf''&lt;br /&gt;
** Save and close.&lt;br /&gt;
* Now open ''httpd-ssl.conf'' file in your text editor, e.g. '''vim httpd-ssl.conf'''&lt;br /&gt;
** Make sure '''ServerName''' line looks like: ''ServerName localhost''&lt;br /&gt;
** Modify '''ServerAdmin''' line to use one of your email addresses&lt;br /&gt;
** '''SSLCertificateFile &amp;quot;/private/etc/apache2/ssl/ssl.crt&amp;quot;'''&lt;br /&gt;
** '''SSLCertificateKeyFile &amp;quot;/private/etc/apache2/ssl/ssl.key&amp;quot;'''&lt;br /&gt;
** In the same file comment out (add a # to the beginning of the line) the '''SSLCACertificatePath''' and '''SSLCARevocationPath''' lines if they’re not already.&lt;br /&gt;
** Save and close.&lt;br /&gt;
* Now go to new ssl folder: '''cd /private/etc/apache2/ssl'''&lt;br /&gt;
** The following steps are based on http://www.akadia.com/services/ssh_test_certificate.html&amp;lt;br&amp;gt;Don't have to read, just run the following commands:&lt;br /&gt;
** '''openssl genrsa -des3 -out server.key 1024'''&amp;lt;br&amp;gt;Pass-phrase can be anything stupid, we'll remove it&lt;br /&gt;
** '''openssl req -new -key server.key -out server.csr'''&lt;br /&gt;
** '''cp server.key server.key.org&amp;lt;br&amp;gt;openssl rsa -in server.key.org -out server.key'''&lt;br /&gt;
** '''openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt'''&lt;br /&gt;
* Restart apache: '''apachectl restart'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Changes&amp;diff=17154</id>
		<title>AppSuite:Changes</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Changes&amp;diff=17154"/>
		<updated>2014-02-25T13:19:04Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Changes&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.6.0 ==&lt;br /&gt;
&lt;br /&gt;
=== grunt ===&lt;br /&gt;
grunt has superseded jake as a build system. In this section all changes will be described.&lt;br /&gt;
&lt;br /&gt;
Instead of a shell wrapper around jake (the `build-appsuite` script), grunt should now be invoked&lt;br /&gt;
directly. The recommended workflow will be described in the next subsections, where all tasks relevant&lt;br /&gt;
for development will be explained in detail.&lt;br /&gt;
&lt;br /&gt;
Grunt is a well documented task-runner (see http://gruntjs.com) and there is a large community writing plugins.&lt;br /&gt;
Unless stated otherwise, we implemented standard grunt behaviour and rely on best-practice introduced by the&lt;br /&gt;
grunt community.&lt;br /&gt;
&lt;br /&gt;
==== local configuration ====&lt;br /&gt;
All local configuration is now done in `grunt/local.conf.json` using the JSON format. This replaces&lt;br /&gt;
the `local.conf` file, that was sourced into build-appsuite shell script. This new way is more platform&lt;br /&gt;
independent.&lt;br /&gt;
&lt;br /&gt;
=== appserver ===&lt;br /&gt;
The functionality of the appserver is now provided by the grunt-contrib-connect plugin. The `connect` task&lt;br /&gt;
should be run in conjunction with the `watch` task like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
grunt connect watch&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will start the appserver middleware and start watching for changed files. In case you don't want this&lt;br /&gt;
behaviour, you have to start the `connect` task with the keepalive option (as documented in grunt-contrib-connect documentation):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
grunt connect:server:keepalive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Bower ===&lt;br /&gt;
Most of our third party front-end libraries are now managed via bower. The location for these libraries has changed from lib/ to bower_components/. These files will be handled when building by the new grunt build system and copied or concatinated accordingly.&lt;br /&gt;
&lt;br /&gt;
**Warning: Manual editing/patching/hacking files in &amp;quot;bower_components/&amp;quot; is deprecated.**&lt;br /&gt;
&lt;br /&gt;
_However if you are positive that there is a bug in one of these libraries a possible course of action would be to fork the package on github and commit your patch there and create an upstream pull request, in any case this should be handled by the frontend team._&lt;br /&gt;
&lt;br /&gt;
An up-to-date list of packages maintained by bower can be reviewed in the bower.json file in the ui root.&lt;br /&gt;
&lt;br /&gt;
* jquery&lt;br /&gt;
* underscore&lt;br /&gt;
* mediaelement&lt;br /&gt;
* bootstrap&lt;br /&gt;
* bootstrap-datepicker&lt;br /&gt;
* bootstrap-typeahead&lt;br /&gt;
* font-awesome&lt;br /&gt;
* open-sans-fontface&lt;br /&gt;
* backbone&lt;br /&gt;
* backbone-validation&lt;br /&gt;
* Chart.js&lt;br /&gt;
* bigscreen&lt;br /&gt;
* jquery-placeholder&lt;br /&gt;
* jquery-imageloader&lt;br /&gt;
* textarea-helper&lt;br /&gt;
* requirejs&lt;br /&gt;
* bootstrap-accessibility-plugin&lt;br /&gt;
&lt;br /&gt;
Read more about bower [http://bower.io].&lt;br /&gt;
&lt;br /&gt;
=== Require.js ===&lt;br /&gt;
Require.js updated from 2.1.8 to 2.1.11&lt;br /&gt;
&lt;br /&gt;
We also changed the way style files are included in the require.js define() method.&lt;br /&gt;
less and css files are now defined in the same way as javascript files, WITHOUT its extension.&lt;br /&gt;
&lt;br /&gt;
* less!io.ox/calendar/style.less =&amp;gt; less!io.ox/calendar/style&lt;br /&gt;
* css!io.ox/calendar/style.css =&amp;gt; css!io.ox/calendar/style&lt;br /&gt;
&lt;br /&gt;
=== jQuery ===&lt;br /&gt;
jQuery was updated from 2.0.3 to 2.1.0&lt;br /&gt;
&lt;br /&gt;
If you experience any issues please check [this blogpost](http://blog.jquery.com/2014/01/24/jquery-1-11-and-2-1-released/) for changes.&lt;br /&gt;
&lt;br /&gt;
=== Underscore.js ===&lt;br /&gt;
&lt;br /&gt;
Underscore was updated from Version 1.4.4 to Version 1.6&lt;br /&gt;
&lt;br /&gt;
Please read the [changelog](http://underscorejs.org/#changelog).&lt;br /&gt;
&lt;br /&gt;
**Hint: Look for &amp;quot;Removed the ability to call _.bindAll with no method name arguments&amp;quot;, this was pretty much the only issue we had whilst updating.**&lt;br /&gt;
&lt;br /&gt;
=== Backbone.js ===&lt;br /&gt;
&lt;br /&gt;
Backbone.js was updated from 0.9.x to Version 1.0.0&lt;br /&gt;
&lt;br /&gt;
Please read the [changelog](http://backbonejs.org/#changelog).&lt;br /&gt;
&lt;br /&gt;
**Note: We currently cannot update to 1.1.2, which is the current version of backbone, but will do so in the near future, when we resolve our issues.**&lt;br /&gt;
&lt;br /&gt;
=== Bootstrap ===&lt;br /&gt;
&lt;br /&gt;
Bootstrap was updated from 2.2.2 to 3.1.1&lt;br /&gt;
&lt;br /&gt;
Please read the [Bootstrap 2 to Bootstrap 3 migration guide](http://getbootstrap.com/getting-started/#migration), as there are many significant changes, to markup and styles.&lt;br /&gt;
&lt;br /&gt;
All bootstrap plugins and our core components have been updated accordingly.&lt;br /&gt;
&lt;br /&gt;
**Note: In Bootstrap 3 the typeahead plugin was dropped in favor of Twitters typeahead.js. This change would break our current autocomplete functions, so we added the Bootstrap 3 Typeahead (https://github.com/bassjobsen/Bootstrap-3-Typeahead) for backwards-compatibility.**&lt;br /&gt;
&lt;br /&gt;
See also changes for themes below.&lt;br /&gt;
&lt;br /&gt;
=== Themes ===&lt;br /&gt;
&lt;br /&gt;
We cleaned up definitions.less and removed duplicate and obsolete definitions. If you want to override specific bootstrap default values you can do so by overriding variables from &amp;quot;/bower_components/bootstrap/less/variables.less&amp;quot; in your themes definitions.less file.&lt;br /&gt;
&lt;br /&gt;
Mixins were also removed from definitions and reside now in a seperate file &amp;quot;/apps/themes/mixins.less&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Font Awesome ===&lt;br /&gt;
&lt;br /&gt;
Font Awesome was updated to it's latest version (4.0.3).&lt;br /&gt;
You can read about the changes [here](http://fortawesome.github.io/Font-Awesome/whats-new/).&lt;br /&gt;
&lt;br /&gt;
These classes have been replaced in our core components:&lt;br /&gt;
&lt;br /&gt;
* icon-align-justify      =&amp;gt; fa fa-align-justify&lt;br /&gt;
* icon-align-left         =&amp;gt; fa fa-align-left&lt;br /&gt;
* icon-angle-left         =&amp;gt; fa fa-angle-left&lt;br /&gt;
* icon-angle-right        =&amp;gt; fa fa-angle-right&lt;br /&gt;
* icon-archive            =&amp;gt; fa fa-archive&lt;br /&gt;
* icon-arrow-down         =&amp;gt; fa fa-arrow-down&lt;br /&gt;
* icon-arrow-up           =&amp;gt; fa fa-arrow-up&lt;br /&gt;
* icon-book               =&amp;gt; fa fa-book&lt;br /&gt;
* icon-bookmark           =&amp;gt; fa fa-bookmark&lt;br /&gt;
* icon-bookmark-empty     =&amp;gt; fa fa-bookmark-o&lt;br /&gt;
* icon-caret-down         =&amp;gt; fa fa-caret-down&lt;br /&gt;
* icon-caret-right        =&amp;gt; fa fa-caret-right&lt;br /&gt;
* icon-chevron-left       =&amp;gt; fa fa-chevron-left&lt;br /&gt;
* icon-chevron-right      =&amp;gt; fa fa-chevron-right&lt;br /&gt;
* icon-circle             =&amp;gt; fa fa-circle&lt;br /&gt;
* icon-circle-arrow-right =&amp;gt; fa fa-circle-arrow-right&lt;br /&gt;
* icon-cloud-download     =&amp;gt; fa fa-cloud-download&lt;br /&gt;
* icon-cog                =&amp;gt; fa fa-cog&lt;br /&gt;
* icon-collapse-alt       =&amp;gt; fa fa-minus-square-o&lt;br /&gt;
* icon-comment-alt        =&amp;gt; fa fa-comment-o&lt;br /&gt;
* icon-download-alt       =&amp;gt; fa fa-download&lt;br /&gt;
* icon-edit               =&amp;gt; fa fa-edit&lt;br /&gt;
* icon-envelope           =&amp;gt; fa fa-envelope&lt;br /&gt;
* icon-envelope-alt       =&amp;gt; fa fa-envelope-o&lt;br /&gt;
* icon-exclamation        =&amp;gt; fa fa-exclamation&lt;br /&gt;
* icon-expand-alt         =&amp;gt; fa fa-plus-square-o&lt;br /&gt;
* icon-external-link      =&amp;gt; fa fa-external-link&lt;br /&gt;
* icon-external-link-sign =&amp;gt; fa fa-external-link-square&lt;br /&gt;
* icon-eye-open           =&amp;gt; fa fa-eye&lt;br /&gt;
* icon-file               =&amp;gt; fa fa-file&lt;br /&gt;
* icon-film               =&amp;gt; fa fa-film&lt;br /&gt;
* icon-folder-close       =&amp;gt; fa fa-folder&lt;br /&gt;
* icon-folder-open        =&amp;gt; fa fa-folder-open&lt;br /&gt;
* icon-gear               =&amp;gt; fa fa-cog&lt;br /&gt;
* icon-group              =&amp;gt; fa fa-group&lt;br /&gt;
* icon-list-alt           =&amp;gt; fa fa-list-alt&lt;br /&gt;
* icon-lock               =&amp;gt; fa fa-lock&lt;br /&gt;
* icon-magic              =&amp;gt; fa fa-magic&lt;br /&gt;
* icon-mail-forward       =&amp;gt; fa fa-mail-forward&lt;br /&gt;
* icon-minus-sign         =&amp;gt; fa fa-minus-circle&lt;br /&gt;
* icon-music              =&amp;gt; fa fa-music&lt;br /&gt;
* icon-ok                 =&amp;gt; fa fa-check&lt;br /&gt;
* icon-paper-clip         =&amp;gt; fa fa-paperclip&lt;br /&gt;
* icon-pencil             =&amp;gt; fa fa-pencil&lt;br /&gt;
* icon-picture            =&amp;gt; fa fa-picture-o&lt;br /&gt;
* icon-play               =&amp;gt; fa fa-play&lt;br /&gt;
* icon-plus-sign          =&amp;gt; fa fa-plus-circle&lt;br /&gt;
* icon-print              =&amp;gt; fa fa-print&lt;br /&gt;
* icon-qrcode             =&amp;gt; fa fa-qrcode&lt;br /&gt;
* icon-question-sign      =&amp;gt; fa fa-question-circle&lt;br /&gt;
* icon-refresh            =&amp;gt; fa fa-refresh&lt;br /&gt;
* icon-remove             =&amp;gt; fa fa-times&lt;br /&gt;
* icon-remove-circle      =&amp;gt; fa fa-times-circle&lt;br /&gt;
* icon-reorder            =&amp;gt; fa fa-bars&lt;br /&gt;
* icon-reply              =&amp;gt; fa fa-reply&lt;br /&gt;
* icon-resize-full        =&amp;gt; fa fa-expand&lt;br /&gt;
* icon-retweet            =&amp;gt; fa fa-retweet&lt;br /&gt;
* icon-rss                =&amp;gt; fa fa-rss&lt;br /&gt;
* icon-search             =&amp;gt; fa fa-search&lt;br /&gt;
* icon-shopping-cart      =&amp;gt; fa fa-shopping-cart&lt;br /&gt;
* icon-signin             =&amp;gt; fa fa-sign-in&lt;br /&gt;
* icon-spin               =&amp;gt; fa fa-spin&lt;br /&gt;
* icon-star               =&amp;gt; fa fa-star&lt;br /&gt;
* icon-table              =&amp;gt; fa fa-table&lt;br /&gt;
* icon-tag                =&amp;gt; fa fa-tag&lt;br /&gt;
* icon-th                 =&amp;gt; fa fa-th&lt;br /&gt;
* icon-th-large           =&amp;gt; fa fa-th-large&lt;br /&gt;
* icon-th-list            =&amp;gt; fa fa-th-list&lt;br /&gt;
* icon-tint               =&amp;gt; fa fa-tint&lt;br /&gt;
* icon-trash              =&amp;gt; fa fa-trash-o&lt;br /&gt;
* icon-unlock             =&amp;gt; fa fa-unlock&lt;br /&gt;
* icon-user               =&amp;gt; fa fa-user&lt;br /&gt;
&lt;br /&gt;
=== TinyMCE ===&lt;br /&gt;
&lt;br /&gt;
TinyMCE was updated from 3.4.7 to 3.5.10.&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Changes&amp;diff=17153</id>
		<title>AppSuite:Changes</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Changes&amp;diff=17153"/>
		<updated>2014-02-25T13:15:41Z</updated>

		<summary type="html">&lt;p&gt;Mattes: Created page with &amp;quot;&amp;lt;div class=&amp;quot;&amp;quot;&amp;gt;Changes&amp;lt;/div&amp;gt;  == 7.6.0 == Blaaaaa&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;&amp;quot;&amp;gt;Changes&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 7.6.0 ==&lt;br /&gt;
Blaaaaa&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:GettingStartedWithGrunt&amp;diff=17144</id>
		<title>AppSuite:GettingStartedWithGrunt</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:GettingStartedWithGrunt&amp;diff=17144"/>
		<updated>2014-02-24T16:44:19Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Getting started with grunt&amp;lt;/div&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
== Node ==&lt;br /&gt;
&lt;br /&gt;
=== Linux ===&lt;br /&gt;
&lt;br /&gt;
Install the default nodejs of your distribution via your favourite package/ports manager and you are good to go.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Head to the node.js [http://nodejs.org/ site] and download and install the latest version.&lt;br /&gt;
It is recommended to restart after the installation, as paths may not be up-to-date.&lt;br /&gt;
&lt;br /&gt;
=== Mac OS X ===&lt;br /&gt;
&lt;br /&gt;
We strongly encourage you to use [http://brew.sh/ homebrew].&lt;br /&gt;
Make sure you have checked your homebrew installation with &amp;lt;tt&amp;gt;brew doctor&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Install node via &amp;lt;tt&amp;gt;brew install node&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Make sure you don't &amp;lt;tt&amp;gt;sudo&amp;lt;/tt&amp;gt; anything related to node. If you think you have to, you are doing something wrong and are probably dealing with a broken homebrew/macports installation! If this is the case, the easiest way of resolving this is completely deleting the homebrew (and if present macports) directories and (re)installing homebrew.&lt;br /&gt;
&lt;br /&gt;
The default system's max opened file limit in mac os x is very low (256), in order to use grunt watch, it needs to be increased.&lt;br /&gt;
&lt;br /&gt;
You can either set this in your shell via &amp;lt;tt&amp;gt;ulimit -n 8192&amp;lt;/tt&amp;gt; to a sensible value or you can set&lt;br /&gt;
it permanently by adding&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;limit maxfiles 8192 20480&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to &amp;lt;tt&amp;gt;/etc/launchd.conf&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Grunt &amp;amp; Bower ==&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;tt&amp;gt;npm install -g bower grunt-cli&amp;lt;/tt&amp;gt; you can install the global npm dependencies needed for grunt and bower.&lt;br /&gt;
&lt;br /&gt;
== Installing node dependencies for OX Appsuite Frontend development ==&lt;br /&gt;
&lt;br /&gt;
Change to the ui directory of your git workdirectory and run &amp;lt;tt&amp;gt;npm install&amp;lt;/tt&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:GettingStartedWithGrunt&amp;diff=17143</id>
		<title>AppSuite:GettingStartedWithGrunt</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:GettingStartedWithGrunt&amp;diff=17143"/>
		<updated>2014-02-24T16:43:47Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Getting started with grunt&amp;lt;/div&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
= Node =&lt;br /&gt;
&lt;br /&gt;
== Linux ==&lt;br /&gt;
&lt;br /&gt;
Install the default nodejs of your distribution via your favourite package/ports manager and you are good to go.&lt;br /&gt;
&lt;br /&gt;
== Windows ==&lt;br /&gt;
&lt;br /&gt;
Head to the node.js [http://nodejs.org/ site] and download and install the latest version.&lt;br /&gt;
It is recommended to restart after the installation, as paths may not be up-to-date.&lt;br /&gt;
&lt;br /&gt;
== Mac OS X ==&lt;br /&gt;
&lt;br /&gt;
We strongly encourage you to use [http://brew.sh/ homebrew].&lt;br /&gt;
Make sure you have checked your homebrew installation with &amp;lt;tt&amp;gt;brew doctor&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Install node via &amp;lt;tt&amp;gt;brew install node&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Make sure you don't &amp;lt;tt&amp;gt;sudo&amp;lt;/tt&amp;gt; anything related to node. If you think you have to, you are doing something wrong and are probably dealing with a broken homebrew/macports installation! If this is the case, the easiest way of resolving this is completely deleting the homebrew (and if present macports) directories and (re)installing homebrew.&lt;br /&gt;
&lt;br /&gt;
The default system's max opened file limit in mac os x is very low (256), in order to use grunt watch, it needs to be increased.&lt;br /&gt;
&lt;br /&gt;
You can either set this in your shell via &amp;lt;tt&amp;gt;ulimit -n 8192&amp;lt;/tt&amp;gt; to a sensible value or you can set&lt;br /&gt;
it permanently by adding&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;limit maxfiles 8192 20480&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to &amp;lt;tt&amp;gt;/etc/launchd.conf&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= Grunt &amp;amp; Bower =&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;tt&amp;gt;npm install -g bower grunt-cli&amp;lt;/tt&amp;gt; you can install the global npm dependencies needed for grunt and bower.&lt;br /&gt;
&lt;br /&gt;
= Installing node dependencies for OX Appsuite Frontend development =&lt;br /&gt;
&lt;br /&gt;
Change to the ui directory of your git workdirectory and run &amp;lt;tt&amp;gt;npm install&amp;lt;/tt&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:GettingStartedWithGrunt&amp;diff=17142</id>
		<title>AppSuite:GettingStartedWithGrunt</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:GettingStartedWithGrunt&amp;diff=17142"/>
		<updated>2014-02-24T16:43:04Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Getting started with grunt&amp;lt;/div&amp;gt;&lt;br /&gt;
__TOC__&lt;br /&gt;
= Prerequisites =&lt;br /&gt;
&lt;br /&gt;
== Node ==&lt;br /&gt;
&lt;br /&gt;
=== Linux ===&lt;br /&gt;
&lt;br /&gt;
Install the default nodejs of your distribution via your favourite package/ports manager and you are good to go.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Head to the node.js [http://nodejs.org/ site] and download and install the latest version.&lt;br /&gt;
It is recommended to restart after the installation, as paths may not be up-to-date.&lt;br /&gt;
&lt;br /&gt;
=== Mac OS X ===&lt;br /&gt;
&lt;br /&gt;
We strongly encourage you to use [http://brew.sh/ homebrew].&lt;br /&gt;
Make sure you have checked your homebrew installation with &amp;lt;tt&amp;gt;brew doctor&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Install node via &amp;lt;tt&amp;gt;brew install node&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Make sure you don't &amp;lt;tt&amp;gt;sudo&amp;lt;/tt&amp;gt; anything related to node. If you think you have to, you are doing something wrong and are probably dealing with a broken homebrew/macports installation! If this is the case, the easiest way of resolving this is completely deleting the homebrew (and if present macports) directories and (re)installing homebrew.&lt;br /&gt;
&lt;br /&gt;
The default system's max opened file limit in mac os x is very low (256), in order to use grunt watch, it needs to be increased.&lt;br /&gt;
&lt;br /&gt;
You can either set this in your shell via &amp;lt;tt&amp;gt;ulimit -n 8192&amp;lt;/tt&amp;gt; to a sensible value or you can set&lt;br /&gt;
it permanently by adding&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;limit maxfiles 8192 20480&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to &amp;lt;tt&amp;gt;/etc/launchd.conf&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Grunt &amp;amp; Bower ==&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;tt&amp;gt;npm install -g bower grunt-cli&amp;lt;/tt&amp;gt; you can install the global npm dependencies needed for grunt and bower.&lt;br /&gt;
&lt;br /&gt;
== Installing node dependencies for OX Appsuite Frontend development ==&lt;br /&gt;
&lt;br /&gt;
Change to the ui directory of your git workdirectory and run &amp;lt;tt&amp;gt;npm install&amp;lt;/tt&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:VGrid&amp;diff=16852</id>
		<title>AppSuite:VGrid</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:VGrid&amp;diff=16852"/>
		<updated>2014-01-10T13:55:14Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stability-experimental}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;VGrid&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''' Abstract:''' The VGrid is a grid used to structure contents in the main viewport. For example, if you see mails stacked in the v-split of the mail module, this is the VGrid at work.&lt;br /&gt;
&lt;br /&gt;
Create new instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// pass jQuery node where VGrid should be drawn&lt;br /&gt;
var grid = new ox.ui.tk.VGrid(node);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add basic template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
grid.addTemplate({&lt;br /&gt;
  build: function () {&lt;br /&gt;
    var name, email;&lt;br /&gt;
    this&lt;br /&gt;
      .addClass(&amp;quot;contact&amp;quot;)&lt;br /&gt;
      .append(name = $(&amp;quot;&amp;lt;div/&amp;gt;&amp;quot;).addClass(&amp;quot;fullname&amp;quot;))&lt;br /&gt;
      .append(email = $(&amp;quot;&amp;lt;div/&amp;gt;&amp;quot;))&lt;br /&gt;
      .append(job = $(&amp;quot;&amp;lt;div/&amp;gt;&amp;quot;).addClass(&amp;quot;bright-text&amp;quot;));&lt;br /&gt;
    return { name: name, job: job, email: email };&lt;br /&gt;
  },&lt;br /&gt;
  set: function (data, fields, index) {&lt;br /&gt;
    fields.name.text(data.display_name);&lt;br /&gt;
    fields.email.text(data.email);&lt;br /&gt;
    fields.job.text(data.job);&lt;br /&gt;
  }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add label template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
grid.addLabelTemplate({&lt;br /&gt;
  build: function () { },&lt;br /&gt;
  set: function (data, fields, index) {&lt;br /&gt;
    var name = data.last_name || data.display_name || &amp;quot;#&amp;quot;;&lt;br /&gt;
    this.text(name.substr(0, 1).toUpperCase());&lt;br /&gt;
  }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add a function to determine if a new label is needed:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
grid.requiresLabel = function (i, data, current) {&lt;br /&gt;
  var name = data.last_name || data.display_name || &amp;quot;#&amp;quot;,&lt;br /&gt;
    prefix = name.substr(0, 1).toUpperCase();&lt;br /&gt;
  return (i === 0 || prefix !== current) ? prefix : false;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Define functions to get data:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// get all IDs of all objects&lt;br /&gt;
grid.setAllRequest(function (cont) {&lt;br /&gt;
  // must return deferred object&lt;br /&gt;
  return api.getAll().done(cont);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// define a named &amp;quot;search&amp;quot; request&lt;br /&gt;
grid.setAllRequest(&amp;quot;search&amp;quot;, function (cont) {&lt;br /&gt;
  // must return deferred object&lt;br /&gt;
  return api.search(win.search.query).done(cont);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// define a request that loads detailled data on demand&lt;br /&gt;
grid.setListRequest(function (ids, cont) {&lt;br /&gt;
  // must return deferred object&lt;br /&gt;
  return api.getList(ids).done(cont);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:ToDo]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Test_basics&amp;diff=16622</id>
		<title>AppSuite:Test basics</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Test_basics&amp;diff=16622"/>
		<updated>2013-12-02T14:08:21Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Lessons learned painfully while doing testing:&lt;br /&gt;
* PhantomJS thinks it is a touch device (Modernizr.touch === true)&lt;br /&gt;
* Almost no CSS is loaded. Don't rely on classes like &amp;quot;hidden&amp;quot; (bootstrap class)&lt;br /&gt;
* Don't clear &amp;lt;body&amp;gt; (e.g. $(document.body).empty()). UI is not robust against that.&lt;br /&gt;
* The browser window is elastic. It has no fixed size. Usually affects scrolling tests.&lt;br /&gt;
* If weird things happen, try to check if your app/window/node is really still in the DOM.&lt;br /&gt;
* HTML fixtures cannot be loaded (don't know why yet); just rename your files to *.txt&lt;br /&gt;
* Please mind that your fake server only works inside &amp;quot;description&amp;quot; (not across specs)&lt;br /&gt;
* PhantomJS fails at: Date.parse(&amp;quot;2012-01-01&amp;quot;); (see https://code.google.com/p/phantomjs/issues/detail?id=267#c2)&lt;br /&gt;
&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:Developer]]&lt;br /&gt;
[[Category:Testing]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Supported_file_types&amp;diff=16227</id>
		<title>AppSuite:Supported file types</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Supported_file_types&amp;diff=16227"/>
		<updated>2013-10-24T16:19:07Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Audio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;AppSuite allows you to preview, view and edit files. A common question is what files are supported. The following list is not definitive&lt;br /&gt;
&lt;br /&gt;
== Mediaplayer ==&lt;br /&gt;
The AppSuite &amp;quot;media player&amp;quot; uses the native html 5 video playback of each browser. The actual file support  depends on the user's browser, so a definitive list can not be given. Here is an attempt:&lt;br /&gt;
&lt;br /&gt;
=== Video ===&lt;br /&gt;
&lt;br /&gt;
* Chrome: m4v, ogv, webm&lt;br /&gt;
* Safari: m4v&lt;br /&gt;
* IE: m4v&lt;br /&gt;
* Firefox: ogv, webm&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
&lt;br /&gt;
For audio files a flash/silverlight fallback is used if a browser is not capable of native mp3 playback like Firefox.&lt;br /&gt;
&lt;br /&gt;
* Chrome: mp3, wav, m4a, m4b, ogg&lt;br /&gt;
* Safari: mp3, wav, m4a, m4b, aac&lt;br /&gt;
* IE: mp3, m4a, m4b&lt;br /&gt;
* Firefox: mp3, wav, ogg&lt;br /&gt;
&lt;br /&gt;
== Preview ==&lt;br /&gt;
&lt;br /&gt;
=== Images ===&lt;br /&gt;
&lt;br /&gt;
* png&lt;br /&gt;
* jpg, jpeg&lt;br /&gt;
&lt;br /&gt;
=== Text Documents ===&lt;br /&gt;
&lt;br /&gt;
* docx (Microsoft Office Word text document)&lt;br /&gt;
* docm (Microsoft Office Word macro-enabled text document)&lt;br /&gt;
* dotx (Microsoft Office Word text document template)&lt;br /&gt;
* dotm (Microsoft Office Word macro-enabled text document template)&lt;br /&gt;
* odt (OpenDocument text document)&lt;br /&gt;
* ott (OpenDocument text document template)&lt;br /&gt;
* doc (Microsoft Word 97-2003 text document)&lt;br /&gt;
* dot (Microsoft Word 97-2003 text document template)&lt;br /&gt;
* rtf (Rich Text Format)&lt;br /&gt;
&lt;br /&gt;
=== Spreadsheet Documents ===&lt;br /&gt;
&lt;br /&gt;
* xlsx (Microsoft Office Excel workbook)&lt;br /&gt;
* xlsm (Microsoft Office Excel macro-enabled workbook)&lt;br /&gt;
* xltx (Microsoft Office Excel workbook template)&lt;br /&gt;
* xltm (Microsoft Office Excel macro-enabled workbook template)&lt;br /&gt;
* xlsb (Microsoft Office Excel macro-enabled workbook, binary format)&lt;br /&gt;
* xlam (Microsoft Office Excel add-in)&lt;br /&gt;
* ods (OpenDocument spreadsheet document)&lt;br /&gt;
* ots (OpenDocument spreadsheet document template)&lt;br /&gt;
* xls (Microsoft Excel 97-2003 workbook)&lt;br /&gt;
* xlt (Microsoft Excel 97-2003 workbook template)&lt;br /&gt;
* xla (Microsoft Excel 97-2003 add-in)&lt;br /&gt;
&lt;br /&gt;
=== Presentation Documents ===&lt;br /&gt;
&lt;br /&gt;
* pptx (Microsoft Office PowerPoint presentation)&lt;br /&gt;
* pptm (Microsoft Office PowerPoint macro-enabled presentation)&lt;br /&gt;
* potx (Microsoft Office PowerPoint presentation template)&lt;br /&gt;
* potm (Microsoft Office PowerPoint macro-enabled presentation template)&lt;br /&gt;
* ppsx (Microsoft Office PowerPoint slide show)&lt;br /&gt;
* ppsm (Microsoft Office PowerPoint macro-enabled slide show)&lt;br /&gt;
* ppam (Microsoft Office PowerPoint add-in)&lt;br /&gt;
* odp (OpenDocument presentation document)&lt;br /&gt;
* otp (OpenDocument presentation document template)&lt;br /&gt;
* ppt (Microsoft PowerPoint 97-2003 presentation)&lt;br /&gt;
* pot (Microsoft PowerPoint 97-2003 presentation template)&lt;br /&gt;
* pps (Microsoft PowerPoint 97-2003 slide show)&lt;br /&gt;
* ppa (Microsoft PowerPoint 97-2003 add-in)&lt;br /&gt;
&lt;br /&gt;
=== Miscellaneous ===&lt;br /&gt;
&lt;br /&gt;
* pdf (Portable Document Format)&lt;br /&gt;
* odg (OpenDocument drawing document)&lt;br /&gt;
* otg (OpenDocument drawing document template)&lt;br /&gt;
* odi (OpenDocument image document)&lt;br /&gt;
* oti (OpenDocument image document template)&lt;br /&gt;
* odc (OpenDocument chart document)&lt;br /&gt;
* otc (OpenDocument chart document template)&lt;br /&gt;
* odf (OpenDocument formula document)&lt;br /&gt;
* otf (OpenDocument formula document template)&lt;br /&gt;
* odm (OpenDocument global text document)&lt;br /&gt;
&lt;br /&gt;
== Documents ==&lt;br /&gt;
&lt;br /&gt;
=== Text Documents ===&lt;br /&gt;
&lt;br /&gt;
* docx (Microsoft Office Word text document)&lt;br /&gt;
* docm (Microsoft Office Word macro-enabled text document)&lt;br /&gt;
* dotx (Microsoft Office Word text document template)&lt;br /&gt;
* dotm (Microsoft Office Word macro-enabled text document template)&lt;br /&gt;
* odt (OpenDocument text document)&lt;br /&gt;
* ott (OpenDocument text document template)&lt;br /&gt;
* doc (Microsoft Word 97-2003 text document, converted to &amp;quot;odt&amp;quot; when edited)&lt;br /&gt;
* dot (Microsoft Word 97-2003 text document template, converted to &amp;quot;ott&amp;quot; when edited)&lt;br /&gt;
* rtf (Rich Text Format, converted to &amp;quot;odt&amp;quot; when edited)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:Server]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Apache_Configuration&amp;diff=15594</id>
		<title>AppSuite:Apache Configuration</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Apache_Configuration&amp;diff=15594"/>
		<updated>2013-08-30T15:31:25Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Setup SSL support on MacOS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stability-experimental}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Apache Configuration&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
To setup your development environment please follow these steps.&lt;br /&gt;
&lt;br /&gt;
==Setup build system==&lt;br /&gt;
# Check out the UI from git&lt;br /&gt;
# Figure out Apache's document root. Common places are:&amp;lt;br&amp;gt;MacOS: /Library/WebServer/Documents&amp;lt;br&amp;gt;Linux: /var/www&lt;br /&gt;
# Create a new folder appsuite in Apache's document root&lt;br /&gt;
# You need node.js to build the UI. For MacOS (use /var/www instead of /Library/WebServer/Documents for debian).&lt;br /&gt;
&lt;br /&gt;
===Installing node.js===&lt;br /&gt;
# Visit https://sites.google.com/site/nodejsmacosx/ and install stable version.&lt;br /&gt;
# Open terminal&lt;br /&gt;
# Set environment variable:&amp;lt;br&amp;gt;''export buildir=&amp;quot;/Library/WebServer/Documents/appsuite&amp;quot;''&lt;br /&gt;
# Build UI: '''./build.sh'''&lt;br /&gt;
# Note: Instead of exporting the builddir every time your want to build the ui or run the appserver, you can also create a file '''local.conf''' and set the directory in there. This way, every time the buildsystem or appserver runs, it automatically picks up the correct directory.&amp;lt;br&amp;gt;local.conf: ''export buildir=&amp;quot;/Library/WebServer/Documents/appsuite&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
===AppServer===&lt;br /&gt;
Run the app loading server: '''./appserver.sh''' Don't worry: If it doesn't tell you anything it's happily running.&lt;br /&gt;
&lt;br /&gt;
==Apache config==&lt;br /&gt;
Make sure Apache loads the following modules:&amp;lt;br&amp;gt;''mod_proxy, mod_proxy_ajp, mod_expires, mod_deflate, mod_rewrite, mod_headers, mod_mime, and mod_setenvif''&lt;br /&gt;
&lt;br /&gt;
Tell your Apache to process .htaccess files and how to connect to backend:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-conf&amp;quot;&amp;gt;&lt;br /&gt;
ProxyPass /appsuite/api/apps/load/ http://localhost:8337/apps/load/&lt;br /&gt;
ProxyPass /appsuite/api ajp://127.0.0.1:8009/ajax &lt;br /&gt;
# optional parameters: retry=0 connectiontimeout=5 timeout=10&lt;br /&gt;
&lt;br /&gt;
&amp;amp;lt;Directory /Library/WebServer/Documents/appsuite&amp;gt;&lt;br /&gt;
  Options None +FollowSymLinks&lt;br /&gt;
  AllowOverride Indexes FileInfo&lt;br /&gt;
&amp;amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use the proper document root depending on your OS or custom configuration! If backend does not run on localhost (127.0.0.1), you have to adjust the ProxyPass directive.&lt;br /&gt;
&lt;br /&gt;
'''Restart Apache''', e.g. sudo apachectl restart. And please double check everything you're doing!&lt;br /&gt;
&lt;br /&gt;
==Setup SSL support on MacOS==&lt;br /&gt;
&lt;br /&gt;
Based on: http://webdevstudios.com/2013/05/24/how-to-set-up-ssl-with-osx-mountain-lions-built-in-apache/&lt;br /&gt;
&lt;br /&gt;
* Open terminal and '''cd /private/etc/apache2'''&lt;br /&gt;
* Become root: '''sudo su'''&lt;br /&gt;
* '''mkdir ssl'''&lt;br /&gt;
* Open ''httpd.conf'' in your text editor, e.g. '''vim httpd.conf'''&lt;br /&gt;
** Make sure the SSL module is enabled if it’s not. Do this by uncommenting (aka, remove the ‘#’ symbol in front) the line that looks like: ''LoadModule ssl_module libexec/apache2/mod_ssl.so''&lt;br /&gt;
** In the same file search for and uncomment (remove the #) this line: ''Include /private/etc/apache2/extra/httpd-ssl.conf''&lt;br /&gt;
** Save and close.&lt;br /&gt;
* Now open ''httpd-ssl.conf'' file in your text editor, e.g. '''vim httpd-ssl.conf'''&lt;br /&gt;
** Make sure '''ServerName''' line looks like: ''ServerName localhost''&lt;br /&gt;
** Modify '''ServerAdmin''' line to use one of your email addresses&lt;br /&gt;
** '''SSLCertificateFile &amp;quot;/private/etc/apache2/ssl/ssl.crt&amp;quot;'''&lt;br /&gt;
** '''SSLCertificateKeyFile &amp;quot;/private/etc/apache2/ssl/ssl.key&amp;quot;'''&lt;br /&gt;
** In the same file comment out (add a # to the beginning of the line) the '''SSLCACertificatePath''' and '''SSLCARevocationPath''' lines if they’re not already.&lt;br /&gt;
** Save and close.&lt;br /&gt;
* Now go to new ssl folder: '''cd /private/etc/apache2/ssl'''&lt;br /&gt;
** The following steps are based on http://www.akadia.com/services/ssh_test_certificate.html&amp;lt;br&amp;gt;Don't have to read, just run the following commands:&lt;br /&gt;
** '''openssl genrsa -des3 -out server.key 1024'''&amp;lt;br&amp;gt;Pass-phrase can be anything stupid, we'll remove it&lt;br /&gt;
** '''openssl req -new -key server.key -out server.csr'''&lt;br /&gt;
** '''cp server.key server.key.org&amp;lt;br&amp;gt;openssl rsa -in server.key.org -out server.key'''&lt;br /&gt;
** '''openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt'''&lt;br /&gt;
* Restart apache: '''apachectl restart'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Apache_Configuration&amp;diff=15593</id>
		<title>AppSuite:Apache Configuration</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Apache_Configuration&amp;diff=15593"/>
		<updated>2013-08-30T15:30:29Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Setup SSL support on MacOS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stability-experimental}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Apache Configuration&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
To setup your development environment please follow these steps.&lt;br /&gt;
&lt;br /&gt;
==Setup build system==&lt;br /&gt;
# Check out the UI from git&lt;br /&gt;
# Figure out Apache's document root. Common places are:&amp;lt;br&amp;gt;MacOS: /Library/WebServer/Documents&amp;lt;br&amp;gt;Linux: /var/www&lt;br /&gt;
# Create a new folder appsuite in Apache's document root&lt;br /&gt;
# You need node.js to build the UI. For MacOS (use /var/www instead of /Library/WebServer/Documents for debian).&lt;br /&gt;
&lt;br /&gt;
===Installing node.js===&lt;br /&gt;
# Visit https://sites.google.com/site/nodejsmacosx/ and install stable version.&lt;br /&gt;
# Open terminal&lt;br /&gt;
# Set environment variable:&amp;lt;br&amp;gt;''export buildir=&amp;quot;/Library/WebServer/Documents/appsuite&amp;quot;''&lt;br /&gt;
# Build UI: '''./build.sh'''&lt;br /&gt;
# Note: Instead of exporting the builddir every time your want to build the ui or run the appserver, you can also create a file '''local.conf''' and set the directory in there. This way, every time the buildsystem or appserver runs, it automatically picks up the correct directory.&amp;lt;br&amp;gt;local.conf: ''export buildir=&amp;quot;/Library/WebServer/Documents/appsuite&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
===AppServer===&lt;br /&gt;
Run the app loading server: '''./appserver.sh''' Don't worry: If it doesn't tell you anything it's happily running.&lt;br /&gt;
&lt;br /&gt;
==Apache config==&lt;br /&gt;
Make sure Apache loads the following modules:&amp;lt;br&amp;gt;''mod_proxy, mod_proxy_ajp, mod_expires, mod_deflate, mod_rewrite, mod_headers, mod_mime, and mod_setenvif''&lt;br /&gt;
&lt;br /&gt;
Tell your Apache to process .htaccess files and how to connect to backend:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-conf&amp;quot;&amp;gt;&lt;br /&gt;
ProxyPass /appsuite/api/apps/load/ http://localhost:8337/apps/load/&lt;br /&gt;
ProxyPass /appsuite/api ajp://127.0.0.1:8009/ajax &lt;br /&gt;
# optional parameters: retry=0 connectiontimeout=5 timeout=10&lt;br /&gt;
&lt;br /&gt;
&amp;amp;lt;Directory /Library/WebServer/Documents/appsuite&amp;gt;&lt;br /&gt;
  Options None +FollowSymLinks&lt;br /&gt;
  AllowOverride Indexes FileInfo&lt;br /&gt;
&amp;amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use the proper document root depending on your OS or custom configuration! If backend does not run on localhost (127.0.0.1), you have to adjust the ProxyPass directive.&lt;br /&gt;
&lt;br /&gt;
'''Restart Apache''', e.g. sudo apachectl restart. And please double check everything you're doing!&lt;br /&gt;
&lt;br /&gt;
==Setup SSL support on MacOS==&lt;br /&gt;
&lt;br /&gt;
Based on: http://webdevstudios.com/2013/05/24/how-to-set-up-ssl-with-osx-mountain-lions-built-in-apache/&lt;br /&gt;
&lt;br /&gt;
* Open terminal and '''cd /private/etc/apache2'''&lt;br /&gt;
* Become root: '''sudo su'''&lt;br /&gt;
* '''mkdir ssl'''&lt;br /&gt;
* Open ''httpd.conf'' in your text editor, e.g. '''vim httpd.conf'''&lt;br /&gt;
** Make sure the SSL module is enabled if it’s not. Do this by uncommenting (aka, remove the ‘#’ symbol in front) the line that looks like: ''LoadModule ssl_module libexec/apache2/mod_ssl.so''&lt;br /&gt;
** In the same file search for and uncomment (remove the #) this line: ''Include /private/etc/apache2/extra/httpd-ssl.conf''&lt;br /&gt;
** Save and close.&lt;br /&gt;
* Now open ''httpd-ssl.conf'' file in your text editor, e.g. '''vim httpd-ssl.conf'''&lt;br /&gt;
** Make sure '''ServerName''' line looks like: ''ServerName localhost''&lt;br /&gt;
** Modify '''ServerAdmin''' line to use one of your email addresses&lt;br /&gt;
** '''SSLCertificateFile &amp;quot;/private/etc/apache2/ssl/ssl.crt&amp;quot;'''&lt;br /&gt;
** '''SSLCertificateKeyFile &amp;quot;/private/etc/apache2/ssl/ssl.key&amp;quot;'''&lt;br /&gt;
** In the same file comment out (add a # to the beginning of the line) the '''SSLCACertificatePath''' and '''SSLCARevocationPath''' lines if they’re not already.&lt;br /&gt;
** Save and close.&lt;br /&gt;
* Now go to new ssl folder: '''cd /private/etc/apache2/ssl'''&lt;br /&gt;
** '''openssl genrsa -des3 -out server.key 1024'''&amp;lt;br&amp;gt;Pass-phrase can be anything stupid, we'll remove it&lt;br /&gt;
** '''openssl req -new -key server.key -out server.csr'''&lt;br /&gt;
** '''cp server.key server.key.org&amp;lt;br&amp;gt;openssl rsa -in server.key.org -out server.key'''&lt;br /&gt;
** '''openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt'''&lt;br /&gt;
* Restart apache: '''apachectl restart'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Apache_Configuration&amp;diff=15592</id>
		<title>AppSuite:Apache Configuration</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Apache_Configuration&amp;diff=15592"/>
		<updated>2013-08-30T15:28:15Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Setup SSL support on MacOS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stability-experimental}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Apache Configuration&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
To setup your development environment please follow these steps.&lt;br /&gt;
&lt;br /&gt;
==Setup build system==&lt;br /&gt;
# Check out the UI from git&lt;br /&gt;
# Figure out Apache's document root. Common places are:&amp;lt;br&amp;gt;MacOS: /Library/WebServer/Documents&amp;lt;br&amp;gt;Linux: /var/www&lt;br /&gt;
# Create a new folder appsuite in Apache's document root&lt;br /&gt;
# You need node.js to build the UI. For MacOS (use /var/www instead of /Library/WebServer/Documents for debian).&lt;br /&gt;
&lt;br /&gt;
===Installing node.js===&lt;br /&gt;
# Visit https://sites.google.com/site/nodejsmacosx/ and install stable version.&lt;br /&gt;
# Open terminal&lt;br /&gt;
# Set environment variable:&amp;lt;br&amp;gt;''export buildir=&amp;quot;/Library/WebServer/Documents/appsuite&amp;quot;''&lt;br /&gt;
# Build UI: '''./build.sh'''&lt;br /&gt;
# Note: Instead of exporting the builddir every time your want to build the ui or run the appserver, you can also create a file '''local.conf''' and set the directory in there. This way, every time the buildsystem or appserver runs, it automatically picks up the correct directory.&amp;lt;br&amp;gt;local.conf: ''export buildir=&amp;quot;/Library/WebServer/Documents/appsuite&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
===AppServer===&lt;br /&gt;
Run the app loading server: '''./appserver.sh''' Don't worry: If it doesn't tell you anything it's happily running.&lt;br /&gt;
&lt;br /&gt;
==Apache config==&lt;br /&gt;
Make sure Apache loads the following modules:&amp;lt;br&amp;gt;''mod_proxy, mod_proxy_ajp, mod_expires, mod_deflate, mod_rewrite, mod_headers, mod_mime, and mod_setenvif''&lt;br /&gt;
&lt;br /&gt;
Tell your Apache to process .htaccess files and how to connect to backend:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-conf&amp;quot;&amp;gt;&lt;br /&gt;
ProxyPass /appsuite/api/apps/load/ http://localhost:8337/apps/load/&lt;br /&gt;
ProxyPass /appsuite/api ajp://127.0.0.1:8009/ajax &lt;br /&gt;
# optional parameters: retry=0 connectiontimeout=5 timeout=10&lt;br /&gt;
&lt;br /&gt;
&amp;amp;lt;Directory /Library/WebServer/Documents/appsuite&amp;gt;&lt;br /&gt;
  Options None +FollowSymLinks&lt;br /&gt;
  AllowOverride Indexes FileInfo&lt;br /&gt;
&amp;amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use the proper document root depending on your OS or custom configuration! If backend does not run on localhost (127.0.0.1), you have to adjust the ProxyPass directive.&lt;br /&gt;
&lt;br /&gt;
'''Restart Apache''', e.g. sudo apachectl restart. And please double check everything you're doing!&lt;br /&gt;
&lt;br /&gt;
==Setup SSL support on MacOS==&lt;br /&gt;
&lt;br /&gt;
Based on: http://webdevstudios.com/2013/05/24/how-to-set-up-ssl-with-osx-mountain-lions-built-in-apache/&lt;br /&gt;
&lt;br /&gt;
* Open terminal and go to '''/private/etc/apache2'''&lt;br /&gt;
* Become root: '''sudo su'''&lt;br /&gt;
* '''mkdir ssl'''&lt;br /&gt;
* Open the '''httpd.conf''' file in your text editor&lt;br /&gt;
** Make sure the SSL module is enabled if it’s not. Do this by uncommenting (aka, remove the ‘#’ symbol in front) the line that looks like: ''LoadModule ssl_module libexec/apache2/mod_ssl.so''&lt;br /&gt;
** In the same file search for and uncomment (remove the #) this line: ''Include /private/etc/apache2/extra/httpd-ssl.conf''&lt;br /&gt;
** Save and close.&lt;br /&gt;
* Now open the '''httpd-ssl.conf''' file in your text editor&lt;br /&gt;
** Make sure '''ServerName''' line looks like: ''ServerName localhost''&lt;br /&gt;
** Modify '''ServerAdmin''' line to use one of your email addresses&lt;br /&gt;
** '''SSLCertificateFile &amp;quot;/private/etc/apache2/ssl/ssl.crt&amp;quot;'''&lt;br /&gt;
** '''SSLCertificateKeyFile &amp;quot;/private/etc/apache2/ssl/ssl.key&amp;quot;'''&lt;br /&gt;
** In the same file comment out (add a # to the beginning of the line) the '''SSLCACertificatePath''' and '''SSLCARevocationPath''' lines if they’re not already.&lt;br /&gt;
** Save and close.&lt;br /&gt;
* Now go to folder '''/private/etc/apache2/ssl'''&lt;br /&gt;
** '''openssl genrsa -des3 -out server.key 1024'''&amp;lt;br&amp;gt;Pass-phrase can be anything stupid, we'll remove it&lt;br /&gt;
** '''openssl req -new -key server.key -out server.csr'''&lt;br /&gt;
** '''cp server.key server.key.org&amp;lt;br&amp;gt;openssl rsa -in server.key.org -out server.key'''&lt;br /&gt;
** '''openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt'''&lt;br /&gt;
* Restart apache: '''apachectl restart'''&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Apache_Configuration&amp;diff=15591</id>
		<title>AppSuite:Apache Configuration</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Apache_Configuration&amp;diff=15591"/>
		<updated>2013-08-30T15:27:38Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Setup SSL support on MacOS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stability-experimental}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Apache Configuration&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
To setup your development environment please follow these steps.&lt;br /&gt;
&lt;br /&gt;
==Setup build system==&lt;br /&gt;
# Check out the UI from git&lt;br /&gt;
# Figure out Apache's document root. Common places are:&amp;lt;br&amp;gt;MacOS: /Library/WebServer/Documents&amp;lt;br&amp;gt;Linux: /var/www&lt;br /&gt;
# Create a new folder appsuite in Apache's document root&lt;br /&gt;
# You need node.js to build the UI. For MacOS (use /var/www instead of /Library/WebServer/Documents for debian).&lt;br /&gt;
&lt;br /&gt;
===Installing node.js===&lt;br /&gt;
# Visit https://sites.google.com/site/nodejsmacosx/ and install stable version.&lt;br /&gt;
# Open terminal&lt;br /&gt;
# Set environment variable:&amp;lt;br&amp;gt;''export buildir=&amp;quot;/Library/WebServer/Documents/appsuite&amp;quot;''&lt;br /&gt;
# Build UI: '''./build.sh'''&lt;br /&gt;
# Note: Instead of exporting the builddir every time your want to build the ui or run the appserver, you can also create a file '''local.conf''' and set the directory in there. This way, every time the buildsystem or appserver runs, it automatically picks up the correct directory.&amp;lt;br&amp;gt;local.conf: ''export buildir=&amp;quot;/Library/WebServer/Documents/appsuite&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
===AppServer===&lt;br /&gt;
Run the app loading server: '''./appserver.sh''' Don't worry: If it doesn't tell you anything it's happily running.&lt;br /&gt;
&lt;br /&gt;
==Apache config==&lt;br /&gt;
Make sure Apache loads the following modules:&amp;lt;br&amp;gt;''mod_proxy, mod_proxy_ajp, mod_expires, mod_deflate, mod_rewrite, mod_headers, mod_mime, and mod_setenvif''&lt;br /&gt;
&lt;br /&gt;
Tell your Apache to process .htaccess files and how to connect to backend:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-conf&amp;quot;&amp;gt;&lt;br /&gt;
ProxyPass /appsuite/api/apps/load/ http://localhost:8337/apps/load/&lt;br /&gt;
ProxyPass /appsuite/api ajp://127.0.0.1:8009/ajax &lt;br /&gt;
# optional parameters: retry=0 connectiontimeout=5 timeout=10&lt;br /&gt;
&lt;br /&gt;
&amp;amp;lt;Directory /Library/WebServer/Documents/appsuite&amp;gt;&lt;br /&gt;
  Options None +FollowSymLinks&lt;br /&gt;
  AllowOverride Indexes FileInfo&lt;br /&gt;
&amp;amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use the proper document root depending on your OS or custom configuration! If backend does not run on localhost (127.0.0.1), you have to adjust the ProxyPass directive.&lt;br /&gt;
&lt;br /&gt;
'''Restart Apache''', e.g. sudo apachectl restart. And please double check everything you're doing!&lt;br /&gt;
&lt;br /&gt;
==Setup SSL support on MacOS==&lt;br /&gt;
&lt;br /&gt;
Based on: http://webdevstudios.com/2013/05/24/how-to-set-up-ssl-with-osx-mountain-lions-built-in-apache/&lt;br /&gt;
&lt;br /&gt;
* Open terminal and go to '''/private/etc/apache2'''&lt;br /&gt;
* Become root: '''sudo su'''&lt;br /&gt;
* '''mkdir ssl'''&lt;br /&gt;
* Open the '''httpd.conf''' file in your text editor&lt;br /&gt;
** Make sure the SSL module is enabled if it’s not. Do this by uncommenting (aka, remove the ‘#’ symbol in front) the line that looks like: ''LoadModule ssl_module libexec/apache2/mod_ssl.so''&lt;br /&gt;
** In the same file search for and uncomment (remove the #) this line: ''Include &lt;br /&gt;
/private/etc/apache2/extra/httpd-ssl.conf''&lt;br /&gt;
** Save and close.&lt;br /&gt;
* Now open the '''httpd-ssl.conf''' file in your text editor&lt;br /&gt;
** Make sure '''ServerName''' line looks like: ''ServerName localhost''&lt;br /&gt;
** Modify '''ServerAdmin''' line to use one of your email addresses&lt;br /&gt;
** '''SSLCertificateFile &amp;quot;/private/etc/apache2/ssl/ssl.crt&amp;quot;'''&lt;br /&gt;
** '''SSLCertificateKeyFile &amp;quot;/private/etc/apache2/ssl/ssl.key&amp;quot;'''&lt;br /&gt;
** In the same file comment out (add a # to the beginning of the line) the '''SSLCACertificatePath''' and '''SSLCARevocationPath''' lines if they’re not already.&lt;br /&gt;
** Save and close.&lt;br /&gt;
* Now go to folder '''/private/etc/apache2/ssl'''&lt;br /&gt;
* '''openssl genrsa -des3 -out server.key 1024'''&lt;br /&gt;
* Pass-phrase can be anything stupid, we'll remove it&lt;br /&gt;
* '''openssl req -new -key server.key -out server.csr'''&lt;br /&gt;
* '''cp server.key server.key.org&amp;lt;br&amp;gt;openssl rsa -in server.key.org -out server.key'''&lt;br /&gt;
* '''openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt'''&lt;br /&gt;
* Restart apache: '''apachectl restart'''&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Apache_Configuration&amp;diff=15590</id>
		<title>AppSuite:Apache Configuration</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Apache_Configuration&amp;diff=15590"/>
		<updated>2013-08-30T15:25:38Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Setup SSL support on MacOS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stability-experimental}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Apache Configuration&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
To setup your development environment please follow these steps.&lt;br /&gt;
&lt;br /&gt;
==Setup build system==&lt;br /&gt;
# Check out the UI from git&lt;br /&gt;
# Figure out Apache's document root. Common places are:&amp;lt;br&amp;gt;MacOS: /Library/WebServer/Documents&amp;lt;br&amp;gt;Linux: /var/www&lt;br /&gt;
# Create a new folder appsuite in Apache's document root&lt;br /&gt;
# You need node.js to build the UI. For MacOS (use /var/www instead of /Library/WebServer/Documents for debian).&lt;br /&gt;
&lt;br /&gt;
===Installing node.js===&lt;br /&gt;
# Visit https://sites.google.com/site/nodejsmacosx/ and install stable version.&lt;br /&gt;
# Open terminal&lt;br /&gt;
# Set environment variable:&amp;lt;br&amp;gt;''export buildir=&amp;quot;/Library/WebServer/Documents/appsuite&amp;quot;''&lt;br /&gt;
# Build UI: '''./build.sh'''&lt;br /&gt;
# Note: Instead of exporting the builddir every time your want to build the ui or run the appserver, you can also create a file '''local.conf''' and set the directory in there. This way, every time the buildsystem or appserver runs, it automatically picks up the correct directory.&amp;lt;br&amp;gt;local.conf: ''export buildir=&amp;quot;/Library/WebServer/Documents/appsuite&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
===AppServer===&lt;br /&gt;
Run the app loading server: '''./appserver.sh''' Don't worry: If it doesn't tell you anything it's happily running.&lt;br /&gt;
&lt;br /&gt;
==Apache config==&lt;br /&gt;
Make sure Apache loads the following modules:&amp;lt;br&amp;gt;''mod_proxy, mod_proxy_ajp, mod_expires, mod_deflate, mod_rewrite, mod_headers, mod_mime, and mod_setenvif''&lt;br /&gt;
&lt;br /&gt;
Tell your Apache to process .htaccess files and how to connect to backend:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-conf&amp;quot;&amp;gt;&lt;br /&gt;
ProxyPass /appsuite/api/apps/load/ http://localhost:8337/apps/load/&lt;br /&gt;
ProxyPass /appsuite/api ajp://127.0.0.1:8009/ajax &lt;br /&gt;
# optional parameters: retry=0 connectiontimeout=5 timeout=10&lt;br /&gt;
&lt;br /&gt;
&amp;amp;lt;Directory /Library/WebServer/Documents/appsuite&amp;gt;&lt;br /&gt;
  Options None +FollowSymLinks&lt;br /&gt;
  AllowOverride Indexes FileInfo&lt;br /&gt;
&amp;amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use the proper document root depending on your OS or custom configuration! If backend does not run on localhost (127.0.0.1), you have to adjust the ProxyPass directive.&lt;br /&gt;
&lt;br /&gt;
'''Restart Apache''', e.g. sudo apachectl restart. And please double check everything you're doing!&lt;br /&gt;
&lt;br /&gt;
==Setup SSL support on MacOS==&lt;br /&gt;
&lt;br /&gt;
Based on: http://webdevstudios.com/2013/05/24/how-to-set-up-ssl-with-osx-mountain-lions-built-in-apache/&lt;br /&gt;
&lt;br /&gt;
* Open terminal and go to '''/private/etc/apache2'''&lt;br /&gt;
* Become root: '''sudo su'''&lt;br /&gt;
* '''mkdir ssl'''&lt;br /&gt;
* Make sure the SSL module is enabled if it’s not. httpd.conf: ''LoadModule ssl_module libexec/apache2/mod_ssl.so''&lt;br /&gt;
* In the same file search for and uncomment (remove the #) this line: ''Include /private/etc/apache2/extra/httpd-ssl.conf''&lt;br /&gt;
* Now open the '''httpd-ssl.conf''' file in your text editor&lt;br /&gt;
* Make sure '''ServerName''' line looks like: ''ServerName localhost''&lt;br /&gt;
* Modify '''ServerAdmin''' line to use one of your email addresses&lt;br /&gt;
* '''SSLCertificateFile &amp;quot;/private/etc/apache2/ssl/ssl.crt&amp;quot;'''&lt;br /&gt;
* '''SSLCertificateKeyFile &amp;quot;/private/etc/apache2/ssl/ssl.key&amp;quot;'''&lt;br /&gt;
* In the same file comment out (add a # to the beginning of the line) the '''SSLCACertificatePath''' and '''SSLCARevocationPath''' lines if they’re not already.&lt;br /&gt;
* Now go to folder '''/private/etc/apache2/ssl'''&lt;br /&gt;
* '''openssl genrsa -des3 -out server.key 1024'''&lt;br /&gt;
* Pass-phrase can be anything stupid, we'll remove it&lt;br /&gt;
* '''openssl req -new -key server.key -out server.csr'''&lt;br /&gt;
* '''cp server.key server.key.org&amp;lt;br&amp;gt;openssl rsa -in server.key.org -out server.key'''&lt;br /&gt;
* '''openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt'''&lt;br /&gt;
* Restart apache: '''apachectl restart'''&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Apache_Configuration&amp;diff=15589</id>
		<title>AppSuite:Apache Configuration</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Apache_Configuration&amp;diff=15589"/>
		<updated>2013-08-30T15:10:10Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stability-experimental}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Apache Configuration&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
To setup your development environment please follow these steps.&lt;br /&gt;
&lt;br /&gt;
==Setup build system==&lt;br /&gt;
# Check out the UI from git&lt;br /&gt;
# Figure out Apache's document root. Common places are:&amp;lt;br&amp;gt;MacOS: /Library/WebServer/Documents&amp;lt;br&amp;gt;Linux: /var/www&lt;br /&gt;
# Create a new folder appsuite in Apache's document root&lt;br /&gt;
# You need node.js to build the UI. For MacOS (use /var/www instead of /Library/WebServer/Documents for debian).&lt;br /&gt;
&lt;br /&gt;
===Installing node.js===&lt;br /&gt;
# Visit https://sites.google.com/site/nodejsmacosx/ and install stable version.&lt;br /&gt;
# Open terminal&lt;br /&gt;
# Set environment variable:&amp;lt;br&amp;gt;''export buildir=&amp;quot;/Library/WebServer/Documents/appsuite&amp;quot;''&lt;br /&gt;
# Build UI: '''./build.sh'''&lt;br /&gt;
# Note: Instead of exporting the builddir every time your want to build the ui or run the appserver, you can also create a file '''local.conf''' and set the directory in there. This way, every time the buildsystem or appserver runs, it automatically picks up the correct directory.&amp;lt;br&amp;gt;local.conf: ''export buildir=&amp;quot;/Library/WebServer/Documents/appsuite&amp;quot;''&lt;br /&gt;
&lt;br /&gt;
===AppServer===&lt;br /&gt;
Run the app loading server: '''./appserver.sh''' Don't worry: If it doesn't tell you anything it's happily running.&lt;br /&gt;
&lt;br /&gt;
==Apache config==&lt;br /&gt;
Make sure Apache loads the following modules:&amp;lt;br&amp;gt;''mod_proxy, mod_proxy_ajp, mod_expires, mod_deflate, mod_rewrite, mod_headers, mod_mime, and mod_setenvif''&lt;br /&gt;
&lt;br /&gt;
Tell your Apache to process .htaccess files and how to connect to backend:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-conf&amp;quot;&amp;gt;&lt;br /&gt;
ProxyPass /appsuite/api/apps/load/ http://localhost:8337/apps/load/&lt;br /&gt;
ProxyPass /appsuite/api ajp://127.0.0.1:8009/ajax &lt;br /&gt;
# optional parameters: retry=0 connectiontimeout=5 timeout=10&lt;br /&gt;
&lt;br /&gt;
&amp;amp;lt;Directory /Library/WebServer/Documents/appsuite&amp;gt;&lt;br /&gt;
  Options None +FollowSymLinks&lt;br /&gt;
  AllowOverride Indexes FileInfo&lt;br /&gt;
&amp;amp;lt;/Directory&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use the proper document root depending on your OS or custom configuration! If backend does not run on localhost (127.0.0.1), you have to adjust the ProxyPass directive.&lt;br /&gt;
&lt;br /&gt;
'''Restart Apache''', e.g. sudo apachectl restart. And please double check everything you're doing!&lt;br /&gt;
&lt;br /&gt;
==Setup SSL support on MacOS==&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15554</id>
		<title>AppSuite:Debugging the UI</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15554"/>
		<updated>2013-08-29T13:38:27Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Debugging the UI&amp;lt;/div&amp;gt;&lt;br /&gt;
'''Synopsis:''' A collection of hints to debug during UI development&lt;br /&gt;
__TOC__&lt;br /&gt;
== What capabilities are available? ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
_(ox.serverConfig.capabilities).pluck(&amp;quot;id&amp;quot;).sort();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Check settings ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// check core settings&lt;br /&gt;
require('settings!io.ox/core').get();&lt;br /&gt;
// check mail settings&lt;br /&gt;
require('settings!io.ox/mail').get();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Clear all persistent caches ==&lt;br /&gt;
Please mind that this does not clear the regular browser cache! It clears localStorage, IndexedDB, and WebSQL.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
ox.cache.clear();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debug relogin ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
ox.autoLogoutRestartDebug();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Enable/disable capability via URL hash ==&lt;br /&gt;
Just add the parameter &amp;quot;cap&amp;quot; to URL hash. A leading minus disables a capability. Multiple capabilities separated by comma. Example:&lt;br /&gt;
&amp;lt;pre language=&amp;quot;none&amp;quot;&amp;gt; &lt;br /&gt;
...&amp;amp;cap=emoji,-calendar&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Disable source caching via URL hash ==&lt;br /&gt;
Add the parameter &amp;quot;debug-js=true&amp;quot; to URL hash. Example:&lt;br /&gt;
&amp;lt;pre language=&amp;quot;none&amp;quot;&amp;gt; &lt;br /&gt;
...&amp;amp;debug-js=true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debug a specific folder ==&lt;br /&gt;
If you want to get details of a specific folder, just inspect it via dev tools and look for data-obj-id=&amp;quot;...&amp;quot;. Copy the id and run the following in console:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
void require('io.ox/core/api/folder').get({ folder: 'default0/INBOX' }).always(_.inspect);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15550</id>
		<title>AppSuite:Debugging the UI</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15550"/>
		<updated>2013-08-29T10:07:24Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Clear all persistent caches */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Debugging the UI&amp;lt;/div&amp;gt;&lt;br /&gt;
'''Synopsis:''' A collection of hints to debug during UI development&lt;br /&gt;
__TOC__&lt;br /&gt;
== What capabilities are available? ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
_(ox.serverConfig.capabilities).pluck(&amp;quot;id&amp;quot;).sort();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Check settings ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// check core settings&lt;br /&gt;
require('settings!io.ox/core').get();&lt;br /&gt;
// check mail settings&lt;br /&gt;
require('settings!io.ox/mail').get();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Clear all persistent caches ==&lt;br /&gt;
Please mind that this does not clear the regular browser cache! It clears localStorage, IndexedDB, and WebSQL.&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
ox.cache.clear();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debug relogin ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
ox.autoLogoutRestartDebug();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Enable/disable capability via URL hash ==&lt;br /&gt;
Just add the parameter &amp;quot;cap&amp;quot; to URL hash. A leading minus disables a capability. Multiple capabilities separated by comma. Example:&lt;br /&gt;
&amp;lt;pre language=&amp;quot;none&amp;quot;&amp;gt; &lt;br /&gt;
...&amp;amp;cap=emoji,-calendar&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15549</id>
		<title>AppSuite:Debugging the UI</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15549"/>
		<updated>2013-08-29T10:06:48Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Debugging the UI&amp;lt;/div&amp;gt;&lt;br /&gt;
'''Synopsis:''' A collection of hints to debug during UI development&lt;br /&gt;
__TOC__&lt;br /&gt;
== What capabilities are available? ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
_(ox.serverConfig.capabilities).pluck(&amp;quot;id&amp;quot;).sort();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Check settings ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// check core settings&lt;br /&gt;
require('settings!io.ox/core').get();&lt;br /&gt;
// check mail settings&lt;br /&gt;
require('settings!io.ox/mail').get();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Clear all persistent caches ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
ox.cache.clear();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debug relogin ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
ox.autoLogoutRestartDebug();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Enable/disable capability via URL hash ==&lt;br /&gt;
Just add the parameter &amp;quot;cap&amp;quot; to URL hash. A leading minus disables a capability. Multiple capabilities separated by comma. Example:&lt;br /&gt;
&amp;lt;pre language=&amp;quot;none&amp;quot;&amp;gt; &lt;br /&gt;
...&amp;amp;cap=emoji,-calendar&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15547</id>
		<title>AppSuite:Debugging the UI</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15547"/>
		<updated>2013-08-29T10:01:02Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Enable capability via URL hash */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Debugging the UI&amp;lt;/div&amp;gt;&lt;br /&gt;
'''Synopsis:''' A collection of hints to debug during UI development&lt;br /&gt;
__TOC__&lt;br /&gt;
== What capabilities are available? ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
_(ox.serverConfig.capabilities).pluck(&amp;quot;id&amp;quot;).sort();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Check settings ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
// check core settings&lt;br /&gt;
require('settings!io.ox/core').get();&lt;br /&gt;
// check mail settings&lt;br /&gt;
require('settings!io.ox/mail').get();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Enable/disable capability via URL hash ==&lt;br /&gt;
Just add the parameter &amp;quot;cap&amp;quot; to URL hash. A leading minus disables a capability. Multiple capabilities separated by comma. Example:&lt;br /&gt;
&amp;lt;pre language=&amp;quot;none&amp;quot;&amp;gt; &lt;br /&gt;
...&amp;amp;cap=emoji,-calendar&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15546</id>
		<title>AppSuite:Debugging the UI</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15546"/>
		<updated>2013-08-29T10:00:50Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Enable capability via URL hash */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Debugging the UI&amp;lt;/div&amp;gt;&lt;br /&gt;
'''Synopsis:''' A collection of hints to debug during UI development&lt;br /&gt;
__TOC__&lt;br /&gt;
== What capabilities are available? ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
_(ox.serverConfig.capabilities).pluck(&amp;quot;id&amp;quot;).sort();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Check settings ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
// check core settings&lt;br /&gt;
require('settings!io.ox/core').get();&lt;br /&gt;
// check mail settings&lt;br /&gt;
require('settings!io.ox/mail').get();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Enable capability via URL hash ==&lt;br /&gt;
Just add the parameter &amp;quot;cap&amp;quot; to URL hash. A leading minus disables a capability. Multiple capabilities separated by comma. Example:&lt;br /&gt;
&amp;lt;pre language=&amp;quot;none&amp;quot;&amp;gt; &lt;br /&gt;
...&amp;amp;cap=emoji,-calendar&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15545</id>
		<title>AppSuite:Debugging the UI</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15545"/>
		<updated>2013-08-29T10:00:31Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Enable capability via URL hash */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Debugging the UI&amp;lt;/div&amp;gt;&lt;br /&gt;
'''Synopsis:''' A collection of hints to debug during UI development&lt;br /&gt;
__TOC__&lt;br /&gt;
== What capabilities are available? ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
_(ox.serverConfig.capabilities).pluck(&amp;quot;id&amp;quot;).sort();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Check settings ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
// check core settings&lt;br /&gt;
require('settings!io.ox/core').get();&lt;br /&gt;
// check mail settings&lt;br /&gt;
require('settings!io.ox/mail').get();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Enable capability via URL hash ==&lt;br /&gt;
Just add the parameter &amp;quot;cap&amp;quot; to URL hash, e.g. '''...&amp;amp;cap=emoji'''. A leading minus disables a capability. Multiple capabilities separated by comma:&lt;br /&gt;
&amp;lt;pre language=&amp;quot;none&amp;quot;&amp;gt; &lt;br /&gt;
...&amp;amp;cap=emoji,-calendar&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15544</id>
		<title>AppSuite:Debugging the UI</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15544"/>
		<updated>2013-08-29T09:58:32Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Enable capability via URL hash */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Debugging the UI&amp;lt;/div&amp;gt;&lt;br /&gt;
'''Synopsis:''' A collection of hints to debug during UI development&lt;br /&gt;
__TOC__&lt;br /&gt;
== What capabilities are available? ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
_(ox.serverConfig.capabilities).pluck(&amp;quot;id&amp;quot;).sort();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Check settings ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
// check core settings&lt;br /&gt;
require('settings!io.ox/core').get();&lt;br /&gt;
// check mail settings&lt;br /&gt;
require('settings!io.ox/mail').get();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Enable capability via URL hash ==&lt;br /&gt;
Just add the parameter &amp;quot;cap&amp;quot; to URL hash, e.g. '''...&amp;amp;cap=emoji'''. A leading minus disables a capability.&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15543</id>
		<title>AppSuite:Debugging the UI</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15543"/>
		<updated>2013-08-29T09:58:16Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Enable capability via URL hash */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Debugging the UI&amp;lt;/div&amp;gt;&lt;br /&gt;
'''Synopsis:''' A collection of hints to debug during UI development&lt;br /&gt;
__TOC__&lt;br /&gt;
== What capabilities are available? ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
_(ox.serverConfig.capabilities).pluck(&amp;quot;id&amp;quot;).sort();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Check settings ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
// check core settings&lt;br /&gt;
require('settings!io.ox/core').get();&lt;br /&gt;
// check mail settings&lt;br /&gt;
require('settings!io.ox/mail').get();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Enable capability via URL hash ==&lt;br /&gt;
Just add parameter cap to URL hash, e.g. '''...&amp;amp;cap=emoji'''. A leading minus disables a capability.&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15542</id>
		<title>AppSuite:Debugging the UI</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15542"/>
		<updated>2013-08-29T09:58:00Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Debugging the UI&amp;lt;/div&amp;gt;&lt;br /&gt;
'''Synopsis:''' A collection of hints to debug during UI development&lt;br /&gt;
__TOC__&lt;br /&gt;
== What capabilities are available? ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
_(ox.serverConfig.capabilities).pluck(&amp;quot;id&amp;quot;).sort();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Check settings ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
// check core settings&lt;br /&gt;
require('settings!io.ox/core').get();&lt;br /&gt;
// check mail settings&lt;br /&gt;
require('settings!io.ox/mail').get();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Enable capability via URL hash ==&lt;br /&gt;
Just add parameter cap to URL hash, e.g. ...&amp;amp;cap=emoji. A leading minus disables a capability.&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15541</id>
		<title>AppSuite:Debugging the UI</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15541"/>
		<updated>2013-08-29T09:52:26Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Check settings */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Debugging the UI&amp;lt;/div&amp;gt;&lt;br /&gt;
'''Synopsis:''' A collection of hints to debug during UI development&lt;br /&gt;
__TOC__&lt;br /&gt;
== What capabilities are available? ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
_(ox.serverConfig.capabilities).pluck(&amp;quot;id&amp;quot;).sort();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Check settings ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
// check core settings&lt;br /&gt;
require('settings!io.ox/core').get();&lt;br /&gt;
// check mail settings&lt;br /&gt;
require('settings!io.ox/mail').get();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15540</id>
		<title>AppSuite:Debugging the UI</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15540"/>
		<updated>2013-08-29T09:51:48Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Debugging the UI&amp;lt;/div&amp;gt;&lt;br /&gt;
'''Synopsis:''' A collection of hints to debug during UI development&lt;br /&gt;
__TOC__&lt;br /&gt;
== What capabilities are available? ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
_(ox.serverConfig.capabilities).pluck(&amp;quot;id&amp;quot;).sort();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Check settings ==&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
require('settings!io.ox/core').get();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15539</id>
		<title>AppSuite:Debugging the UI</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Debugging_the_UI&amp;diff=15539"/>
		<updated>2013-08-29T09:51:04Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Debugging the UI&amp;lt;/div&amp;gt;&lt;br /&gt;
'''Synopsis:''' A collection of hints to debug during UI development&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== What capabilities are available? ==&lt;br /&gt;
   _(ox.serverConfig.capabilities).pluck(&amp;quot;id&amp;quot;).sort();&lt;br /&gt;
&lt;br /&gt;
== Check settings ==&lt;br /&gt;
require('settings!io.ox/core').get();&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Configuration&amp;diff=15308</id>
		<title>AppSuite:Configuration</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Configuration&amp;diff=15308"/>
		<updated>2013-08-15T14:06:02Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Folders: hiding folders in panel */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stability-experimental}}&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Configuration&amp;lt;/div&amp;gt;&lt;br /&gt;
Overview of server-side settings mainly hiding/disabling front end elements without affecting backend. Please mind that this listing isn't complete yet.&lt;br /&gt;
&lt;br /&gt;
==Folders: hiding folders in panel==&lt;br /&gt;
In order to configure this server-side, just create a new property file in '''/opt/open-xchange/etc/settings''' or append to the existing file '''/opt/open-xchange/etc/settings/appsuite.properties''' (mind the '''double-slash'''; this in not a typo!):&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-config&amp;quot;&amp;gt; &lt;br /&gt;
io.ox/core//folder/blacklist/&amp;lt;id&amp;gt;=true|false&lt;br /&gt;
&lt;br /&gt;
# example: hide global address book&lt;br /&gt;
io.ox/core//folder/blacklist/6=true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Avoid white-space between the folder id and equal sign!'''&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
&lt;br /&gt;
==Mediaplayer: enabling/disabling ==&lt;br /&gt;
Please take a look at the [[ AppSuite:Mediaplayer#How_to_enable.2Fdisable_the_media_player | media player article ]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Configuration&amp;diff=15307</id>
		<title>AppSuite:Configuration</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Configuration&amp;diff=15307"/>
		<updated>2013-08-15T14:04:56Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Folders: hiding folders in panel */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stability-experimental}}&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Configuration&amp;lt;/div&amp;gt;&lt;br /&gt;
Overview of server-side settings mainly hiding/disabling front end elements without affecting backend. Please mind that this listing isn't complete yet.&lt;br /&gt;
&lt;br /&gt;
==Folders: hiding folders in panel==&lt;br /&gt;
In order to configure this server-side, just create a new property file in '''/opt/open-xchange/etc/settings''' or append to the existing file '''/opt/open-xchange/etc/settings/appsuite.properties''' (mind the '''double-slash'''; this in not a typo!):&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-config&amp;quot;&amp;gt; &lt;br /&gt;
io.ox/core//folder/blacklist/&amp;lt;id&amp;gt;=true|false&lt;br /&gt;
&lt;br /&gt;
# example: hide global address book&lt;br /&gt;
io.ox/core//folder/blacklist/6=true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
&lt;br /&gt;
==Mediaplayer: enabling/disabling ==&lt;br /&gt;
Please take a look at the [[ AppSuite:Mediaplayer#How_to_enable.2Fdisable_the_media_player | media player article ]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15293</id>
		<title>AppSuite:KeyboardControlled</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15293"/>
		<updated>2013-08-14T07:16:20Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* General navigation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;OX App Suite Keyboard Shortcuts&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General navigation ==&lt;br /&gt;
&lt;br /&gt;
The following keyboard shortcuts can be used across the UI in order to access element just via keyboard:&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''MacOS (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Move to next accessible element, e.g. links || Tab || &lt;br /&gt;
|-&lt;br /&gt;
|Move to previous accessible element || Shift-Tab || &lt;br /&gt;
|-&lt;br /&gt;
|Trigger element action (same as mouse click)  || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Move selection in lists and hierarchies, e.g. folder tree || Cursor Up/Down || &lt;br /&gt;
|-&lt;br /&gt;
|Move to top/bottom item in lists || - || Cmd+Cursor Up/Down&lt;br /&gt;
|-&lt;br /&gt;
|Open/close folder in folder tree view || Cursor right/left ||&lt;br /&gt;
|-&lt;br /&gt;
|Close popup dialogs || Escape ||&lt;br /&gt;
|-&lt;br /&gt;
|Move to next important component, e.g. top bar, folder tree, item lists || Ctrl-F6 || F6&lt;br /&gt;
|-&lt;br /&gt;
|Move to previous important component || Shift-Ctrl-F6 || Shift-F6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Documents ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Collapse or expand the side pane || Ctrl + F3 || Cmd + F3&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content  || Ctrl + F6 || F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content (backwards) || Shift + Ctrl + F6 || Shift + F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items (backwards) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button (without moving the focus) || Space ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the next ribbon control) || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the previous ribbon control) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move between dropdown menu entries || Cursor keys ||&lt;br /&gt;
|-&lt;br /&gt;
|Close dropdown menu || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
|Print || Ctrl + P || Cmd + P&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Document Viewer ==&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up || Arrow Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up fast || Page Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down || Arrow Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down fast || Page Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of first page || Home || Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of previous page || Alt + Page Up || Cmd + Page Up &lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of next page || Alt + Page Down || Cmd + Page Down&lt;br /&gt;
|-&lt;br /&gt;
|Jump to bottom of last page || End ||  Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Zoom in || + (also on numeric pad) ||&lt;br /&gt;
|-&lt;br /&gt;
|Zoom out || - (also on numeric pad) ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Editors ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents editor applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Focus the document || ESC ||&lt;br /&gt;
|-&lt;br /&gt;
| Undo the last action || Ctrl + Z, Alt + Backspace || Cmd + Z, Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Redo the last action || Ctrl + Y, Shift + Alt + Backspace || Cmd + Y, Shift + Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Copy selected text or object || Ctrl + C, Ctrl + Insert || Cmd + C&lt;br /&gt;
|-&lt;br /&gt;
| Cut selected text or object || Ctrl + X, Shift + Delete || Cmd + X, Shift + Delete&lt;br /&gt;
|-&lt;br /&gt;
| Paste selected text or object || Ctrl + V, Shift + Insert || Cmd + V&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Text ==&lt;br /&gt;
&lt;br /&gt;
'''Navigation'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
| '''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Jump one character to the left/right || Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump one word to the left/right || Ctrl + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to the beginning of a line || Home || Cmd + Arrow Left    &lt;br /&gt;
|-&lt;br /&gt;
| Jump to the end of a line || End || ✘                    &lt;br /&gt;
|-&lt;br /&gt;
| Jump one line up/down || Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to beginning/end of document || Ctrl + Home/End || Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Jump to next table cell || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to previous table cell || Shift + Tab ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Text Selection'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one character to the left/right || Shift + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the beginning of a line || Shift + Home || Shift + Cmd + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the end of a line || Shift + End || ✘    &lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one line up/down || Shift + Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to beginning/end of document || Shift + Ctrl + Home/End || Shift + Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to entire document || Ctrl + A || Cmd + A                 &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Search and Replace'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Open Search and Replace pane || Ctrl + F || Cmd + F &lt;br /&gt;
|-&lt;br /&gt;
| Close Search and Replace pane || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
| Select next search result || Ctrl + G || Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
| Select previous search result || Ctrl+ Shift + G || Shift + Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Edit Document'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Insert paragraph break || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
| Insert line break without breaking paragraph || Shift + Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Format Text'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove bold || Ctrl + B || Cmd + B&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove italic || Ctrl + I || Cmd + I&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove underline || Ctrl + U || Cmd + U&lt;br /&gt;
|-&lt;br /&gt;
| Remove all manual styles || Ctrl + Space ||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15292</id>
		<title>AppSuite:KeyboardControlled</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15292"/>
		<updated>2013-08-14T07:16:10Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* General navigation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;OX App Suite Keyboard Shortcuts&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General navigation ==&lt;br /&gt;
&lt;br /&gt;
The following keyboard shortcuts can be used across the UI in order to access element just via keyboard:&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''MacOS (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Move to next accessible element, e.g. links || Tab || &lt;br /&gt;
|-&lt;br /&gt;
|Move to previous accessible element || Shift-Tab || &lt;br /&gt;
|-&lt;br /&gt;
|Trigger element action (same as mouse click)  || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Move selection in lists and hierarchies, e.g. folder tree || Cursor Up/Down || &lt;br /&gt;
|-&lt;br /&gt;
|Move to top/bottom item in lists || || Cmd+Cursor Up/Down&lt;br /&gt;
|-&lt;br /&gt;
|Open/close folder in folder tree view || Cursor right/left ||&lt;br /&gt;
|-&lt;br /&gt;
|Close popup dialogs || Escape ||&lt;br /&gt;
|-&lt;br /&gt;
|Move to next important component, e.g. top bar, folder tree, item lists || Ctrl-F6 || F6&lt;br /&gt;
|-&lt;br /&gt;
|Move to previous important component || Shift-Ctrl-F6 || Shift-F6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Documents ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Collapse or expand the side pane || Ctrl + F3 || Cmd + F3&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content  || Ctrl + F6 || F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content (backwards) || Shift + Ctrl + F6 || Shift + F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items (backwards) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button (without moving the focus) || Space ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the next ribbon control) || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the previous ribbon control) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move between dropdown menu entries || Cursor keys ||&lt;br /&gt;
|-&lt;br /&gt;
|Close dropdown menu || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
|Print || Ctrl + P || Cmd + P&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Document Viewer ==&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up || Arrow Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up fast || Page Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down || Arrow Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down fast || Page Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of first page || Home || Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of previous page || Alt + Page Up || Cmd + Page Up &lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of next page || Alt + Page Down || Cmd + Page Down&lt;br /&gt;
|-&lt;br /&gt;
|Jump to bottom of last page || End ||  Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Zoom in || + (also on numeric pad) ||&lt;br /&gt;
|-&lt;br /&gt;
|Zoom out || - (also on numeric pad) ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Editors ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents editor applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Focus the document || ESC ||&lt;br /&gt;
|-&lt;br /&gt;
| Undo the last action || Ctrl + Z, Alt + Backspace || Cmd + Z, Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Redo the last action || Ctrl + Y, Shift + Alt + Backspace || Cmd + Y, Shift + Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Copy selected text or object || Ctrl + C, Ctrl + Insert || Cmd + C&lt;br /&gt;
|-&lt;br /&gt;
| Cut selected text or object || Ctrl + X, Shift + Delete || Cmd + X, Shift + Delete&lt;br /&gt;
|-&lt;br /&gt;
| Paste selected text or object || Ctrl + V, Shift + Insert || Cmd + V&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Text ==&lt;br /&gt;
&lt;br /&gt;
'''Navigation'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
| '''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Jump one character to the left/right || Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump one word to the left/right || Ctrl + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to the beginning of a line || Home || Cmd + Arrow Left    &lt;br /&gt;
|-&lt;br /&gt;
| Jump to the end of a line || End || ✘                    &lt;br /&gt;
|-&lt;br /&gt;
| Jump one line up/down || Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to beginning/end of document || Ctrl + Home/End || Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Jump to next table cell || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to previous table cell || Shift + Tab ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Text Selection'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one character to the left/right || Shift + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the beginning of a line || Shift + Home || Shift + Cmd + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the end of a line || Shift + End || ✘    &lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one line up/down || Shift + Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to beginning/end of document || Shift + Ctrl + Home/End || Shift + Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to entire document || Ctrl + A || Cmd + A                 &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Search and Replace'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Open Search and Replace pane || Ctrl + F || Cmd + F &lt;br /&gt;
|-&lt;br /&gt;
| Close Search and Replace pane || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
| Select next search result || Ctrl + G || Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
| Select previous search result || Ctrl+ Shift + G || Shift + Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Edit Document'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Insert paragraph break || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
| Insert line break without breaking paragraph || Shift + Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Format Text'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove bold || Ctrl + B || Cmd + B&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove italic || Ctrl + I || Cmd + I&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove underline || Ctrl + U || Cmd + U&lt;br /&gt;
|-&lt;br /&gt;
| Remove all manual styles || Ctrl + Space ||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15291</id>
		<title>AppSuite:KeyboardControlled</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15291"/>
		<updated>2013-08-14T07:13:05Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* General */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;OX App Suite Keyboard Shortcuts&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General navigation ==&lt;br /&gt;
&lt;br /&gt;
The following keyboard shortcuts can be used across the UI in order to access element just via keyboard:&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''MacOS (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Move to next accessible element, e.g. links || Tab || &lt;br /&gt;
|-&lt;br /&gt;
|Move to previous accessible element || Shift-Tab || &lt;br /&gt;
|-&lt;br /&gt;
|Trigger element action (same as mouse click)  || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Move selection in lists and hierarchies, e.g. folder tree || Cursor Up/Down || &lt;br /&gt;
|-&lt;br /&gt;
|Close popup dialogs || Escape ||&lt;br /&gt;
|-&lt;br /&gt;
|Move to next important component, e.g. top bar, folder tree, item lists || Ctrl-F6 || F6&lt;br /&gt;
|-&lt;br /&gt;
|Move to previous important component || Shift-Ctrl-F6 || Shift-F6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Documents ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Collapse or expand the side pane || Ctrl + F3 || Cmd + F3&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content  || Ctrl + F6 || F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content (backwards) || Shift + Ctrl + F6 || Shift + F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items (backwards) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button (without moving the focus) || Space ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the next ribbon control) || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the previous ribbon control) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move between dropdown menu entries || Cursor keys ||&lt;br /&gt;
|-&lt;br /&gt;
|Close dropdown menu || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
|Print || Ctrl + P || Cmd + P&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Document Viewer ==&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up || Arrow Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up fast || Page Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down || Arrow Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down fast || Page Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of first page || Home || Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of previous page || Alt + Page Up || Cmd + Page Up &lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of next page || Alt + Page Down || Cmd + Page Down&lt;br /&gt;
|-&lt;br /&gt;
|Jump to bottom of last page || End ||  Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Zoom in || + (also on numeric pad) ||&lt;br /&gt;
|-&lt;br /&gt;
|Zoom out || - (also on numeric pad) ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Editors ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents editor applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Focus the document || ESC ||&lt;br /&gt;
|-&lt;br /&gt;
| Undo the last action || Ctrl + Z, Alt + Backspace || Cmd + Z, Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Redo the last action || Ctrl + Y, Shift + Alt + Backspace || Cmd + Y, Shift + Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Copy selected text or object || Ctrl + C, Ctrl + Insert || Cmd + C&lt;br /&gt;
|-&lt;br /&gt;
| Cut selected text or object || Ctrl + X, Shift + Delete || Cmd + X, Shift + Delete&lt;br /&gt;
|-&lt;br /&gt;
| Paste selected text or object || Ctrl + V, Shift + Insert || Cmd + V&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Text ==&lt;br /&gt;
&lt;br /&gt;
'''Navigation'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
| '''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Jump one character to the left/right || Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump one word to the left/right || Ctrl + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to the beginning of a line || Home || Cmd + Arrow Left    &lt;br /&gt;
|-&lt;br /&gt;
| Jump to the end of a line || End || ✘                    &lt;br /&gt;
|-&lt;br /&gt;
| Jump one line up/down || Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to beginning/end of document || Ctrl + Home/End || Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Jump to next table cell || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to previous table cell || Shift + Tab ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Text Selection'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one character to the left/right || Shift + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the beginning of a line || Shift + Home || Shift + Cmd + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the end of a line || Shift + End || ✘    &lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one line up/down || Shift + Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to beginning/end of document || Shift + Ctrl + Home/End || Shift + Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to entire document || Ctrl + A || Cmd + A                 &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Search and Replace'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Open Search and Replace pane || Ctrl + F || Cmd + F &lt;br /&gt;
|-&lt;br /&gt;
| Close Search and Replace pane || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
| Select next search result || Ctrl + G || Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
| Select previous search result || Ctrl+ Shift + G || Shift + Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Edit Document'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Insert paragraph break || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
| Insert line break without breaking paragraph || Shift + Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Format Text'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove bold || Ctrl + B || Cmd + B&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove italic || Ctrl + I || Cmd + I&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove underline || Ctrl + U || Cmd + U&lt;br /&gt;
|-&lt;br /&gt;
| Remove all manual styles || Ctrl + Space ||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15290</id>
		<title>AppSuite:KeyboardControlled</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15290"/>
		<updated>2013-08-14T07:12:10Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* General */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;OX App Suite Keyboard Shortcuts&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
&lt;br /&gt;
The following keyboard shortcuts can be used across the UI in order to access element just via keyboard:&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''MacOS (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Move to next accessible element, e.g. links || Tab || &lt;br /&gt;
|-&lt;br /&gt;
|Move to previous accessible element || Shift-Tab || &lt;br /&gt;
|-&lt;br /&gt;
|Trigger element action (same as mouse click)  || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Move selection in lists and hierarchies, e.g. folder tree || Cursor Up/Down || &lt;br /&gt;
|-&lt;br /&gt;
|Close popup dialogs || Escape ||&lt;br /&gt;
|-&lt;br /&gt;
|Move to next important component, e.g. top bar, folder tree, item lists || Ctrl-F6 || F6&lt;br /&gt;
|-&lt;br /&gt;
|Move to previous important component || Shift-Ctrl-F6 || Shift-F6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Documents ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Collapse or expand the side pane || Ctrl + F3 || Cmd + F3&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content  || Ctrl + F6 || F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content (backwards) || Shift + Ctrl + F6 || Shift + F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items (backwards) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button (without moving the focus) || Space ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the next ribbon control) || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the previous ribbon control) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move between dropdown menu entries || Cursor keys ||&lt;br /&gt;
|-&lt;br /&gt;
|Close dropdown menu || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
|Print || Ctrl + P || Cmd + P&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Document Viewer ==&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up || Arrow Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up fast || Page Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down || Arrow Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down fast || Page Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of first page || Home || Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of previous page || Alt + Page Up || Cmd + Page Up &lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of next page || Alt + Page Down || Cmd + Page Down&lt;br /&gt;
|-&lt;br /&gt;
|Jump to bottom of last page || End ||  Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Zoom in || + (also on numeric pad) ||&lt;br /&gt;
|-&lt;br /&gt;
|Zoom out || - (also on numeric pad) ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Editors ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents editor applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Focus the document || ESC ||&lt;br /&gt;
|-&lt;br /&gt;
| Undo the last action || Ctrl + Z, Alt + Backspace || Cmd + Z, Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Redo the last action || Ctrl + Y, Shift + Alt + Backspace || Cmd + Y, Shift + Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Copy selected text or object || Ctrl + C, Ctrl + Insert || Cmd + C&lt;br /&gt;
|-&lt;br /&gt;
| Cut selected text or object || Ctrl + X, Shift + Delete || Cmd + X, Shift + Delete&lt;br /&gt;
|-&lt;br /&gt;
| Paste selected text or object || Ctrl + V, Shift + Insert || Cmd + V&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Text ==&lt;br /&gt;
&lt;br /&gt;
'''Navigation'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
| '''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Jump one character to the left/right || Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump one word to the left/right || Ctrl + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to the beginning of a line || Home || Cmd + Arrow Left    &lt;br /&gt;
|-&lt;br /&gt;
| Jump to the end of a line || End || ✘                    &lt;br /&gt;
|-&lt;br /&gt;
| Jump one line up/down || Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to beginning/end of document || Ctrl + Home/End || Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Jump to next table cell || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to previous table cell || Shift + Tab ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Text Selection'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one character to the left/right || Shift + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the beginning of a line || Shift + Home || Shift + Cmd + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the end of a line || Shift + End || ✘    &lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one line up/down || Shift + Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to beginning/end of document || Shift + Ctrl + Home/End || Shift + Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to entire document || Ctrl + A || Cmd + A                 &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Search and Replace'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Open Search and Replace pane || Ctrl + F || Cmd + F &lt;br /&gt;
|-&lt;br /&gt;
| Close Search and Replace pane || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
| Select next search result || Ctrl + G || Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
| Select previous search result || Ctrl+ Shift + G || Shift + Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Edit Document'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Insert paragraph break || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
| Insert line break without breaking paragraph || Shift + Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Format Text'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove bold || Ctrl + B || Cmd + B&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove italic || Ctrl + I || Cmd + I&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove underline || Ctrl + U || Cmd + U&lt;br /&gt;
|-&lt;br /&gt;
| Remove all manual styles || Ctrl + Space ||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15289</id>
		<title>AppSuite:KeyboardControlled</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15289"/>
		<updated>2013-08-14T07:10:56Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* General */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;OX App Suite Keyboard Shortcuts&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
&lt;br /&gt;
The following keyboard shortcuts can be used across the UI.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''MacOS (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Move to next accessible element, e.g. links || Tab || &lt;br /&gt;
|-&lt;br /&gt;
|Move to previous accessible element || Shift-Tab || &lt;br /&gt;
|-&lt;br /&gt;
|Trigger element action (same as mouse click)  || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Move selection in lists and hierarchies, e.g. folder tree || Cursor Up/Down || &lt;br /&gt;
|-&lt;br /&gt;
|Close popup dialogs || Escape ||&lt;br /&gt;
|-&lt;br /&gt;
|Move to next important component, e.g. top bar, folder tree, item lists || Ctrl-F6 || F6&lt;br /&gt;
|-&lt;br /&gt;
|Move to previous important component || Shift-Ctrl-F6 || Shift-F6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Documents ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Collapse or expand the side pane || Ctrl + F3 || Cmd + F3&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content  || Ctrl + F6 || F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content (backwards) || Shift + Ctrl + F6 || Shift + F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items (backwards) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button (without moving the focus) || Space ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the next ribbon control) || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the previous ribbon control) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move between dropdown menu entries || Cursor keys ||&lt;br /&gt;
|-&lt;br /&gt;
|Close dropdown menu || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
|Print || Ctrl + P || Cmd + P&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Document Viewer ==&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up || Arrow Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up fast || Page Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down || Arrow Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down fast || Page Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of first page || Home || Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of previous page || Alt + Page Up || Cmd + Page Up &lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of next page || Alt + Page Down || Cmd + Page Down&lt;br /&gt;
|-&lt;br /&gt;
|Jump to bottom of last page || End ||  Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Zoom in || + (also on numeric pad) ||&lt;br /&gt;
|-&lt;br /&gt;
|Zoom out || - (also on numeric pad) ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Editors ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents editor applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Focus the document || ESC ||&lt;br /&gt;
|-&lt;br /&gt;
| Undo the last action || Ctrl + Z, Alt + Backspace || Cmd + Z, Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Redo the last action || Ctrl + Y, Shift + Alt + Backspace || Cmd + Y, Shift + Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Copy selected text or object || Ctrl + C, Ctrl + Insert || Cmd + C&lt;br /&gt;
|-&lt;br /&gt;
| Cut selected text or object || Ctrl + X, Shift + Delete || Cmd + X, Shift + Delete&lt;br /&gt;
|-&lt;br /&gt;
| Paste selected text or object || Ctrl + V, Shift + Insert || Cmd + V&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Text ==&lt;br /&gt;
&lt;br /&gt;
'''Navigation'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
| '''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Jump one character to the left/right || Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump one word to the left/right || Ctrl + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to the beginning of a line || Home || Cmd + Arrow Left    &lt;br /&gt;
|-&lt;br /&gt;
| Jump to the end of a line || End || ✘                    &lt;br /&gt;
|-&lt;br /&gt;
| Jump one line up/down || Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to beginning/end of document || Ctrl + Home/End || Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Jump to next table cell || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to previous table cell || Shift + Tab ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Text Selection'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one character to the left/right || Shift + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the beginning of a line || Shift + Home || Shift + Cmd + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the end of a line || Shift + End || ✘    &lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one line up/down || Shift + Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to beginning/end of document || Shift + Ctrl + Home/End || Shift + Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to entire document || Ctrl + A || Cmd + A                 &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Search and Replace'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Open Search and Replace pane || Ctrl + F || Cmd + F &lt;br /&gt;
|-&lt;br /&gt;
| Close Search and Replace pane || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
| Select next search result || Ctrl + G || Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
| Select previous search result || Ctrl+ Shift + G || Shift + Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Edit Document'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Insert paragraph break || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
| Insert line break without breaking paragraph || Shift + Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Format Text'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove bold || Ctrl + B || Cmd + B&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove italic || Ctrl + I || Cmd + I&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove underline || Ctrl + U || Cmd + U&lt;br /&gt;
|-&lt;br /&gt;
| Remove all manual styles || Ctrl + Space ||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15288</id>
		<title>AppSuite:KeyboardControlled</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15288"/>
		<updated>2013-08-14T07:10:32Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* General */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;OX App Suite Keyboard Shortcuts&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
&lt;br /&gt;
The following keyboard shortcuts can be used across the UI.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Move to next accessible element, e.g. links || Tab || &lt;br /&gt;
|-&lt;br /&gt;
|Move to previous accessible element || Shift-Tab || &lt;br /&gt;
|-&lt;br /&gt;
|Trigger element action (same as mouse click)  || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Move selection in lists and hierarchies, e.g. folder tree || Cursor Up/Down || &lt;br /&gt;
|-&lt;br /&gt;
|Close popup dialogs || Escape ||&lt;br /&gt;
|-&lt;br /&gt;
|Move to next important component, e.g. top bar, folder tree, item lists || Ctrl-F6 || F6&lt;br /&gt;
|-&lt;br /&gt;
|Move to previous important component || Shift-Ctrl-F6 || Shift-F6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Documents ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Collapse or expand the side pane || Ctrl + F3 || Cmd + F3&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content  || Ctrl + F6 || F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content (backwards) || Shift + Ctrl + F6 || Shift + F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items (backwards) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button (without moving the focus) || Space ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the next ribbon control) || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the previous ribbon control) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move between dropdown menu entries || Cursor keys ||&lt;br /&gt;
|-&lt;br /&gt;
|Close dropdown menu || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
|Print || Ctrl + P || Cmd + P&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Document Viewer ==&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up || Arrow Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up fast || Page Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down || Arrow Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down fast || Page Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of first page || Home || Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of previous page || Alt + Page Up || Cmd + Page Up &lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of next page || Alt + Page Down || Cmd + Page Down&lt;br /&gt;
|-&lt;br /&gt;
|Jump to bottom of last page || End ||  Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Zoom in || + (also on numeric pad) ||&lt;br /&gt;
|-&lt;br /&gt;
|Zoom out || - (also on numeric pad) ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Editors ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents editor applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Focus the document || ESC ||&lt;br /&gt;
|-&lt;br /&gt;
| Undo the last action || Ctrl + Z, Alt + Backspace || Cmd + Z, Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Redo the last action || Ctrl + Y, Shift + Alt + Backspace || Cmd + Y, Shift + Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Copy selected text or object || Ctrl + C, Ctrl + Insert || Cmd + C&lt;br /&gt;
|-&lt;br /&gt;
| Cut selected text or object || Ctrl + X, Shift + Delete || Cmd + X, Shift + Delete&lt;br /&gt;
|-&lt;br /&gt;
| Paste selected text or object || Ctrl + V, Shift + Insert || Cmd + V&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Text ==&lt;br /&gt;
&lt;br /&gt;
'''Navigation'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
| '''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Jump one character to the left/right || Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump one word to the left/right || Ctrl + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to the beginning of a line || Home || Cmd + Arrow Left    &lt;br /&gt;
|-&lt;br /&gt;
| Jump to the end of a line || End || ✘                    &lt;br /&gt;
|-&lt;br /&gt;
| Jump one line up/down || Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to beginning/end of document || Ctrl + Home/End || Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Jump to next table cell || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to previous table cell || Shift + Tab ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Text Selection'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one character to the left/right || Shift + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the beginning of a line || Shift + Home || Shift + Cmd + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the end of a line || Shift + End || ✘    &lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one line up/down || Shift + Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to beginning/end of document || Shift + Ctrl + Home/End || Shift + Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to entire document || Ctrl + A || Cmd + A                 &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Search and Replace'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Open Search and Replace pane || Ctrl + F || Cmd + F &lt;br /&gt;
|-&lt;br /&gt;
| Close Search and Replace pane || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
| Select next search result || Ctrl + G || Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
| Select previous search result || Ctrl+ Shift + G || Shift + Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Edit Document'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Insert paragraph break || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
| Insert line break without breaking paragraph || Shift + Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Format Text'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove bold || Ctrl + B || Cmd + B&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove italic || Ctrl + I || Cmd + I&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove underline || Ctrl + U || Cmd + U&lt;br /&gt;
|-&lt;br /&gt;
| Remove all manual styles || Ctrl + Space ||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15287</id>
		<title>AppSuite:KeyboardControlled</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15287"/>
		<updated>2013-08-14T07:07:54Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* General */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;OX App Suite Keyboard Shortcuts&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
&lt;br /&gt;
The following keyboard shortcuts can be used across the UI.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Traverse accessible elements, e.g. links || Tab || &lt;br /&gt;
|-&lt;br /&gt;
|Trigger element action (same as mouse click)  || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Move selection in lists and hierarchies, e.g. folder tree || Cursor Up/Down || &lt;br /&gt;
|-&lt;br /&gt;
|Close popup dialogs || Escape ||&lt;br /&gt;
|-&lt;br /&gt;
|Traverse important components, e.g. top bar, folder tree, item lists || Ctrl-F6 || F6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Documents ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Collapse or expand the side pane || Ctrl + F3 || Cmd + F3&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content  || Ctrl + F6 || F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content (backwards) || Shift + Ctrl + F6 || Shift + F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items (backwards) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button (without moving the focus) || Space ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the next ribbon control) || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the previous ribbon control) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move between dropdown menu entries || Cursor keys ||&lt;br /&gt;
|-&lt;br /&gt;
|Close dropdown menu || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
|Print || Ctrl + P || Cmd + P&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Document Viewer ==&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up || Arrow Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up fast || Page Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down || Arrow Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down fast || Page Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of first page || Home || Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of previous page || Alt + Page Up || Cmd + Page Up &lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of next page || Alt + Page Down || Cmd + Page Down&lt;br /&gt;
|-&lt;br /&gt;
|Jump to bottom of last page || End ||  Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Zoom in || + (also on numeric pad) ||&lt;br /&gt;
|-&lt;br /&gt;
|Zoom out || - (also on numeric pad) ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Editors ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents editor applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Focus the document || ESC ||&lt;br /&gt;
|-&lt;br /&gt;
| Undo the last action || Ctrl + Z, Alt + Backspace || Cmd + Z, Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Redo the last action || Ctrl + Y, Shift + Alt + Backspace || Cmd + Y, Shift + Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Copy selected text or object || Ctrl + C, Ctrl + Insert || Cmd + C&lt;br /&gt;
|-&lt;br /&gt;
| Cut selected text or object || Ctrl + X, Shift + Delete || Cmd + X, Shift + Delete&lt;br /&gt;
|-&lt;br /&gt;
| Paste selected text or object || Ctrl + V, Shift + Insert || Cmd + V&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Text ==&lt;br /&gt;
&lt;br /&gt;
'''Navigation'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
| '''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Jump one character to the left/right || Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump one word to the left/right || Ctrl + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to the beginning of a line || Home || Cmd + Arrow Left    &lt;br /&gt;
|-&lt;br /&gt;
| Jump to the end of a line || End || ✘                    &lt;br /&gt;
|-&lt;br /&gt;
| Jump one line up/down || Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to beginning/end of document || Ctrl + Home/End || Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Jump to next table cell || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to previous table cell || Shift + Tab ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Text Selection'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one character to the left/right || Shift + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the beginning of a line || Shift + Home || Shift + Cmd + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the end of a line || Shift + End || ✘    &lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one line up/down || Shift + Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to beginning/end of document || Shift + Ctrl + Home/End || Shift + Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to entire document || Ctrl + A || Cmd + A                 &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Search and Replace'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Open Search and Replace pane || Ctrl + F || Cmd + F &lt;br /&gt;
|-&lt;br /&gt;
| Close Search and Replace pane || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
| Select next search result || Ctrl + G || Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
| Select previous search result || Ctrl+ Shift + G || Shift + Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Edit Document'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Insert paragraph break || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
| Insert line break without breaking paragraph || Shift + Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Format Text'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove bold || Ctrl + B || Cmd + B&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove italic || Ctrl + I || Cmd + I&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove underline || Ctrl + U || Cmd + U&lt;br /&gt;
|-&lt;br /&gt;
| Remove all manual styles || Ctrl + Space ||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15286</id>
		<title>AppSuite:KeyboardControlled</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15286"/>
		<updated>2013-08-14T06:56:02Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;OX App Suite Keyboard Shortcuts&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
&lt;br /&gt;
The following keyboard shortcuts can be used across the UI.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Traverse accessible elements, e.g. links || Tab || &lt;br /&gt;
|-&lt;br /&gt;
|Trigger element action (same as mouse click)  || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Move selection in lists and hierarchies, e.g. folder tree || Cursor Up/Down || &lt;br /&gt;
|-&lt;br /&gt;
|Close popup dialogs || Escape ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Documents ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Collapse or expand the side pane || Ctrl + F3 || Cmd + F3&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content  || Ctrl + F6 || F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content (backwards) || Shift + Ctrl + F6 || Shift + F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items (backwards) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button (without moving the focus) || Space ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the next ribbon control) || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the previous ribbon control) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move between dropdown menu entries || Cursor keys ||&lt;br /&gt;
|-&lt;br /&gt;
|Close dropdown menu || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
|Print || Ctrl + P || Cmd + P&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Document Viewer ==&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up || Arrow Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up fast || Page Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down || Arrow Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down fast || Page Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of first page || Home || Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of previous page || Alt + Page Up || Cmd + Page Up &lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of next page || Alt + Page Down || Cmd + Page Down&lt;br /&gt;
|-&lt;br /&gt;
|Jump to bottom of last page || End ||  Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Zoom in || + (also on numeric pad) ||&lt;br /&gt;
|-&lt;br /&gt;
|Zoom out || - (also on numeric pad) ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Editors ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents editor applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Focus the document || ESC ||&lt;br /&gt;
|-&lt;br /&gt;
| Undo the last action || Ctrl + Z, Alt + Backspace || Cmd + Z, Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Redo the last action || Ctrl + Y, Shift + Alt + Backspace || Cmd + Y, Shift + Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Copy selected text or object || Ctrl + C, Ctrl + Insert || Cmd + C&lt;br /&gt;
|-&lt;br /&gt;
| Cut selected text or object || Ctrl + X, Shift + Delete || Cmd + X, Shift + Delete&lt;br /&gt;
|-&lt;br /&gt;
| Paste selected text or object || Ctrl + V, Shift + Insert || Cmd + V&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Text ==&lt;br /&gt;
&lt;br /&gt;
'''Navigation'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
| '''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Jump one character to the left/right || Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump one word to the left/right || Ctrl + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to the beginning of a line || Home || Cmd + Arrow Left    &lt;br /&gt;
|-&lt;br /&gt;
| Jump to the end of a line || End || ✘                    &lt;br /&gt;
|-&lt;br /&gt;
| Jump one line up/down || Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to beginning/end of document || Ctrl + Home/End || Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Jump to next table cell || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to previous table cell || Shift + Tab ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Text Selection'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one character to the left/right || Shift + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the beginning of a line || Shift + Home || Shift + Cmd + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the end of a line || Shift + End || ✘    &lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one line up/down || Shift + Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to beginning/end of document || Shift + Ctrl + Home/End || Shift + Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to entire document || Ctrl + A || Cmd + A                 &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Search and Replace'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Open Search and Replace pane || Ctrl + F || Cmd + F &lt;br /&gt;
|-&lt;br /&gt;
| Close Search and Replace pane || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
| Select next search result || Ctrl + G || Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
| Select previous search result || Ctrl+ Shift + G || Shift + Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Edit Document'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Insert paragraph break || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
| Insert line break without breaking paragraph || Shift + Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Format Text'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove bold || Ctrl + B || Cmd + B&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove italic || Ctrl + I || Cmd + I&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove underline || Ctrl + U || Cmd + U&lt;br /&gt;
|-&lt;br /&gt;
| Remove all manual styles || Ctrl + Space ||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15285</id>
		<title>AppSuite:KeyboardControlled</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:KeyboardControlled&amp;diff=15285"/>
		<updated>2013-08-14T06:52:16Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;OX App Suite Keyboard Shortcuts&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== OX Documents ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Collapse or expand the side pane || Ctrl + F3 || Cmd + F3&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content  || Ctrl + F6 || F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus between tool bars and document content (backwards) || Shift + Ctrl + F6 || Shift + F6&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move focus among tool bar items (backwards) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected button (without moving the focus) || Space ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the next ribbon control) || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Execute the currently selected entry in a dropdown menu (moving the focus to the previous ribbon control) || Shift + Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Move between dropdown menu entries || Cursor keys ||&lt;br /&gt;
|-&lt;br /&gt;
|Close dropdown menu || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
|Print || Ctrl + P || Cmd + P&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Document Viewer ==&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up || Arrow Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll up fast || Page Up ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down || Arrow Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Scroll down fast || Page Down ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of first page || Home || Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of previous page || Alt + Page Up || Cmd + Page Up &lt;br /&gt;
|-&lt;br /&gt;
|Jump to top of next page || Alt + Page Down || Cmd + Page Down&lt;br /&gt;
|-&lt;br /&gt;
|Jump to bottom of last page || End ||  Fn + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
|Zoom in || + (also on numeric pad) ||&lt;br /&gt;
|-&lt;br /&gt;
|Zoom out || - (also on numeric pad) ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Editors ==&lt;br /&gt;
&lt;br /&gt;
These keyboard shortcuts apply for all OX Documents editor applications.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Focus the document || ESC ||&lt;br /&gt;
|-&lt;br /&gt;
| Undo the last action || Ctrl + Z, Alt + Backspace || Cmd + Z, Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Redo the last action || Ctrl + Y, Shift + Alt + Backspace || Cmd + Y, Shift + Alt + Backspace&lt;br /&gt;
|-&lt;br /&gt;
| Copy selected text or object || Ctrl + C, Ctrl + Insert || Cmd + C&lt;br /&gt;
|-&lt;br /&gt;
| Cut selected text or object || Ctrl + X, Shift + Delete || Cmd + X, Shift + Delete&lt;br /&gt;
|-&lt;br /&gt;
| Paste selected text or object || Ctrl + V, Shift + Insert || Cmd + V&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== OX Text ==&lt;br /&gt;
&lt;br /&gt;
'''Navigation'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
| '''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Jump one character to the left/right || Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump one word to the left/right || Ctrl + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to the beginning of a line || Home || Cmd + Arrow Left    &lt;br /&gt;
|-&lt;br /&gt;
| Jump to the end of a line || End || ✘                    &lt;br /&gt;
|-&lt;br /&gt;
| Jump one line up/down || Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Jump to beginning/end of document || Ctrl + Home/End || Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Jump to next table cell || Tab ||&lt;br /&gt;
|-&lt;br /&gt;
|Jump to previous table cell || Shift + Tab ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Text Selection'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one character to the left/right || Shift + Arrow Left/Right ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the beginning of a line || Shift + Home || Shift + Cmd + Arrow Left&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to the end of a line || Shift + End || ✘    &lt;br /&gt;
|-&lt;br /&gt;
| Extend selection one line up/down || Shift + Arrow Up/Down ||&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to beginning/end of document || Shift + Ctrl + Home/End || Shift + Cmd + Arrow Up/Down&lt;br /&gt;
|-&lt;br /&gt;
| Extend selection to entire document || Ctrl + A || Cmd + A                 &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Search and Replace'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Open Search and Replace pane || Ctrl + F || Cmd + F &lt;br /&gt;
|-&lt;br /&gt;
| Close Search and Replace pane || Esc ||&lt;br /&gt;
|-&lt;br /&gt;
| Select next search result || Ctrl + G || Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
| Select previous search result || Ctrl+ Shift + G || Shift + Cmd + G &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Edit Document'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Insert paragraph break || Enter ||&lt;br /&gt;
|-&lt;br /&gt;
| Insert line break without breaking paragraph || Shift + Enter ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''Format Text'''&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
|'''Function''' || '''Windows / Linux''' || '''Apple Mac (if different)'''&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove bold || Ctrl + B || Cmd + B&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove italic || Ctrl + I || Cmd + I&lt;br /&gt;
|-&lt;br /&gt;
| Apply/remove underline || Ctrl + U || Cmd + U&lt;br /&gt;
|-&lt;br /&gt;
| Remove all manual styles || Ctrl + Space ||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Upsell&amp;diff=15127</id>
		<title>AppSuite:Upsell</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Upsell&amp;diff=15127"/>
		<updated>2013-07-23T11:46:33Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Upsell&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract.''' This article is mainly for UI developers and introduces the concept of upsell from a technical point of view. In short: End-user has a set of so-called ''capabilities''. UI, however, offers functionality beyond that limited set for promotion purposes. Actions, e.g. inline links, that require missing capabilities trigger an '''in-app upsell'''. This process leads to a trial period or a new subscription. Technical challenge for the UI developer is to check what the end-user has, what can be shown beyond that, and how to handle upsell. It is also possible for hosting companies to easily integrate their own online shop into OX Upsell, since the internal mechanisms are ''loosely coupled'' via events.&lt;br /&gt;
__TOC__&lt;br /&gt;
==Enable upsell==&lt;br /&gt;
In order to configure upsell server-side, just create a new file '''upsell.properties''' or append to existing '''appsuite.properties''' (mind the '''double-slash'''; this in not a typo! plus: changing such settings requires a backend restart):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
io.ox/core//upsell/enabled/infostore=true&lt;br /&gt;
io.ox/core//upsell/enabled/portal=true&lt;br /&gt;
io.ox/core//upsell/enabled/tasks=true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Each line enables a specific [[AppSuite:Upsell#Capabilities|capability]] for upsell. That means whenever a feature misses one these capabilities a special upsell-related event is triggered.&lt;br /&gt;
&lt;br /&gt;
Hint: For simple demo purposes, you can enable an internal upsell configuration by appending '''&amp;quot;&amp;amp;demo=upsell&amp;quot;''' to the URL. Needs to reload page, of course.&lt;br /&gt;
&lt;br /&gt;
==Upsell Wizard==&lt;br /&gt;
&amp;lt;div style=&amp;quot;color: #3A87AD; text-align: right; margin: -1em 0 1em 0; padding: 0.5em; background-color: #D9EDF7;&amp;quot;&amp;gt;Shipped with 7.2.1&amp;lt;/div&amp;gt;&lt;br /&gt;
Hosters usually want to offer context-sensitive content in an IFRAME if the upsell is triggered. Therefore, App Suite comes with an integrated but optional plugin that takes care of this. Just [[AppSuite:UI_manifests_explained#Loading_custom_manifest_during_development|enable]] ''plugins/upsell/simple-wizard''. This plugin registers for the event ''&amp;quot;upsell:requires-upsell&amp;quot;'', opens a modal popup, and loads a custom URL in an embedded IFRAME.&lt;br /&gt;
&lt;br /&gt;
[[File:Simple_upsell_wizard.png|800 px|Custom content in an IFRAME]]&lt;br /&gt;
&lt;br /&gt;
===Wizard settings===&lt;br /&gt;
In order to configure this server-side, just create a new file '''upsell.properties''' or append to existing '''appsuite.properties''' (mind the '''double-slash'''; this in not a typo! plus: changing such settings requires a backend restart):&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt;&lt;br /&gt;
plugins/upsell/simple-wizard//url=blank.html?user=$user,user_id=$user_id,context_id=$context_id&lt;br /&gt;
plugins/upsell/simple-wizard//overlayOpacity=0.5&lt;br /&gt;
plugins/upsell/simple-wizard//overlayColor=black&lt;br /&gt;
plugins/upsell/simple-wizard//zeroPadding=true&lt;br /&gt;
plugins/upsell/simple-wizard//width=750&lt;br /&gt;
plugins/upsell/simple-wizard//height=390&lt;br /&gt;
plugins/upsell/simple-wizard//closeButton=true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
! Settings !! Description&lt;br /&gt;
|-&lt;br /&gt;
| url&lt;br /&gt;
| Custom URL that is loaded in IFRAME; can contain special [[AppSuite:Upsell#Custom_URL_variables|variables]].&lt;br /&gt;
|-&lt;br /&gt;
| overlayOpacity &lt;br /&gt;
| CSS opacity value for overlay; default is 0.5&lt;br /&gt;
|-&lt;br /&gt;
| overlayColor&lt;br /&gt;
| CSS background color for overlay; default is black&lt;br /&gt;
|-&lt;br /&gt;
| zeroPadding&lt;br /&gt;
| If true (default) there is no inner padding inside modal dialog, i.e. the IFRAME covers the popup&lt;br /&gt;
|-&lt;br /&gt;
| width&lt;br /&gt;
| Width of outer popup (not IFRAME) in pixel&lt;br /&gt;
|-&lt;br /&gt;
| height&lt;br /&gt;
| Height of IFRAME in pixel&lt;br /&gt;
|-&lt;br /&gt;
| closeButton&lt;br /&gt;
| If true (default) the wizard shows its own close button&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Custom URL variables===&lt;br /&gt;
The plugin offers a set of variables that help providing context-sensitive content. ''$missing'' is probably the most prominent one. Other variables help identifying the user. An example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-setting&amp;quot;&amp;gt;&lt;br /&gt;
upsell.php?user_id=$user_id&amp;amp;context_id=$context_id&amp;amp;language=$language&amp;amp;missing=$missing&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
! Variable !! Description&lt;br /&gt;
|-&lt;br /&gt;
| $context_id&lt;br /&gt;
| context_id of current user&lt;br /&gt;
|-&lt;br /&gt;
| $hostname&lt;br /&gt;
| hostname of current session, e.g. www.one-of-countless-virtual-hosts.com&lt;br /&gt;
|-&lt;br /&gt;
| $id&lt;br /&gt;
| The trigger's identifier, e.g. &amp;quot;io.ox/files&amp;quot;. Can refer to an app, an inline action, or a portal plugin. See $type&lt;br /&gt;
|-&lt;br /&gt;
| $imap_login&lt;br /&gt;
| The current user's imap login&lt;br /&gt;
|-&lt;br /&gt;
| $language&lt;br /&gt;
| The current user's language, e.g. de_DE or en_US&lt;br /&gt;
|-&lt;br /&gt;
| $mail&lt;br /&gt;
| The current user's primary email address&lt;br /&gt;
|-&lt;br /&gt;
| $missing&lt;br /&gt;
| The set of missing capabilities, comma separated, e.g. &amp;quot;files&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| $session&lt;br /&gt;
| The current user's session id&lt;br /&gt;
|-&lt;br /&gt;
| $type&lt;br /&gt;
| Either app, inline-action, or portal-widget. Describes what triggered the upsell. See $id&lt;br /&gt;
|-&lt;br /&gt;
| $user&lt;br /&gt;
| The current user's login name (can include context name, i.e somebody@foo)&lt;br /&gt;
|-&lt;br /&gt;
| $user_id&lt;br /&gt;
| The current user's numeric id&lt;br /&gt;
|-&lt;br /&gt;
| $user_login&lt;br /&gt;
| The current user's login (usually without context name)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Develop and debug===&lt;br /&gt;
While experimenting or developing, you can use the following helpful functions:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// get plugin (this must be properly loaded, otherwise you get a runtime error)&lt;br /&gt;
var wizard = require('plugins/upsell/simple-wizard/register');&lt;br /&gt;
&lt;br /&gt;
// if you have no chance to enabled this plugin server-side, use the following approach &lt;br /&gt;
   // but don't use this in production plugins, it's just a hack for console: &lt;br /&gt;
   // if you don't know the difference please take a look at &lt;br /&gt;
   // http://requirejs.org/docs/errors.html#notloaded &lt;br /&gt;
var wizard; require(['plugins/upsell/simple-wizard/register'], function (w) { wizard = w; });&lt;br /&gt;
&lt;br /&gt;
// get variables (optional: options from upsell:require-upgrade event)&lt;br /&gt;
wizard.getVariables({ type: 'app', id: 'io.ox/files', missing: 'files' });&lt;br /&gt;
&lt;br /&gt;
// get URL (optional: options from upsell:require-upgrade event)&lt;br /&gt;
   // replaces placeholders ($foo) by variable values&lt;br /&gt;
wizard.getURL({ type: 'app', id: 'io.ox/files', missing: 'files' });&lt;br /&gt;
&lt;br /&gt;
// get all settings (can be changed on the fly)&lt;br /&gt;
console.log(wizard.settings);&lt;br /&gt;
&lt;br /&gt;
// global upsell events; parameters: (e, popup)&lt;br /&gt;
ox.on('upsell:simple-wizard:show:before', _.inspect);&lt;br /&gt;
ox.on('upsell:simple-wizard:show', _.inspect);&lt;br /&gt;
ox.on('upsell:simple-wizard:close', _.inspect);&lt;br /&gt;
&lt;br /&gt;
// special event to customize settings (e, variables, settings)&lt;br /&gt;
   // triggered before creating dialog instance;&lt;br /&gt;
   // 2nd parameter has variables like type, missing, user_id etc.&lt;br /&gt;
   // 3rd parameter refers to a local copy of wizard settings&lt;br /&gt;
ox.on('upsell:simple-wizard:init', _.inspect);&lt;br /&gt;
&lt;br /&gt;
// open wizard manually&lt;br /&gt;
wizard.open();&lt;br /&gt;
&lt;br /&gt;
// close wizard manually&lt;br /&gt;
wizard.close();&lt;br /&gt;
&lt;br /&gt;
// disable wizard (unregisters upsell event)&lt;br /&gt;
wizard.disable();&lt;br /&gt;
&lt;br /&gt;
// and of course: enable wizard (registers for upsell event)&lt;br /&gt;
wizard.enable();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some examples for customizations in UI plugins or in console:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
// get plugin (this muse be properly loaded, otherwise you get a runtime error)&lt;br /&gt;
var wizard = require('plugins/upsell/simple-wizard/register'); &lt;br /&gt;
&lt;br /&gt;
// extend IFRAME constructor (see http://underscorejs.org/#compose)&lt;br /&gt;
var custom = function (iframe) {&lt;br /&gt;
  return iframe.css({ border: '5px solid #08c', boxSizing: 'border-box' });&lt;br /&gt;
};&lt;br /&gt;
wizard.getIFrame = _.compose(custom, wizard.getIFrame);&lt;br /&gt;
&lt;br /&gt;
// use an event to customize the IFRAME&lt;br /&gt;
ox.on('upsell:simple-wizard:show:before', function (e, popup) {&lt;br /&gt;
  popup.getContentNode().find('iframe')&lt;br /&gt;
    .css({ border: '5px solid #08c', boxSizing: 'border-box' });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Close wizard===&lt;br /&gt;
The upsell wizard can easily be closed via javascript or by redirecting the IFRAME to a prepared HTML page. In order to see this in action, run the following code (step by step):&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// get plugin (this must be properly loaded, otherwise you get a runtime error)&lt;br /&gt;
var wizard = require('plugins/upsell/simple-wizard/register');&lt;br /&gt;
&lt;br /&gt;
// open wizard&lt;br /&gt;
wizard.open();&lt;br /&gt;
&lt;br /&gt;
// redirect now&lt;br /&gt;
wizard.setSrc('apps/plugins/upsell/simple-wizard/close.html');&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Custom backend systems that run on a different domain cannot use javascript to close the wizard [http://en.wikipedia.org/wiki/Cross-site_scripting]. However, such systems can redirect to ''close.html''. Since this page is part of the UI and therefore located on the same domain, it is allowed to call the wizard's close function.&lt;br /&gt;
&lt;br /&gt;
==Custom development==&lt;br /&gt;
This section documents some of the inner workings of the upsell layer. It should provide some useful insights and hopefully helps at implementing custom upsell solutions.&lt;br /&gt;
===Events===&lt;br /&gt;
Whenever the user starts an app or clicks on an inline-action, a capability-check is performed. For example, all inline actions have native support for such checks:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
new Action('io.ox/calendar/detail/actions/sendmail', {&lt;br /&gt;
    // this action requires the capability &amp;quot;webmail&amp;quot;&lt;br /&gt;
    capabilities: 'webmail',&lt;br /&gt;
    action: function (baton) {&lt;br /&gt;
        // send mail&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the end-user does not have &amp;quot;webmail&amp;quot; (e.g. in a files-only setup) but calls this action, a proper event is fired:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// if any action misses a capability&lt;br /&gt;
ox.trigger('upsell:requires-upgrade');&lt;br /&gt;
// which provides the following data for apps:&lt;br /&gt;
{&lt;br /&gt;
  type: &amp;quot;app&amp;quot;, // type of the upsell trigger&lt;br /&gt;
  id: &amp;quot;io.ox/mail/main&amp;quot;, // upsell trigger ID&lt;br /&gt;
  missing: &amp;quot;webmail&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// and for inline-actions:&lt;br /&gt;
{&lt;br /&gt;
  type: &amp;quot;inline-action&amp;quot;,&lt;br /&gt;
  id: &amp;quot;io.ox/calendar/detail/actions/sendmail&amp;quot;,&lt;br /&gt;
  missing: &amp;quot;webmail&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Capabilities and Upsell triggers===&lt;br /&gt;
There are lots of different capabilities. They are defined on the server-side and basically they are just strings. Let's keep it simple and understand them as either services (e.g. mobility), specific functionalities (e.g. multiple_mail_accounts) or applications (e.g. calendar). Some obvious examples:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
! Capability !! Description !! Upsell trigger (if capability is missing)&lt;br /&gt;
|-&lt;br /&gt;
| calendar&lt;br /&gt;
| User has &amp;quot;Calendar&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail/All recipients: Invite to appointment&lt;br /&gt;
* Add portal widget&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| contacts &lt;br /&gt;
| User has &amp;quot;Address Book&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail/App recipients: Save as distribution list&lt;br /&gt;
* Calendar: Save participants as distribution list&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| infostore&lt;br /&gt;
| User has &amp;quot;Files&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail: Save in infostore&lt;br /&gt;
* Add portal widget (My latest files, Recently changed files)&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| portal&lt;br /&gt;
| User has &amp;quot;Portal&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail: Add to portal&lt;br /&gt;
* Contacts: Add to portal&lt;br /&gt;
* Files: Add to portal&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| tasks&lt;br /&gt;
| User has &amp;quot;Tasks&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail: Remind me&lt;br /&gt;
* Add portal widget&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| webmail&lt;br /&gt;
| User has &amp;quot;Mail&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Calendar: Send mail to all participants&lt;br /&gt;
* Contacts: Send mail&lt;br /&gt;
* Contacts: Send vCard&lt;br /&gt;
* Files: Send as link&lt;br /&gt;
* Files: Send by mail&lt;br /&gt;
* Add portal widget&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// list all available capabilities&lt;br /&gt;
_(ox.serverConfig.capabilities).pluck('id').sort();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An example: Free-mail users might just have '''webmail''' and '''contacts'''. If '''infostore''' is enabled for upsell, end-users will see the link to store mail attachments. But since this capability is missing, the event &amp;quot;upsell:requires-upgrade&amp;quot; is triggered which starts the upsell process. Upon successful completion this process should unlock the capability '''infostore''' for the end-user.&lt;br /&gt;
&lt;br /&gt;
The advantage of using rather atomic capabilities as the foundation for upsell is that developers don't have to consider and implement sales programs or marketing matrices in UI code.&lt;br /&gt;
&lt;br /&gt;
===Example dialog===&lt;br /&gt;
Whenever the event ''&amp;quot;upsell:requires-upgrade&amp;quot;'' is triggered there should be some response for the end-user. Usually an upsell dialog should open. This can be implemented as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
function showUpgradeDialog(e, options) {&lt;br /&gt;
    require(['io.ox/core/tk/dialogs'], function (dialogs) {&lt;br /&gt;
        new dialogs.ModalDialog({ easyOut: true })&lt;br /&gt;
            .build(function () {&lt;br /&gt;
                this.getHeader().append(&lt;br /&gt;
                    $('&amp;lt;h4&amp;gt;').text('Upgrade required')&lt;br /&gt;
                );&lt;br /&gt;
                this.getContentNode().append(&lt;br /&gt;
                    $.txt('This feature is not available.'),&lt;br /&gt;
                    $.txt('You need to upgrade your account now.'),&lt;br /&gt;
                    $.txt(' '),&lt;br /&gt;
                    $.txt('The first 90 days are free.')&lt;br /&gt;
                );&lt;br /&gt;
                this.addPrimaryButton('upgrade', 'Get free upgrade');&lt;br /&gt;
                this.addButton('cancel', 'Cancel');&lt;br /&gt;
            })&lt;br /&gt;
            .setUnderlayStyle({&lt;br /&gt;
                opacity: 0.70,&lt;br /&gt;
                backgroundColor: '#08C'&lt;br /&gt;
            })&lt;br /&gt;
            .on('upgrade', function () {&lt;br /&gt;
                ox.trigger('upsell:upgrade', options);&lt;br /&gt;
            })&lt;br /&gt;
            .on('show', function () {&lt;br /&gt;
                ox.off('upsell:requires-upgrade', showUpgradeDialog);&lt;br /&gt;
            })&lt;br /&gt;
            .on('close', function () {&lt;br /&gt;
                ox.on('upsell:requires-upgrade', showUpgradeDialog);&lt;br /&gt;
            })&lt;br /&gt;
            .show();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function upgrade(e, options) {&lt;br /&gt;
    console.debug('upgrade', options);&lt;br /&gt;
    alert('User decided to upgrade! (global event: upsell:upgrade)');&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ox.on('upsell:requires-upgrade', showUpgradeDialog);&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * convention: 'upsell:upgrade' is used to trigger final upsell&lt;br /&gt;
 * the current user and user_id can be found in global variables ox.user and ox.user_id&lt;br /&gt;
 */&lt;br /&gt;
ox.on('upsell:upgrade', upgrade);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The second event '''&amp;quot;upsell:upgrade&amp;quot;''' can be understood as the final imperative to request the upsell server-side.&lt;br /&gt;
&lt;br /&gt;
===Example portal widget===&lt;br /&gt;
Besides waiting for the user to click on such links, it's always a good idea to offer explicit controls to trigger an upsell. One option is creating a portal widget that advertises a premium subscription:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
/**&lt;br /&gt;
 * This work is provided under the terms of the CREATIVE COMMONS PUBLIC&lt;br /&gt;
 * LICENSE. This work is protected by copyright and/or other applicable&lt;br /&gt;
 * law. Any use of the work other than as authorized under this license&lt;br /&gt;
 * or copyright law is prohibited.&lt;br /&gt;
 *&lt;br /&gt;
 * http://creativecommons.org/licenses/by-nc-sa/2.5/&lt;br /&gt;
 * © 2013 Open-Xchange Inc., Tarrytown, NY, USA. info@open-xchange.com&lt;br /&gt;
 *&lt;br /&gt;
 * @author Matthias Biggeleben &amp;lt;matthias.biggeleben@open-xchange.com&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
define('plugins/portal/upsell/register',&lt;br /&gt;
    ['io.ox/core/extensions',&lt;br /&gt;
     'io.ox/files/api',&lt;br /&gt;
     'gettext!plugins/portal'], function (ext, api, gt) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var title = gt('Upgrade to premium');&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget/upsell').extend({&lt;br /&gt;
&lt;br /&gt;
        title: title,&lt;br /&gt;
&lt;br /&gt;
        preview: function (baton) {&lt;br /&gt;
&lt;br /&gt;
            this.addClass('hide-title').append(&lt;br /&gt;
                $('&amp;amp;lt;div class=&amp;quot;content centered&amp;quot; style=&amp;quot;cursor: pointer; padding-top: 3em;&amp;quot;&amp;gt;').append(&lt;br /&gt;
                    $('&amp;amp;lt;h2&amp;gt;').append(&lt;br /&gt;
                        $.txt(title + ' '),&lt;br /&gt;
                        $('&amp;amp;lt;i class=&amp;quot;icon-star&amp;quot;&amp;gt;')&lt;br /&gt;
                    ),&lt;br /&gt;
                    $('&amp;amp;lt;div&amp;gt;').text(gt('Click here for free trial.'))&lt;br /&gt;
                )&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    ox.trigger('upsell:upgrade', {&lt;br /&gt;
                        type: 'widget',&lt;br /&gt;
                        id: 'io.ox/portal/widget/upsell',&lt;br /&gt;
                        missing: ''&lt;br /&gt;
                    });&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Accessing upsell settings===&lt;br /&gt;
The upsell configuration is located in the namespace ''&amp;quot;io.ox/core&amp;quot;'', the path is ''&amp;quot;upsell/enabled&amp;quot;''. Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// get all capabilities that can trigger upsell&lt;br /&gt;
require('settings!io.ox/core').get('upsell/enabled');&lt;br /&gt;
&lt;br /&gt;
// contains data like this&lt;br /&gt;
{&lt;br /&gt;
  infostore: true,&lt;br /&gt;
  portal: true,&lt;br /&gt;
  tasks: true&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If upsell is '''not''' enabled and the end-user lacks specific capabilities, the app or the inline-action is not shown. If upsell is enabled by the upper configuration, inline-actions are shown and trigger the upsell event ''&amp;quot;upsell:requires-upgrade&amp;quot;'' if clicked (but do not execute the action itself).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
/* &lt;br /&gt;
 * if you want to create your own controls, you can use the following helpers &lt;br /&gt;
 */&lt;br /&gt;
var upsell = require('io.ox/core/upsell');&lt;br /&gt;
&lt;br /&gt;
// check capabilities (space-separated) &lt;br /&gt;
upsell.has('portal webmail');&lt;br /&gt;
&lt;br /&gt;
// get missing capabilities (would return &amp;quot;calendar&amp;quot; in demo mode) &lt;br /&gt;
upsell.missing(['portal webmail', 'contacts', 'calendar']);&lt;br /&gt;
&lt;br /&gt;
/* checks if upsell is enabled for a set of capabilities &lt;br /&gt;
 * true if at least one set matches &lt;br /&gt;
 */&lt;br /&gt;
upsell.enabled(['portal webmail', 'webmail calendar']);&lt;br /&gt;
&lt;br /&gt;
/* convenience function: &amp;quot;visible&amp;quot; &lt;br /&gt;
 * checks if something should be visible depending on required capabilities &lt;br /&gt;
 * true if any item matches requires capabilities &lt;br /&gt;
 * true if any item does not match its requirements but is enabled for upsell &lt;br /&gt;
 * this function is used for any inline link, for example, to decide whether or not showing it &lt;br /&gt;
 */&lt;br /&gt;
upsell.visible(['portal webmail', 'contacts', 'calendar']);&lt;br /&gt;
&lt;br /&gt;
// likewise if neither capability set nor enabled for upsell, we get a false &lt;br /&gt;
upsell.visible(['foo']);&lt;br /&gt;
&lt;br /&gt;
// in case something weird happens (usually bad configuration) debug() helps&lt;br /&gt;
upsell.debug();&lt;br /&gt;
&lt;br /&gt;
// and this one&lt;br /&gt;
_(ox.serverConfig.capabilities).pluck('id').sort();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Upsell in OX6==&lt;br /&gt;
Please also consider [[Upsell|this article]] as it also covers backend aspects.&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Upsell&amp;diff=14989</id>
		<title>AppSuite:Upsell</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Upsell&amp;diff=14989"/>
		<updated>2013-07-14T19:31:38Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Events */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stability-unstable}} &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Upsell&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract.''' This article is mainly for UI developers and introduces the concept of upsell from a technical point of view. In short: End-user has a set of so-called ''capabilities''. UI, however, offers functionality beyond that limited set for promotion purposes. Actions, e.g. inline links, that require missing capabilities trigger an '''in-app upsell'''. This process leads to a trial period or a new subscription. Technical challenge for the UI developer is to check what the end-user has, what can be shown beyond that, and how to handle upsell. It is also possible for hosting companies to easily integrate their own online shop into OX Upsell, since the internal mechanisms are ''loosely coupled'' via events.&lt;br /&gt;
__TOC__&lt;br /&gt;
==Enable upsell==&lt;br /&gt;
In order to configure upsell server-side, just create a new file '''upsell.properties''' or append to existing '''appsuite.properties''' (mind the '''double-slash'''; this in not a typo! plus: changing such settings requires a backend restart):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
io.ox/core//upsell/enabled/infostore=true&lt;br /&gt;
io.ox/core//upsell/enabled/portal=true&lt;br /&gt;
io.ox/core//upsell/enabled/tasks=true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Each line enables a specific [[AppSuite:Upsell#Capabilities|capability]] for upsell. That means whenever a feature misses one these capabilities a special upsell-related event is triggered.&lt;br /&gt;
&lt;br /&gt;
Hint: For simple demo purposes, you can enable an internal upsell configuration by appending '''&amp;quot;&amp;amp;demo=upsell&amp;quot;''' to the URL. Needs to reload page, of course.&lt;br /&gt;
&lt;br /&gt;
==Upsell Wizard==&lt;br /&gt;
&amp;lt;div style=&amp;quot;color: #3A87AD; text-align: right; margin: -1em 0 1em 0; padding: 0.5em; background-color: #D9EDF7;&amp;quot;&amp;gt;Shipped with 7.2.1&amp;lt;/div&amp;gt;&lt;br /&gt;
Hosters usually want to offer context-sensitive content in an IFRAME if the upsell is triggered. Therefore, App Suite comes with an integrated but optional plugin that takes care of this. Just [[AppSuite:UI_manifests_explained#Loading_custom_manifest_during_development|enable]] ''plugins/upsell/simple-wizard''. This plugin registers for the event ''&amp;quot;upsell:requires-upsell&amp;quot;'', opens a modal popup, and loads a custom URL in an embedded IFRAME.&lt;br /&gt;
&lt;br /&gt;
[[File:Simple_upsell_wizard.png|800 px|Custom content in an IFRAME]]&lt;br /&gt;
&lt;br /&gt;
===Wizard settings===&lt;br /&gt;
In order to configure this server-side, just create a new file '''upsell.properties''' or append to existing '''appsuite.properties''' (mind the '''double-slash'''; this in not a typo! plus: changing such settings requires a backend restart):&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt;&lt;br /&gt;
plugins/upsell/simple-wizard//url=blank.html?user=$user,user_id=$user_id,context_id=$context_id&lt;br /&gt;
plugins/upsell/simple-wizard//overlayOpacity=0.5&lt;br /&gt;
plugins/upsell/simple-wizard//overlayColor=black&lt;br /&gt;
plugins/upsell/simple-wizard//zeroPadding=true&lt;br /&gt;
plugins/upsell/simple-wizard//width=750&lt;br /&gt;
plugins/upsell/simple-wizard//height=390&lt;br /&gt;
plugins/upsell/simple-wizard//closeButton=true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
! Settings !! Description&lt;br /&gt;
|-&lt;br /&gt;
| url&lt;br /&gt;
| Custom URL that is loaded in IFRAME; can contain special [[AppSuite:Upsell#Custom_URL_variables|variables]].&lt;br /&gt;
|-&lt;br /&gt;
| overlayOpacity &lt;br /&gt;
| CSS opacity value for overlay; default is 0.5&lt;br /&gt;
|-&lt;br /&gt;
| overlayColor&lt;br /&gt;
| CSS background color for overlay; default is black&lt;br /&gt;
|-&lt;br /&gt;
| zeroPadding&lt;br /&gt;
| If true (default) there is no inner padding inside modal dialog, i.e. the IFRAME covers the popup&lt;br /&gt;
|-&lt;br /&gt;
| width&lt;br /&gt;
| Width of outer popup (not IFRAME) in pixel&lt;br /&gt;
|-&lt;br /&gt;
| height&lt;br /&gt;
| Height of IFRAME in pixel&lt;br /&gt;
|-&lt;br /&gt;
| closeButton&lt;br /&gt;
| If true (default) the wizard shows its own close button&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Custom URL variables===&lt;br /&gt;
The plugin offers a set of variables that help providing context-sensitive content. ''$missing'' is probably the most prominent one. Other variables help identifying the user. An example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-setting&amp;quot;&amp;gt;&lt;br /&gt;
upsell.php?user_id=$user_id&amp;amp;context_id=$context_id&amp;amp;language=$language&amp;amp;missing=$missing&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
! Variable !! Description&lt;br /&gt;
|-&lt;br /&gt;
| $context_id&lt;br /&gt;
| context_id of current user&lt;br /&gt;
|-&lt;br /&gt;
| $hostname&lt;br /&gt;
| hostname of current session, e.g. www.one-of-countless-virtual-hosts.com&lt;br /&gt;
|-&lt;br /&gt;
| $id&lt;br /&gt;
| The trigger's identifier, e.g. &amp;quot;io.ox/files&amp;quot;. Can refer to an app, an inline action, or a portal plugin. See $type&lt;br /&gt;
|-&lt;br /&gt;
| $imap_login&lt;br /&gt;
| The current user's imap login&lt;br /&gt;
|-&lt;br /&gt;
| $language&lt;br /&gt;
| The current user's language, e.g. de_DE or en_US&lt;br /&gt;
|-&lt;br /&gt;
| $mail&lt;br /&gt;
| The current user's primary email address&lt;br /&gt;
|-&lt;br /&gt;
| $missing&lt;br /&gt;
| The set of missing capabilities, comma separated, e.g. &amp;quot;files&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| $session&lt;br /&gt;
| The current user's session id&lt;br /&gt;
|-&lt;br /&gt;
| $type&lt;br /&gt;
| Either app, inline-action, or portal-widget. Describes what triggered the upsell. See $id&lt;br /&gt;
|-&lt;br /&gt;
| $user&lt;br /&gt;
| The current user's login name (can include context name, i.e somebody@foo)&lt;br /&gt;
|-&lt;br /&gt;
| $user_id&lt;br /&gt;
| The current user's numeric id&lt;br /&gt;
|-&lt;br /&gt;
| $user_login&lt;br /&gt;
| The current user's login (usually without context name)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Develop and debug===&lt;br /&gt;
While experimenting or developing, you can use the following helpful functions:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// get plugin (this must be properly loaded, otherwise you get a runtime error)&lt;br /&gt;
var wizard = require('plugins/upsell/simple-wizard/register');&lt;br /&gt;
&lt;br /&gt;
// if you have no chance to enabled this plugin server-side, use the following approach &lt;br /&gt;
   // but don't use this in production plugins, it's just a hack for console: &lt;br /&gt;
   // if you don't know the difference please take a look at &lt;br /&gt;
   // http://requirejs.org/docs/errors.html#notloaded &lt;br /&gt;
var wizard; require(['plugins/upsell/simple-wizard/register'], function (w) { wizard = w; });&lt;br /&gt;
&lt;br /&gt;
// get variables (optional: options from upsell:require-upgrade event)&lt;br /&gt;
wizard.getVariables({ type: 'app', id: 'io.ox/files', missing: 'files' });&lt;br /&gt;
&lt;br /&gt;
// get URL (optional: options from upsell:require-upgrade event)&lt;br /&gt;
   // replaces placeholders ($foo) by variable values&lt;br /&gt;
wizard.getURL({ type: 'app', id: 'io.ox/files', missing: 'files' });&lt;br /&gt;
&lt;br /&gt;
// get all settings (can be changed on the fly)&lt;br /&gt;
console.log(wizard.settings);&lt;br /&gt;
&lt;br /&gt;
// global upsell events; parameters: (e, popup)&lt;br /&gt;
ox.on('upsell:simple-wizard:show:before', _.inspect);&lt;br /&gt;
ox.on('upsell:simple-wizard:show', _.inspect);&lt;br /&gt;
ox.on('upsell:simple-wizard:close', _.inspect);&lt;br /&gt;
&lt;br /&gt;
// special event to customize settings (e, variables, settings)&lt;br /&gt;
   // triggered before creating dialog instance;&lt;br /&gt;
   // 2nd parameter has variables like type, missing, user_id etc.&lt;br /&gt;
   // 3rd parameter refers to a local copy of wizard settings&lt;br /&gt;
ox.on('upsell:simple-wizard:init', _.inspect);&lt;br /&gt;
&lt;br /&gt;
// open wizard manually&lt;br /&gt;
wizard.open();&lt;br /&gt;
&lt;br /&gt;
// close wizard manually&lt;br /&gt;
wizard.close();&lt;br /&gt;
&lt;br /&gt;
// disable wizard (unregisters upsell event)&lt;br /&gt;
wizard.disable();&lt;br /&gt;
&lt;br /&gt;
// and of course: enable wizard (registers for upsell event)&lt;br /&gt;
wizard.enable();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some examples for customizations in UI plugins or in console:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
// get plugin (this muse be properly loaded, otherwise you get a runtime error)&lt;br /&gt;
var wizard = require('plugins/upsell/simple-wizard/register'); &lt;br /&gt;
&lt;br /&gt;
// extend IFRAME constructor (see http://underscorejs.org/#compose)&lt;br /&gt;
var custom = function (iframe) {&lt;br /&gt;
  return iframe.css({ border: '5px solid #08c', boxSizing: 'border-box' });&lt;br /&gt;
};&lt;br /&gt;
wizard.getIFrame = _.compose(custom, wizard.getIFrame);&lt;br /&gt;
&lt;br /&gt;
// use an event to customize the IFRAME&lt;br /&gt;
ox.on('upsell:simple-wizard:show:before', function (e, popup) {&lt;br /&gt;
  popup.getContentNode().find('iframe')&lt;br /&gt;
    .css({ border: '5px solid #08c', boxSizing: 'border-box' });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Close wizard===&lt;br /&gt;
The upsell wizard can easily be closed via javascript or by redirecting the IFRAME to a prepared HTML page. In order to see this in action, run the following code (step by step):&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// get plugin (this must be properly loaded, otherwise you get a runtime error)&lt;br /&gt;
var wizard = require('plugins/upsell/simple-wizard/register');&lt;br /&gt;
&lt;br /&gt;
// open wizard&lt;br /&gt;
wizard.open();&lt;br /&gt;
&lt;br /&gt;
// redirect now&lt;br /&gt;
wizard.setSrc('apps/plugins/upsell/simple-wizard/close.html');&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Custom backend systems that run on a different domain cannot use javascript to close the wizard [http://en.wikipedia.org/wiki/Cross-site_scripting]. However, such systems can redirect to ''close.html''. Since this page is part of the UI and therefore located on the same domain, it is allowed to call the wizard's close function.&lt;br /&gt;
&lt;br /&gt;
==Custom development==&lt;br /&gt;
This section documents some of the inner workings of the upsell layer. It should provide some useful insights and hopefully helps at implementing custom upsell solutions.&lt;br /&gt;
===Events===&lt;br /&gt;
Whenever the user starts an app or clicks on an inline-action, a capability-check is performed. For example, all inline actions have native support for such checks:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
new Action('io.ox/calendar/detail/actions/sendmail', {&lt;br /&gt;
    // this action requires the capability &amp;quot;webmail&amp;quot;&lt;br /&gt;
    capabilities: 'webmail',&lt;br /&gt;
    action: function (baton) {&lt;br /&gt;
        // send mail&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the end-user does not have &amp;quot;webmail&amp;quot; (e.g. in a files-only setup) but calls this action, a proper event is fired:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// if any action misses a capability&lt;br /&gt;
ox.trigger('upsell:requires-upgrade');&lt;br /&gt;
// which provides the following data for apps:&lt;br /&gt;
{&lt;br /&gt;
  type: &amp;quot;app&amp;quot;, // type of the upsell trigger&lt;br /&gt;
  id: &amp;quot;io.ox/mail/main&amp;quot;, // upsell trigger ID&lt;br /&gt;
  missing: &amp;quot;webmail&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// and for inline-actions:&lt;br /&gt;
{&lt;br /&gt;
  type: &amp;quot;inline-action&amp;quot;,&lt;br /&gt;
  id: &amp;quot;io.ox/calendar/detail/actions/sendmail&amp;quot;,&lt;br /&gt;
  missing: &amp;quot;webmail&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Capabilities and Upsell triggers===&lt;br /&gt;
There are lots of different capabilities. They are defined on the server-side and basically they are just strings. Let's keep it simple and understand them as either services (e.g. mobility), specific functionalities (e.g. multiple_mail_accounts) or applications (e.g. calendar). Some obvious examples:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
! Capability !! Description !! Upsell trigger (if capability is missing)&lt;br /&gt;
|-&lt;br /&gt;
| calendar&lt;br /&gt;
| User has &amp;quot;Calendar&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail/All recipients: Invite to appointment&lt;br /&gt;
* Add portal widget&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| contacts &lt;br /&gt;
| User has &amp;quot;Address Book&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail/App recipients: Save as distribution list&lt;br /&gt;
* Calendar: Save participants as distribution list&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| infostore&lt;br /&gt;
| User has &amp;quot;Files&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail: Save in infostore&lt;br /&gt;
* Add portal widget (My latest files, Recently changed files)&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| portal&lt;br /&gt;
| User has &amp;quot;Portal&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail: Add to portal&lt;br /&gt;
* Contacts: Add to portal&lt;br /&gt;
* Files: Add to portal&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| tasks&lt;br /&gt;
| User has &amp;quot;Tasks&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail: Remind me&lt;br /&gt;
* Add portal widget&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| webmail&lt;br /&gt;
| User has &amp;quot;Mail&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Calendar: Send mail to all participants&lt;br /&gt;
* Contacts: Send mail&lt;br /&gt;
* Contacts: Send vCard&lt;br /&gt;
* Files: Send as link&lt;br /&gt;
* Files: Send by mail&lt;br /&gt;
* Add portal widget&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// list all available capabilities&lt;br /&gt;
_(ox.serverConfig.capabilities).pluck('id').sort();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An example: Free-mail users might just have '''webmail''' and '''contacts'''. If '''infostore''' is enabled for upsell, end-users will see the link to store mail attachments. But since this capability is missing, the event &amp;quot;upsell:requires-upgrade&amp;quot; is triggered which starts the upsell process. Upon successful completion this process should unlock the capability '''infostore''' for the end-user.&lt;br /&gt;
&lt;br /&gt;
The advantage of using rather atomic capabilities as the foundation for upsell is that developers don't have to consider and implement sales programs or marketing matrices in UI code.&lt;br /&gt;
&lt;br /&gt;
===Example dialog===&lt;br /&gt;
Whenever the event ''&amp;quot;upsell:requires-upgrade&amp;quot;'' is triggered there should be some response for the end-user. Usually an upsell dialog should open. This can be implemented as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
function showUpgradeDialog(e, options) {&lt;br /&gt;
    require(['io.ox/core/tk/dialogs'], function (dialogs) {&lt;br /&gt;
        new dialogs.ModalDialog({ easyOut: true })&lt;br /&gt;
            .build(function () {&lt;br /&gt;
                this.getHeader().append(&lt;br /&gt;
                    $('&amp;lt;h4&amp;gt;').text('Upgrade required')&lt;br /&gt;
                );&lt;br /&gt;
                this.getContentNode().append(&lt;br /&gt;
                    $.txt('This feature is not available.'),&lt;br /&gt;
                    $.txt('You need to upgrade your account now.'),&lt;br /&gt;
                    $.txt(' '),&lt;br /&gt;
                    $.txt('The first 90 days are free.')&lt;br /&gt;
                );&lt;br /&gt;
                this.addPrimaryButton('upgrade', 'Get free upgrade');&lt;br /&gt;
                this.addButton('cancel', 'Cancel');&lt;br /&gt;
            })&lt;br /&gt;
            .setUnderlayStyle({&lt;br /&gt;
                opacity: 0.70,&lt;br /&gt;
                backgroundColor: '#08C'&lt;br /&gt;
            })&lt;br /&gt;
            .on('upgrade', function () {&lt;br /&gt;
                ox.trigger('upsell:upgrade', options);&lt;br /&gt;
            })&lt;br /&gt;
            .on('show', function () {&lt;br /&gt;
                ox.off('upsell:requires-upgrade', showUpgradeDialog);&lt;br /&gt;
            })&lt;br /&gt;
            .on('close', function () {&lt;br /&gt;
                ox.on('upsell:requires-upgrade', showUpgradeDialog);&lt;br /&gt;
            })&lt;br /&gt;
            .show();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function upgrade(e, options) {&lt;br /&gt;
    console.debug('upgrade', options);&lt;br /&gt;
    alert('User decided to upgrade! (global event: upsell:upgrade)');&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ox.on('upsell:requires-upgrade', showUpgradeDialog);&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * convention: 'upsell:upgrade' is used to trigger final upsell&lt;br /&gt;
 * the current user and user_id can be found in global variables ox.user and ox.user_id&lt;br /&gt;
 */&lt;br /&gt;
ox.on('upsell:upgrade', upgrade);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The second event '''&amp;quot;upsell:upgrade&amp;quot;''' can be understood as the final imperative to request the upsell server-side.&lt;br /&gt;
&lt;br /&gt;
===Example portal widget===&lt;br /&gt;
Besides waiting for the user to click on such links, it's always a good idea to offer explicit controls to trigger an upsell. One option is creating a portal widget that advertises a premium subscription:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
/**&lt;br /&gt;
 * This work is provided under the terms of the CREATIVE COMMONS PUBLIC&lt;br /&gt;
 * LICENSE. This work is protected by copyright and/or other applicable&lt;br /&gt;
 * law. Any use of the work other than as authorized under this license&lt;br /&gt;
 * or copyright law is prohibited.&lt;br /&gt;
 *&lt;br /&gt;
 * http://creativecommons.org/licenses/by-nc-sa/2.5/&lt;br /&gt;
 * © 2013 Open-Xchange Inc., Tarrytown, NY, USA. info@open-xchange.com&lt;br /&gt;
 *&lt;br /&gt;
 * @author Matthias Biggeleben &amp;lt;matthias.biggeleben@open-xchange.com&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
define('plugins/portal/upsell/register',&lt;br /&gt;
    ['io.ox/core/extensions',&lt;br /&gt;
     'io.ox/files/api',&lt;br /&gt;
     'gettext!plugins/portal'], function (ext, api, gt) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var title = gt('Upgrade to premium');&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget/upsell').extend({&lt;br /&gt;
&lt;br /&gt;
        title: title,&lt;br /&gt;
&lt;br /&gt;
        preview: function (baton) {&lt;br /&gt;
&lt;br /&gt;
            this.addClass('hide-title').append(&lt;br /&gt;
                $('&amp;amp;lt;div class=&amp;quot;content centered&amp;quot; style=&amp;quot;cursor: pointer; padding-top: 3em;&amp;quot;&amp;gt;').append(&lt;br /&gt;
                    $('&amp;amp;lt;h2&amp;gt;').append(&lt;br /&gt;
                        $.txt(title + ' '),&lt;br /&gt;
                        $('&amp;amp;lt;i class=&amp;quot;icon-star&amp;quot;&amp;gt;')&lt;br /&gt;
                    ),&lt;br /&gt;
                    $('&amp;amp;lt;div&amp;gt;').text(gt('Click here for free trial.'))&lt;br /&gt;
                )&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    ox.trigger('upsell:upgrade', {&lt;br /&gt;
                        type: 'widget',&lt;br /&gt;
                        id: 'io.ox/portal/widget/upsell',&lt;br /&gt;
                        missing: ''&lt;br /&gt;
                    });&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Accessing upsell settings===&lt;br /&gt;
The upsell configuration is located in the namespace ''&amp;quot;io.ox/core&amp;quot;'', the path is ''&amp;quot;upsell/enabled&amp;quot;''. Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// get all capabilities that can trigger upsell&lt;br /&gt;
require('settings!io.ox/core').get('upsell/enabled');&lt;br /&gt;
&lt;br /&gt;
// contains data like this&lt;br /&gt;
{&lt;br /&gt;
  infostore: true,&lt;br /&gt;
  portal: true,&lt;br /&gt;
  tasks: true&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If upsell is '''not''' enabled and the end-user lacks specific capabilities, the app or the inline-action is not shown. If upsell is enabled by the upper configuration, inline-actions are shown and trigger the upsell event ''&amp;quot;upsell:requires-upgrade&amp;quot;'' if clicked (but do not execute the action itself).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
/* &lt;br /&gt;
 * if you want to create your own controls, you can use the following helpers &lt;br /&gt;
 */&lt;br /&gt;
var upsell = require('io.ox/core/upsell');&lt;br /&gt;
&lt;br /&gt;
// check capabilities (space-separated) &lt;br /&gt;
upsell.has('portal webmail');&lt;br /&gt;
&lt;br /&gt;
// get missing capabilities (would return &amp;quot;calendar&amp;quot; in demo mode) &lt;br /&gt;
upsell.missing(['portal webmail', 'contacts', 'calendar']);&lt;br /&gt;
&lt;br /&gt;
/* checks if upsell is enabled for a set of capabilities &lt;br /&gt;
 * true if at least one set matches &lt;br /&gt;
 */&lt;br /&gt;
upsell.enabled(['portal webmail', 'webmail calendar']);&lt;br /&gt;
&lt;br /&gt;
/* convenience function: &amp;quot;visible&amp;quot; &lt;br /&gt;
 * checks if something should be visible depending on required capabilities &lt;br /&gt;
 * true if any item matches requires capabilities &lt;br /&gt;
 * true if any item does not match its requirements but is enabled for upsell &lt;br /&gt;
 * this function is used for any inline link, for example, to decide whether or not showing it &lt;br /&gt;
 */&lt;br /&gt;
upsell.visible(['portal webmail', 'contacts', 'calendar']);&lt;br /&gt;
&lt;br /&gt;
// likewise if neither capability set nor enabled for upsell, we get a false &lt;br /&gt;
upsell.visible(['foo']);&lt;br /&gt;
&lt;br /&gt;
// in case something weird happens (usually bad configuration) debug() helps&lt;br /&gt;
upsell.debug();&lt;br /&gt;
&lt;br /&gt;
// and this one&lt;br /&gt;
_(ox.serverConfig.capabilities).pluck('id').sort();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Upsell in OX6==&lt;br /&gt;
Please also consider [[Upsell|this article]] as it also covers backend aspects.&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Upsell&amp;diff=14988</id>
		<title>AppSuite:Upsell</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Upsell&amp;diff=14988"/>
		<updated>2013-07-14T19:29:28Z</updated>

		<summary type="html">&lt;p&gt;Mattes: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stability-unstable}} &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Upsell&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract.''' This article is mainly for UI developers and introduces the concept of upsell from a technical point of view. In short: End-user has a set of so-called ''capabilities''. UI, however, offers functionality beyond that limited set for promotion purposes. Actions, e.g. inline links, that require missing capabilities trigger an '''in-app upsell'''. This process leads to a trial period or a new subscription. Technical challenge for the UI developer is to check what the end-user has, what can be shown beyond that, and how to handle upsell. It is also possible for hosting companies to easily integrate their own online shop into OX Upsell, since the internal mechanisms are ''loosely coupled'' via events.&lt;br /&gt;
__TOC__&lt;br /&gt;
==Enable upsell==&lt;br /&gt;
In order to configure upsell server-side, just create a new file '''upsell.properties''' or append to existing '''appsuite.properties''' (mind the '''double-slash'''; this in not a typo! plus: changing such settings requires a backend restart):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
io.ox/core//upsell/enabled/infostore=true&lt;br /&gt;
io.ox/core//upsell/enabled/portal=true&lt;br /&gt;
io.ox/core//upsell/enabled/tasks=true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Each line enables a specific [[AppSuite:Upsell#Capabilities|capability]] for upsell. That means whenever a feature misses one these capabilities a special upsell-related event is triggered.&lt;br /&gt;
&lt;br /&gt;
Hint: For simple demo purposes, you can enable an internal upsell configuration by appending '''&amp;quot;&amp;amp;demo=upsell&amp;quot;''' to the URL. Needs to reload page, of course.&lt;br /&gt;
&lt;br /&gt;
==Upsell Wizard==&lt;br /&gt;
&amp;lt;div style=&amp;quot;color: #3A87AD; text-align: right; margin: -1em 0 1em 0; padding: 0.5em; background-color: #D9EDF7;&amp;quot;&amp;gt;Shipped with 7.2.1&amp;lt;/div&amp;gt;&lt;br /&gt;
Hosters usually want to offer context-sensitive content in an IFRAME if the upsell is triggered. Therefore, App Suite comes with an integrated but optional plugin that takes care of this. Just [[AppSuite:UI_manifests_explained#Loading_custom_manifest_during_development|enable]] ''plugins/upsell/simple-wizard''. This plugin registers for the event ''&amp;quot;upsell:requires-upsell&amp;quot;'', opens a modal popup, and loads a custom URL in an embedded IFRAME.&lt;br /&gt;
&lt;br /&gt;
[[File:Simple_upsell_wizard.png|800 px|Custom content in an IFRAME]]&lt;br /&gt;
&lt;br /&gt;
===Wizard settings===&lt;br /&gt;
In order to configure this server-side, just create a new file '''upsell.properties''' or append to existing '''appsuite.properties''' (mind the '''double-slash'''; this in not a typo! plus: changing such settings requires a backend restart):&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt;&lt;br /&gt;
plugins/upsell/simple-wizard//url=blank.html?user=$user,user_id=$user_id,context_id=$context_id&lt;br /&gt;
plugins/upsell/simple-wizard//overlayOpacity=0.5&lt;br /&gt;
plugins/upsell/simple-wizard//overlayColor=black&lt;br /&gt;
plugins/upsell/simple-wizard//zeroPadding=true&lt;br /&gt;
plugins/upsell/simple-wizard//width=750&lt;br /&gt;
plugins/upsell/simple-wizard//height=390&lt;br /&gt;
plugins/upsell/simple-wizard//closeButton=true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
! Settings !! Description&lt;br /&gt;
|-&lt;br /&gt;
| url&lt;br /&gt;
| Custom URL that is loaded in IFRAME; can contain special [[AppSuite:Upsell#Custom_URL_variables|variables]].&lt;br /&gt;
|-&lt;br /&gt;
| overlayOpacity &lt;br /&gt;
| CSS opacity value for overlay; default is 0.5&lt;br /&gt;
|-&lt;br /&gt;
| overlayColor&lt;br /&gt;
| CSS background color for overlay; default is black&lt;br /&gt;
|-&lt;br /&gt;
| zeroPadding&lt;br /&gt;
| If true (default) there is no inner padding inside modal dialog, i.e. the IFRAME covers the popup&lt;br /&gt;
|-&lt;br /&gt;
| width&lt;br /&gt;
| Width of outer popup (not IFRAME) in pixel&lt;br /&gt;
|-&lt;br /&gt;
| height&lt;br /&gt;
| Height of IFRAME in pixel&lt;br /&gt;
|-&lt;br /&gt;
| closeButton&lt;br /&gt;
| If true (default) the wizard shows its own close button&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Custom URL variables===&lt;br /&gt;
The plugin offers a set of variables that help providing context-sensitive content. ''$missing'' is probably the most prominent one. Other variables help identifying the user. An example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-setting&amp;quot;&amp;gt;&lt;br /&gt;
upsell.php?user_id=$user_id&amp;amp;context_id=$context_id&amp;amp;language=$language&amp;amp;missing=$missing&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
! Variable !! Description&lt;br /&gt;
|-&lt;br /&gt;
| $context_id&lt;br /&gt;
| context_id of current user&lt;br /&gt;
|-&lt;br /&gt;
| $hostname&lt;br /&gt;
| hostname of current session, e.g. www.one-of-countless-virtual-hosts.com&lt;br /&gt;
|-&lt;br /&gt;
| $id&lt;br /&gt;
| The trigger's identifier, e.g. &amp;quot;io.ox/files&amp;quot;. Can refer to an app, an inline action, or a portal plugin. See $type&lt;br /&gt;
|-&lt;br /&gt;
| $imap_login&lt;br /&gt;
| The current user's imap login&lt;br /&gt;
|-&lt;br /&gt;
| $language&lt;br /&gt;
| The current user's language, e.g. de_DE or en_US&lt;br /&gt;
|-&lt;br /&gt;
| $mail&lt;br /&gt;
| The current user's primary email address&lt;br /&gt;
|-&lt;br /&gt;
| $missing&lt;br /&gt;
| The set of missing capabilities, comma separated, e.g. &amp;quot;files&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| $session&lt;br /&gt;
| The current user's session id&lt;br /&gt;
|-&lt;br /&gt;
| $type&lt;br /&gt;
| Either app, inline-action, or portal-widget. Describes what triggered the upsell. See $id&lt;br /&gt;
|-&lt;br /&gt;
| $user&lt;br /&gt;
| The current user's login name (can include context name, i.e somebody@foo)&lt;br /&gt;
|-&lt;br /&gt;
| $user_id&lt;br /&gt;
| The current user's numeric id&lt;br /&gt;
|-&lt;br /&gt;
| $user_login&lt;br /&gt;
| The current user's login (usually without context name)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Develop and debug===&lt;br /&gt;
While experimenting or developing, you can use the following helpful functions:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// get plugin (this must be properly loaded, otherwise you get a runtime error)&lt;br /&gt;
var wizard = require('plugins/upsell/simple-wizard/register');&lt;br /&gt;
&lt;br /&gt;
// if you have no chance to enabled this plugin server-side, use the following approach &lt;br /&gt;
   // but don't use this in production plugins, it's just a hack for console: &lt;br /&gt;
   // if you don't know the difference please take a look at &lt;br /&gt;
   // http://requirejs.org/docs/errors.html#notloaded &lt;br /&gt;
var wizard; require(['plugins/upsell/simple-wizard/register'], function (w) { wizard = w; });&lt;br /&gt;
&lt;br /&gt;
// get variables (optional: options from upsell:require-upgrade event)&lt;br /&gt;
wizard.getVariables({ type: 'app', id: 'io.ox/files', missing: 'files' });&lt;br /&gt;
&lt;br /&gt;
// get URL (optional: options from upsell:require-upgrade event)&lt;br /&gt;
   // replaces placeholders ($foo) by variable values&lt;br /&gt;
wizard.getURL({ type: 'app', id: 'io.ox/files', missing: 'files' });&lt;br /&gt;
&lt;br /&gt;
// get all settings (can be changed on the fly)&lt;br /&gt;
console.log(wizard.settings);&lt;br /&gt;
&lt;br /&gt;
// global upsell events; parameters: (e, popup)&lt;br /&gt;
ox.on('upsell:simple-wizard:show:before', _.inspect);&lt;br /&gt;
ox.on('upsell:simple-wizard:show', _.inspect);&lt;br /&gt;
ox.on('upsell:simple-wizard:close', _.inspect);&lt;br /&gt;
&lt;br /&gt;
// special event to customize settings (e, variables, settings)&lt;br /&gt;
   // triggered before creating dialog instance;&lt;br /&gt;
   // 2nd parameter has variables like type, missing, user_id etc.&lt;br /&gt;
   // 3rd parameter refers to a local copy of wizard settings&lt;br /&gt;
ox.on('upsell:simple-wizard:init', _.inspect);&lt;br /&gt;
&lt;br /&gt;
// open wizard manually&lt;br /&gt;
wizard.open();&lt;br /&gt;
&lt;br /&gt;
// close wizard manually&lt;br /&gt;
wizard.close();&lt;br /&gt;
&lt;br /&gt;
// disable wizard (unregisters upsell event)&lt;br /&gt;
wizard.disable();&lt;br /&gt;
&lt;br /&gt;
// and of course: enable wizard (registers for upsell event)&lt;br /&gt;
wizard.enable();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some examples for customizations in UI plugins or in console:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
// get plugin (this muse be properly loaded, otherwise you get a runtime error)&lt;br /&gt;
var wizard = require('plugins/upsell/simple-wizard/register'); &lt;br /&gt;
&lt;br /&gt;
// extend IFRAME constructor (see http://underscorejs.org/#compose)&lt;br /&gt;
var custom = function (iframe) {&lt;br /&gt;
  return iframe.css({ border: '5px solid #08c', boxSizing: 'border-box' });&lt;br /&gt;
};&lt;br /&gt;
wizard.getIFrame = _.compose(custom, wizard.getIFrame);&lt;br /&gt;
&lt;br /&gt;
// use an event to customize the IFRAME&lt;br /&gt;
ox.on('upsell:simple-wizard:show:before', function (e, popup) {&lt;br /&gt;
  popup.getContentNode().find('iframe')&lt;br /&gt;
    .css({ border: '5px solid #08c', boxSizing: 'border-box' });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Close wizard===&lt;br /&gt;
The upsell wizard can easily be closed via javascript or by redirecting the IFRAME to a prepared HTML page. In order to see this in action, run the following code (step by step):&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// get plugin (this must be properly loaded, otherwise you get a runtime error)&lt;br /&gt;
var wizard = require('plugins/upsell/simple-wizard/register');&lt;br /&gt;
&lt;br /&gt;
// open wizard&lt;br /&gt;
wizard.open();&lt;br /&gt;
&lt;br /&gt;
// redirect now&lt;br /&gt;
wizard.setSrc('apps/plugins/upsell/simple-wizard/close.html');&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Custom backend systems that run on a different domain cannot use javascript to close the wizard [http://en.wikipedia.org/wiki/Cross-site_scripting]. However, such systems can redirect to ''close.html''. Since this page is part of the UI and therefore located on the same domain, it is allowed to call the wizard's close function.&lt;br /&gt;
&lt;br /&gt;
==Custom development==&lt;br /&gt;
This section documents some of the inner workings of the upsell layer. It should provide some useful insights and hopefully helps at implementing custom upsell solutions.&lt;br /&gt;
===Events===&lt;br /&gt;
Whenever the user starts an app or clicks on an inline-action, a capability-check is performed. For example, all inline actions have native support for such checks:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
new Action('io.ox/calendar/detail/actions/sendmail', {&lt;br /&gt;
    // this action requires the capability &amp;quot;webmail&amp;quot;&lt;br /&gt;
    capabilities: 'webmail',&lt;br /&gt;
    action: function (baton) {&lt;br /&gt;
        // send mail&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the end-user does not have &amp;quot;webmail&amp;quot; (e.g. in a files-only setup) but calls this action, a proper event is fired:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// if any action misses a capability&lt;br /&gt;
ox.trigger('upsell:requires-upgrade');&lt;br /&gt;
// which provides the following data for apps:&lt;br /&gt;
{&lt;br /&gt;
  type: &amp;quot;app&amp;quot;,&lt;br /&gt;
  id: &amp;quot;io.ox/mail/main&amp;quot;,&lt;br /&gt;
  missing: &amp;quot;webmail&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// and for inline-actions:&lt;br /&gt;
{&lt;br /&gt;
  type: &amp;quot;inline-action&amp;quot;,&lt;br /&gt;
  id: &amp;quot;io.ox/calendar/detail/actions/sendmail&amp;quot;,&lt;br /&gt;
  missing: &amp;quot;webmail&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Capabilities and Upsell triggers===&lt;br /&gt;
There are lots of different capabilities. They are defined on the server-side and basically they are just strings. Let's keep it simple and understand them as either services (e.g. mobility), specific functionalities (e.g. multiple_mail_accounts) or applications (e.g. calendar). Some obvious examples:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
! Capability !! Description !! Upsell trigger (if capability is missing)&lt;br /&gt;
|-&lt;br /&gt;
| calendar&lt;br /&gt;
| User has &amp;quot;Calendar&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail/All recipients: Invite to appointment&lt;br /&gt;
* Add portal widget&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| contacts &lt;br /&gt;
| User has &amp;quot;Address Book&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail/App recipients: Save as distribution list&lt;br /&gt;
* Calendar: Save participants as distribution list&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| infostore&lt;br /&gt;
| User has &amp;quot;Files&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail: Save in infostore&lt;br /&gt;
* Add portal widget (My latest files, Recently changed files)&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| portal&lt;br /&gt;
| User has &amp;quot;Portal&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail: Add to portal&lt;br /&gt;
* Contacts: Add to portal&lt;br /&gt;
* Files: Add to portal&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| tasks&lt;br /&gt;
| User has &amp;quot;Tasks&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail: Remind me&lt;br /&gt;
* Add portal widget&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| webmail&lt;br /&gt;
| User has &amp;quot;Mail&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Calendar: Send mail to all participants&lt;br /&gt;
* Contacts: Send mail&lt;br /&gt;
* Contacts: Send vCard&lt;br /&gt;
* Files: Send as link&lt;br /&gt;
* Files: Send by mail&lt;br /&gt;
* Add portal widget&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// list all available capabilities&lt;br /&gt;
_(ox.serverConfig.capabilities).pluck('id').sort();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An example: Free-mail users might just have '''webmail''' and '''contacts'''. If '''infostore''' is enabled for upsell, end-users will see the link to store mail attachments. But since this capability is missing, the event &amp;quot;upsell:requires-upgrade&amp;quot; is triggered which starts the upsell process. Upon successful completion this process should unlock the capability '''infostore''' for the end-user.&lt;br /&gt;
&lt;br /&gt;
The advantage of using rather atomic capabilities as the foundation for upsell is that developers don't have to consider and implement sales programs or marketing matrices in UI code.&lt;br /&gt;
&lt;br /&gt;
===Example dialog===&lt;br /&gt;
Whenever the event ''&amp;quot;upsell:requires-upgrade&amp;quot;'' is triggered there should be some response for the end-user. Usually an upsell dialog should open. This can be implemented as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
function showUpgradeDialog(e, options) {&lt;br /&gt;
    require(['io.ox/core/tk/dialogs'], function (dialogs) {&lt;br /&gt;
        new dialogs.ModalDialog({ easyOut: true })&lt;br /&gt;
            .build(function () {&lt;br /&gt;
                this.getHeader().append(&lt;br /&gt;
                    $('&amp;lt;h4&amp;gt;').text('Upgrade required')&lt;br /&gt;
                );&lt;br /&gt;
                this.getContentNode().append(&lt;br /&gt;
                    $.txt('This feature is not available.'),&lt;br /&gt;
                    $.txt('You need to upgrade your account now.'),&lt;br /&gt;
                    $.txt(' '),&lt;br /&gt;
                    $.txt('The first 90 days are free.')&lt;br /&gt;
                );&lt;br /&gt;
                this.addPrimaryButton('upgrade', 'Get free upgrade');&lt;br /&gt;
                this.addButton('cancel', 'Cancel');&lt;br /&gt;
            })&lt;br /&gt;
            .setUnderlayStyle({&lt;br /&gt;
                opacity: 0.70,&lt;br /&gt;
                backgroundColor: '#08C'&lt;br /&gt;
            })&lt;br /&gt;
            .on('upgrade', function () {&lt;br /&gt;
                ox.trigger('upsell:upgrade', options);&lt;br /&gt;
            })&lt;br /&gt;
            .on('show', function () {&lt;br /&gt;
                ox.off('upsell:requires-upgrade', showUpgradeDialog);&lt;br /&gt;
            })&lt;br /&gt;
            .on('close', function () {&lt;br /&gt;
                ox.on('upsell:requires-upgrade', showUpgradeDialog);&lt;br /&gt;
            })&lt;br /&gt;
            .show();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function upgrade(e, options) {&lt;br /&gt;
    console.debug('upgrade', options);&lt;br /&gt;
    alert('User decided to upgrade! (global event: upsell:upgrade)');&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ox.on('upsell:requires-upgrade', showUpgradeDialog);&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * convention: 'upsell:upgrade' is used to trigger final upsell&lt;br /&gt;
 * the current user and user_id can be found in global variables ox.user and ox.user_id&lt;br /&gt;
 */&lt;br /&gt;
ox.on('upsell:upgrade', upgrade);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The second event '''&amp;quot;upsell:upgrade&amp;quot;''' can be understood as the final imperative to request the upsell server-side.&lt;br /&gt;
&lt;br /&gt;
===Example portal widget===&lt;br /&gt;
Besides waiting for the user to click on such links, it's always a good idea to offer explicit controls to trigger an upsell. One option is creating a portal widget that advertises a premium subscription:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
/**&lt;br /&gt;
 * This work is provided under the terms of the CREATIVE COMMONS PUBLIC&lt;br /&gt;
 * LICENSE. This work is protected by copyright and/or other applicable&lt;br /&gt;
 * law. Any use of the work other than as authorized under this license&lt;br /&gt;
 * or copyright law is prohibited.&lt;br /&gt;
 *&lt;br /&gt;
 * http://creativecommons.org/licenses/by-nc-sa/2.5/&lt;br /&gt;
 * © 2013 Open-Xchange Inc., Tarrytown, NY, USA. info@open-xchange.com&lt;br /&gt;
 *&lt;br /&gt;
 * @author Matthias Biggeleben &amp;lt;matthias.biggeleben@open-xchange.com&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
define('plugins/portal/upsell/register',&lt;br /&gt;
    ['io.ox/core/extensions',&lt;br /&gt;
     'io.ox/files/api',&lt;br /&gt;
     'gettext!plugins/portal'], function (ext, api, gt) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var title = gt('Upgrade to premium');&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget/upsell').extend({&lt;br /&gt;
&lt;br /&gt;
        title: title,&lt;br /&gt;
&lt;br /&gt;
        preview: function (baton) {&lt;br /&gt;
&lt;br /&gt;
            this.addClass('hide-title').append(&lt;br /&gt;
                $('&amp;amp;lt;div class=&amp;quot;content centered&amp;quot; style=&amp;quot;cursor: pointer; padding-top: 3em;&amp;quot;&amp;gt;').append(&lt;br /&gt;
                    $('&amp;amp;lt;h2&amp;gt;').append(&lt;br /&gt;
                        $.txt(title + ' '),&lt;br /&gt;
                        $('&amp;amp;lt;i class=&amp;quot;icon-star&amp;quot;&amp;gt;')&lt;br /&gt;
                    ),&lt;br /&gt;
                    $('&amp;amp;lt;div&amp;gt;').text(gt('Click here for free trial.'))&lt;br /&gt;
                )&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    ox.trigger('upsell:upgrade', {&lt;br /&gt;
                        type: 'widget',&lt;br /&gt;
                        id: 'io.ox/portal/widget/upsell',&lt;br /&gt;
                        missing: ''&lt;br /&gt;
                    });&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Accessing upsell settings===&lt;br /&gt;
The upsell configuration is located in the namespace ''&amp;quot;io.ox/core&amp;quot;'', the path is ''&amp;quot;upsell/enabled&amp;quot;''. Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// get all capabilities that can trigger upsell&lt;br /&gt;
require('settings!io.ox/core').get('upsell/enabled');&lt;br /&gt;
&lt;br /&gt;
// contains data like this&lt;br /&gt;
{&lt;br /&gt;
  infostore: true,&lt;br /&gt;
  portal: true,&lt;br /&gt;
  tasks: true&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If upsell is '''not''' enabled and the end-user lacks specific capabilities, the app or the inline-action is not shown. If upsell is enabled by the upper configuration, inline-actions are shown and trigger the upsell event ''&amp;quot;upsell:requires-upgrade&amp;quot;'' if clicked (but do not execute the action itself).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
/* &lt;br /&gt;
 * if you want to create your own controls, you can use the following helpers &lt;br /&gt;
 */&lt;br /&gt;
var upsell = require('io.ox/core/upsell');&lt;br /&gt;
&lt;br /&gt;
// check capabilities (space-separated) &lt;br /&gt;
upsell.has('portal webmail');&lt;br /&gt;
&lt;br /&gt;
// get missing capabilities (would return &amp;quot;calendar&amp;quot; in demo mode) &lt;br /&gt;
upsell.missing(['portal webmail', 'contacts', 'calendar']);&lt;br /&gt;
&lt;br /&gt;
/* checks if upsell is enabled for a set of capabilities &lt;br /&gt;
 * true if at least one set matches &lt;br /&gt;
 */&lt;br /&gt;
upsell.enabled(['portal webmail', 'webmail calendar']);&lt;br /&gt;
&lt;br /&gt;
/* convenience function: &amp;quot;visible&amp;quot; &lt;br /&gt;
 * checks if something should be visible depending on required capabilities &lt;br /&gt;
 * true if any item matches requires capabilities &lt;br /&gt;
 * true if any item does not match its requirements but is enabled for upsell &lt;br /&gt;
 * this function is used for any inline link, for example, to decide whether or not showing it &lt;br /&gt;
 */&lt;br /&gt;
upsell.visible(['portal webmail', 'contacts', 'calendar']);&lt;br /&gt;
&lt;br /&gt;
// likewise if neither capability set nor enabled for upsell, we get a false &lt;br /&gt;
upsell.visible(['foo']);&lt;br /&gt;
&lt;br /&gt;
// in case something weird happens (usually bad configuration) debug() helps&lt;br /&gt;
upsell.debug();&lt;br /&gt;
&lt;br /&gt;
// and this one&lt;br /&gt;
_(ox.serverConfig.capabilities).pluck('id').sort();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Upsell in OX6==&lt;br /&gt;
Please also consider [[Upsell|this article]] as it also covers backend aspects.&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Upsell&amp;diff=14987</id>
		<title>AppSuite:Upsell</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Upsell&amp;diff=14987"/>
		<updated>2013-07-14T19:29:11Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Capabilities and triggers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stability-experimental}} &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Upsell&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract.''' This article is mainly for UI developers and introduces the concept of upsell from a technical point of view. In short: End-user has a set of so-called ''capabilities''. UI, however, offers functionality beyond that limited set for promotion purposes. Actions, e.g. inline links, that require missing capabilities trigger an '''in-app upsell'''. This process leads to a trial period or a new subscription. Technical challenge for the UI developer is to check what the end-user has, what can be shown beyond that, and how to handle upsell. It is also possible for hosting companies to easily integrate their own online shop into OX Upsell, since the internal mechanisms are ''loosely coupled'' via events.&lt;br /&gt;
__TOC__&lt;br /&gt;
==Enable upsell==&lt;br /&gt;
In order to configure upsell server-side, just create a new file '''upsell.properties''' or append to existing '''appsuite.properties''' (mind the '''double-slash'''; this in not a typo! plus: changing such settings requires a backend restart):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
io.ox/core//upsell/enabled/infostore=true&lt;br /&gt;
io.ox/core//upsell/enabled/portal=true&lt;br /&gt;
io.ox/core//upsell/enabled/tasks=true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Each line enables a specific [[AppSuite:Upsell#Capabilities|capability]] for upsell. That means whenever a feature misses one these capabilities a special upsell-related event is triggered.&lt;br /&gt;
&lt;br /&gt;
Hint: For simple demo purposes, you can enable an internal upsell configuration by appending '''&amp;quot;&amp;amp;demo=upsell&amp;quot;''' to the URL. Needs to reload page, of course.&lt;br /&gt;
&lt;br /&gt;
==Upsell Wizard==&lt;br /&gt;
&amp;lt;div style=&amp;quot;color: #3A87AD; text-align: right; margin: -1em 0 1em 0; padding: 0.5em; background-color: #D9EDF7;&amp;quot;&amp;gt;Shipped with 7.2.1&amp;lt;/div&amp;gt;&lt;br /&gt;
Hosters usually want to offer context-sensitive content in an IFRAME if the upsell is triggered. Therefore, App Suite comes with an integrated but optional plugin that takes care of this. Just [[AppSuite:UI_manifests_explained#Loading_custom_manifest_during_development|enable]] ''plugins/upsell/simple-wizard''. This plugin registers for the event ''&amp;quot;upsell:requires-upsell&amp;quot;'', opens a modal popup, and loads a custom URL in an embedded IFRAME.&lt;br /&gt;
&lt;br /&gt;
[[File:Simple_upsell_wizard.png|800 px|Custom content in an IFRAME]]&lt;br /&gt;
&lt;br /&gt;
===Wizard settings===&lt;br /&gt;
In order to configure this server-side, just create a new file '''upsell.properties''' or append to existing '''appsuite.properties''' (mind the '''double-slash'''; this in not a typo! plus: changing such settings requires a backend restart):&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt;&lt;br /&gt;
plugins/upsell/simple-wizard//url=blank.html?user=$user,user_id=$user_id,context_id=$context_id&lt;br /&gt;
plugins/upsell/simple-wizard//overlayOpacity=0.5&lt;br /&gt;
plugins/upsell/simple-wizard//overlayColor=black&lt;br /&gt;
plugins/upsell/simple-wizard//zeroPadding=true&lt;br /&gt;
plugins/upsell/simple-wizard//width=750&lt;br /&gt;
plugins/upsell/simple-wizard//height=390&lt;br /&gt;
plugins/upsell/simple-wizard//closeButton=true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
! Settings !! Description&lt;br /&gt;
|-&lt;br /&gt;
| url&lt;br /&gt;
| Custom URL that is loaded in IFRAME; can contain special [[AppSuite:Upsell#Custom_URL_variables|variables]].&lt;br /&gt;
|-&lt;br /&gt;
| overlayOpacity &lt;br /&gt;
| CSS opacity value for overlay; default is 0.5&lt;br /&gt;
|-&lt;br /&gt;
| overlayColor&lt;br /&gt;
| CSS background color for overlay; default is black&lt;br /&gt;
|-&lt;br /&gt;
| zeroPadding&lt;br /&gt;
| If true (default) there is no inner padding inside modal dialog, i.e. the IFRAME covers the popup&lt;br /&gt;
|-&lt;br /&gt;
| width&lt;br /&gt;
| Width of outer popup (not IFRAME) in pixel&lt;br /&gt;
|-&lt;br /&gt;
| height&lt;br /&gt;
| Height of IFRAME in pixel&lt;br /&gt;
|-&lt;br /&gt;
| closeButton&lt;br /&gt;
| If true (default) the wizard shows its own close button&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Custom URL variables===&lt;br /&gt;
The plugin offers a set of variables that help providing context-sensitive content. ''$missing'' is probably the most prominent one. Other variables help identifying the user. An example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-setting&amp;quot;&amp;gt;&lt;br /&gt;
upsell.php?user_id=$user_id&amp;amp;context_id=$context_id&amp;amp;language=$language&amp;amp;missing=$missing&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
! Variable !! Description&lt;br /&gt;
|-&lt;br /&gt;
| $context_id&lt;br /&gt;
| context_id of current user&lt;br /&gt;
|-&lt;br /&gt;
| $hostname&lt;br /&gt;
| hostname of current session, e.g. www.one-of-countless-virtual-hosts.com&lt;br /&gt;
|-&lt;br /&gt;
| $id&lt;br /&gt;
| The trigger's identifier, e.g. &amp;quot;io.ox/files&amp;quot;. Can refer to an app, an inline action, or a portal plugin. See $type&lt;br /&gt;
|-&lt;br /&gt;
| $imap_login&lt;br /&gt;
| The current user's imap login&lt;br /&gt;
|-&lt;br /&gt;
| $language&lt;br /&gt;
| The current user's language, e.g. de_DE or en_US&lt;br /&gt;
|-&lt;br /&gt;
| $mail&lt;br /&gt;
| The current user's primary email address&lt;br /&gt;
|-&lt;br /&gt;
| $missing&lt;br /&gt;
| The set of missing capabilities, comma separated, e.g. &amp;quot;files&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| $session&lt;br /&gt;
| The current user's session id&lt;br /&gt;
|-&lt;br /&gt;
| $type&lt;br /&gt;
| Either app, inline-action, or portal-widget. Describes what triggered the upsell. See $id&lt;br /&gt;
|-&lt;br /&gt;
| $user&lt;br /&gt;
| The current user's login name (can include context name, i.e somebody@foo)&lt;br /&gt;
|-&lt;br /&gt;
| $user_id&lt;br /&gt;
| The current user's numeric id&lt;br /&gt;
|-&lt;br /&gt;
| $user_login&lt;br /&gt;
| The current user's login (usually without context name)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Develop and debug===&lt;br /&gt;
While experimenting or developing, you can use the following helpful functions:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// get plugin (this must be properly loaded, otherwise you get a runtime error)&lt;br /&gt;
var wizard = require('plugins/upsell/simple-wizard/register');&lt;br /&gt;
&lt;br /&gt;
// if you have no chance to enabled this plugin server-side, use the following approach &lt;br /&gt;
   // but don't use this in production plugins, it's just a hack for console: &lt;br /&gt;
   // if you don't know the difference please take a look at &lt;br /&gt;
   // http://requirejs.org/docs/errors.html#notloaded &lt;br /&gt;
var wizard; require(['plugins/upsell/simple-wizard/register'], function (w) { wizard = w; });&lt;br /&gt;
&lt;br /&gt;
// get variables (optional: options from upsell:require-upgrade event)&lt;br /&gt;
wizard.getVariables({ type: 'app', id: 'io.ox/files', missing: 'files' });&lt;br /&gt;
&lt;br /&gt;
// get URL (optional: options from upsell:require-upgrade event)&lt;br /&gt;
   // replaces placeholders ($foo) by variable values&lt;br /&gt;
wizard.getURL({ type: 'app', id: 'io.ox/files', missing: 'files' });&lt;br /&gt;
&lt;br /&gt;
// get all settings (can be changed on the fly)&lt;br /&gt;
console.log(wizard.settings);&lt;br /&gt;
&lt;br /&gt;
// global upsell events; parameters: (e, popup)&lt;br /&gt;
ox.on('upsell:simple-wizard:show:before', _.inspect);&lt;br /&gt;
ox.on('upsell:simple-wizard:show', _.inspect);&lt;br /&gt;
ox.on('upsell:simple-wizard:close', _.inspect);&lt;br /&gt;
&lt;br /&gt;
// special event to customize settings (e, variables, settings)&lt;br /&gt;
   // triggered before creating dialog instance;&lt;br /&gt;
   // 2nd parameter has variables like type, missing, user_id etc.&lt;br /&gt;
   // 3rd parameter refers to a local copy of wizard settings&lt;br /&gt;
ox.on('upsell:simple-wizard:init', _.inspect);&lt;br /&gt;
&lt;br /&gt;
// open wizard manually&lt;br /&gt;
wizard.open();&lt;br /&gt;
&lt;br /&gt;
// close wizard manually&lt;br /&gt;
wizard.close();&lt;br /&gt;
&lt;br /&gt;
// disable wizard (unregisters upsell event)&lt;br /&gt;
wizard.disable();&lt;br /&gt;
&lt;br /&gt;
// and of course: enable wizard (registers for upsell event)&lt;br /&gt;
wizard.enable();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some examples for customizations in UI plugins or in console:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
// get plugin (this muse be properly loaded, otherwise you get a runtime error)&lt;br /&gt;
var wizard = require('plugins/upsell/simple-wizard/register'); &lt;br /&gt;
&lt;br /&gt;
// extend IFRAME constructor (see http://underscorejs.org/#compose)&lt;br /&gt;
var custom = function (iframe) {&lt;br /&gt;
  return iframe.css({ border: '5px solid #08c', boxSizing: 'border-box' });&lt;br /&gt;
};&lt;br /&gt;
wizard.getIFrame = _.compose(custom, wizard.getIFrame);&lt;br /&gt;
&lt;br /&gt;
// use an event to customize the IFRAME&lt;br /&gt;
ox.on('upsell:simple-wizard:show:before', function (e, popup) {&lt;br /&gt;
  popup.getContentNode().find('iframe')&lt;br /&gt;
    .css({ border: '5px solid #08c', boxSizing: 'border-box' });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Close wizard===&lt;br /&gt;
The upsell wizard can easily be closed via javascript or by redirecting the IFRAME to a prepared HTML page. In order to see this in action, run the following code (step by step):&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// get plugin (this must be properly loaded, otherwise you get a runtime error)&lt;br /&gt;
var wizard = require('plugins/upsell/simple-wizard/register');&lt;br /&gt;
&lt;br /&gt;
// open wizard&lt;br /&gt;
wizard.open();&lt;br /&gt;
&lt;br /&gt;
// redirect now&lt;br /&gt;
wizard.setSrc('apps/plugins/upsell/simple-wizard/close.html');&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Custom backend systems that run on a different domain cannot use javascript to close the wizard [http://en.wikipedia.org/wiki/Cross-site_scripting]. However, such systems can redirect to ''close.html''. Since this page is part of the UI and therefore located on the same domain, it is allowed to call the wizard's close function.&lt;br /&gt;
&lt;br /&gt;
==Custom development==&lt;br /&gt;
This section documents some of the inner workings of the upsell layer. It should provide some useful insights and hopefully helps at implementing custom upsell solutions.&lt;br /&gt;
===Events===&lt;br /&gt;
Whenever the user starts an app or clicks on an inline-action, a capability-check is performed. For example, all inline actions have native support for such checks:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
new Action('io.ox/calendar/detail/actions/sendmail', {&lt;br /&gt;
    // this action requires the capability &amp;quot;webmail&amp;quot;&lt;br /&gt;
    capabilities: 'webmail',&lt;br /&gt;
    action: function (baton) {&lt;br /&gt;
        // send mail&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the end-user does not have &amp;quot;webmail&amp;quot; (e.g. in a files-only setup) but calls this action, a proper event is fired:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// if any action misses a capability&lt;br /&gt;
ox.trigger('upsell:requires-upgrade');&lt;br /&gt;
// which provides the following data for apps:&lt;br /&gt;
{&lt;br /&gt;
  type: &amp;quot;app&amp;quot;,&lt;br /&gt;
  id: &amp;quot;io.ox/mail/main&amp;quot;,&lt;br /&gt;
  missing: &amp;quot;webmail&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// and for inline-actions:&lt;br /&gt;
{&lt;br /&gt;
  type: &amp;quot;inline-action&amp;quot;,&lt;br /&gt;
  id: &amp;quot;io.ox/calendar/detail/actions/sendmail&amp;quot;,&lt;br /&gt;
  missing: &amp;quot;webmail&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Capabilities and Upsell triggers===&lt;br /&gt;
There are lots of different capabilities. They are defined on the server-side and basically they are just strings. Let's keep it simple and understand them as either services (e.g. mobility), specific functionalities (e.g. multiple_mail_accounts) or applications (e.g. calendar). Some obvious examples:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
! Capability !! Description !! Upsell trigger (if capability is missing)&lt;br /&gt;
|-&lt;br /&gt;
| calendar&lt;br /&gt;
| User has &amp;quot;Calendar&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail/All recipients: Invite to appointment&lt;br /&gt;
* Add portal widget&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| contacts &lt;br /&gt;
| User has &amp;quot;Address Book&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail/App recipients: Save as distribution list&lt;br /&gt;
* Calendar: Save participants as distribution list&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| infostore&lt;br /&gt;
| User has &amp;quot;Files&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail: Save in infostore&lt;br /&gt;
* Add portal widget (My latest files, Recently changed files)&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| portal&lt;br /&gt;
| User has &amp;quot;Portal&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail: Add to portal&lt;br /&gt;
* Contacts: Add to portal&lt;br /&gt;
* Files: Add to portal&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| tasks&lt;br /&gt;
| User has &amp;quot;Tasks&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail: Remind me&lt;br /&gt;
* Add portal widget&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| webmail&lt;br /&gt;
| User has &amp;quot;Mail&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Calendar: Send mail to all participants&lt;br /&gt;
* Contacts: Send mail&lt;br /&gt;
* Contacts: Send vCard&lt;br /&gt;
* Files: Send as link&lt;br /&gt;
* Files: Send by mail&lt;br /&gt;
* Add portal widget&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// list all available capabilities&lt;br /&gt;
_(ox.serverConfig.capabilities).pluck('id').sort();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An example: Free-mail users might just have '''webmail''' and '''contacts'''. If '''infostore''' is enabled for upsell, end-users will see the link to store mail attachments. But since this capability is missing, the event &amp;quot;upsell:requires-upgrade&amp;quot; is triggered which starts the upsell process. Upon successful completion this process should unlock the capability '''infostore''' for the end-user.&lt;br /&gt;
&lt;br /&gt;
The advantage of using rather atomic capabilities as the foundation for upsell is that developers don't have to consider and implement sales programs or marketing matrices in UI code.&lt;br /&gt;
&lt;br /&gt;
===Example dialog===&lt;br /&gt;
Whenever the event ''&amp;quot;upsell:requires-upgrade&amp;quot;'' is triggered there should be some response for the end-user. Usually an upsell dialog should open. This can be implemented as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
function showUpgradeDialog(e, options) {&lt;br /&gt;
    require(['io.ox/core/tk/dialogs'], function (dialogs) {&lt;br /&gt;
        new dialogs.ModalDialog({ easyOut: true })&lt;br /&gt;
            .build(function () {&lt;br /&gt;
                this.getHeader().append(&lt;br /&gt;
                    $('&amp;lt;h4&amp;gt;').text('Upgrade required')&lt;br /&gt;
                );&lt;br /&gt;
                this.getContentNode().append(&lt;br /&gt;
                    $.txt('This feature is not available.'),&lt;br /&gt;
                    $.txt('You need to upgrade your account now.'),&lt;br /&gt;
                    $.txt(' '),&lt;br /&gt;
                    $.txt('The first 90 days are free.')&lt;br /&gt;
                );&lt;br /&gt;
                this.addPrimaryButton('upgrade', 'Get free upgrade');&lt;br /&gt;
                this.addButton('cancel', 'Cancel');&lt;br /&gt;
            })&lt;br /&gt;
            .setUnderlayStyle({&lt;br /&gt;
                opacity: 0.70,&lt;br /&gt;
                backgroundColor: '#08C'&lt;br /&gt;
            })&lt;br /&gt;
            .on('upgrade', function () {&lt;br /&gt;
                ox.trigger('upsell:upgrade', options);&lt;br /&gt;
            })&lt;br /&gt;
            .on('show', function () {&lt;br /&gt;
                ox.off('upsell:requires-upgrade', showUpgradeDialog);&lt;br /&gt;
            })&lt;br /&gt;
            .on('close', function () {&lt;br /&gt;
                ox.on('upsell:requires-upgrade', showUpgradeDialog);&lt;br /&gt;
            })&lt;br /&gt;
            .show();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function upgrade(e, options) {&lt;br /&gt;
    console.debug('upgrade', options);&lt;br /&gt;
    alert('User decided to upgrade! (global event: upsell:upgrade)');&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ox.on('upsell:requires-upgrade', showUpgradeDialog);&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * convention: 'upsell:upgrade' is used to trigger final upsell&lt;br /&gt;
 * the current user and user_id can be found in global variables ox.user and ox.user_id&lt;br /&gt;
 */&lt;br /&gt;
ox.on('upsell:upgrade', upgrade);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The second event '''&amp;quot;upsell:upgrade&amp;quot;''' can be understood as the final imperative to request the upsell server-side.&lt;br /&gt;
&lt;br /&gt;
===Example portal widget===&lt;br /&gt;
Besides waiting for the user to click on such links, it's always a good idea to offer explicit controls to trigger an upsell. One option is creating a portal widget that advertises a premium subscription:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
/**&lt;br /&gt;
 * This work is provided under the terms of the CREATIVE COMMONS PUBLIC&lt;br /&gt;
 * LICENSE. This work is protected by copyright and/or other applicable&lt;br /&gt;
 * law. Any use of the work other than as authorized under this license&lt;br /&gt;
 * or copyright law is prohibited.&lt;br /&gt;
 *&lt;br /&gt;
 * http://creativecommons.org/licenses/by-nc-sa/2.5/&lt;br /&gt;
 * © 2013 Open-Xchange Inc., Tarrytown, NY, USA. info@open-xchange.com&lt;br /&gt;
 *&lt;br /&gt;
 * @author Matthias Biggeleben &amp;lt;matthias.biggeleben@open-xchange.com&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
define('plugins/portal/upsell/register',&lt;br /&gt;
    ['io.ox/core/extensions',&lt;br /&gt;
     'io.ox/files/api',&lt;br /&gt;
     'gettext!plugins/portal'], function (ext, api, gt) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var title = gt('Upgrade to premium');&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget/upsell').extend({&lt;br /&gt;
&lt;br /&gt;
        title: title,&lt;br /&gt;
&lt;br /&gt;
        preview: function (baton) {&lt;br /&gt;
&lt;br /&gt;
            this.addClass('hide-title').append(&lt;br /&gt;
                $('&amp;amp;lt;div class=&amp;quot;content centered&amp;quot; style=&amp;quot;cursor: pointer; padding-top: 3em;&amp;quot;&amp;gt;').append(&lt;br /&gt;
                    $('&amp;amp;lt;h2&amp;gt;').append(&lt;br /&gt;
                        $.txt(title + ' '),&lt;br /&gt;
                        $('&amp;amp;lt;i class=&amp;quot;icon-star&amp;quot;&amp;gt;')&lt;br /&gt;
                    ),&lt;br /&gt;
                    $('&amp;amp;lt;div&amp;gt;').text(gt('Click here for free trial.'))&lt;br /&gt;
                )&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    ox.trigger('upsell:upgrade', {&lt;br /&gt;
                        type: 'widget',&lt;br /&gt;
                        id: 'io.ox/portal/widget/upsell',&lt;br /&gt;
                        missing: ''&lt;br /&gt;
                    });&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Accessing upsell settings===&lt;br /&gt;
The upsell configuration is located in the namespace ''&amp;quot;io.ox/core&amp;quot;'', the path is ''&amp;quot;upsell/enabled&amp;quot;''. Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// get all capabilities that can trigger upsell&lt;br /&gt;
require('settings!io.ox/core').get('upsell/enabled');&lt;br /&gt;
&lt;br /&gt;
// contains data like this&lt;br /&gt;
{&lt;br /&gt;
  infostore: true,&lt;br /&gt;
  portal: true,&lt;br /&gt;
  tasks: true&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If upsell is '''not''' enabled and the end-user lacks specific capabilities, the app or the inline-action is not shown. If upsell is enabled by the upper configuration, inline-actions are shown and trigger the upsell event ''&amp;quot;upsell:requires-upgrade&amp;quot;'' if clicked (but do not execute the action itself).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
/* &lt;br /&gt;
 * if you want to create your own controls, you can use the following helpers &lt;br /&gt;
 */&lt;br /&gt;
var upsell = require('io.ox/core/upsell');&lt;br /&gt;
&lt;br /&gt;
// check capabilities (space-separated) &lt;br /&gt;
upsell.has('portal webmail');&lt;br /&gt;
&lt;br /&gt;
// get missing capabilities (would return &amp;quot;calendar&amp;quot; in demo mode) &lt;br /&gt;
upsell.missing(['portal webmail', 'contacts', 'calendar']);&lt;br /&gt;
&lt;br /&gt;
/* checks if upsell is enabled for a set of capabilities &lt;br /&gt;
 * true if at least one set matches &lt;br /&gt;
 */&lt;br /&gt;
upsell.enabled(['portal webmail', 'webmail calendar']);&lt;br /&gt;
&lt;br /&gt;
/* convenience function: &amp;quot;visible&amp;quot; &lt;br /&gt;
 * checks if something should be visible depending on required capabilities &lt;br /&gt;
 * true if any item matches requires capabilities &lt;br /&gt;
 * true if any item does not match its requirements but is enabled for upsell &lt;br /&gt;
 * this function is used for any inline link, for example, to decide whether or not showing it &lt;br /&gt;
 */&lt;br /&gt;
upsell.visible(['portal webmail', 'contacts', 'calendar']);&lt;br /&gt;
&lt;br /&gt;
// likewise if neither capability set nor enabled for upsell, we get a false &lt;br /&gt;
upsell.visible(['foo']);&lt;br /&gt;
&lt;br /&gt;
// in case something weird happens (usually bad configuration) debug() helps&lt;br /&gt;
upsell.debug();&lt;br /&gt;
&lt;br /&gt;
// and this one&lt;br /&gt;
_(ox.serverConfig.capabilities).pluck('id').sort();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Upsell in OX6==&lt;br /&gt;
Please also consider [[Upsell|this article]] as it also covers backend aspects.&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Upsell&amp;diff=14986</id>
		<title>AppSuite:Upsell</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Upsell&amp;diff=14986"/>
		<updated>2013-07-14T19:28:50Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Capabilities */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stability-experimental}} &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Upsell&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract.''' This article is mainly for UI developers and introduces the concept of upsell from a technical point of view. In short: End-user has a set of so-called ''capabilities''. UI, however, offers functionality beyond that limited set for promotion purposes. Actions, e.g. inline links, that require missing capabilities trigger an '''in-app upsell'''. This process leads to a trial period or a new subscription. Technical challenge for the UI developer is to check what the end-user has, what can be shown beyond that, and how to handle upsell. It is also possible for hosting companies to easily integrate their own online shop into OX Upsell, since the internal mechanisms are ''loosely coupled'' via events.&lt;br /&gt;
__TOC__&lt;br /&gt;
==Enable upsell==&lt;br /&gt;
In order to configure upsell server-side, just create a new file '''upsell.properties''' or append to existing '''appsuite.properties''' (mind the '''double-slash'''; this in not a typo! plus: changing such settings requires a backend restart):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt; &lt;br /&gt;
io.ox/core//upsell/enabled/infostore=true&lt;br /&gt;
io.ox/core//upsell/enabled/portal=true&lt;br /&gt;
io.ox/core//upsell/enabled/tasks=true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Each line enables a specific [[AppSuite:Upsell#Capabilities|capability]] for upsell. That means whenever a feature misses one these capabilities a special upsell-related event is triggered.&lt;br /&gt;
&lt;br /&gt;
Hint: For simple demo purposes, you can enable an internal upsell configuration by appending '''&amp;quot;&amp;amp;demo=upsell&amp;quot;''' to the URL. Needs to reload page, of course.&lt;br /&gt;
&lt;br /&gt;
==Upsell Wizard==&lt;br /&gt;
&amp;lt;div style=&amp;quot;color: #3A87AD; text-align: right; margin: -1em 0 1em 0; padding: 0.5em; background-color: #D9EDF7;&amp;quot;&amp;gt;Shipped with 7.2.1&amp;lt;/div&amp;gt;&lt;br /&gt;
Hosters usually want to offer context-sensitive content in an IFRAME if the upsell is triggered. Therefore, App Suite comes with an integrated but optional plugin that takes care of this. Just [[AppSuite:UI_manifests_explained#Loading_custom_manifest_during_development|enable]] ''plugins/upsell/simple-wizard''. This plugin registers for the event ''&amp;quot;upsell:requires-upsell&amp;quot;'', opens a modal popup, and loads a custom URL in an embedded IFRAME.&lt;br /&gt;
&lt;br /&gt;
[[File:Simple_upsell_wizard.png|800 px|Custom content in an IFRAME]]&lt;br /&gt;
&lt;br /&gt;
===Wizard settings===&lt;br /&gt;
In order to configure this server-side, just create a new file '''upsell.properties''' or append to existing '''appsuite.properties''' (mind the '''double-slash'''; this in not a typo! plus: changing such settings requires a backend restart):&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-settings&amp;quot;&amp;gt;&lt;br /&gt;
plugins/upsell/simple-wizard//url=blank.html?user=$user,user_id=$user_id,context_id=$context_id&lt;br /&gt;
plugins/upsell/simple-wizard//overlayOpacity=0.5&lt;br /&gt;
plugins/upsell/simple-wizard//overlayColor=black&lt;br /&gt;
plugins/upsell/simple-wizard//zeroPadding=true&lt;br /&gt;
plugins/upsell/simple-wizard//width=750&lt;br /&gt;
plugins/upsell/simple-wizard//height=390&lt;br /&gt;
plugins/upsell/simple-wizard//closeButton=true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
! Settings !! Description&lt;br /&gt;
|-&lt;br /&gt;
| url&lt;br /&gt;
| Custom URL that is loaded in IFRAME; can contain special [[AppSuite:Upsell#Custom_URL_variables|variables]].&lt;br /&gt;
|-&lt;br /&gt;
| overlayOpacity &lt;br /&gt;
| CSS opacity value for overlay; default is 0.5&lt;br /&gt;
|-&lt;br /&gt;
| overlayColor&lt;br /&gt;
| CSS background color for overlay; default is black&lt;br /&gt;
|-&lt;br /&gt;
| zeroPadding&lt;br /&gt;
| If true (default) there is no inner padding inside modal dialog, i.e. the IFRAME covers the popup&lt;br /&gt;
|-&lt;br /&gt;
| width&lt;br /&gt;
| Width of outer popup (not IFRAME) in pixel&lt;br /&gt;
|-&lt;br /&gt;
| height&lt;br /&gt;
| Height of IFRAME in pixel&lt;br /&gt;
|-&lt;br /&gt;
| closeButton&lt;br /&gt;
| If true (default) the wizard shows its own close button&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Custom URL variables===&lt;br /&gt;
The plugin offers a set of variables that help providing context-sensitive content. ''$missing'' is probably the most prominent one. Other variables help identifying the user. An example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-setting&amp;quot;&amp;gt;&lt;br /&gt;
upsell.php?user_id=$user_id&amp;amp;context_id=$context_id&amp;amp;language=$language&amp;amp;missing=$missing&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
! Variable !! Description&lt;br /&gt;
|-&lt;br /&gt;
| $context_id&lt;br /&gt;
| context_id of current user&lt;br /&gt;
|-&lt;br /&gt;
| $hostname&lt;br /&gt;
| hostname of current session, e.g. www.one-of-countless-virtual-hosts.com&lt;br /&gt;
|-&lt;br /&gt;
| $id&lt;br /&gt;
| The trigger's identifier, e.g. &amp;quot;io.ox/files&amp;quot;. Can refer to an app, an inline action, or a portal plugin. See $type&lt;br /&gt;
|-&lt;br /&gt;
| $imap_login&lt;br /&gt;
| The current user's imap login&lt;br /&gt;
|-&lt;br /&gt;
| $language&lt;br /&gt;
| The current user's language, e.g. de_DE or en_US&lt;br /&gt;
|-&lt;br /&gt;
| $mail&lt;br /&gt;
| The current user's primary email address&lt;br /&gt;
|-&lt;br /&gt;
| $missing&lt;br /&gt;
| The set of missing capabilities, comma separated, e.g. &amp;quot;files&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| $session&lt;br /&gt;
| The current user's session id&lt;br /&gt;
|-&lt;br /&gt;
| $type&lt;br /&gt;
| Either app, inline-action, or portal-widget. Describes what triggered the upsell. See $id&lt;br /&gt;
|-&lt;br /&gt;
| $user&lt;br /&gt;
| The current user's login name (can include context name, i.e somebody@foo)&lt;br /&gt;
|-&lt;br /&gt;
| $user_id&lt;br /&gt;
| The current user's numeric id&lt;br /&gt;
|-&lt;br /&gt;
| $user_login&lt;br /&gt;
| The current user's login (usually without context name)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Develop and debug===&lt;br /&gt;
While experimenting or developing, you can use the following helpful functions:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// get plugin (this must be properly loaded, otherwise you get a runtime error)&lt;br /&gt;
var wizard = require('plugins/upsell/simple-wizard/register');&lt;br /&gt;
&lt;br /&gt;
// if you have no chance to enabled this plugin server-side, use the following approach &lt;br /&gt;
   // but don't use this in production plugins, it's just a hack for console: &lt;br /&gt;
   // if you don't know the difference please take a look at &lt;br /&gt;
   // http://requirejs.org/docs/errors.html#notloaded &lt;br /&gt;
var wizard; require(['plugins/upsell/simple-wizard/register'], function (w) { wizard = w; });&lt;br /&gt;
&lt;br /&gt;
// get variables (optional: options from upsell:require-upgrade event)&lt;br /&gt;
wizard.getVariables({ type: 'app', id: 'io.ox/files', missing: 'files' });&lt;br /&gt;
&lt;br /&gt;
// get URL (optional: options from upsell:require-upgrade event)&lt;br /&gt;
   // replaces placeholders ($foo) by variable values&lt;br /&gt;
wizard.getURL({ type: 'app', id: 'io.ox/files', missing: 'files' });&lt;br /&gt;
&lt;br /&gt;
// get all settings (can be changed on the fly)&lt;br /&gt;
console.log(wizard.settings);&lt;br /&gt;
&lt;br /&gt;
// global upsell events; parameters: (e, popup)&lt;br /&gt;
ox.on('upsell:simple-wizard:show:before', _.inspect);&lt;br /&gt;
ox.on('upsell:simple-wizard:show', _.inspect);&lt;br /&gt;
ox.on('upsell:simple-wizard:close', _.inspect);&lt;br /&gt;
&lt;br /&gt;
// special event to customize settings (e, variables, settings)&lt;br /&gt;
   // triggered before creating dialog instance;&lt;br /&gt;
   // 2nd parameter has variables like type, missing, user_id etc.&lt;br /&gt;
   // 3rd parameter refers to a local copy of wizard settings&lt;br /&gt;
ox.on('upsell:simple-wizard:init', _.inspect);&lt;br /&gt;
&lt;br /&gt;
// open wizard manually&lt;br /&gt;
wizard.open();&lt;br /&gt;
&lt;br /&gt;
// close wizard manually&lt;br /&gt;
wizard.close();&lt;br /&gt;
&lt;br /&gt;
// disable wizard (unregisters upsell event)&lt;br /&gt;
wizard.disable();&lt;br /&gt;
&lt;br /&gt;
// and of course: enable wizard (registers for upsell event)&lt;br /&gt;
wizard.enable();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some examples for customizations in UI plugins or in console:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
// get plugin (this muse be properly loaded, otherwise you get a runtime error)&lt;br /&gt;
var wizard = require('plugins/upsell/simple-wizard/register'); &lt;br /&gt;
&lt;br /&gt;
// extend IFRAME constructor (see http://underscorejs.org/#compose)&lt;br /&gt;
var custom = function (iframe) {&lt;br /&gt;
  return iframe.css({ border: '5px solid #08c', boxSizing: 'border-box' });&lt;br /&gt;
};&lt;br /&gt;
wizard.getIFrame = _.compose(custom, wizard.getIFrame);&lt;br /&gt;
&lt;br /&gt;
// use an event to customize the IFRAME&lt;br /&gt;
ox.on('upsell:simple-wizard:show:before', function (e, popup) {&lt;br /&gt;
  popup.getContentNode().find('iframe')&lt;br /&gt;
    .css({ border: '5px solid #08c', boxSizing: 'border-box' });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Close wizard===&lt;br /&gt;
The upsell wizard can easily be closed via javascript or by redirecting the IFRAME to a prepared HTML page. In order to see this in action, run the following code (step by step):&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// get plugin (this must be properly loaded, otherwise you get a runtime error)&lt;br /&gt;
var wizard = require('plugins/upsell/simple-wizard/register');&lt;br /&gt;
&lt;br /&gt;
// open wizard&lt;br /&gt;
wizard.open();&lt;br /&gt;
&lt;br /&gt;
// redirect now&lt;br /&gt;
wizard.setSrc('apps/plugins/upsell/simple-wizard/close.html');&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Custom backend systems that run on a different domain cannot use javascript to close the wizard [http://en.wikipedia.org/wiki/Cross-site_scripting]. However, such systems can redirect to ''close.html''. Since this page is part of the UI and therefore located on the same domain, it is allowed to call the wizard's close function.&lt;br /&gt;
&lt;br /&gt;
==Custom development==&lt;br /&gt;
This section documents some of the inner workings of the upsell layer. It should provide some useful insights and hopefully helps at implementing custom upsell solutions.&lt;br /&gt;
===Events===&lt;br /&gt;
Whenever the user starts an app or clicks on an inline-action, a capability-check is performed. For example, all inline actions have native support for such checks:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
new Action('io.ox/calendar/detail/actions/sendmail', {&lt;br /&gt;
    // this action requires the capability &amp;quot;webmail&amp;quot;&lt;br /&gt;
    capabilities: 'webmail',&lt;br /&gt;
    action: function (baton) {&lt;br /&gt;
        // send mail&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the end-user does not have &amp;quot;webmail&amp;quot; (e.g. in a files-only setup) but calls this action, a proper event is fired:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// if any action misses a capability&lt;br /&gt;
ox.trigger('upsell:requires-upgrade');&lt;br /&gt;
// which provides the following data for apps:&lt;br /&gt;
{&lt;br /&gt;
  type: &amp;quot;app&amp;quot;,&lt;br /&gt;
  id: &amp;quot;io.ox/mail/main&amp;quot;,&lt;br /&gt;
  missing: &amp;quot;webmail&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
// and for inline-actions:&lt;br /&gt;
{&lt;br /&gt;
  type: &amp;quot;inline-action&amp;quot;,&lt;br /&gt;
  id: &amp;quot;io.ox/calendar/detail/actions/sendmail&amp;quot;,&lt;br /&gt;
  missing: &amp;quot;webmail&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Capabilities and triggers===&lt;br /&gt;
There are lots of different capabilities. They are defined on the server-side and basically they are just strings. Let's keep it simple and understand them as either services (e.g. mobility), specific functionalities (e.g. multiple_mail_accounts) or applications (e.g. calendar). Some obvious examples:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
! Capability !! Description !! Upsell trigger (if capability is missing)&lt;br /&gt;
|-&lt;br /&gt;
| calendar&lt;br /&gt;
| User has &amp;quot;Calendar&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail/All recipients: Invite to appointment&lt;br /&gt;
* Add portal widget&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| contacts &lt;br /&gt;
| User has &amp;quot;Address Book&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail/App recipients: Save as distribution list&lt;br /&gt;
* Calendar: Save participants as distribution list&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| infostore&lt;br /&gt;
| User has &amp;quot;Files&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail: Save in infostore&lt;br /&gt;
* Add portal widget (My latest files, Recently changed files)&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| portal&lt;br /&gt;
| User has &amp;quot;Portal&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail: Add to portal&lt;br /&gt;
* Contacts: Add to portal&lt;br /&gt;
* Files: Add to portal&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| tasks&lt;br /&gt;
| User has &amp;quot;Tasks&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Mail: Remind me&lt;br /&gt;
* Add portal widget&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|-&lt;br /&gt;
| webmail&lt;br /&gt;
| User has &amp;quot;Mail&amp;quot; app&lt;br /&gt;
|&lt;br /&gt;
* Calendar: Send mail to all participants&lt;br /&gt;
* Contacts: Send mail&lt;br /&gt;
* Contacts: Send vCard&lt;br /&gt;
* Files: Send as link&lt;br /&gt;
* Files: Send by mail&lt;br /&gt;
* Add portal widget&lt;br /&gt;
* Top bar&lt;br /&gt;
* Launch pad&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// list all available capabilities&lt;br /&gt;
_(ox.serverConfig.capabilities).pluck('id').sort();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An example: Free-mail users might just have '''webmail''' and '''contacts'''. If '''infostore''' is enabled for upsell, end-users will see the link to store mail attachments. But since this capability is missing, the event &amp;quot;upsell:requires-upgrade&amp;quot; is triggered which starts the upsell process. Upon successful completion this process should unlock the capability '''infostore''' for the end-user.&lt;br /&gt;
&lt;br /&gt;
The advantage of using rather atomic capabilities as the foundation for upsell is that developers don't have to consider and implement sales programs or marketing matrices in UI code.&lt;br /&gt;
&lt;br /&gt;
===Example dialog===&lt;br /&gt;
Whenever the event ''&amp;quot;upsell:requires-upgrade&amp;quot;'' is triggered there should be some response for the end-user. Usually an upsell dialog should open. This can be implemented as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
function showUpgradeDialog(e, options) {&lt;br /&gt;
    require(['io.ox/core/tk/dialogs'], function (dialogs) {&lt;br /&gt;
        new dialogs.ModalDialog({ easyOut: true })&lt;br /&gt;
            .build(function () {&lt;br /&gt;
                this.getHeader().append(&lt;br /&gt;
                    $('&amp;lt;h4&amp;gt;').text('Upgrade required')&lt;br /&gt;
                );&lt;br /&gt;
                this.getContentNode().append(&lt;br /&gt;
                    $.txt('This feature is not available.'),&lt;br /&gt;
                    $.txt('You need to upgrade your account now.'),&lt;br /&gt;
                    $.txt(' '),&lt;br /&gt;
                    $.txt('The first 90 days are free.')&lt;br /&gt;
                );&lt;br /&gt;
                this.addPrimaryButton('upgrade', 'Get free upgrade');&lt;br /&gt;
                this.addButton('cancel', 'Cancel');&lt;br /&gt;
            })&lt;br /&gt;
            .setUnderlayStyle({&lt;br /&gt;
                opacity: 0.70,&lt;br /&gt;
                backgroundColor: '#08C'&lt;br /&gt;
            })&lt;br /&gt;
            .on('upgrade', function () {&lt;br /&gt;
                ox.trigger('upsell:upgrade', options);&lt;br /&gt;
            })&lt;br /&gt;
            .on('show', function () {&lt;br /&gt;
                ox.off('upsell:requires-upgrade', showUpgradeDialog);&lt;br /&gt;
            })&lt;br /&gt;
            .on('close', function () {&lt;br /&gt;
                ox.on('upsell:requires-upgrade', showUpgradeDialog);&lt;br /&gt;
            })&lt;br /&gt;
            .show();&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function upgrade(e, options) {&lt;br /&gt;
    console.debug('upgrade', options);&lt;br /&gt;
    alert('User decided to upgrade! (global event: upsell:upgrade)');&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ox.on('upsell:requires-upgrade', showUpgradeDialog);&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * convention: 'upsell:upgrade' is used to trigger final upsell&lt;br /&gt;
 * the current user and user_id can be found in global variables ox.user and ox.user_id&lt;br /&gt;
 */&lt;br /&gt;
ox.on('upsell:upgrade', upgrade);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The second event '''&amp;quot;upsell:upgrade&amp;quot;''' can be understood as the final imperative to request the upsell server-side.&lt;br /&gt;
&lt;br /&gt;
===Example portal widget===&lt;br /&gt;
Besides waiting for the user to click on such links, it's always a good idea to offer explicit controls to trigger an upsell. One option is creating a portal widget that advertises a premium subscription:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
/**&lt;br /&gt;
 * This work is provided under the terms of the CREATIVE COMMONS PUBLIC&lt;br /&gt;
 * LICENSE. This work is protected by copyright and/or other applicable&lt;br /&gt;
 * law. Any use of the work other than as authorized under this license&lt;br /&gt;
 * or copyright law is prohibited.&lt;br /&gt;
 *&lt;br /&gt;
 * http://creativecommons.org/licenses/by-nc-sa/2.5/&lt;br /&gt;
 * © 2013 Open-Xchange Inc., Tarrytown, NY, USA. info@open-xchange.com&lt;br /&gt;
 *&lt;br /&gt;
 * @author Matthias Biggeleben &amp;lt;matthias.biggeleben@open-xchange.com&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
define('plugins/portal/upsell/register',&lt;br /&gt;
    ['io.ox/core/extensions',&lt;br /&gt;
     'io.ox/files/api',&lt;br /&gt;
     'gettext!plugins/portal'], function (ext, api, gt) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var title = gt('Upgrade to premium');&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget/upsell').extend({&lt;br /&gt;
&lt;br /&gt;
        title: title,&lt;br /&gt;
&lt;br /&gt;
        preview: function (baton) {&lt;br /&gt;
&lt;br /&gt;
            this.addClass('hide-title').append(&lt;br /&gt;
                $('&amp;amp;lt;div class=&amp;quot;content centered&amp;quot; style=&amp;quot;cursor: pointer; padding-top: 3em;&amp;quot;&amp;gt;').append(&lt;br /&gt;
                    $('&amp;amp;lt;h2&amp;gt;').append(&lt;br /&gt;
                        $.txt(title + ' '),&lt;br /&gt;
                        $('&amp;amp;lt;i class=&amp;quot;icon-star&amp;quot;&amp;gt;')&lt;br /&gt;
                    ),&lt;br /&gt;
                    $('&amp;amp;lt;div&amp;gt;').text(gt('Click here for free trial.'))&lt;br /&gt;
                )&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    ox.trigger('upsell:upgrade', {&lt;br /&gt;
                        type: 'widget',&lt;br /&gt;
                        id: 'io.ox/portal/widget/upsell',&lt;br /&gt;
                        missing: ''&lt;br /&gt;
                    });&lt;br /&gt;
                })&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Accessing upsell settings===&lt;br /&gt;
The upsell configuration is located in the namespace ''&amp;quot;io.ox/core&amp;quot;'', the path is ''&amp;quot;upsell/enabled&amp;quot;''. Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
// get all capabilities that can trigger upsell&lt;br /&gt;
require('settings!io.ox/core').get('upsell/enabled');&lt;br /&gt;
&lt;br /&gt;
// contains data like this&lt;br /&gt;
{&lt;br /&gt;
  infostore: true,&lt;br /&gt;
  portal: true,&lt;br /&gt;
  tasks: true&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If upsell is '''not''' enabled and the end-user lacks specific capabilities, the app or the inline-action is not shown. If upsell is enabled by the upper configuration, inline-actions are shown and trigger the upsell event ''&amp;quot;upsell:requires-upgrade&amp;quot;'' if clicked (but do not execute the action itself).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
/* &lt;br /&gt;
 * if you want to create your own controls, you can use the following helpers &lt;br /&gt;
 */&lt;br /&gt;
var upsell = require('io.ox/core/upsell');&lt;br /&gt;
&lt;br /&gt;
// check capabilities (space-separated) &lt;br /&gt;
upsell.has('portal webmail');&lt;br /&gt;
&lt;br /&gt;
// get missing capabilities (would return &amp;quot;calendar&amp;quot; in demo mode) &lt;br /&gt;
upsell.missing(['portal webmail', 'contacts', 'calendar']);&lt;br /&gt;
&lt;br /&gt;
/* checks if upsell is enabled for a set of capabilities &lt;br /&gt;
 * true if at least one set matches &lt;br /&gt;
 */&lt;br /&gt;
upsell.enabled(['portal webmail', 'webmail calendar']);&lt;br /&gt;
&lt;br /&gt;
/* convenience function: &amp;quot;visible&amp;quot; &lt;br /&gt;
 * checks if something should be visible depending on required capabilities &lt;br /&gt;
 * true if any item matches requires capabilities &lt;br /&gt;
 * true if any item does not match its requirements but is enabled for upsell &lt;br /&gt;
 * this function is used for any inline link, for example, to decide whether or not showing it &lt;br /&gt;
 */&lt;br /&gt;
upsell.visible(['portal webmail', 'contacts', 'calendar']);&lt;br /&gt;
&lt;br /&gt;
// likewise if neither capability set nor enabled for upsell, we get a false &lt;br /&gt;
upsell.visible(['foo']);&lt;br /&gt;
&lt;br /&gt;
// in case something weird happens (usually bad configuration) debug() helps&lt;br /&gt;
upsell.debug();&lt;br /&gt;
&lt;br /&gt;
// and this one&lt;br /&gt;
_(ox.serverConfig.capabilities).pluck('id').sort();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Upsell in OX6==&lt;br /&gt;
Please also consider [[Upsell|this article]] as it also covers backend aspects.&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:MSISDN&amp;diff=14968</id>
		<title>AppSuite:MSISDN</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:MSISDN&amp;diff=14968"/>
		<updated>2013-07-11T07:40:30Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Setting default sender address */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;MSISDN Support&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract.''' In this article, the support for MSISDN is described in detail. It allows sending emails to and receiving email from phone numbers.&lt;br /&gt;
__TOC__&lt;br /&gt;
== Enabling MSISDN Support ==&lt;br /&gt;
MSISDN support is disabled by default. In order to enable this feature, you must define the capability '''msisdn'''. This is done by simply adding the word &amp;quot;msisdn&amp;quot; to the property &amp;quot;permissions&amp;quot; in '''/opt/openexchange/etc/permission.properties''':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
permissions=...,msisdn&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Server Settings ==&lt;br /&gt;
&lt;br /&gt;
=== Default configuration ===&lt;br /&gt;
By default, cellular_telephone1 (551) and  cellular_telephone2 (552) are used for the phone number lookup. This setting applies for both the sender and the recipient dialogs. It can by configured as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
io.ox/contacts/msisdn/columns=['551', '552']&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemplary custom configuration ===&lt;br /&gt;
Adding another phone number is straight-forward. Just add it as follows, for example, telephone_other (553):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
io.ox/contacts/msisdn/columns=['551', '552', '553']&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See [[HTTP_API#DetailedContactData|HTTP API]] for all relevant columns.&lt;br /&gt;
&lt;br /&gt;
=== Setting default sender address ===&lt;br /&gt;
A phone number can also be configured as default sender address. This can be customized via the [[AppSuite:User_management#changeuser|changeuser]] interface. Relevant setting is ''defaultsenderaddress'':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
./changeuser ... --defaultsenderaddress &amp;lt;stringvalue&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:MSISDN&amp;diff=14966</id>
		<title>AppSuite:MSISDN</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:MSISDN&amp;diff=14966"/>
		<updated>2013-07-11T07:39:29Z</updated>

		<summary type="html">&lt;p&gt;Mattes: /* Setting default sender address */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;MSISDN Support&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract.''' In this article, the support for MSISDN is described in detail. It allows sending emails to and receiving email from phone numbers.&lt;br /&gt;
__TOC__&lt;br /&gt;
== Enabling MSISDN Support ==&lt;br /&gt;
MSISDN support is disabled by default. In order to enable this feature, you must define the capability '''msisdn'''. This is done by simply adding the word &amp;quot;msisdn&amp;quot; to the property &amp;quot;permissions&amp;quot; in '''/opt/openexchange/etc/permission.properties''':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
permissions=...,msisdn&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Server Settings ==&lt;br /&gt;
&lt;br /&gt;
=== Default configuration ===&lt;br /&gt;
By default, cellular_telephone1 (551) and  cellular_telephone2 (552) are used for the phone number lookup. This setting applies for both the sender and the recipient dialogs. It can by configured as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
io.ox/contacts/msisdn/columns=['551', '552']&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemplary custom configuration ===&lt;br /&gt;
Adding another phone number is straight-forward. Just add it as follows, for example, telephone_other (553):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
io.ox/contacts/msisdn/columns=['551', '552', '553']&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See [[HTTP_API#DetailedContactData|HTTP API]] for all relevant columns.&lt;br /&gt;
&lt;br /&gt;
=== Setting default sender address ===&lt;br /&gt;
A phone number can also be configured as default sender address. This can be customized via the [[AppSuite:User_management#changeuser|changeuser]] interface. Relevant setting is '''defaultsenderaddress'''.&lt;/div&gt;</summary>
		<author><name>Mattes</name></author>
	</entry>
</feed>