https://oxpedia.org/wiki/api.php?action=feedcontributions&user=Mark.schmidts&feedformat=atomOpen-Xchange - User contributions [en]2024-03-29T10:50:43ZUser contributionsMediaWiki 1.31.0https://oxpedia.org/wiki/index.php?title=AppSuite:Date_and_time&diff=16636AppSuite:Date and time2013-12-03T16:11:28Z<p>Mark.schmidts: /* Time Zones */</p>
<hr />
<div>{{Stability-experimental}}<br />
<br />
<div class="title">Date and Time</div><br />
<br />
The handling of date and time is a complicated mess of historical conventions, which are still changed from time to time by governments around the world. To keep this away from day-to-day activities of developers, the OX App Suite platform provides the module date, which performs conversion between different time zones, formatting and parsing of date and time values.<br />
<br />
== Time Zones ==<br />
<br />
The built-in JavaScript class Date supports calculations using UTC and the operating system's local time zone. Unfortunately, this is not enough. Examples include using a time zone different from the time zone of the client system, or displaying times in multiple time zones at once. For the examples to work in the way they are intended, it's obligatory to load the [[AppSuite:I18n | gettext module]], the date module itself and store them in variables <tt>gettext</tt> and <tt>date</tt>.<br />
<br />
<pre class="language-javascript"><br />
var gettext;<br />
var date;<br />
require(['gettext!example', 'io.ox/core/date']).done(function (gt, d) {<br />
gettext = gt;<br />
date = d;<br />
}); <br />
</pre><br />
<br />
The class Local is almost a drop-in replacement for Date, with the main difference being that it operates in the default time zone of the OX App Suite user, even if it is different from the time zone of the browser's operating system. The following code displays the current date and time. It will show a different time when called after changing the user's time zone.<br />
<br />
<pre class="language-javascript"><br />
alert(new date.Local());<br />
</pre><br />
<br />
To work with other time zones, the function <tt>getTimeZone()</tt> can be used to create replacement classes similar to Local, which are all descendants of the private class LocalDate (for which all methods are documented below). Since the time zone definitions are loaded on-demand, the function returns a jQuery promise, which is resolved to the class constructor once the time zone definition is loaded. This class can then be used to e.g. convert between time zones.<br />
<br />
<pre class="language-javascript"><br />
date.getTimeZone('America/New_York').done(function (NewYork) {<br />
alert(gettext('New York celebrated New Year\'s at %1$s',<br />
new date.Local(new NewYork(2012, 0, 1))));<br />
});<br />
</pre><br />
<br />
The function getTimeZone() is memoized for performance reasons, i.e. multiple calls with the same argument will return the same promise and will therefore resolve to the same class object.<br />
<br />
== Formatting ==<br />
<br />
The default <tt>LocalDate.prototype.toString()</tt> method displays the full date and time, including the day of week and the time zone. To allow better control of the resulting string, the method <tt>LocalDate.prototype.format()</tt> accepts a set of format flags. The flags determine, which fields should be included in the output. Currently, there are four flags:<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local();<br />
alert(d.format(date.DATE));<br />
alert(d.format(date.TIME));<br />
alert(d.format(date.DAYOFWEEK));<br />
alert(d.format(date.TIMEZONE));<br />
</pre><br />
<br />
Multiple flags can be combined by adding them, or by using one of the predefined combination constants. Not all possible combinations produce unique results. When DAYOFWEEK is specified together with any other fields, DATE is automatically included in the output. Similarly, TIMEZONE implies TIME when used with other fields.<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local();<br />
assert(d.format(date.DAYOFWEEK + date.TIMEZONE) === d.format(date.FULL_DATE);<br />
</pre><br />
<br />
The format flags select one of several predefined format strings, which is stored in the current locale settings. This frees both the developers and the translators from having to remember arcane letter combinations.<br />
<br />
For the case that even finer control of the generated output is required, LocalDate.prototype.format() accepts a format string directly. The syntax of the format strings is a subset of CLDR date format patterns. Format specifiers which are not used in the Gregorian calendar will be implemented on-demand.<br />
<br />
<pre class="language-javascript"><br />
alert(new date.Local().format('EEEE'));<br />
</pre><br />
<br />
In general, if format strings are required, this indicates that the current date API should be extended. Feedback is always welcome.<br />
<br />
One situation where direct access to format strings is useful, is the manipulation of the localized format strings, e.g. to decorate individual fields in a displayed date with HTML markup. To achieve this, the localized format string is retrieved with getFormat(), and parts of it passed individually to LocalDate.prototype.format().<br />
<br />
<pre class="language-javascript"><br />
// Get the original format string.<br />
var fmt = date.getFormat(date.FULL_DATE);<br />
<br />
// Regular expression to parse the format string.<br />
// . . ( time zone )|quote|'quoted text'|rest<br />
var re = /(v+|V+|z+|Z+)|(?:''|'(?:[^']|'')*'|[^vVzZ'])+/g;<br />
<br />
// Appends a formatted date to a jQuery node and returns<br />
// the time zone as a separate node.<br />
function decorateTimeZone(d, parent) {<br />
var span;<br />
fmt.replace(re, function (match, tz) {<br />
if (tz) { // found the time zone field<br />
// Wrap the formatted time zone in a <span> element.<br />
span = $('<span>').text(d.format(match));<br />
parent.append(result);<br />
} else {<br />
// Append all other formatted text as plain text nodes.<br />
parent.append($.txt(d.format(match)));<br />
}<br />
});<br />
// Return the wrapped field for further customization.<br />
return span;<br />
}<br />
</pre><br />
<br />
''Does anybody want this use case as an API function?''<br />
<br />
== Intervals ==<br />
<br />
In addition to formatting individual dates, LocalDate instances can format intervals. The difference to simply inserting two dates into a translated string is that short intervals may have a compacter representation, e.g. 'Jan 1–10, 2012' instead of 'Jan 1, 2012 – Jan 10, 2012'.<br />
<br />
<pre class="language-javascript"><br />
var start = new date.Local(), end = new date.Local(start);<br />
end.add(date.DAY);<br />
alert(start.formatInterval(end, date.DATE));<br />
</pre><br />
<br />
The methods LocalDate.prototype.formatInterval() and LocalDate.prototype.getIntervalFormat() are used like LocalDate.prototype.format() and getFormat(), with two differences. First, the interval functions accept the end of the interval as first parameter before the format flags. And second, since the format string depends on the actual interval, LocalDate.prototype.getIntervalFormat() is a member function and requires the same end value as used later for LocalDate.prototype.formatInterval().<br />
<br />
== Parsing ==<br />
<br />
Parsing is the reverse of formatting, except that ideally, users should be able to enter almost anything, as long as it is not ambiguous. The practice looks a bit more restricted. The LocalDate.parse() function takes a format parameter like the formatting functions, and expects the parsed string to match it very closely.<br />
<br />
<pre class="language-javascript"><br />
var input = prompt(gettext('Please enter a date'), '');<br />
var d = date.Local.parse(input, date.DATE);<br />
alert(gettext('I understood %1$s', d);<br />
</pre><br />
<br />
If there is demand, we can implement some heuristics. There are a lot of abstract algorithm descriptions in the standards, which describe how to parse almost anything while using the format string only as disambiguation help.<br />
<br />
== Manipulation of LocalDate objects ==<br />
<br />
Since the LocalDate class is designed as a drop-in for the Date class, its instances support getter and setter methods for all fields of a date. They can be used to modify an existing LocalDate object, e. g. to round a date to the nearest day or hour.<br />
<br />
<pre class="language-javascript"><br />
var start = new date.Local(), end = new date.Local(start);<br />
start.setHours(0, 0, 0, 0);<br />
end.setHours(24, 0, 0, 0);<br />
alert(gettext('Today is %1$s', start.formatInterval(end)));<br />
</pre><br />
<br />
One manipulation, which is often needed in calendars, is iteration over time. This operation seems simple, at least for iteration steps with a constant duration like hours, days or weeks. One just needs to add the step duration to the timestamp. While there is a method to do exactly this, LocalDate.prototype.addUTC(), you will encounter problems as soon as the iteration transcends a daylight savings switch. First, days and weeks are not actually constant. And second, sometimes the iteration might need to follow the displayed 'wall clock' time instead of the physical time. For these cases, the method LocalDate.prototype.add() increments the local time instead of the UTC time. Both methods accept an increment value in milliseconds, which can also be negative. There are predefined constants for the most common (almost-)fixed-duration periods.<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local(2012, 2);<br />
for (; d.getMonth() < 3; d.add(date.DAY)) {<br />
// Display a day in a month view.<br />
}<br />
</pre><br />
<br />
Iteration with larger intervals like months and years has the additional difficulty, that a single numeric parameter like 30 * date.DAY cannot be interpreted as a month, because it might be just really 30 days. To solve this, there are separate methods for months and years: LocalDate.prototype.addMonths() and LocalDate.prototype.addYears(). They accept the number of months, respective years as parameter.<br />
<br />
<pre class="language-javascript"> <br />
var d = new date.Local(2012, 0);<br />
for (; g.getYear() < 2013; d.addMonths(1)) {<br />
// Display a month in a year view.<br />
}<br />
</pre><br />
<br />
Finally, most calendars default to displaying the current date, and therefore need to figure out the iteration range based on an arbitrary point inside that range. In most cases, the start can be computed by simply calling the appropriate setters with all zeros as parameters to find the start of the range, and adding the range duration to find the end. One exception is the week. There is no setter for the day of the week. Instead, the method LocalDate.prototype.setStartOfWeek() can be used to find the start of a week.<br />
<br />
<pre class="language-javascript"> <br />
// Find the start and the end of the current week<br />
var d = new date.Local().setStartOfWeek();<br />
var end = new date.Local(start).add(date.WEEK);<br />
// Iterate over the week<br />
for (; d < end; d.add(date.DAY)) {<br />
// Display a day in a week view.<br />
}<br />
</pre><br />
<br />
In addition to explicit method calls, the JavaScript standard method LocalDate.prototype.valueOf() allows native comparison, addition and subtraction operators to work on LocalDate objects. The result of LocalDate.prototype.valueOf(), and therefore of addition and subtraction, is a timestamp, which can be passed to the LocalDate constructor to get a LocalDate object again.<br />
<br />
<pre class="language-javascript"> <br />
var start = date.Local.parse(prompt(gettext('Start date'), ''));<br />
var end = date.Local.parse(prompt(gettext('End date'), ''));<br />
if (end < start) alert(gettext('Invalid date range!'));<br />
</pre><br />
<br />
== Differences between LocalDate and Date ==<br />
<br />
The LocalDate classes duplicate most of the Date API with a few exceptions:<br />
<br />
* The constructor can not be called as a function. The Date constructor does in this case nothing useful anyway.<br />
* The constructor always uses full years, it does not add 1900 for years 0 to 99.<br />
* Date.UTC() should not be necessary, but since it returns a numeric timestamp and has nothing to do with time zones, it can still be used directly.<br />
* Except for LocalDate.prototype.toString(), all to*String() methods are replaced by LocalDate.prototype.format().<br />
* There are no UTC variants of getters and setters. They should not be necessary. But just in case, you can still use a LocalDate class for the time zone 'UTC' instead.<br />
* The getter and setter for the year are called getYear and setYear instead of getFullYear and setFullYear since we have no legacy code with Y2K issues.<br />
* Setters return the modified object instead of the timestamp. This is useful for chaining of method calls.<br />
* Date.prototype.getTimeZoneOffset() should not be necessary, since hiding these details is the whole point of the date module. If still necessary, LocalDate.getTTInfo() can be used instead.<br />
<br />
== API Reference ==<br />
<br />
This section provides a short reference of the date API.<br />
<br />
=== Locale ===<br />
<br />
A locale describes the localization settings which usually depend not only on the language, but also on the region and optionally even on the personal preferences of the user. The locale object is loaded at startup and provides various settings and translations.<br />
<br />
Various arrays containing translations can be used directly without any other date function.<br />
<br />
locale.dayPeriods<br />
A map from an identifier of a day period to the corresponding translation. The members am and pm are used in the 12h time format, but other members may be useful for greetings. Is anyone interested in a function which returns the correct greeting period for a given time? If not, maybe remove everything except AM and PM?<br />
locale.days<br />
An array with translated full names of days of the week, starting with Sunday. CLDR context: "format", CLDR width: "wide".<br />
locale.daysShort<br />
An array with translated abbreviated names of days of the week, starting with Sunday. CLDR context: "format", CLDR width: "abbreviated".<br />
locale.daysStandalone<br />
An array with translated standalone names of days of the week, starting with Sunday. CLDR context: "standalone", CLDR width: "abbreviated".<br />
locale.eras<br />
An array with translated abbreviations for the two eras of the Gregorian calendar: BC and AD (in that order).<br />
locale.months<br />
An array with translated full names of months. CLDR context: "format", CLDR width: "wide".<br />
locale.monthsShort<br />
An array with translated abbreviated names of months. CLDR context: "format", CLDR width: "abbreviated".<br />
Diverse week-based calculations need to know on which day the week starts and how the first week of the year is defined.<br />
<br />
locale.daysInFirstWeek<br />
The lowest number of days of a week which must be in the new year for that week to be considered week number 1. Common values are<br />
* 1 if the week of January 1st is week number 1,<br />
* 4 if the first week which has most of its days in the new year is week number 1.<br />
* 7 if the first week which starts in the new year is week number 1.<br />
locale.weekStart<br />
First day of the week. Common values are<br />
* 0 for Sunday,<br />
* 1 for Monday.<br />
Deprecated and internal fields should not be used since they can change or disappear entirely without notice. They are still documented here for completeness.<br />
<br />
locale.date<br />
Deprecated, use DATE instead.<br />
locale.dateTime<br />
Deprecated, use DATE_TIME instead.<br />
locale.dateTimeFormat<br />
The default format used to combine a time (%1$s) and a date (%2$s). Not used yet, will probably disappear.<br />
locale.formats<br />
A map from various canonical sets of format fields to the corresponding localized format strings. Used mainly by getFormat(). Maybe remove it from the public interface after loading, since it's internal?<br />
locale.h12<br />
A boolean indicating whether the 12h format is used. WANTED: a better name.<br />
locale.intervals<br />
A map from various canonical sets of format fields to the corresponding formatting rules. A formatting rule is a map from the largest field, which is different between the start and end of the interval, to the corresponding localized formatting string. The field is specified as a single lower case letter. The formatting string is split at the first repeating field. The first part is formatted using the start of the interval, the second part is formatted using the end of the interval. Used mainly by LocalDate.prototype.getIntervalFormat(). Maybe remove it from the public interface after loading, since it's internal?<br />
locale.intervals.fallback<br />
The default format string to combine the start (%1$s) and end (%2$s) of an interval when none of the other members of locale.intervals apply. Maybe remove it from the public interface after loading, since it's internal?<br />
locale.time<br />
Deprecated, use TIME instead.<br />
getTimeZone<br />
<br />
The main entry points of the date API are the class Local which replaces Date for use with the user's default time zone and a function to generate similar classes for arbitrary time zones.<br />
<br />
getTimeZone(name)<br />
Creates a LocalDate class which operates in the specified time zone. Multiple calls with the same name will return the same object.<br />
name String - The name of the requested time zone. It must be one of the values returned by api/config/availableTimeZones.<br />
Returns Promise - A promise which resolves to a LocalDate class which uses the requested time zone.<br />
Local<br />
A convenience LocalDate class which uses the user's current time zone.<br />
<br />
=== LocalDate ===<br />
<br />
The core of the date API is the abstract class LocalDate which is the superclass of time zone specific classes. The class itself is not publically available, only its subclasses can be created by calling getTimeZone(). The subclasses and their instances are referred to as LocalDate classes and LocalDate objects.<br />
<br />
The constructor mimics the behavior of the Date class, but it can't be called as a function.<br />
<br />
<pre class="language-javascript"> <br />
new LocalDate()<br />
new LocalDate(timestamp)<br />
new LocalDate(year, month, date, hours, minutes, seconds, ms)<br />
</pre><br />
<br />
The constructor accepts the same parameters as the Date constructor.<br />
The entire functionality of the class is based on a few low level functions. They should not be necessary outside the date module itself, assuming the API is complete. If you find you need these functions, please let's extend the high level APIs instead.<br />
<br />
LocalDate.getTTInfo(t)<br />
Returns the GMT offset, daylight savings and the abbreviation of the time zone which are in effect at the specified time.<br />
t Timestamp - The timestamp.<br />
Returns { gmtoff, isdst, abbr } - An object with the GMT offset in milliseconds, whether daylight savings are in effect (0 or 1, not a real boolean) and the abbreviation like 'CET' (!isdst) or 'CEST' (!!isdst).<br />
LocalDate.getTTInfoLocal(t)<br />
* Returns the GMT offset, daylight savings and the abbreviation of the time zone which are in effect at the specified local time. If the local time is ambiguous or invalid, the same fallbacks as for LocalDate.utc() are used. (It is actually implemented as a wrapper for this function.)<br />
* t Number - The local time.<br />
* Returns { gmtoff, isdst, abbr } - An object with the GMT offset in milliseconds, whether daylight savings are in effect (0 or 1, not a real boolean) and the abbreviation like 'CET' (!isdst) or 'CEST' (!!isdst).<br />
<br />
LocalDate.localTime(t)<br />
* Converts a UTC timestamp to local time.<br />
* t Timestamp - The UTC timestamp to convert.<br />
* Returns Number - A local time which is used in computations of date and time components.<br />
<br />
LocalDate.utc(t)<br />
* Converts local time to a UTC timestamp. If the local time is ambiguous because of a DST switch, the local time is interpreted as before the switch. E.g. 02:30 at the end of DST is interpreted as DST. If the local time is invalid because of a DST switch, the local time is interpreted as if the switch already occurred. E.g. 02:30 at the start of DST returns the same timestamp as 01:30 before the switch.<br />
* t Number - The local time to convert.<br />
* Returns Timestamp - The corresponsing UTC timestamp.<br />
Metadata about a time zone is stored directly on the LocalDate object.<br />
<br />
LocalDate.id<br />
* Original name used to retrieve this time zone.<br />
<br />
LocalDate.displayName<br />
* A human-readable name of this time zone as provided by the config module under "availableTimeZones".<br />
* Parsing of date and time strings as entered by a user is done using format flags from Constants. The current implementation expects the string to match the corresponding localized format string pretty closely. Any difficulties with parsing common entered dates and times should be taken as an opportunity to extend the parsing heuristics.<br />
<br />
LocalDate.parse(string, format)<br />
* Parses a string using either the specified format string or localized version of one of predefined format strings selected by format flags.<br />
* string String - The string to parse.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats.<br />
* Returns LocalDate or null - A new LocalDate object which represents the parsed date and time or null if the string could not be parsed.<br />
* Methods of LocalDate instances can be grouped into several categories. The first are the setters and getters for individual fields from Date. Since each LocalDate class has its own time zone, There are no UTC variants of each getter and setter. They all work with local time.<br />
<br />
<pre class="language-javascript"> <br />
LocalDate.prototype.getYear()<br />
LocalDate.prototype.getMonth()<br />
LocalDate.prototype.getDate()<br />
LocalDate.prototype.getHours()<br />
LocalDate.prototype.getMinutes()<br />
LocalDate.prototype.getSeconds()<br />
LocalDate.prototype.getMilliseconds()<br />
</pre><br />
* Return the corresponding field of the local date or time.<br />
* Returns Number - The requested field, as a number.<br />
<br />
<pre class="language-javascript"> <br />
LocalDate.prototype.setYear(year, month, date)<br />
LocalDate.prototype.setMonth(month, date)<br />
LocalDate.prototype.setDate(date)<br />
LocalDate.prototype.setHours(hour, min, sec, ms)<br />
LocalDate.prototype.setMinutes(min, sec, ms)<br />
LocalDate.prototype.setSeconds(sec, ms)<br />
LocalDate.prototype.setMilliseconds(ms)<br />
</pre><br />
* Set the specified date or time fields. Any unspecified fields retain their current value. Values outside of the specified ranges will result in overflow to the neighboring periods and can therefore be used for date arithmetic.<br />
** year Number - The year.<br />
** month Number - The month. Values range from 0 for January to 11 for December.<br />
** date Number - The date. Values range from 1 to 31.<br />
** hour Number - The hours. Values range from 0 to 23.<br />
** min Number - The minutes. Values range from 0 to 59.<br />
** sec Number - The seconds. Values range from 0 to 59.<br />
** ms Number - The milliseconds. Values range from 0 to 999.<br />
<br />
LocalDate.prototype.getDay()<br />
* Returns Number - The day of the week. Values range from 0 for Sunday to 6 for Saturday.<br />
<br />
LocalDate.prototype.getTimeZone()<br />
* This method is not present in Date. It returns the abbreviation of the specific time zone. The abbreviation indicate the GMT offset and is therefore different between daylight savings time and standard time.<br />
* Returns String - The abbreviation of the specific time zone.<br />
* Other getters and setters work with the entire timestamp and not just individual fields.<br />
<br />
LocalDate.prototype.getDays()<br />
* Returns the day number of this object. This may be useful to find the start of the same day (by multiplying the result with DAY).<br />
* Returns Number - The number of days since 1970-01-01 in this object's time zone.<br />
<br />
LocalDate.prototype.getTime()<br />
* Returns Timestamp - The UTC timestamp of this object.<br />
<br />
LocalDate.prototype.setTime(time)<br />
* Sets the UTC timestamp to a new value.<br />
* time Timestamp - The new UTC timestamp of this object.<br />
* While setters can be used to perform date arithmetic, LocalDate provides convenience functions for the most frequent cases of adding and subtracting a time period and finding the start of a week.<br />
<br />
LocalDate.prototype.add(time)<br />
* Adds or subtracts a time period in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
* time Number - The time period to add, in milliseconds. Use negative values to subtract. See also Constants.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addUTC(time)<br />
* Adds or subtracts a physical time period, i.e. simply increments the timestamp.<br />
time Number - The time period to add, in milliseconds. Use negative values to subtract. See also Constants.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addMonths(months)<br />
* Adds or subtracts a number of months in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
months Number - The number of months to add. Use negative values to subtract.<br />
Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addYears(years)<br />
* Adds or subtracts a number of years in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
years Number - The number of years to add. Use negative values to subtract.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.setStartOfWeek()<br />
* Sets the date to the start of the same week as determined by locale.weekStart. The time is reset to midnight.<br />
* Returns this - This object for chaining.<br />
* Formatting functions implement the conversion of dates and intervals into localized strings which are suitable for direct presentation to the user.<br />
<br />
LocalDate.prototype.format(format)<br />
* Formats the date according to the specified format flags or format string.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats. The default value is DATE_TIME.<br />
* Returns String - This object formatted according to the specified format.<br />
<br />
LocalDate.prototype.getIntervalFormat(end, format)<br />
* Returns a format string for a time interval with this object as the start and another LocalDate object as the end.<br />
* end LocalDate - The end of the interval.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.intervals and locale.formats. The default value is DATE_TIME.<br />
* Returns String - The format string for the interval accorging to the specified format.<br />
<br />
LocalDate.prototype.formatInterval(end, format)<br />
* Formats an interval with this object as the start and another LocalDate object as the end.<br />
end LocalDate - The end of the interval.<br />
format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.intervals and locale.formats. The default value is DATE_TIME.<br />
* Returns String - The interval formatted accorging to the specified format.<br />
* Finally, the JavaScript standard conversion functions allow easy debugging and arithmetic on timestamps.<br />
<br />
LocalDate.prototype.toString()<br />
* Converts this object to a string using this.format(FULL_DATE).<br />
* Returns String - The string representation of this object.<br />
<br />
LocalDate.prototype.valueOf()<br />
* Converts this object to a primitive value by returning the UTC timestamp. This can be used for arithmetic directly on LocalDate objects and as the single parameter to new LocalDate().<br />
* Returns Timestamp - The UTC timestamp of this object.<br />
<br />
=== Constants ===<br />
<br />
All date classes operate on timestamps expressed as milliseconds since the UNIX epoch, 1970-01-01 00:00 UTC. The date module defines constants for common time intervals with a constant duration.<br />
<br />
SECOND<br />
Number of milliseconds in a second.<br />
MINUTE<br />
Number of milliseconds in a minute.<br />
HOUR<br />
Number of milliseconds in an hour.<br />
DAY<br />
Number of milliseconds in a day.<br />
WEEK<br />
Number of milliseconds in a week.<br />
<br />
Format flags for parsing and formatting functions are defined as constants. Multiple flags can be combined via addition or bitwise ORing.<br />
<br />
<pre class="language-javascript"> <br />
DAYOFWEEK<br />
Day of the week<br />
DATE<br />
Date<br />
TIME<br />
Time<br />
TIMEZONE<br />
Timezone<br />
</pre><br />
Valid format flag combinations have dedicated constants. In a combination, DAYOFWEEK implies DATE and TIMEZONE implies TIME.<br />
<br />
<pre class="language-javascript"> <br />
DAYOFWEEK_DATE<br />
DAYOFWEEK + DATE<br />
DATE_TIME<br />
DATE + TIME<br />
DAYOFWEEK_DATE_TIME<br />
DAYOFWEEK + DATE + TIME<br />
TIME_TIMEZONE<br />
TIME + TIMEZONE<br />
DATE_TIME_TIMEZONE<br />
DATE + TIME + TIMEZONE<br />
FULL_DATE<br />
DAYOFWEEK + DATE + TIME + TIMEZONE<br />
Miscellaneous<br />
</pre><br />
See [[#Formatting|Formatting]] for usage of this function.<br />
<br />
getFormat(format)<br />
* Returns the localized format string for the specified format flags.<br />
format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats. The default value is DATE_TIME.<br />
* Returns String - The localized format string which corresponds to the specified format flags. If format is a string, that string is returned unmodified.<br />
<br />
[[Category:AppSuite]][[Category:UI]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Date_and_time&diff=16561AppSuite:Date and time2013-11-26T16:34:50Z<p>Mark.schmidts: /* Locale */</p>
<hr />
<div>{{Stability-experimental}}<br />
<br />
<div class="title">Date and Time</div><br />
<br />
The handling of date and time is a complicated mess of historical conventions, which are still changed from time to time by governments around the world. To keep this away from day-to-day activities of developers, the OX App Suite platform provides the module date, which performs conversion between different time zones, formatting and parsing of date and time values.<br />
<br />
== Time Zones ==<br />
<br />
The built-in JavaScript class Date supports calculations using UTC and the operating system's local time zone. Unfortunately, this is not enough. Examples include using a time zone different from the time zone of the client system, or displaying times in multiple time zones at once.<br />
<br />
The class Local is almost a drop-in replacement for Date, with the main difference being that it operates in the default time zone of the OX App Suite user, even if it is different from the time zone of the browser's operating system. The following code displays the current date and time. It will show a different time when called after changing the user's time zone.<br />
<br />
<pre class="language-javascript"><br />
alert(new date.Local());<br />
</pre><br />
<br />
To work with other time zones, the function <tt>getTimeZone()</tt> can be used to create replacement classes similar to Local, which are all descendants of the private class LocalDate (for which all methods are documented below). Since the time zone definitions are loaded on-demand, the function returns a jQuery promise, which is resolved to the class constructor once the time zone definition is loaded. This class can then be used to e.g. convert between time zones.<br />
<br />
<pre class="language-javascript"><br />
date.getTimeZone('America/New_York').done(function (NewYork) {<br />
alert(gettext('New York celebrated New Year\'s at %1$s',<br />
new date.Local(new NewYork(2012, 0, 1))));<br />
});<br />
</pre><br />
<br />
The function getTimeZone() is memoized for performance reasons, i.e. multiple calls with the same argument will return the same promise and will therefore resolve to the same class object.<br />
<br />
== Formatting ==<br />
<br />
The default <tt>LocalDate.prototype.toString()</tt> method displays the full date and time, including the day of week and the time zone. To allow better control of the resulting string, the method <tt>LocalDate.prototype.format()</tt> accepts a set of format flags. The flags determine, which fields should be included in the output. Currently, there are four flags:<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local();<br />
alert(d.format(date.DATE));<br />
alert(d.format(date.TIME));<br />
alert(d.format(date.DAYOFWEEK));<br />
alert(d.format(date.TIMEZONE));<br />
</pre><br />
<br />
Multiple flags can be combined by adding them, or by using one of the predefined combination constants. Not all possible combinations produce unique results. When DAYOFWEEK is specified together with any other fields, DATE is automatically included in the output. Similarly, TIMEZONE implies TIME when used with other fields.<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local();<br />
assert(d.format(date.DAYOFWEEK + date.TIMEZONE) === d.format(date.FULL_DATE);<br />
</pre><br />
<br />
The format flags select one of several predefined format strings, which is stored in the current locale settings. This frees both the developers and the translators from having to remember arcane letter combinations.<br />
<br />
For the case that even finer control of the generated output is required, LocalDate.prototype.format() accepts a format string directly. The syntax of the format strings is a subset of CLDR date format patterns. Format specifiers which are not used in the Gregorian calendar will be implemented on-demand.<br />
<br />
<pre class="language-javascript"><br />
alert(new date.Local().format('EEEE'));<br />
</pre><br />
<br />
In general, if format strings are required, this indicates that the current date API should be extended. Feedback is always welcome.<br />
<br />
One situation where direct access to format strings is useful, is the manipulation of the localized format strings, e.g. to decorate individual fields in a displayed date with HTML markup. To achieve this, the localized format string is retrieved with getFormat(), and parts of it passed individually to LocalDate.prototype.format().<br />
<br />
<pre class="language-javascript"><br />
// Get the original format string.<br />
var fmt = date.getFormat(date.FULL_DATE);<br />
<br />
// Regular expression to parse the format string.<br />
// . . ( time zone )|quote|'quoted text'|rest<br />
var re = /(v+|V+|z+|Z+)|(?:''|'(?:[^']|'')*'|[^vVzZ'])+/g;<br />
<br />
// Appends a formatted date to a jQuery node and returns<br />
// the time zone as a separate node.<br />
function decorateTimeZone(d, parent) {<br />
var span;<br />
fmt.replace(re, function (match, tz) {<br />
if (tz) { // found the time zone field<br />
// Wrap the formatted time zone in a <span> element.<br />
span = $('<span>').text(d.format(match));<br />
parent.append(result);<br />
} else {<br />
// Append all other formatted text as plain text nodes.<br />
parent.append($.txt(d.format(match)));<br />
}<br />
});<br />
// Return the wrapped field for further customization.<br />
return span;<br />
}<br />
</pre><br />
<br />
''Does anybody want this use case as an API function?''<br />
<br />
== Intervals ==<br />
<br />
In addition to formatting individual dates, LocalDate instances can format intervals. The difference to simply inserting two dates into a translated string is that short intervals may have a compacter representation, e.g. 'Jan 1–10, 2012' instead of 'Jan 1, 2012 – Jan 10, 2012'.<br />
<br />
<pre class="language-javascript"><br />
var start = new date.Local(), end = new date.Local(start);<br />
end.add(date.DAY);<br />
alert(start.formatInterval(end, date.DATE));<br />
</pre><br />
<br />
The methods LocalDate.prototype.formatInterval() and LocalDate.prototype.getIntervalFormat() are used like LocalDate.prototype.format() and getFormat(), with two differences. First, the interval functions accept the end of the interval as first parameter before the format flags. And second, since the format string depends on the actual interval, LocalDate.prototype.getIntervalFormat() is a member function and requires the same end value as used later for LocalDate.prototype.formatInterval().<br />
<br />
== Parsing ==<br />
<br />
Parsing is the reverse of formatting, except that ideally, users should be able to enter almost anything, as long as it is not ambiguous. The practice looks a bit more restricted. The LocalDate.parse() function takes a format parameter like the formatting functions, and expects the parsed string to match it very closely.<br />
<br />
<pre class="language-javascript"><br />
var input = prompt(gettext('Please enter a date'), '');<br />
var d = date.Local.parse(input, date.DATE);<br />
alert(gettext('I understood %1$s', d);<br />
</pre><br />
<br />
If there is demand, we can implement some heuristics. There are a lot of abstract algorithm descriptions in the standards, which describe how to parse almost anything while using the format string only as disambiguation help.<br />
<br />
== Manipulation of LocalDate objects ==<br />
<br />
Since the LocalDate class is designed as a drop-in for the Date class, its instances support getter and setter methods for all fields of a date. They can be used to modify an existing LocalDate object, e. g. to round a date to the nearest day or hour.<br />
<br />
<pre class="language-javascript"><br />
var start = new date.Local(), end = new date.Local(start);<br />
start.setHours(0, 0, 0, 0);<br />
end.setHours(24, 0, 0, 0);<br />
alert(gettext('Today is %1$s', start.formatInterval(end)));<br />
</pre><br />
<br />
One manipulation, which is often needed in calendars, is iteration over time. This operation seems simple, at least for iteration steps with a constant duration like hours, days or weeks. One just needs to add the step duration to the timestamp. While there is a method to do exactly this, LocalDate.prototype.addUTC(), you will encounter problems as soon as the iteration transcends a daylight savings switch. First, days and weeks are not actually constant. And second, sometimes the iteration might need to follow the displayed 'wall clock' time instead of the physical time. For these cases, the method LocalDate.prototype.add() increments the local time instead of the UTC time. Both methods accept an increment value in milliseconds, which can also be negative. There are predefined constants for the most common (almost-)fixed-duration periods.<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local(2012, 2);<br />
for (; d.getMonth() < 3; d.add(date.DAY)) {<br />
// Display a day in a month view.<br />
}<br />
</pre><br />
<br />
Iteration with larger intervals like months and years has the additional difficulty, that a single numeric parameter like 30 * date.DAY cannot be interpreted as a month, because it might be just really 30 days. To solve this, there are separate methods for months and years: LocalDate.prototype.addMonths() and LocalDate.prototype.addYears(). They accept the number of months, respective years as parameter.<br />
<br />
<pre class="language-javascript"> <br />
var d = new date.Local(2012, 0);<br />
for (; g.getYear() < 2013; d.addMonths(1)) {<br />
// Display a month in a year view.<br />
}<br />
</pre><br />
<br />
Finally, most calendars default to displaying the current date, and therefore need to figure out the iteration range based on an arbitrary point inside that range. In most cases, the start can be computed by simply calling the appropriate setters with all zeros as parameters to find the start of the range, and adding the range duration to find the end. One exception is the week. There is no setter for the day of the week. Instead, the method LocalDate.prototype.setStartOfWeek() can be used to find the start of a week.<br />
<br />
<pre class="language-javascript"> <br />
// Find the start and the end of the current week<br />
var d = new date.Local().setStartOfWeek();<br />
var end = new date.Local(start).add(date.WEEK);<br />
// Iterate over the week<br />
for (; d < end; d.add(date.DAY)) {<br />
// Display a day in a week view.<br />
}<br />
</pre><br />
<br />
In addition to explicit method calls, the JavaScript standard method LocalDate.prototype.valueOf() allows native comparison, addition and subtraction operators to work on LocalDate objects. The result of LocalDate.prototype.valueOf(), and therefore of addition and subtraction, is a timestamp, which can be passed to the LocalDate constructor to get a LocalDate object again.<br />
<br />
<pre class="language-javascript"> <br />
var start = date.Local.parse(prompt(gettext('Start date'), ''));<br />
var end = date.Local.parse(prompt(gettext('End date'), ''));<br />
if (end < start) alert(gettext('Invalid date range!'));<br />
</pre><br />
<br />
== Differences between LocalDate and Date ==<br />
<br />
The LocalDate classes duplicate most of the Date API with a few exceptions:<br />
<br />
* The constructor can not be called as a function. The Date constructor does in this case nothing useful anyway.<br />
* The constructor always uses full years, it does not add 1900 for years 0 to 99.<br />
* Date.UTC() should not be necessary, but since it returns a numeric timestamp and has nothing to do with time zones, it can still be used directly.<br />
* Except for LocalDate.prototype.toString(), all to*String() methods are replaced by LocalDate.prototype.format().<br />
* There are no UTC variants of getters and setters. They should not be necessary. But just in case, you can still use a LocalDate class for the time zone 'UTC' instead.<br />
* The getter and setter for the year are called getYear and setYear instead of getFullYear and setFullYear since we have no legacy code with Y2K issues.<br />
* Setters return the modified object instead of the timestamp. This is useful for chaining of method calls.<br />
* Date.prototype.getTimeZoneOffset() should not be necessary, since hiding these details is the whole point of the date module. If still necessary, LocalDate.getTTInfo() can be used instead.<br />
<br />
== API Reference ==<br />
<br />
This section provides a short reference of the date API.<br />
<br />
=== Locale ===<br />
<br />
A locale describes the localization settings which usually depend not only on the language, but also on the region and optionally even on the personal preferences of the user. The locale object is loaded at startup and provides various settings and translations.<br />
<br />
Various arrays containing translations can be used directly without any other date function.<br />
<br />
locale.dayPeriods<br />
A map from an identifier of a day period to the corresponding translation. The members am and pm are used in the 12h time format, but other members may be useful for greetings. Is anyone interested in a function which returns the correct greeting period for a given time? If not, maybe remove everything except AM and PM?<br />
locale.days<br />
An array with translated full names of days of the week, starting with Sunday. CLDR context: "format", CLDR width: "wide".<br />
locale.daysShort<br />
An array with translated abbreviated names of days of the week, starting with Sunday. CLDR context: "format", CLDR width: "abbreviated".<br />
locale.daysStandalone<br />
An array with translated standalone names of days of the week, starting with Sunday. CLDR context: "standalone", CLDR width: "abbreviated".<br />
locale.eras<br />
An array with translated abbreviations for the two eras of the Gregorian calendar: BC and AD (in that order).<br />
locale.months<br />
An array with translated full names of months. CLDR context: "format", CLDR width: "wide".<br />
locale.monthsShort<br />
An array with translated abbreviated names of months. CLDR context: "format", CLDR width: "abbreviated".<br />
Diverse week-based calculations need to know on which day the week starts and how the first week of the year is defined.<br />
<br />
locale.daysInFirstWeek<br />
The lowest number of days of a week which must be in the new year for that week to be considered week number 1. Common values are<br />
* 1 if the week of January 1st is week number 1,<br />
* 4 if the first week which has most of its days in the new year is week number 1.<br />
* 7 if the first week which starts in the new year is week number 1.<br />
locale.weekStart<br />
First day of the week. Common values are<br />
* 0 for Sunday,<br />
* 1 for Monday.<br />
Deprecated and internal fields should not be used since they can change or disappear entirely without notice. They are still documented here for completeness.<br />
<br />
locale.date<br />
Deprecated, use DATE instead.<br />
locale.dateTime<br />
Deprecated, use DATE_TIME instead.<br />
locale.dateTimeFormat<br />
The default format used to combine a time (%1$s) and a date (%2$s). Not used yet, will probably disappear.<br />
locale.formats<br />
A map from various canonical sets of format fields to the corresponding localized format strings. Used mainly by getFormat(). Maybe remove it from the public interface after loading, since it's internal?<br />
locale.h12<br />
A boolean indicating whether the 12h format is used. WANTED: a better name.<br />
locale.intervals<br />
A map from various canonical sets of format fields to the corresponding formatting rules. A formatting rule is a map from the largest field, which is different between the start and end of the interval, to the corresponding localized formatting string. The field is specified as a single lower case letter. The formatting string is split at the first repeating field. The first part is formatted using the start of the interval, the second part is formatted using the end of the interval. Used mainly by LocalDate.prototype.getIntervalFormat(). Maybe remove it from the public interface after loading, since it's internal?<br />
locale.intervals.fallback<br />
The default format string to combine the start (%1$s) and end (%2$s) of an interval when none of the other members of locale.intervals apply. Maybe remove it from the public interface after loading, since it's internal?<br />
locale.time<br />
Deprecated, use TIME instead.<br />
getTimeZone<br />
<br />
The main entry points of the date API are the class Local which replaces Date for use with the user's default time zone and a function to generate similar classes for arbitrary time zones.<br />
<br />
getTimeZone(name)<br />
Creates a LocalDate class which operates in the specified time zone. Multiple calls with the same name will return the same object.<br />
name String - The name of the requested time zone. It must be one of the values returned by api/config/availableTimeZones.<br />
Returns Promise - A promise which resolves to a LocalDate class which uses the requested time zone.<br />
Local<br />
A convenience LocalDate class which uses the user's current time zone.<br />
<br />
=== LocalDate ===<br />
<br />
The core of the date API is the abstract class LocalDate which is the superclass of time zone specific classes. The class itself is not publically available, only its subclasses can be created by calling getTimeZone(). The subclasses and their instances are referred to as LocalDate classes and LocalDate objects.<br />
<br />
The constructor mimics the behavior of the Date class, but it can't be called as a function.<br />
<br />
<pre class="language-javascript"> <br />
new LocalDate()<br />
new LocalDate(timestamp)<br />
new LocalDate(year, month, date, hours, minutes, seconds, ms)<br />
</pre><br />
<br />
The constructor accepts the same parameters as the Date constructor.<br />
The entire functionality of the class is based on a few low level functions. They should not be necessary outside the date module itself, assuming the API is complete. If you find you need these functions, please let's extend the high level APIs instead.<br />
<br />
LocalDate.getTTInfo(t)<br />
Returns the GMT offset, daylight savings and the abbreviation of the time zone which are in effect at the specified time.<br />
t Timestamp - The timestamp.<br />
Returns { gmtoff, isdst, abbr } - An object with the GMT offset in milliseconds, whether daylight savings are in effect (0 or 1, not a real boolean) and the abbreviation like 'CET' (!isdst) or 'CEST' (!!isdst).<br />
LocalDate.getTTInfoLocal(t)<br />
* Returns the GMT offset, daylight savings and the abbreviation of the time zone which are in effect at the specified local time. If the local time is ambiguous or invalid, the same fallbacks as for LocalDate.utc() are used. (It is actually implemented as a wrapper for this function.)<br />
* t Number - The local time.<br />
* Returns { gmtoff, isdst, abbr } - An object with the GMT offset in milliseconds, whether daylight savings are in effect (0 or 1, not a real boolean) and the abbreviation like 'CET' (!isdst) or 'CEST' (!!isdst).<br />
<br />
LocalDate.localTime(t)<br />
* Converts a UTC timestamp to local time.<br />
* t Timestamp - The UTC timestamp to convert.<br />
* Returns Number - A local time which is used in computations of date and time components.<br />
<br />
LocalDate.utc(t)<br />
* Converts local time to a UTC timestamp. If the local time is ambiguous because of a DST switch, the local time is interpreted as before the switch. E.g. 02:30 at the end of DST is interpreted as DST. If the local time is invalid because of a DST switch, the local time is interpreted as if the switch already occurred. E.g. 02:30 at the start of DST returns the same timestamp as 01:30 before the switch.<br />
* t Number - The local time to convert.<br />
* Returns Timestamp - The corresponsing UTC timestamp.<br />
Metadata about a time zone is stored directly on the LocalDate object.<br />
<br />
LocalDate.id<br />
* Original name used to retrieve this time zone.<br />
<br />
LocalDate.displayName<br />
* A human-readable name of this time zone as provided by the config module under "availableTimeZones".<br />
* Parsing of date and time strings as entered by a user is done using format flags from Constants. The current implementation expects the string to match the corresponding localized format string pretty closely. Any difficulties with parsing common entered dates and times should be taken as an opportunity to extend the parsing heuristics.<br />
<br />
LocalDate.parse(string, format)<br />
* Parses a string using either the specified format string or localized version of one of predefined format strings selected by format flags.<br />
* string String - The string to parse.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats.<br />
* Returns LocalDate or null - A new LocalDate object which represents the parsed date and time or null if the string could not be parsed.<br />
* Methods of LocalDate instances can be grouped into several categories. The first are the setters and getters for individual fields from Date. Since each LocalDate class has its own time zone, There are no UTC variants of each getter and setter. They all work with local time.<br />
<br />
<pre class="language-javascript"> <br />
LocalDate.prototype.getYear()<br />
LocalDate.prototype.getMonth()<br />
LocalDate.prototype.getDate()<br />
LocalDate.prototype.getHours()<br />
LocalDate.prototype.getMinutes()<br />
LocalDate.prototype.getSeconds()<br />
LocalDate.prototype.getMilliseconds()<br />
</pre><br />
* Return the corresponding field of the local date or time.<br />
* Returns Number - The requested field, as a number.<br />
<br />
<pre class="language-javascript"> <br />
LocalDate.prototype.setYear(year, month, date)<br />
LocalDate.prototype.setMonth(month, date)<br />
LocalDate.prototype.setDate(date)<br />
LocalDate.prototype.setHours(hour, min, sec, ms)<br />
LocalDate.prototype.setMinutes(min, sec, ms)<br />
LocalDate.prototype.setSeconds(sec, ms)<br />
LocalDate.prototype.setMilliseconds(ms)<br />
</pre><br />
* Set the specified date or time fields. Any unspecified fields retain their current value. Values outside of the specified ranges will result in overflow to the neighboring periods and can therefore be used for date arithmetic.<br />
** year Number - The year.<br />
** month Number - The month. Values range from 0 for January to 11 for December.<br />
** date Number - The date. Values range from 1 to 31.<br />
** hour Number - The hours. Values range from 0 to 23.<br />
** min Number - The minutes. Values range from 0 to 59.<br />
** sec Number - The seconds. Values range from 0 to 59.<br />
** ms Number - The milliseconds. Values range from 0 to 999.<br />
<br />
LocalDate.prototype.getDay()<br />
* Returns Number - The day of the week. Values range from 0 for Sunday to 6 for Saturday.<br />
<br />
LocalDate.prototype.getTimeZone()<br />
* This method is not present in Date. It returns the abbreviation of the specific time zone. The abbreviation indicate the GMT offset and is therefore different between daylight savings time and standard time.<br />
* Returns String - The abbreviation of the specific time zone.<br />
* Other getters and setters work with the entire timestamp and not just individual fields.<br />
<br />
LocalDate.prototype.getDays()<br />
* Returns the day number of this object. This may be useful to find the start of the same day (by multiplying the result with DAY).<br />
* Returns Number - The number of days since 1970-01-01 in this object's time zone.<br />
<br />
LocalDate.prototype.getTime()<br />
* Returns Timestamp - The UTC timestamp of this object.<br />
<br />
LocalDate.prototype.setTime(time)<br />
* Sets the UTC timestamp to a new value.<br />
* time Timestamp - The new UTC timestamp of this object.<br />
* While setters can be used to perform date arithmetic, LocalDate provides convenience functions for the most frequent cases of adding and subtracting a time period and finding the start of a week.<br />
<br />
LocalDate.prototype.add(time)<br />
* Adds or subtracts a time period in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
* time Number - The time period to add, in milliseconds. Use negative values to subtract. See also Constants.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addUTC(time)<br />
* Adds or subtracts a physical time period, i.e. simply increments the timestamp.<br />
time Number - The time period to add, in milliseconds. Use negative values to subtract. See also Constants.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addMonths(months)<br />
* Adds or subtracts a number of months in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
months Number - The number of months to add. Use negative values to subtract.<br />
Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addYears(years)<br />
* Adds or subtracts a number of years in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
years Number - The number of years to add. Use negative values to subtract.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.setStartOfWeek()<br />
* Sets the date to the start of the same week as determined by locale.weekStart. The time is reset to midnight.<br />
* Returns this - This object for chaining.<br />
* Formatting functions implement the conversion of dates and intervals into localized strings which are suitable for direct presentation to the user.<br />
<br />
LocalDate.prototype.format(format)<br />
* Formats the date according to the specified format flags or format string.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats. The default value is DATE_TIME.<br />
* Returns String - This object formatted according to the specified format.<br />
<br />
LocalDate.prototype.getIntervalFormat(end, format)<br />
* Returns a format string for a time interval with this object as the start and another LocalDate object as the end.<br />
* end LocalDate - The end of the interval.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.intervals and locale.formats. The default value is DATE_TIME.<br />
* Returns String - The format string for the interval accorging to the specified format.<br />
<br />
LocalDate.prototype.formatInterval(end, format)<br />
* Formats an interval with this object as the start and another LocalDate object as the end.<br />
end LocalDate - The end of the interval.<br />
format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.intervals and locale.formats. The default value is DATE_TIME.<br />
* Returns String - The interval formatted accorging to the specified format.<br />
* Finally, the JavaScript standard conversion functions allow easy debugging and arithmetic on timestamps.<br />
<br />
LocalDate.prototype.toString()<br />
* Converts this object to a string using this.format(FULL_DATE).<br />
* Returns String - The string representation of this object.<br />
<br />
LocalDate.prototype.valueOf()<br />
* Converts this object to a primitive value by returning the UTC timestamp. This can be used for arithmetic directly on LocalDate objects and as the single parameter to new LocalDate().<br />
* Returns Timestamp - The UTC timestamp of this object.<br />
<br />
=== Constants ===<br />
<br />
All date classes operate on timestamps expressed as milliseconds since the UNIX epoch, 1970-01-01 00:00 UTC. The date module defines constants for common time intervals with a constant duration.<br />
<br />
SECOND<br />
Number of milliseconds in a second.<br />
MINUTE<br />
Number of milliseconds in a minute.<br />
HOUR<br />
Number of milliseconds in an hour.<br />
DAY<br />
Number of milliseconds in a day.<br />
WEEK<br />
Number of milliseconds in a week.<br />
<br />
Format flags for parsing and formatting functions are defined as constants. Multiple flags can be combined via addition or bitwise ORing.<br />
<br />
<pre class="language-javascript"> <br />
DAYOFWEEK<br />
Day of the week<br />
DATE<br />
Date<br />
TIME<br />
Time<br />
TIMEZONE<br />
Timezone<br />
</pre><br />
Valid format flag combinations have dedicated constants. In a combination, DAYOFWEEK implies DATE and TIMEZONE implies TIME.<br />
<br />
<pre class="language-javascript"> <br />
DAYOFWEEK_DATE<br />
DAYOFWEEK + DATE<br />
DATE_TIME<br />
DATE + TIME<br />
DAYOFWEEK_DATE_TIME<br />
DAYOFWEEK + DATE + TIME<br />
TIME_TIMEZONE<br />
TIME + TIMEZONE<br />
DATE_TIME_TIMEZONE<br />
DATE + TIME + TIMEZONE<br />
FULL_DATE<br />
DAYOFWEEK + DATE + TIME + TIMEZONE<br />
Miscellaneous<br />
</pre><br />
See [[#Formatting|Formatting]] for usage of this function.<br />
<br />
getFormat(format)<br />
* Returns the localized format string for the specified format flags.<br />
format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats. The default value is DATE_TIME.<br />
* Returns String - The localized format string which corresponds to the specified format flags. If format is a string, that string is returned unmodified.<br />
<br />
[[Category:AppSuite]][[Category:UI]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Date_and_time&diff=16560AppSuite:Date and time2013-11-26T16:33:31Z<p>Mark.schmidts: /* Locale */</p>
<hr />
<div>{{Stability-experimental}}<br />
<br />
<div class="title">Date and Time</div><br />
<br />
The handling of date and time is a complicated mess of historical conventions, which are still changed from time to time by governments around the world. To keep this away from day-to-day activities of developers, the OX App Suite platform provides the module date, which performs conversion between different time zones, formatting and parsing of date and time values.<br />
<br />
== Time Zones ==<br />
<br />
The built-in JavaScript class Date supports calculations using UTC and the operating system's local time zone. Unfortunately, this is not enough. Examples include using a time zone different from the time zone of the client system, or displaying times in multiple time zones at once.<br />
<br />
The class Local is almost a drop-in replacement for Date, with the main difference being that it operates in the default time zone of the OX App Suite user, even if it is different from the time zone of the browser's operating system. The following code displays the current date and time. It will show a different time when called after changing the user's time zone.<br />
<br />
<pre class="language-javascript"><br />
alert(new date.Local());<br />
</pre><br />
<br />
To work with other time zones, the function <tt>getTimeZone()</tt> can be used to create replacement classes similar to Local, which are all descendants of the private class LocalDate (for which all methods are documented below). Since the time zone definitions are loaded on-demand, the function returns a jQuery promise, which is resolved to the class constructor once the time zone definition is loaded. This class can then be used to e.g. convert between time zones.<br />
<br />
<pre class="language-javascript"><br />
date.getTimeZone('America/New_York').done(function (NewYork) {<br />
alert(gettext('New York celebrated New Year\'s at %1$s',<br />
new date.Local(new NewYork(2012, 0, 1))));<br />
});<br />
</pre><br />
<br />
The function getTimeZone() is memoized for performance reasons, i.e. multiple calls with the same argument will return the same promise and will therefore resolve to the same class object.<br />
<br />
== Formatting ==<br />
<br />
The default <tt>LocalDate.prototype.toString()</tt> method displays the full date and time, including the day of week and the time zone. To allow better control of the resulting string, the method <tt>LocalDate.prototype.format()</tt> accepts a set of format flags. The flags determine, which fields should be included in the output. Currently, there are four flags:<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local();<br />
alert(d.format(date.DATE));<br />
alert(d.format(date.TIME));<br />
alert(d.format(date.DAYOFWEEK));<br />
alert(d.format(date.TIMEZONE));<br />
</pre><br />
<br />
Multiple flags can be combined by adding them, or by using one of the predefined combination constants. Not all possible combinations produce unique results. When DAYOFWEEK is specified together with any other fields, DATE is automatically included in the output. Similarly, TIMEZONE implies TIME when used with other fields.<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local();<br />
assert(d.format(date.DAYOFWEEK + date.TIMEZONE) === d.format(date.FULL_DATE);<br />
</pre><br />
<br />
The format flags select one of several predefined format strings, which is stored in the current locale settings. This frees both the developers and the translators from having to remember arcane letter combinations.<br />
<br />
For the case that even finer control of the generated output is required, LocalDate.prototype.format() accepts a format string directly. The syntax of the format strings is a subset of CLDR date format patterns. Format specifiers which are not used in the Gregorian calendar will be implemented on-demand.<br />
<br />
<pre class="language-javascript"><br />
alert(new date.Local().format('EEEE'));<br />
</pre><br />
<br />
In general, if format strings are required, this indicates that the current date API should be extended. Feedback is always welcome.<br />
<br />
One situation where direct access to format strings is useful, is the manipulation of the localized format strings, e.g. to decorate individual fields in a displayed date with HTML markup. To achieve this, the localized format string is retrieved with getFormat(), and parts of it passed individually to LocalDate.prototype.format().<br />
<br />
<pre class="language-javascript"><br />
// Get the original format string.<br />
var fmt = date.getFormat(date.FULL_DATE);<br />
<br />
// Regular expression to parse the format string.<br />
// . . ( time zone )|quote|'quoted text'|rest<br />
var re = /(v+|V+|z+|Z+)|(?:''|'(?:[^']|'')*'|[^vVzZ'])+/g;<br />
<br />
// Appends a formatted date to a jQuery node and returns<br />
// the time zone as a separate node.<br />
function decorateTimeZone(d, parent) {<br />
var span;<br />
fmt.replace(re, function (match, tz) {<br />
if (tz) { // found the time zone field<br />
// Wrap the formatted time zone in a <span> element.<br />
span = $('<span>').text(d.format(match));<br />
parent.append(result);<br />
} else {<br />
// Append all other formatted text as plain text nodes.<br />
parent.append($.txt(d.format(match)));<br />
}<br />
});<br />
// Return the wrapped field for further customization.<br />
return span;<br />
}<br />
</pre><br />
<br />
''Does anybody want this use case as an API function?''<br />
<br />
== Intervals ==<br />
<br />
In addition to formatting individual dates, LocalDate instances can format intervals. The difference to simply inserting two dates into a translated string is that short intervals may have a compacter representation, e.g. 'Jan 1–10, 2012' instead of 'Jan 1, 2012 – Jan 10, 2012'.<br />
<br />
<pre class="language-javascript"><br />
var start = new date.Local(), end = new date.Local(start);<br />
end.add(date.DAY);<br />
alert(start.formatInterval(end, date.DATE));<br />
</pre><br />
<br />
The methods LocalDate.prototype.formatInterval() and LocalDate.prototype.getIntervalFormat() are used like LocalDate.prototype.format() and getFormat(), with two differences. First, the interval functions accept the end of the interval as first parameter before the format flags. And second, since the format string depends on the actual interval, LocalDate.prototype.getIntervalFormat() is a member function and requires the same end value as used later for LocalDate.prototype.formatInterval().<br />
<br />
== Parsing ==<br />
<br />
Parsing is the reverse of formatting, except that ideally, users should be able to enter almost anything, as long as it is not ambiguous. The practice looks a bit more restricted. The LocalDate.parse() function takes a format parameter like the formatting functions, and expects the parsed string to match it very closely.<br />
<br />
<pre class="language-javascript"><br />
var input = prompt(gettext('Please enter a date'), '');<br />
var d = date.Local.parse(input, date.DATE);<br />
alert(gettext('I understood %1$s', d);<br />
</pre><br />
<br />
If there is demand, we can implement some heuristics. There are a lot of abstract algorithm descriptions in the standards, which describe how to parse almost anything while using the format string only as disambiguation help.<br />
<br />
== Manipulation of LocalDate objects ==<br />
<br />
Since the LocalDate class is designed as a drop-in for the Date class, its instances support getter and setter methods for all fields of a date. They can be used to modify an existing LocalDate object, e. g. to round a date to the nearest day or hour.<br />
<br />
<pre class="language-javascript"><br />
var start = new date.Local(), end = new date.Local(start);<br />
start.setHours(0, 0, 0, 0);<br />
end.setHours(24, 0, 0, 0);<br />
alert(gettext('Today is %1$s', start.formatInterval(end)));<br />
</pre><br />
<br />
One manipulation, which is often needed in calendars, is iteration over time. This operation seems simple, at least for iteration steps with a constant duration like hours, days or weeks. One just needs to add the step duration to the timestamp. While there is a method to do exactly this, LocalDate.prototype.addUTC(), you will encounter problems as soon as the iteration transcends a daylight savings switch. First, days and weeks are not actually constant. And second, sometimes the iteration might need to follow the displayed 'wall clock' time instead of the physical time. For these cases, the method LocalDate.prototype.add() increments the local time instead of the UTC time. Both methods accept an increment value in milliseconds, which can also be negative. There are predefined constants for the most common (almost-)fixed-duration periods.<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local(2012, 2);<br />
for (; d.getMonth() < 3; d.add(date.DAY)) {<br />
// Display a day in a month view.<br />
}<br />
</pre><br />
<br />
Iteration with larger intervals like months and years has the additional difficulty, that a single numeric parameter like 30 * date.DAY cannot be interpreted as a month, because it might be just really 30 days. To solve this, there are separate methods for months and years: LocalDate.prototype.addMonths() and LocalDate.prototype.addYears(). They accept the number of months, respective years as parameter.<br />
<br />
<pre class="language-javascript"> <br />
var d = new date.Local(2012, 0);<br />
for (; g.getYear() < 2013; d.addMonths(1)) {<br />
// Display a month in a year view.<br />
}<br />
</pre><br />
<br />
Finally, most calendars default to displaying the current date, and therefore need to figure out the iteration range based on an arbitrary point inside that range. In most cases, the start can be computed by simply calling the appropriate setters with all zeros as parameters to find the start of the range, and adding the range duration to find the end. One exception is the week. There is no setter for the day of the week. Instead, the method LocalDate.prototype.setStartOfWeek() can be used to find the start of a week.<br />
<br />
<pre class="language-javascript"> <br />
// Find the start and the end of the current week<br />
var d = new date.Local().setStartOfWeek();<br />
var end = new date.Local(start).add(date.WEEK);<br />
// Iterate over the week<br />
for (; d < end; d.add(date.DAY)) {<br />
// Display a day in a week view.<br />
}<br />
</pre><br />
<br />
In addition to explicit method calls, the JavaScript standard method LocalDate.prototype.valueOf() allows native comparison, addition and subtraction operators to work on LocalDate objects. The result of LocalDate.prototype.valueOf(), and therefore of addition and subtraction, is a timestamp, which can be passed to the LocalDate constructor to get a LocalDate object again.<br />
<br />
<pre class="language-javascript"> <br />
var start = date.Local.parse(prompt(gettext('Start date'), ''));<br />
var end = date.Local.parse(prompt(gettext('End date'), ''));<br />
if (end < start) alert(gettext('Invalid date range!'));<br />
</pre><br />
<br />
== Differences between LocalDate and Date ==<br />
<br />
The LocalDate classes duplicate most of the Date API with a few exceptions:<br />
<br />
* The constructor can not be called as a function. The Date constructor does in this case nothing useful anyway.<br />
* The constructor always uses full years, it does not add 1900 for years 0 to 99.<br />
* Date.UTC() should not be necessary, but since it returns a numeric timestamp and has nothing to do with time zones, it can still be used directly.<br />
* Except for LocalDate.prototype.toString(), all to*String() methods are replaced by LocalDate.prototype.format().<br />
* There are no UTC variants of getters and setters. They should not be necessary. But just in case, you can still use a LocalDate class for the time zone 'UTC' instead.<br />
* The getter and setter for the year are called getYear and setYear instead of getFullYear and setFullYear since we have no legacy code with Y2K issues.<br />
* Setters return the modified object instead of the timestamp. This is useful for chaining of method calls.<br />
* Date.prototype.getTimeZoneOffset() should not be necessary, since hiding these details is the whole point of the date module. If still necessary, LocalDate.getTTInfo() can be used instead.<br />
<br />
== API Reference ==<br />
<br />
This section provides a short reference of the date API.<br />
<br />
=== Locale ===<br />
<br />
A locale describes the localization settings which usually depend not only on the language, but also on the region and optionally even on the personal preferences of the user. The locale object is loaded at startup and provides various settings and translations.<br />
<br />
Various arrays containing translations can be used directly without any other date function.<br />
<br />
locale.dayPeriods<br />
A map from an identifier of a day period to the corresponding translation. The members am and pm are used in the 12h time format, but other members may be useful for greetings. Is anyone interested in a function which returns the correct greeting period for a given time? If not, maybe remove everything except AM and PM?<br />
locale.days<br />
An array with translated full names of days of the week, starting with Sunday. CLDR context: "format", CLDR width: "wide".<br />
locale.daysShort<br />
An array with translated abbreviated names of days of the week, starting with Sunday. CLDR context: "format", CLDR width: "abbreviated".<br />
locale.daysStandalone<br />
An array with translated standalone names of days of the week, starting with Sunday. CLDR context: "standalone", CLDR width: "abbreviated".<br />
locale.eras<br />
An array with translated abbreviations for the two eras of the Gregorian calendar: BC and AD (in that order).<br />
locale.months<br />
An array with translated full names of months. CLDR context: "format", CLDR width: "wide".<br />
locale.monthsShort<br />
An array with translated abbreviated names of months. CLDR context: "format", CLDR width: "abbreviated".<br />
Diverse week-based calculations need to know on which day the week starts and how the first week of the year is defined.<br />
<br />
locale.daysInFirstWeek<br />
The lowest number of days of a week which must be in the new year for that week to be considered week number 1. Common values are<br />
* 1 if the week of January 1st is week number 1,<br />
* 4 if the first week which has most of its days in the new year is week number 1.<br />
* 7 if the first week which starts in the new year is week number 1.<br />
locale.weekStart<br />
First day of the week. Common values are<br />
* 0 for Sunday,<br />
* 1 for Monday.<br />
Deprecated and internal fields should not be used since they can change or disappear entirely without notice. They are still documented here for completeness.<br />
<br />
locale.date<br />
Deprecated, use DATE instead.<br />
locale.dateTime<br />
Deprecated, use DATE_TIMEinstead.<br />
locale.dateTimeFormat<br />
The default format used to combine a time (%1$s) and a date (%2$s). Not used yet, will probably disappear.<br />
locale.formats<br />
A map from various canonical sets of format fields to the corresponding localized format strings. Used mainly by getFormat(). Maybe remove it from the public interface after loading, since it's internal?<br />
locale.h12<br />
A boolean indicating whether the 12h format is used. WANTED: a better name.<br />
locale.intervals<br />
A map from various canonical sets of format fields to the corresponding formatting rules. A formatting rule is a map from the largest field, which is different between the start and end of the interval, to the corresponding localized formatting string. The field is specified as a single lower case letter. The formatting string is split at the first repeating field. The first part is formatted using the start of the interval, the second part is formatted using the end of the interval. Used mainly by LocalDate.prototype.getIntervalFormat(). Maybe remove it from the public interface after loading, since it's internal?<br />
locale.intervals.fallback<br />
The default format string to combine the start (%1$s) and end (%2$s) of an interval when none of the other members of locale.intervals apply. Maybe remove it from the public interface after loading, since it's internal?<br />
locale.time<br />
Deprecated, use TIME instead.<br />
getTimeZone<br />
<br />
The main entry points of the date API are the class Local which replaces Date for use with the user's default time zone and a function to generate similar classes for arbitrary time zones.<br />
<br />
getTimeZone(name)<br />
Creates a LocalDate class which operates in the specified time zone. Multiple calls with the same name will return the same object.<br />
name String - The name of the requested time zone. It must be one of the values returned by api/config/availableTimeZones.<br />
Returns Promise - A promise which resolves to a LocalDate class which uses the requested time zone.<br />
Local<br />
A convenience LocalDate class which uses the user's current time zone.<br />
<br />
=== LocalDate ===<br />
<br />
The core of the date API is the abstract class LocalDate which is the superclass of time zone specific classes. The class itself is not publically available, only its subclasses can be created by calling getTimeZone(). The subclasses and their instances are referred to as LocalDate classes and LocalDate objects.<br />
<br />
The constructor mimics the behavior of the Date class, but it can't be called as a function.<br />
<br />
<pre class="language-javascript"> <br />
new LocalDate()<br />
new LocalDate(timestamp)<br />
new LocalDate(year, month, date, hours, minutes, seconds, ms)<br />
</pre><br />
<br />
The constructor accepts the same parameters as the Date constructor.<br />
The entire functionality of the class is based on a few low level functions. They should not be necessary outside the date module itself, assuming the API is complete. If you find you need these functions, please let's extend the high level APIs instead.<br />
<br />
LocalDate.getTTInfo(t)<br />
Returns the GMT offset, daylight savings and the abbreviation of the time zone which are in effect at the specified time.<br />
t Timestamp - The timestamp.<br />
Returns { gmtoff, isdst, abbr } - An object with the GMT offset in milliseconds, whether daylight savings are in effect (0 or 1, not a real boolean) and the abbreviation like 'CET' (!isdst) or 'CEST' (!!isdst).<br />
LocalDate.getTTInfoLocal(t)<br />
* Returns the GMT offset, daylight savings and the abbreviation of the time zone which are in effect at the specified local time. If the local time is ambiguous or invalid, the same fallbacks as for LocalDate.utc() are used. (It is actually implemented as a wrapper for this function.)<br />
* t Number - The local time.<br />
* Returns { gmtoff, isdst, abbr } - An object with the GMT offset in milliseconds, whether daylight savings are in effect (0 or 1, not a real boolean) and the abbreviation like 'CET' (!isdst) or 'CEST' (!!isdst).<br />
<br />
LocalDate.localTime(t)<br />
* Converts a UTC timestamp to local time.<br />
* t Timestamp - The UTC timestamp to convert.<br />
* Returns Number - A local time which is used in computations of date and time components.<br />
<br />
LocalDate.utc(t)<br />
* Converts local time to a UTC timestamp. If the local time is ambiguous because of a DST switch, the local time is interpreted as before the switch. E.g. 02:30 at the end of DST is interpreted as DST. If the local time is invalid because of a DST switch, the local time is interpreted as if the switch already occurred. E.g. 02:30 at the start of DST returns the same timestamp as 01:30 before the switch.<br />
* t Number - The local time to convert.<br />
* Returns Timestamp - The corresponsing UTC timestamp.<br />
Metadata about a time zone is stored directly on the LocalDate object.<br />
<br />
LocalDate.id<br />
* Original name used to retrieve this time zone.<br />
<br />
LocalDate.displayName<br />
* A human-readable name of this time zone as provided by the config module under "availableTimeZones".<br />
* Parsing of date and time strings as entered by a user is done using format flags from Constants. The current implementation expects the string to match the corresponding localized format string pretty closely. Any difficulties with parsing common entered dates and times should be taken as an opportunity to extend the parsing heuristics.<br />
<br />
LocalDate.parse(string, format)<br />
* Parses a string using either the specified format string or localized version of one of predefined format strings selected by format flags.<br />
* string String - The string to parse.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats.<br />
* Returns LocalDate or null - A new LocalDate object which represents the parsed date and time or null if the string could not be parsed.<br />
* Methods of LocalDate instances can be grouped into several categories. The first are the setters and getters for individual fields from Date. Since each LocalDate class has its own time zone, There are no UTC variants of each getter and setter. They all work with local time.<br />
<br />
<pre class="language-javascript"> <br />
LocalDate.prototype.getYear()<br />
LocalDate.prototype.getMonth()<br />
LocalDate.prototype.getDate()<br />
LocalDate.prototype.getHours()<br />
LocalDate.prototype.getMinutes()<br />
LocalDate.prototype.getSeconds()<br />
LocalDate.prototype.getMilliseconds()<br />
</pre><br />
* Return the corresponding field of the local date or time.<br />
* Returns Number - The requested field, as a number.<br />
<br />
<pre class="language-javascript"> <br />
LocalDate.prototype.setYear(year, month, date)<br />
LocalDate.prototype.setMonth(month, date)<br />
LocalDate.prototype.setDate(date)<br />
LocalDate.prototype.setHours(hour, min, sec, ms)<br />
LocalDate.prototype.setMinutes(min, sec, ms)<br />
LocalDate.prototype.setSeconds(sec, ms)<br />
LocalDate.prototype.setMilliseconds(ms)<br />
</pre><br />
* Set the specified date or time fields. Any unspecified fields retain their current value. Values outside of the specified ranges will result in overflow to the neighboring periods and can therefore be used for date arithmetic.<br />
** year Number - The year.<br />
** month Number - The month. Values range from 0 for January to 11 for December.<br />
** date Number - The date. Values range from 1 to 31.<br />
** hour Number - The hours. Values range from 0 to 23.<br />
** min Number - The minutes. Values range from 0 to 59.<br />
** sec Number - The seconds. Values range from 0 to 59.<br />
** ms Number - The milliseconds. Values range from 0 to 999.<br />
<br />
LocalDate.prototype.getDay()<br />
* Returns Number - The day of the week. Values range from 0 for Sunday to 6 for Saturday.<br />
<br />
LocalDate.prototype.getTimeZone()<br />
* This method is not present in Date. It returns the abbreviation of the specific time zone. The abbreviation indicate the GMT offset and is therefore different between daylight savings time and standard time.<br />
* Returns String - The abbreviation of the specific time zone.<br />
* Other getters and setters work with the entire timestamp and not just individual fields.<br />
<br />
LocalDate.prototype.getDays()<br />
* Returns the day number of this object. This may be useful to find the start of the same day (by multiplying the result with DAY).<br />
* Returns Number - The number of days since 1970-01-01 in this object's time zone.<br />
<br />
LocalDate.prototype.getTime()<br />
* Returns Timestamp - The UTC timestamp of this object.<br />
<br />
LocalDate.prototype.setTime(time)<br />
* Sets the UTC timestamp to a new value.<br />
* time Timestamp - The new UTC timestamp of this object.<br />
* While setters can be used to perform date arithmetic, LocalDate provides convenience functions for the most frequent cases of adding and subtracting a time period and finding the start of a week.<br />
<br />
LocalDate.prototype.add(time)<br />
* Adds or subtracts a time period in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
* time Number - The time period to add, in milliseconds. Use negative values to subtract. See also Constants.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addUTC(time)<br />
* Adds or subtracts a physical time period, i.e. simply increments the timestamp.<br />
time Number - The time period to add, in milliseconds. Use negative values to subtract. See also Constants.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addMonths(months)<br />
* Adds or subtracts a number of months in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
months Number - The number of months to add. Use negative values to subtract.<br />
Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addYears(years)<br />
* Adds or subtracts a number of years in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
years Number - The number of years to add. Use negative values to subtract.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.setStartOfWeek()<br />
* Sets the date to the start of the same week as determined by locale.weekStart. The time is reset to midnight.<br />
* Returns this - This object for chaining.<br />
* Formatting functions implement the conversion of dates and intervals into localized strings which are suitable for direct presentation to the user.<br />
<br />
LocalDate.prototype.format(format)<br />
* Formats the date according to the specified format flags or format string.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats. The default value is DATE_TIME.<br />
* Returns String - This object formatted according to the specified format.<br />
<br />
LocalDate.prototype.getIntervalFormat(end, format)<br />
* Returns a format string for a time interval with this object as the start and another LocalDate object as the end.<br />
* end LocalDate - The end of the interval.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.intervals and locale.formats. The default value is DATE_TIME.<br />
* Returns String - The format string for the interval accorging to the specified format.<br />
<br />
LocalDate.prototype.formatInterval(end, format)<br />
* Formats an interval with this object as the start and another LocalDate object as the end.<br />
end LocalDate - The end of the interval.<br />
format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.intervals and locale.formats. The default value is DATE_TIME.<br />
* Returns String - The interval formatted accorging to the specified format.<br />
* Finally, the JavaScript standard conversion functions allow easy debugging and arithmetic on timestamps.<br />
<br />
LocalDate.prototype.toString()<br />
* Converts this object to a string using this.format(FULL_DATE).<br />
* Returns String - The string representation of this object.<br />
<br />
LocalDate.prototype.valueOf()<br />
* Converts this object to a primitive value by returning the UTC timestamp. This can be used for arithmetic directly on LocalDate objects and as the single parameter to new LocalDate().<br />
* Returns Timestamp - The UTC timestamp of this object.<br />
<br />
=== Constants ===<br />
<br />
All date classes operate on timestamps expressed as milliseconds since the UNIX epoch, 1970-01-01 00:00 UTC. The date module defines constants for common time intervals with a constant duration.<br />
<br />
SECOND<br />
Number of milliseconds in a second.<br />
MINUTE<br />
Number of milliseconds in a minute.<br />
HOUR<br />
Number of milliseconds in an hour.<br />
DAY<br />
Number of milliseconds in a day.<br />
WEEK<br />
Number of milliseconds in a week.<br />
<br />
Format flags for parsing and formatting functions are defined as constants. Multiple flags can be combined via addition or bitwise ORing.<br />
<br />
<pre class="language-javascript"> <br />
DAYOFWEEK<br />
Day of the week<br />
DATE<br />
Date<br />
TIME<br />
Time<br />
TIMEZONE<br />
Timezone<br />
</pre><br />
Valid format flag combinations have dedicated constants. In a combination, DAYOFWEEK implies DATE and TIMEZONE implies TIME.<br />
<br />
<pre class="language-javascript"> <br />
DAYOFWEEK_DATE<br />
DAYOFWEEK + DATE<br />
DATE_TIME<br />
DATE + TIME<br />
DAYOFWEEK_DATE_TIME<br />
DAYOFWEEK + DATE + TIME<br />
TIME_TIMEZONE<br />
TIME + TIMEZONE<br />
DATE_TIME_TIMEZONE<br />
DATE + TIME + TIMEZONE<br />
FULL_DATE<br />
DAYOFWEEK + DATE + TIME + TIMEZONE<br />
Miscellaneous<br />
</pre><br />
See [[#Formatting|Formatting]] for usage of this function.<br />
<br />
getFormat(format)<br />
* Returns the localized format string for the specified format flags.<br />
format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats. The default value is DATE_TIME.<br />
* Returns String - The localized format string which corresponds to the specified format flags. If format is a string, that string is returned unmodified.<br />
<br />
[[Category:AppSuite]][[Category:UI]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Date_and_time&diff=16557AppSuite:Date and time2013-11-26T14:53:00Z<p>Mark.schmidts: /* Formatting */</p>
<hr />
<div>{{Stability-experimental}}<br />
<br />
<div class="title">Date and Time</div><br />
<br />
The handling of date and time is a complicated mess of historical conventions, which are still changed from time to time by governments around the world. To keep this away from day-to-day activities of developers, the OX App Suite platform provides the module date, which performs conversion between different time zones, formatting and parsing of date and time values.<br />
<br />
== Time Zones ==<br />
<br />
The built-in JavaScript class Date supports calculations using UTC and the operating system's local time zone. Unfortunately, this is not enough. Examples include using a time zone different from the time zone of the client system, or displaying times in multiple time zones at once.<br />
<br />
The class Local is almost a drop-in replacement for Date, with the main difference being that it operates in the default time zone of the OX App Suite user, even if it is different from the time zone of the browser's operating system. The following code displays the current date and time. It will show a different time when called after changing the user's time zone.<br />
<br />
<pre class="language-javascript"><br />
alert(new date.Local());<br />
</pre><br />
<br />
To work with other time zones, the function <tt>getTimeZone()</tt> can be used to create replacement classes similar to Local, which are all descendants of the private class LocalDate (for which all methods are documented below). Since the time zone definitions are loaded on-demand, the function returns a jQuery promise, which is resolved to the class constructor once the time zone definition is loaded. This class can then be used to e.g. convert between time zones.<br />
<br />
<pre class="language-javascript"><br />
date.getTimeZone('America/New_York').done(function (NewYork) {<br />
alert(gettext('New York celebrated New Year\'s at %1$s',<br />
new date.Local(new NewYork(2012, 0, 1))));<br />
});<br />
</pre><br />
<br />
The function getTimeZone() is memorized for performance reasons, i.e. multiple calls with the same argument will return the same promise and will therefore resolve to the same class object.<br />
<br />
== Formatting ==<br />
<br />
The default <tt>LocalDate.prototype.toString()</tt> method displays the full date and time, including the day of week and the time zone. To allow better control of the resulting string, the method <tt>LocalDate.prototype.format()</tt> accepts a set of format flags. The flags determine, which fields should be included in the output. Currently, there are four flags:<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local();<br />
alert(d.format(date.DATE));<br />
alert(d.format(date.TIME));<br />
alert(d.format(date.DAYOFWEEK));<br />
alert(d.format(date.TIMEZONE));<br />
</pre><br />
<br />
Multiple flags can be combined by adding them, or by using one of the predefined combination constants. Not all possible combinations produce unique results. When DAYOFWEEK is specified together with any other fields, DATE is automatically included in the output. Similarly, TIMEZONE implies TIME when used with other fields.<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local();<br />
assert(d.format(date.DAYOFWEEK + date.TIMEZONE) === d.format(date.FULL_DATE);<br />
</pre><br />
<br />
The format flags select one of several predefined format strings, which is stored in the current locale settings. This frees both the developers and the translators from having to remember arcane letter combinations.<br />
<br />
For the case that even finer control of the generated output is required, LocalDate.prototype.format() accepts a format string directly. The syntax of the format strings is a subset of CLDR date format patterns. Format specifiers which are not used in the Gregorian calendar will be implemented on-demand.<br />
<br />
<pre class="language-javascript"><br />
alert(new date.Local().format('EEEE'));<br />
</pre><br />
<br />
In general, if format strings are required, this indicates that the current date API should be extended. Feedback is always welcome.<br />
<br />
One situation where direct access to format strings is useful, is the manipulation of the localized format strings, e.g. to decorate individual fields in a displayed date with HTML markup. To achieve this, the localized format string is retrieved with getFormat(), and parts of it passed individually to LocalDate.prototype.format().<br />
<br />
<pre class="language-javascript"><br />
// Get the original format string.<br />
var fmt = date.getFormat(date.FULL_DATE);<br />
<br />
// Regular expression to parse the format string.<br />
// . . ( time zone )|quote|'quoted text'|rest<br />
var re = /(v+|V+|z+|Z+)|(?:''|'(?:[^']|'')*'|[^vVzZ'])+/g;<br />
<br />
// Appends a formatted date to a jQuery node and returns<br />
// the time zone as a separate node.<br />
function decorateTimeZone(d, parent) {<br />
var span;<br />
fmt.replace(re, function (match, tz) {<br />
if (tz) { // found the time zone field<br />
// Wrap the formatted time zone in a <span> element.<br />
span = $('<span>').text(d.format(match));<br />
parent.append(result);<br />
} else {<br />
// Append all other formatted text as plain text nodes.<br />
parent.append($.txt(d.format(match)));<br />
}<br />
});<br />
// Return the wrapped field for further customization.<br />
return span;<br />
}<br />
</pre><br />
<br />
''Does anybody want this use case as an API function?''<br />
<br />
== Intervals ==<br />
<br />
In addition to formatting individual dates, LocalDate instances can format intervals. The difference to simply inserting two dates into a translated string is that short intervals may have a compacter representation, e.g. 'Jan 1–10, 2012' instead of 'Jan 1, 2012 – Jan 10, 2012'.<br />
<br />
<pre class="language-javascript"><br />
var start = new date.Local(), end = new date.Local(start);<br />
end.add(date.DAY);<br />
alert(start.formatInterval(end, date.DATE));<br />
</pre><br />
<br />
The methods LocalDate.prototype.formatInterval() and LocalDate.prototype.getIntervalFormat() are used like LocalDate.prototype.format() and getFormat(), with two differences. First, the interval functions accept the end of the interval as first parameter before the format flags. And second, since the format string depends on the actual interval, LocalDate.prototype.getIntervalFormat() is a member function and requires the same end value as used later for LocalDate.prototype.formatInterval().<br />
<br />
== Parsing ==<br />
<br />
Parsing is the reverse of formatting, except that ideally, users should be able to enter almost anything, as long as it is not ambiguous. The practice looks a bit more restricted. The LocalDate.parse() function takes a format parameter like the formatting functions, and expects the parsed string to match it very closely.<br />
<br />
<pre class="language-javascript"><br />
var input = prompt(gettext('Please enter a date'), '');<br />
var d = date.Local.parse(input, date.DATE);<br />
alert(gettext('I understood %1$s', d);<br />
</pre><br />
<br />
If there is demand, we can implement some heuristics. There are a lot of abstract algorithm descriptions in the standards, which describe how to parse almost anything while using the format string only as disambiguation help.<br />
<br />
== Manipulation of LocalDate objects ==<br />
<br />
Since the LocalDate class is designed as a drop-in for the Date class, its instances support getter and setter methods for all fields of a date. They can be used to modify an existing LocalDate object, e. g. to round a date to the nearest day or hour.<br />
<br />
<pre class="language-javascript"><br />
var start = new date.Local(), end = new date.Local(start);<br />
start.setHours(0, 0, 0, 0);<br />
end.setHours(24, 0, 0, 0);<br />
alert(gettext('Today is %1$s', start.formatInterval(end)));<br />
</pre><br />
<br />
One manipulation, which is often needed in calendars, is iteration over time. This operation seems simple, at least for iteration steps with a constant duration like hours, days or weeks. One just needs to add the step duration to the timestamp. While there is a method to do exactly this, LocalDate.prototype.addUTC(), you will encounter problems as soon as the iteration transcends a daylight savings switch. First, days and weeks are not actually constant. And second, sometimes the iteration might need to follow the displayed 'wall clock' time instead of the physical time. For these cases, the method LocalDate.prototype.add() increments the local time instead of the UTC time. Both methods accept an increment value in milliseconds, which can also be negative. There are predefined constants for the most common (almost-)fixed-duration periods.<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local(2012, 2);<br />
for (; d.getMonth() < 3; d.add(date.DAY)) {<br />
// Display a day in a month view.<br />
}<br />
</pre><br />
<br />
Iteration with larger intervals like months and years has the additional difficulty, that a single numeric parameter like 30 * date.DAY cannot be interpreted as a month, because it might be just really 30 days. To solve this, there are separate methods for months and years: LocalDate.prototype.addMonths() and LocalDate.prototype.addYears(). They accept the number of months, respective years as parameter.<br />
<br />
<pre class="language-javascript"> <br />
var d = new date.Local(2012, 0);<br />
for (; g.getYear() < 2013; d.addMonths(1)) {<br />
// Display a month in a year view.<br />
}<br />
</pre><br />
<br />
Finally, most calendars default to displaying the current date, and therefore need to figure out the iteration range based on an arbitrary point inside that range. In most cases, the start can be computed by simply calling the appropriate setters with all zeros as parameters to find the start of the range, and adding the range duration to find the end. One exception is the week. There is no setter for the day of the week. Instead, the method LocalDate.prototype.setStartOfWeek() can be used to find the start of a week.<br />
<br />
<pre class="language-javascript"> <br />
// Find the start and the end of the current week<br />
var d = new date.Local().setStartOfWeek();<br />
var end = new date.Local(start).add(date.WEEK);<br />
// Iterate over the week<br />
for (; d < end; d.add(date.DAY)) {<br />
// Display a day in a week view.<br />
}<br />
</pre><br />
<br />
In addition to explicit method calls, the JavaScript standard method LocalDate.prototype.valueOf() allows native comparison, addition and subtraction operators to work on LocalDate objects. The result of LocalDate.prototype.valueOf(), and therefore of addition and subtraction, is a timestamp, which can be passed to the LocalDate constructor to get a LocalDate object again.<br />
<br />
<pre class="language-javascript"> <br />
var start = date.Local.parse(prompt(gettext('Start date'), ''));<br />
var end = date.Local.parse(prompt(gettext('End date'), ''));<br />
if (end < start) alert(gettext('Invalid date range!'));<br />
</pre><br />
<br />
== Differences between LocalDate and Date ==<br />
<br />
The LocalDate classes duplicate most of the Date API with a few exceptions:<br />
<br />
* The constructor can not be called as a function. The Date constructor does in this case nothing useful anyway.<br />
* The constructor always uses full years, it does not add 1900 for years 0 to 99.<br />
* Date.UTC() should not be necessary, but since it returns a numeric timestamp and has nothing to do with time zones, it can still be used directly.<br />
* Except for LocalDate.prototype.toString(), all to*String() methods are replaced by LocalDate.prototype.format().<br />
* There are no UTC variants of getters and setters. They should not be necessary. But just in case, you can still use a LocalDate class for the time zone 'UTC' instead.<br />
* The getter and setter for the year are called getYear and setYear instead of getFullYear and setFullYear since we have no legacy code with Y2K issues.<br />
* Setters return the modified object instead of the timestamp. This is useful for chaining of method calls.<br />
* Date.prototype.getTimeZoneOffset() should not be necessary, since hiding these details is the whole point of the date module. If still necessary, LocalDate.getTTInfo() can be used instead.<br />
<br />
== API Reference ==<br />
<br />
This section provides a short reference of the date API.<br />
<br />
=== Locale ===<br />
<br />
A locale describes the localization settings which usually depend not only on thelanguage, but also on the region and optionally even on the personal preferences of the user. The locale object is loaded at startup and provides various settings and translations.<br />
<br />
Various arrays containing translations can be used directly without any other date function.<br />
<br />
locale.dayPeriods<br />
A map from an identifier of a day period to the corresponding translation. The members am and pm are used in the 12h time format, but other members may be useful for greetings. Is anyone interested in a function which returns the correct greeting period for a given time? If not, maybe remove everything except AM and PM?<br />
locale.days<br />
An array with translated full names of days of the week, starting with Sunday. CLDR context: "format", CLDR width: "wide".<br />
locale.daysShort<br />
An array with translated abbreviated names of days of the week, starting with Sunday. CLDR context: "format", CLDR width: "abbreviated".<br />
locale.daysStandalone<br />
An array with translated standalone names of days of the week, starting with Sunday. CLDR context: "standalone", CLDR width: "abbreviated".<br />
locale.eras<br />
An array with translated abbreviations for the two eras of the Gregorian calendar: BC and AD (in that order).<br />
locale.months<br />
An array with translated full names of months. CLDR context: "format", CLDR width: "wide".<br />
locale.monthsShort<br />
An array with translated abbreviated names of months. CLDR context: "format", CLDR width: "abbreviated".<br />
Diverse week-based calculations need to know on which day the week starts and how the first week of the year is defined.<br />
<br />
locale.daysInFirstWeek<br />
The lowest number of days of a week which must be in the new year for that week to be considered week number 1. Common values are<br />
* 1 if the week of January 1st is week number 1,<br />
* 4 if the first week which has most of its days in the new year is week number 1.<br />
* 7 if the first week which starts in the new year is week number 1.<br />
locale.weekStart<br />
First day of the week. Common values are<br />
* 0 for Sunday,<br />
* 1 for Monday.<br />
Deprecated and internal fields should not be used since they can change or disappear entirely without notice. They are still documented here for completeness.<br />
<br />
locale.date<br />
Deprecated, use DATE instead.<br />
locale.dateTime<br />
Deprecated, use DATE_TIMEinstead.<br />
locale.dateTimeFormat<br />
The default format used to combine a time (%1$s) and a date (%2$s). Not used yet, will probably disappear.<br />
locale.formats<br />
A map from various canonical sets of format fields to the corresponding localized format strings. Used mainly by getFormat(). Maybe remove it from the public interface after loading, since it's internal?<br />
locale.h12<br />
A boolean indicating whether the 12h format is used. WANTED: a better name.<br />
locale.intervals<br />
A map from various canonical sets of format fields to the corresponding formatting rules. A formatting rule is a map from the largest field, which is different between the start and end of the interval, to the corresponding localized formatting string. The field is specified as a single lower case letter. The formatting string is split at the first repeating field. The first part is formatted using the start of the interval, the second part is formatted using the end of the interval. Used mainly by LocalDate.prototype.getIntervalFormat(). Maybe remove it from the public interface after loading, since it's internal?<br />
locale.intervals.fallback<br />
The default format string to combine the start (%1$s) and end (%2$s) of an interval when none of the other members of locale.intervals apply. Maybe remove it from the public interface after loading, since it's internal?<br />
locale.time<br />
Deprecated, use TIME instead.<br />
getTimeZone<br />
<br />
The main entry points of the date API are the class Local which replaces Date for use with the user's default time zone and a function to generate similar classes for arbitrary time zones.<br />
<br />
getTimeZone(name)<br />
Creates a LocalDate class which operates in the specified time zone. Multiple calls with the same name will return the same object.<br />
name String - The name of the requested time zone. It must be one of the values returned by api/config/availableTimeZones.<br />
Returns Promise - A promise which resolves to a LocalDate class which uses the requested time zone.<br />
Local<br />
A convenience LocalDate class which uses the user's current time zone.<br />
<br />
=== LocalDate ===<br />
<br />
The core of the date API is the abstract class LocalDate which is the superclass of time zone specific classes. The class itself is not publically available, only its subclasses can be created by calling getTimeZone(). The subclasses and their instances are referred to as LocalDate classes and LocalDate objects.<br />
<br />
The constructor mimics the behavior of the Date class, but it can't be called as a function.<br />
<br />
<pre class="language-javascript"> <br />
new LocalDate()<br />
new LocalDate(timestamp)<br />
new LocalDate(year, month, date, hours, minutes, seconds, ms)<br />
</pre><br />
<br />
The constructor accepts the same parameters as the Date constructor.<br />
The entire functionality of the class is based on a few low level functions. They should not be necessary outside the date module itself, assuming the API is complete. If you find you need these functions, please let's extend the high level APIs instead.<br />
<br />
LocalDate.getTTInfo(t)<br />
Returns the GMT offset, daylight savings and the abbreviation of the time zone which are in effect at the specified time.<br />
t Timestamp - The timestamp.<br />
Returns { gmtoff, isdst, abbr } - An object with the GMT offset in milliseconds, whether daylight savings are in effect (0 or 1, not a real boolean) and the abbreviation like 'CET' (!isdst) or 'CEST' (!!isdst).<br />
LocalDate.getTTInfoLocal(t)<br />
* Returns the GMT offset, daylight savings and the abbreviation of the time zone which are in effect at the specified local time. If the local time is ambiguous or invalid, the same fallbacks as for LocalDate.utc() are used. (It is actually implemented as a wrapper for this function.)<br />
* t Number - The local time.<br />
* Returns { gmtoff, isdst, abbr } - An object with the GMT offset in milliseconds, whether daylight savings are in effect (0 or 1, not a real boolean) and the abbreviation like 'CET' (!isdst) or 'CEST' (!!isdst).<br />
<br />
LocalDate.localTime(t)<br />
* Converts a UTC timestamp to local time.<br />
* t Timestamp - The UTC timestamp to convert.<br />
* Returns Number - A local time which is used in computations of date and time components.<br />
<br />
LocalDate.utc(t)<br />
* Converts local time to a UTC timestamp. If the local time is ambiguous because of a DST switch, the local time is interpreted as before the switch. E.g. 02:30 at the end of DST is interpreted as DST. If the local time is invalid because of a DST switch, the local time is interpreted as if the switch already occurred. E.g. 02:30 at the start of DST returns the same timestamp as 01:30 before the switch.<br />
* t Number - The local time to convert.<br />
* Returns Timestamp - The corresponsing UTC timestamp.<br />
Metadata about a time zone is stored directly on the LocalDate object.<br />
<br />
LocalDate.id<br />
* Original name used to retrieve this time zone.<br />
<br />
LocalDate.displayName<br />
* A human-readable name of this time zone as provided by the config module under "availableTimeZones".<br />
* Parsing of date and time strings as entered by a user is done using format flags from Constants. The current implementation expects the string to match the corresponding localized format string pretty closely. Any difficulties with parsing common entered dates and times should be taken as an opportunity to extend the parsing heuristics.<br />
<br />
LocalDate.parse(string, format)<br />
* Parses a string using either the specified format string or localized version of one of predefined format strings selected by format flags.<br />
* string String - The string to parse.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats.<br />
* Returns LocalDate or null - A new LocalDate object which represents the parsed date and time or null if the string could not be parsed.<br />
* Methods of LocalDate instances can be grouped into several categories. The first are the setters and getters for individual fields from Date. Since each LocalDate class has its own time zone, There are no UTC variants of each getter and setter. They all work with local time.<br />
<br />
<pre class="language-javascript"> <br />
LocalDate.prototype.getYear()<br />
LocalDate.prototype.getMonth()<br />
LocalDate.prototype.getDate()<br />
LocalDate.prototype.getHours()<br />
LocalDate.prototype.getMinutes()<br />
LocalDate.prototype.getSeconds()<br />
LocalDate.prototype.getMilliseconds()<br />
</pre><br />
* Return the corresponding field of the local date or time.<br />
* Returns Number - The requested field, as a number.<br />
<br />
<pre class="language-javascript"> <br />
LocalDate.prototype.setYear(year, month, date)<br />
LocalDate.prototype.setMonth(month, date)<br />
LocalDate.prototype.setDate(date)<br />
LocalDate.prototype.setHours(hour, min, sec, ms)<br />
LocalDate.prototype.setMinutes(min, sec, ms)<br />
LocalDate.prototype.setSeconds(sec, ms)<br />
LocalDate.prototype.setMilliseconds(ms)<br />
</pre><br />
* Set the specified date or time fields. Any unspecified fields retain their current value. Values outside of the specified ranges will result in overflow to the neighboring periods and can therefore be used for date arithmetic.<br />
** year Number - The year.<br />
** month Number - The month. Values range from 0 for January to 11 for December.<br />
** date Number - The date. Values range from 1 to 31.<br />
** hour Number - The hours. Values range from 0 to 23.<br />
** min Number - The minutes. Values range from 0 to 59.<br />
** sec Number - The seconds. Values range from 0 to 59.<br />
** ms Number - The milliseconds. Values range from 0 to 999.<br />
<br />
LocalDate.prototype.getDay()<br />
* Returns Number - The day of the week. Values range from 0 for Sunday to 6 for Saturday.<br />
<br />
LocalDate.prototype.getTimeZone()<br />
* This method is not present in Date. It returns the abbreviation of the specific time zone. The abbreviation indicate the GMT offset and is therefore different between daylight savings time and standard time.<br />
* Returns String - The abbreviation of the specific time zone.<br />
* Other getters and setters work with the entire timestamp and not just individual fields.<br />
<br />
LocalDate.prototype.getDays()<br />
* Returns the day number of this object. This may be useful to find the start of the same day (by multiplying the result with DAY).<br />
* Returns Number - The number of days since 1970-01-01 in this object's time zone.<br />
<br />
LocalDate.prototype.getTime()<br />
* Returns Timestamp - The UTC timestamp of this object.<br />
<br />
LocalDate.prototype.setTime(time)<br />
* Sets the UTC timestamp to a new value.<br />
* time Timestamp - The new UTC timestamp of this object.<br />
* While setters can be used to perform date arithmetic, LocalDate provides convenience functions for the most frequent cases of adding and subtracting a time period and finding the start of a week.<br />
<br />
LocalDate.prototype.add(time)<br />
* Adds or subtracts a time period in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
* time Number - The time period to add, in milliseconds. Use negative values to subtract. See also Constants.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addUTC(time)<br />
* Adds or subtracts a physical time period, i.e. simply increments the timestamp.<br />
time Number - The time period to add, in milliseconds. Use negative values to subtract. See also Constants.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addMonths(months)<br />
* Adds or subtracts a number of months in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
months Number - The number of months to add. Use negative values to subtract.<br />
Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addYears(years)<br />
* Adds or subtracts a number of years in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
years Number - The number of years to add. Use negative values to subtract.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.setStartOfWeek()<br />
* Sets the date to the start of the same week as determined by locale.weekStart. The time is reset to midnight.<br />
* Returns this - This object for chaining.<br />
* Formatting functions implement the conversion of dates and intervals into localized strings which are suitable for direct presentation to the user.<br />
<br />
LocalDate.prototype.format(format)<br />
* Formats the date according to the specified format flags or format string.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats. The default value is DATE_TIME.<br />
* Returns String - This object formatted according to the specified format.<br />
<br />
LocalDate.prototype.getIntervalFormat(end, format)<br />
* Returns a format string for a time interval with this object as the start and another LocalDate object as the end.<br />
* end LocalDate - The end of the interval.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.intervals and locale.formats. The default value is DATE_TIME.<br />
* Returns String - The format string for the interval accorging to the specified format.<br />
<br />
LocalDate.prototype.formatInterval(end, format)<br />
* Formats an interval with this object as the start and another LocalDate object as the end.<br />
end LocalDate - The end of the interval.<br />
format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.intervals and locale.formats. The default value is DATE_TIME.<br />
* Returns String - The interval formatted accorging to the specified format.<br />
* Finally, the JavaScript standard conversion functions allow easy debugging and arithmetic on timestamps.<br />
<br />
LocalDate.prototype.toString()<br />
* Converts this object to a string using this.format(FULL_DATE).<br />
* Returns String - The string representation of this object.<br />
<br />
LocalDate.prototype.valueOf()<br />
* Converts this object to a primitive value by returning the UTC timestamp. This can be used for arithmetic directly on LocalDate objects and as the single parameter to new LocalDate().<br />
* Returns Timestamp - The UTC timestamp of this object.<br />
<br />
=== Constants ===<br />
<br />
All date classes operate on timestamps expressed as milliseconds since the UNIX epoch, 1970-01-01 00:00 UTC. The date module defines constants for common time intervals with a constant duration.<br />
<br />
SECOND<br />
Number of milliseconds in a second.<br />
MINUTE<br />
Number of milliseconds in a minute.<br />
HOUR<br />
Number of milliseconds in an hour.<br />
DAY<br />
Number of milliseconds in a day.<br />
WEEK<br />
Number of milliseconds in a week.<br />
<br />
Format flags for parsing and formatting functions are defined as constants. Multiple flags can be combined via addition or bitwise ORing.<br />
<br />
<pre class="language-javascript"> <br />
DAYOFWEEK<br />
Day of the week<br />
DATE<br />
Date<br />
TIME<br />
Time<br />
TIMEZONE<br />
Timezone<br />
</pre><br />
Valid format flag combinations have dedicated constants. In a combination, DAYOFWEEK implies DATE and TIMEZONE implies TIME.<br />
<br />
<pre class="language-javascript"> <br />
DAYOFWEEK_DATE<br />
DAYOFWEEK + DATE<br />
DATE_TIME<br />
DATE + TIME<br />
DAYOFWEEK_DATE_TIME<br />
DAYOFWEEK + DATE + TIME<br />
TIME_TIMEZONE<br />
TIME + TIMEZONE<br />
DATE_TIME_TIMEZONE<br />
DATE + TIME + TIMEZONE<br />
FULL_DATE<br />
DAYOFWEEK + DATE + TIME + TIMEZONE<br />
Miscellaneous<br />
</pre><br />
See [[#Formatting|Formatting]] for usage of this function.<br />
<br />
getFormat(format)<br />
* Returns the localized format string for the specified format flags.<br />
format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats. The default value is DATE_TIME.<br />
* Returns String - The localized format string which corresponds to the specified format flags. If format is a string, that string is returned unmodified.<br />
<br />
[[Category:AppSuite]][[Category:UI]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Date_and_time&diff=16556AppSuite:Date and time2013-11-26T14:36:37Z<p>Mark.schmidts: /* Time Zones */</p>
<hr />
<div>{{Stability-experimental}}<br />
<br />
<div class="title">Date and Time</div><br />
<br />
The handling of date and time is a complicated mess of historical conventions, which are still changed from time to time by governments around the world. To keep this away from day-to-day activities of developers, the OX App Suite platform provides the module date, which performs conversion between different time zones, formatting and parsing of date and time values.<br />
<br />
== Time Zones ==<br />
<br />
The built-in JavaScript class Date supports calculations using UTC and the operating system's local time zone. Unfortunately, this is not enough. Examples include using a time zone different from the time zone of the client system, or displaying times in multiple time zones at once.<br />
<br />
The class Local is almost a drop-in replacement for Date, with the main difference being that it operates in the default time zone of the OX App Suite user, even if it is different from the time zone of the browser's operating system. The following code displays the current date and time. It will show a different time when called after changing the user's time zone.<br />
<br />
<pre class="language-javascript"><br />
alert(new date.Local());<br />
</pre><br />
<br />
To work with other time zones, the function <tt>getTimeZone()</tt> can be used to create replacement classes similar to Local, which are all descendants of the private class LocalDate (for which all methods are documented below). Since the time zone definitions are loaded on-demand, the function returns a jQuery promise, which is resolved to the class constructor once the time zone definition is loaded. This class can then be used to e.g. convert between time zones.<br />
<br />
<pre class="language-javascript"><br />
date.getTimeZone('America/New_York').done(function (NewYork) {<br />
alert(gettext('New York celebrated New Year\'s at %1$s',<br />
new date.Local(new NewYork(2012, 0, 1))));<br />
});<br />
</pre><br />
<br />
The function getTimeZone() is memorized for performance reasons, i.e. multiple calls with the same argument will return the same promise and will therefore resolve to the same class object.<br />
<br />
== Formatting ==<br />
<br />
The default LocalDate.prototype.toString() method displays the full date and time, including the day of week and the time zone. To allow better control of the resulting string, the method LocalDate.prototype.format() accepts a set of format flags. The flags determine, which fields should be included in the output. Currently, there are four flags:<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local();<br />
alert(d.format(date.DATE));<br />
alert(d.format(date.TIME));<br />
alert(d.format(date.DAYOFWEEK));<br />
alert(d.format(date.TIMEZONE));<br />
</pre><br />
<br />
Multiple flags can be combined by adding them, or by using one of the predefined combination constants. Not all possible combinations produce unique results. When DAYOFWEEK is specified together with any other fields, DATE is automatically included in the output. Similarly, TIMEZONE implies TIME when used with other fields.<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local();<br />
assert(d.format(date.DAYOFWEEK + date.TIMEZONE) === d.format(date.FULL_DATE);<br />
</pre><br />
<br />
The format flags select one of several predefined format strings, which is stored in the current locale settings. This frees both the developers and the translators from having to remember arcane letter combinations.<br />
<br />
For the case that even finer control of the generated output is required, LocalDate.prototype.format() accepts a format string directly. The syntax of the format strings is a subset of CLDR date format patterns. Format specifiers which are not used in the Gregorian calendar will be implemented on-demand.<br />
<br />
<pre class="language-javascript"><br />
alert(new date.Local().format('EEEE'));<br />
</pre><br />
<br />
In general, if format strings are required, this indicates that the current date API should be extended. Feedback is always welcome.<br />
<br />
One situation where direct access to format strings is useful, is the manipulation of the localized format strings, e.g. to decorate individual fields in a displayed date with HTML markup. To achieve this, the localized format string is retrieved with getFormat(), and parts of it passed individually to LocalDate.prototype.format().<br />
<br />
<pre class="language-javascript"><br />
// Get the original format string.<br />
var fmt = date.getFormat(date.FULL_DATE);<br />
<br />
// Regular expression to parse the format string.<br />
// . . ( time zone )|quote|'quoted text'|rest<br />
var re = /(v+|V+|z+|Z+)|(?:''|'(?:[^']|'')*'|[^vVzZ'])+/g;<br />
<br />
// Appends a formatted date to a jQuery node and returns<br />
// the time zone as a separate node.<br />
function decorateTimeZone(d, parent) {<br />
var span;<br />
fmt.replace(re, function (match, tz) {<br />
if (tz) { // found the time zone field<br />
// Wrap the formatted time zone in a <span> element.<br />
span = $('<span>').text(d.format(match));<br />
parent.append(result);<br />
} else {<br />
// Append all other formatted text as plain text nodes.<br />
parent.append($.txt(d.format(match)));<br />
}<br />
});<br />
// Return the wrapped field for further customization.<br />
return span;<br />
}<br />
</pre><br />
<br />
''Does anybody want this use case as an API function?''<br />
<br />
== Intervals ==<br />
<br />
In addition to formatting individual dates, LocalDate instances can format intervals. The difference to simply inserting two dates into a translated string is that short intervals may have a compacter representation, e.g. 'Jan 1–10, 2012' instead of 'Jan 1, 2012 – Jan 10, 2012'.<br />
<br />
<pre class="language-javascript"><br />
var start = new date.Local(), end = new date.Local(start);<br />
end.add(date.DAY);<br />
alert(start.formatInterval(end, date.DATE));<br />
</pre><br />
<br />
The methods LocalDate.prototype.formatInterval() and LocalDate.prototype.getIntervalFormat() are used like LocalDate.prototype.format() and getFormat(), with two differences. First, the interval functions accept the end of the interval as first parameter before the format flags. And second, since the format string depends on the actual interval, LocalDate.prototype.getIntervalFormat() is a member function and requires the same end value as used later for LocalDate.prototype.formatInterval().<br />
<br />
== Parsing ==<br />
<br />
Parsing is the reverse of formatting, except that ideally, users should be able to enter almost anything, as long as it is not ambiguous. The practice looks a bit more restricted. The LocalDate.parse() function takes a format parameter like the formatting functions, and expects the parsed string to match it very closely.<br />
<br />
<pre class="language-javascript"><br />
var input = prompt(gettext('Please enter a date'), '');<br />
var d = date.Local.parse(input, date.DATE);<br />
alert(gettext('I understood %1$s', d);<br />
</pre><br />
<br />
If there is demand, we can implement some heuristics. There are a lot of abstract algorithm descriptions in the standards, which describe how to parse almost anything while using the format string only as disambiguation help.<br />
<br />
== Manipulation of LocalDate objects ==<br />
<br />
Since the LocalDate class is designed as a drop-in for the Date class, its instances support getter and setter methods for all fields of a date. They can be used to modify an existing LocalDate object, e. g. to round a date to the nearest day or hour.<br />
<br />
<pre class="language-javascript"><br />
var start = new date.Local(), end = new date.Local(start);<br />
start.setHours(0, 0, 0, 0);<br />
end.setHours(24, 0, 0, 0);<br />
alert(gettext('Today is %1$s', start.formatInterval(end)));<br />
</pre><br />
<br />
One manipulation, which is often needed in calendars, is iteration over time. This operation seems simple, at least for iteration steps with a constant duration like hours, days or weeks. One just needs to add the step duration to the timestamp. While there is a method to do exactly this, LocalDate.prototype.addUTC(), you will encounter problems as soon as the iteration transcends a daylight savings switch. First, days and weeks are not actually constant. And second, sometimes the iteration might need to follow the displayed 'wall clock' time instead of the physical time. For these cases, the method LocalDate.prototype.add() increments the local time instead of the UTC time. Both methods accept an increment value in milliseconds, which can also be negative. There are predefined constants for the most common (almost-)fixed-duration periods.<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local(2012, 2);<br />
for (; d.getMonth() < 3; d.add(date.DAY)) {<br />
// Display a day in a month view.<br />
}<br />
</pre><br />
<br />
Iteration with larger intervals like months and years has the additional difficulty, that a single numeric parameter like 30 * date.DAY cannot be interpreted as a month, because it might be just really 30 days. To solve this, there are separate methods for months and years: LocalDate.prototype.addMonths() and LocalDate.prototype.addYears(). They accept the number of months, respective years as parameter.<br />
<br />
<pre class="language-javascript"> <br />
var d = new date.Local(2012, 0);<br />
for (; g.getYear() < 2013; d.addMonths(1)) {<br />
// Display a month in a year view.<br />
}<br />
</pre><br />
<br />
Finally, most calendars default to displaying the current date, and therefore need to figure out the iteration range based on an arbitrary point inside that range. In most cases, the start can be computed by simply calling the appropriate setters with all zeros as parameters to find the start of the range, and adding the range duration to find the end. One exception is the week. There is no setter for the day of the week. Instead, the method LocalDate.prototype.setStartOfWeek() can be used to find the start of a week.<br />
<br />
<pre class="language-javascript"> <br />
// Find the start and the end of the current week<br />
var d = new date.Local().setStartOfWeek();<br />
var end = new date.Local(start).add(date.WEEK);<br />
// Iterate over the week<br />
for (; d < end; d.add(date.DAY)) {<br />
// Display a day in a week view.<br />
}<br />
</pre><br />
<br />
In addition to explicit method calls, the JavaScript standard method LocalDate.prototype.valueOf() allows native comparison, addition and subtraction operators to work on LocalDate objects. The result of LocalDate.prototype.valueOf(), and therefore of addition and subtraction, is a timestamp, which can be passed to the LocalDate constructor to get a LocalDate object again.<br />
<br />
<pre class="language-javascript"> <br />
var start = date.Local.parse(prompt(gettext('Start date'), ''));<br />
var end = date.Local.parse(prompt(gettext('End date'), ''));<br />
if (end < start) alert(gettext('Invalid date range!'));<br />
</pre><br />
<br />
== Differences between LocalDate and Date ==<br />
<br />
The LocalDate classes duplicate most of the Date API with a few exceptions:<br />
<br />
* The constructor can not be called as a function. The Date constructor does in this case nothing useful anyway.<br />
* The constructor always uses full years, it does not add 1900 for years 0 to 99.<br />
* Date.UTC() should not be necessary, but since it returns a numeric timestamp and has nothing to do with time zones, it can still be used directly.<br />
* Except for LocalDate.prototype.toString(), all to*String() methods are replaced by LocalDate.prototype.format().<br />
* There are no UTC variants of getters and setters. They should not be necessary. But just in case, you can still use a LocalDate class for the time zone 'UTC' instead.<br />
* The getter and setter for the year are called getYear and setYear instead of getFullYear and setFullYear since we have no legacy code with Y2K issues.<br />
* Setters return the modified object instead of the timestamp. This is useful for chaining of method calls.<br />
* Date.prototype.getTimeZoneOffset() should not be necessary, since hiding these details is the whole point of the date module. If still necessary, LocalDate.getTTInfo() can be used instead.<br />
<br />
== API Reference ==<br />
<br />
This section provides a short reference of the date API.<br />
<br />
=== Locale ===<br />
<br />
A locale describes the localization settings which usually depend not only on thelanguage, but also on the region and optionally even on the personal preferences of the user. The locale object is loaded at startup and provides various settings and translations.<br />
<br />
Various arrays containing translations can be used directly without any other date function.<br />
<br />
locale.dayPeriods<br />
A map from an identifier of a day period to the corresponding translation. The members am and pm are used in the 12h time format, but other members may be useful for greetings. Is anyone interested in a function which returns the correct greeting period for a given time? If not, maybe remove everything except AM and PM?<br />
locale.days<br />
An array with translated full names of days of the week, starting with Sunday. CLDR context: "format", CLDR width: "wide".<br />
locale.daysShort<br />
An array with translated abbreviated names of days of the week, starting with Sunday. CLDR context: "format", CLDR width: "abbreviated".<br />
locale.daysStandalone<br />
An array with translated standalone names of days of the week, starting with Sunday. CLDR context: "standalone", CLDR width: "abbreviated".<br />
locale.eras<br />
An array with translated abbreviations for the two eras of the Gregorian calendar: BC and AD (in that order).<br />
locale.months<br />
An array with translated full names of months. CLDR context: "format", CLDR width: "wide".<br />
locale.monthsShort<br />
An array with translated abbreviated names of months. CLDR context: "format", CLDR width: "abbreviated".<br />
Diverse week-based calculations need to know on which day the week starts and how the first week of the year is defined.<br />
<br />
locale.daysInFirstWeek<br />
The lowest number of days of a week which must be in the new year for that week to be considered week number 1. Common values are<br />
* 1 if the week of January 1st is week number 1,<br />
* 4 if the first week which has most of its days in the new year is week number 1.<br />
* 7 if the first week which starts in the new year is week number 1.<br />
locale.weekStart<br />
First day of the week. Common values are<br />
* 0 for Sunday,<br />
* 1 for Monday.<br />
Deprecated and internal fields should not be used since they can change or disappear entirely without notice. They are still documented here for completeness.<br />
<br />
locale.date<br />
Deprecated, use DATE instead.<br />
locale.dateTime<br />
Deprecated, use DATE_TIMEinstead.<br />
locale.dateTimeFormat<br />
The default format used to combine a time (%1$s) and a date (%2$s). Not used yet, will probably disappear.<br />
locale.formats<br />
A map from various canonical sets of format fields to the corresponding localized format strings. Used mainly by getFormat(). Maybe remove it from the public interface after loading, since it's internal?<br />
locale.h12<br />
A boolean indicating whether the 12h format is used. WANTED: a better name.<br />
locale.intervals<br />
A map from various canonical sets of format fields to the corresponding formatting rules. A formatting rule is a map from the largest field, which is different between the start and end of the interval, to the corresponding localized formatting string. The field is specified as a single lower case letter. The formatting string is split at the first repeating field. The first part is formatted using the start of the interval, the second part is formatted using the end of the interval. Used mainly by LocalDate.prototype.getIntervalFormat(). Maybe remove it from the public interface after loading, since it's internal?<br />
locale.intervals.fallback<br />
The default format string to combine the start (%1$s) and end (%2$s) of an interval when none of the other members of locale.intervals apply. Maybe remove it from the public interface after loading, since it's internal?<br />
locale.time<br />
Deprecated, use TIME instead.<br />
getTimeZone<br />
<br />
The main entry points of the date API are the class Local which replaces Date for use with the user's default time zone and a function to generate similar classes for arbitrary time zones.<br />
<br />
getTimeZone(name)<br />
Creates a LocalDate class which operates in the specified time zone. Multiple calls with the same name will return the same object.<br />
name String - The name of the requested time zone. It must be one of the values returned by api/config/availableTimeZones.<br />
Returns Promise - A promise which resolves to a LocalDate class which uses the requested time zone.<br />
Local<br />
A convenience LocalDate class which uses the user's current time zone.<br />
<br />
=== LocalDate ===<br />
<br />
The core of the date API is the abstract class LocalDate which is the superclass of time zone specific classes. The class itself is not publically available, only its subclasses can be created by calling getTimeZone(). The subclasses and their instances are referred to as LocalDate classes and LocalDate objects.<br />
<br />
The constructor mimics the behavior of the Date class, but it can't be called as a function.<br />
<br />
<pre class="language-javascript"> <br />
new LocalDate()<br />
new LocalDate(timestamp)<br />
new LocalDate(year, month, date, hours, minutes, seconds, ms)<br />
</pre><br />
<br />
The constructor accepts the same parameters as the Date constructor.<br />
The entire functionality of the class is based on a few low level functions. They should not be necessary outside the date module itself, assuming the API is complete. If you find you need these functions, please let's extend the high level APIs instead.<br />
<br />
LocalDate.getTTInfo(t)<br />
Returns the GMT offset, daylight savings and the abbreviation of the time zone which are in effect at the specified time.<br />
t Timestamp - The timestamp.<br />
Returns { gmtoff, isdst, abbr } - An object with the GMT offset in milliseconds, whether daylight savings are in effect (0 or 1, not a real boolean) and the abbreviation like 'CET' (!isdst) or 'CEST' (!!isdst).<br />
LocalDate.getTTInfoLocal(t)<br />
* Returns the GMT offset, daylight savings and the abbreviation of the time zone which are in effect at the specified local time. If the local time is ambiguous or invalid, the same fallbacks as for LocalDate.utc() are used. (It is actually implemented as a wrapper for this function.)<br />
* t Number - The local time.<br />
* Returns { gmtoff, isdst, abbr } - An object with the GMT offset in milliseconds, whether daylight savings are in effect (0 or 1, not a real boolean) and the abbreviation like 'CET' (!isdst) or 'CEST' (!!isdst).<br />
<br />
LocalDate.localTime(t)<br />
* Converts a UTC timestamp to local time.<br />
* t Timestamp - The UTC timestamp to convert.<br />
* Returns Number - A local time which is used in computations of date and time components.<br />
<br />
LocalDate.utc(t)<br />
* Converts local time to a UTC timestamp. If the local time is ambiguous because of a DST switch, the local time is interpreted as before the switch. E.g. 02:30 at the end of DST is interpreted as DST. If the local time is invalid because of a DST switch, the local time is interpreted as if the switch already occurred. E.g. 02:30 at the start of DST returns the same timestamp as 01:30 before the switch.<br />
* t Number - The local time to convert.<br />
* Returns Timestamp - The corresponsing UTC timestamp.<br />
Metadata about a time zone is stored directly on the LocalDate object.<br />
<br />
LocalDate.id<br />
* Original name used to retrieve this time zone.<br />
<br />
LocalDate.displayName<br />
* A human-readable name of this time zone as provided by the config module under "availableTimeZones".<br />
* Parsing of date and time strings as entered by a user is done using format flags from Constants. The current implementation expects the string to match the corresponding localized format string pretty closely. Any difficulties with parsing common entered dates and times should be taken as an opportunity to extend the parsing heuristics.<br />
<br />
LocalDate.parse(string, format)<br />
* Parses a string using either the specified format string or localized version of one of predefined format strings selected by format flags.<br />
* string String - The string to parse.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats.<br />
* Returns LocalDate or null - A new LocalDate object which represents the parsed date and time or null if the string could not be parsed.<br />
* Methods of LocalDate instances can be grouped into several categories. The first are the setters and getters for individual fields from Date. Since each LocalDate class has its own time zone, There are no UTC variants of each getter and setter. They all work with local time.<br />
<br />
<pre class="language-javascript"> <br />
LocalDate.prototype.getYear()<br />
LocalDate.prototype.getMonth()<br />
LocalDate.prototype.getDate()<br />
LocalDate.prototype.getHours()<br />
LocalDate.prototype.getMinutes()<br />
LocalDate.prototype.getSeconds()<br />
LocalDate.prototype.getMilliseconds()<br />
</pre><br />
* Return the corresponding field of the local date or time.<br />
* Returns Number - The requested field, as a number.<br />
<br />
<pre class="language-javascript"> <br />
LocalDate.prototype.setYear(year, month, date)<br />
LocalDate.prototype.setMonth(month, date)<br />
LocalDate.prototype.setDate(date)<br />
LocalDate.prototype.setHours(hour, min, sec, ms)<br />
LocalDate.prototype.setMinutes(min, sec, ms)<br />
LocalDate.prototype.setSeconds(sec, ms)<br />
LocalDate.prototype.setMilliseconds(ms)<br />
</pre><br />
* Set the specified date or time fields. Any unspecified fields retain their current value. Values outside of the specified ranges will result in overflow to the neighboring periods and can therefore be used for date arithmetic.<br />
** year Number - The year.<br />
** month Number - The month. Values range from 0 for January to 11 for December.<br />
** date Number - The date. Values range from 1 to 31.<br />
** hour Number - The hours. Values range from 0 to 23.<br />
** min Number - The minutes. Values range from 0 to 59.<br />
** sec Number - The seconds. Values range from 0 to 59.<br />
** ms Number - The milliseconds. Values range from 0 to 999.<br />
<br />
LocalDate.prototype.getDay()<br />
* Returns Number - The day of the week. Values range from 0 for Sunday to 6 for Saturday.<br />
<br />
LocalDate.prototype.getTimeZone()<br />
* This method is not present in Date. It returns the abbreviation of the specific time zone. The abbreviation indicate the GMT offset and is therefore different between daylight savings time and standard time.<br />
* Returns String - The abbreviation of the specific time zone.<br />
* Other getters and setters work with the entire timestamp and not just individual fields.<br />
<br />
LocalDate.prototype.getDays()<br />
* Returns the day number of this object. This may be useful to find the start of the same day (by multiplying the result with DAY).<br />
* Returns Number - The number of days since 1970-01-01 in this object's time zone.<br />
<br />
LocalDate.prototype.getTime()<br />
* Returns Timestamp - The UTC timestamp of this object.<br />
<br />
LocalDate.prototype.setTime(time)<br />
* Sets the UTC timestamp to a new value.<br />
* time Timestamp - The new UTC timestamp of this object.<br />
* While setters can be used to perform date arithmetic, LocalDate provides convenience functions for the most frequent cases of adding and subtracting a time period and finding the start of a week.<br />
<br />
LocalDate.prototype.add(time)<br />
* Adds or subtracts a time period in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
* time Number - The time period to add, in milliseconds. Use negative values to subtract. See also Constants.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addUTC(time)<br />
* Adds or subtracts a physical time period, i.e. simply increments the timestamp.<br />
time Number - The time period to add, in milliseconds. Use negative values to subtract. See also Constants.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addMonths(months)<br />
* Adds or subtracts a number of months in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
months Number - The number of months to add. Use negative values to subtract.<br />
Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addYears(years)<br />
* Adds or subtracts a number of years in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
years Number - The number of years to add. Use negative values to subtract.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.setStartOfWeek()<br />
* Sets the date to the start of the same week as determined by locale.weekStart. The time is reset to midnight.<br />
* Returns this - This object for chaining.<br />
* Formatting functions implement the conversion of dates and intervals into localized strings which are suitable for direct presentation to the user.<br />
<br />
LocalDate.prototype.format(format)<br />
* Formats the date according to the specified format flags or format string.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats. The default value is DATE_TIME.<br />
* Returns String - This object formatted according to the specified format.<br />
<br />
LocalDate.prototype.getIntervalFormat(end, format)<br />
* Returns a format string for a time interval with this object as the start and another LocalDate object as the end.<br />
* end LocalDate - The end of the interval.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.intervals and locale.formats. The default value is DATE_TIME.<br />
* Returns String - The format string for the interval accorging to the specified format.<br />
<br />
LocalDate.prototype.formatInterval(end, format)<br />
* Formats an interval with this object as the start and another LocalDate object as the end.<br />
end LocalDate - The end of the interval.<br />
format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.intervals and locale.formats. The default value is DATE_TIME.<br />
* Returns String - The interval formatted accorging to the specified format.<br />
* Finally, the JavaScript standard conversion functions allow easy debugging and arithmetic on timestamps.<br />
<br />
LocalDate.prototype.toString()<br />
* Converts this object to a string using this.format(FULL_DATE).<br />
* Returns String - The string representation of this object.<br />
<br />
LocalDate.prototype.valueOf()<br />
* Converts this object to a primitive value by returning the UTC timestamp. This can be used for arithmetic directly on LocalDate objects and as the single parameter to new LocalDate().<br />
* Returns Timestamp - The UTC timestamp of this object.<br />
<br />
=== Constants ===<br />
<br />
All date classes operate on timestamps expressed as milliseconds since the UNIX epoch, 1970-01-01 00:00 UTC. The date module defines constants for common time intervals with a constant duration.<br />
<br />
SECOND<br />
Number of milliseconds in a second.<br />
MINUTE<br />
Number of milliseconds in a minute.<br />
HOUR<br />
Number of milliseconds in an hour.<br />
DAY<br />
Number of milliseconds in a day.<br />
WEEK<br />
Number of milliseconds in a week.<br />
<br />
Format flags for parsing and formatting functions are defined as constants. Multiple flags can be combined via addition or bitwise ORing.<br />
<br />
<pre class="language-javascript"> <br />
DAYOFWEEK<br />
Day of the week<br />
DATE<br />
Date<br />
TIME<br />
Time<br />
TIMEZONE<br />
Timezone<br />
</pre><br />
Valid format flag combinations have dedicated constants. In a combination, DAYOFWEEK implies DATE and TIMEZONE implies TIME.<br />
<br />
<pre class="language-javascript"> <br />
DAYOFWEEK_DATE<br />
DAYOFWEEK + DATE<br />
DATE_TIME<br />
DATE + TIME<br />
DAYOFWEEK_DATE_TIME<br />
DAYOFWEEK + DATE + TIME<br />
TIME_TIMEZONE<br />
TIME + TIMEZONE<br />
DATE_TIME_TIMEZONE<br />
DATE + TIME + TIMEZONE<br />
FULL_DATE<br />
DAYOFWEEK + DATE + TIME + TIMEZONE<br />
Miscellaneous<br />
</pre><br />
See [[#Formatting|Formatting]] for usage of this function.<br />
<br />
getFormat(format)<br />
* Returns the localized format string for the specified format flags.<br />
format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats. The default value is DATE_TIME.<br />
* Returns String - The localized format string which corresponds to the specified format flags. If format is a string, that string is returned unmodified.<br />
<br />
[[Category:AppSuite]][[Category:UI]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Date_and_time&diff=16555AppSuite:Date and time2013-11-26T14:27:02Z<p>Mark.schmidts: /* Time Zones */</p>
<hr />
<div>{{Stability-experimental}}<br />
<br />
<div class="title">Date and Time</div><br />
<br />
The handling of date and time is a complicated mess of historical conventions, which are still changed from time to time by governments around the world. To keep this away from day-to-day activities of developers, the OX App Suite platform provides the module date, which performs conversion between different time zones, formatting and parsing of date and time values.<br />
<br />
== Time Zones ==<br />
<br />
The built-in JavaScript class Date supports calculations using UTC and the operating system's local time zone. Unfortunately, this is not enough. Examples include using a time zone different from the time zone of the client system, or displaying times in multiple time zones at once.<br />
<br />
The class Local is almost a drop-in replacement for Date, with the main difference being that it operates in the default time zone of the OX App Suite user, even if it is different from the time zone of the browser's operating system. The following code displays the current date and time. It will show a different time when called after changing the user's time zone.<br />
<br />
<pre class="language-javascript"><br />
alert(new date.Local());<br />
</pre><br />
<br />
To work with other time zones, the function <tt>getTimeZone()</tt> can be used to create replacement classes similar to Local, which are all descendants of the private class LocalDate (for which all methods are documented below). Since the time zone definitions are loaded on-demand, the function returns a jQuery promise, which is resolved to the class constructor once the time zone definition is loaded. This class can then be used to e.g. convert between time zones.<br />
<br />
<pre class="language-javascript"><br />
date.getTimeZone('America/New_York').done(function (NewYork) {<br />
alert(gettext('New York celebrated New Year\'s at %1$s',<br />
new date.Local(new NewYork(2012, 0, 1))));<br />
});<br />
</pre><br />
<br />
The function getTimeZone() is memoized for performance reasons, i.e. multiple calls with the same argument will return the same promise and will therefore resolve to the same class object.<br />
<br />
== Formatting ==<br />
<br />
The default LocalDate.prototype.toString() method displays the full date and time, including the day of week and the time zone. To allow better control of the resulting string, the method LocalDate.prototype.format() accepts a set of format flags. The flags determine, which fields should be included in the output. Currently, there are four flags:<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local();<br />
alert(d.format(date.DATE));<br />
alert(d.format(date.TIME));<br />
alert(d.format(date.DAYOFWEEK));<br />
alert(d.format(date.TIMEZONE));<br />
</pre><br />
<br />
Multiple flags can be combined by adding them, or by using one of the predefined combination constants. Not all possible combinations produce unique results. When DAYOFWEEK is specified together with any other fields, DATE is automatically included in the output. Similarly, TIMEZONE implies TIME when used with other fields.<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local();<br />
assert(d.format(date.DAYOFWEEK + date.TIMEZONE) === d.format(date.FULL_DATE);<br />
</pre><br />
<br />
The format flags select one of several predefined format strings, which is stored in the current locale settings. This frees both the developers and the translators from having to remember arcane letter combinations.<br />
<br />
For the case that even finer control of the generated output is required, LocalDate.prototype.format() accepts a format string directly. The syntax of the format strings is a subset of CLDR date format patterns. Format specifiers which are not used in the Gregorian calendar will be implemented on-demand.<br />
<br />
<pre class="language-javascript"><br />
alert(new date.Local().format('EEEE'));<br />
</pre><br />
<br />
In general, if format strings are required, this indicates that the current date API should be extended. Feedback is always welcome.<br />
<br />
One situation where direct access to format strings is useful, is the manipulation of the localized format strings, e.g. to decorate individual fields in a displayed date with HTML markup. To achieve this, the localized format string is retrieved with getFormat(), and parts of it passed individually to LocalDate.prototype.format().<br />
<br />
<pre class="language-javascript"><br />
// Get the original format string.<br />
var fmt = date.getFormat(date.FULL_DATE);<br />
<br />
// Regular expression to parse the format string.<br />
// . . ( time zone )|quote|'quoted text'|rest<br />
var re = /(v+|V+|z+|Z+)|(?:''|'(?:[^']|'')*'|[^vVzZ'])+/g;<br />
<br />
// Appends a formatted date to a jQuery node and returns<br />
// the time zone as a separate node.<br />
function decorateTimeZone(d, parent) {<br />
var span;<br />
fmt.replace(re, function (match, tz) {<br />
if (tz) { // found the time zone field<br />
// Wrap the formatted time zone in a <span> element.<br />
span = $('<span>').text(d.format(match));<br />
parent.append(result);<br />
} else {<br />
// Append all other formatted text as plain text nodes.<br />
parent.append($.txt(d.format(match)));<br />
}<br />
});<br />
// Return the wrapped field for further customization.<br />
return span;<br />
}<br />
</pre><br />
<br />
''Does anybody want this use case as an API function?''<br />
<br />
== Intervals ==<br />
<br />
In addition to formatting individual dates, LocalDate instances can format intervals. The difference to simply inserting two dates into a translated string is that short intervals may have a compacter representation, e.g. 'Jan 1–10, 2012' instead of 'Jan 1, 2012 – Jan 10, 2012'.<br />
<br />
<pre class="language-javascript"><br />
var start = new date.Local(), end = new date.Local(start);<br />
end.add(date.DAY);<br />
alert(start.formatInterval(end, date.DATE));<br />
</pre><br />
<br />
The methods LocalDate.prototype.formatInterval() and LocalDate.prototype.getIntervalFormat() are used like LocalDate.prototype.format() and getFormat(), with two differences. First, the interval functions accept the end of the interval as first parameter before the format flags. And second, since the format string depends on the actual interval, LocalDate.prototype.getIntervalFormat() is a member function and requires the same end value as used later for LocalDate.prototype.formatInterval().<br />
<br />
== Parsing ==<br />
<br />
Parsing is the reverse of formatting, except that ideally, users should be able to enter almost anything, as long as it is not ambiguous. The practice looks a bit more restricted. The LocalDate.parse() function takes a format parameter like the formatting functions, and expects the parsed string to match it very closely.<br />
<br />
<pre class="language-javascript"><br />
var input = prompt(gettext('Please enter a date'), '');<br />
var d = date.Local.parse(input, date.DATE);<br />
alert(gettext('I understood %1$s', d);<br />
</pre><br />
<br />
If there is demand, we can implement some heuristics. There are a lot of abstract algorithm descriptions in the standards, which describe how to parse almost anything while using the format string only as disambiguation help.<br />
<br />
== Manipulation of LocalDate objects ==<br />
<br />
Since the LocalDate class is designed as a drop-in for the Date class, its instances support getter and setter methods for all fields of a date. They can be used to modify an existing LocalDate object, e. g. to round a date to the nearest day or hour.<br />
<br />
<pre class="language-javascript"><br />
var start = new date.Local(), end = new date.Local(start);<br />
start.setHours(0, 0, 0, 0);<br />
end.setHours(24, 0, 0, 0);<br />
alert(gettext('Today is %1$s', start.formatInterval(end)));<br />
</pre><br />
<br />
One manipulation, which is often needed in calendars, is iteration over time. This operation seems simple, at least for iteration steps with a constant duration like hours, days or weeks. One just needs to add the step duration to the timestamp. While there is a method to do exactly this, LocalDate.prototype.addUTC(), you will encounter problems as soon as the iteration transcends a daylight savings switch. First, days and weeks are not actually constant. And second, sometimes the iteration might need to follow the displayed 'wall clock' time instead of the physical time. For these cases, the method LocalDate.prototype.add() increments the local time instead of the UTC time. Both methods accept an increment value in milliseconds, which can also be negative. There are predefined constants for the most common (almost-)fixed-duration periods.<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local(2012, 2);<br />
for (; d.getMonth() < 3; d.add(date.DAY)) {<br />
// Display a day in a month view.<br />
}<br />
</pre><br />
<br />
Iteration with larger intervals like months and years has the additional difficulty, that a single numeric parameter like 30 * date.DAY cannot be interpreted as a month, because it might be just really 30 days. To solve this, there are separate methods for months and years: LocalDate.prototype.addMonths() and LocalDate.prototype.addYears(). They accept the number of months, respective years as parameter.<br />
<br />
<pre class="language-javascript"> <br />
var d = new date.Local(2012, 0);<br />
for (; g.getYear() < 2013; d.addMonths(1)) {<br />
// Display a month in a year view.<br />
}<br />
</pre><br />
<br />
Finally, most calendars default to displaying the current date, and therefore need to figure out the iteration range based on an arbitrary point inside that range. In most cases, the start can be computed by simply calling the appropriate setters with all zeros as parameters to find the start of the range, and adding the range duration to find the end. One exception is the week. There is no setter for the day of the week. Instead, the method LocalDate.prototype.setStartOfWeek() can be used to find the start of a week.<br />
<br />
<pre class="language-javascript"> <br />
// Find the start and the end of the current week<br />
var d = new date.Local().setStartOfWeek();<br />
var end = new date.Local(start).add(date.WEEK);<br />
// Iterate over the week<br />
for (; d < end; d.add(date.DAY)) {<br />
// Display a day in a week view.<br />
}<br />
</pre><br />
<br />
In addition to explicit method calls, the JavaScript standard method LocalDate.prototype.valueOf() allows native comparison, addition and subtraction operators to work on LocalDate objects. The result of LocalDate.prototype.valueOf(), and therefore of addition and subtraction, is a timestamp, which can be passed to the LocalDate constructor to get a LocalDate object again.<br />
<br />
<pre class="language-javascript"> <br />
var start = date.Local.parse(prompt(gettext('Start date'), ''));<br />
var end = date.Local.parse(prompt(gettext('End date'), ''));<br />
if (end < start) alert(gettext('Invalid date range!'));<br />
</pre><br />
<br />
== Differences between LocalDate and Date ==<br />
<br />
The LocalDate classes duplicate most of the Date API with a few exceptions:<br />
<br />
* The constructor can not be called as a function. The Date constructor does in this case nothing useful anyway.<br />
* The constructor always uses full years, it does not add 1900 for years 0 to 99.<br />
* Date.UTC() should not be necessary, but since it returns a numeric timestamp and has nothing to do with time zones, it can still be used directly.<br />
* Except for LocalDate.prototype.toString(), all to*String() methods are replaced by LocalDate.prototype.format().<br />
* There are no UTC variants of getters and setters. They should not be necessary. But just in case, you can still use a LocalDate class for the time zone 'UTC' instead.<br />
* The getter and setter for the year are called getYear and setYear instead of getFullYear and setFullYear since we have no legacy code with Y2K issues.<br />
* Setters return the modified object instead of the timestamp. This is useful for chaining of method calls.<br />
* Date.prototype.getTimeZoneOffset() should not be necessary, since hiding these details is the whole point of the date module. If still necessary, LocalDate.getTTInfo() can be used instead.<br />
<br />
== API Reference ==<br />
<br />
This section provides a short reference of the date API.<br />
<br />
=== Locale ===<br />
<br />
A locale describes the localization settings which usually depend not only on thelanguage, but also on the region and optionally even on the personal preferences of the user. The locale object is loaded at startup and provides various settings and translations.<br />
<br />
Various arrays containing translations can be used directly without any other date function.<br />
<br />
locale.dayPeriods<br />
A map from an identifier of a day period to the corresponding translation. The members am and pm are used in the 12h time format, but other members may be useful for greetings. Is anyone interested in a function which returns the correct greeting period for a given time? If not, maybe remove everything except AM and PM?<br />
locale.days<br />
An array with translated full names of days of the week, starting with Sunday. CLDR context: "format", CLDR width: "wide".<br />
locale.daysShort<br />
An array with translated abbreviated names of days of the week, starting with Sunday. CLDR context: "format", CLDR width: "abbreviated".<br />
locale.daysStandalone<br />
An array with translated standalone names of days of the week, starting with Sunday. CLDR context: "standalone", CLDR width: "abbreviated".<br />
locale.eras<br />
An array with translated abbreviations for the two eras of the Gregorian calendar: BC and AD (in that order).<br />
locale.months<br />
An array with translated full names of months. CLDR context: "format", CLDR width: "wide".<br />
locale.monthsShort<br />
An array with translated abbreviated names of months. CLDR context: "format", CLDR width: "abbreviated".<br />
Diverse week-based calculations need to know on which day the week starts and how the first week of the year is defined.<br />
<br />
locale.daysInFirstWeek<br />
The lowest number of days of a week which must be in the new year for that week to be considered week number 1. Common values are<br />
* 1 if the week of January 1st is week number 1,<br />
* 4 if the first week which has most of its days in the new year is week number 1.<br />
* 7 if the first week which starts in the new year is week number 1.<br />
locale.weekStart<br />
First day of the week. Common values are<br />
* 0 for Sunday,<br />
* 1 for Monday.<br />
Deprecated and internal fields should not be used since they can change or disappear entirely without notice. They are still documented here for completeness.<br />
<br />
locale.date<br />
Deprecated, use DATE instead.<br />
locale.dateTime<br />
Deprecated, use DATE_TIMEinstead.<br />
locale.dateTimeFormat<br />
The default format used to combine a time (%1$s) and a date (%2$s). Not used yet, will probably disappear.<br />
locale.formats<br />
A map from various canonical sets of format fields to the corresponding localized format strings. Used mainly by getFormat(). Maybe remove it from the public interface after loading, since it's internal?<br />
locale.h12<br />
A boolean indicating whether the 12h format is used. WANTED: a better name.<br />
locale.intervals<br />
A map from various canonical sets of format fields to the corresponding formatting rules. A formatting rule is a map from the largest field, which is different between the start and end of the interval, to the corresponding localized formatting string. The field is specified as a single lower case letter. The formatting string is split at the first repeating field. The first part is formatted using the start of the interval, the second part is formatted using the end of the interval. Used mainly by LocalDate.prototype.getIntervalFormat(). Maybe remove it from the public interface after loading, since it's internal?<br />
locale.intervals.fallback<br />
The default format string to combine the start (%1$s) and end (%2$s) of an interval when none of the other members of locale.intervals apply. Maybe remove it from the public interface after loading, since it's internal?<br />
locale.time<br />
Deprecated, use TIME instead.<br />
getTimeZone<br />
<br />
The main entry points of the date API are the class Local which replaces Date for use with the user's default time zone and a function to generate similar classes for arbitrary time zones.<br />
<br />
getTimeZone(name)<br />
Creates a LocalDate class which operates in the specified time zone. Multiple calls with the same name will return the same object.<br />
name String - The name of the requested time zone. It must be one of the values returned by api/config/availableTimeZones.<br />
Returns Promise - A promise which resolves to a LocalDate class which uses the requested time zone.<br />
Local<br />
A convenience LocalDate class which uses the user's current time zone.<br />
<br />
=== LocalDate ===<br />
<br />
The core of the date API is the abstract class LocalDate which is the superclass of time zone specific classes. The class itself is not publically available, only its subclasses can be created by calling getTimeZone(). The subclasses and their instances are referred to as LocalDate classes and LocalDate objects.<br />
<br />
The constructor mimics the behavior of the Date class, but it can't be called as a function.<br />
<br />
<pre class="language-javascript"> <br />
new LocalDate()<br />
new LocalDate(timestamp)<br />
new LocalDate(year, month, date, hours, minutes, seconds, ms)<br />
</pre><br />
<br />
The constructor accepts the same parameters as the Date constructor.<br />
The entire functionality of the class is based on a few low level functions. They should not be necessary outside the date module itself, assuming the API is complete. If you find you need these functions, please let's extend the high level APIs instead.<br />
<br />
LocalDate.getTTInfo(t)<br />
Returns the GMT offset, daylight savings and the abbreviation of the time zone which are in effect at the specified time.<br />
t Timestamp - The timestamp.<br />
Returns { gmtoff, isdst, abbr } - An object with the GMT offset in milliseconds, whether daylight savings are in effect (0 or 1, not a real boolean) and the abbreviation like 'CET' (!isdst) or 'CEST' (!!isdst).<br />
LocalDate.getTTInfoLocal(t)<br />
* Returns the GMT offset, daylight savings and the abbreviation of the time zone which are in effect at the specified local time. If the local time is ambiguous or invalid, the same fallbacks as for LocalDate.utc() are used. (It is actually implemented as a wrapper for this function.)<br />
* t Number - The local time.<br />
* Returns { gmtoff, isdst, abbr } - An object with the GMT offset in milliseconds, whether daylight savings are in effect (0 or 1, not a real boolean) and the abbreviation like 'CET' (!isdst) or 'CEST' (!!isdst).<br />
<br />
LocalDate.localTime(t)<br />
* Converts a UTC timestamp to local time.<br />
* t Timestamp - The UTC timestamp to convert.<br />
* Returns Number - A local time which is used in computations of date and time components.<br />
<br />
LocalDate.utc(t)<br />
* Converts local time to a UTC timestamp. If the local time is ambiguous because of a DST switch, the local time is interpreted as before the switch. E.g. 02:30 at the end of DST is interpreted as DST. If the local time is invalid because of a DST switch, the local time is interpreted as if the switch already occurred. E.g. 02:30 at the start of DST returns the same timestamp as 01:30 before the switch.<br />
* t Number - The local time to convert.<br />
* Returns Timestamp - The corresponsing UTC timestamp.<br />
Metadata about a time zone is stored directly on the LocalDate object.<br />
<br />
LocalDate.id<br />
* Original name used to retrieve this time zone.<br />
<br />
LocalDate.displayName<br />
* A human-readable name of this time zone as provided by the config module under "availableTimeZones".<br />
* Parsing of date and time strings as entered by a user is done using format flags from Constants. The current implementation expects the string to match the corresponding localized format string pretty closely. Any difficulties with parsing common entered dates and times should be taken as an opportunity to extend the parsing heuristics.<br />
<br />
LocalDate.parse(string, format)<br />
* Parses a string using either the specified format string or localized version of one of predefined format strings selected by format flags.<br />
* string String - The string to parse.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats.<br />
* Returns LocalDate or null - A new LocalDate object which represents the parsed date and time or null if the string could not be parsed.<br />
* Methods of LocalDate instances can be grouped into several categories. The first are the setters and getters for individual fields from Date. Since each LocalDate class has its own time zone, There are no UTC variants of each getter and setter. They all work with local time.<br />
<br />
<pre class="language-javascript"> <br />
LocalDate.prototype.getYear()<br />
LocalDate.prototype.getMonth()<br />
LocalDate.prototype.getDate()<br />
LocalDate.prototype.getHours()<br />
LocalDate.prototype.getMinutes()<br />
LocalDate.prototype.getSeconds()<br />
LocalDate.prototype.getMilliseconds()<br />
</pre><br />
* Return the corresponding field of the local date or time.<br />
* Returns Number - The requested field, as a number.<br />
<br />
<pre class="language-javascript"> <br />
LocalDate.prototype.setYear(year, month, date)<br />
LocalDate.prototype.setMonth(month, date)<br />
LocalDate.prototype.setDate(date)<br />
LocalDate.prototype.setHours(hour, min, sec, ms)<br />
LocalDate.prototype.setMinutes(min, sec, ms)<br />
LocalDate.prototype.setSeconds(sec, ms)<br />
LocalDate.prototype.setMilliseconds(ms)<br />
</pre><br />
* Set the specified date or time fields. Any unspecified fields retain their current value. Values outside of the specified ranges will result in overflow to the neighboring periods and can therefore be used for date arithmetic.<br />
** year Number - The year.<br />
** month Number - The month. Values range from 0 for January to 11 for December.<br />
** date Number - The date. Values range from 1 to 31.<br />
** hour Number - The hours. Values range from 0 to 23.<br />
** min Number - The minutes. Values range from 0 to 59.<br />
** sec Number - The seconds. Values range from 0 to 59.<br />
** ms Number - The milliseconds. Values range from 0 to 999.<br />
<br />
LocalDate.prototype.getDay()<br />
* Returns Number - The day of the week. Values range from 0 for Sunday to 6 for Saturday.<br />
<br />
LocalDate.prototype.getTimeZone()<br />
* This method is not present in Date. It returns the abbreviation of the specific time zone. The abbreviation indicate the GMT offset and is therefore different between daylight savings time and standard time.<br />
* Returns String - The abbreviation of the specific time zone.<br />
* Other getters and setters work with the entire timestamp and not just individual fields.<br />
<br />
LocalDate.prototype.getDays()<br />
* Returns the day number of this object. This may be useful to find the start of the same day (by multiplying the result with DAY).<br />
* Returns Number - The number of days since 1970-01-01 in this object's time zone.<br />
<br />
LocalDate.prototype.getTime()<br />
* Returns Timestamp - The UTC timestamp of this object.<br />
<br />
LocalDate.prototype.setTime(time)<br />
* Sets the UTC timestamp to a new value.<br />
* time Timestamp - The new UTC timestamp of this object.<br />
* While setters can be used to perform date arithmetic, LocalDate provides convenience functions for the most frequent cases of adding and subtracting a time period and finding the start of a week.<br />
<br />
LocalDate.prototype.add(time)<br />
* Adds or subtracts a time period in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
* time Number - The time period to add, in milliseconds. Use negative values to subtract. See also Constants.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addUTC(time)<br />
* Adds or subtracts a physical time period, i.e. simply increments the timestamp.<br />
time Number - The time period to add, in milliseconds. Use negative values to subtract. See also Constants.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addMonths(months)<br />
* Adds or subtracts a number of months in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
months Number - The number of months to add. Use negative values to subtract.<br />
Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addYears(years)<br />
* Adds or subtracts a number of years in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
years Number - The number of years to add. Use negative values to subtract.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.setStartOfWeek()<br />
* Sets the date to the start of the same week as determined by locale.weekStart. The time is reset to midnight.<br />
* Returns this - This object for chaining.<br />
* Formatting functions implement the conversion of dates and intervals into localized strings which are suitable for direct presentation to the user.<br />
<br />
LocalDate.prototype.format(format)<br />
* Formats the date according to the specified format flags or format string.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats. The default value is DATE_TIME.<br />
* Returns String - This object formatted according to the specified format.<br />
<br />
LocalDate.prototype.getIntervalFormat(end, format)<br />
* Returns a format string for a time interval with this object as the start and another LocalDate object as the end.<br />
* end LocalDate - The end of the interval.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.intervals and locale.formats. The default value is DATE_TIME.<br />
* Returns String - The format string for the interval accorging to the specified format.<br />
<br />
LocalDate.prototype.formatInterval(end, format)<br />
* Formats an interval with this object as the start and another LocalDate object as the end.<br />
end LocalDate - The end of the interval.<br />
format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.intervals and locale.formats. The default value is DATE_TIME.<br />
* Returns String - The interval formatted accorging to the specified format.<br />
* Finally, the JavaScript standard conversion functions allow easy debugging and arithmetic on timestamps.<br />
<br />
LocalDate.prototype.toString()<br />
* Converts this object to a string using this.format(FULL_DATE).<br />
* Returns String - The string representation of this object.<br />
<br />
LocalDate.prototype.valueOf()<br />
* Converts this object to a primitive value by returning the UTC timestamp. This can be used for arithmetic directly on LocalDate objects and as the single parameter to new LocalDate().<br />
* Returns Timestamp - The UTC timestamp of this object.<br />
<br />
=== Constants ===<br />
<br />
All date classes operate on timestamps expressed as milliseconds since the UNIX epoch, 1970-01-01 00:00 UTC. The date module defines constants for common time intervals with a constant duration.<br />
<br />
SECOND<br />
Number of milliseconds in a second.<br />
MINUTE<br />
Number of milliseconds in a minute.<br />
HOUR<br />
Number of milliseconds in an hour.<br />
DAY<br />
Number of milliseconds in a day.<br />
WEEK<br />
Number of milliseconds in a week.<br />
<br />
Format flags for parsing and formatting functions are defined as constants. Multiple flags can be combined via addition or bitwise ORing.<br />
<br />
<pre class="language-javascript"> <br />
DAYOFWEEK<br />
Day of the week<br />
DATE<br />
Date<br />
TIME<br />
Time<br />
TIMEZONE<br />
Timezone<br />
</pre><br />
Valid format flag combinations have dedicated constants. In a combination, DAYOFWEEK implies DATE and TIMEZONE implies TIME.<br />
<br />
<pre class="language-javascript"> <br />
DAYOFWEEK_DATE<br />
DAYOFWEEK + DATE<br />
DATE_TIME<br />
DATE + TIME<br />
DAYOFWEEK_DATE_TIME<br />
DAYOFWEEK + DATE + TIME<br />
TIME_TIMEZONE<br />
TIME + TIMEZONE<br />
DATE_TIME_TIMEZONE<br />
DATE + TIME + TIMEZONE<br />
FULL_DATE<br />
DAYOFWEEK + DATE + TIME + TIMEZONE<br />
Miscellaneous<br />
</pre><br />
See [[#Formatting|Formatting]] for usage of this function.<br />
<br />
getFormat(format)<br />
* Returns the localized format string for the specified format flags.<br />
format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats. The default value is DATE_TIME.<br />
* Returns String - The localized format string which corresponds to the specified format flags. If format is a string, that string is returned unmodified.<br />
<br />
[[Category:AppSuite]][[Category:UI]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Date_and_time&diff=16554AppSuite:Date and time2013-11-26T14:24:09Z<p>Mark.schmidts: /* Time Zones */</p>
<hr />
<div>{{Stability-experimental}}<br />
<br />
<div class="title">Date and Time</div><br />
<br />
The handling of date and time is a complicated mess of historical conventions, which are still changed from time to time by governments around the world. To keep this away from day-to-day activities of developers, the OX App Suite platform provides the module date, which performs conversion between different time zones, formatting and parsing of date and time values.<br />
<br />
== Time Zones ==<br />
<br />
The built-in JavaScript class Date supports calculations using UTC and the operating system's local time zone. Unfortunately, this is not enough. Examples include using a time zone different from the time zone of the client system, or displaying times in multiple time zones at once.<br />
<br />
The class Local is almost a drop-in replacement for Date, with the main difference being that it operates in the default time zone of the OX App Suite user, even if it is different from the time zone of the browser's operating system. The following code displays the current date and time. It will show a different time when called after changing the user's time zone.<br />
<br />
<pre class="language-javascript"><br />
alert(new date.Local());<br />
</pre><br />
<br />
To work with other time zones, the function getTimeZone() can be used to create replacement classes similar to Local, which are all descendants of the private class LocalDate (for which all methods are documented below). Since the time zone definitions are loaded on-demand, the function returns a jQuery promise, which is resolved to the class constructor once the time zone definition is loaded. This class can then be used to e.g. convert between time zones.<br />
<br />
<pre class="language-javascript"><br />
date.getTimeZone('America/New_York').done(function (NewYork) {<br />
alert(gettext('New York celebrated New Year\'s at %1$s',<br />
new date.Local(new NewYork(2012, 0, 1))));<br />
});<br />
</pre><br />
<br />
The function getTimeZone() is memoized for performance reasons, i.e. multiple calls with the same argument will return the same promise and will therefore resolve to the same class object.<br />
<br />
== Formatting ==<br />
<br />
The default LocalDate.prototype.toString() method displays the full date and time, including the day of week and the time zone. To allow better control of the resulting string, the method LocalDate.prototype.format() accepts a set of format flags. The flags determine, which fields should be included in the output. Currently, there are four flags:<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local();<br />
alert(d.format(date.DATE));<br />
alert(d.format(date.TIME));<br />
alert(d.format(date.DAYOFWEEK));<br />
alert(d.format(date.TIMEZONE));<br />
</pre><br />
<br />
Multiple flags can be combined by adding them, or by using one of the predefined combination constants. Not all possible combinations produce unique results. When DAYOFWEEK is specified together with any other fields, DATE is automatically included in the output. Similarly, TIMEZONE implies TIME when used with other fields.<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local();<br />
assert(d.format(date.DAYOFWEEK + date.TIMEZONE) === d.format(date.FULL_DATE);<br />
</pre><br />
<br />
The format flags select one of several predefined format strings, which is stored in the current locale settings. This frees both the developers and the translators from having to remember arcane letter combinations.<br />
<br />
For the case that even finer control of the generated output is required, LocalDate.prototype.format() accepts a format string directly. The syntax of the format strings is a subset of CLDR date format patterns. Format specifiers which are not used in the Gregorian calendar will be implemented on-demand.<br />
<br />
<pre class="language-javascript"><br />
alert(new date.Local().format('EEEE'));<br />
</pre><br />
<br />
In general, if format strings are required, this indicates that the current date API should be extended. Feedback is always welcome.<br />
<br />
One situation where direct access to format strings is useful, is the manipulation of the localized format strings, e.g. to decorate individual fields in a displayed date with HTML markup. To achieve this, the localized format string is retrieved with getFormat(), and parts of it passed individually to LocalDate.prototype.format().<br />
<br />
<pre class="language-javascript"><br />
// Get the original format string.<br />
var fmt = date.getFormat(date.FULL_DATE);<br />
<br />
// Regular expression to parse the format string.<br />
// . . ( time zone )|quote|'quoted text'|rest<br />
var re = /(v+|V+|z+|Z+)|(?:''|'(?:[^']|'')*'|[^vVzZ'])+/g;<br />
<br />
// Appends a formatted date to a jQuery node and returns<br />
// the time zone as a separate node.<br />
function decorateTimeZone(d, parent) {<br />
var span;<br />
fmt.replace(re, function (match, tz) {<br />
if (tz) { // found the time zone field<br />
// Wrap the formatted time zone in a <span> element.<br />
span = $('<span>').text(d.format(match));<br />
parent.append(result);<br />
} else {<br />
// Append all other formatted text as plain text nodes.<br />
parent.append($.txt(d.format(match)));<br />
}<br />
});<br />
// Return the wrapped field for further customization.<br />
return span;<br />
}<br />
</pre><br />
<br />
''Does anybody want this use case as an API function?''<br />
<br />
== Intervals ==<br />
<br />
In addition to formatting individual dates, LocalDate instances can format intervals. The difference to simply inserting two dates into a translated string is that short intervals may have a compacter representation, e.g. 'Jan 1–10, 2012' instead of 'Jan 1, 2012 – Jan 10, 2012'.<br />
<br />
<pre class="language-javascript"><br />
var start = new date.Local(), end = new date.Local(start);<br />
end.add(date.DAY);<br />
alert(start.formatInterval(end, date.DATE));<br />
</pre><br />
<br />
The methods LocalDate.prototype.formatInterval() and LocalDate.prototype.getIntervalFormat() are used like LocalDate.prototype.format() and getFormat(), with two differences. First, the interval functions accept the end of the interval as first parameter before the format flags. And second, since the format string depends on the actual interval, LocalDate.prototype.getIntervalFormat() is a member function and requires the same end value as used later for LocalDate.prototype.formatInterval().<br />
<br />
== Parsing ==<br />
<br />
Parsing is the reverse of formatting, except that ideally, users should be able to enter almost anything, as long as it is not ambiguous. The practice looks a bit more restricted. The LocalDate.parse() function takes a format parameter like the formatting functions, and expects the parsed string to match it very closely.<br />
<br />
<pre class="language-javascript"><br />
var input = prompt(gettext('Please enter a date'), '');<br />
var d = date.Local.parse(input, date.DATE);<br />
alert(gettext('I understood %1$s', d);<br />
</pre><br />
<br />
If there is demand, we can implement some heuristics. There are a lot of abstract algorithm descriptions in the standards, which describe how to parse almost anything while using the format string only as disambiguation help.<br />
<br />
== Manipulation of LocalDate objects ==<br />
<br />
Since the LocalDate class is designed as a drop-in for the Date class, its instances support getter and setter methods for all fields of a date. They can be used to modify an existing LocalDate object, e. g. to round a date to the nearest day or hour.<br />
<br />
<pre class="language-javascript"><br />
var start = new date.Local(), end = new date.Local(start);<br />
start.setHours(0, 0, 0, 0);<br />
end.setHours(24, 0, 0, 0);<br />
alert(gettext('Today is %1$s', start.formatInterval(end)));<br />
</pre><br />
<br />
One manipulation, which is often needed in calendars, is iteration over time. This operation seems simple, at least for iteration steps with a constant duration like hours, days or weeks. One just needs to add the step duration to the timestamp. While there is a method to do exactly this, LocalDate.prototype.addUTC(), you will encounter problems as soon as the iteration transcends a daylight savings switch. First, days and weeks are not actually constant. And second, sometimes the iteration might need to follow the displayed 'wall clock' time instead of the physical time. For these cases, the method LocalDate.prototype.add() increments the local time instead of the UTC time. Both methods accept an increment value in milliseconds, which can also be negative. There are predefined constants for the most common (almost-)fixed-duration periods.<br />
<br />
<pre class="language-javascript"><br />
var d = new date.Local(2012, 2);<br />
for (; d.getMonth() < 3; d.add(date.DAY)) {<br />
// Display a day in a month view.<br />
}<br />
</pre><br />
<br />
Iteration with larger intervals like months and years has the additional difficulty, that a single numeric parameter like 30 * date.DAY cannot be interpreted as a month, because it might be just really 30 days. To solve this, there are separate methods for months and years: LocalDate.prototype.addMonths() and LocalDate.prototype.addYears(). They accept the number of months, respective years as parameter.<br />
<br />
<pre class="language-javascript"> <br />
var d = new date.Local(2012, 0);<br />
for (; g.getYear() < 2013; d.addMonths(1)) {<br />
// Display a month in a year view.<br />
}<br />
</pre><br />
<br />
Finally, most calendars default to displaying the current date, and therefore need to figure out the iteration range based on an arbitrary point inside that range. In most cases, the start can be computed by simply calling the appropriate setters with all zeros as parameters to find the start of the range, and adding the range duration to find the end. One exception is the week. There is no setter for the day of the week. Instead, the method LocalDate.prototype.setStartOfWeek() can be used to find the start of a week.<br />
<br />
<pre class="language-javascript"> <br />
// Find the start and the end of the current week<br />
var d = new date.Local().setStartOfWeek();<br />
var end = new date.Local(start).add(date.WEEK);<br />
// Iterate over the week<br />
for (; d < end; d.add(date.DAY)) {<br />
// Display a day in a week view.<br />
}<br />
</pre><br />
<br />
In addition to explicit method calls, the JavaScript standard method LocalDate.prototype.valueOf() allows native comparison, addition and subtraction operators to work on LocalDate objects. The result of LocalDate.prototype.valueOf(), and therefore of addition and subtraction, is a timestamp, which can be passed to the LocalDate constructor to get a LocalDate object again.<br />
<br />
<pre class="language-javascript"> <br />
var start = date.Local.parse(prompt(gettext('Start date'), ''));<br />
var end = date.Local.parse(prompt(gettext('End date'), ''));<br />
if (end < start) alert(gettext('Invalid date range!'));<br />
</pre><br />
<br />
== Differences between LocalDate and Date ==<br />
<br />
The LocalDate classes duplicate most of the Date API with a few exceptions:<br />
<br />
* The constructor can not be called as a function. The Date constructor does in this case nothing useful anyway.<br />
* The constructor always uses full years, it does not add 1900 for years 0 to 99.<br />
* Date.UTC() should not be necessary, but since it returns a numeric timestamp and has nothing to do with time zones, it can still be used directly.<br />
* Except for LocalDate.prototype.toString(), all to*String() methods are replaced by LocalDate.prototype.format().<br />
* There are no UTC variants of getters and setters. They should not be necessary. But just in case, you can still use a LocalDate class for the time zone 'UTC' instead.<br />
* The getter and setter for the year are called getYear and setYear instead of getFullYear and setFullYear since we have no legacy code with Y2K issues.<br />
* Setters return the modified object instead of the timestamp. This is useful for chaining of method calls.<br />
* Date.prototype.getTimeZoneOffset() should not be necessary, since hiding these details is the whole point of the date module. If still necessary, LocalDate.getTTInfo() can be used instead.<br />
<br />
== API Reference ==<br />
<br />
This section provides a short reference of the date API.<br />
<br />
=== Locale ===<br />
<br />
A locale describes the localization settings which usually depend not only on thelanguage, but also on the region and optionally even on the personal preferences of the user. The locale object is loaded at startup and provides various settings and translations.<br />
<br />
Various arrays containing translations can be used directly without any other date function.<br />
<br />
locale.dayPeriods<br />
A map from an identifier of a day period to the corresponding translation. The members am and pm are used in the 12h time format, but other members may be useful for greetings. Is anyone interested in a function which returns the correct greeting period for a given time? If not, maybe remove everything except AM and PM?<br />
locale.days<br />
An array with translated full names of days of the week, starting with Sunday. CLDR context: "format", CLDR width: "wide".<br />
locale.daysShort<br />
An array with translated abbreviated names of days of the week, starting with Sunday. CLDR context: "format", CLDR width: "abbreviated".<br />
locale.daysStandalone<br />
An array with translated standalone names of days of the week, starting with Sunday. CLDR context: "standalone", CLDR width: "abbreviated".<br />
locale.eras<br />
An array with translated abbreviations for the two eras of the Gregorian calendar: BC and AD (in that order).<br />
locale.months<br />
An array with translated full names of months. CLDR context: "format", CLDR width: "wide".<br />
locale.monthsShort<br />
An array with translated abbreviated names of months. CLDR context: "format", CLDR width: "abbreviated".<br />
Diverse week-based calculations need to know on which day the week starts and how the first week of the year is defined.<br />
<br />
locale.daysInFirstWeek<br />
The lowest number of days of a week which must be in the new year for that week to be considered week number 1. Common values are<br />
* 1 if the week of January 1st is week number 1,<br />
* 4 if the first week which has most of its days in the new year is week number 1.<br />
* 7 if the first week which starts in the new year is week number 1.<br />
locale.weekStart<br />
First day of the week. Common values are<br />
* 0 for Sunday,<br />
* 1 for Monday.<br />
Deprecated and internal fields should not be used since they can change or disappear entirely without notice. They are still documented here for completeness.<br />
<br />
locale.date<br />
Deprecated, use DATE instead.<br />
locale.dateTime<br />
Deprecated, use DATE_TIMEinstead.<br />
locale.dateTimeFormat<br />
The default format used to combine a time (%1$s) and a date (%2$s). Not used yet, will probably disappear.<br />
locale.formats<br />
A map from various canonical sets of format fields to the corresponding localized format strings. Used mainly by getFormat(). Maybe remove it from the public interface after loading, since it's internal?<br />
locale.h12<br />
A boolean indicating whether the 12h format is used. WANTED: a better name.<br />
locale.intervals<br />
A map from various canonical sets of format fields to the corresponding formatting rules. A formatting rule is a map from the largest field, which is different between the start and end of the interval, to the corresponding localized formatting string. The field is specified as a single lower case letter. The formatting string is split at the first repeating field. The first part is formatted using the start of the interval, the second part is formatted using the end of the interval. Used mainly by LocalDate.prototype.getIntervalFormat(). Maybe remove it from the public interface after loading, since it's internal?<br />
locale.intervals.fallback<br />
The default format string to combine the start (%1$s) and end (%2$s) of an interval when none of the other members of locale.intervals apply. Maybe remove it from the public interface after loading, since it's internal?<br />
locale.time<br />
Deprecated, use TIME instead.<br />
getTimeZone<br />
<br />
The main entry points of the date API are the class Local which replaces Date for use with the user's default time zone and a function to generate similar classes for arbitrary time zones.<br />
<br />
getTimeZone(name)<br />
Creates a LocalDate class which operates in the specified time zone. Multiple calls with the same name will return the same object.<br />
name String - The name of the requested time zone. It must be one of the values returned by api/config/availableTimeZones.<br />
Returns Promise - A promise which resolves to a LocalDate class which uses the requested time zone.<br />
Local<br />
A convenience LocalDate class which uses the user's current time zone.<br />
<br />
=== LocalDate ===<br />
<br />
The core of the date API is the abstract class LocalDate which is the superclass of time zone specific classes. The class itself is not publically available, only its subclasses can be created by calling getTimeZone(). The subclasses and their instances are referred to as LocalDate classes and LocalDate objects.<br />
<br />
The constructor mimics the behavior of the Date class, but it can't be called as a function.<br />
<br />
<pre class="language-javascript"> <br />
new LocalDate()<br />
new LocalDate(timestamp)<br />
new LocalDate(year, month, date, hours, minutes, seconds, ms)<br />
</pre><br />
<br />
The constructor accepts the same parameters as the Date constructor.<br />
The entire functionality of the class is based on a few low level functions. They should not be necessary outside the date module itself, assuming the API is complete. If you find you need these functions, please let's extend the high level APIs instead.<br />
<br />
LocalDate.getTTInfo(t)<br />
Returns the GMT offset, daylight savings and the abbreviation of the time zone which are in effect at the specified time.<br />
t Timestamp - The timestamp.<br />
Returns { gmtoff, isdst, abbr } - An object with the GMT offset in milliseconds, whether daylight savings are in effect (0 or 1, not a real boolean) and the abbreviation like 'CET' (!isdst) or 'CEST' (!!isdst).<br />
LocalDate.getTTInfoLocal(t)<br />
* Returns the GMT offset, daylight savings and the abbreviation of the time zone which are in effect at the specified local time. If the local time is ambiguous or invalid, the same fallbacks as for LocalDate.utc() are used. (It is actually implemented as a wrapper for this function.)<br />
* t Number - The local time.<br />
* Returns { gmtoff, isdst, abbr } - An object with the GMT offset in milliseconds, whether daylight savings are in effect (0 or 1, not a real boolean) and the abbreviation like 'CET' (!isdst) or 'CEST' (!!isdst).<br />
<br />
LocalDate.localTime(t)<br />
* Converts a UTC timestamp to local time.<br />
* t Timestamp - The UTC timestamp to convert.<br />
* Returns Number - A local time which is used in computations of date and time components.<br />
<br />
LocalDate.utc(t)<br />
* Converts local time to a UTC timestamp. If the local time is ambiguous because of a DST switch, the local time is interpreted as before the switch. E.g. 02:30 at the end of DST is interpreted as DST. If the local time is invalid because of a DST switch, the local time is interpreted as if the switch already occurred. E.g. 02:30 at the start of DST returns the same timestamp as 01:30 before the switch.<br />
* t Number - The local time to convert.<br />
* Returns Timestamp - The corresponsing UTC timestamp.<br />
Metadata about a time zone is stored directly on the LocalDate object.<br />
<br />
LocalDate.id<br />
* Original name used to retrieve this time zone.<br />
<br />
LocalDate.displayName<br />
* A human-readable name of this time zone as provided by the config module under "availableTimeZones".<br />
* Parsing of date and time strings as entered by a user is done using format flags from Constants. The current implementation expects the string to match the corresponding localized format string pretty closely. Any difficulties with parsing common entered dates and times should be taken as an opportunity to extend the parsing heuristics.<br />
<br />
LocalDate.parse(string, format)<br />
* Parses a string using either the specified format string or localized version of one of predefined format strings selected by format flags.<br />
* string String - The string to parse.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats.<br />
* Returns LocalDate or null - A new LocalDate object which represents the parsed date and time or null if the string could not be parsed.<br />
* Methods of LocalDate instances can be grouped into several categories. The first are the setters and getters for individual fields from Date. Since each LocalDate class has its own time zone, There are no UTC variants of each getter and setter. They all work with local time.<br />
<br />
<pre class="language-javascript"> <br />
LocalDate.prototype.getYear()<br />
LocalDate.prototype.getMonth()<br />
LocalDate.prototype.getDate()<br />
LocalDate.prototype.getHours()<br />
LocalDate.prototype.getMinutes()<br />
LocalDate.prototype.getSeconds()<br />
LocalDate.prototype.getMilliseconds()<br />
</pre><br />
* Return the corresponding field of the local date or time.<br />
* Returns Number - The requested field, as a number.<br />
<br />
<pre class="language-javascript"> <br />
LocalDate.prototype.setYear(year, month, date)<br />
LocalDate.prototype.setMonth(month, date)<br />
LocalDate.prototype.setDate(date)<br />
LocalDate.prototype.setHours(hour, min, sec, ms)<br />
LocalDate.prototype.setMinutes(min, sec, ms)<br />
LocalDate.prototype.setSeconds(sec, ms)<br />
LocalDate.prototype.setMilliseconds(ms)<br />
</pre><br />
* Set the specified date or time fields. Any unspecified fields retain their current value. Values outside of the specified ranges will result in overflow to the neighboring periods and can therefore be used for date arithmetic.<br />
** year Number - The year.<br />
** month Number - The month. Values range from 0 for January to 11 for December.<br />
** date Number - The date. Values range from 1 to 31.<br />
** hour Number - The hours. Values range from 0 to 23.<br />
** min Number - The minutes. Values range from 0 to 59.<br />
** sec Number - The seconds. Values range from 0 to 59.<br />
** ms Number - The milliseconds. Values range from 0 to 999.<br />
<br />
LocalDate.prototype.getDay()<br />
* Returns Number - The day of the week. Values range from 0 for Sunday to 6 for Saturday.<br />
<br />
LocalDate.prototype.getTimeZone()<br />
* This method is not present in Date. It returns the abbreviation of the specific time zone. The abbreviation indicate the GMT offset and is therefore different between daylight savings time and standard time.<br />
* Returns String - The abbreviation of the specific time zone.<br />
* Other getters and setters work with the entire timestamp and not just individual fields.<br />
<br />
LocalDate.prototype.getDays()<br />
* Returns the day number of this object. This may be useful to find the start of the same day (by multiplying the result with DAY).<br />
* Returns Number - The number of days since 1970-01-01 in this object's time zone.<br />
<br />
LocalDate.prototype.getTime()<br />
* Returns Timestamp - The UTC timestamp of this object.<br />
<br />
LocalDate.prototype.setTime(time)<br />
* Sets the UTC timestamp to a new value.<br />
* time Timestamp - The new UTC timestamp of this object.<br />
* While setters can be used to perform date arithmetic, LocalDate provides convenience functions for the most frequent cases of adding and subtracting a time period and finding the start of a week.<br />
<br />
LocalDate.prototype.add(time)<br />
* Adds or subtracts a time period in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
* time Number - The time period to add, in milliseconds. Use negative values to subtract. See also Constants.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addUTC(time)<br />
* Adds or subtracts a physical time period, i.e. simply increments the timestamp.<br />
time Number - The time period to add, in milliseconds. Use negative values to subtract. See also Constants.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addMonths(months)<br />
* Adds or subtracts a number of months in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
months Number - The number of months to add. Use negative values to subtract.<br />
Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.addYears(years)<br />
* Adds or subtracts a number of years in local time. The results may be invalid if the end result ends up in the middle of a daylight savings switch.<br />
years Number - The number of years to add. Use negative values to subtract.<br />
* Returns this - This object for chaining.<br />
<br />
LocalDate.prototype.setStartOfWeek()<br />
* Sets the date to the start of the same week as determined by locale.weekStart. The time is reset to midnight.<br />
* Returns this - This object for chaining.<br />
* Formatting functions implement the conversion of dates and intervals into localized strings which are suitable for direct presentation to the user.<br />
<br />
LocalDate.prototype.format(format)<br />
* Formats the date according to the specified format flags or format string.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats. The default value is DATE_TIME.<br />
* Returns String - This object formatted according to the specified format.<br />
<br />
LocalDate.prototype.getIntervalFormat(end, format)<br />
* Returns a format string for a time interval with this object as the start and another LocalDate object as the end.<br />
* end LocalDate - The end of the interval.<br />
* format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.intervals and locale.formats. The default value is DATE_TIME.<br />
* Returns String - The format string for the interval accorging to the specified format.<br />
<br />
LocalDate.prototype.formatInterval(end, format)<br />
* Formats an interval with this object as the start and another LocalDate object as the end.<br />
end LocalDate - The end of the interval.<br />
format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.intervals and locale.formats. The default value is DATE_TIME.<br />
* Returns String - The interval formatted accorging to the specified format.<br />
* Finally, the JavaScript standard conversion functions allow easy debugging and arithmetic on timestamps.<br />
<br />
LocalDate.prototype.toString()<br />
* Converts this object to a string using this.format(FULL_DATE).<br />
* Returns String - The string representation of this object.<br />
<br />
LocalDate.prototype.valueOf()<br />
* Converts this object to a primitive value by returning the UTC timestamp. This can be used for arithmetic directly on LocalDate objects and as the single parameter to new LocalDate().<br />
* Returns Timestamp - The UTC timestamp of this object.<br />
<br />
=== Constants ===<br />
<br />
All date classes operate on timestamps expressed as milliseconds since the UNIX epoch, 1970-01-01 00:00 UTC. The date module defines constants for common time intervals with a constant duration.<br />
<br />
SECOND<br />
Number of milliseconds in a second.<br />
MINUTE<br />
Number of milliseconds in a minute.<br />
HOUR<br />
Number of milliseconds in an hour.<br />
DAY<br />
Number of milliseconds in a day.<br />
WEEK<br />
Number of milliseconds in a week.<br />
<br />
Format flags for parsing and formatting functions are defined as constants. Multiple flags can be combined via addition or bitwise ORing.<br />
<br />
<pre class="language-javascript"> <br />
DAYOFWEEK<br />
Day of the week<br />
DATE<br />
Date<br />
TIME<br />
Time<br />
TIMEZONE<br />
Timezone<br />
</pre><br />
Valid format flag combinations have dedicated constants. In a combination, DAYOFWEEK implies DATE and TIMEZONE implies TIME.<br />
<br />
<pre class="language-javascript"> <br />
DAYOFWEEK_DATE<br />
DAYOFWEEK + DATE<br />
DATE_TIME<br />
DATE + TIME<br />
DAYOFWEEK_DATE_TIME<br />
DAYOFWEEK + DATE + TIME<br />
TIME_TIMEZONE<br />
TIME + TIMEZONE<br />
DATE_TIME_TIMEZONE<br />
DATE + TIME + TIMEZONE<br />
FULL_DATE<br />
DAYOFWEEK + DATE + TIME + TIMEZONE<br />
Miscellaneous<br />
</pre><br />
See [[#Formatting|Formatting]] for usage of this function.<br />
<br />
getFormat(format)<br />
* Returns the localized format string for the specified format flags.<br />
format String or Number - Either a format string with the syntax of CLDR date format patterns, or one of the format flag constants. In the second case, the actual format string is localized for the current user's locale according to locale.formats. The default value is DATE_TIME.<br />
* Returns String - The localized format string which corresponds to the specified format flags. If format is a string, that string is returned unmodified.<br />
<br />
[[Category:AppSuite]][[Category:UI]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Developing_for_the_UI&diff=16322AppSuite:Developing for the UI2013-11-05T08:50:31Z<p>Mark.schmidts: /* What can i build? */</p>
<hr />
<div><div class="title">UI Development for OX AppSuite</div><br />
<br />
__TOC__<br />
<br />
This page contains articles about the inner workings of the web-based graphical user interface. It is aimed at software developers that want to improve on existing features, implement extensions or just gain a general understanding.<br />
<br />
=== Tech Overview ===<br />
All technologies and frameworks used for developing a new component for the AppSuite UI are listed and described in the following article: [[AppSuite:UI developer primer| Requirements to develop for the UI]]<br />
<br />
=== Developing Guidelines ===<br />
While developing code for OX products [[AppSuite:UI Development Style Guide | the UI Developement Style Guide]] helps you writing safe, clear and functional code.<br />
<br />
Designing apps, plugins and widgets running with the right layout, colors, look and feel is a breeze following the guidelines described in [[AppSuite:UI Design Guide | the UI Design Guide]].<br />
<br />
Always keep in mind, that using OX products should be possible for everyone and therefor it's important to follow simple rules regarding [[AppSuite:Accessibility | accessibility]].<br />
<br />
=== Using extension points ===<br />
<br />
Writing apps or plugins for AppSuite will often include extending the existing user interface. AppSuite provides extension points offering you possibilties to add your own contents.<br />
Beginning to develop using extension points? Read this guide first having [[AppSuite:Extending the UI (Hands-on introduction) | a hands-on introduction]] for extending the OX user interface. Get more information and a complete list of [[AppSuite:Extension points |extension points]] offered by OX products.<br />
<br />
=== How to get code ===<br />
Using git as a version version control system getting the code from existing OX products is quite easy.<br />
Simply clone the [[AppSuite:UI build system#Source | UI]] or the [[AppSuite:Backend build system#Source | backend]] repository and start working with it.<br />
<br />
=== What can i build? ===<br />
<br />
If you want to have a simple introduction following easy steps from creating your workspace to actually performing your source code within AppSuite, read our [[AppSuite:GettingStarted | GettingStarted guide]].<br />
<br />
There are several other possibilities available to develop for AppSuite.<br />
<br />
*[[AppSuite:Writing a portal plugin | A portal plugin]] is a widget, which can be used in the 'portal'-section of AppSuite only. Please just check for the right [[AppSuite:Extension points |extension point]] to write a plugin which extends and interacts with other parts of AppSuite. Configuring portal plugins can be achieved by reading [[AppSuite:Configuring portal plugins | this guide]].<br />
<br />
*[[AppSuite:Writing_a_contacts_plugin | A contacts plugin]] let's you modify parts of AppSuite's contact view.<br />
<br />
*[[AppSuite:Using the Upsell widget | Upsell Widget]], to enable the AppSuite user to purchase additional features. <br />
<br />
*[[AppSuite:Writing a simple application | A real application/module]] for AppSuite, which should be displayed full screen.<br />
<br />
*[[AppSuite:Writing a notification area plugin | A notification plugin]] for AppSuite<br />
<br />
*[[AppSuite:Writing a wizard | A wizard]], which can be first time users to show them important informations or configure initial settings for 3rd party applications.<br />
<br />
*[[AppSuite:Creating a settings section in AppSuite settings | Settings plugin]] extending AppSuite settings and creating a new section.<br />
<br />
*[[AppSuite:Embedding your settings into AppSuite settings | Settings plugin]] embedding your own settings section via iframe into AppSuite.<br />
<br />
You got stuck somewhere? There are some hints, which might help you [[AppSuite:Debugging_the_UI | debugging the UI]].<br />
<br />
=== How to get your code running ===<br />
Written your first app/plugin? Using the [[AppSuite:UI build system | UI build system]] will help you to get fast, easy-to-distribute and correct builds running on your AppSuite. The article will show you how to package your code and copy from OX source code / directories.<br />
<br />
Since the AppSuite product consists of a server and a UI, you also need a working backend (AppSuite application server) to communicate with. <br />
Therefor you should run [[AppSuite:Appserver | Appserver]] using an existing OX AppSuite server and (with local parts of the AppSuite) automaticly get the recent stable source packages from the AppSuite servers. For using your namespace as a source for hosting your app, simply add the build-path of your app as an parameter while running appserver.<br />
<br />
=== What's next ===<br />
No Idea what to do first? Read our [[AppSuite:GettingStarted | GettingStarted guide]] to have a step-by-step introduction about how to install the SDK, use the Build System, write your first app and get it running.</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Developing_for_the_UI&diff=16268AppSuite:Developing for the UI2013-10-28T13:06:47Z<p>Mark.schmidts: /* What can i build? */</p>
<hr />
<div><div class="title">UI Development for OX AppSuite</div><br />
<br />
__TOC__<br />
<br />
This page contains articles about the inner workings of the web-based graphical user interface. It is aimed at software developers that want to improve on existing features, implement extensions or just gain a general understanding.<br />
<br />
=== Tech Overview ===<br />
All technologies and frameworks used for developing a new component for the AppSuite UI are listed and described in the following article: [[AppSuite:UI developer primer| Requirements to develop for the UI]]<br />
<br />
=== Developing Guidelines ===<br />
While developing code for OX products [[AppSuite:UI Development Style Guide | the UI Developement Style Guide]] helps you writing safe, clear and functional code.<br />
<br />
Designing apps, plugins and widgets running with the right layout, colors, look and feel is a breeze following the guidelines described in [[AppSuite:UI Design Guide | the UI Design Guide]].<br />
<br />
Always keep in mind, that using OX products should be possible for everyone and therefor it's important to follow simple rules regarding [[AppSuite:Accessibility | accessibility]].<br />
<br />
=== Using extension points ===<br />
<br />
Writing apps or plugins for AppSuite will often include extending the existing user interface. AppSuite provides extension points offering you possibilties to add your own contents.<br />
Beginning to develop using extension points? Read this guide first having [[AppSuite:Extending the UI (Hands-on introduction) | a hands-on introduction]] for extending the OX user interface. Get more information and a complete list of [[AppSuite:Extension points |extension points]] offered by OX products.<br />
<br />
=== How to get code ===<br />
Using git as a version version control system getting the code from existing OX products is quite easy.<br />
Simply clone the [[AppSuite:UI build system#Source | UI]] or the [[AppSuite:Backend build system#Source | backend]] repository and start working with it.<br />
<br />
=== What can i build? ===<br />
<br />
If you want to have a simple introduction following easy steps from creating your workspace to actually performing your source code within AppSuite, read our [[AppSuite:GettingStarted | GettingStarted guide]].<br />
<br />
There are several other possibilities available to develop for AppSuite.<br />
<br />
*[[AppSuite:Writing a portal plugin | A portal plugin]] is a widget, which can be used in the 'portal'-section of AppSuite only. Please just check for the right [[AppSuite:Extension points |extension point]] to write a plugin which extends and interacts with other parts of AppSuite. Configuring portal plugins can be achieved by reading [[AppSuite:Configuring portal plugins | this guide]].<br />
<br />
*[[AppSuite:Writing_a_contacts_plugin | A contacts plugin]] let's you modify parts of AppSuite's contact view.<br />
<br />
*[[AppSuite:Using the Upsell widget | Upsell Widget]], to enable the AppSuite user to purchase additional features. <br />
<br />
*[[AppSuite:Writing a simple application | A real application/module]] for AppSuite, which should be displayed full screen and appear as a bread crump in the title bar, take a look at the article about [[AppSuite:Writing a simple application | 'Writing a simple application']].<br />
<br />
*[[AppSuite:Writing a notification area plugin | A notification plugin]] for AppSuite<br />
<br />
*[[AppSuite:Writing a wizard | A wizard]], which can be first time users to show them important informations or configure initial settings for 3rd party applications.<br />
<br />
*[[AppSuite:Creating a settings section in AppSuite settings | Settings plugin]] extending AppSuite settings and creating a new section.<br />
<br />
*[[AppSuite:Embedding your settings into AppSuite settings | Settings plugin]] embedding your own settings section via iframe into AppSuite.<br />
<br />
You got stuck somewhere? There are some hints, which might help you [[AppSuite:Debugging_the_UI | debugging the UI]].<br />
<br />
=== How to get your code running ===<br />
Written your first app/plugin? Using the [[AppSuite:UI build system | UI build system]] will help you to get fast, easy-to-distribute and correct builds running on your AppSuite. The article will show you how to package your code and copy from OX source code / directories.<br />
<br />
Since the AppSuite product consists of a server and a UI, you also need a working backend (AppSuite application server) to communicate with. <br />
Therefor you should run [[AppSuite:Appserver | Appserver]] using an existing OX AppSuite server and (with local parts of the AppSuite) automaticly get the recent stable source packages from the AppSuite servers. For using your namespace as a source for hosting your app, simply add the build-path of your app as an parameter while running appserver.<br />
<br />
=== What's next ===<br />
No Idea what to do first? Read our [[AppSuite:GettingStarted | GettingStarted guide]] to have a step-by-step introduction about how to install the SDK, use the Build System, write your first app and get it running.</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Developing_for_the_UI&diff=16267AppSuite:Developing for the UI2013-10-28T10:52:59Z<p>Mark.schmidts: /* What can i build? */</p>
<hr />
<div><div class="title">UI Development for OX AppSuite</div><br />
<br />
__TOC__<br />
<br />
This page contains articles about the inner workings of the web-based graphical user interface. It is aimed at software developers that want to improve on existing features, implement extensions or just gain a general understanding.<br />
<br />
=== Tech Overview ===<br />
All technologies and frameworks used for developing a new component for the AppSuite UI are listed and described in the following article: [[AppSuite:UI developer primer| Requirements to develop for the UI]]<br />
<br />
=== Developing Guidelines ===<br />
While developing code for OX products [[AppSuite:UI Development Style Guide | the UI Developement Style Guide]] helps you writing safe, clear and functional code.<br />
<br />
Designing apps, plugins and widgets running with the right layout, colors, look and feel is a breeze following the guidelines described in [[AppSuite:UI Design Guide | the UI Design Guide]].<br />
<br />
Always keep in mind, that using OX products should be possible for everyone and therefor it's important to follow simple rules regarding [[AppSuite:Accessibility | accessibility]].<br />
<br />
=== Using extension points ===<br />
<br />
Writing apps or plugins for AppSuite will often include extending the existing user interface. AppSuite provides extension points offering you possibilties to add your own contents.<br />
Beginning to develop using extension points? Read this guide first having [[AppSuite:Extending the UI (Hands-on introduction) | a hands-on introduction]] for extending the OX user interface. Get more information and a complete list of [[AppSuite:Extension points |extension points]] offered by OX products.<br />
<br />
=== How to get code ===<br />
Using git as a version version control system getting the code from existing OX products is quite easy.<br />
Simply clone the [[AppSuite:UI build system#Source | UI]] or the [[AppSuite:Backend build system#Source | backend]] repository and start working with it.<br />
<br />
=== What can i build? ===<br />
<br />
If you want to have a simple introduction following easy steps from creating your workspace to actually performing your source code within AppSuite, read our [[AppSuite:GettingStarted | GettingStarted guide]].<br />
<br />
There are several other possibilities available to develop for AppSuite.<br />
<br />
*[[AppSuite:Writing a portal plugin | A portal plugin]] is a widget, which can be used in the 'portal'-section of AppSuite only. Please just check for the right [[AppSuite:Extension points |extension point]] to write a plugin which extends and interacts with other parts of AppSuite. Configuring portal plugins can be achieved by reading [[AppSuite:Configuring portal plugins | this guide]].<br />
<!--<br />
*[[AppSuite:Writing_a_contacts_plugin | A contacts plugin]] let's you modify parts of AppSuite's contact view.<br />
--><br />
*[[AppSuite:Using the Upsell widget | Upsell Widget]], to enable the AppSuite user to purchase additional features. <br />
<br />
*[[AppSuite:Writing a simple application | A real application/module]] for AppSuite, which should be displayed full screen and appear as a bread crump in the title bar, take a look at the article about [[AppSuite:Writing a simple application | 'Writing a simple application']].<br />
<br />
*[[AppSuite:Writing a notification area plugin | A notification plugin]] for AppSuite<br />
<br />
*[[AppSuite:Writing a wizard | A wizard]], which can be first time users to show them important informations or configure initial settings for 3rd party applications.<br />
<br />
*[[AppSuite:Creating a settings section in AppSuite settings | Settings plugin]] extending AppSuite settings and creating a new section.<br />
<br />
*[[AppSuite:Embedding your settings into AppSuite settings | Settings plugin]] embedding your own settings section via iframe into AppSuite.<br />
<br />
You got stuck somewhere? There are some hints, which might help you [[AppSuite:Debugging_the_UI | debugging the UI]].<br />
<br />
=== How to get your code running ===<br />
Written your first app/plugin? Using the [[AppSuite:UI build system | UI build system]] will help you to get fast, easy-to-distribute and correct builds running on your AppSuite. The article will show you how to package your code and copy from OX source code / directories.<br />
<br />
Since the AppSuite product consists of a server and a UI, you also need a working backend (AppSuite application server) to communicate with. <br />
Therefor you should run [[AppSuite:Appserver | Appserver]] using an existing OX AppSuite server and (with local parts of the AppSuite) automaticly get the recent stable source packages from the AppSuite servers. For using your namespace as a source for hosting your app, simply add the build-path of your app as an parameter while running appserver.<br />
<br />
=== What's next ===<br />
No Idea what to do first? Read our [[AppSuite:GettingStarted | GettingStarted guide]] to have a step-by-step introduction about how to install the SDK, use the Build System, write your first app and get it running.</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Developing_for_the_UI&diff=16266AppSuite:Developing for the UI2013-10-28T10:52:48Z<p>Mark.schmidts: /* What can i build? */</p>
<hr />
<div><div class="title">UI Development for OX AppSuite</div><br />
<br />
__TOC__<br />
<br />
This page contains articles about the inner workings of the web-based graphical user interface. It is aimed at software developers that want to improve on existing features, implement extensions or just gain a general understanding.<br />
<br />
=== Tech Overview ===<br />
All technologies and frameworks used for developing a new component for the AppSuite UI are listed and described in the following article: [[AppSuite:UI developer primer| Requirements to develop for the UI]]<br />
<br />
=== Developing Guidelines ===<br />
While developing code for OX products [[AppSuite:UI Development Style Guide | the UI Developement Style Guide]] helps you writing safe, clear and functional code.<br />
<br />
Designing apps, plugins and widgets running with the right layout, colors, look and feel is a breeze following the guidelines described in [[AppSuite:UI Design Guide | the UI Design Guide]].<br />
<br />
Always keep in mind, that using OX products should be possible for everyone and therefor it's important to follow simple rules regarding [[AppSuite:Accessibility | accessibility]].<br />
<br />
=== Using extension points ===<br />
<br />
Writing apps or plugins for AppSuite will often include extending the existing user interface. AppSuite provides extension points offering you possibilties to add your own contents.<br />
Beginning to develop using extension points? Read this guide first having [[AppSuite:Extending the UI (Hands-on introduction) | a hands-on introduction]] for extending the OX user interface. Get more information and a complete list of [[AppSuite:Extension points |extension points]] offered by OX products.<br />
<br />
=== How to get code ===<br />
Using git as a version version control system getting the code from existing OX products is quite easy.<br />
Simply clone the [[AppSuite:UI build system#Source | UI]] or the [[AppSuite:Backend build system#Source | backend]] repository and start working with it.<br />
<br />
=== What can i build? ===<br />
<br />
If you want to have a simple introduction following easy steps from creating your workspace to actually performing your source code within AppSuite, read our [[AppSuite:GettingStarted | GettingStarted guide]].<br />
<br />
There are several other possibilities available to develop for AppSuite.<br />
<br />
*[[AppSuite:Writing a portal plugin | A portal plugin]] is a widget, which can be used in the 'portal'-section of AppSuite only. Please just check for the right [[AppSuite:Extension points |extension point]] to write a plugin which extends and interacts with other parts of AppSuite. Configuring portal plugins can be achieved by reading [[AppSuite:Configuring portal plugins | this guide]].<br />
<br />
<!--<br />
*[[AppSuite:Writing_a_contacts_plugin | A contacts plugin]] let's you modify parts of AppSuite's contact view.<br />
--><br />
<br />
*[[AppSuite:Using the Upsell widget | Upsell Widget]], to enable the AppSuite user to purchase additional features. <br />
<br />
*[[AppSuite:Writing a simple application | A real application/module]] for AppSuite, which should be displayed full screen and appear as a bread crump in the title bar, take a look at the article about [[AppSuite:Writing a simple application | 'Writing a simple application']].<br />
<br />
*[[AppSuite:Writing a notification area plugin | A notification plugin]] for AppSuite<br />
<br />
*[[AppSuite:Writing a wizard | A wizard]], which can be first time users to show them important informations or configure initial settings for 3rd party applications.<br />
<br />
*[[AppSuite:Creating a settings section in AppSuite settings | Settings plugin]] extending AppSuite settings and creating a new section.<br />
<br />
*[[AppSuite:Embedding your settings into AppSuite settings | Settings plugin]] embedding your own settings section via iframe into AppSuite.<br />
<br />
You got stuck somewhere? There are some hints, which might help you [[AppSuite:Debugging_the_UI | debugging the UI]].<br />
<br />
=== How to get your code running ===<br />
Written your first app/plugin? Using the [[AppSuite:UI build system | UI build system]] will help you to get fast, easy-to-distribute and correct builds running on your AppSuite. The article will show you how to package your code and copy from OX source code / directories.<br />
<br />
Since the AppSuite product consists of a server and a UI, you also need a working backend (AppSuite application server) to communicate with. <br />
Therefor you should run [[AppSuite:Appserver | Appserver]] using an existing OX AppSuite server and (with local parts of the AppSuite) automaticly get the recent stable source packages from the AppSuite servers. For using your namespace as a source for hosting your app, simply add the build-path of your app as an parameter while running appserver.<br />
<br />
=== What's next ===<br />
No Idea what to do first? Read our [[AppSuite:GettingStarted | GettingStarted guide]] to have a step-by-step introduction about how to install the SDK, use the Build System, write your first app and get it running.</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:GettingStarted_7.4.2&diff=16264AppSuite:GettingStarted 7.4.22013-10-28T10:39:48Z<p>Mark.schmidts: /* Installing */</p>
<hr />
<div><div class="title">Getting Started</div><br />
<br />
__TOC__<br />
<br />
Hello and welcome to OX App Suite development. This document will get you started to develop your first own app for OX App Suite with a minimal setup. We will look at the steps necessary but will also tempt you to learn more by linking you to some more in-depth documentation about these topics. Depending on how you wound up reading this page, you will probably have already completed some of the steps below.<br />
<br />
== Installing ==<br />
<br />
First, you need to install some tools which are necessary for UI development. For now, the simplest way is to download the source of the OX App Suite UI. Since the source code is kept in a [http://git-scm.com/ Git] repository, the source is downloaded using <tt>git</tt>:<br />
<br />
$ git clone --depth 1 -b release-7.4.1 https://code.open-xchange.com/git/wd/frontend/web<br />
<br />
This downloads the latest version and unpacks it into a subdirectory <tt>web</tt> in the current directory.<br />
<br />
The option -b develop specifies a git branch. In this case you will clone the current realease-branch <tt>release-7.4.1</tt>. The full functionality described in this article is only available in the <tt>develop</tt> branch.<br />
<br />
The option --depth 1 prevents the download of the entire history, and reduces the download size from hundreds of MB to less than 20MB. It should not be used by OX App Suite developers since it also prevents git push from working properly. <br />
<br />
To simplify calling of scripts contained in the ui/bin directory, you should add it to your <tt>$PATH</tt>:<br />
<br />
$ export PATH="$PATH:$(pwd)/web/ui/bin"<br />
<br />
== Preparing ==<br />
<br />
=== Create Workspace ===<br />
<br />
In order to have a proper space for your app/plugin create a workspace prospectivly containing all your code.<br />
This folder should contain the subfolder <tt>apps</tt>.<br />
The following article is written assuming, you're working in your workspace directory.<br />
In this example we will create our own workspace called <tt>example-workspace</tt> and add the suiteable subdirectory <tt>apps</tt> for our code: <br />
<br />
$ mkdir example-workspace<br />
$ cd example-workspace<br />
$ mkdir apps<br />
<br />
== Writing ==<br />
<br />
As an example, let's create a small app and build it. It requires only two files: <code>example-workspace/apps/com.example/main.js</code> for the source code of the app<br />
<br />
<pre class="language-javascript"> <br />
define('com.example/main', function () {<br />
'use strict';<br />
var app = ox.ui.createApp({ name: 'com.example' });<br />
app.setLauncher(function () {<br />
var win = ox.ui.createWindow({<br />
name: 'com.example',<br />
title: 'Hello World App'<br />
});<br />
app.setWindow(win);<br />
win.nodes.main.append($('<h1>').text('Hello, World!'));<br />
win.show();<br />
});<br />
return { getApp: app.getInstance };<br />
});<br />
</pre><br />
<br />
and <code>example-workspace/apps/com.example/manifest.json</code> for the [[AppSuite:UI_manifests_explained | manifest]]:<br />
<br />
<pre class="language-javascript">{ title: 'Hello World App' }</pre><br />
<br />
While developing always keep in mind, that there is an [[AppSuite:Debugging_the_UI | article about debugging the user interface]] which helps you avoiding and fixing typical errors.<br />
<br />
== Building ==<br />
<br />
This step will process your app, checking the source code for syntax errors and compressing it, to make it run error-free and fast. Calling this command will also write the processed source to the a subdirectory called <tt>build</tt> in your workspace, containing also the apps-directory with the original source code.<br />
<br />
While you're in the folder containing <tt>apps</tt>-subdirectory <tt>example-workspace</tt>, using the [[AppSuite:UI_build_system | the UI Build System]] makes building the app is as easy as calling:<br />
<br />
$ build-appsuite app<br />
<br />
== Running ==<br />
<br />
=== Hosting the app ===<br />
For quickest round-trip times, the directory with the generated files in <tt>build</tt>-folder should be made available via the [[AppSuite:Appserver|appserver]] tool, which is also part of the [[#Installing | installed SDK]]. Your OX App Suite installation will use <code>appserver</code> use as upstream server, Assuming you are calling <code>appserver</code> from your workspace, and using [http://ox.io/ ox.io] as server:<br />
<br />
<nowiki>$ appserver --server=https://www.ox.io/appsuite/ build</nowiki><br />
<br />
This command will host your app locally. Once you started it, it will always have to run in the background, making all changes within the given build-directories visible. To add the build path of an other workspace, stop appserver and run the upper command again appending the other directory after a white space.<br />
<br />
WARNING: Take care that build variables like <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or <code>[[AppSuite:UI_build_system#manifestDir|manifestDir]]</code> are not set during development. Otherwise, you will have to specify their directories manually for <code>appserver</code>. Also, the <code>[[AppSuite:UI_build_system#clean|clean]]</code> task will delete these directories and all their contents! In general, don't point <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or any other <code>*Dir</code> variables at existing directories.<br />
<br />
=== Testing the app ===<br />
<br />
Once made your app available, you can access OX App Suite opening your browser with this address:<br />
http://localhost:8337/appsuite<br />
Then simply run this command in your browser's javascript console to open the hello world application:<br />
<pre class="language-javascript"><br />
ox.launch("com.example/main")<br />
</pre><br />
<br />
=== Development cycle ===<br />
<br />
Once successfully tested your first app, you will probably continue developing it. <br />
Keep in mind that after [[#Writing | writing your code]], you will always need to [[#Building | build the app]] and have your [[#Hosting the app | Appserver]] running.<br />
<br />
== Packaging ==<br />
When your app is done, you probably want to test it on a staging system, and later install it on a production system. To keep track of which installed files belong to which version of which app, you should use the native package manager of the Linux distribution of the target system. The packages can be easily created using the build system.<br />
<br />
=== Initialization ===<br />
First, you need to create several files describing how to package you app. Use the <tt>init-packaging</tt> task of the build system:<br />
<br />
$ build-appsuite init-packaging<br />
Node version: v0.10.21<br />
Build path: build<br />
Build version: 0.0.1-1.20131025.133931<br />
Package name: example-app<br />
Version [0.0.1]: <br />
Maintainer (Name <e-mail>): Maintainer <maintainer@example.com><br />
Copyright line [2013 Open-Xchange, Inc]: <br />
<br />
Known licenses for which you don't need to specify a file:<br />
APACHE-2, BSD-2-CLAUSE, BSD-3-CLAUSE, CC-BY-3, CC-BY-NC-3, CC-BY-NC-ND-3,<br />
CC-BY-NC-SA-3, CC-BY-ND-3, CC-BY-SA-3, CC0-1, EXPAT, GPL-2, GPL-3, LGPL-3<br />
<br />
License name [CC-BY-NC-SA-3.0]: BSD-3-Clause<br />
Short description: Example app<br />
<br />
The task presents a number of interactive prompts to get the necessary information about the generated packages. The default values are presented in square brackets ([...]) and can be selected by just pressing Enter. Otherwise, the entered values should follow the Debian Maintainer's Guide. Debian tools are especially picky about the syntax of the maintainer name and email address.<br />
<br />
If none of the known licenses suit you, you can enter any other license name. Then you will be asked to enter the file name of your license text. It should be a plain text file using the UTF-8 encoding.<br />
<br />
Some or even all prompts can be skipped by explicitly specifying the information as a build variable. The list of variable names is available in the reference of the <tt>[[AppSuite:UI_build_system#init-packaging|init-packaging]]</tt> task.<br />
<br />
After answering all the questions, you can customize the generated files to account for any additional packaging requirements.<br />
<br />
=== Static Files ===<br />
If your app includes images (e.g. themes do this most of the time), then you should check the generated packaging files for sections marked<br />
<br />
## Uncomment for multiple packages<br />
#...<br />
<br />
and remove the '#' at the start of each line in each block. This enables the creation of a second package, with a name ending in "<tt>-static</tt>". The images and any other files which are not JavaScript or CSS are server by the Apache web server, instead of the OX App Suite application server. These files are copied to a separate package for the case that the web server is on a dedicated system or maybe even has its own cluster. The default package is installed on the OX application server, and the second, "<tt>-static</tt>" package is installed on the web server.<br />
<br />
=== Building Packages ===<br />
Since the actual package format depends on the distribution it is built for, and there already exist tools to create packages from suitably arranged source code archives, the OX App Suite build system merely prepares such source archives. Using the <tt>dist</tt> task to create the archives:<br />
<br />
$ build-appsuite dist<br />
Node version: v0.10.21<br />
Build path: build<br />
Build version: 0.0.1-1.20131025.150034<br />
dpkg-source: info: using source format `3.0 (quilt)'<br />
dpkg-source: info: building example-app using existing ./example-app_0.0.1.orig.tar.bz2<br />
dpkg-source: info: building example-app in example-app_0.0.1-1.debian.tar.bz2<br />
dpkg-source: info: building example-app in example-app_0.0.1-1.dsc<br />
<br />
$ ls tmp/packaging/<br />
example-app-0.0.1 example-app_0.0.1-1.dsc<br />
example-app.spec example-app_0.0.1.orig.tar.bz2<br />
example-app_0.0.1-1.debian.tar.bz2<br />
<br />
The task creates a temporary directory and four files. The archive with the extension <tt>.orig.tar.bz2</tt> contains the source of your app. It is required to build both Debian and RPM packages. The files with extensions <tt>.debian.tar.bz2</tt> and <tt>.dsc</tt> are used together with the <tt>.orig.tar.bz2</tt> archive to build Debian packages. The file with the extension <tt>.spec</tt> is used together with the <tt>.orig.tar.bz2</tt> archive to build RPM packages.<br />
<br />
==== Building Debian Packages ====<br />
The Debian package can be built directly in the temporary directory created by the <tt>dist</tt> task:<br />
<br />
$ cd tmp/packaging/example-app-0.0.1/<br />
$ dpkg-buildpackage -b<br />
<br />
The package will be placed in <tt>tmp/packaging/</tt>.<br />
<br />
==== Building RPM Packages ====<br />
The RPM package build toor, <tt>rpmbuild</tt> requires the files to be in a specific directory layout before building:<br />
<br />
$ mkdir -p ~/rpmbuild/SOURCES<br />
$ cp tmp/packages/*.orig.tar.bz2 ~/rpmbuild/SOURCES/<br />
$ mkdir -p ~/rpmbuild/SPECS<br />
$ cp tmp/packaging/*.spec ~/rpmbuild/SPECS/<br />
$ rpmbuild ~/rpmbuild/SPECS/*.spec<br />
<br />
The package will be placed in <tt>~/rpmbuild/RPMS/</tt>.<br />
<br />
== Further Reading ==<br />
* You just build your first app for OX App Suite, keep in mind that there [[DevelopingTheUI#What_can_i_build.3F | quite a few options]] how you can develop for OX App Suite.<br />
* It's highly recommended to gain more knowledge about all the benefits [[AppSuite:UI_build_system | the UI build system]] and [[AppSuite:Appserver|the Appserver]] are providing you for developing OX App Suite.<br />
* If you're stuck somewhere, the article about [[AppSuite:Debugging_the_UI | debugging the UI]] might help you.<br />
* Get a better overview about [[DevelopingTheUI | developing the user inferface]].</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:GettingStarted_7.4.2&diff=16263AppSuite:GettingStarted 7.4.22013-10-28T10:39:18Z<p>Mark.schmidts: /* Installing */</p>
<hr />
<div><div class="title">Getting Started</div><br />
<br />
__TOC__<br />
<br />
Hello and welcome to OX App Suite development. This document will get you started to develop your first own app for OX App Suite with a minimal setup. We will look at the steps necessary but will also tempt you to learn more by linking you to some more in-depth documentation about these topics. Depending on how you wound up reading this page, you will probably have already completed some of the steps below.<br />
<br />
== Installing ==<br />
<br />
First, you need to install some tools which are necessary for UI development. For now, the simplest way is to download the source of the OX App Suite UI. Since the source code is kept in a [http://git-scm.com/ Git] repository, the source is downloaded using <tt>git</tt>:<br />
<br />
$ git clone --depth 1 -b release-7.4.1 https://code.open-xchange.com/git/wd/frontend/web<br />
<br />
This downloads the latest version and unpacks it into a subdirectory <tt>web</tt> in the current directory.<br />
<br />
The option -b develop specifies a git branch. In this case you will clone the current realease-branch <tt>release-7.4.1</tt>. The full functionality described in this article is only available in the "develop" branch.<br />
<br />
The option --depth 1 prevents the download of the entire history, and reduces the download size from hundreds of MB to less than 20MB. It should not be used by OX App Suite developers since it also prevents git push from working properly. <br />
<br />
To simplify calling of scripts contained in the ui/bin directory, you should add it to your <tt>$PATH</tt>:<br />
<br />
$ export PATH="$PATH:$(pwd)/web/ui/bin"<br />
<br />
== Preparing ==<br />
<br />
=== Create Workspace ===<br />
<br />
In order to have a proper space for your app/plugin create a workspace prospectivly containing all your code.<br />
This folder should contain the subfolder <tt>apps</tt>.<br />
The following article is written assuming, you're working in your workspace directory.<br />
In this example we will create our own workspace called <tt>example-workspace</tt> and add the suiteable subdirectory <tt>apps</tt> for our code: <br />
<br />
$ mkdir example-workspace<br />
$ cd example-workspace<br />
$ mkdir apps<br />
<br />
== Writing ==<br />
<br />
As an example, let's create a small app and build it. It requires only two files: <code>example-workspace/apps/com.example/main.js</code> for the source code of the app<br />
<br />
<pre class="language-javascript"> <br />
define('com.example/main', function () {<br />
'use strict';<br />
var app = ox.ui.createApp({ name: 'com.example' });<br />
app.setLauncher(function () {<br />
var win = ox.ui.createWindow({<br />
name: 'com.example',<br />
title: 'Hello World App'<br />
});<br />
app.setWindow(win);<br />
win.nodes.main.append($('<h1>').text('Hello, World!'));<br />
win.show();<br />
});<br />
return { getApp: app.getInstance };<br />
});<br />
</pre><br />
<br />
and <code>example-workspace/apps/com.example/manifest.json</code> for the [[AppSuite:UI_manifests_explained | manifest]]:<br />
<br />
<pre class="language-javascript">{ title: 'Hello World App' }</pre><br />
<br />
While developing always keep in mind, that there is an [[AppSuite:Debugging_the_UI | article about debugging the user interface]] which helps you avoiding and fixing typical errors.<br />
<br />
== Building ==<br />
<br />
This step will process your app, checking the source code for syntax errors and compressing it, to make it run error-free and fast. Calling this command will also write the processed source to the a subdirectory called <tt>build</tt> in your workspace, containing also the apps-directory with the original source code.<br />
<br />
While you're in the folder containing <tt>apps</tt>-subdirectory <tt>example-workspace</tt>, using the [[AppSuite:UI_build_system | the UI Build System]] makes building the app is as easy as calling:<br />
<br />
$ build-appsuite app<br />
<br />
== Running ==<br />
<br />
=== Hosting the app ===<br />
For quickest round-trip times, the directory with the generated files in <tt>build</tt>-folder should be made available via the [[AppSuite:Appserver|appserver]] tool, which is also part of the [[#Installing | installed SDK]]. Your OX App Suite installation will use <code>appserver</code> use as upstream server, Assuming you are calling <code>appserver</code> from your workspace, and using [http://ox.io/ ox.io] as server:<br />
<br />
<nowiki>$ appserver --server=https://www.ox.io/appsuite/ build</nowiki><br />
<br />
This command will host your app locally. Once you started it, it will always have to run in the background, making all changes within the given build-directories visible. To add the build path of an other workspace, stop appserver and run the upper command again appending the other directory after a white space.<br />
<br />
WARNING: Take care that build variables like <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or <code>[[AppSuite:UI_build_system#manifestDir|manifestDir]]</code> are not set during development. Otherwise, you will have to specify their directories manually for <code>appserver</code>. Also, the <code>[[AppSuite:UI_build_system#clean|clean]]</code> task will delete these directories and all their contents! In general, don't point <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or any other <code>*Dir</code> variables at existing directories.<br />
<br />
=== Testing the app ===<br />
<br />
Once made your app available, you can access OX App Suite opening your browser with this address:<br />
http://localhost:8337/appsuite<br />
Then simply run this command in your browser's javascript console to open the hello world application:<br />
<pre class="language-javascript"><br />
ox.launch("com.example/main")<br />
</pre><br />
<br />
=== Development cycle ===<br />
<br />
Once successfully tested your first app, you will probably continue developing it. <br />
Keep in mind that after [[#Writing | writing your code]], you will always need to [[#Building | build the app]] and have your [[#Hosting the app | Appserver]] running.<br />
<br />
== Packaging ==<br />
When your app is done, you probably want to test it on a staging system, and later install it on a production system. To keep track of which installed files belong to which version of which app, you should use the native package manager of the Linux distribution of the target system. The packages can be easily created using the build system.<br />
<br />
=== Initialization ===<br />
First, you need to create several files describing how to package you app. Use the <tt>init-packaging</tt> task of the build system:<br />
<br />
$ build-appsuite init-packaging<br />
Node version: v0.10.21<br />
Build path: build<br />
Build version: 0.0.1-1.20131025.133931<br />
Package name: example-app<br />
Version [0.0.1]: <br />
Maintainer (Name <e-mail>): Maintainer <maintainer@example.com><br />
Copyright line [2013 Open-Xchange, Inc]: <br />
<br />
Known licenses for which you don't need to specify a file:<br />
APACHE-2, BSD-2-CLAUSE, BSD-3-CLAUSE, CC-BY-3, CC-BY-NC-3, CC-BY-NC-ND-3,<br />
CC-BY-NC-SA-3, CC-BY-ND-3, CC-BY-SA-3, CC0-1, EXPAT, GPL-2, GPL-3, LGPL-3<br />
<br />
License name [CC-BY-NC-SA-3.0]: BSD-3-Clause<br />
Short description: Example app<br />
<br />
The task presents a number of interactive prompts to get the necessary information about the generated packages. The default values are presented in square brackets ([...]) and can be selected by just pressing Enter. Otherwise, the entered values should follow the Debian Maintainer's Guide. Debian tools are especially picky about the syntax of the maintainer name and email address.<br />
<br />
If none of the known licenses suit you, you can enter any other license name. Then you will be asked to enter the file name of your license text. It should be a plain text file using the UTF-8 encoding.<br />
<br />
Some or even all prompts can be skipped by explicitly specifying the information as a build variable. The list of variable names is available in the reference of the <tt>[[AppSuite:UI_build_system#init-packaging|init-packaging]]</tt> task.<br />
<br />
After answering all the questions, you can customize the generated files to account for any additional packaging requirements.<br />
<br />
=== Static Files ===<br />
If your app includes images (e.g. themes do this most of the time), then you should check the generated packaging files for sections marked<br />
<br />
## Uncomment for multiple packages<br />
#...<br />
<br />
and remove the '#' at the start of each line in each block. This enables the creation of a second package, with a name ending in "<tt>-static</tt>". The images and any other files which are not JavaScript or CSS are server by the Apache web server, instead of the OX App Suite application server. These files are copied to a separate package for the case that the web server is on a dedicated system or maybe even has its own cluster. The default package is installed on the OX application server, and the second, "<tt>-static</tt>" package is installed on the web server.<br />
<br />
=== Building Packages ===<br />
Since the actual package format depends on the distribution it is built for, and there already exist tools to create packages from suitably arranged source code archives, the OX App Suite build system merely prepares such source archives. Using the <tt>dist</tt> task to create the archives:<br />
<br />
$ build-appsuite dist<br />
Node version: v0.10.21<br />
Build path: build<br />
Build version: 0.0.1-1.20131025.150034<br />
dpkg-source: info: using source format `3.0 (quilt)'<br />
dpkg-source: info: building example-app using existing ./example-app_0.0.1.orig.tar.bz2<br />
dpkg-source: info: building example-app in example-app_0.0.1-1.debian.tar.bz2<br />
dpkg-source: info: building example-app in example-app_0.0.1-1.dsc<br />
<br />
$ ls tmp/packaging/<br />
example-app-0.0.1 example-app_0.0.1-1.dsc<br />
example-app.spec example-app_0.0.1.orig.tar.bz2<br />
example-app_0.0.1-1.debian.tar.bz2<br />
<br />
The task creates a temporary directory and four files. The archive with the extension <tt>.orig.tar.bz2</tt> contains the source of your app. It is required to build both Debian and RPM packages. The files with extensions <tt>.debian.tar.bz2</tt> and <tt>.dsc</tt> are used together with the <tt>.orig.tar.bz2</tt> archive to build Debian packages. The file with the extension <tt>.spec</tt> is used together with the <tt>.orig.tar.bz2</tt> archive to build RPM packages.<br />
<br />
==== Building Debian Packages ====<br />
The Debian package can be built directly in the temporary directory created by the <tt>dist</tt> task:<br />
<br />
$ cd tmp/packaging/example-app-0.0.1/<br />
$ dpkg-buildpackage -b<br />
<br />
The package will be placed in <tt>tmp/packaging/</tt>.<br />
<br />
==== Building RPM Packages ====<br />
The RPM package build toor, <tt>rpmbuild</tt> requires the files to be in a specific directory layout before building:<br />
<br />
$ mkdir -p ~/rpmbuild/SOURCES<br />
$ cp tmp/packages/*.orig.tar.bz2 ~/rpmbuild/SOURCES/<br />
$ mkdir -p ~/rpmbuild/SPECS<br />
$ cp tmp/packaging/*.spec ~/rpmbuild/SPECS/<br />
$ rpmbuild ~/rpmbuild/SPECS/*.spec<br />
<br />
The package will be placed in <tt>~/rpmbuild/RPMS/</tt>.<br />
<br />
== Further Reading ==<br />
* You just build your first app for OX App Suite, keep in mind that there [[DevelopingTheUI#What_can_i_build.3F | quite a few options]] how you can develop for OX App Suite.<br />
* It's highly recommended to gain more knowledge about all the benefits [[AppSuite:UI_build_system | the UI build system]] and [[AppSuite:Appserver|the Appserver]] are providing you for developing OX App Suite.<br />
* If you're stuck somewhere, the article about [[AppSuite:Debugging_the_UI | debugging the UI]] might help you.<br />
* Get a better overview about [[DevelopingTheUI | developing the user inferface]].</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:GettingStarted_7.4.2&diff=16262AppSuite:GettingStarted 7.4.22013-10-28T10:26:11Z<p>Mark.schmidts: /* Installing */</p>
<hr />
<div><div class="title">Getting Started</div><br />
<br />
__TOC__<br />
<br />
Hello and welcome to OX App Suite development. This document will get you started to develop your first own app for OX App Suite with a minimal setup. We will look at the steps necessary but will also tempt you to learn more by linking you to some more in-depth documentation about these topics. Depending on how you wound up reading this page, you will probably have already completed some of the steps below.<br />
<br />
== Installing ==<br />
<br />
First, you need to install some tools which are necessary for UI development. For now, the simplest way is to download the source of the OX App Suite UI. Since the source code is kept in a [http://git-scm.com/ Git] repository, the source is downloaded using <tt>git</tt>:<br />
<br />
$ git clone --depth 1 -b release-7.4.1 https://code.open-xchange.com/git/wd/frontend/web<br />
<br />
This downloads the latest version and unpacks it into a subdirectory <tt>web</tt> in the current directory.<br />
<br />
The option -b develop specifies a git branch. In this case you will clone the current realease-branch <tt>release-7.4.1</tt><br />
<br />
The option --depth 1 prevents the download of the entire history, and reduces the download size from hundreds of MB to less than 20MB. It should not be used by OX App Suite developers since it also prevents git push from working properly. <br />
<br />
To simplify calling of scripts contained in the ui/bin directory, you should add it to your <tt>$PATH</tt>:<br />
<br />
$ export PATH="$PATH:$(pwd)/web/ui/bin"<br />
<br />
== Preparing ==<br />
<br />
=== Create Workspace ===<br />
<br />
In order to have a proper space for your app/plugin create a workspace prospectivly containing all your code.<br />
This folder should contain the subfolder <tt>apps</tt>.<br />
The following article is written assuming, you're working in your workspace directory.<br />
In this example we will create our own workspace called <tt>example-workspace</tt> and add the suiteable subdirectory <tt>apps</tt> for our code: <br />
<br />
$ mkdir example-workspace<br />
$ cd example-workspace<br />
$ mkdir apps<br />
<br />
== Writing ==<br />
<br />
As an example, let's create a small app and build it. It requires only two files: <code>example-workspace/apps/com.example/main.js</code> for the source code of the app<br />
<br />
<pre class="language-javascript"> <br />
define('com.example/main', function () {<br />
'use strict';<br />
var app = ox.ui.createApp({ name: 'com.example' });<br />
app.setLauncher(function () {<br />
var win = ox.ui.createWindow({<br />
name: 'com.example',<br />
title: 'Hello World App'<br />
});<br />
app.setWindow(win);<br />
win.nodes.main.append($('<h1>').text('Hello, World!'));<br />
win.show();<br />
});<br />
return { getApp: app.getInstance };<br />
});<br />
</pre><br />
<br />
and <code>example-workspace/apps/com.example/manifest.json</code> for the [[AppSuite:UI_manifests_explained | manifest]]:<br />
<br />
<pre class="language-javascript">{ title: 'Hello World App' }</pre><br />
<br />
While developing always keep in mind, that there is an [[AppSuite:Debugging_the_UI | article about debugging the user interface]] which helps you avoiding and fixing typical errors.<br />
<br />
== Building ==<br />
<br />
This step will process your app, checking the source code for syntax errors and compressing it, to make it run error-free and fast. Calling this command will also write the processed source to the a subdirectory called <tt>build</tt> in your workspace, containing also the apps-directory with the original source code.<br />
<br />
While you're in the folder containing <tt>apps</tt>-subdirectory <tt>example-workspace</tt>, using the [[AppSuite:UI_build_system | the UI Build System]] makes building the app is as easy as calling:<br />
<br />
$ build-appsuite app<br />
<br />
== Running ==<br />
<br />
=== Hosting the app ===<br />
For quickest round-trip times, the directory with the generated files in <tt>build</tt>-folder should be made available via the [[AppSuite:Appserver|appserver]] tool, which is also part of the [[#Installing | installed SDK]]. Your OX App Suite installation will use <code>appserver</code> use as upstream server, Assuming you are calling <code>appserver</code> from your workspace, and using [http://ox.io/ ox.io] as server:<br />
<br />
<nowiki>$ appserver --server=https://www.ox.io/appsuite/ build</nowiki><br />
<br />
This command will host your app locally. Once you started it, it will always have to run in the background, making all changes within the given build-directories visible. To add the build path of an other workspace, stop appserver and run the upper command again appending the other directory after a white space.<br />
<br />
WARNING: Take care that build variables like <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or <code>[[AppSuite:UI_build_system#manifestDir|manifestDir]]</code> are not set during development. Otherwise, you will have to specify their directories manually for <code>appserver</code>. Also, the <code>[[AppSuite:UI_build_system#clean|clean]]</code> task will delete these directories and all their contents! In general, don't point <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or any other <code>*Dir</code> variables at existing directories.<br />
<br />
=== Testing the app ===<br />
<br />
Once made your app available, you can access OX App Suite opening your browser with this address:<br />
http://localhost:8337/appsuite<br />
Then simply run this command in your browser's javascript console to open the hello world application:<br />
<pre class="language-javascript"><br />
ox.launch("com.example/main")<br />
</pre><br />
<br />
=== Development cycle ===<br />
<br />
Once successfully tested your first app, you will probably continue developing it. <br />
Keep in mind that after [[#Writing | writing your code]], you will always need to [[#Building | build the app]] and have your [[#Hosting the app | Appserver]] running.<br />
<br />
== Packaging ==<br />
When your app is done, you probably want to test it on a staging system, and later install it on a production system. To keep track of which installed files belong to which version of which app, you should use the native package manager of the Linux distribution of the target system. The packages can be easily created using the build system.<br />
<br />
=== Initialization ===<br />
First, you need to create several files describing how to package you app. Use the <tt>init-packaging</tt> task of the build system:<br />
<br />
$ build-appsuite init-packaging<br />
Node version: v0.10.21<br />
Build path: build<br />
Build version: 0.0.1-1.20131025.133931<br />
Package name: example-app<br />
Version [0.0.1]: <br />
Maintainer (Name <e-mail>): Maintainer <maintainer@example.com><br />
Copyright line [2013 Open-Xchange, Inc]: <br />
<br />
Known licenses for which you don't need to specify a file:<br />
APACHE-2, BSD-2-CLAUSE, BSD-3-CLAUSE, CC-BY-3, CC-BY-NC-3, CC-BY-NC-ND-3,<br />
CC-BY-NC-SA-3, CC-BY-ND-3, CC-BY-SA-3, CC0-1, EXPAT, GPL-2, GPL-3, LGPL-3<br />
<br />
License name [CC-BY-NC-SA-3.0]: BSD-3-Clause<br />
Short description: Example app<br />
<br />
The task presents a number of interactive prompts to get the necessary information about the generated packages. The default values are presented in square brackets ([...]) and can be selected by just pressing Enter. Otherwise, the entered values should follow the Debian Maintainer's Guide. Debian tools are especially picky about the syntax of the maintainer name and email address.<br />
<br />
If none of the known licenses suit you, you can enter any other license name. Then you will be asked to enter the file name of your license text. It should be a plain text file using the UTF-8 encoding.<br />
<br />
Some or even all prompts can be skipped by explicitly specifying the information as a build variable. The list of variable names is available in the reference of the <tt>[[AppSuite:UI_build_system#init-packaging|init-packaging]]</tt> task.<br />
<br />
After answering all the questions, you can customize the generated files to account for any additional packaging requirements.<br />
<br />
=== Static Files ===<br />
If your app includes images (e.g. themes do this most of the time), then you should check the generated packaging files for sections marked<br />
<br />
## Uncomment for multiple packages<br />
#...<br />
<br />
and remove the '#' at the start of each line in each block. This enables the creation of a second package, with a name ending in "<tt>-static</tt>". The images and any other files which are not JavaScript or CSS are server by the Apache web server, instead of the OX App Suite application server. These files are copied to a separate package for the case that the web server is on a dedicated system or maybe even has its own cluster. The default package is installed on the OX application server, and the second, "<tt>-static</tt>" package is installed on the web server.<br />
<br />
=== Building Packages ===<br />
Since the actual package format depends on the distribution it is built for, and there already exist tools to create packages from suitably arranged source code archives, the OX App Suite build system merely prepares such source archives. Using the <tt>dist</tt> task to create the archives:<br />
<br />
$ build-appsuite dist<br />
Node version: v0.10.21<br />
Build path: build<br />
Build version: 0.0.1-1.20131025.150034<br />
dpkg-source: info: using source format `3.0 (quilt)'<br />
dpkg-source: info: building example-app using existing ./example-app_0.0.1.orig.tar.bz2<br />
dpkg-source: info: building example-app in example-app_0.0.1-1.debian.tar.bz2<br />
dpkg-source: info: building example-app in example-app_0.0.1-1.dsc<br />
<br />
$ ls tmp/packaging/<br />
example-app-0.0.1 example-app_0.0.1-1.dsc<br />
example-app.spec example-app_0.0.1.orig.tar.bz2<br />
example-app_0.0.1-1.debian.tar.bz2<br />
<br />
The task creates a temporary directory and four files. The archive with the extension <tt>.orig.tar.bz2</tt> contains the source of your app. It is required to build both Debian and RPM packages. The files with extensions <tt>.debian.tar.bz2</tt> and <tt>.dsc</tt> are used together with the <tt>.orig.tar.bz2</tt> archive to build Debian packages. The file with the extension <tt>.spec</tt> is used together with the <tt>.orig.tar.bz2</tt> archive to build RPM packages.<br />
<br />
==== Building Debian Packages ====<br />
The Debian package can be built directly in the temporary directory created by the <tt>dist</tt> task:<br />
<br />
$ cd tmp/packaging/example-app-0.0.1/<br />
$ dpkg-buildpackage -b<br />
<br />
The package will be placed in <tt>tmp/packaging/</tt>.<br />
<br />
==== Building RPM Packages ====<br />
The RPM package build toor, <tt>rpmbuild</tt> requires the files to be in a specific directory layout before building:<br />
<br />
$ mkdir -p ~/rpmbuild/SOURCES<br />
$ cp tmp/packages/*.orig.tar.bz2 ~/rpmbuild/SOURCES/<br />
$ mkdir -p ~/rpmbuild/SPECS<br />
$ cp tmp/packaging/*.spec ~/rpmbuild/SPECS/<br />
$ rpmbuild ~/rpmbuild/SPECS/*.spec<br />
<br />
The package will be placed in <tt>~/rpmbuild/RPMS/</tt>.<br />
<br />
== Further Reading ==<br />
* You just build your first app for OX App Suite, keep in mind that there [[DevelopingTheUI#What_can_i_build.3F | quite a few options]] how you can develop for OX App Suite.<br />
* It's highly recommended to gain more knowledge about all the benefits [[AppSuite:UI_build_system | the UI build system]] and [[AppSuite:Appserver|the Appserver]] are providing you for developing OX App Suite.<br />
* If you're stuck somewhere, the article about [[AppSuite:Debugging_the_UI | debugging the UI]] might help you.<br />
* Get a better overview about [[DevelopingTheUI | developing the user inferface]].</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:GettingStarted_7.4.2&diff=16261AppSuite:GettingStarted 7.4.22013-10-28T10:25:42Z<p>Mark.schmidts: /* Installing */</p>
<hr />
<div><div class="title">Getting Started</div><br />
<br />
__TOC__<br />
<br />
Hello and welcome to OX App Suite development. This document will get you started to develop your first own app for OX App Suite with a minimal setup. We will look at the steps necessary but will also tempt you to learn more by linking you to some more in-depth documentation about these topics. Depending on how you wound up reading this page, you will probably have already completed some of the steps below.<br />
<br />
== Installing ==<br />
<br />
First, you need to install some tools which are necessary for UI development. For now, the simplest way is to download the source of the OX App Suite UI. Since the source code is kept in a [http://git-scm.com/ Git] repository, the source is downloaded using <tt>git</tt>:<br />
<br />
$ git clone --depth 1 -b release-7.4.1 https://code.open-xchange.com/git/wd/frontend/web<br />
<br />
This downloads the latest version and unpacks it into a subdirectory <tt>web</tt> in the current directory.<br />
<br />
The option -b develop specifies a git branch. In this case you will address the current version <tt>release-7.4.1</tt><br />
<br />
The option --depth 1 prevents the download of the entire history, and reduces the download size from hundreds of MB to less than 20MB. It should not be used by OX App Suite developers since it also prevents git push from working properly. <br />
<br />
To simplify calling of scripts contained in the ui/bin directory, you should add it to your <tt>$PATH</tt>:<br />
<br />
$ export PATH="$PATH:$(pwd)/web/ui/bin"<br />
<br />
== Preparing ==<br />
<br />
=== Create Workspace ===<br />
<br />
In order to have a proper space for your app/plugin create a workspace prospectivly containing all your code.<br />
This folder should contain the subfolder <tt>apps</tt>.<br />
The following article is written assuming, you're working in your workspace directory.<br />
In this example we will create our own workspace called <tt>example-workspace</tt> and add the suiteable subdirectory <tt>apps</tt> for our code: <br />
<br />
$ mkdir example-workspace<br />
$ cd example-workspace<br />
$ mkdir apps<br />
<br />
== Writing ==<br />
<br />
As an example, let's create a small app and build it. It requires only two files: <code>example-workspace/apps/com.example/main.js</code> for the source code of the app<br />
<br />
<pre class="language-javascript"> <br />
define('com.example/main', function () {<br />
'use strict';<br />
var app = ox.ui.createApp({ name: 'com.example' });<br />
app.setLauncher(function () {<br />
var win = ox.ui.createWindow({<br />
name: 'com.example',<br />
title: 'Hello World App'<br />
});<br />
app.setWindow(win);<br />
win.nodes.main.append($('<h1>').text('Hello, World!'));<br />
win.show();<br />
});<br />
return { getApp: app.getInstance };<br />
});<br />
</pre><br />
<br />
and <code>example-workspace/apps/com.example/manifest.json</code> for the [[AppSuite:UI_manifests_explained | manifest]]:<br />
<br />
<pre class="language-javascript">{ title: 'Hello World App' }</pre><br />
<br />
While developing always keep in mind, that there is an [[AppSuite:Debugging_the_UI | article about debugging the user interface]] which helps you avoiding and fixing typical errors.<br />
<br />
== Building ==<br />
<br />
This step will process your app, checking the source code for syntax errors and compressing it, to make it run error-free and fast. Calling this command will also write the processed source to the a subdirectory called <tt>build</tt> in your workspace, containing also the apps-directory with the original source code.<br />
<br />
While you're in the folder containing <tt>apps</tt>-subdirectory <tt>example-workspace</tt>, using the [[AppSuite:UI_build_system | the UI Build System]] makes building the app is as easy as calling:<br />
<br />
$ build-appsuite app<br />
<br />
== Running ==<br />
<br />
=== Hosting the app ===<br />
For quickest round-trip times, the directory with the generated files in <tt>build</tt>-folder should be made available via the [[AppSuite:Appserver|appserver]] tool, which is also part of the [[#Installing | installed SDK]]. Your OX App Suite installation will use <code>appserver</code> use as upstream server, Assuming you are calling <code>appserver</code> from your workspace, and using [http://ox.io/ ox.io] as server:<br />
<br />
<nowiki>$ appserver --server=https://www.ox.io/appsuite/ build</nowiki><br />
<br />
This command will host your app locally. Once you started it, it will always have to run in the background, making all changes within the given build-directories visible. To add the build path of an other workspace, stop appserver and run the upper command again appending the other directory after a white space.<br />
<br />
WARNING: Take care that build variables like <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or <code>[[AppSuite:UI_build_system#manifestDir|manifestDir]]</code> are not set during development. Otherwise, you will have to specify their directories manually for <code>appserver</code>. Also, the <code>[[AppSuite:UI_build_system#clean|clean]]</code> task will delete these directories and all their contents! In general, don't point <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or any other <code>*Dir</code> variables at existing directories.<br />
<br />
=== Testing the app ===<br />
<br />
Once made your app available, you can access OX App Suite opening your browser with this address:<br />
http://localhost:8337/appsuite<br />
Then simply run this command in your browser's javascript console to open the hello world application:<br />
<pre class="language-javascript"><br />
ox.launch("com.example/main")<br />
</pre><br />
<br />
=== Development cycle ===<br />
<br />
Once successfully tested your first app, you will probably continue developing it. <br />
Keep in mind that after [[#Writing | writing your code]], you will always need to [[#Building | build the app]] and have your [[#Hosting the app | Appserver]] running.<br />
<br />
== Packaging ==<br />
When your app is done, you probably want to test it on a staging system, and later install it on a production system. To keep track of which installed files belong to which version of which app, you should use the native package manager of the Linux distribution of the target system. The packages can be easily created using the build system.<br />
<br />
=== Initialization ===<br />
First, you need to create several files describing how to package you app. Use the <tt>init-packaging</tt> task of the build system:<br />
<br />
$ build-appsuite init-packaging<br />
Node version: v0.10.21<br />
Build path: build<br />
Build version: 0.0.1-1.20131025.133931<br />
Package name: example-app<br />
Version [0.0.1]: <br />
Maintainer (Name <e-mail>): Maintainer <maintainer@example.com><br />
Copyright line [2013 Open-Xchange, Inc]: <br />
<br />
Known licenses for which you don't need to specify a file:<br />
APACHE-2, BSD-2-CLAUSE, BSD-3-CLAUSE, CC-BY-3, CC-BY-NC-3, CC-BY-NC-ND-3,<br />
CC-BY-NC-SA-3, CC-BY-ND-3, CC-BY-SA-3, CC0-1, EXPAT, GPL-2, GPL-3, LGPL-3<br />
<br />
License name [CC-BY-NC-SA-3.0]: BSD-3-Clause<br />
Short description: Example app<br />
<br />
The task presents a number of interactive prompts to get the necessary information about the generated packages. The default values are presented in square brackets ([...]) and can be selected by just pressing Enter. Otherwise, the entered values should follow the Debian Maintainer's Guide. Debian tools are especially picky about the syntax of the maintainer name and email address.<br />
<br />
If none of the known licenses suit you, you can enter any other license name. Then you will be asked to enter the file name of your license text. It should be a plain text file using the UTF-8 encoding.<br />
<br />
Some or even all prompts can be skipped by explicitly specifying the information as a build variable. The list of variable names is available in the reference of the <tt>[[AppSuite:UI_build_system#init-packaging|init-packaging]]</tt> task.<br />
<br />
After answering all the questions, you can customize the generated files to account for any additional packaging requirements.<br />
<br />
=== Static Files ===<br />
If your app includes images (e.g. themes do this most of the time), then you should check the generated packaging files for sections marked<br />
<br />
## Uncomment for multiple packages<br />
#...<br />
<br />
and remove the '#' at the start of each line in each block. This enables the creation of a second package, with a name ending in "<tt>-static</tt>". The images and any other files which are not JavaScript or CSS are server by the Apache web server, instead of the OX App Suite application server. These files are copied to a separate package for the case that the web server is on a dedicated system or maybe even has its own cluster. The default package is installed on the OX application server, and the second, "<tt>-static</tt>" package is installed on the web server.<br />
<br />
=== Building Packages ===<br />
Since the actual package format depends on the distribution it is built for, and there already exist tools to create packages from suitably arranged source code archives, the OX App Suite build system merely prepares such source archives. Using the <tt>dist</tt> task to create the archives:<br />
<br />
$ build-appsuite dist<br />
Node version: v0.10.21<br />
Build path: build<br />
Build version: 0.0.1-1.20131025.150034<br />
dpkg-source: info: using source format `3.0 (quilt)'<br />
dpkg-source: info: building example-app using existing ./example-app_0.0.1.orig.tar.bz2<br />
dpkg-source: info: building example-app in example-app_0.0.1-1.debian.tar.bz2<br />
dpkg-source: info: building example-app in example-app_0.0.1-1.dsc<br />
<br />
$ ls tmp/packaging/<br />
example-app-0.0.1 example-app_0.0.1-1.dsc<br />
example-app.spec example-app_0.0.1.orig.tar.bz2<br />
example-app_0.0.1-1.debian.tar.bz2<br />
<br />
The task creates a temporary directory and four files. The archive with the extension <tt>.orig.tar.bz2</tt> contains the source of your app. It is required to build both Debian and RPM packages. The files with extensions <tt>.debian.tar.bz2</tt> and <tt>.dsc</tt> are used together with the <tt>.orig.tar.bz2</tt> archive to build Debian packages. The file with the extension <tt>.spec</tt> is used together with the <tt>.orig.tar.bz2</tt> archive to build RPM packages.<br />
<br />
==== Building Debian Packages ====<br />
The Debian package can be built directly in the temporary directory created by the <tt>dist</tt> task:<br />
<br />
$ cd tmp/packaging/example-app-0.0.1/<br />
$ dpkg-buildpackage -b<br />
<br />
The package will be placed in <tt>tmp/packaging/</tt>.<br />
<br />
==== Building RPM Packages ====<br />
The RPM package build toor, <tt>rpmbuild</tt> requires the files to be in a specific directory layout before building:<br />
<br />
$ mkdir -p ~/rpmbuild/SOURCES<br />
$ cp tmp/packages/*.orig.tar.bz2 ~/rpmbuild/SOURCES/<br />
$ mkdir -p ~/rpmbuild/SPECS<br />
$ cp tmp/packaging/*.spec ~/rpmbuild/SPECS/<br />
$ rpmbuild ~/rpmbuild/SPECS/*.spec<br />
<br />
The package will be placed in <tt>~/rpmbuild/RPMS/</tt>.<br />
<br />
== Further Reading ==<br />
* You just build your first app for OX App Suite, keep in mind that there [[DevelopingTheUI#What_can_i_build.3F | quite a few options]] how you can develop for OX App Suite.<br />
* It's highly recommended to gain more knowledge about all the benefits [[AppSuite:UI_build_system | the UI build system]] and [[AppSuite:Appserver|the Appserver]] are providing you for developing OX App Suite.<br />
* If you're stuck somewhere, the article about [[AppSuite:Debugging_the_UI | debugging the UI]] might help you.<br />
* Get a better overview about [[DevelopingTheUI | developing the user inferface]].</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:UI_build_system&diff=16258AppSuite:UI build system2013-10-28T10:17:04Z<p>Mark.schmidts: /* Workflow */</p>
<hr />
<div>{{Stability-experimental}}<br />
<br />
<div class="title">Build System</div><br />
<br />
'''Abstract:''' This document describes the build system of OX App Suite. It is intended for app developers who use the build system to create apps as well as for OX App Suite developers who not only use the build system but also may wish to extend it.<br />
<br />
The build system is used to create source archives from source files. These source archives can be used to compile installable packages for various Linux distributions. The build system can generate archives for the core UI as well as for independently installed apps.<br />
<br />
The OX App Suite build system uses [https://github.com/mde/jake Jake], a port of Rake from Ruby to [http://nodejs.org Node.js]. Both Rake and Jake are dependency-based build systems like Make, which allows quick incremental builds. But unlike Make, Jake doesn't have its own syntax. Instead, it provides an API in JavaScript. The API is used not only to specify dependencies between files using a full programming language, but also to implement the generation of files in the same language. This allows easy implementation of complex build systems, of which the OX App Suite build system is an example. Using the same language for the developed project and for its build system also allows any core developer to quickly extend the build system without having to switch to another language.<br />
<br />
== Using the Build System ==<br />
<br />
While easily extensible, most of the time the build system will be used as-is. This chapter describes how to set up and use the build system to develop apps and the OX App Suite core.<br />
<br />
All command examples are given for the Debian operating system. The instructions should work similarly on other POSIX systems. The first character of each command indicates whether it should be executed as root (#) or as a normal user ($).<br />
<br />
== Installing ==<br />
<br />
Installing the right environment for running the <code>appserver</code> and the UI build system is described in [[AppSuite:GettingStarted#Installing | the getting started article]].<br />
<br />
== Running ==<br />
<br />
The build system is executed by invoking the command <code>build-appsuite</code>. Similar to most build systems, the build system can perform multiple tasks, which are specified as parameters on the command line. Each task can require any number of parameters. These parameters can be specified either on the command line, using the syntax <code>name=value</code>, or as environment variables.<br />
<br />
If present, the file <code>local.conf</code> is sourced by a shell script before the build process starts. This file can export environment variables which are specific to the local system, without checking them into a version control system. Typically, it defines values for <code>[[#builddir|builddir]]</code> and <code>[[#debug|debug]]</code>.<br />
<br />
Since the build system is based on Jake, it also accepts all other Jake options. In addition, the environment variable <code>$nodeopts</code> can be used to pass command line parameters to Node.js. One of the most useful parameters is <code>--debug-brk</code>, which can be used to debug the build system.<br />
<br />
When developing external apps, the build system must be run from the top directory of the app's source. As a safety precaution, execution is aborted if the subdirectory <code>apps</code>, which usually contains JavaScript source code, is not found. This Article is written assuming, you're working in your workspace directory, containing the subfolder <code>apps</code>.<br />
<br />
== Workflow ==<br />
<br />
The build system is used not only to create source archives for packaging. It can also directly install and update the built UI in a directory during development, help with the setup of the source of a new external app and more. While all of these tasks are described in the reference section, daily work involves just a few of them.<br />
<br />
To have an easy example about how to [[AppSuite:GettingStarted#Writing | write]], [[AppSuite:GettingStarted#Building | build]] & [[AppSuite:GettingStarted#Running | host]] your javascript code and how to [[AppSuite:GettingStarted#Initialization | initialize]] & [[AppSuite:GettingStarted#Building_Packages | build]] your packages, please have a look at the [[AppSuite:GettingStarted | GettingStarted article]].<br />
<br />
==== JSHINT ====<br />
<br />
One step of the build process is running jshint to statically analyse the sources for certain errors. JSHint is configured with (what we think) sane defaults, but if you want to configure your own rules, edit <code>.jshintrc</code> in your project`s root folder, according to your needs.<br />
<br />
=== default ===<br />
<br />
The default task is used instead of the app task when building the core OX App Suite. Since it is the default Jake task, it is not necessary to specify it on the command line when it's the only task.<br />
<br />
The top directory of OX App Suite source code includes the script <code>build.sh</code>, which should be used instead of calling a potentially unrelated version of <code>build-appsuite</code>. The script changes the current directory to its own, so that it can be called from any directory.<br />
<br />
$ web/ui/build.sh<br />
<br />
=== clean ===<br />
<br />
The build system uses dependencies and file timestamps to decide which files to rebuild. This assumes that any change to a file increases its timestamp to a value which is greater than the timestamp of any existing file. When this assumption is violated (e.g. after switching to a different source control branch with older files) it may become necessary to rebuild everything to restore the assumption about timestamps. The simplest way to achieve this is the clean task, which simply deletes all generated files.<br />
<br />
WARNING: This can be potentially dangerous, since the clean task simply deletes the directories specified by the variables builddir, destDir, l10nDir, manifestDir, and helpDir.<br />
<br />
=== dist ===<br />
<br />
When the app is ready to be shipped, or rather all the time on a continuous build system, the app needs to be packaged in a format suitable for installation on a production system. Since there already exist tools to create packages from suitably arranged source code archives, the OX App Suite build system merely prepares such source archives.<br />
<br />
The dist task creates an archive with the source (the one ending in .orig.tar.bz2) and a few additional files necessary for Debian packaging. RPM packages can be generated using the same source archive and the .spec file created by init-packaging. The version of the package is extracted from the newest entry in the file debian/changelog.<br />
<br />
Debian packages can also be generated manually either from the temporary directory left behind by dist, or even directly from the source tree. The second option pollutes the source tree with generated files, so it is not recommended, although the .gitignore file created by init-packaging can handle these generated files.<br />
<br />
$ build-appsuite dist<br />
$ ls tmp/packaging/<br />
example-app-0.0.1 example-app_0.0.1-1.dsc<br />
example-app_0.0.1-1.debian.tar.bz2 example-app_0.0.1.orig.tar.bz2<br />
$ cd tmp/packaging/example-app-0.0.1/<br />
$ dpkg-buildpackage -b<br />
<br />
== Reference ==<br />
<br />
=== Variables ===<br />
<br />
==== BASEDIR ====<br />
The top directory of the build system.<br />
<br />
<b>Used by:</b> all tasks.<br />
<br />
<b>Default:</b> installation directory of the build system<br />
<br />
Required to build external apps, since in this case, the build<br />
system is not installed in the current directory. This variable is<br />
automatically set as an environment variable by the build system<br />
executable based on <code>$OX_APPSUITE_DEV</code>.<br />
<br />
==== branch ====<br />
The Subversion branch of the CLDR to checkout.<br />
<br />
<b>Used by:</b> <code>update-i18n</code>.<br />
<br />
==== builddir ====<br />
The target directory for generated files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>, <code>docs</code>,<br />
<code>jakedeps</code>.<br />
<br />
Default: <code>build</code><br />
<br />
==== copyright ====<br />
The copyright line to be included in packaging metadata.<br />
<br />
<b>Used by:</b> <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
<b>Example:</b> <code>2012 Open-Xchange, Inc</code><br />
<br />
==== coreDir ====<br />
Location of OX App Suite UI files.<br />
<br />
<b>Used by:</b> <code>[[#app|app]]</code>, <code>[[#default|default]]</code>.<br />
<br />
<b>Default:</b> same as <code>[[#builddir|builddir]]</code><br />
<br />
Some tasks depend on installed files from the OX App Suite. When building external apps, <code>[[#coreDir|coreDir]]</code> specified the directory which contains these files.<br />
<br />
Currently, this parameter is used to compile <code>.less</code> files for every installed theme. This can be disabled by setting <code>[[#skipLess|skipLess]]</code>.<br />
<br />
==== debug ====<br />
Enables a debug build.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
To simplify debugging of OX App Suite, compression of source code<br />
can be disabled by specifying <code>on</code>, <code>yes</code>,<br />
<code>true</code> or <code>1</code>.<br />
<br />
==== description ====<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
The description of the app to be included in packaging metadata.<br />
<br />
==== destDir ====<br />
Output directory for source archives created by<br />
the <code>dist</code> task.<br />
<br />
<b>Used by:</b> <code>clean</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> <code>tmp/packaging</code><br />
<br />
==== disableStrictMode ====<br />
Removes all <code>"use strict"</code> directives from processed<br />
JavaScript code.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
Some debugging tools which use code instrumentation have problems<br />
when the debugged code uses strict mode. This setting enables code<br />
processing even whe using <code>debug</code> mode, so line numbers<br />
will not match the original source code.<br />
<br />
==== forceDeb ====<br />
Whether an error during the generation of Debian source packages is an error.<br />
<br />
<b>Used by:</b> <code>dist</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This is useful when Debian packages are generated automatically, and a failure of <code>dpkg-source</code> is also a failure of the entire build. By default it merely produces a warning.<br />
<br />
==== from ====<br />
The root of the printed dependency tree between Jake tasks.<br />
<br />
<b>Used by:</b> <code>jakedeps</code>.<br />
<br />
==== helpDir ====<br />
The location of online help files.<br />
<br />
<b>Used by:</b> <code>clean</code>, <code>default</code>,<br />
<code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
If the value contains the string <code>@lang@</code>, it will be<br />
replaced by the lowercase language code (e.g. <code>en-us</code>) to<br />
allow per-language directories.<br />
<br />
==== l10nDir ====<br />
The location of compiled l10n files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
If the value contains the string <code>@lang@</code>, it will be<br />
replaced by the lowercase language code (e.g. <code>en-us</code>) to<br />
allow per-language directories.<br />
<br />
==== license ====<br />
File name of the full text of the distribution license.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Default:</b> based on <code>licenseName</code>.<br />
<br />
==== licenseName ====<br />
Name of the distribution license to be included in packaging<br />
metadata.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Default:</b> <code>CC-BY-NC-SA-3.0</code><br />
<br />
==== manifestDir ====<br />
The location of the combined manifest file.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
==== maintainer ====<br />
Name and email address of the package maintainer.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Format:</b> <code><var>Name</var> &lt;<var>email</var>&gt;</code><br />
<br />
==== package ====<br />
The name of the package for the built app.<br />
<br />
<b>Used by:</b> all tasks.<br />
<br />
<b>Default:</b> the package name in the first line of<br />
<code>debian/changelog</code><br />
<br />
Since the name of the manifest file contains the package name and it<br />
is required to determine build dependencies, the package name must<br />
be always known. This means either <code>debian/changelog</code><br />
must exist and contain at least one entry, or the parameter must be<br />
explicitly specified.<br />
<br />
==== reverse ====<br />
Reverses the direction of printed dependencies.<br />
<br />
<b>Used by:</b> <code>deps</code>.<br />
<br />
When specified, the <code>deps</code> task prints modules which<br />
depend on the specified modules, instead of modules on which<br />
the specified module depends.<br />
<br />
==== revision ====<br />
Revision number of the package for the app.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>,<br />
<code>dist</code>.<br />
<br />
<b>Default:</b> <code>1</code><br />
<br />
The revision number must increase with each rebuild of the same<br />
version to enable the creation of unique version strings. These are<br />
required in package names and to control content caching in clients.<br />
<br />
==== root ====<br />
Specifies for which module to print the dependencies.<br />
<br />
<b>Used by:</b> <code>deps</code>.<br />
<br />
<b>Default:</b> print all roots<br />
<br />
If specified, only the dependencies of the specified module are<br />
printed. Otherwise, the dependencies of all modules are printed.<br />
<br />
==== skipDeb ====<br />
Whether to skip the generation of Debian source packages.<br />
<br />
<b>Used by:</b> <code>dist</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This is useful when Debian packages are not required and/or<br />
<code>dpkg-source</code> is not available, e.g. on RPM based<br />
systems.<br />
<br />
Even when using this flag, at least the file<br />
<code>debian/changelog</code> is still required, because it is used<br />
to store the package name and version. <br />
<br />
==== skipLess ====<br />
Whether to skip the preprocessing of LessCSS files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This flag skips the generation of CSS files in<br />
the <code>apps/themes/*/less</code> directories of all themes.<br />
It is used by the packaging system, where the LessCSS files are<br />
precompiled after installation on the target system instead of<br />
while building the package.<br />
<br />
==== tag ====<br />
The Subversion tag of the CLDR to checkout.<br />
<br />
<b>Used by:</b> <code>update-i18n</code>.<br />
<br />
==== to ====<br />
The leaf task in the printed dependency path between Jake tasks.<br />
<br />
<b>Used by:</b> <code>jakedeps</code>.<br />
<br />
When specified, only a single path from the root to the leaf task is<br />
printed (in reverse order).<br />
<br />
==== version ====<br />
Version number of the app.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>,<br />
<code>dist</code>, <code>init-packaging</code>.<br />
<br />
<b>Default:</b> <code>0.0.1</code><br />
<br />
The version should consist of a major, minor and patch version<br />
separated by dots.<br />
<br />
=== Tasks ===<br />
<p><br />
An up-to-date list of tasks can be printed using the -T command line option.<br />
<br />
==== app ====<br />
Builds an external app.<br />
<br />
<b>Variables:</b> <code>[[#BASEDIR|BASEDIR]]</code>, <code>[[#builddir|builddir]]</code>, <code>[[#coreDir|coreDir]]</code>, <code>[[#debug|debug]]</code>, <code>[[#disableStrictMode|disableStrictMode]]</code>, <code>[[#l10nDir|l10nDir]]</code>, <code>[[#manifestDir|manifestDir]]</code>, <code>[[#package|package]]</code>, <code>[[#revision|revision]]</code>, <code>[[#version|version]]</code>.<br />
<br />
This is the main task used to build external apps.<br />
<br />
It works without explicitly specifying any variables, but during<br />
development, <code>[[#builddir|builddir]]</code> is usually pointed to<br />
the directory of a locally installed OX App Suite UI to avoid<br />
additional copying steps. For debugging, <code>[[#debug|debug]]</code> is also<br />
often used. Note that <code>[[#clean|clean]]</code> must be called when<br />
changing any of the variables.<br />
<br />
==== clean ====<br />
Removes all generated files.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>destDir</code>, <code>l10nDir</code>,<br />
<code>manifestDir</code>, <code>package</code>.<br />
<br />
This task should be executed before a normal build using<br />
<code>app</code> or <code>default</code> after changing any build<br />
variables and after a switch between Git branches. Normal<br />
incremental builds can miss changed files if a branch switch<br />
replaces files by older versions.<br />
<br />
==== default ====<br />
Builds OX App Suite.<br />
<br />
<b>Variables:</b> <code>[[#BASEDIR|BASEDIR]]</code>, <code>[[#builddir|builddir]]</code>, <code>[[#debug|debug]]</code>, <code>[[#disableStrictMode|disableStrictMode]]</code>, <code>[[#l10nDir|l10nDir]]</code>, <code>[[#manifestDir|manifestDir]]</code>, <code>[[#package|package]]</code>, <code>[[#revision|revision]]</code>, <code>[[#version|version]]</code>.<br />
<br />
This is the main task to build OX App Suite. Since it is the default<br />
Jake task, it does not need to be specified explicitly on<br />
the command line when it is the only task.<br />
<br />
It works without explicitly specifying any variables, but during<br />
development, <code>[[#builddir|builddir]]</code> is usually pointed to<br />
a directory which is accessible to a local web server. For<br />
debugging, <code>[[#debug|debug]]</code> is also often used. Note that<br />
<code>[[#clean|clean]]</code> must be called when changing any of<br />
the variables.<br />
<br />
==== deps ====<br />
Prints module dependencies.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>package</code>,<br />
<code>reverse</code>, <code>root</code>.<br />
<br />
This task visualizes dependencies of RequireJS modules. It prints<br />
a tree of dependencies to <code>stdout</code>.<br />
<br />
If <code>root</code> is specified, then only the dependencies of<br />
that module are printed. Otherwise, the dependencies of all modules,<br />
on which no other module depends are printed in sequence. <br />
<br />
If <code>reverse</code> is specified, then this task prints<br />
dependants instead of dependencies, i.e. modules which depend on<br />
the specified module instead of modules on which the specified<br />
module depends.<br />
<br />
==== dist ====<br />
Creates source packages.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>destDir</code>, <code>forceDeb</code>, <code>l10nDir</code>,<br />
<code>manifestDir</code>, <code>package</code>,<br />
<code>revision</code>, <code>skipDeb</code>,<br />
<code>version</code>.<br />
<br />
This task cleans the source tree by calling <code>clean</code> and<br />
packs the source into an archive which can be used to create Debian<br />
and RPM packages. The necessary Debian metadata is created alongside<br />
the source archive. All files necessary for Debian packaging are<br />
placed in the directory specified by <code>destDir</code>.<br />
The generated <code>.orig.tar.bz2</code> archive can also be used<br />
together with the <code>.spec</code> file to generate RPM packages.<br />
<br />
Unless the variable <code>skipDeb</code> is set to<br />
<code>true</code>, the program <code>dpkg-source</code> is required<br />
by this task. It is used to generate Debian-specific packaging<br />
metadata.<br />
<br />
==== init-packaging ====<br />
Initializes packaging information for a new app.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>copyright</code>,<br />
<code>description</code>, <code>license</code>,<br />
<code>licenseName</code>, <code>maintainer</code>,<br />
<code>package</code>, <code>version</code>.<br />
<br />
This task is the first task called when starting with<br />
the development of a new external app. The directory from which it<br />
is called must already contain at least the <code>apps</code><br />
subdirectory. This is also the only task where<br />
the <code>package</code> variable must be specified explicitly.<br />
Afterwards, the package name is looked up automatically in the file<br />
<code>debian/changelog</code>, which is created by this task.<br />
<br />
The variables <code>version</code>, <code>maintainer</code>,<br />
<code>copyright</code>, <code>licenseName</code>,<br />
<code>license</code>, and <code>description</code> are required to<br />
fill out all necessary packaging metadata. Any of these variables<br />
which are not specified explicitly will cause an interactive prompt.<br />
This avoids the need to remember the list of variables before one<br />
can start developing an app.<br />
<br />
==== jakedeps ====<br />
Shows the dependency chain between two Jake tasks.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>from</code>,<br />
<code>package</code>, <code>to</code>.<br />
<br />
This task visualized dependencies between Jake tasks. The variable<br />
<code>from</code> specifies the root of a dependency tree, with all<br />
dependencies of <code>from</code> as inner and leaf nodes. If<br />
<code>to</code> is not specified, then that entire tree is printed.<br />
<br />
If <code>to</code> is also specified, then only the first found<br />
dependency path from <code>from</code> to <code>to</code> is<br />
.printed with <code>to</code> at the top and <code>from</code> at<br />
the bottom.<br />
<br />
==== merge ====<br />
Updates all <code>.po</code> files with the generated<br />
<code>ox.pot</code>.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>debug</code>, <code>package</code>, <code>revision</code>,<br />
<code>version</code>.<br />
<br />
This task updates the list of extracted i18n strings in<br />
<code>ox.pot</code> and calls the GNU Gettext tool<br />
<code>msgmerge</code> for every language in <code>i18n/*.po</code>.<br />
<br />
<code>i18n/en_US.po</code> is not updated by this task because the original strings are already in the <code>en_US</code> locale. It would only end up with every translation mapping every string to itself. The only entries in that file should be for cases when the <code>en_US</code> text is not a suitable fallback for missing translations. The original string in such a case would be something internationally appropriate (e.&nbsp;g. a date written as "2013-01-01" instead of "01/01/2013") and <code>i18n/en_US.po</code> would contain a translation.<br />
<br />
==== update-i18n ====<br />
Updates CLDR data in the source tree.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>branch</code>,<br />
<code>package</code>, <code>tag</code>.<br />
<br />
This task downloads data from the Unicode CLDR and updates date<br />
translations for all languages in <code>i18n/*.po</code>.<br />
<br />
The exact version of CLDR data is specified as Suubversion tag or<br />
branch by the variables <code>tag</code> and <code>branch</code>,<br />
respectively. If neither is specified, then the Subversion trunk is<br />
checked out. If both are specified, <code>tag</code> is used.<br />
<br />
==== verify-doc ====<br />
Generates a documentation skeleton for extension points.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>package</code>.<br />
<br />
This task is still under development. Currently, it creates a list of all extension points, which have a constant name in the source code. In the future it is supposed to update an existing list instead of overwriting it, and to handle non-constant extension point names.<br />
<br />
The list of extension points is stored as an HTML snippet in <code>doc/extensionpoints.html</code>.<br />
<br />
<br />
[[Category:AppSuite]]<br />
[[Category:UI]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:UI_build_system&diff=16257AppSuite:UI build system2013-10-28T10:11:49Z<p>Mark.schmidts: /* Workflow */</p>
<hr />
<div>{{Stability-experimental}}<br />
<br />
<div class="title">Build System</div><br />
<br />
'''Abstract:''' This document describes the build system of OX App Suite. It is intended for app developers who use the build system to create apps as well as for OX App Suite developers who not only use the build system but also may wish to extend it.<br />
<br />
The build system is used to create source archives from source files. These source archives can be used to compile installable packages for various Linux distributions. The build system can generate archives for the core UI as well as for independently installed apps.<br />
<br />
The OX App Suite build system uses [https://github.com/mde/jake Jake], a port of Rake from Ruby to [http://nodejs.org Node.js]. Both Rake and Jake are dependency-based build systems like Make, which allows quick incremental builds. But unlike Make, Jake doesn't have its own syntax. Instead, it provides an API in JavaScript. The API is used not only to specify dependencies between files using a full programming language, but also to implement the generation of files in the same language. This allows easy implementation of complex build systems, of which the OX App Suite build system is an example. Using the same language for the developed project and for its build system also allows any core developer to quickly extend the build system without having to switch to another language.<br />
<br />
== Using the Build System ==<br />
<br />
While easily extensible, most of the time the build system will be used as-is. This chapter describes how to set up and use the build system to develop apps and the OX App Suite core.<br />
<br />
All command examples are given for the Debian operating system. The instructions should work similarly on other POSIX systems. The first character of each command indicates whether it should be executed as root (#) or as a normal user ($).<br />
<br />
== Installing ==<br />
<br />
Installing the right environment for running the <code>appserver</code> and the UI build system is described in [[AppSuite:GettingStarted#Installing | the getting started article]].<br />
<br />
== Running ==<br />
<br />
The build system is executed by invoking the command <code>build-appsuite</code>. Similar to most build systems, the build system can perform multiple tasks, which are specified as parameters on the command line. Each task can require any number of parameters. These parameters can be specified either on the command line, using the syntax <code>name=value</code>, or as environment variables.<br />
<br />
If present, the file <code>local.conf</code> is sourced by a shell script before the build process starts. This file can export environment variables which are specific to the local system, without checking them into a version control system. Typically, it defines values for <code>[[#builddir|builddir]]</code> and <code>[[#debug|debug]]</code>.<br />
<br />
Since the build system is based on Jake, it also accepts all other Jake options. In addition, the environment variable <code>$nodeopts</code> can be used to pass command line parameters to Node.js. One of the most useful parameters is <code>--debug-brk</code>, which can be used to debug the build system.<br />
<br />
When developing external apps, the build system must be run from the top directory of the app's source. As a safety precaution, execution is aborted if the subdirectory <code>apps</code>, which usually contains JavaScript source code, is not found. This Article is written assuming, you're working in your workspace directory, containing the subfolder <code>apps</code>.<br />
<br />
== Workflow ==<br />
<br />
The build system is used not only to create source archives for packaging. It can also directly install and update the built UI in a directory during development, help with the setup of the source of a new external app and more. While all of these tasks are described in the reference section, daily work involves just a few of them.<br />
<br />
To have an easy example about how to write, build & host your javascript code and how to initialize & build your packages, please have a look at the [[AppSuite:GettingStarted | GettingStarted article]].<br />
<br />
==== JSHINT ====<br />
<br />
One step of the build process is running jshint to statically analyse the sources for certain errors. JSHint is configured with (what we think) sane defaults, but if you want to configure your own rules, edit <code>.jshintrc</code> in your project`s root folder, according to your needs.<br />
<br />
=== default ===<br />
<br />
The default task is used instead of the app task when building the core OX App Suite. Since it is the default Jake task, it is not necessary to specify it on the command line when it's the only task.<br />
<br />
The top directory of OX App Suite source code includes the script <code>build.sh</code>, which should be used instead of calling a potentially unrelated version of <code>build-appsuite</code>. The script changes the current directory to its own, so that it can be called from any directory.<br />
<br />
$ web/ui/build.sh<br />
<br />
=== clean ===<br />
<br />
The build system uses dependencies and file timestamps to decide which files to rebuild. This assumes that any change to a file increases its timestamp to a value which is greater than the timestamp of any existing file. When this assumption is violated (e.g. after switching to a different source control branch with older files) it may become necessary to rebuild everything to restore the assumption about timestamps. The simplest way to achieve this is the clean task, which simply deletes all generated files.<br />
<br />
WARNING: This can be potentially dangerous, since the clean task simply deletes the directories specified by the variables builddir, destDir, l10nDir, manifestDir, and helpDir.<br />
<br />
=== dist ===<br />
<br />
When the app is ready to be shipped, or rather all the time on a continuous build system, the app needs to be packaged in a format suitable for installation on a production system. Since there already exist tools to create packages from suitably arranged source code archives, the OX App Suite build system merely prepares such source archives.<br />
<br />
The dist task creates an archive with the source (the one ending in .orig.tar.bz2) and a few additional files necessary for Debian packaging. RPM packages can be generated using the same source archive and the .spec file created by init-packaging. The version of the package is extracted from the newest entry in the file debian/changelog.<br />
<br />
Debian packages can also be generated manually either from the temporary directory left behind by dist, or even directly from the source tree. The second option pollutes the source tree with generated files, so it is not recommended, although the .gitignore file created by init-packaging can handle these generated files.<br />
<br />
$ build-appsuite dist<br />
$ ls tmp/packaging/<br />
example-app-0.0.1 example-app_0.0.1-1.dsc<br />
example-app_0.0.1-1.debian.tar.bz2 example-app_0.0.1.orig.tar.bz2<br />
$ cd tmp/packaging/example-app-0.0.1/<br />
$ dpkg-buildpackage -b<br />
<br />
== Reference ==<br />
<br />
=== Variables ===<br />
<br />
==== BASEDIR ====<br />
The top directory of the build system.<br />
<br />
<b>Used by:</b> all tasks.<br />
<br />
<b>Default:</b> installation directory of the build system<br />
<br />
Required to build external apps, since in this case, the build<br />
system is not installed in the current directory. This variable is<br />
automatically set as an environment variable by the build system<br />
executable based on <code>$OX_APPSUITE_DEV</code>.<br />
<br />
==== branch ====<br />
The Subversion branch of the CLDR to checkout.<br />
<br />
<b>Used by:</b> <code>update-i18n</code>.<br />
<br />
==== builddir ====<br />
The target directory for generated files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>, <code>docs</code>,<br />
<code>jakedeps</code>.<br />
<br />
Default: <code>build</code><br />
<br />
==== copyright ====<br />
The copyright line to be included in packaging metadata.<br />
<br />
<b>Used by:</b> <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
<b>Example:</b> <code>2012 Open-Xchange, Inc</code><br />
<br />
==== coreDir ====<br />
Location of OX App Suite UI files.<br />
<br />
<b>Used by:</b> <code>[[#app|app]]</code>, <code>[[#default|default]]</code>.<br />
<br />
<b>Default:</b> same as <code>[[#builddir|builddir]]</code><br />
<br />
Some tasks depend on installed files from the OX App Suite. When building external apps, <code>[[#coreDir|coreDir]]</code> specified the directory which contains these files.<br />
<br />
Currently, this parameter is used to compile <code>.less</code> files for every installed theme. This can be disabled by setting <code>[[#skipLess|skipLess]]</code>.<br />
<br />
==== debug ====<br />
Enables a debug build.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
To simplify debugging of OX App Suite, compression of source code<br />
can be disabled by specifying <code>on</code>, <code>yes</code>,<br />
<code>true</code> or <code>1</code>.<br />
<br />
==== description ====<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
The description of the app to be included in packaging metadata.<br />
<br />
==== destDir ====<br />
Output directory for source archives created by<br />
the <code>dist</code> task.<br />
<br />
<b>Used by:</b> <code>clean</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> <code>tmp/packaging</code><br />
<br />
==== disableStrictMode ====<br />
Removes all <code>"use strict"</code> directives from processed<br />
JavaScript code.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
Some debugging tools which use code instrumentation have problems<br />
when the debugged code uses strict mode. This setting enables code<br />
processing even whe using <code>debug</code> mode, so line numbers<br />
will not match the original source code.<br />
<br />
==== forceDeb ====<br />
Whether an error during the generation of Debian source packages is an error.<br />
<br />
<b>Used by:</b> <code>dist</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This is useful when Debian packages are generated automatically, and a failure of <code>dpkg-source</code> is also a failure of the entire build. By default it merely produces a warning.<br />
<br />
==== from ====<br />
The root of the printed dependency tree between Jake tasks.<br />
<br />
<b>Used by:</b> <code>jakedeps</code>.<br />
<br />
==== helpDir ====<br />
The location of online help files.<br />
<br />
<b>Used by:</b> <code>clean</code>, <code>default</code>,<br />
<code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
If the value contains the string <code>@lang@</code>, it will be<br />
replaced by the lowercase language code (e.g. <code>en-us</code>) to<br />
allow per-language directories.<br />
<br />
==== l10nDir ====<br />
The location of compiled l10n files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
If the value contains the string <code>@lang@</code>, it will be<br />
replaced by the lowercase language code (e.g. <code>en-us</code>) to<br />
allow per-language directories.<br />
<br />
==== license ====<br />
File name of the full text of the distribution license.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Default:</b> based on <code>licenseName</code>.<br />
<br />
==== licenseName ====<br />
Name of the distribution license to be included in packaging<br />
metadata.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Default:</b> <code>CC-BY-NC-SA-3.0</code><br />
<br />
==== manifestDir ====<br />
The location of the combined manifest file.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
==== maintainer ====<br />
Name and email address of the package maintainer.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Format:</b> <code><var>Name</var> &lt;<var>email</var>&gt;</code><br />
<br />
==== package ====<br />
The name of the package for the built app.<br />
<br />
<b>Used by:</b> all tasks.<br />
<br />
<b>Default:</b> the package name in the first line of<br />
<code>debian/changelog</code><br />
<br />
Since the name of the manifest file contains the package name and it<br />
is required to determine build dependencies, the package name must<br />
be always known. This means either <code>debian/changelog</code><br />
must exist and contain at least one entry, or the parameter must be<br />
explicitly specified.<br />
<br />
==== reverse ====<br />
Reverses the direction of printed dependencies.<br />
<br />
<b>Used by:</b> <code>deps</code>.<br />
<br />
When specified, the <code>deps</code> task prints modules which<br />
depend on the specified modules, instead of modules on which<br />
the specified module depends.<br />
<br />
==== revision ====<br />
Revision number of the package for the app.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>,<br />
<code>dist</code>.<br />
<br />
<b>Default:</b> <code>1</code><br />
<br />
The revision number must increase with each rebuild of the same<br />
version to enable the creation of unique version strings. These are<br />
required in package names and to control content caching in clients.<br />
<br />
==== root ====<br />
Specifies for which module to print the dependencies.<br />
<br />
<b>Used by:</b> <code>deps</code>.<br />
<br />
<b>Default:</b> print all roots<br />
<br />
If specified, only the dependencies of the specified module are<br />
printed. Otherwise, the dependencies of all modules are printed.<br />
<br />
==== skipDeb ====<br />
Whether to skip the generation of Debian source packages.<br />
<br />
<b>Used by:</b> <code>dist</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This is useful when Debian packages are not required and/or<br />
<code>dpkg-source</code> is not available, e.g. on RPM based<br />
systems.<br />
<br />
Even when using this flag, at least the file<br />
<code>debian/changelog</code> is still required, because it is used<br />
to store the package name and version. <br />
<br />
==== skipLess ====<br />
Whether to skip the preprocessing of LessCSS files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This flag skips the generation of CSS files in<br />
the <code>apps/themes/*/less</code> directories of all themes.<br />
It is used by the packaging system, where the LessCSS files are<br />
precompiled after installation on the target system instead of<br />
while building the package.<br />
<br />
==== tag ====<br />
The Subversion tag of the CLDR to checkout.<br />
<br />
<b>Used by:</b> <code>update-i18n</code>.<br />
<br />
==== to ====<br />
The leaf task in the printed dependency path between Jake tasks.<br />
<br />
<b>Used by:</b> <code>jakedeps</code>.<br />
<br />
When specified, only a single path from the root to the leaf task is<br />
printed (in reverse order).<br />
<br />
==== version ====<br />
Version number of the app.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>,<br />
<code>dist</code>, <code>init-packaging</code>.<br />
<br />
<b>Default:</b> <code>0.0.1</code><br />
<br />
The version should consist of a major, minor and patch version<br />
separated by dots.<br />
<br />
=== Tasks ===<br />
<p><br />
An up-to-date list of tasks can be printed using the -T command line option.<br />
<br />
==== app ====<br />
Builds an external app.<br />
<br />
<b>Variables:</b> <code>[[#BASEDIR|BASEDIR]]</code>, <code>[[#builddir|builddir]]</code>, <code>[[#coreDir|coreDir]]</code>, <code>[[#debug|debug]]</code>, <code>[[#disableStrictMode|disableStrictMode]]</code>, <code>[[#l10nDir|l10nDir]]</code>, <code>[[#manifestDir|manifestDir]]</code>, <code>[[#package|package]]</code>, <code>[[#revision|revision]]</code>, <code>[[#version|version]]</code>.<br />
<br />
This is the main task used to build external apps.<br />
<br />
It works without explicitly specifying any variables, but during<br />
development, <code>[[#builddir|builddir]]</code> is usually pointed to<br />
the directory of a locally installed OX App Suite UI to avoid<br />
additional copying steps. For debugging, <code>[[#debug|debug]]</code> is also<br />
often used. Note that <code>[[#clean|clean]]</code> must be called when<br />
changing any of the variables.<br />
<br />
==== clean ====<br />
Removes all generated files.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>destDir</code>, <code>l10nDir</code>,<br />
<code>manifestDir</code>, <code>package</code>.<br />
<br />
This task should be executed before a normal build using<br />
<code>app</code> or <code>default</code> after changing any build<br />
variables and after a switch between Git branches. Normal<br />
incremental builds can miss changed files if a branch switch<br />
replaces files by older versions.<br />
<br />
==== default ====<br />
Builds OX App Suite.<br />
<br />
<b>Variables:</b> <code>[[#BASEDIR|BASEDIR]]</code>, <code>[[#builddir|builddir]]</code>, <code>[[#debug|debug]]</code>, <code>[[#disableStrictMode|disableStrictMode]]</code>, <code>[[#l10nDir|l10nDir]]</code>, <code>[[#manifestDir|manifestDir]]</code>, <code>[[#package|package]]</code>, <code>[[#revision|revision]]</code>, <code>[[#version|version]]</code>.<br />
<br />
This is the main task to build OX App Suite. Since it is the default<br />
Jake task, it does not need to be specified explicitly on<br />
the command line when it is the only task.<br />
<br />
It works without explicitly specifying any variables, but during<br />
development, <code>[[#builddir|builddir]]</code> is usually pointed to<br />
a directory which is accessible to a local web server. For<br />
debugging, <code>[[#debug|debug]]</code> is also often used. Note that<br />
<code>[[#clean|clean]]</code> must be called when changing any of<br />
the variables.<br />
<br />
==== deps ====<br />
Prints module dependencies.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>package</code>,<br />
<code>reverse</code>, <code>root</code>.<br />
<br />
This task visualizes dependencies of RequireJS modules. It prints<br />
a tree of dependencies to <code>stdout</code>.<br />
<br />
If <code>root</code> is specified, then only the dependencies of<br />
that module are printed. Otherwise, the dependencies of all modules,<br />
on which no other module depends are printed in sequence. <br />
<br />
If <code>reverse</code> is specified, then this task prints<br />
dependants instead of dependencies, i.e. modules which depend on<br />
the specified module instead of modules on which the specified<br />
module depends.<br />
<br />
==== dist ====<br />
Creates source packages.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>destDir</code>, <code>forceDeb</code>, <code>l10nDir</code>,<br />
<code>manifestDir</code>, <code>package</code>,<br />
<code>revision</code>, <code>skipDeb</code>,<br />
<code>version</code>.<br />
<br />
This task cleans the source tree by calling <code>clean</code> and<br />
packs the source into an archive which can be used to create Debian<br />
and RPM packages. The necessary Debian metadata is created alongside<br />
the source archive. All files necessary for Debian packaging are<br />
placed in the directory specified by <code>destDir</code>.<br />
The generated <code>.orig.tar.bz2</code> archive can also be used<br />
together with the <code>.spec</code> file to generate RPM packages.<br />
<br />
Unless the variable <code>skipDeb</code> is set to<br />
<code>true</code>, the program <code>dpkg-source</code> is required<br />
by this task. It is used to generate Debian-specific packaging<br />
metadata.<br />
<br />
==== init-packaging ====<br />
Initializes packaging information for a new app.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>copyright</code>,<br />
<code>description</code>, <code>license</code>,<br />
<code>licenseName</code>, <code>maintainer</code>,<br />
<code>package</code>, <code>version</code>.<br />
<br />
This task is the first task called when starting with<br />
the development of a new external app. The directory from which it<br />
is called must already contain at least the <code>apps</code><br />
subdirectory. This is also the only task where<br />
the <code>package</code> variable must be specified explicitly.<br />
Afterwards, the package name is looked up automatically in the file<br />
<code>debian/changelog</code>, which is created by this task.<br />
<br />
The variables <code>version</code>, <code>maintainer</code>,<br />
<code>copyright</code>, <code>licenseName</code>,<br />
<code>license</code>, and <code>description</code> are required to<br />
fill out all necessary packaging metadata. Any of these variables<br />
which are not specified explicitly will cause an interactive prompt.<br />
This avoids the need to remember the list of variables before one<br />
can start developing an app.<br />
<br />
==== jakedeps ====<br />
Shows the dependency chain between two Jake tasks.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>from</code>,<br />
<code>package</code>, <code>to</code>.<br />
<br />
This task visualized dependencies between Jake tasks. The variable<br />
<code>from</code> specifies the root of a dependency tree, with all<br />
dependencies of <code>from</code> as inner and leaf nodes. If<br />
<code>to</code> is not specified, then that entire tree is printed.<br />
<br />
If <code>to</code> is also specified, then only the first found<br />
dependency path from <code>from</code> to <code>to</code> is<br />
.printed with <code>to</code> at the top and <code>from</code> at<br />
the bottom.<br />
<br />
==== merge ====<br />
Updates all <code>.po</code> files with the generated<br />
<code>ox.pot</code>.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>debug</code>, <code>package</code>, <code>revision</code>,<br />
<code>version</code>.<br />
<br />
This task updates the list of extracted i18n strings in<br />
<code>ox.pot</code> and calls the GNU Gettext tool<br />
<code>msgmerge</code> for every language in <code>i18n/*.po</code>.<br />
<br />
<code>i18n/en_US.po</code> is not updated by this task because the original strings are already in the <code>en_US</code> locale. It would only end up with every translation mapping every string to itself. The only entries in that file should be for cases when the <code>en_US</code> text is not a suitable fallback for missing translations. The original string in such a case would be something internationally appropriate (e.&nbsp;g. a date written as "2013-01-01" instead of "01/01/2013") and <code>i18n/en_US.po</code> would contain a translation.<br />
<br />
==== update-i18n ====<br />
Updates CLDR data in the source tree.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>branch</code>,<br />
<code>package</code>, <code>tag</code>.<br />
<br />
This task downloads data from the Unicode CLDR and updates date<br />
translations for all languages in <code>i18n/*.po</code>.<br />
<br />
The exact version of CLDR data is specified as Suubversion tag or<br />
branch by the variables <code>tag</code> and <code>branch</code>,<br />
respectively. If neither is specified, then the Subversion trunk is<br />
checked out. If both are specified, <code>tag</code> is used.<br />
<br />
==== verify-doc ====<br />
Generates a documentation skeleton for extension points.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>package</code>.<br />
<br />
This task is still under development. Currently, it creates a list of all extension points, which have a constant name in the source code. In the future it is supposed to update an existing list instead of overwriting it, and to handle non-constant extension point names.<br />
<br />
The list of extension points is stored as an HTML snippet in <code>doc/extensionpoints.html</code>.<br />
<br />
<br />
[[Category:AppSuite]]<br />
[[Category:UI]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:UI_build_system&diff=16256AppSuite:UI build system2013-10-28T10:10:41Z<p>Mark.schmidts: /* Workflow */</p>
<hr />
<div>{{Stability-experimental}}<br />
<br />
<div class="title">Build System</div><br />
<br />
'''Abstract:''' This document describes the build system of OX App Suite. It is intended for app developers who use the build system to create apps as well as for OX App Suite developers who not only use the build system but also may wish to extend it.<br />
<br />
The build system is used to create source archives from source files. These source archives can be used to compile installable packages for various Linux distributions. The build system can generate archives for the core UI as well as for independently installed apps.<br />
<br />
The OX App Suite build system uses [https://github.com/mde/jake Jake], a port of Rake from Ruby to [http://nodejs.org Node.js]. Both Rake and Jake are dependency-based build systems like Make, which allows quick incremental builds. But unlike Make, Jake doesn't have its own syntax. Instead, it provides an API in JavaScript. The API is used not only to specify dependencies between files using a full programming language, but also to implement the generation of files in the same language. This allows easy implementation of complex build systems, of which the OX App Suite build system is an example. Using the same language for the developed project and for its build system also allows any core developer to quickly extend the build system without having to switch to another language.<br />
<br />
== Using the Build System ==<br />
<br />
While easily extensible, most of the time the build system will be used as-is. This chapter describes how to set up and use the build system to develop apps and the OX App Suite core.<br />
<br />
All command examples are given for the Debian operating system. The instructions should work similarly on other POSIX systems. The first character of each command indicates whether it should be executed as root (#) or as a normal user ($).<br />
<br />
== Installing ==<br />
<br />
Installing the right environment for running the <code>appserver</code> and the UI build system is described in [[AppSuite:GettingStarted#Installing | the getting started article]].<br />
<br />
== Running ==<br />
<br />
The build system is executed by invoking the command <code>build-appsuite</code>. Similar to most build systems, the build system can perform multiple tasks, which are specified as parameters on the command line. Each task can require any number of parameters. These parameters can be specified either on the command line, using the syntax <code>name=value</code>, or as environment variables.<br />
<br />
If present, the file <code>local.conf</code> is sourced by a shell script before the build process starts. This file can export environment variables which are specific to the local system, without checking them into a version control system. Typically, it defines values for <code>[[#builddir|builddir]]</code> and <code>[[#debug|debug]]</code>.<br />
<br />
Since the build system is based on Jake, it also accepts all other Jake options. In addition, the environment variable <code>$nodeopts</code> can be used to pass command line parameters to Node.js. One of the most useful parameters is <code>--debug-brk</code>, which can be used to debug the build system.<br />
<br />
When developing external apps, the build system must be run from the top directory of the app's source. As a safety precaution, execution is aborted if the subdirectory <code>apps</code>, which usually contains JavaScript source code, is not found. This Article is written assuming, you're working in your workspace directory, containing the subfolder <code>apps</code>.<br />
<br />
== Workflow ==<br />
<br />
The build system is used not only to create source archives for packaging. It can also directly install and update the built UI in a directory during development, help with the setup of the source of a new external app and more. While all of these tasks are described in the reference section, daily work involves just a few of them.<br />
<br />
=== Create packaging metadata ===<br />
<br />
The first task which should be executed when creating a new external app is <code>[[#init-packaging|init-packaging]]</code>. It creates packaging metadata in the current directory. It requires the parameter <code>package</code> to specify the package name in the generated files. All subsequent tasks will automatically extract the package name from the files generated by <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
Before execution, the <code>apps</code> subdirectory must be created. It indicates that the current directory is actually a valid source directory.<br />
<br />
$ mkdir apps<br />
$ build-appsuite init-packaging package=example-app<br />
Build path: build<br />
Build version: 0.0.1-1.20130424.123835<br />
<br />
Version [0.0.1]: <br />
<br />
Maintainer (Name <e-mail>): Maintainer <maintainer@example.com><br />
<br />
Copyright line [2013 Open-Xchange, Inc]: <br />
<br />
License name [CC-BY-NC-SA-3.0]: <br />
<br />
Short description: Hello World app to demonstrate usage of the build system<br />
<br />
The task presents a number of interactive prompts to get the necessary information about the generated packages. The entered values should follow the Debian Maintainer's Guide. Some or even all prompts can be skipped by explicitly specifying the information as a build variable. The list of variable names is available in the reference of <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
After the task is finished, the generated files can be customized manually to account for any additional packaging requirements.<br />
<br />
=== Building apps ===<br />
<br />
To have an easy example about how to write, build & host your javascript code and how to initialize & build your packages, please have a look at the [[AppSuite:GettingStarted | GettingStarted article]].<br />
<br />
==== JSHINT ====<br />
<br />
One step of the build process is running jshint to statically analyse the sources for certain errors. JSHint is configured with (what we think) sane defaults, but if you want to configure your own rules, edit <code>.jshintrc</code> in your project`s root folder, according to your needs.<br />
<br />
=== default ===<br />
<br />
The default task is used instead of the app task when building the core OX App Suite. Since it is the default Jake task, it is not necessary to specify it on the command line when it's the only task.<br />
<br />
The top directory of OX App Suite source code includes the script <code>build.sh</code>, which should be used instead of calling a potentially unrelated version of <code>build-appsuite</code>. The script changes the current directory to its own, so that it can be called from any directory.<br />
<br />
$ web/ui/build.sh<br />
<br />
=== clean ===<br />
<br />
The build system uses dependencies and file timestamps to decide which files to rebuild. This assumes that any change to a file increases its timestamp to a value which is greater than the timestamp of any existing file. When this assumption is violated (e.g. after switching to a different source control branch with older files) it may become necessary to rebuild everything to restore the assumption about timestamps. The simplest way to achieve this is the clean task, which simply deletes all generated files.<br />
<br />
WARNING: This can be potentially dangerous, since the clean task simply deletes the directories specified by the variables builddir, destDir, l10nDir, manifestDir, and helpDir.<br />
<br />
=== dist ===<br />
<br />
When the app is ready to be shipped, or rather all the time on a continuous build system, the app needs to be packaged in a format suitable for installation on a production system. Since there already exist tools to create packages from suitably arranged source code archives, the OX App Suite build system merely prepares such source archives.<br />
<br />
The dist task creates an archive with the source (the one ending in .orig.tar.bz2) and a few additional files necessary for Debian packaging. RPM packages can be generated using the same source archive and the .spec file created by init-packaging. The version of the package is extracted from the newest entry in the file debian/changelog.<br />
<br />
Debian packages can also be generated manually either from the temporary directory left behind by dist, or even directly from the source tree. The second option pollutes the source tree with generated files, so it is not recommended, although the .gitignore file created by init-packaging can handle these generated files.<br />
<br />
$ build-appsuite dist<br />
$ ls tmp/packaging/<br />
example-app-0.0.1 example-app_0.0.1-1.dsc<br />
example-app_0.0.1-1.debian.tar.bz2 example-app_0.0.1.orig.tar.bz2<br />
$ cd tmp/packaging/example-app-0.0.1/<br />
$ dpkg-buildpackage -b<br />
<br />
== Reference ==<br />
<br />
=== Variables ===<br />
<br />
==== BASEDIR ====<br />
The top directory of the build system.<br />
<br />
<b>Used by:</b> all tasks.<br />
<br />
<b>Default:</b> installation directory of the build system<br />
<br />
Required to build external apps, since in this case, the build<br />
system is not installed in the current directory. This variable is<br />
automatically set as an environment variable by the build system<br />
executable based on <code>$OX_APPSUITE_DEV</code>.<br />
<br />
==== branch ====<br />
The Subversion branch of the CLDR to checkout.<br />
<br />
<b>Used by:</b> <code>update-i18n</code>.<br />
<br />
==== builddir ====<br />
The target directory for generated files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>, <code>docs</code>,<br />
<code>jakedeps</code>.<br />
<br />
Default: <code>build</code><br />
<br />
==== copyright ====<br />
The copyright line to be included in packaging metadata.<br />
<br />
<b>Used by:</b> <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
<b>Example:</b> <code>2012 Open-Xchange, Inc</code><br />
<br />
==== coreDir ====<br />
Location of OX App Suite UI files.<br />
<br />
<b>Used by:</b> <code>[[#app|app]]</code>, <code>[[#default|default]]</code>.<br />
<br />
<b>Default:</b> same as <code>[[#builddir|builddir]]</code><br />
<br />
Some tasks depend on installed files from the OX App Suite. When building external apps, <code>[[#coreDir|coreDir]]</code> specified the directory which contains these files.<br />
<br />
Currently, this parameter is used to compile <code>.less</code> files for every installed theme. This can be disabled by setting <code>[[#skipLess|skipLess]]</code>.<br />
<br />
==== debug ====<br />
Enables a debug build.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
To simplify debugging of OX App Suite, compression of source code<br />
can be disabled by specifying <code>on</code>, <code>yes</code>,<br />
<code>true</code> or <code>1</code>.<br />
<br />
==== description ====<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
The description of the app to be included in packaging metadata.<br />
<br />
==== destDir ====<br />
Output directory for source archives created by<br />
the <code>dist</code> task.<br />
<br />
<b>Used by:</b> <code>clean</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> <code>tmp/packaging</code><br />
<br />
==== disableStrictMode ====<br />
Removes all <code>"use strict"</code> directives from processed<br />
JavaScript code.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
Some debugging tools which use code instrumentation have problems<br />
when the debugged code uses strict mode. This setting enables code<br />
processing even whe using <code>debug</code> mode, so line numbers<br />
will not match the original source code.<br />
<br />
==== forceDeb ====<br />
Whether an error during the generation of Debian source packages is an error.<br />
<br />
<b>Used by:</b> <code>dist</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This is useful when Debian packages are generated automatically, and a failure of <code>dpkg-source</code> is also a failure of the entire build. By default it merely produces a warning.<br />
<br />
==== from ====<br />
The root of the printed dependency tree between Jake tasks.<br />
<br />
<b>Used by:</b> <code>jakedeps</code>.<br />
<br />
==== helpDir ====<br />
The location of online help files.<br />
<br />
<b>Used by:</b> <code>clean</code>, <code>default</code>,<br />
<code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
If the value contains the string <code>@lang@</code>, it will be<br />
replaced by the lowercase language code (e.g. <code>en-us</code>) to<br />
allow per-language directories.<br />
<br />
==== l10nDir ====<br />
The location of compiled l10n files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
If the value contains the string <code>@lang@</code>, it will be<br />
replaced by the lowercase language code (e.g. <code>en-us</code>) to<br />
allow per-language directories.<br />
<br />
==== license ====<br />
File name of the full text of the distribution license.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Default:</b> based on <code>licenseName</code>.<br />
<br />
==== licenseName ====<br />
Name of the distribution license to be included in packaging<br />
metadata.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Default:</b> <code>CC-BY-NC-SA-3.0</code><br />
<br />
==== manifestDir ====<br />
The location of the combined manifest file.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
==== maintainer ====<br />
Name and email address of the package maintainer.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Format:</b> <code><var>Name</var> &lt;<var>email</var>&gt;</code><br />
<br />
==== package ====<br />
The name of the package for the built app.<br />
<br />
<b>Used by:</b> all tasks.<br />
<br />
<b>Default:</b> the package name in the first line of<br />
<code>debian/changelog</code><br />
<br />
Since the name of the manifest file contains the package name and it<br />
is required to determine build dependencies, the package name must<br />
be always known. This means either <code>debian/changelog</code><br />
must exist and contain at least one entry, or the parameter must be<br />
explicitly specified.<br />
<br />
==== reverse ====<br />
Reverses the direction of printed dependencies.<br />
<br />
<b>Used by:</b> <code>deps</code>.<br />
<br />
When specified, the <code>deps</code> task prints modules which<br />
depend on the specified modules, instead of modules on which<br />
the specified module depends.<br />
<br />
==== revision ====<br />
Revision number of the package for the app.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>,<br />
<code>dist</code>.<br />
<br />
<b>Default:</b> <code>1</code><br />
<br />
The revision number must increase with each rebuild of the same<br />
version to enable the creation of unique version strings. These are<br />
required in package names and to control content caching in clients.<br />
<br />
==== root ====<br />
Specifies for which module to print the dependencies.<br />
<br />
<b>Used by:</b> <code>deps</code>.<br />
<br />
<b>Default:</b> print all roots<br />
<br />
If specified, only the dependencies of the specified module are<br />
printed. Otherwise, the dependencies of all modules are printed.<br />
<br />
==== skipDeb ====<br />
Whether to skip the generation of Debian source packages.<br />
<br />
<b>Used by:</b> <code>dist</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This is useful when Debian packages are not required and/or<br />
<code>dpkg-source</code> is not available, e.g. on RPM based<br />
systems.<br />
<br />
Even when using this flag, at least the file<br />
<code>debian/changelog</code> is still required, because it is used<br />
to store the package name and version. <br />
<br />
==== skipLess ====<br />
Whether to skip the preprocessing of LessCSS files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This flag skips the generation of CSS files in<br />
the <code>apps/themes/*/less</code> directories of all themes.<br />
It is used by the packaging system, where the LessCSS files are<br />
precompiled after installation on the target system instead of<br />
while building the package.<br />
<br />
==== tag ====<br />
The Subversion tag of the CLDR to checkout.<br />
<br />
<b>Used by:</b> <code>update-i18n</code>.<br />
<br />
==== to ====<br />
The leaf task in the printed dependency path between Jake tasks.<br />
<br />
<b>Used by:</b> <code>jakedeps</code>.<br />
<br />
When specified, only a single path from the root to the leaf task is<br />
printed (in reverse order).<br />
<br />
==== version ====<br />
Version number of the app.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>,<br />
<code>dist</code>, <code>init-packaging</code>.<br />
<br />
<b>Default:</b> <code>0.0.1</code><br />
<br />
The version should consist of a major, minor and patch version<br />
separated by dots.<br />
<br />
=== Tasks ===<br />
<p><br />
An up-to-date list of tasks can be printed using the -T command line option.<br />
<br />
==== app ====<br />
Builds an external app.<br />
<br />
<b>Variables:</b> <code>[[#BASEDIR|BASEDIR]]</code>, <code>[[#builddir|builddir]]</code>, <code>[[#coreDir|coreDir]]</code>, <code>[[#debug|debug]]</code>, <code>[[#disableStrictMode|disableStrictMode]]</code>, <code>[[#l10nDir|l10nDir]]</code>, <code>[[#manifestDir|manifestDir]]</code>, <code>[[#package|package]]</code>, <code>[[#revision|revision]]</code>, <code>[[#version|version]]</code>.<br />
<br />
This is the main task used to build external apps.<br />
<br />
It works without explicitly specifying any variables, but during<br />
development, <code>[[#builddir|builddir]]</code> is usually pointed to<br />
the directory of a locally installed OX App Suite UI to avoid<br />
additional copying steps. For debugging, <code>[[#debug|debug]]</code> is also<br />
often used. Note that <code>[[#clean|clean]]</code> must be called when<br />
changing any of the variables.<br />
<br />
==== clean ====<br />
Removes all generated files.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>destDir</code>, <code>l10nDir</code>,<br />
<code>manifestDir</code>, <code>package</code>.<br />
<br />
This task should be executed before a normal build using<br />
<code>app</code> or <code>default</code> after changing any build<br />
variables and after a switch between Git branches. Normal<br />
incremental builds can miss changed files if a branch switch<br />
replaces files by older versions.<br />
<br />
==== default ====<br />
Builds OX App Suite.<br />
<br />
<b>Variables:</b> <code>[[#BASEDIR|BASEDIR]]</code>, <code>[[#builddir|builddir]]</code>, <code>[[#debug|debug]]</code>, <code>[[#disableStrictMode|disableStrictMode]]</code>, <code>[[#l10nDir|l10nDir]]</code>, <code>[[#manifestDir|manifestDir]]</code>, <code>[[#package|package]]</code>, <code>[[#revision|revision]]</code>, <code>[[#version|version]]</code>.<br />
<br />
This is the main task to build OX App Suite. Since it is the default<br />
Jake task, it does not need to be specified explicitly on<br />
the command line when it is the only task.<br />
<br />
It works without explicitly specifying any variables, but during<br />
development, <code>[[#builddir|builddir]]</code> is usually pointed to<br />
a directory which is accessible to a local web server. For<br />
debugging, <code>[[#debug|debug]]</code> is also often used. Note that<br />
<code>[[#clean|clean]]</code> must be called when changing any of<br />
the variables.<br />
<br />
==== deps ====<br />
Prints module dependencies.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>package</code>,<br />
<code>reverse</code>, <code>root</code>.<br />
<br />
This task visualizes dependencies of RequireJS modules. It prints<br />
a tree of dependencies to <code>stdout</code>.<br />
<br />
If <code>root</code> is specified, then only the dependencies of<br />
that module are printed. Otherwise, the dependencies of all modules,<br />
on which no other module depends are printed in sequence. <br />
<br />
If <code>reverse</code> is specified, then this task prints<br />
dependants instead of dependencies, i.e. modules which depend on<br />
the specified module instead of modules on which the specified<br />
module depends.<br />
<br />
==== dist ====<br />
Creates source packages.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>destDir</code>, <code>forceDeb</code>, <code>l10nDir</code>,<br />
<code>manifestDir</code>, <code>package</code>,<br />
<code>revision</code>, <code>skipDeb</code>,<br />
<code>version</code>.<br />
<br />
This task cleans the source tree by calling <code>clean</code> and<br />
packs the source into an archive which can be used to create Debian<br />
and RPM packages. The necessary Debian metadata is created alongside<br />
the source archive. All files necessary for Debian packaging are<br />
placed in the directory specified by <code>destDir</code>.<br />
The generated <code>.orig.tar.bz2</code> archive can also be used<br />
together with the <code>.spec</code> file to generate RPM packages.<br />
<br />
Unless the variable <code>skipDeb</code> is set to<br />
<code>true</code>, the program <code>dpkg-source</code> is required<br />
by this task. It is used to generate Debian-specific packaging<br />
metadata.<br />
<br />
==== init-packaging ====<br />
Initializes packaging information for a new app.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>copyright</code>,<br />
<code>description</code>, <code>license</code>,<br />
<code>licenseName</code>, <code>maintainer</code>,<br />
<code>package</code>, <code>version</code>.<br />
<br />
This task is the first task called when starting with<br />
the development of a new external app. The directory from which it<br />
is called must already contain at least the <code>apps</code><br />
subdirectory. This is also the only task where<br />
the <code>package</code> variable must be specified explicitly.<br />
Afterwards, the package name is looked up automatically in the file<br />
<code>debian/changelog</code>, which is created by this task.<br />
<br />
The variables <code>version</code>, <code>maintainer</code>,<br />
<code>copyright</code>, <code>licenseName</code>,<br />
<code>license</code>, and <code>description</code> are required to<br />
fill out all necessary packaging metadata. Any of these variables<br />
which are not specified explicitly will cause an interactive prompt.<br />
This avoids the need to remember the list of variables before one<br />
can start developing an app.<br />
<br />
==== jakedeps ====<br />
Shows the dependency chain between two Jake tasks.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>from</code>,<br />
<code>package</code>, <code>to</code>.<br />
<br />
This task visualized dependencies between Jake tasks. The variable<br />
<code>from</code> specifies the root of a dependency tree, with all<br />
dependencies of <code>from</code> as inner and leaf nodes. If<br />
<code>to</code> is not specified, then that entire tree is printed.<br />
<br />
If <code>to</code> is also specified, then only the first found<br />
dependency path from <code>from</code> to <code>to</code> is<br />
.printed with <code>to</code> at the top and <code>from</code> at<br />
the bottom.<br />
<br />
==== merge ====<br />
Updates all <code>.po</code> files with the generated<br />
<code>ox.pot</code>.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>debug</code>, <code>package</code>, <code>revision</code>,<br />
<code>version</code>.<br />
<br />
This task updates the list of extracted i18n strings in<br />
<code>ox.pot</code> and calls the GNU Gettext tool<br />
<code>msgmerge</code> for every language in <code>i18n/*.po</code>.<br />
<br />
<code>i18n/en_US.po</code> is not updated by this task because the original strings are already in the <code>en_US</code> locale. It would only end up with every translation mapping every string to itself. The only entries in that file should be for cases when the <code>en_US</code> text is not a suitable fallback for missing translations. The original string in such a case would be something internationally appropriate (e.&nbsp;g. a date written as "2013-01-01" instead of "01/01/2013") and <code>i18n/en_US.po</code> would contain a translation.<br />
<br />
==== update-i18n ====<br />
Updates CLDR data in the source tree.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>branch</code>,<br />
<code>package</code>, <code>tag</code>.<br />
<br />
This task downloads data from the Unicode CLDR and updates date<br />
translations for all languages in <code>i18n/*.po</code>.<br />
<br />
The exact version of CLDR data is specified as Suubversion tag or<br />
branch by the variables <code>tag</code> and <code>branch</code>,<br />
respectively. If neither is specified, then the Subversion trunk is<br />
checked out. If both are specified, <code>tag</code> is used.<br />
<br />
==== verify-doc ====<br />
Generates a documentation skeleton for extension points.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>package</code>.<br />
<br />
This task is still under development. Currently, it creates a list of all extension points, which have a constant name in the source code. In the future it is supposed to update an existing list instead of overwriting it, and to handle non-constant extension point names.<br />
<br />
The list of extension points is stored as an HTML snippet in <code>doc/extensionpoints.html</code>.<br />
<br />
<br />
[[Category:AppSuite]]<br />
[[Category:UI]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Appserver&diff=16255AppSuite:Appserver2013-10-28T10:06:14Z<p>Mark.schmidts: /* Installation */</p>
<hr />
<div>{{Stability-unstable}}<br />
<br />
<div class="title">Appserver</div><br />
<br />
The <code>appserver</code> tool is used to develop and test the OX App Suite UI and its plugins with a remote backend. <code>appserver</code> acts as a reverse HTTP proxy for an existing OX App Suite installation and injects the tested JavaScript code in its replies.<br />
<br />
== Installation ==<br />
<br />
The core of <code>appserver</code> is a Node.js script, so if your OS does not provide a <code>nodejs</code> package, you will have to install it manually, either as a [https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager 3rd party package] or directly from [http://nodejs.org/ nodejs.org].<br />
<br />
Read more about how to install the tools for developing for OX App Suite in the [[AppSuite:GettingStarted#Installing | getting started article]].<br />
<br />
== Standalone use ==<br />
<br />
In the simplest case of developing an app or a plugin, all that is needed is an existing OX App Suite installation. Point <code>appserver</code> to the URL of OX App Suite and to the build directory of your app. Assuming you are in the top directory of your app's source code and <code>[[AppSuite:UI build system#builddir|$builddir]]</code> is not set:<br />
<br />
appserver [[#server|--server]]=<nowiki>https://www.ox.io/appsuite/</nowiki> build<br />
<br />
If there are no errors, you can point your browser to http://localhost:8337/appsuite/ to test a version of OX App Suite which includes your app. Do not forget the trailing slash in the URL. Otherwise, the server sends a redirect from <code>/appsuite</code> to <code>/appsuite/</code> and includes its own absolute URL in the redirect.<br />
<br />
You do not need to restart anything after re-building the app, a refresh of the browser page should be enough. If your code doesn’t show up after a refresh, our file cache mighgt not be up-to-date. Until this is fixed in appserver, you can append <code>&debug-js=true</code> to your URL to disable the file cache.<br />
<br />
== Use with Apache ==<br />
<br />
For more complex cases involving testing your own build of the UI, or apps which include static resources (e.&nbsp;g. images), a local web server is required to serve static resources. The following examples use the Apache HTTP Server, but any web server which can act as a reverse HTTP proxy should work (assuming the configuration and <code>.htaccess</code> files are adapted, of course).<br />
<br />
First, make your app visible in Apache. The simplest way is to symlink the <code>[[AppSuite:UI build system#builddir|$builddir]]</code> inside the document root. Assuming the app is in <code>/home/user/myapp</code> and the web server's document root is <code>/var/www</code>:<br />
<br />
sudo ln -s /home/user/myapp/build /var/www/myapp<br />
<br />
In case Apache ignores the symlink, ensure that its configuration directive <code><Directory /var/www/></code> contains "<code>Options FollowSymlinks</code>" or something to that effect.<br />
<br />
Second, configure Apache to request from <code>appserver</code> anything that it can't find locally. This configuration requires at least <code>mod_rewrite</code>, <code>mod_proxy</code> and <code>mod_proxy_http</code> to be enabled. Editing a file like <code>/etc/apache2/sites-enabled/000-default</code> containing the proxy configuration, add the following inside an eventual <code><VirtualHost></code> directive, but outside of any <code><Directory></code> directives:<br />
<br />
RewriteEngine On<br />
ProxyPreserveHost On<br />
<br />
ProxyPassMatch ^/((appsuite|ajax|infostore|publications\<br />
|realtime|servlet|usm-json|webservices)(/.*)?)$ \<br />
<nowiki>http://localhost:8337/$1</nowiki><br />
<br />
RewriteCond %{DOCUMENT_ROOT}/myapp/$2 -f<br />
RewriteRule ^/appsuite/(v=[^,/]+/)?(.*)$ /myapp/$2 [PT]<br />
<br />
Take care configuring apache configuration, proxy definitions might take place in several files. For example <code>/etc/apache2/conf.d/proxy_http.conf</code> does also often contain http proxy configuration, which may differ from the definitions in the file edited above.<br />
<br />
If you want to test multiple apps, use a different directory for each, and repeat the last two lines for each app, substituting the proper values for "<code>myapp</code>". If you are using aliases instead of symlinks then replace <code>%{DOCUMENT_ROOT}</code> with the actual file system path from the <code>Alias</code> directive.<br />
<br />
Now, restart Apache and start <code>appserver</code> adding the path to your simlinked build-path of the app as an parameter.<br />
<br />
sudo apachectl restart<br />
appserver [[#server|--server]]=<nowiki>https://www.ox.io/appsuite/</nowiki> /var/www/myapp<br />
<br />
If there are no errors, you can point your browser to http://localhost/appsuite/ to test a version of OX App Suite which includes your app. You do not need to restart anything after re-building the app, a refresh of the browser page should be enough.<br />
<br />
=== Custom UI builds ===<br />
<br />
To test your own build of the core UI, use <code>/var/www/appsuite</code> as directory, but don't add a <code>RewriteRule</code> for it. Instead, replace "<code>appsuite</code>" with "<code>appsuite/api</code>" in the <code>ProxyPassMatch</code> directive and add a <code><Directory></code> directive like for any other OX App Suite installation:<br />
<br />
<Directory /var/www/appsuite/><br />
Options FollowSymlinks<br />
AllowOverride Indexes FileInfo<br />
</Directory><br />
<br />
== Reference ==<br />
<br />
<code>appserver</code> is a reverse HTTP proxy. It accepts HTTP requests and forwards most of them to another HTTP server. There are currently two exceptions:<br />
* <code>api/apps/load</code> is served from a list of local paths. Only files which could not be found are fetched from the remote HTTP server. This allows to inject the code of a tested app without installing it on the remote server. The list of paths is specified as non-option parameters on the command line. Each path should normally have at least the subdirectories <code>apps</code> and <code>manifests</code>. Each injected file is looked up in the <code>apps</code> subdirectory of each path, in the order in which they appear on the command line, and the first found file is used. If a file is not found in any path, and the <code>[[#server|--server]]</code> option is specified, the file is downloaded from the server.<br />
* <code>api/apps/manifests?action=config</code> is extended by local manifests. This is necessary to enable the tested app in the UI. If no <code>[[#manifests|--manifests]]</code> options are specified, then all files from the <code>manifests</code> subdirectory of each path are combined and added to the manifests from the remote server. Each manifest entry overrides any entries with the same <code>path</code> attribute. Similar to the priority for files, manifest entries from earlier paths override entries from later paths, and local entries override remote entries.<br />
<br />
=== help ===<br />
<br />
Displays a short summary of available options:<br />
<br />
Usage: appserver [OPTION]... [PATH]...<br />
<br />
-h, --help print this help message and exit<br />
-m PATH, --manifests=PATH add manifests from the specified path (default:<br />
the "manifests" subdirectory of every file path)<br />
--path=PATH absolute path of the UI (default: /appsuite)<br />
-p PORT, --port=PORT listen on PORT (default: 8337)<br />
-s URL, --server=URL use an existing server as fallback<br />
-v TYPE, --verbose=TYPE print more information depending on TYPE:<br />
local: local files, remote: remote files,<br />
proxy: forwarded URLs, all: shortcut for all three<br />
-z PATH, --zoneinfo=PATH use timezone data from the specified path<br />
(default: /usr/share/zoneinfo/)<br />
<br />
Files are searched in each PATH in order and requested from the server if not<br />
found. If no paths are specified, the default is /var/www/appsuite/.<br />
<br />
=== manifests ===<br />
<br />
By default, the manifests of an app are collected and put into <code>[[AppSuite:UI build system#builddir|$builddir]]/manifests</code>. Therefore, by default, <code>appserver</code> collects manifests from the <code>manifests</code> subdirectoriy of each file path. Since the destination directory for manifests can be changed by setting <code>[[AppSuite:UI build system#manifestDir|$manifestDir]]</code>, the manifest directories can also be changed in <code>appserver</code> by specifying each directory with a separate <code>--manifests</code> option.<br />
<br />
If at least one <code>--manifests</code> option is specified, the default file paths are not used for manifests at all.<br />
<br />
=== path ===<br />
<br />
By default, URLs belonging to the OX App Suite (i.&nbsp;e. starting with <code>/appsuite/</code>) get mapped to the URL of the <code>[[#server|--server]]</code> parameter, while all other paths get mapped to identical paths on that server to allow services like <code>/publications</code> to work.<br />
<br />
This parameter changes the path of the local OX App Suite URL e.&nbsp;g. to allow testing multiple UIs with the same server.<br />
<br />
=== port ===<br />
<br />
Specifies the port to listen on. The default is 8337. This option might be useful to run multiple instances of <code>appserver</code> at once or when port 8337 is already in use.<br />
<br />
=== server ===<br />
<br />
Specifies the URL of an existing OX App Suite installation. The URL must start with <code>http://</code> or <code>https://</code>. To make forwarding of an HTTPS URL over HTTP possible, <code>appserver</code> removes the <code>Secure</code> attribute from all cookies set by the server.<br />
<br />
This option is required for manifest injection to work, since the intercepted request contains more data than just the manifests.<br />
<br />
=== verbose ===<br />
<br />
Enables verbose output. During normal operation, <code>appserver</code> only writes errors to its console. By specifying this option one or more times, additional output can be enabled, depending on the value of each option:<br />
<br />
; local : The name of every read local file is written to standard output.<br />
; remote : The URL of every request for missing local files is written to standard output.<br />
; proxy : The URL of every client request which is forwarded as-is is written to standard output.<br />
; all : This is just a shortcut for <code>-v local -v remote -v proxy</code>.<br />
<br />
Output lines belonging to the same client request are grouped together and separated from the next request by an empty line.<br />
<br />
=== zoneinfo ===<br />
<br />
Specifies the path to the zoneinfo database. On POSIX systems, the default of <code>/usr/share/zoneinfo/</code> should always work. Even on systems without the database everything should just work if <code>[[#server|--server]]</code> is specified, since any missing files will be fetched from the remote server. This option may still be useful when debugging time zone problems caused by different versions of the zoneinfo database.<br />
<br />
[[Category:AppSuite]]<br />
[[Category:UI]]<br />
[[Category:Developer]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Appserver&diff=16254AppSuite:Appserver2013-10-28T10:05:27Z<p>Mark.schmidts: /* Installation */</p>
<hr />
<div>{{Stability-unstable}}<br />
<br />
<div class="title">Appserver</div><br />
<br />
The <code>appserver</code> tool is used to develop and test the OX App Suite UI and its plugins with a remote backend. <code>appserver</code> acts as a reverse HTTP proxy for an existing OX App Suite installation and injects the tested JavaScript code in its replies.<br />
<br />
== Installation ==<br />
<br />
The core of <code>appserver</code> is a Node.js script, so if your OS does not provide a <code>nodejs</code> package, you will have to install it manually, either as a [https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager 3rd party package] or directly from [http://nodejs.org/ nodejs.org].<br />
<br />
Read more about how to install the tools for developing for OX App Suite in the [[AppSuite:GettingStarted#Installing | Getting Started article]].<br />
<br />
== Standalone use ==<br />
<br />
In the simplest case of developing an app or a plugin, all that is needed is an existing OX App Suite installation. Point <code>appserver</code> to the URL of OX App Suite and to the build directory of your app. Assuming you are in the top directory of your app's source code and <code>[[AppSuite:UI build system#builddir|$builddir]]</code> is not set:<br />
<br />
appserver [[#server|--server]]=<nowiki>https://www.ox.io/appsuite/</nowiki> build<br />
<br />
If there are no errors, you can point your browser to http://localhost:8337/appsuite/ to test a version of OX App Suite which includes your app. Do not forget the trailing slash in the URL. Otherwise, the server sends a redirect from <code>/appsuite</code> to <code>/appsuite/</code> and includes its own absolute URL in the redirect.<br />
<br />
You do not need to restart anything after re-building the app, a refresh of the browser page should be enough. If your code doesn’t show up after a refresh, our file cache mighgt not be up-to-date. Until this is fixed in appserver, you can append <code>&debug-js=true</code> to your URL to disable the file cache.<br />
<br />
== Use with Apache ==<br />
<br />
For more complex cases involving testing your own build of the UI, or apps which include static resources (e.&nbsp;g. images), a local web server is required to serve static resources. The following examples use the Apache HTTP Server, but any web server which can act as a reverse HTTP proxy should work (assuming the configuration and <code>.htaccess</code> files are adapted, of course).<br />
<br />
First, make your app visible in Apache. The simplest way is to symlink the <code>[[AppSuite:UI build system#builddir|$builddir]]</code> inside the document root. Assuming the app is in <code>/home/user/myapp</code> and the web server's document root is <code>/var/www</code>:<br />
<br />
sudo ln -s /home/user/myapp/build /var/www/myapp<br />
<br />
In case Apache ignores the symlink, ensure that its configuration directive <code><Directory /var/www/></code> contains "<code>Options FollowSymlinks</code>" or something to that effect.<br />
<br />
Second, configure Apache to request from <code>appserver</code> anything that it can't find locally. This configuration requires at least <code>mod_rewrite</code>, <code>mod_proxy</code> and <code>mod_proxy_http</code> to be enabled. Editing a file like <code>/etc/apache2/sites-enabled/000-default</code> containing the proxy configuration, add the following inside an eventual <code><VirtualHost></code> directive, but outside of any <code><Directory></code> directives:<br />
<br />
RewriteEngine On<br />
ProxyPreserveHost On<br />
<br />
ProxyPassMatch ^/((appsuite|ajax|infostore|publications\<br />
|realtime|servlet|usm-json|webservices)(/.*)?)$ \<br />
<nowiki>http://localhost:8337/$1</nowiki><br />
<br />
RewriteCond %{DOCUMENT_ROOT}/myapp/$2 -f<br />
RewriteRule ^/appsuite/(v=[^,/]+/)?(.*)$ /myapp/$2 [PT]<br />
<br />
Take care configuring apache configuration, proxy definitions might take place in several files. For example <code>/etc/apache2/conf.d/proxy_http.conf</code> does also often contain http proxy configuration, which may differ from the definitions in the file edited above.<br />
<br />
If you want to test multiple apps, use a different directory for each, and repeat the last two lines for each app, substituting the proper values for "<code>myapp</code>". If you are using aliases instead of symlinks then replace <code>%{DOCUMENT_ROOT}</code> with the actual file system path from the <code>Alias</code> directive.<br />
<br />
Now, restart Apache and start <code>appserver</code> adding the path to your simlinked build-path of the app as an parameter.<br />
<br />
sudo apachectl restart<br />
appserver [[#server|--server]]=<nowiki>https://www.ox.io/appsuite/</nowiki> /var/www/myapp<br />
<br />
If there are no errors, you can point your browser to http://localhost/appsuite/ to test a version of OX App Suite which includes your app. You do not need to restart anything after re-building the app, a refresh of the browser page should be enough.<br />
<br />
=== Custom UI builds ===<br />
<br />
To test your own build of the core UI, use <code>/var/www/appsuite</code> as directory, but don't add a <code>RewriteRule</code> for it. Instead, replace "<code>appsuite</code>" with "<code>appsuite/api</code>" in the <code>ProxyPassMatch</code> directive and add a <code><Directory></code> directive like for any other OX App Suite installation:<br />
<br />
<Directory /var/www/appsuite/><br />
Options FollowSymlinks<br />
AllowOverride Indexes FileInfo<br />
</Directory><br />
<br />
== Reference ==<br />
<br />
<code>appserver</code> is a reverse HTTP proxy. It accepts HTTP requests and forwards most of them to another HTTP server. There are currently two exceptions:<br />
* <code>api/apps/load</code> is served from a list of local paths. Only files which could not be found are fetched from the remote HTTP server. This allows to inject the code of a tested app without installing it on the remote server. The list of paths is specified as non-option parameters on the command line. Each path should normally have at least the subdirectories <code>apps</code> and <code>manifests</code>. Each injected file is looked up in the <code>apps</code> subdirectory of each path, in the order in which they appear on the command line, and the first found file is used. If a file is not found in any path, and the <code>[[#server|--server]]</code> option is specified, the file is downloaded from the server.<br />
* <code>api/apps/manifests?action=config</code> is extended by local manifests. This is necessary to enable the tested app in the UI. If no <code>[[#manifests|--manifests]]</code> options are specified, then all files from the <code>manifests</code> subdirectory of each path are combined and added to the manifests from the remote server. Each manifest entry overrides any entries with the same <code>path</code> attribute. Similar to the priority for files, manifest entries from earlier paths override entries from later paths, and local entries override remote entries.<br />
<br />
=== help ===<br />
<br />
Displays a short summary of available options:<br />
<br />
Usage: appserver [OPTION]... [PATH]...<br />
<br />
-h, --help print this help message and exit<br />
-m PATH, --manifests=PATH add manifests from the specified path (default:<br />
the "manifests" subdirectory of every file path)<br />
--path=PATH absolute path of the UI (default: /appsuite)<br />
-p PORT, --port=PORT listen on PORT (default: 8337)<br />
-s URL, --server=URL use an existing server as fallback<br />
-v TYPE, --verbose=TYPE print more information depending on TYPE:<br />
local: local files, remote: remote files,<br />
proxy: forwarded URLs, all: shortcut for all three<br />
-z PATH, --zoneinfo=PATH use timezone data from the specified path<br />
(default: /usr/share/zoneinfo/)<br />
<br />
Files are searched in each PATH in order and requested from the server if not<br />
found. If no paths are specified, the default is /var/www/appsuite/.<br />
<br />
=== manifests ===<br />
<br />
By default, the manifests of an app are collected and put into <code>[[AppSuite:UI build system#builddir|$builddir]]/manifests</code>. Therefore, by default, <code>appserver</code> collects manifests from the <code>manifests</code> subdirectoriy of each file path. Since the destination directory for manifests can be changed by setting <code>[[AppSuite:UI build system#manifestDir|$manifestDir]]</code>, the manifest directories can also be changed in <code>appserver</code> by specifying each directory with a separate <code>--manifests</code> option.<br />
<br />
If at least one <code>--manifests</code> option is specified, the default file paths are not used for manifests at all.<br />
<br />
=== path ===<br />
<br />
By default, URLs belonging to the OX App Suite (i.&nbsp;e. starting with <code>/appsuite/</code>) get mapped to the URL of the <code>[[#server|--server]]</code> parameter, while all other paths get mapped to identical paths on that server to allow services like <code>/publications</code> to work.<br />
<br />
This parameter changes the path of the local OX App Suite URL e.&nbsp;g. to allow testing multiple UIs with the same server.<br />
<br />
=== port ===<br />
<br />
Specifies the port to listen on. The default is 8337. This option might be useful to run multiple instances of <code>appserver</code> at once or when port 8337 is already in use.<br />
<br />
=== server ===<br />
<br />
Specifies the URL of an existing OX App Suite installation. The URL must start with <code>http://</code> or <code>https://</code>. To make forwarding of an HTTPS URL over HTTP possible, <code>appserver</code> removes the <code>Secure</code> attribute from all cookies set by the server.<br />
<br />
This option is required for manifest injection to work, since the intercepted request contains more data than just the manifests.<br />
<br />
=== verbose ===<br />
<br />
Enables verbose output. During normal operation, <code>appserver</code> only writes errors to its console. By specifying this option one or more times, additional output can be enabled, depending on the value of each option:<br />
<br />
; local : The name of every read local file is written to standard output.<br />
; remote : The URL of every request for missing local files is written to standard output.<br />
; proxy : The URL of every client request which is forwarded as-is is written to standard output.<br />
; all : This is just a shortcut for <code>-v local -v remote -v proxy</code>.<br />
<br />
Output lines belonging to the same client request are grouped together and separated from the next request by an empty line.<br />
<br />
=== zoneinfo ===<br />
<br />
Specifies the path to the zoneinfo database. On POSIX systems, the default of <code>/usr/share/zoneinfo/</code> should always work. Even on systems without the database everything should just work if <code>[[#server|--server]]</code> is specified, since any missing files will be fetched from the remote server. This option may still be useful when debugging time zone problems caused by different versions of the zoneinfo database.<br />
<br />
[[Category:AppSuite]]<br />
[[Category:UI]]<br />
[[Category:Developer]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Appserver&diff=16253AppSuite:Appserver2013-10-28T10:05:15Z<p>Mark.schmidts: /* Installation */</p>
<hr />
<div>{{Stability-unstable}}<br />
<br />
<div class="title">Appserver</div><br />
<br />
The <code>appserver</code> tool is used to develop and test the OX App Suite UI and its plugins with a remote backend. <code>appserver</code> acts as a reverse HTTP proxy for an existing OX App Suite installation and injects the tested JavaScript code in its replies.<br />
<br />
== Installation ==<br />
<br />
The core of <code>appserver</code> is a Node.js script, so if your OS does not provide a <code>nodejs</code> package, you will have to install it manually, either as a [https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager 3rd party package] or directly from [http://nodejs.org/ nodejs.org].<br />
<br />
Read more about how to install the tools for developing for OX App Suite in the [[AppSuite:GettingStarted#Installing | Getting Started article ]].<br />
<br />
== Standalone use ==<br />
<br />
In the simplest case of developing an app or a plugin, all that is needed is an existing OX App Suite installation. Point <code>appserver</code> to the URL of OX App Suite and to the build directory of your app. Assuming you are in the top directory of your app's source code and <code>[[AppSuite:UI build system#builddir|$builddir]]</code> is not set:<br />
<br />
appserver [[#server|--server]]=<nowiki>https://www.ox.io/appsuite/</nowiki> build<br />
<br />
If there are no errors, you can point your browser to http://localhost:8337/appsuite/ to test a version of OX App Suite which includes your app. Do not forget the trailing slash in the URL. Otherwise, the server sends a redirect from <code>/appsuite</code> to <code>/appsuite/</code> and includes its own absolute URL in the redirect.<br />
<br />
You do not need to restart anything after re-building the app, a refresh of the browser page should be enough. If your code doesn’t show up after a refresh, our file cache mighgt not be up-to-date. Until this is fixed in appserver, you can append <code>&debug-js=true</code> to your URL to disable the file cache.<br />
<br />
== Use with Apache ==<br />
<br />
For more complex cases involving testing your own build of the UI, or apps which include static resources (e.&nbsp;g. images), a local web server is required to serve static resources. The following examples use the Apache HTTP Server, but any web server which can act as a reverse HTTP proxy should work (assuming the configuration and <code>.htaccess</code> files are adapted, of course).<br />
<br />
First, make your app visible in Apache. The simplest way is to symlink the <code>[[AppSuite:UI build system#builddir|$builddir]]</code> inside the document root. Assuming the app is in <code>/home/user/myapp</code> and the web server's document root is <code>/var/www</code>:<br />
<br />
sudo ln -s /home/user/myapp/build /var/www/myapp<br />
<br />
In case Apache ignores the symlink, ensure that its configuration directive <code><Directory /var/www/></code> contains "<code>Options FollowSymlinks</code>" or something to that effect.<br />
<br />
Second, configure Apache to request from <code>appserver</code> anything that it can't find locally. This configuration requires at least <code>mod_rewrite</code>, <code>mod_proxy</code> and <code>mod_proxy_http</code> to be enabled. Editing a file like <code>/etc/apache2/sites-enabled/000-default</code> containing the proxy configuration, add the following inside an eventual <code><VirtualHost></code> directive, but outside of any <code><Directory></code> directives:<br />
<br />
RewriteEngine On<br />
ProxyPreserveHost On<br />
<br />
ProxyPassMatch ^/((appsuite|ajax|infostore|publications\<br />
|realtime|servlet|usm-json|webservices)(/.*)?)$ \<br />
<nowiki>http://localhost:8337/$1</nowiki><br />
<br />
RewriteCond %{DOCUMENT_ROOT}/myapp/$2 -f<br />
RewriteRule ^/appsuite/(v=[^,/]+/)?(.*)$ /myapp/$2 [PT]<br />
<br />
Take care configuring apache configuration, proxy definitions might take place in several files. For example <code>/etc/apache2/conf.d/proxy_http.conf</code> does also often contain http proxy configuration, which may differ from the definitions in the file edited above.<br />
<br />
If you want to test multiple apps, use a different directory for each, and repeat the last two lines for each app, substituting the proper values for "<code>myapp</code>". If you are using aliases instead of symlinks then replace <code>%{DOCUMENT_ROOT}</code> with the actual file system path from the <code>Alias</code> directive.<br />
<br />
Now, restart Apache and start <code>appserver</code> adding the path to your simlinked build-path of the app as an parameter.<br />
<br />
sudo apachectl restart<br />
appserver [[#server|--server]]=<nowiki>https://www.ox.io/appsuite/</nowiki> /var/www/myapp<br />
<br />
If there are no errors, you can point your browser to http://localhost/appsuite/ to test a version of OX App Suite which includes your app. You do not need to restart anything after re-building the app, a refresh of the browser page should be enough.<br />
<br />
=== Custom UI builds ===<br />
<br />
To test your own build of the core UI, use <code>/var/www/appsuite</code> as directory, but don't add a <code>RewriteRule</code> for it. Instead, replace "<code>appsuite</code>" with "<code>appsuite/api</code>" in the <code>ProxyPassMatch</code> directive and add a <code><Directory></code> directive like for any other OX App Suite installation:<br />
<br />
<Directory /var/www/appsuite/><br />
Options FollowSymlinks<br />
AllowOverride Indexes FileInfo<br />
</Directory><br />
<br />
== Reference ==<br />
<br />
<code>appserver</code> is a reverse HTTP proxy. It accepts HTTP requests and forwards most of them to another HTTP server. There are currently two exceptions:<br />
* <code>api/apps/load</code> is served from a list of local paths. Only files which could not be found are fetched from the remote HTTP server. This allows to inject the code of a tested app without installing it on the remote server. The list of paths is specified as non-option parameters on the command line. Each path should normally have at least the subdirectories <code>apps</code> and <code>manifests</code>. Each injected file is looked up in the <code>apps</code> subdirectory of each path, in the order in which they appear on the command line, and the first found file is used. If a file is not found in any path, and the <code>[[#server|--server]]</code> option is specified, the file is downloaded from the server.<br />
* <code>api/apps/manifests?action=config</code> is extended by local manifests. This is necessary to enable the tested app in the UI. If no <code>[[#manifests|--manifests]]</code> options are specified, then all files from the <code>manifests</code> subdirectory of each path are combined and added to the manifests from the remote server. Each manifest entry overrides any entries with the same <code>path</code> attribute. Similar to the priority for files, manifest entries from earlier paths override entries from later paths, and local entries override remote entries.<br />
<br />
=== help ===<br />
<br />
Displays a short summary of available options:<br />
<br />
Usage: appserver [OPTION]... [PATH]...<br />
<br />
-h, --help print this help message and exit<br />
-m PATH, --manifests=PATH add manifests from the specified path (default:<br />
the "manifests" subdirectory of every file path)<br />
--path=PATH absolute path of the UI (default: /appsuite)<br />
-p PORT, --port=PORT listen on PORT (default: 8337)<br />
-s URL, --server=URL use an existing server as fallback<br />
-v TYPE, --verbose=TYPE print more information depending on TYPE:<br />
local: local files, remote: remote files,<br />
proxy: forwarded URLs, all: shortcut for all three<br />
-z PATH, --zoneinfo=PATH use timezone data from the specified path<br />
(default: /usr/share/zoneinfo/)<br />
<br />
Files are searched in each PATH in order and requested from the server if not<br />
found. If no paths are specified, the default is /var/www/appsuite/.<br />
<br />
=== manifests ===<br />
<br />
By default, the manifests of an app are collected and put into <code>[[AppSuite:UI build system#builddir|$builddir]]/manifests</code>. Therefore, by default, <code>appserver</code> collects manifests from the <code>manifests</code> subdirectoriy of each file path. Since the destination directory for manifests can be changed by setting <code>[[AppSuite:UI build system#manifestDir|$manifestDir]]</code>, the manifest directories can also be changed in <code>appserver</code> by specifying each directory with a separate <code>--manifests</code> option.<br />
<br />
If at least one <code>--manifests</code> option is specified, the default file paths are not used for manifests at all.<br />
<br />
=== path ===<br />
<br />
By default, URLs belonging to the OX App Suite (i.&nbsp;e. starting with <code>/appsuite/</code>) get mapped to the URL of the <code>[[#server|--server]]</code> parameter, while all other paths get mapped to identical paths on that server to allow services like <code>/publications</code> to work.<br />
<br />
This parameter changes the path of the local OX App Suite URL e.&nbsp;g. to allow testing multiple UIs with the same server.<br />
<br />
=== port ===<br />
<br />
Specifies the port to listen on. The default is 8337. This option might be useful to run multiple instances of <code>appserver</code> at once or when port 8337 is already in use.<br />
<br />
=== server ===<br />
<br />
Specifies the URL of an existing OX App Suite installation. The URL must start with <code>http://</code> or <code>https://</code>. To make forwarding of an HTTPS URL over HTTP possible, <code>appserver</code> removes the <code>Secure</code> attribute from all cookies set by the server.<br />
<br />
This option is required for manifest injection to work, since the intercepted request contains more data than just the manifests.<br />
<br />
=== verbose ===<br />
<br />
Enables verbose output. During normal operation, <code>appserver</code> only writes errors to its console. By specifying this option one or more times, additional output can be enabled, depending on the value of each option:<br />
<br />
; local : The name of every read local file is written to standard output.<br />
; remote : The URL of every request for missing local files is written to standard output.<br />
; proxy : The URL of every client request which is forwarded as-is is written to standard output.<br />
; all : This is just a shortcut for <code>-v local -v remote -v proxy</code>.<br />
<br />
Output lines belonging to the same client request are grouped together and separated from the next request by an empty line.<br />
<br />
=== zoneinfo ===<br />
<br />
Specifies the path to the zoneinfo database. On POSIX systems, the default of <code>/usr/share/zoneinfo/</code> should always work. Even on systems without the database everything should just work if <code>[[#server|--server]]</code> is specified, since any missing files will be fetched from the remote server. This option may still be useful when debugging time zone problems caused by different versions of the zoneinfo database.<br />
<br />
[[Category:AppSuite]]<br />
[[Category:UI]]<br />
[[Category:Developer]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Appserver&diff=16252AppSuite:Appserver2013-10-28T10:05:02Z<p>Mark.schmidts: /* Installation */</p>
<hr />
<div>{{Stability-unstable}}<br />
<br />
<div class="title">Appserver</div><br />
<br />
The <code>appserver</code> tool is used to develop and test the OX App Suite UI and its plugins with a remote backend. <code>appserver</code> acts as a reverse HTTP proxy for an existing OX App Suite installation and injects the tested JavaScript code in its replies.<br />
<br />
== Installation ==<br />
<br />
The core of <code>appserver</code> is a Node.js script, so if your OS does not provide a <code>nodejs</code> package, you will have to install it manually, either as a [https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager 3rd party package] or directly from [http://nodejs.org/ nodejs.org].<br />
<br />
Read more about how to install the tools for developing for OX App Suite in the [[AppSuite:GettingStarted#Installing | Getting Started article ]]<br />
<br />
== Standalone use ==<br />
<br />
In the simplest case of developing an app or a plugin, all that is needed is an existing OX App Suite installation. Point <code>appserver</code> to the URL of OX App Suite and to the build directory of your app. Assuming you are in the top directory of your app's source code and <code>[[AppSuite:UI build system#builddir|$builddir]]</code> is not set:<br />
<br />
appserver [[#server|--server]]=<nowiki>https://www.ox.io/appsuite/</nowiki> build<br />
<br />
If there are no errors, you can point your browser to http://localhost:8337/appsuite/ to test a version of OX App Suite which includes your app. Do not forget the trailing slash in the URL. Otherwise, the server sends a redirect from <code>/appsuite</code> to <code>/appsuite/</code> and includes its own absolute URL in the redirect.<br />
<br />
You do not need to restart anything after re-building the app, a refresh of the browser page should be enough. If your code doesn’t show up after a refresh, our file cache mighgt not be up-to-date. Until this is fixed in appserver, you can append <code>&debug-js=true</code> to your URL to disable the file cache.<br />
<br />
== Use with Apache ==<br />
<br />
For more complex cases involving testing your own build of the UI, or apps which include static resources (e.&nbsp;g. images), a local web server is required to serve static resources. The following examples use the Apache HTTP Server, but any web server which can act as a reverse HTTP proxy should work (assuming the configuration and <code>.htaccess</code> files are adapted, of course).<br />
<br />
First, make your app visible in Apache. The simplest way is to symlink the <code>[[AppSuite:UI build system#builddir|$builddir]]</code> inside the document root. Assuming the app is in <code>/home/user/myapp</code> and the web server's document root is <code>/var/www</code>:<br />
<br />
sudo ln -s /home/user/myapp/build /var/www/myapp<br />
<br />
In case Apache ignores the symlink, ensure that its configuration directive <code><Directory /var/www/></code> contains "<code>Options FollowSymlinks</code>" or something to that effect.<br />
<br />
Second, configure Apache to request from <code>appserver</code> anything that it can't find locally. This configuration requires at least <code>mod_rewrite</code>, <code>mod_proxy</code> and <code>mod_proxy_http</code> to be enabled. Editing a file like <code>/etc/apache2/sites-enabled/000-default</code> containing the proxy configuration, add the following inside an eventual <code><VirtualHost></code> directive, but outside of any <code><Directory></code> directives:<br />
<br />
RewriteEngine On<br />
ProxyPreserveHost On<br />
<br />
ProxyPassMatch ^/((appsuite|ajax|infostore|publications\<br />
|realtime|servlet|usm-json|webservices)(/.*)?)$ \<br />
<nowiki>http://localhost:8337/$1</nowiki><br />
<br />
RewriteCond %{DOCUMENT_ROOT}/myapp/$2 -f<br />
RewriteRule ^/appsuite/(v=[^,/]+/)?(.*)$ /myapp/$2 [PT]<br />
<br />
Take care configuring apache configuration, proxy definitions might take place in several files. For example <code>/etc/apache2/conf.d/proxy_http.conf</code> does also often contain http proxy configuration, which may differ from the definitions in the file edited above.<br />
<br />
If you want to test multiple apps, use a different directory for each, and repeat the last two lines for each app, substituting the proper values for "<code>myapp</code>". If you are using aliases instead of symlinks then replace <code>%{DOCUMENT_ROOT}</code> with the actual file system path from the <code>Alias</code> directive.<br />
<br />
Now, restart Apache and start <code>appserver</code> adding the path to your simlinked build-path of the app as an parameter.<br />
<br />
sudo apachectl restart<br />
appserver [[#server|--server]]=<nowiki>https://www.ox.io/appsuite/</nowiki> /var/www/myapp<br />
<br />
If there are no errors, you can point your browser to http://localhost/appsuite/ to test a version of OX App Suite which includes your app. You do not need to restart anything after re-building the app, a refresh of the browser page should be enough.<br />
<br />
=== Custom UI builds ===<br />
<br />
To test your own build of the core UI, use <code>/var/www/appsuite</code> as directory, but don't add a <code>RewriteRule</code> for it. Instead, replace "<code>appsuite</code>" with "<code>appsuite/api</code>" in the <code>ProxyPassMatch</code> directive and add a <code><Directory></code> directive like for any other OX App Suite installation:<br />
<br />
<Directory /var/www/appsuite/><br />
Options FollowSymlinks<br />
AllowOverride Indexes FileInfo<br />
</Directory><br />
<br />
== Reference ==<br />
<br />
<code>appserver</code> is a reverse HTTP proxy. It accepts HTTP requests and forwards most of them to another HTTP server. There are currently two exceptions:<br />
* <code>api/apps/load</code> is served from a list of local paths. Only files which could not be found are fetched from the remote HTTP server. This allows to inject the code of a tested app without installing it on the remote server. The list of paths is specified as non-option parameters on the command line. Each path should normally have at least the subdirectories <code>apps</code> and <code>manifests</code>. Each injected file is looked up in the <code>apps</code> subdirectory of each path, in the order in which they appear on the command line, and the first found file is used. If a file is not found in any path, and the <code>[[#server|--server]]</code> option is specified, the file is downloaded from the server.<br />
* <code>api/apps/manifests?action=config</code> is extended by local manifests. This is necessary to enable the tested app in the UI. If no <code>[[#manifests|--manifests]]</code> options are specified, then all files from the <code>manifests</code> subdirectory of each path are combined and added to the manifests from the remote server. Each manifest entry overrides any entries with the same <code>path</code> attribute. Similar to the priority for files, manifest entries from earlier paths override entries from later paths, and local entries override remote entries.<br />
<br />
=== help ===<br />
<br />
Displays a short summary of available options:<br />
<br />
Usage: appserver [OPTION]... [PATH]...<br />
<br />
-h, --help print this help message and exit<br />
-m PATH, --manifests=PATH add manifests from the specified path (default:<br />
the "manifests" subdirectory of every file path)<br />
--path=PATH absolute path of the UI (default: /appsuite)<br />
-p PORT, --port=PORT listen on PORT (default: 8337)<br />
-s URL, --server=URL use an existing server as fallback<br />
-v TYPE, --verbose=TYPE print more information depending on TYPE:<br />
local: local files, remote: remote files,<br />
proxy: forwarded URLs, all: shortcut for all three<br />
-z PATH, --zoneinfo=PATH use timezone data from the specified path<br />
(default: /usr/share/zoneinfo/)<br />
<br />
Files are searched in each PATH in order and requested from the server if not<br />
found. If no paths are specified, the default is /var/www/appsuite/.<br />
<br />
=== manifests ===<br />
<br />
By default, the manifests of an app are collected and put into <code>[[AppSuite:UI build system#builddir|$builddir]]/manifests</code>. Therefore, by default, <code>appserver</code> collects manifests from the <code>manifests</code> subdirectoriy of each file path. Since the destination directory for manifests can be changed by setting <code>[[AppSuite:UI build system#manifestDir|$manifestDir]]</code>, the manifest directories can also be changed in <code>appserver</code> by specifying each directory with a separate <code>--manifests</code> option.<br />
<br />
If at least one <code>--manifests</code> option is specified, the default file paths are not used for manifests at all.<br />
<br />
=== path ===<br />
<br />
By default, URLs belonging to the OX App Suite (i.&nbsp;e. starting with <code>/appsuite/</code>) get mapped to the URL of the <code>[[#server|--server]]</code> parameter, while all other paths get mapped to identical paths on that server to allow services like <code>/publications</code> to work.<br />
<br />
This parameter changes the path of the local OX App Suite URL e.&nbsp;g. to allow testing multiple UIs with the same server.<br />
<br />
=== port ===<br />
<br />
Specifies the port to listen on. The default is 8337. This option might be useful to run multiple instances of <code>appserver</code> at once or when port 8337 is already in use.<br />
<br />
=== server ===<br />
<br />
Specifies the URL of an existing OX App Suite installation. The URL must start with <code>http://</code> or <code>https://</code>. To make forwarding of an HTTPS URL over HTTP possible, <code>appserver</code> removes the <code>Secure</code> attribute from all cookies set by the server.<br />
<br />
This option is required for manifest injection to work, since the intercepted request contains more data than just the manifests.<br />
<br />
=== verbose ===<br />
<br />
Enables verbose output. During normal operation, <code>appserver</code> only writes errors to its console. By specifying this option one or more times, additional output can be enabled, depending on the value of each option:<br />
<br />
; local : The name of every read local file is written to standard output.<br />
; remote : The URL of every request for missing local files is written to standard output.<br />
; proxy : The URL of every client request which is forwarded as-is is written to standard output.<br />
; all : This is just a shortcut for <code>-v local -v remote -v proxy</code>.<br />
<br />
Output lines belonging to the same client request are grouped together and separated from the next request by an empty line.<br />
<br />
=== zoneinfo ===<br />
<br />
Specifies the path to the zoneinfo database. On POSIX systems, the default of <code>/usr/share/zoneinfo/</code> should always work. Even on systems without the database everything should just work if <code>[[#server|--server]]</code> is specified, since any missing files will be fetched from the remote server. This option may still be useful when debugging time zone problems caused by different versions of the zoneinfo database.<br />
<br />
[[Category:AppSuite]]<br />
[[Category:UI]]<br />
[[Category:Developer]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Appserver&diff=16251AppSuite:Appserver2013-10-28T10:03:03Z<p>Mark.schmidts: /* Installation */</p>
<hr />
<div>{{Stability-unstable}}<br />
<br />
<div class="title">Appserver</div><br />
<br />
The <code>appserver</code> tool is used to develop and test the OX App Suite UI and its plugins with a remote backend. <code>appserver</code> acts as a reverse HTTP proxy for an existing OX App Suite installation and injects the tested JavaScript code in its replies.<br />
<br />
== Installation ==<br />
<br />
The core of <code>appserver</code> is a Node.js script, so if your OS does not provide a <code>nodejs</code> package, you will have to install it manually, either as a [https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager 3rd party package] or directly from [http://nodejs.org/ nodejs.org].<br />
<br />
Read more about how to install the tools for developing for OX App Suite in the [[AppSuite:GettingStarted#Installing || Getting Started article ]]<br />
<br />
== Standalone use ==<br />
<br />
In the simplest case of developing an app or a plugin, all that is needed is an existing OX App Suite installation. Point <code>appserver</code> to the URL of OX App Suite and to the build directory of your app. Assuming you are in the top directory of your app's source code and <code>[[AppSuite:UI build system#builddir|$builddir]]</code> is not set:<br />
<br />
appserver [[#server|--server]]=<nowiki>https://www.ox.io/appsuite/</nowiki> build<br />
<br />
If there are no errors, you can point your browser to http://localhost:8337/appsuite/ to test a version of OX App Suite which includes your app. Do not forget the trailing slash in the URL. Otherwise, the server sends a redirect from <code>/appsuite</code> to <code>/appsuite/</code> and includes its own absolute URL in the redirect.<br />
<br />
You do not need to restart anything after re-building the app, a refresh of the browser page should be enough. If your code doesn’t show up after a refresh, our file cache mighgt not be up-to-date. Until this is fixed in appserver, you can append <code>&debug-js=true</code> to your URL to disable the file cache.<br />
<br />
== Use with Apache ==<br />
<br />
For more complex cases involving testing your own build of the UI, or apps which include static resources (e.&nbsp;g. images), a local web server is required to serve static resources. The following examples use the Apache HTTP Server, but any web server which can act as a reverse HTTP proxy should work (assuming the configuration and <code>.htaccess</code> files are adapted, of course).<br />
<br />
First, make your app visible in Apache. The simplest way is to symlink the <code>[[AppSuite:UI build system#builddir|$builddir]]</code> inside the document root. Assuming the app is in <code>/home/user/myapp</code> and the web server's document root is <code>/var/www</code>:<br />
<br />
sudo ln -s /home/user/myapp/build /var/www/myapp<br />
<br />
In case Apache ignores the symlink, ensure that its configuration directive <code><Directory /var/www/></code> contains "<code>Options FollowSymlinks</code>" or something to that effect.<br />
<br />
Second, configure Apache to request from <code>appserver</code> anything that it can't find locally. This configuration requires at least <code>mod_rewrite</code>, <code>mod_proxy</code> and <code>mod_proxy_http</code> to be enabled. Editing a file like <code>/etc/apache2/sites-enabled/000-default</code> containing the proxy configuration, add the following inside an eventual <code><VirtualHost></code> directive, but outside of any <code><Directory></code> directives:<br />
<br />
RewriteEngine On<br />
ProxyPreserveHost On<br />
<br />
ProxyPassMatch ^/((appsuite|ajax|infostore|publications\<br />
|realtime|servlet|usm-json|webservices)(/.*)?)$ \<br />
<nowiki>http://localhost:8337/$1</nowiki><br />
<br />
RewriteCond %{DOCUMENT_ROOT}/myapp/$2 -f<br />
RewriteRule ^/appsuite/(v=[^,/]+/)?(.*)$ /myapp/$2 [PT]<br />
<br />
Take care configuring apache configuration, proxy definitions might take place in several files. For example <code>/etc/apache2/conf.d/proxy_http.conf</code> does also often contain http proxy configuration, which may differ from the definitions in the file edited above.<br />
<br />
If you want to test multiple apps, use a different directory for each, and repeat the last two lines for each app, substituting the proper values for "<code>myapp</code>". If you are using aliases instead of symlinks then replace <code>%{DOCUMENT_ROOT}</code> with the actual file system path from the <code>Alias</code> directive.<br />
<br />
Now, restart Apache and start <code>appserver</code> adding the path to your simlinked build-path of the app as an parameter.<br />
<br />
sudo apachectl restart<br />
appserver [[#server|--server]]=<nowiki>https://www.ox.io/appsuite/</nowiki> /var/www/myapp<br />
<br />
If there are no errors, you can point your browser to http://localhost/appsuite/ to test a version of OX App Suite which includes your app. You do not need to restart anything after re-building the app, a refresh of the browser page should be enough.<br />
<br />
=== Custom UI builds ===<br />
<br />
To test your own build of the core UI, use <code>/var/www/appsuite</code> as directory, but don't add a <code>RewriteRule</code> for it. Instead, replace "<code>appsuite</code>" with "<code>appsuite/api</code>" in the <code>ProxyPassMatch</code> directive and add a <code><Directory></code> directive like for any other OX App Suite installation:<br />
<br />
<Directory /var/www/appsuite/><br />
Options FollowSymlinks<br />
AllowOverride Indexes FileInfo<br />
</Directory><br />
<br />
== Reference ==<br />
<br />
<code>appserver</code> is a reverse HTTP proxy. It accepts HTTP requests and forwards most of them to another HTTP server. There are currently two exceptions:<br />
* <code>api/apps/load</code> is served from a list of local paths. Only files which could not be found are fetched from the remote HTTP server. This allows to inject the code of a tested app without installing it on the remote server. The list of paths is specified as non-option parameters on the command line. Each path should normally have at least the subdirectories <code>apps</code> and <code>manifests</code>. Each injected file is looked up in the <code>apps</code> subdirectory of each path, in the order in which they appear on the command line, and the first found file is used. If a file is not found in any path, and the <code>[[#server|--server]]</code> option is specified, the file is downloaded from the server.<br />
* <code>api/apps/manifests?action=config</code> is extended by local manifests. This is necessary to enable the tested app in the UI. If no <code>[[#manifests|--manifests]]</code> options are specified, then all files from the <code>manifests</code> subdirectory of each path are combined and added to the manifests from the remote server. Each manifest entry overrides any entries with the same <code>path</code> attribute. Similar to the priority for files, manifest entries from earlier paths override entries from later paths, and local entries override remote entries.<br />
<br />
=== help ===<br />
<br />
Displays a short summary of available options:<br />
<br />
Usage: appserver [OPTION]... [PATH]...<br />
<br />
-h, --help print this help message and exit<br />
-m PATH, --manifests=PATH add manifests from the specified path (default:<br />
the "manifests" subdirectory of every file path)<br />
--path=PATH absolute path of the UI (default: /appsuite)<br />
-p PORT, --port=PORT listen on PORT (default: 8337)<br />
-s URL, --server=URL use an existing server as fallback<br />
-v TYPE, --verbose=TYPE print more information depending on TYPE:<br />
local: local files, remote: remote files,<br />
proxy: forwarded URLs, all: shortcut for all three<br />
-z PATH, --zoneinfo=PATH use timezone data from the specified path<br />
(default: /usr/share/zoneinfo/)<br />
<br />
Files are searched in each PATH in order and requested from the server if not<br />
found. If no paths are specified, the default is /var/www/appsuite/.<br />
<br />
=== manifests ===<br />
<br />
By default, the manifests of an app are collected and put into <code>[[AppSuite:UI build system#builddir|$builddir]]/manifests</code>. Therefore, by default, <code>appserver</code> collects manifests from the <code>manifests</code> subdirectoriy of each file path. Since the destination directory for manifests can be changed by setting <code>[[AppSuite:UI build system#manifestDir|$manifestDir]]</code>, the manifest directories can also be changed in <code>appserver</code> by specifying each directory with a separate <code>--manifests</code> option.<br />
<br />
If at least one <code>--manifests</code> option is specified, the default file paths are not used for manifests at all.<br />
<br />
=== path ===<br />
<br />
By default, URLs belonging to the OX App Suite (i.&nbsp;e. starting with <code>/appsuite/</code>) get mapped to the URL of the <code>[[#server|--server]]</code> parameter, while all other paths get mapped to identical paths on that server to allow services like <code>/publications</code> to work.<br />
<br />
This parameter changes the path of the local OX App Suite URL e.&nbsp;g. to allow testing multiple UIs with the same server.<br />
<br />
=== port ===<br />
<br />
Specifies the port to listen on. The default is 8337. This option might be useful to run multiple instances of <code>appserver</code> at once or when port 8337 is already in use.<br />
<br />
=== server ===<br />
<br />
Specifies the URL of an existing OX App Suite installation. The URL must start with <code>http://</code> or <code>https://</code>. To make forwarding of an HTTPS URL over HTTP possible, <code>appserver</code> removes the <code>Secure</code> attribute from all cookies set by the server.<br />
<br />
This option is required for manifest injection to work, since the intercepted request contains more data than just the manifests.<br />
<br />
=== verbose ===<br />
<br />
Enables verbose output. During normal operation, <code>appserver</code> only writes errors to its console. By specifying this option one or more times, additional output can be enabled, depending on the value of each option:<br />
<br />
; local : The name of every read local file is written to standard output.<br />
; remote : The URL of every request for missing local files is written to standard output.<br />
; proxy : The URL of every client request which is forwarded as-is is written to standard output.<br />
; all : This is just a shortcut for <code>-v local -v remote -v proxy</code>.<br />
<br />
Output lines belonging to the same client request are grouped together and separated from the next request by an empty line.<br />
<br />
=== zoneinfo ===<br />
<br />
Specifies the path to the zoneinfo database. On POSIX systems, the default of <code>/usr/share/zoneinfo/</code> should always work. Even on systems without the database everything should just work if <code>[[#server|--server]]</code> is specified, since any missing files will be fetched from the remote server. This option may still be useful when debugging time zone problems caused by different versions of the zoneinfo database.<br />
<br />
[[Category:AppSuite]]<br />
[[Category:UI]]<br />
[[Category:Developer]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:GettingStarted_7.4.2&diff=16250AppSuite:GettingStarted 7.4.22013-10-28T09:59:09Z<p>Mark.schmidts: /* Installing */</p>
<hr />
<div><div class="title">Getting Started</div><br />
<br />
__TOC__<br />
<br />
Hello and welcome to OX App Suite development. This document will get you started to develop your first own app for OX App Suite with a minimal setup. We will look at the steps necessary but will also tempt you to learn more by linking you to some more in-depth documentation about these topics. Depending on how you wound up reading this page, you will probably have already completed some of the steps below.<br />
<br />
== Installing ==<br />
<br />
First, you need to install some tools which are necessary for UI development. For now, the simplest way is to download the source of the OX App Suite UI. Since the source code is kept in a [http://git-scm.com/ Git] repository, the source is downloaded using <tt>git</tt>:<br />
<br />
$ git clone --depth 1 -b releae-7.4.1 https://code.open-xchange.com/git/wd/frontend/web<br />
<br />
This downloads the latest version and unpacks it into a subdirectory <tt>web</tt> in the current directory.<br />
<br />
The option -b develop specifies a git branch. Until version 7.4 is released, the full functionality described in this article is only available in the "develop" branch.<br />
<br />
The option --depth 1 prevents the download of the entire history, and reduces the download size from hundreds of MB to less than 20MB. It should not be used by OX App Suite developers since it also prevents git push from working properly. <br />
<br />
To simplify calling of scripts contained in the ui/bin directory, you should add it to your <tt>$PATH</tt>:<br />
<br />
$ export PATH="$PATH:$(pwd)/web/ui/bin"<br />
<br />
== Preparing ==<br />
<br />
=== Create Workspace ===<br />
<br />
In order to have a proper space for your app/plugin create a workspace prospectivly containing all your code.<br />
This folder should contain the subfolder <tt>apps</tt>.<br />
The following article is written assuming, you're working in your workspace directory.<br />
In this example we will create our own workspace called <tt>example-workspace</tt> and add the suiteable subdirectory <tt>apps</tt> for our code: <br />
<br />
$ mkdir example-workspace<br />
$ cd example-workspace<br />
$ mkdir apps<br />
<br />
== Writing ==<br />
<br />
As an example, let's create a small app and build it. It requires only two files: <code>example-workspace/apps/com.example/main.js</code> for the source code of the app<br />
<br />
<pre class="language-javascript"> <br />
define('com.example/main', function () {<br />
'use strict';<br />
var app = ox.ui.createApp({ name: 'com.example' });<br />
app.setLauncher(function () {<br />
var win = ox.ui.createWindow({<br />
name: 'com.example',<br />
title: 'Hello World App'<br />
});<br />
app.setWindow(win);<br />
win.nodes.main.append($('<h1>').text('Hello, World!'));<br />
win.show();<br />
});<br />
return { getApp: app.getInstance };<br />
});<br />
</pre><br />
<br />
and <code>example-workspace/apps/com.example/manifest.json</code> for the [[AppSuite:UI_manifests_explained | manifest]]:<br />
<br />
<pre class="language-javascript">{ title: 'Hello World App' }</pre><br />
<br />
While developing always keep in mind, that there is an [[AppSuite:Debugging_the_UI | article about debugging the user interface]] which helps you avoiding and fixing typical errors.<br />
<br />
== Building ==<br />
<br />
This step will process your app, checking the source code for syntax errors and compressing it, to make it run error-free and fast. Calling this command will also write the processed source to the a subdirectory called <tt>build</tt> in your workspace, containing also the apps-directory with the original source code.<br />
<br />
While you're in the folder containing <tt>apps</tt>-subdirectory <tt>example-workspace</tt>, using the [[AppSuite:UI_build_system | the UI Build System]] makes building the app is as easy as calling:<br />
<br />
$ build-appsuite app<br />
<br />
== Running ==<br />
<br />
=== Hosting the app ===<br />
For quickest round-trip times, the directory with the generated files in <tt>build</tt>-folder should be made available via the [[AppSuite:Appserver|appserver]] tool, which is also part of the [[#Installing | installed SDK]]. Your OX App Suite installation will use <code>appserver</code> use as upstream server, Assuming you are calling <code>appserver</code> from your workspace, and using [http://ox.io/ ox.io] as server:<br />
<br />
<nowiki>$ appserver --server=https://www.ox.io/appsuite/ build</nowiki><br />
<br />
This command will host your app locally. Once you started it, it will always have to run in the background, making all changes within the given build-directories visible. To add the build path of an other workspace, stop appserver and run the upper command again appending the other directory after a white space.<br />
<br />
WARNING: Take care that build variables like <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or <code>[[AppSuite:UI_build_system#manifestDir|manifestDir]]</code> are not set during development. Otherwise, you will have to specify their directories manually for <code>appserver</code>. Also, the <code>[[AppSuite:UI_build_system#clean|clean]]</code> task will delete these directories and all their contents! In general, don't point <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or any other <code>*Dir</code> variables at existing directories.<br />
<br />
=== Testing the app ===<br />
<br />
Once made your app available, you can access OX App Suite opening your browser with this address:<br />
http://localhost:8337/appsuite<br />
Then simply run this command in your browser's javascript console to open the hello world application:<br />
<pre class="language-javascript"><br />
ox.launch("com.example/main")<br />
</pre><br />
<br />
=== Development cycle ===<br />
<br />
Once successfully tested your first app, you will probably continue developing it. <br />
Keep in mind that after [[#Writing | writing your code]], you will always need to [[#Building | build the app]] and have your [[#Hosting the app | Appserver]] running.<br />
<br />
== Packaging ==<br />
When your app is done, you probably want to test it on a staging system, and later install it on a production system. To keep track of which installed files belong to which version of which app, you should use the native package manager of the Linux distribution of the target system. The packages can be easily created using the build system.<br />
<br />
=== Initialization ===<br />
First, you need to create several files describing how to package you app. Use the <tt>init-packaging</tt> task of the build system:<br />
<br />
$ build-appsuite init-packaging<br />
Node version: v0.10.21<br />
Build path: build<br />
Build version: 0.0.1-1.20131025.133931<br />
Package name: example-app<br />
Version [0.0.1]: <br />
Maintainer (Name <e-mail>): Maintainer <maintainer@example.com><br />
Copyright line [2013 Open-Xchange, Inc]: <br />
<br />
Known licenses for which you don't need to specify a file:<br />
APACHE-2, BSD-2-CLAUSE, BSD-3-CLAUSE, CC-BY-3, CC-BY-NC-3, CC-BY-NC-ND-3,<br />
CC-BY-NC-SA-3, CC-BY-ND-3, CC-BY-SA-3, CC0-1, EXPAT, GPL-2, GPL-3, LGPL-3<br />
<br />
License name [CC-BY-NC-SA-3.0]: BSD-3-Clause<br />
Short description: Example app<br />
<br />
The task presents a number of interactive prompts to get the necessary information about the generated packages. The default values are presented in square brackets ([...]) and can be selected by just pressing Enter. Otherwise, the entered values should follow the Debian Maintainer's Guide. Debian tools are especially picky about the syntax of the maintainer name and email address.<br />
<br />
If none of the known licenses suit you, you can enter any other license name. Then you will be asked to enter the file name of your license text. It should be a plain text file using the UTF-8 encoding.<br />
<br />
Some or even all prompts can be skipped by explicitly specifying the information as a build variable. The list of variable names is available in the reference of the <tt>[[AppSuite:UI_build_system#init-packaging|init-packaging]]</tt> task.<br />
<br />
After answering all the questions, you can customize the generated files to account for any additional packaging requirements.<br />
<br />
=== Static Files ===<br />
If your app includes images (e.g. themes do this most of the time), then you should check the generated packaging files for sections marked<br />
<br />
## Uncomment for multiple packages<br />
#...<br />
<br />
and remove the '#' at the start of each line in each block. This enables the creation of a second package, with a name ending in "<tt>-static</tt>". The images and any other files which are not JavaScript or CSS are server by the Apache web server, instead of the OX App Suite application server. These files are copied to a separate package for the case that the web server is on a dedicated system or maybe even has its own cluster. The default package is installed on the OX application server, and the second, "<tt>-static</tt>" package is installed on the web server.<br />
<br />
=== Building Packages ===<br />
Since the actual package format depends on the distribution it is built for, and there already exist tools to create packages from suitably arranged source code archives, the OX App Suite build system merely prepares such source archives. Using the <tt>dist</tt> task to create the archives:<br />
<br />
$ build-appsuite dist<br />
Node version: v0.10.21<br />
Build path: build<br />
Build version: 0.0.1-1.20131025.150034<br />
dpkg-source: info: using source format `3.0 (quilt)'<br />
dpkg-source: info: building example-app using existing ./example-app_0.0.1.orig.tar.bz2<br />
dpkg-source: info: building example-app in example-app_0.0.1-1.debian.tar.bz2<br />
dpkg-source: info: building example-app in example-app_0.0.1-1.dsc<br />
<br />
$ ls tmp/packaging/<br />
example-app-0.0.1 example-app_0.0.1-1.dsc<br />
example-app.spec example-app_0.0.1.orig.tar.bz2<br />
example-app_0.0.1-1.debian.tar.bz2<br />
<br />
The task creates a temporary directory and four files. The archive with the extension <tt>.orig.tar.bz2</tt> contains the source of your app. It is required to build both Debian and RPM packages. The files with extensions <tt>.debian.tar.bz2</tt> and <tt>.dsc</tt> are used together with the <tt>.orig.tar.bz2</tt> archive to build Debian packages. The file with the extension <tt>.spec</tt> is used together with the <tt>.orig.tar.bz2</tt> archive to build RPM packages.<br />
<br />
==== Building Debian Packages ====<br />
The Debian package can be built directly in the temporary directory created by the <tt>dist</tt> task:<br />
<br />
$ cd tmp/packaging/example-app-0.0.1/<br />
$ dpkg-buildpackage -b<br />
<br />
The package will be placed in <tt>tmp/packaging/</tt>.<br />
<br />
==== Building RPM Packages ====<br />
The RPM package build toor, <tt>rpmbuild</tt> requires the files to be in a specific directory layout before building:<br />
<br />
$ mkdir -p ~/rpmbuild/SOURCES<br />
$ cp tmp/packages/*.orig.tar.bz2 ~/rpmbuild/SOURCES/<br />
$ mkdir -p ~/rpmbuild/SPECS<br />
$ cp tmp/packaging/*.spec ~/rpmbuild/SPECS/<br />
$ rpmbuild ~/rpmbuild/SPECS/*.spec<br />
<br />
The package will be placed in <tt>~/rpmbuild/RPMS/</tt>.<br />
<br />
== Further Reading ==<br />
* You just build your first app for OX App Suite, keep in mind that there [[DevelopingTheUI#What_can_i_build.3F | quite a few options]] how you can develop for OX App Suite.<br />
* It's highly recommended to gain more knowledge about all the benefits [[AppSuite:UI_build_system | the UI build system]] and [[AppSuite:Appserver|the Appserver]] are providing you for developing OX App Suite.<br />
* If you're stuck somewhere, the article about [[AppSuite:Debugging_the_UI | debugging the UI]] might help you.<br />
* Get a better overview about [[DevelopingTheUI | developing the user inferface]].</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:GettingStarted_7.4.2&diff=16249AppSuite:GettingStarted 7.4.22013-10-28T09:58:51Z<p>Mark.schmidts: /* Installing */</p>
<hr />
<div><div class="title">Getting Started</div><br />
<br />
__TOC__<br />
<br />
Hello and welcome to OX App Suite development. This document will get you started to develop your first own app for OX App Suite with a minimal setup. We will look at the steps necessary but will also tempt you to learn more by linking you to some more in-depth documentation about these topics. Depending on how you wound up reading this page, you will probably have already completed some of the steps below.<br />
<br />
== Installing ==<br />
<br />
First, you need to install some tools which are necessary for UI development. For now, the simplest way is to download the source of the OX App Suite UI. Since the source code is kept in a [http://git-scm.com/ Git] repository, the source is downloaded using <tt>git</tt>:<br />
<br />
$ git clone --depth 1 -b releae-7.4.1 https://code.open-xchange.com/git/wd/frontend/web<br />
<br />
This downloads the latest version and unpacks it into a subdirectory <tt>web</tt> in the current directory.<br />
<br />
The option -b develop specifies a git branch. Until version 7.4 is released, the full functionality described in this article is only available in the "develop" branch.<br />
The option --depth 1 prevents the download of the entire history, and reduces the download size from hundreds of MB to less than 20MB. It should not be used by OX App Suite developers since it also prevents git push from working properly. <br />
<br />
To simplify calling of scripts contained in the ui/bin directory, you should add it to your <tt>$PATH</tt>:<br />
<br />
$ export PATH="$PATH:$(pwd)/web/ui/bin"<br />
<br />
== Preparing ==<br />
<br />
=== Create Workspace ===<br />
<br />
In order to have a proper space for your app/plugin create a workspace prospectivly containing all your code.<br />
This folder should contain the subfolder <tt>apps</tt>.<br />
The following article is written assuming, you're working in your workspace directory.<br />
In this example we will create our own workspace called <tt>example-workspace</tt> and add the suiteable subdirectory <tt>apps</tt> for our code: <br />
<br />
$ mkdir example-workspace<br />
$ cd example-workspace<br />
$ mkdir apps<br />
<br />
== Writing ==<br />
<br />
As an example, let's create a small app and build it. It requires only two files: <code>example-workspace/apps/com.example/main.js</code> for the source code of the app<br />
<br />
<pre class="language-javascript"> <br />
define('com.example/main', function () {<br />
'use strict';<br />
var app = ox.ui.createApp({ name: 'com.example' });<br />
app.setLauncher(function () {<br />
var win = ox.ui.createWindow({<br />
name: 'com.example',<br />
title: 'Hello World App'<br />
});<br />
app.setWindow(win);<br />
win.nodes.main.append($('<h1>').text('Hello, World!'));<br />
win.show();<br />
});<br />
return { getApp: app.getInstance };<br />
});<br />
</pre><br />
<br />
and <code>example-workspace/apps/com.example/manifest.json</code> for the [[AppSuite:UI_manifests_explained | manifest]]:<br />
<br />
<pre class="language-javascript">{ title: 'Hello World App' }</pre><br />
<br />
While developing always keep in mind, that there is an [[AppSuite:Debugging_the_UI | article about debugging the user interface]] which helps you avoiding and fixing typical errors.<br />
<br />
== Building ==<br />
<br />
This step will process your app, checking the source code for syntax errors and compressing it, to make it run error-free and fast. Calling this command will also write the processed source to the a subdirectory called <tt>build</tt> in your workspace, containing also the apps-directory with the original source code.<br />
<br />
While you're in the folder containing <tt>apps</tt>-subdirectory <tt>example-workspace</tt>, using the [[AppSuite:UI_build_system | the UI Build System]] makes building the app is as easy as calling:<br />
<br />
$ build-appsuite app<br />
<br />
== Running ==<br />
<br />
=== Hosting the app ===<br />
For quickest round-trip times, the directory with the generated files in <tt>build</tt>-folder should be made available via the [[AppSuite:Appserver|appserver]] tool, which is also part of the [[#Installing | installed SDK]]. Your OX App Suite installation will use <code>appserver</code> use as upstream server, Assuming you are calling <code>appserver</code> from your workspace, and using [http://ox.io/ ox.io] as server:<br />
<br />
<nowiki>$ appserver --server=https://www.ox.io/appsuite/ build</nowiki><br />
<br />
This command will host your app locally. Once you started it, it will always have to run in the background, making all changes within the given build-directories visible. To add the build path of an other workspace, stop appserver and run the upper command again appending the other directory after a white space.<br />
<br />
WARNING: Take care that build variables like <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or <code>[[AppSuite:UI_build_system#manifestDir|manifestDir]]</code> are not set during development. Otherwise, you will have to specify their directories manually for <code>appserver</code>. Also, the <code>[[AppSuite:UI_build_system#clean|clean]]</code> task will delete these directories and all their contents! In general, don't point <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or any other <code>*Dir</code> variables at existing directories.<br />
<br />
=== Testing the app ===<br />
<br />
Once made your app available, you can access OX App Suite opening your browser with this address:<br />
http://localhost:8337/appsuite<br />
Then simply run this command in your browser's javascript console to open the hello world application:<br />
<pre class="language-javascript"><br />
ox.launch("com.example/main")<br />
</pre><br />
<br />
=== Development cycle ===<br />
<br />
Once successfully tested your first app, you will probably continue developing it. <br />
Keep in mind that after [[#Writing | writing your code]], you will always need to [[#Building | build the app]] and have your [[#Hosting the app | Appserver]] running.<br />
<br />
== Packaging ==<br />
When your app is done, you probably want to test it on a staging system, and later install it on a production system. To keep track of which installed files belong to which version of which app, you should use the native package manager of the Linux distribution of the target system. The packages can be easily created using the build system.<br />
<br />
=== Initialization ===<br />
First, you need to create several files describing how to package you app. Use the <tt>init-packaging</tt> task of the build system:<br />
<br />
$ build-appsuite init-packaging<br />
Node version: v0.10.21<br />
Build path: build<br />
Build version: 0.0.1-1.20131025.133931<br />
Package name: example-app<br />
Version [0.0.1]: <br />
Maintainer (Name <e-mail>): Maintainer <maintainer@example.com><br />
Copyright line [2013 Open-Xchange, Inc]: <br />
<br />
Known licenses for which you don't need to specify a file:<br />
APACHE-2, BSD-2-CLAUSE, BSD-3-CLAUSE, CC-BY-3, CC-BY-NC-3, CC-BY-NC-ND-3,<br />
CC-BY-NC-SA-3, CC-BY-ND-3, CC-BY-SA-3, CC0-1, EXPAT, GPL-2, GPL-3, LGPL-3<br />
<br />
License name [CC-BY-NC-SA-3.0]: BSD-3-Clause<br />
Short description: Example app<br />
<br />
The task presents a number of interactive prompts to get the necessary information about the generated packages. The default values are presented in square brackets ([...]) and can be selected by just pressing Enter. Otherwise, the entered values should follow the Debian Maintainer's Guide. Debian tools are especially picky about the syntax of the maintainer name and email address.<br />
<br />
If none of the known licenses suit you, you can enter any other license name. Then you will be asked to enter the file name of your license text. It should be a plain text file using the UTF-8 encoding.<br />
<br />
Some or even all prompts can be skipped by explicitly specifying the information as a build variable. The list of variable names is available in the reference of the <tt>[[AppSuite:UI_build_system#init-packaging|init-packaging]]</tt> task.<br />
<br />
After answering all the questions, you can customize the generated files to account for any additional packaging requirements.<br />
<br />
=== Static Files ===<br />
If your app includes images (e.g. themes do this most of the time), then you should check the generated packaging files for sections marked<br />
<br />
## Uncomment for multiple packages<br />
#...<br />
<br />
and remove the '#' at the start of each line in each block. This enables the creation of a second package, with a name ending in "<tt>-static</tt>". The images and any other files which are not JavaScript or CSS are server by the Apache web server, instead of the OX App Suite application server. These files are copied to a separate package for the case that the web server is on a dedicated system or maybe even has its own cluster. The default package is installed on the OX application server, and the second, "<tt>-static</tt>" package is installed on the web server.<br />
<br />
=== Building Packages ===<br />
Since the actual package format depends on the distribution it is built for, and there already exist tools to create packages from suitably arranged source code archives, the OX App Suite build system merely prepares such source archives. Using the <tt>dist</tt> task to create the archives:<br />
<br />
$ build-appsuite dist<br />
Node version: v0.10.21<br />
Build path: build<br />
Build version: 0.0.1-1.20131025.150034<br />
dpkg-source: info: using source format `3.0 (quilt)'<br />
dpkg-source: info: building example-app using existing ./example-app_0.0.1.orig.tar.bz2<br />
dpkg-source: info: building example-app in example-app_0.0.1-1.debian.tar.bz2<br />
dpkg-source: info: building example-app in example-app_0.0.1-1.dsc<br />
<br />
$ ls tmp/packaging/<br />
example-app-0.0.1 example-app_0.0.1-1.dsc<br />
example-app.spec example-app_0.0.1.orig.tar.bz2<br />
example-app_0.0.1-1.debian.tar.bz2<br />
<br />
The task creates a temporary directory and four files. The archive with the extension <tt>.orig.tar.bz2</tt> contains the source of your app. It is required to build both Debian and RPM packages. The files with extensions <tt>.debian.tar.bz2</tt> and <tt>.dsc</tt> are used together with the <tt>.orig.tar.bz2</tt> archive to build Debian packages. The file with the extension <tt>.spec</tt> is used together with the <tt>.orig.tar.bz2</tt> archive to build RPM packages.<br />
<br />
==== Building Debian Packages ====<br />
The Debian package can be built directly in the temporary directory created by the <tt>dist</tt> task:<br />
<br />
$ cd tmp/packaging/example-app-0.0.1/<br />
$ dpkg-buildpackage -b<br />
<br />
The package will be placed in <tt>tmp/packaging/</tt>.<br />
<br />
==== Building RPM Packages ====<br />
The RPM package build toor, <tt>rpmbuild</tt> requires the files to be in a specific directory layout before building:<br />
<br />
$ mkdir -p ~/rpmbuild/SOURCES<br />
$ cp tmp/packages/*.orig.tar.bz2 ~/rpmbuild/SOURCES/<br />
$ mkdir -p ~/rpmbuild/SPECS<br />
$ cp tmp/packaging/*.spec ~/rpmbuild/SPECS/<br />
$ rpmbuild ~/rpmbuild/SPECS/*.spec<br />
<br />
The package will be placed in <tt>~/rpmbuild/RPMS/</tt>.<br />
<br />
== Further Reading ==<br />
* You just build your first app for OX App Suite, keep in mind that there [[DevelopingTheUI#What_can_i_build.3F | quite a few options]] how you can develop for OX App Suite.<br />
* It's highly recommended to gain more knowledge about all the benefits [[AppSuite:UI_build_system | the UI build system]] and [[AppSuite:Appserver|the Appserver]] are providing you for developing OX App Suite.<br />
* If you're stuck somewhere, the article about [[AppSuite:Debugging_the_UI | debugging the UI]] might help you.<br />
* Get a better overview about [[DevelopingTheUI | developing the user inferface]].</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:GettingStarted_7.4.2&diff=16248AppSuite:GettingStarted 7.4.22013-10-28T09:58:18Z<p>Mark.schmidts: /* Installing */</p>
<hr />
<div><div class="title">Getting Started</div><br />
<br />
__TOC__<br />
<br />
Hello and welcome to OX App Suite development. This document will get you started to develop your first own app for OX App Suite with a minimal setup. We will look at the steps necessary but will also tempt you to learn more by linking you to some more in-depth documentation about these topics. Depending on how you wound up reading this page, you will probably have already completed some of the steps below.<br />
<br />
== Installing ==<br />
<br />
First, you need to install some tools which are necessary for UI development. For now, the simplest way is to download the source of the OX App Suite UI. Since the source code is kept in a [http://git-scm.com/ Git] repository, the source is downloaded using <tt>git</tt>:<br />
<br />
$ git clone --depth 1 -b releae-7.4.1 https://code.open-xchange.com/git/wd/frontend/web<br />
<br />
This downloads the latest version and unpacks it into a subdirectory <tt>web</tt> in the current directory.<br />
<br />
The option -b develop specifies a git branch. Until version 7.4 is released, the full functionality described in this article is only available in the "develop" branch.<br />
<br />
The option --depth 1 prevents the download of the entire history, and reduces the download size from hundreds of MB to less than 20MB. It should not be used by OX App Suite developers since it also prevents git push from working properly. <br />
<br />
To simplify calling of scripts contained in the ui/bin directory, you should add it to your <tt>$PATH</tt>:<br />
<br />
$ export PATH="$PATH:$(pwd)/web/ui/bin"<br />
<br />
== Preparing ==<br />
<br />
=== Create Workspace ===<br />
<br />
In order to have a proper space for your app/plugin create a workspace prospectivly containing all your code.<br />
This folder should contain the subfolder <tt>apps</tt>.<br />
The following article is written assuming, you're working in your workspace directory.<br />
In this example we will create our own workspace called <tt>example-workspace</tt> and add the suiteable subdirectory <tt>apps</tt> for our code: <br />
<br />
$ mkdir example-workspace<br />
$ cd example-workspace<br />
$ mkdir apps<br />
<br />
== Writing ==<br />
<br />
As an example, let's create a small app and build it. It requires only two files: <code>example-workspace/apps/com.example/main.js</code> for the source code of the app<br />
<br />
<pre class="language-javascript"> <br />
define('com.example/main', function () {<br />
'use strict';<br />
var app = ox.ui.createApp({ name: 'com.example' });<br />
app.setLauncher(function () {<br />
var win = ox.ui.createWindow({<br />
name: 'com.example',<br />
title: 'Hello World App'<br />
});<br />
app.setWindow(win);<br />
win.nodes.main.append($('<h1>').text('Hello, World!'));<br />
win.show();<br />
});<br />
return { getApp: app.getInstance };<br />
});<br />
</pre><br />
<br />
and <code>example-workspace/apps/com.example/manifest.json</code> for the [[AppSuite:UI_manifests_explained | manifest]]:<br />
<br />
<pre class="language-javascript">{ title: 'Hello World App' }</pre><br />
<br />
While developing always keep in mind, that there is an [[AppSuite:Debugging_the_UI | article about debugging the user interface]] which helps you avoiding and fixing typical errors.<br />
<br />
== Building ==<br />
<br />
This step will process your app, checking the source code for syntax errors and compressing it, to make it run error-free and fast. Calling this command will also write the processed source to the a subdirectory called <tt>build</tt> in your workspace, containing also the apps-directory with the original source code.<br />
<br />
While you're in the folder containing <tt>apps</tt>-subdirectory <tt>example-workspace</tt>, using the [[AppSuite:UI_build_system | the UI Build System]] makes building the app is as easy as calling:<br />
<br />
$ build-appsuite app<br />
<br />
== Running ==<br />
<br />
=== Hosting the app ===<br />
For quickest round-trip times, the directory with the generated files in <tt>build</tt>-folder should be made available via the [[AppSuite:Appserver|appserver]] tool, which is also part of the [[#Installing | installed SDK]]. Your OX App Suite installation will use <code>appserver</code> use as upstream server, Assuming you are calling <code>appserver</code> from your workspace, and using [http://ox.io/ ox.io] as server:<br />
<br />
<nowiki>$ appserver --server=https://www.ox.io/appsuite/ build</nowiki><br />
<br />
This command will host your app locally. Once you started it, it will always have to run in the background, making all changes within the given build-directories visible. To add the build path of an other workspace, stop appserver and run the upper command again appending the other directory after a white space.<br />
<br />
WARNING: Take care that build variables like <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or <code>[[AppSuite:UI_build_system#manifestDir|manifestDir]]</code> are not set during development. Otherwise, you will have to specify their directories manually for <code>appserver</code>. Also, the <code>[[AppSuite:UI_build_system#clean|clean]]</code> task will delete these directories and all their contents! In general, don't point <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or any other <code>*Dir</code> variables at existing directories.<br />
<br />
=== Testing the app ===<br />
<br />
Once made your app available, you can access OX App Suite opening your browser with this address:<br />
http://localhost:8337/appsuite<br />
Then simply run this command in your browser's javascript console to open the hello world application:<br />
<pre class="language-javascript"><br />
ox.launch("com.example/main")<br />
</pre><br />
<br />
=== Development cycle ===<br />
<br />
Once successfully tested your first app, you will probably continue developing it. <br />
Keep in mind that after [[#Writing | writing your code]], you will always need to [[#Building | build the app]] and have your [[#Hosting the app | Appserver]] running.<br />
<br />
== Packaging ==<br />
When your app is done, you probably want to test it on a staging system, and later install it on a production system. To keep track of which installed files belong to which version of which app, you should use the native package manager of the Linux distribution of the target system. The packages can be easily created using the build system.<br />
<br />
=== Initialization ===<br />
First, you need to create several files describing how to package you app. Use the <tt>init-packaging</tt> task of the build system:<br />
<br />
$ build-appsuite init-packaging<br />
Node version: v0.10.21<br />
Build path: build<br />
Build version: 0.0.1-1.20131025.133931<br />
Package name: example-app<br />
Version [0.0.1]: <br />
Maintainer (Name <e-mail>): Maintainer <maintainer@example.com><br />
Copyright line [2013 Open-Xchange, Inc]: <br />
<br />
Known licenses for which you don't need to specify a file:<br />
APACHE-2, BSD-2-CLAUSE, BSD-3-CLAUSE, CC-BY-3, CC-BY-NC-3, CC-BY-NC-ND-3,<br />
CC-BY-NC-SA-3, CC-BY-ND-3, CC-BY-SA-3, CC0-1, EXPAT, GPL-2, GPL-3, LGPL-3<br />
<br />
License name [CC-BY-NC-SA-3.0]: BSD-3-Clause<br />
Short description: Example app<br />
<br />
The task presents a number of interactive prompts to get the necessary information about the generated packages. The default values are presented in square brackets ([...]) and can be selected by just pressing Enter. Otherwise, the entered values should follow the Debian Maintainer's Guide. Debian tools are especially picky about the syntax of the maintainer name and email address.<br />
<br />
If none of the known licenses suit you, you can enter any other license name. Then you will be asked to enter the file name of your license text. It should be a plain text file using the UTF-8 encoding.<br />
<br />
Some or even all prompts can be skipped by explicitly specifying the information as a build variable. The list of variable names is available in the reference of the <tt>[[AppSuite:UI_build_system#init-packaging|init-packaging]]</tt> task.<br />
<br />
After answering all the questions, you can customize the generated files to account for any additional packaging requirements.<br />
<br />
=== Static Files ===<br />
If your app includes images (e.g. themes do this most of the time), then you should check the generated packaging files for sections marked<br />
<br />
## Uncomment for multiple packages<br />
#...<br />
<br />
and remove the '#' at the start of each line in each block. This enables the creation of a second package, with a name ending in "<tt>-static</tt>". The images and any other files which are not JavaScript or CSS are server by the Apache web server, instead of the OX App Suite application server. These files are copied to a separate package for the case that the web server is on a dedicated system or maybe even has its own cluster. The default package is installed on the OX application server, and the second, "<tt>-static</tt>" package is installed on the web server.<br />
<br />
=== Building Packages ===<br />
Since the actual package format depends on the distribution it is built for, and there already exist tools to create packages from suitably arranged source code archives, the OX App Suite build system merely prepares such source archives. Using the <tt>dist</tt> task to create the archives:<br />
<br />
$ build-appsuite dist<br />
Node version: v0.10.21<br />
Build path: build<br />
Build version: 0.0.1-1.20131025.150034<br />
dpkg-source: info: using source format `3.0 (quilt)'<br />
dpkg-source: info: building example-app using existing ./example-app_0.0.1.orig.tar.bz2<br />
dpkg-source: info: building example-app in example-app_0.0.1-1.debian.tar.bz2<br />
dpkg-source: info: building example-app in example-app_0.0.1-1.dsc<br />
<br />
$ ls tmp/packaging/<br />
example-app-0.0.1 example-app_0.0.1-1.dsc<br />
example-app.spec example-app_0.0.1.orig.tar.bz2<br />
example-app_0.0.1-1.debian.tar.bz2<br />
<br />
The task creates a temporary directory and four files. The archive with the extension <tt>.orig.tar.bz2</tt> contains the source of your app. It is required to build both Debian and RPM packages. The files with extensions <tt>.debian.tar.bz2</tt> and <tt>.dsc</tt> are used together with the <tt>.orig.tar.bz2</tt> archive to build Debian packages. The file with the extension <tt>.spec</tt> is used together with the <tt>.orig.tar.bz2</tt> archive to build RPM packages.<br />
<br />
==== Building Debian Packages ====<br />
The Debian package can be built directly in the temporary directory created by the <tt>dist</tt> task:<br />
<br />
$ cd tmp/packaging/example-app-0.0.1/<br />
$ dpkg-buildpackage -b<br />
<br />
The package will be placed in <tt>tmp/packaging/</tt>.<br />
<br />
==== Building RPM Packages ====<br />
The RPM package build toor, <tt>rpmbuild</tt> requires the files to be in a specific directory layout before building:<br />
<br />
$ mkdir -p ~/rpmbuild/SOURCES<br />
$ cp tmp/packages/*.orig.tar.bz2 ~/rpmbuild/SOURCES/<br />
$ mkdir -p ~/rpmbuild/SPECS<br />
$ cp tmp/packaging/*.spec ~/rpmbuild/SPECS/<br />
$ rpmbuild ~/rpmbuild/SPECS/*.spec<br />
<br />
The package will be placed in <tt>~/rpmbuild/RPMS/</tt>.<br />
<br />
== Further Reading ==<br />
* You just build your first app for OX App Suite, keep in mind that there [[DevelopingTheUI#What_can_i_build.3F | quite a few options]] how you can develop for OX App Suite.<br />
* It's highly recommended to gain more knowledge about all the benefits [[AppSuite:UI_build_system | the UI build system]] and [[AppSuite:Appserver|the Appserver]] are providing you for developing OX App Suite.<br />
* If you're stuck somewhere, the article about [[AppSuite:Debugging_the_UI | debugging the UI]] might help you.<br />
* Get a better overview about [[DevelopingTheUI | developing the user inferface]].</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:GettingStarted_7.4.2&diff=16247AppSuite:GettingStarted 7.4.22013-10-28T09:51:25Z<p>Mark.schmidts: /* Testing the app */</p>
<hr />
<div><div class="title">Getting Started</div><br />
<br />
__TOC__<br />
<br />
Hello and welcome to OX App Suite development. This document will get you started to develop your first own app for OX App Suite with a minimal setup. We will look at the steps necessary but will also tempt you to learn more by linking you to some more in-depth documentation about these topics. Depending on how you wound up reading this page, you will probably have already completed some of the steps below.<br />
<br />
== Installing ==<br />
<br />
First, you need to install some tools which are necessary for UI development. For now, the simplest way is to download the source of the OX App Suite UI. Since the source code is kept in a [http://git-scm.com/ Git] repository, the source is downloaded using <tt>git</tt>:<br />
<br />
$ git clone --depth 1 -b releae-7.4.1 https://code.open-xchange.com/git/wd/frontend/web<br />
<br />
This downloads the latest version and unpacks it into a subdirectory <tt>web</tt> in the current directory. To simplify calling of scripts contained in the ui/bin directory, you should add it to your <tt>$PATH</tt>:<br />
<br />
$ export PATH="$PATH:$(pwd)/web/ui/bin"<br />
<br />
== Preparing ==<br />
<br />
=== Create Workspace ===<br />
<br />
In order to have a proper space for your app/plugin create a workspace prospectivly containing all your code.<br />
This folder should contain the subfolder <tt>apps</tt>.<br />
The following article is written assuming, you're working in your workspace directory.<br />
In this example we will create our own workspace called <tt>example-workspace</tt> and add the suiteable subdirectory <tt>apps</tt> for our code: <br />
<br />
$ mkdir example-workspace<br />
$ cd example-workspace<br />
$ mkdir apps<br />
<br />
== Writing ==<br />
<br />
As an example, let's create a small app and build it. It requires only two files: <code>example-workspace/apps/com.example/main.js</code> for the source code of the app<br />
<br />
<pre class="language-javascript"> <br />
define('com.example/main', function () {<br />
'use strict';<br />
var app = ox.ui.createApp({ name: 'com.example' });<br />
app.setLauncher(function () {<br />
var win = ox.ui.createWindow({<br />
name: 'com.example',<br />
title: 'Hello World App'<br />
});<br />
app.setWindow(win);<br />
win.nodes.main.append($('<h1>').text('Hello, World!'));<br />
win.show();<br />
});<br />
return { getApp: app.getInstance };<br />
});<br />
</pre><br />
<br />
and <code>example-workspace/apps/com.example/manifest.json</code> for the [[AppSuite:UI_manifests_explained | manifest]]:<br />
<br />
<pre class="language-javascript">{ title: 'Hello World App' }</pre><br />
<br />
While developing always keep in mind, that there is an [[AppSuite:Debugging_the_UI | article about debugging the user interface]] which helps you avoiding and fixing typical errors.<br />
<br />
== Building ==<br />
<br />
This step will process your app, checking the source code for syntax errors and compressing it, to make it run error-free and fast. Calling this command will also write the processed source to the a subdirectory called <tt>build</tt> in your workspace, containing also the apps-directory with the original source code.<br />
<br />
While you're in the folder containing <tt>apps</tt>-subdirectory <tt>example-workspace</tt>, using the [[AppSuite:UI_build_system | the UI Build System]] makes building the app is as easy as calling:<br />
<br />
$ build-appsuite app<br />
<br />
== Running ==<br />
<br />
=== Hosting the app ===<br />
For quickest round-trip times, the directory with the generated files in <tt>build</tt>-folder should be made available via the [[AppSuite:Appserver|appserver]] tool, which is also part of the [[#Installing | installed SDK]]. Your OX App Suite installation will use <code>appserver</code> use as upstream server, Assuming you are calling <code>appserver</code> from your workspace, and using [http://ox.io/ ox.io] as server:<br />
<br />
<nowiki>$ appserver --server=https://www.ox.io/appsuite/ build</nowiki><br />
<br />
This command will host your app locally. Once you started it, it will always have to run in the background, making all changes within the given build-directories visible. To add the build path of an other workspace, stop appserver and run the upper command again appending the other directory after a white space.<br />
<br />
WARNING: Take care that build variables like <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or <code>[[AppSuite:UI_build_system#manifestDir|manifestDir]]</code> are not set during development. Otherwise, you will have to specify their directories manually for <code>appserver</code>. Also, the <code>[[AppSuite:UI_build_system#clean|clean]]</code> task will delete these directories and all their contents! In general, don't point <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or any other <code>*Dir</code> variables at existing directories.<br />
<br />
=== Testing the app ===<br />
<br />
Once made your app available, you can access OX App Suite opening your browser with this address:<br />
http://localhost:8337/appsuite<br />
Then simply run this command in your browser's javascript console to open the hello world application:<br />
<pre class="language-javascript"><br />
ox.launch("com.example/main")<br />
</pre><br />
<br />
=== Development cycle ===<br />
<br />
Once successfully tested your first app, you will probably continue developing it. <br />
Keep in mind that after [[#Writing | writing your code]], you will always need to [[#Building | build the app]] and have your [[#Hosting the app | Appserver]] running.<br />
<br />
== Packaging ==<br />
When your app is done, you probably want to test it on a staging system, and later install it on a production system. To keep track of which installed files belong to which version of which app, you should use the native package manager of the Linux distribution of the target system. The packages can be easily created using the build system.<br />
<br />
=== Initialization ===<br />
First, you need to create several files describing how to package you app. Use the <tt>init-packaging</tt> task of the build system:<br />
<br />
$ build-appsuite init-packaging<br />
Node version: v0.10.21<br />
Build path: build<br />
Build version: 0.0.1-1.20131025.133931<br />
Package name: example-app<br />
Version [0.0.1]: <br />
Maintainer (Name <e-mail>): Maintainer <maintainer@example.com><br />
Copyright line [2013 Open-Xchange, Inc]: <br />
<br />
Known licenses for which you don't need to specify a file:<br />
APACHE-2, BSD-2-CLAUSE, BSD-3-CLAUSE, CC-BY-3, CC-BY-NC-3, CC-BY-NC-ND-3,<br />
CC-BY-NC-SA-3, CC-BY-ND-3, CC-BY-SA-3, CC0-1, EXPAT, GPL-2, GPL-3, LGPL-3<br />
<br />
License name [CC-BY-NC-SA-3.0]: BSD-3-Clause<br />
Short description: Example app<br />
<br />
The task presents a number of interactive prompts to get the necessary information about the generated packages. The default values are presented in square brackets ([...]) and can be selected by just pressing Enter. Otherwise, the entered values should follow the Debian Maintainer's Guide. Debian tools are especially picky about the syntax of the maintainer name and email address.<br />
<br />
If none of the known licenses suit you, you can enter any other license name. Then you will be asked to enter the file name of your license text. It should be a plain text file using the UTF-8 encoding.<br />
<br />
Some or even all prompts can be skipped by explicitly specifying the information as a build variable. The list of variable names is available in the reference of the <tt>[[AppSuite:UI_build_system#init-packaging|init-packaging]]</tt> task.<br />
<br />
After answering all the questions, you can customize the generated files to account for any additional packaging requirements.<br />
<br />
=== Static Files ===<br />
If your app includes images (e.g. themes do this most of the time), then you should check the generated packaging files for sections marked<br />
<br />
## Uncomment for multiple packages<br />
#...<br />
<br />
and remove the '#' at the start of each line in each block. This enables the creation of a second package, with a name ending in "<tt>-static</tt>". The images and any other files which are not JavaScript or CSS are server by the Apache web server, instead of the OX App Suite application server. These files are copied to a separate package for the case that the web server is on a dedicated system or maybe even has its own cluster. The default package is installed on the OX application server, and the second, "<tt>-static</tt>" package is installed on the web server.<br />
<br />
=== Building Packages ===<br />
Since the actual package format depends on the distribution it is built for, and there already exist tools to create packages from suitably arranged source code archives, the OX App Suite build system merely prepares such source archives. Using the <tt>dist</tt> task to create the archives:<br />
<br />
$ build-appsuite dist<br />
Node version: v0.10.21<br />
Build path: build<br />
Build version: 0.0.1-1.20131025.150034<br />
dpkg-source: info: using source format `3.0 (quilt)'<br />
dpkg-source: info: building example-app using existing ./example-app_0.0.1.orig.tar.bz2<br />
dpkg-source: info: building example-app in example-app_0.0.1-1.debian.tar.bz2<br />
dpkg-source: info: building example-app in example-app_0.0.1-1.dsc<br />
<br />
$ ls tmp/packaging/<br />
example-app-0.0.1 example-app_0.0.1-1.dsc<br />
example-app.spec example-app_0.0.1.orig.tar.bz2<br />
example-app_0.0.1-1.debian.tar.bz2<br />
<br />
The task creates a temporary directory and four files. The archive with the extension <tt>.orig.tar.bz2</tt> contains the source of your app. It is required to build both Debian and RPM packages. The files with extensions <tt>.debian.tar.bz2</tt> and <tt>.dsc</tt> are used together with the <tt>.orig.tar.bz2</tt> archive to build Debian packages. The file with the extension <tt>.spec</tt> is used together with the <tt>.orig.tar.bz2</tt> archive to build RPM packages.<br />
<br />
==== Building Debian Packages ====<br />
The Debian package can be built directly in the temporary directory created by the <tt>dist</tt> task:<br />
<br />
$ cd tmp/packaging/example-app-0.0.1/<br />
$ dpkg-buildpackage -b<br />
<br />
The package will be placed in <tt>tmp/packaging/</tt>.<br />
<br />
==== Building RPM Packages ====<br />
The RPM package build toor, <tt>rpmbuild</tt> requires the files to be in a specific directory layout before building:<br />
<br />
$ mkdir -p ~/rpmbuild/SOURCES<br />
$ cp tmp/packages/*.orig.tar.bz2 ~/rpmbuild/SOURCES/<br />
$ mkdir -p ~/rpmbuild/SPECS<br />
$ cp tmp/packaging/*.spec ~/rpmbuild/SPECS/<br />
$ rpmbuild ~/rpmbuild/SPECS/*.spec<br />
<br />
The package will be placed in <tt>~/rpmbuild/RPMS/</tt>.<br />
<br />
== Further Reading ==<br />
* You just build your first app for OX App Suite, keep in mind that there [[DevelopingTheUI#What_can_i_build.3F | quite a few options]] how you can develop for OX App Suite.<br />
* It's highly recommended to gain more knowledge about all the benefits [[AppSuite:UI_build_system | the UI build system]] and [[AppSuite:Appserver|the Appserver]] are providing you for developing OX App Suite.<br />
* If you're stuck somewhere, the article about [[AppSuite:Debugging_the_UI | debugging the UI]] might help you.<br />
* Get a better overview about [[DevelopingTheUI | developing the user inferface]].</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Developing_for_the_UI&diff=16214AppSuite:Developing for the UI2013-10-24T13:50:15Z<p>Mark.schmidts: /* Tech Overview */</p>
<hr />
<div><div class="title">UI Development for OX AppSuite</div><br />
<br />
__TOC__<br />
<br />
This page contains articles about the inner workings of the web-based graphical user interface. It is aimed at software developers that want to improve on existing features, implement extensions or just gain a general understanding.<br />
<br />
=== Tech Overview ===<br />
All technologies and frameworks used for developing a new component for the AppSuite UI are listed and described in the following article: [[AppSuite:UI developer primer| Requirements to develop the UI]]<br />
<br />
=== Developing Guidelines ===<br />
While developing code for OX products [[AppSuite:UI Development Style Guide | the UI Developement Style Guide]] helps you writing safe, clear and functional code.<br />
<br />
Designing apps, plugins and widgets running with the right layout, colors, look and feel is a breeze following the guidelines described in [[AppSuite:UI Design Guide | the UI Design Guide]].<br />
<br />
Always keep in mind, that using OX products should be possible for everyone and therefor it's important to follow simple rules regarding [[AppSuite:Accessibility | accessibility]].<br />
<br />
=== Using extension points ===<br />
<br />
Writing apps or plugins for AppSuite will often include extending the existing user interface. AppSuite provides extension points offering you possibilties to add your own contents.<br />
Beginning to develop using extension points? Read this guide first having [[AppSuite:Extending the UI (Hands-on introduction) | a hands-on introduction]] for extending the OX user interface. Get more information and a complete list of [[AppSuite:Extension points |extension points]] offered by OX products.<br />
<br />
=== How to get code ===<br />
Using git as a version version control system getting the code from existing OX products is quite easy.<br />
Simply clone the [[AppSuite:UI build system#Source | UI]] or the [[AppSuite:Backend build system#Source | backend]] repository and start working with it.<br />
<br />
=== What can i build? ===<br />
<br />
If you want to have a simple introduction following easy steps from creating your workspace to actually performing your source code within AppSuite, read our [[AppSuite:GettingStarted | GettingStarted guide]].<br />
<br />
There are several other possibilities available to develop for AppSuite.<br />
<br />
*[[AppSuite:Writing a portal plugin | A portal plugin]] is a widget, which can be used in the 'portal'-section of AppSuite only. Please just check for the right [[AppSuite:Extension points |extension point]] to write a plugin which extends and interacts with other parts of AppSuite. Configuring portal plugins can be achieved by reading [[AppSuite:Configuring portal plugins | this guide]].<br />
<br />
*[[AppSuite:Writing_a_contacts_plugin | A contacts plugin]] let's you modify parts of AppSuite's contact view.<br />
<br />
*[[AppSuite:Using the Upsell widget | Upsell Widget]], to enable the AppSuite user to purchase additional features. <br />
<br />
*[[AppSuite:Writing a simple application | A real application/module]] for AppSuite, which should be displayed full screen and appear as a bread crump in the title bar, take a look at the article about [[AppSuite:Writing a simple application | 'Writing a simple application']].<br />
<br />
*[[AppSuite:Writing a notification area plugin | A notification plugin]] for AppSuite<br />
<br />
*[[AppSuite:Writing a wizard | A wizard]], which can be first time users to show them important informations or configure initial settings for 3rd party applications.<br />
<br />
*[[AppSuite:Creating a settings section in AppSuite settings | Settings plugin]] extending AppSuite settings and creating a new section.<br />
<br />
*[[AppSuite:Embedding your settings into AppSuite settings | Settings plugin]] embedding your own settings section via iframe into AppSuite.<br />
<br />
You got stuck somewhere? There are some hints, which might help you [[AppSuite:Debugging_the_UI | debugging the UI]].<br />
<br />
=== How to get your code running ===<br />
Written your first app/plugin? Using the [[AppSuite:UI build system | UI build system]] will help you to get fast, easy-to-distribute and correct builds running on your AppSuite. The article will show you how to package your code and copy from OX source code / directories.<br />
<br />
Since the AppSuite product consists of a server and a UI, you also need a working backend (AppSuite application server) to communicate with. <br />
Therefor you should run [[AppSuite:Appserver | Appserver]] using an existing OX AppSuite server and (with local parts of the AppSuite) automaticly get the recent stable source packages from the AppSuite servers. For using your namespace as a source for hosting your app, simply add the build-path of your app as an parameter while running appserver.<br />
<br />
=== What's next ===<br />
No Idea what to do first? Read our [[AppSuite:GettingStarted | GettingStarted guide]] to have a step-by-step introduction about how to install the SDK, use the Build System, write your first app and get it running.</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:UI_build_system&diff=16212AppSuite:UI build system2013-10-24T13:32:46Z<p>Mark.schmidts: /* Installing */</p>
<hr />
<div>{{Stability-experimental}}<br />
<br />
<div class="title">Build System</div><br />
<br />
'''Abstract:''' This document describes the build system of OX App Suite. It is intended for app developers who use the build system to create apps as well as for OX App Suite developers who not only use the build system but also may wish to extend it.<br />
<br />
The build system is used to create source archives from source files. These source archives can be used to compile installable packages for various Linux distributions. The build system can generate archives for the core UI as well as for independently installed apps.<br />
<br />
The OX App Suite build system uses [https://github.com/mde/jake Jake], a port of Rake from Ruby to [http://nodejs.org Node.js]. Both Rake and Jake are dependency-based build systems like Make, which allows quick incremental builds. But unlike Make, Jake doesn't have its own syntax. Instead, it provides an API in JavaScript. The API is used not only to specify dependencies between files using a full programming language, but also to implement the generation of files in the same language. This allows easy implementation of complex build systems, of which the OX App Suite build system is an example. Using the same language for the developed project and for its build system also allows any core developer to quickly extend the build system without having to switch to another language.<br />
<br />
== Using the Build System ==<br />
<br />
While easily extensible, most of the time the build system will be used as-is. This chapter describes how to set up and use the build system to develop apps and the OX App Suite core.<br />
<br />
All command examples are given for the Debian operating system. The instructions should work similarly on other POSIX systems. The first character of each command indicates whether it should be executed as root (#) or as a normal user ($).<br />
<br />
== Installing ==<br />
<br />
Installing the right environment for running the <code>appserver</code> and the UI build system is described in [[AppSuite:GettingStarted#Installing | the getting started article]].<br />
<br />
== Running ==<br />
<br />
The build system is executed by invoking the command <code>build-appsuite</code>. Similar to most build systems, the build system can perform multiple tasks, which are specified as parameters on the command line. Each task can require any number of parameters. These parameters can be specified either on the command line, using the syntax <code>name=value</code>, or as environment variables.<br />
<br />
If present, the file <code>local.conf</code> is sourced by a shell script before the build process starts. This file can export environment variables which are specific to the local system, without checking them into a version control system. Typically, it defines values for <code>[[#builddir|builddir]]</code> and <code>[[#debug|debug]]</code>.<br />
<br />
Since the build system is based on Jake, it also accepts all other Jake options. In addition, the environment variable <code>$nodeopts</code> can be used to pass command line parameters to Node.js. One of the most useful parameters is <code>--debug-brk</code>, which can be used to debug the build system.<br />
<br />
When developing external apps, the build system must be run from the top directory of the app's source. As a safety precaution, execution is aborted if the subdirectory <code>apps</code>, which usually contains JavaScript source code, is not found. This Article is written assuming, you're working in your workspace directory, containing the subfolder <code>apps</code>.<br />
<br />
== Workflow ==<br />
<br />
The build system is used not only to create source archives for packaging. It can also directly install and update the built UI in a directory during development, help with the setup of the source of a new external app and more. While all of these tasks are described in the reference section, daily work involves just a few of them.<br />
<br />
=== Create packaging metadata ===<br />
<br />
The first task which should be executed when creating a new external app is <code>[[#init-packaging|init-packaging]]</code>. It creates packaging metadata in the current directory. It requires the parameter <code>package</code> to specify the package name in the generated files. All subsequent tasks will automatically extract the package name from the files generated by <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
Before execution, the <code>apps</code> subdirectory must be created. It indicates that the current directory is actually a valid source directory.<br />
<br />
$ mkdir apps<br />
$ build-appsuite init-packaging package=example-app<br />
Build path: build<br />
Build version: 0.0.1-1.20130424.123835<br />
<br />
Version [0.0.1]: <br />
<br />
Maintainer (Name <e-mail>): Maintainer <maintainer@example.com><br />
<br />
Copyright line [2013 Open-Xchange, Inc]: <br />
<br />
License name [CC-BY-NC-SA-3.0]: <br />
<br />
Short description: Hello World app to demonstrate usage of the build system<br />
<br />
The task presents a number of interactive prompts to get the necessary information about the generated packages. The entered values should follow the Debian Maintainer's Guide. Some or even all prompts can be skipped by explicitly specifying the information as a build variable. The list of variable names is available in the reference of <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
After the task is finished, the generated files can be customized manually to account for any additional packaging requirements.<br />
<br />
=== Building apps ===<br />
<br />
To have an easy example about how to write, build and host your javascript code, please have a look at the [[AppSuite:GettingStarted | GettingStarted article]].<br />
<br />
==== JSHINT ====<br />
<br />
One step of the build process is running jshint to statically analyse the sources for certain errors. JSHint is configured with (what we think) sane defaults, but if you want to configure your own rules, edit <code>.jshintrc</code> in your project`s root folder, according to your needs.<br />
<br />
=== default ===<br />
<br />
The default task is used instead of the app task when building the core OX App Suite. Since it is the default Jake task, it is not necessary to specify it on the command line when it's the only task.<br />
<br />
The top directory of OX App Suite source code includes the script <code>build.sh</code>, which should be used instead of calling a potentially unrelated version of <code>build-appsuite</code>. The script changes the current directory to its own, so that it can be called from any directory.<br />
<br />
$ web/ui/build.sh<br />
<br />
=== clean ===<br />
<br />
The build system uses dependencies and file timestamps to decide which files to rebuild. This assumes that any change to a file increases its timestamp to a value which is greater than the timestamp of any existing file. When this assumption is violated (e.g. after switching to a different source control branch with older files) it may become necessary to rebuild everything to restore the assumption about timestamps. The simplest way to achieve this is the clean task, which simply deletes all generated files.<br />
<br />
WARNING: This can be potentially dangerous, since the clean task simply deletes the directories specified by the variables builddir, destDir, l10nDir, manifestDir, and helpDir.<br />
<br />
=== dist ===<br />
<br />
When the app is ready to be shipped, or rather all the time on a continuous build system, the app needs to be packaged in a format suitable for installation on a production system. Since there already exist tools to create packages from suitably arranged source code archives, the OX App Suite build system merely prepares such source archives.<br />
<br />
The dist task creates an archive with the source (the one ending in .orig.tar.bz2) and a few additional files necessary for Debian packaging. RPM packages can be generated using the same source archive and the .spec file created by init-packaging. The version of the package is extracted from the newest entry in the file debian/changelog.<br />
<br />
Debian packages can also be generated manually either from the temporary directory left behind by dist, or even directly from the source tree. The second option pollutes the source tree with generated files, so it is not recommended, although the .gitignore file created by init-packaging can handle these generated files.<br />
<br />
$ build-appsuite dist<br />
$ ls tmp/packaging/<br />
example-app-0.0.1 example-app_0.0.1-1.dsc<br />
example-app_0.0.1-1.debian.tar.bz2 example-app_0.0.1.orig.tar.bz2<br />
$ cd tmp/packaging/example-app-0.0.1/<br />
$ dpkg-buildpackage -b<br />
<br />
== Reference ==<br />
<br />
=== Variables ===<br />
<br />
==== BASEDIR ====<br />
The top directory of the build system.<br />
<br />
<b>Used by:</b> all tasks.<br />
<br />
<b>Default:</b> installation directory of the build system<br />
<br />
Required to build external apps, since in this case, the build<br />
system is not installed in the current directory. This variable is<br />
automatically set as an environment variable by the build system<br />
executable based on <code>$OX_APPSUITE_DEV</code>.<br />
<br />
==== branch ====<br />
The Subversion branch of the CLDR to checkout.<br />
<br />
<b>Used by:</b> <code>update-i18n</code>.<br />
<br />
==== builddir ====<br />
The target directory for generated files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>, <code>docs</code>,<br />
<code>jakedeps</code>.<br />
<br />
Default: <code>build</code><br />
<br />
==== copyright ====<br />
The copyright line to be included in packaging metadata.<br />
<br />
<b>Used by:</b> <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
<b>Example:</b> <code>2012 Open-Xchange, Inc</code><br />
<br />
==== coreDir ====<br />
Location of OX App Suite UI files.<br />
<br />
<b>Used by:</b> <code>[[#app|app]]</code>, <code>[[#default|default]]</code>.<br />
<br />
<b>Default:</b> same as <code>[[#builddir|builddir]]</code><br />
<br />
Some tasks depend on installed files from the OX App Suite. When building external apps, <code>[[#coreDir|coreDir]]</code> specified the directory which contains these files.<br />
<br />
Currently, this parameter is used to compile <code>.less</code> files for every installed theme. This can be disabled by setting <code>[[#skipLess|skipLess]]</code>.<br />
<br />
==== debug ====<br />
Enables a debug build.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
To simplify debugging of OX App Suite, compression of source code<br />
can be disabled by specifying <code>on</code>, <code>yes</code>,<br />
<code>true</code> or <code>1</code>.<br />
<br />
==== description ====<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
The description of the app to be included in packaging metadata.<br />
<br />
==== destDir ====<br />
Output directory for source archives created by<br />
the <code>dist</code> task.<br />
<br />
<b>Used by:</b> <code>clean</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> <code>tmp/packaging</code><br />
<br />
==== disableStrictMode ====<br />
Removes all <code>"use strict"</code> directives from processed<br />
JavaScript code.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
Some debugging tools which use code instrumentation have problems<br />
when the debugged code uses strict mode. This setting enables code<br />
processing even whe using <code>debug</code> mode, so line numbers<br />
will not match the original source code.<br />
<br />
==== forceDeb ====<br />
Whether an error during the generation of Debian source packages is an error.<br />
<br />
<b>Used by:</b> <code>dist</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This is useful when Debian packages are generated automatically, and a failure of <code>dpkg-source</code> is also a failure of the entire build. By default it merely produces a warning.<br />
<br />
==== from ====<br />
The root of the printed dependency tree between Jake tasks.<br />
<br />
<b>Used by:</b> <code>jakedeps</code>.<br />
<br />
==== helpDir ====<br />
The location of online help files.<br />
<br />
<b>Used by:</b> <code>clean</code>, <code>default</code>,<br />
<code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
If the value contains the string <code>@lang@</code>, it will be<br />
replaced by the lowercase language code (e.g. <code>en-us</code>) to<br />
allow per-language directories.<br />
<br />
==== l10nDir ====<br />
The location of compiled l10n files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
If the value contains the string <code>@lang@</code>, it will be<br />
replaced by the lowercase language code (e.g. <code>en-us</code>) to<br />
allow per-language directories.<br />
<br />
==== license ====<br />
File name of the full text of the distribution license.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Default:</b> based on <code>licenseName</code>.<br />
<br />
==== licenseName ====<br />
Name of the distribution license to be included in packaging<br />
metadata.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Default:</b> <code>CC-BY-NC-SA-3.0</code><br />
<br />
==== manifestDir ====<br />
The location of the combined manifest file.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
==== maintainer ====<br />
Name and email address of the package maintainer.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Format:</b> <code><var>Name</var> &lt;<var>email</var>&gt;</code><br />
<br />
==== package ====<br />
The name of the package for the built app.<br />
<br />
<b>Used by:</b> all tasks.<br />
<br />
<b>Default:</b> the package name in the first line of<br />
<code>debian/changelog</code><br />
<br />
Since the name of the manifest file contains the package name and it<br />
is required to determine build dependencies, the package name must<br />
be always known. This means either <code>debian/changelog</code><br />
must exist and contain at least one entry, or the parameter must be<br />
explicitly specified.<br />
<br />
==== reverse ====<br />
Reverses the direction of printed dependencies.<br />
<br />
<b>Used by:</b> <code>deps</code>.<br />
<br />
When specified, the <code>deps</code> task prints modules which<br />
depend on the specified modules, instead of modules on which<br />
the specified module depends.<br />
<br />
==== revision ====<br />
Revision number of the package for the app.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>,<br />
<code>dist</code>.<br />
<br />
<b>Default:</b> <code>1</code><br />
<br />
The revision number must increase with each rebuild of the same<br />
version to enable the creation of unique version strings. These are<br />
required in package names and to control content caching in clients.<br />
<br />
==== root ====<br />
Specifies for which module to print the dependencies.<br />
<br />
<b>Used by:</b> <code>deps</code>.<br />
<br />
<b>Default:</b> print all roots<br />
<br />
If specified, only the dependencies of the specified module are<br />
printed. Otherwise, the dependencies of all modules are printed.<br />
<br />
==== skipDeb ====<br />
Whether to skip the generation of Debian source packages.<br />
<br />
<b>Used by:</b> <code>dist</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This is useful when Debian packages are not required and/or<br />
<code>dpkg-source</code> is not available, e.g. on RPM based<br />
systems.<br />
<br />
Even when using this flag, at least the file<br />
<code>debian/changelog</code> is still required, because it is used<br />
to store the package name and version. <br />
<br />
==== skipLess ====<br />
Whether to skip the preprocessing of LessCSS files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This flag skips the generation of CSS files in<br />
the <code>apps/themes/*/less</code> directories of all themes.<br />
It is used by the packaging system, where the LessCSS files are<br />
precompiled after installation on the target system instead of<br />
while building the package.<br />
<br />
==== tag ====<br />
The Subversion tag of the CLDR to checkout.<br />
<br />
<b>Used by:</b> <code>update-i18n</code>.<br />
<br />
==== to ====<br />
The leaf task in the printed dependency path between Jake tasks.<br />
<br />
<b>Used by:</b> <code>jakedeps</code>.<br />
<br />
When specified, only a single path from the root to the leaf task is<br />
printed (in reverse order).<br />
<br />
==== version ====<br />
Version number of the app.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>,<br />
<code>dist</code>, <code>init-packaging</code>.<br />
<br />
<b>Default:</b> <code>0.0.1</code><br />
<br />
The version should consist of a major, minor and patch version<br />
separated by dots.<br />
<br />
=== Tasks ===<br />
<p><br />
An up-to-date list of tasks can be printed using the -T command line option.<br />
<br />
==== app ====<br />
Builds an external app.<br />
<br />
<b>Variables:</b> <code>[[#BASEDIR|BASEDIR]]</code>, <code>[[#builddir|builddir]]</code>, <code>[[#coreDir|coreDir]]</code>, <code>[[#debug|debug]]</code>, <code>[[#disableStrictMode|disableStrictMode]]</code>, <code>[[#l10nDir|l10nDir]]</code>, <code>[[#manifestDir|manifestDir]]</code>, <code>[[#package|package]]</code>, <code>[[#revision|revision]]</code>, <code>[[#version|version]]</code>.<br />
<br />
This is the main task used to build external apps.<br />
<br />
It works without explicitly specifying any variables, but during<br />
development, <code>[[#builddir|builddir]]</code> is usually pointed to<br />
the directory of a locally installed OX App Suite UI to avoid<br />
additional copying steps. For debugging, <code>[[#debug|debug]]</code> is also<br />
often used. Note that <code>[[#clean|clean]]</code> must be called when<br />
changing any of the variables.<br />
<br />
==== clean ====<br />
Removes all generated files.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>destDir</code>, <code>l10nDir</code>,<br />
<code>manifestDir</code>, <code>package</code>.<br />
<br />
This task should be executed before a normal build using<br />
<code>app</code> or <code>default</code> after changing any build<br />
variables and after a switch between Git branches. Normal<br />
incremental builds can miss changed files if a branch switch<br />
replaces files by older versions.<br />
<br />
==== default ====<br />
Builds OX App Suite.<br />
<br />
<b>Variables:</b> <code>[[#BASEDIR|BASEDIR]]</code>, <code>[[#builddir|builddir]]</code>, <code>[[#debug|debug]]</code>, <code>[[#disableStrictMode|disableStrictMode]]</code>, <code>[[#l10nDir|l10nDir]]</code>, <code>[[#manifestDir|manifestDir]]</code>, <code>[[#package|package]]</code>, <code>[[#revision|revision]]</code>, <code>[[#version|version]]</code>.<br />
<br />
This is the main task to build OX App Suite. Since it is the default<br />
Jake task, it does not need to be specified explicitly on<br />
the command line when it is the only task.<br />
<br />
It works without explicitly specifying any variables, but during<br />
development, <code>[[#builddir|builddir]]</code> is usually pointed to<br />
a directory which is accessible to a local web server. For<br />
debugging, <code>[[#debug|debug]]</code> is also often used. Note that<br />
<code>[[#clean|clean]]</code> must be called when changing any of<br />
the variables.<br />
<br />
==== deps ====<br />
Prints module dependencies.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>package</code>,<br />
<code>reverse</code>, <code>root</code>.<br />
<br />
This task visualizes dependencies of RequireJS modules. It prints<br />
a tree of dependencies to <code>stdout</code>.<br />
<br />
If <code>root</code> is specified, then only the dependencies of<br />
that module are printed. Otherwise, the dependencies of all modules,<br />
on which no other module depends are printed in sequence. <br />
<br />
If <code>reverse</code> is specified, then this task prints<br />
dependants instead of dependencies, i.e. modules which depend on<br />
the specified module instead of modules on which the specified<br />
module depends.<br />
<br />
==== dist ====<br />
Creates source packages.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>destDir</code>, <code>forceDeb</code>, <code>l10nDir</code>,<br />
<code>manifestDir</code>, <code>package</code>,<br />
<code>revision</code>, <code>skipDeb</code>,<br />
<code>version</code>.<br />
<br />
This task cleans the source tree by calling <code>clean</code> and<br />
packs the source into an archive which can be used to create Debian<br />
and RPM packages. The necessary Debian metadata is created alongside<br />
the source archive. All files necessary for Debian packaging are<br />
placed in the directory specified by <code>destDir</code>.<br />
The generated <code>.orig.tar.bz2</code> archive can also be used<br />
together with the <code>.spec</code> file to generate RPM packages.<br />
<br />
Unless the variable <code>skipDeb</code> is set to<br />
<code>true</code>, the program <code>dpkg-source</code> is required<br />
by this task. It is used to generate Debian-specific packaging<br />
metadata.<br />
<br />
==== init-packaging ====<br />
Initializes packaging information for a new app.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>copyright</code>,<br />
<code>description</code>, <code>license</code>,<br />
<code>licenseName</code>, <code>maintainer</code>,<br />
<code>package</code>, <code>version</code>.<br />
<br />
This task is the first task called when starting with<br />
the development of a new external app. The directory from which it<br />
is called must already contain at least the <code>apps</code><br />
subdirectory. This is also the only task where<br />
the <code>package</code> variable must be specified explicitly.<br />
Afterwards, the package name is looked up automatically in the file<br />
<code>debian/changelog</code>, which is created by this task.<br />
<br />
The variables <code>version</code>, <code>maintainer</code>,<br />
<code>copyright</code>, <code>licenseName</code>,<br />
<code>license</code>, and <code>description</code> are required to<br />
fill out all necessary packaging metadata. Any of these variables<br />
which are not specified explicitly will cause an interactive prompt.<br />
This avoids the need to remember the list of variables before one<br />
can start developing an app.<br />
<br />
==== jakedeps ====<br />
Shows the dependency chain between two Jake tasks.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>from</code>,<br />
<code>package</code>, <code>to</code>.<br />
<br />
This task visualized dependencies between Jake tasks. The variable<br />
<code>from</code> specifies the root of a dependency tree, with all<br />
dependencies of <code>from</code> as inner and leaf nodes. If<br />
<code>to</code> is not specified, then that entire tree is printed.<br />
<br />
If <code>to</code> is also specified, then only the first found<br />
dependency path from <code>from</code> to <code>to</code> is<br />
.printed with <code>to</code> at the top and <code>from</code> at<br />
the bottom.<br />
<br />
==== merge ====<br />
Updates all <code>.po</code> files with the generated<br />
<code>ox.pot</code>.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>debug</code>, <code>package</code>, <code>revision</code>,<br />
<code>version</code>.<br />
<br />
This task updates the list of extracted i18n strings in<br />
<code>ox.pot</code> and calls the GNU Gettext tool<br />
<code>msgmerge</code> for every language in <code>i18n/*.po</code>.<br />
<br />
<code>i18n/en_US.po</code> is not updated by this task because the original strings are already in the <code>en_US</code> locale. It would only end up with every translation mapping every string to itself. The only entries in that file should be for cases when the <code>en_US</code> text is not a suitable fallback for missing translations. The original string in such a case would be something internationally appropriate (e.&nbsp;g. a date written as "2013-01-01" instead of "01/01/2013") and <code>i18n/en_US.po</code> would contain a translation.<br />
<br />
==== update-i18n ====<br />
Updates CLDR data in the source tree.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>branch</code>,<br />
<code>package</code>, <code>tag</code>.<br />
<br />
This task downloads data from the Unicode CLDR and updates date<br />
translations for all languages in <code>i18n/*.po</code>.<br />
<br />
The exact version of CLDR data is specified as Suubversion tag or<br />
branch by the variables <code>tag</code> and <code>branch</code>,<br />
respectively. If neither is specified, then the Subversion trunk is<br />
checked out. If both are specified, <code>tag</code> is used.<br />
<br />
==== verify-doc ====<br />
Generates a documentation skeleton for extension points.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>package</code>.<br />
<br />
This task is still under development. Currently, it creates a list of all extension points, which have a constant name in the source code. In the future it is supposed to update an existing list instead of overwriting it, and to handle non-constant extension point names.<br />
<br />
The list of extension points is stored as an HTML snippet in <code>doc/extensionpoints.html</code>.<br />
<br />
<br />
[[Category:AppSuite]]<br />
[[Category:UI]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:GettingStarted_7.4.2&diff=16210AppSuite:GettingStarted 7.4.22013-10-24T13:22:56Z<p>Mark.schmidts: /* Writing */</p>
<hr />
<div><div class="title">Getting Started</div><br />
<br />
__TOC__<br />
<br />
Hello and welcome to OX App Suite development. This document will get you started to develop your first own app for OX App Suite with a minimal setup. We will look at the steps necessary but will also tempt you to learn more by linking you to some more in-depth documentation about these topics. Depending on how you wound up reading this page, you will probably have already completed some of the steps below.<br />
<br />
== Installing ==<br />
<br />
First, you need to install some tools which are necessary for UI development. For now, the simplest way is to download the source of the OX App Suite UI. Since the source code is kept in a [http://git-scm.com/ Git] repository, the source is downloaded using <tt>git</tt>:<br />
<br />
$ git clone --depth 1 -b releae-7.4.1 https://code.open-xchange.com/git/wd/frontend/web<br />
<br />
This downloads the latest version and unpacks it into a subdirectory <tt>web</tt> in the current directory. To simplify calling of scripts contained in the ui/bin directory, you should add it to your <tt>$PATH</tt>:<br />
<br />
$ export PATH="$PATH:$(pwd)/web/ui/bin"<br />
<br />
== Preparing ==<br />
<br />
=== Create Workspace ===<br />
<br />
In order to have a proper space for your app/plugin create a workspace prospectivly containing all your code.<br />
This folder should contain the subfolder <tt>apps</tt>.<br />
The following article is written assuming, you're working in your workspace directory.<br />
In this example we will create our own workspace called <tt>example-workspace</tt> and add the suiteable subdirectory <tt>apps</tt> for our code: <br />
<br />
$ mkdir example-workspace<br />
$ cd example-workspace<br />
$ mkdir apps<br />
<br />
=== Packaging ===<br />
To keep written plugins/apps easy-to-distribute OX uses [[AppSuite:UI_build_system | the UI Build System]] packaging new components. Before writing your first lines of code initialize the package to gather information about the app/plugin you're writing:<br />
$ build-appsuite init-packaging package=example-app<br />
<br />
Build path: build<br />
Build version: 0.0.1-1.20130424.123835<br />
<br />
Version [0.0.1]: <br />
<br />
Maintainer (Name <e-mail>): Maintainer <maintainer@example.com><br />
<br />
Copyright line [2013 Open-Xchange, Inc]: <br />
<br />
License name [CC-BY-NC-SA-3.0]: <br />
<br />
Short description: Hello World app<br />
<br />
The task presents a number of interactive prompts to get the necessary information about the generated packages. The entered values should follow the Debian Maintainer's Guide. Some or even all prompts can be skipped by explicitly specifying the information as a build variable. The list of variable names is available in the reference of <code>[[AppSuite:UI_build_system#init-packaging|init-packaging]]</code>.<br />
<br />
After the task is finished, the generated files can be customized manually to account for any additional packaging requirements.<br />
<br />
== Writing ==<br />
<br />
As an example, let's create a small app and build it. It requires only two files: <code>example-workspace/apps/com.example/main.js</code> for the source code of the app<br />
<br />
<pre class="language-javascript"> <br />
define('com.example/main', function () {<br />
'use strict';<br />
var app = ox.ui.createApp({ name: 'com.example' });<br />
app.setLauncher(function () {<br />
var win = ox.ui.createWindow({<br />
name: 'com.example',<br />
title: 'Hello World App'<br />
});<br />
app.setWindow(win);<br />
win.nodes.main.append($('<h1>').text('Hello, World!'));<br />
win.show();<br />
});<br />
return { getApp: app.getInstance };<br />
});<br />
</pre><br />
<br />
and <code>example-workspace/apps/com.example/manifest.json</code> for the [[AppSuite:UI_manifests_explained | manifest]]:<br />
<br />
<pre class="language-javascript">{ title: 'Hello World App' }</pre><br />
<br />
While developing always keep in mind, that there is an [[AppSuite:Debugging_the_UI | article about debugging the user interface]] which helps you avoiding and fixing typical errors.<br />
<br />
== Building ==<br />
<br />
This step will process your app, checking the source code for syntax errors and compressing it, to make it run error-free and fast. Calling this command will also write the processed source to the a subdirectory called <tt>build</tt> in your workspace, containing also the apps-directory with the original source code.<br />
<br />
While you're in the folder containing <tt>apps</tt>-subdirectory <tt>example-workspace</tt>, using the [[AppSuite:UI_build_system | the UI Build System]] makes building the app is as easy as calling:<br />
<br />
$ build-appsuite app<br />
<br />
== Running ==<br />
<br />
=== Hosting the app ===<br />
For quickest round-trip times, the directory with the generated files in <tt>build</tt>-folder should be made available via the [[AppSuite:Appserver|appserver]] tool, which is also part of the [[#Installing | installed SDK]]. Your OX App Suite installation will use <code>appserver</code> use as upstream server, Assuming you are calling <code>appserver</code> from your workspace, and using [http://ox.io/ ox.io] as server:<br />
<br />
<nowiki>$ appserver --server=https://www.ox.io/appsuite/ build</nowiki><br />
<br />
This command will host your app locally. Once you started it, it will always have to run in the background, making all changes within the given build-directories visible. To add the build path of an other workspace, stop appserver and run the upper command again appending the other directory after a white space.<br />
<br />
WARNING: Take care that build variables like <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or <code>[[AppSuite:UI_build_system#manifestDir|manifestDir]]</code> are not set during development. Otherwise, you will have to specify their directories manually for <code>appserver</code>. Also, the <code>[[AppSuite:UI_build_system#clean|clean]]</code> task will delete these directories and all their contents! In general, don't point <code>[[AppSuite:UI_build_system#builddir|builddir]]</code> or any other <code>*Dir</code> variables at existing directories.<br />
<br />
=== Testing the app ===<br />
<br />
Once made your app available, you can access OX App Suite opening your browser with this address:<br />
http://localhost:8337/appsuite<br />
<br />
Then simply run this command in your browser's javascript console to open the hello world application:<br />
<pre class="language-javascript"><br />
ox.launch("com.example/main")<br />
</pre><br />
<br />
=== Development cycle ===<br />
<br />
Once successfully tested your first app, you will probably continue developing it. <br />
Keep in mind that after [[#Writing | writing your code]], you will always need to [[#Building | build the app]] and have your [[#Hosting the app | Appserver]] running.<br />
<br />
== Further Reading ==<br />
* You just build your first app for OX App Suite, keep in mind that there [[DevelopingTheUI#What_can_i_build.3F | quite a few options]] how you can develop for OX App Suite.<br />
* It's highly recommended to gain more knowledge about all the benefits [[AppSuite:UI_build_system | the UI build system]] and [[AppSuite:Appserver|the Appserver]] are providing you for developing OX App Suite.<br />
* If you're stuck somewhere, the article about [[AppSuite:Debugging_the_UI | debugging the UI]] might help you.<br />
* Get a better overview about [[DevelopingTheUI | developing the user inferface]].</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Creating_a_settings_section_in_AppSuite_settings&diff=16206AppSuite:Creating a settings section in AppSuite settings2013-10-24T11:26:56Z<p>Mark.schmidts: </p>
<hr />
<div><div class="title">Creating a settings section in AppSuite settings</div><br />
<br />
This article explains how to add an settings section into AppSuite settings. You can also [[AppSuite:Embedding_your_settings_into_AppSuite_settings | implement your own settings using iframes]]. <br />
<br />
<br />
__TOC__ <br />
<br />
== Folder structure ==<br />
Assuming you got an app or plugin in a folder like <code>com.example/helloWorld</code> for which you want to implement settings in AppSuite, you will need a new subfolder called <code>settings</code>. So <code>com.example/helloWorld/settings</code> will prospectively contain the files managing your settings.<br />
<br />
== File Structure ==<br />
=== Manifest ===<br />
Creating a [[AppSuite:UI_manifests_explained | manifest]] is quite easy, writing the following into <code>com.example/helloWorld/settings/manifest.json</code> to load your settings, once AppSuite loads it's settings<br />
<br />
<pre class="language-javascript"><br />
{<br />
namespace: ['io.ox/settings/main']<br />
}<br />
</pre><br />
<br />
=== Defaults ===<br />
<code>com.example/helloWorld/settings/default.js</code> should contain your default settings, so an example setting the variable <code>exampleBoolean</code> to <code>false</code> and <code>exampleInteger</code> to 15 might be<br />
<pre class="language-javascript"><br />
define('com.example/helloWorld/settings/defaults', [], function () {<br />
<br />
'use strict';<br />
<br />
// define the default values for your settings here<br />
var settingsDefaults = {<br />
exampleBoolean: false,<br />
exampleInteger: 15<br />
};<br />
<br />
return settingsDefaults;<br />
});<br />
</pre><br />
<br />
=== Model ===<br />
<code>com.example/helloWorld/settings/model.js</code> contains an example of a simple default model, which you can use for your first settings<br />
<br />
<pre class="language-javascript"><br />
define('plugins/mail/AdvertOxMail/settings/model',<br />
['settings!plugins/mail/AdvertOxMail'], function (settings) {<br />
<br />
'use strict';<br />
<br />
// Very simple default model<br />
var exampleModel = Backbone.Model.extend({<br />
initialize: function (options) {<br />
<br />
},<br />
<br />
save: function () {<br />
settings.save(this.attributes);<br />
},<br />
<br />
destroy: function () {<br />
<br />
}<br />
});<br />
return exampleModel;<br />
});<br />
</pre><br />
<br />
=== Register ===<br />
Create a file called <code>com.example/helloWorld/settings/register.js</code> to extend the AppSuite settings and implement your own. <br />
<br />
The Head should look like this:<br />
<pre class="language-javascript"><br />
define("com.example/helloWorld/settings/register",<br />
['io.ox/core/extensions',<br />
'settings!com.example/helloWorld'<br />
],<br />
function (ext, settings) {<br />
'use strict';<br />
</pre><br />
<br />
Extend the panel which stores the different setting categories:<br />
<pre class="language-javascript"><br />
ext.point("io.ox/settings/pane").extend({<br />
id: 'com.example/helloWorld',<br />
title: 'Hello World Settings,<br />
ref: 'com.example/helloWorld',<br />
loadSettingPane: false,<br />
index: 400,<br />
lazySaveSettings: true<br />
});<br />
</pre><br />
<br />
And now extend the extension point which was established through reffering to <code>com.example/helloWorld</code> above.<br />
<code>(ref: 'com.example/helloWorld')</code><br />
<pre class="language-javascript"><br />
ext.point("com.example/helloWorld/settings/detail").extend({<br />
index: 50,<br />
id: 'extensions',<br />
draw: function () {<br />
var content=$('div').addClass('content');<br />
content.text('Add form elements to control your settings here');<br />
this.append(content);<br />
}<br />
});<br />
});<br />
</pre><br />
<br />
== Stuck somewhere? ==<br />
You got stuck with a problem while developing? OXpedia might help you out with the article about [[AppSuite:Debugging_the_UI | debugging the UI]].</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Creating_a_settings_section_in_AppSuite_settings&diff=16205AppSuite:Creating a settings section in AppSuite settings2013-10-24T11:26:12Z<p>Mark.schmidts: /* File Structure */</p>
<hr />
<div><div class="title">Creating a settings section in AppSuite settings</div><br />
<br />
This article explains how to add an settings section into AppSuite settings. You can also [[AppSuite:Embedding_your_settings_into_AppSuite_settings | implement your own settings using iframes]]. <br />
<br />
<br />
__TOC__ <br />
<br />
== Folder structure ==<br />
Assuming you got an app or plugin in a folder like <code>com.example/helloWorld</code> for which you want to implement settings in AppSuite, you will need a new subfolder called <code>settings</code>. So <code>com.example/helloWorld/settings</code> will prospectively contain the files managing your settings.<br />
<br />
== File Structure ==<br />
=== Manifest ===<br />
Creating a [[AppSuite:UI_manifests_explained | manifest]] is quite easy, writing the following into <code>com.example/helloWorld/settings/manifest.json</code> to load your settings, once AppSuite loads it's settings<br />
<br />
<pre class="language-javascript"><br />
{<br />
namespace: ['io.ox/settings/main']<br />
}<br />
</pre><br />
<br />
=== Defaults ===<br />
<code>com.example/helloWorld/settings/default.js</code> should contain your default settings, so an example setting the variable <code>exampleBoolean</code> to <code>false</code> and <code>exampleInteger</code> to 15 might be<br />
<pre class="language-javascript"><br />
define('com.example/helloWorld/settings/defaults', [], function () {<br />
<br />
'use strict';<br />
<br />
// define the default values for your settings here<br />
var settingsDefaults = {<br />
exampleBoolean: false,<br />
exampleInteger: 15<br />
};<br />
<br />
return settingsDefaults;<br />
});<br />
</pre><br />
<br />
=== Model ===<br />
<code>com.example/helloWorld/settings/model.js</code> contains an example of a simple default model, which you can use for your first settings<br />
<br />
<pre class="language-javascript"><br />
define('plugins/mail/AdvertOxMail/settings/model',<br />
['settings!plugins/mail/AdvertOxMail'], function (settings) {<br />
<br />
'use strict';<br />
<br />
// Very simple default model<br />
var exampleModel = Backbone.Model.extend({<br />
initialize: function (options) {<br />
<br />
},<br />
<br />
save: function () {<br />
settings.save(this.attributes);<br />
},<br />
<br />
destroy: function () {<br />
<br />
}<br />
});<br />
return exampleModel;<br />
});<br />
</pre><br />
<br />
=== Register ===<br />
Create a file called <code>com.example/helloWorld/settings/register.js</code> to extend the AppSuite settings and implement your own. <br />
<br />
The Head should look like this:<br />
<pre class="language-javascript"><br />
define("com.example/helloWorld/settings/register",<br />
['io.ox/core/extensions',<br />
'settings!com.example/helloWorld'<br />
],<br />
function (ext, settings) {<br />
'use strict';<br />
</pre><br />
<br />
Extend the panel which stores the different setting categories:<br />
<pre class="language-javascript"><br />
ext.point("io.ox/settings/pane").extend({<br />
id: 'com.example/helloWorld',<br />
title: 'Hello World Settings,<br />
ref: 'com.example/helloWorld',<br />
loadSettingPane: false,<br />
index: 400,<br />
lazySaveSettings: true<br />
});<br />
</pre><br />
<br />
And now extend the extension point which was established through reffering to <code>com.example/helloWorld</code> above.<br />
<code>(ref: 'com.example/helloWorld')</code><br />
<pre class="language-javascript"><br />
ext.point("com.example/helloWorld/settings/detail").extend({<br />
index: 50,<br />
id: 'extensions',<br />
draw: function () {<br />
var content=$('div').addClass('content');<br />
content.text('Add form elements to control your settings here');<br />
this.append(content);<br />
}<br />
});<br />
});<br />
</pre></div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Creating_a_settings_section_in_AppSuite_settings&diff=16204AppSuite:Creating a settings section in AppSuite settings2013-10-24T11:16:29Z<p>Mark.schmidts: /* Register */</p>
<hr />
<div><div class="title">Creating a settings section in AppSuite settings</div><br />
<br />
This article explains how to add an settings section into AppSuite settings. You can also [[AppSuite:Embedding_your_settings_into_AppSuite_settings | implement your own settings using iframes]]. <br />
<br />
<br />
__TOC__ <br />
<br />
== Folder structure ==<br />
Assuming you got an app or plugin in a folder like <code>com.example/helloWorld</code> for which you want to implement settings in AppSuite, you will need a new subfolder called <code>settings</code>. So <code>com.example/helloWorld/settings</code> will prospectively contain the files managing your settings.<br />
<br />
== File Structure ==<br />
=== Manifest ===<br />
Creating a [[AppSuite:UI_manifests_explained | manifest]] is quite easy, writing the following into <code>com.example/helloWorld/settings/manifest.json</code> to load your settings, once AppSuite loads it's settings<br />
<br />
<pre class="language-javascript"><br />
{<br />
namespace: ['io.ox/settings/main']<br />
}<br />
</pre><br />
<br />
=== Register ===<br />
Create a file called <code>com.example/helloWorld/settings/register.js</code> to extend the AppSuite settings and implement your own. <br />
<br />
The Head should look like this:<br />
<pre class="language-javascript"><br />
define("com.example/helloWorld/settings/register",<br />
['io.ox/core/extensions',<br />
'settings!com.example/helloWorld'<br />
],<br />
function (ext, settings) {<br />
'use strict';<br />
</pre><br />
<br />
Extend the panel which stores the different setting categories:<br />
<pre class="language-javascript"><br />
ext.point("io.ox/settings/pane").extend({<br />
id: 'com.example/helloWorld',<br />
title: 'Hello World Settings,<br />
ref: 'com.example/helloWorld',<br />
loadSettingPane: false,<br />
index: 400,<br />
lazySaveSettings: true<br />
});<br />
</pre><br />
<br />
And now extend the extension point which was established through reffering to <code>com.example/helloWorld</code> above.<br />
<code>(ref: 'com.example/helloWorld')</code><br />
<pre class="language-javascript"><br />
ext.point("com.example/helloWorld/settings/detail").extend({<br />
index: 50,<br />
id: 'extensions',<br />
draw: function () {<br />
var content=$('div').addClass('content');<br />
content.text('Add form elements to control your settings here');<br />
this.append(content);<br />
}<br />
});<br />
});<br />
</pre></div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Creating_a_settings_section_in_AppSuite_settings&diff=16203AppSuite:Creating a settings section in AppSuite settings2013-10-24T11:13:51Z<p>Mark.schmidts: Created page with "<div class="title">Creating a settings section in AppSuite settings</div> This article explains how to add an settings section into AppSuite settings. You can also AppSuite..."</p>
<hr />
<div><div class="title">Creating a settings section in AppSuite settings</div><br />
<br />
This article explains how to add an settings section into AppSuite settings. You can also [[AppSuite:Embedding_your_settings_into_AppSuite_settings | implement your own settings using iframes]]. <br />
<br />
<br />
__TOC__ <br />
<br />
== Folder structure ==<br />
Assuming you got an app or plugin in a folder like <code>com.example/helloWorld</code> for which you want to implement settings in AppSuite, you will need a new subfolder called <code>settings</code>. So <code>com.example/helloWorld/settings</code> will prospectively contain the files managing your settings.<br />
<br />
== File Structure ==<br />
=== Manifest ===<br />
Creating a [[AppSuite:UI_manifests_explained | manifest]] is quite easy, writing the following into <code>com.example/helloWorld/settings/manifest.json</code> to load your settings, once AppSuite loads it's settings<br />
<br />
<pre class="language-javascript"><br />
{<br />
namespace: ['io.ox/settings/main']<br />
}<br />
</pre><br />
<br />
=== Register ===<br />
Create a file called <code>com.example/helloWorld/settings/register.js</code> to extend the AppSuite settings and implement your own. <br />
<br />
The Head should look like this:<br />
<pre class="language-javascript"><br />
define("com.example/helloWorld/settings/register",<br />
['io.ox/core/extensions',<br />
'settings!com.example/helloWorld'<br />
],<br />
function (ext, settings) {<br />
'use strict';<br />
</pre><br />
<br />
Extend the panel which stores the different setting categories:<br />
<pre class="language-javascript"><br />
ext.point("io.ox/settings/pane").extend({<br />
id: 'com.example/helloWorld',<br />
title: 'Hello World Settings,<br />
ref: 'com.example/helloWorld',<br />
loadSettingPane: false,<br />
index: 400,<br />
lazySaveSettings: true<br />
});<br />
</pre><br />
<br />
And now extend the extension point which was established through reffering to <code>com.example/helloWorld</code> above.<br />
<code>(ref: 'com.example/helloWorld')</code><br />
<pre class="language-javascript"><br />
ext.point("com.example/helloWorld/settings/detail").extend({<br />
index: 50,<br />
id: 'extensions',<br />
draw: function () {<br />
var content=$('div').addClass('content');<br />
content.text('Add form elements to control your settings here');<br />
this.append(content);<br />
}<br />
});<br />
});<br />
</pre></div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Embedding_your_settings_into_AppSuite_settings&diff=16202AppSuite:Embedding your settings into AppSuite settings2013-10-24T10:31:45Z<p>Mark.schmidts: </p>
<hr />
<div><div class="title">Embedding your settings into AppSuite settings</div><br />
<br />
''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 "Config Jump" of OX6. Not to be confused with [[AppSuite:Creating_a_settings_section_in_AppSuite_settings | simply adding new settings]] into AppSuite<br />
<br />
__TOC__<br />
<br />
<br />
== Declare the page you want to embed ==<br />
<br />
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:<br />
<br />
➜ /opt/open-xchange/etc/settings/configjump.yml<br />
io.ox/settings/configjump//changePlans:<br />
url: "http://localhost/~fla/changePlans.php?token=[token]"<br />
title: “Change Plan”<br />
after: "io.ox/mail"<br />
<br />
''io.ox/settings/configjump'' contains one object per embedded page (e.g. "changePlans"). If you want to add more pages, follow this pattern.<br />
<br />
An object of this type has the following properties:<br />
<br />
* '''url''': The URL to be branched to. The place holder [token] will be replaced by the token you get from the token login system<br />
* '''title''': The title as to be seen on the settings page.<br />
* '''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.<br />
<br />
== Create a secret ==<br />
<br />
Now you just need to declare the app your are about to embed in the backend and you are good to go:<br />
<br />
➜ cat /opt/open-xchange/etc/tokenlogin-secrets<br />
#<br />
# Listing of known Web Application secrets followed by an optional semicolon-separated parameter list<br />
#<br />
# e.g. 1254654698621354; accessPasword=true<br />
#<br />
<br />
# Dummy entry<br />
# 1234-56789-98765-4321; accessPassword=true<br />
12345-phpapp-54321<br />
<br />
This secret, combined with the token, can be traded for a login.<br />
<br />
== Redeem a token ==<br />
<br />
GET /login?action=redeemToken<br />
<br />
* '''token''': The token you want to trade.<br />
* '''secret''': A valid secret for your app.<br />
<br />
This request can be sent by the embedded app to the AppSuite backend to get authorisation info.<br />
<br />
<br />
[[Category:AppSuite]]<br />
<br />
[[Category:UI]][[Category:Backend]]<br />
<br />
[[Category:Administrator]][[Category:Developer]]<br />
<br />
<br />
== Stuck somewhere? ==<br />
You got stuck with a problem while developing? OXpedia might help you out with the article about [[AppSuite:Debugging_the_UI | debugging the UI]].</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Developing_for_the_UI&diff=16201AppSuite:Developing for the UI2013-10-24T10:26:44Z<p>Mark.schmidts: /* What can i build? */</p>
<hr />
<div><div class="title">UI Development for OX AppSuite</div><br />
<br />
__TOC__<br />
<br />
This page contains articles about the inner workings of the web-based graphical user interface. It is aimed at software developers that want to improve on existing features, implement extensions or just gain a general understanding.<br />
<br />
=== Tech Overview ===<br />
All technologies and frameworks used for developing a new component for the AppSuite UI are listed and described in the following article: [[AppSuite:UI developer primer| Skills needed to develop the UI]]<br />
<br />
=== Developing Guidelines ===<br />
While developing code for OX products [[AppSuite:UI Development Style Guide | the UI Developement Style Guide]] helps you writing safe, clear and functional code.<br />
<br />
Designing apps, plugins and widgets running with the right layout, colors, look and feel is a breeze following the guidelines described in [[AppSuite:UI Design Guide | the UI Design Guide]].<br />
<br />
Always keep in mind, that using OX products should be possible for everyone and therefor it's important to follow simple rules regarding [[AppSuite:Accessibility | accessibility]].<br />
<br />
=== Using extension points ===<br />
<br />
Writing apps or plugins for AppSuite will often include extending the existing user interface. AppSuite provides extension points offering you possibilties to add your own contents.<br />
Beginning to develop using extension points? Read this guide first having [[AppSuite:Extending the UI (Hands-on introduction) | a hands-on introduction]] for extending the OX user interface. Get more information and a complete list of [[AppSuite:Extension points |extension points]] offered by OX products.<br />
<br />
=== How to get code ===<br />
Using git as a version version control system getting the code from existing OX products is quite easy.<br />
Simply clone the [[AppSuite:UI build system#Source | UI]] or the [[AppSuite:Backend build system#Source | backend]] repository and start working with it.<br />
<br />
=== What can i build? ===<br />
<br />
If you want to have a simple introduction following easy steps from creating your workspace to actually performing your source code within AppSuite, read our [[AppSuite:GettingStarted | GettingStarted guide]].<br />
<br />
There are several other possibilities available to develop for AppSuite.<br />
<br />
*[[AppSuite:Writing a portal plugin | A portal plugin]] is a widget, which can be used in the 'portal'-section of AppSuite only. Please just check for the right [[AppSuite:Extension points |extension point]] to write a plugin which extends and interacts with other parts of AppSuite. Configuring portal plugins can be achieved by reading [[AppSuite:Configuring portal plugins | this guide]].<br />
<br />
*[[AppSuite:Writing_a_contacts_plugin | A contacts plugin]] let's you modify parts of AppSuite's contact view.<br />
<br />
*[[AppSuite:Using the Upsell widget | Upsell Widget]], to enable the AppSuite user to purchase additional features. <br />
<br />
*[[AppSuite:Writing a simple application | A real application/module]] for AppSuite, which should be displayed full screen and appear as a bread crump in the title bar, take a look at the article about [[AppSuite:Writing a simple application | 'Writing a simple application']].<br />
<br />
*[[AppSuite:Writing a notification area plugin | A notification plugin]] for AppSuite<br />
<br />
*[[AppSuite:Writing a wizard | A wizard]], which can be first time users to show them important informations or configure initial settings for 3rd party applications.<br />
<br />
*[[AppSuite:Creating a settings section in AppSuite settings | Settings plugin]] extending AppSuite settings and creating a new section.<br />
<br />
*[[AppSuite:Embedding your settings into AppSuite settings | Settings plugin]] embedding your own settings section via iframe into AppSuite.<br />
<br />
You got stuck somewhere? There are some hints, which might help you [[AppSuite:Debugging_the_UI | debugging the UI]].<br />
<br />
=== How to get your code running ===<br />
Written your first app/plugin? Using the [[AppSuite:UI build system | UI build system]] will help you to get fast, easy-to-distribute and correct builds running on your AppSuite. The article will show you how to package your code and copy from OX source code / directories.<br />
<br />
Since the AppSuite product consists of a server and a UI, you also need a working backend (AppSuite application server) to communicate with. <br />
Therefor you should run [[AppSuite:Appserver | Appserver]] using an existing OX AppSuite server and (with local parts of the AppSuite) automaticly get the recent stable source packages from the AppSuite servers. For using your namespace as a source for hosting your app, simply add the build-path of your app as an parameter while running appserver.<br />
<br />
=== What's next ===<br />
No Idea what to do first? Read our [[AppSuite:GettingStarted | GettingStarted guide]] to have a step-by-step introduction about how to install the SDK, use the Build System, write your first app and get it running.</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Developing_for_the_UI&diff=16200AppSuite:Developing for the UI2013-10-24T10:23:54Z<p>Mark.schmidts: /* What can i build? */</p>
<hr />
<div><div class="title">UI Development for OX AppSuite</div><br />
<br />
__TOC__<br />
<br />
This page contains articles about the inner workings of the web-based graphical user interface. It is aimed at software developers that want to improve on existing features, implement extensions or just gain a general understanding.<br />
<br />
=== Tech Overview ===<br />
All technologies and frameworks used for developing a new component for the AppSuite UI are listed and described in the following article: [[AppSuite:UI developer primer| Skills needed to develop the UI]]<br />
<br />
=== Developing Guidelines ===<br />
While developing code for OX products [[AppSuite:UI Development Style Guide | the UI Developement Style Guide]] helps you writing safe, clear and functional code.<br />
<br />
Designing apps, plugins and widgets running with the right layout, colors, look and feel is a breeze following the guidelines described in [[AppSuite:UI Design Guide | the UI Design Guide]].<br />
<br />
Always keep in mind, that using OX products should be possible for everyone and therefor it's important to follow simple rules regarding [[AppSuite:Accessibility | accessibility]].<br />
<br />
=== Using extension points ===<br />
<br />
Writing apps or plugins for AppSuite will often include extending the existing user interface. AppSuite provides extension points offering you possibilties to add your own contents.<br />
Beginning to develop using extension points? Read this guide first having [[AppSuite:Extending the UI (Hands-on introduction) | a hands-on introduction]] for extending the OX user interface. Get more information and a complete list of [[AppSuite:Extension points |extension points]] offered by OX products.<br />
<br />
=== How to get code ===<br />
Using git as a version version control system getting the code from existing OX products is quite easy.<br />
Simply clone the [[AppSuite:UI build system#Source | UI]] or the [[AppSuite:Backend build system#Source | backend]] repository and start working with it.<br />
<br />
=== What can i build? ===<br />
<br />
If you want to have a simple introduction following easy steps from creating your workspace to actually performing your source code within AppSuite, read our [[AppSuite:GettingStarted | GettingStarted guide]].<br />
<br />
There are several other possibilities available to develop for AppSuite.<br />
<br />
*[[AppSuite:Writing a portal plugin | A portal plugin]] is a widget, which can be used in the 'portal'-section of AppSuite only. Please just check for the right [[AppSuite:Extension points |extension point]] to write a plugin which extends and interacts with other parts of AppSuite. Configuring portal plugins can be achieved by reading [[AppSuite:Configuring portal plugins | this guide]].<br />
<br />
*[[AppSuite:Writing_a_contacts_plugin | A contacts plugin]] let's you modify parts of AppSuite's contact view.<br />
<br />
*[[AppSuite:Using the Upsell widget | Upsell Widget]], to enable the AppSuite user to purchase additional features. <br />
<br />
*[[AppSuite:Writing a simple application | A real application/module]] for AppSuite, which should be displayed full screen and appear as a bread crump in the title bar, take a look at the article about [[AppSuite:Writing a simple application | 'Writing a simple application']].<br />
<br />
*[[AppSuite:Writing a notification area plugin | A notification plugin]] for AppSuite<br />
<br />
*[[AppSuite:Writing a wizard | A wizard]], which can be first time users to show them important informations or configure initial settings for 3rd party applications.<br />
<br />
*[[AppSuite:Embedding your settings into AppSuite settings | Settings plugin]] extending AppSuite settings and creating a new section.<br />
<br />
*[[AppSuite:Embedding your settings into AppSuite settings | Settings plugin]] embedding your own settings section via iframe into AppSuite.<br />
<br />
You got stuck somewhere? There are some hints, which might help you [[AppSuite:Debugging_the_UI | debugging the UI]].<br />
<br />
=== How to get your code running ===<br />
Written your first app/plugin? Using the [[AppSuite:UI build system | UI build system]] will help you to get fast, easy-to-distribute and correct builds running on your AppSuite. The article will show you how to package your code and copy from OX source code / directories.<br />
<br />
Since the AppSuite product consists of a server and a UI, you also need a working backend (AppSuite application server) to communicate with. <br />
Therefor you should run [[AppSuite:Appserver | Appserver]] using an existing OX AppSuite server and (with local parts of the AppSuite) automaticly get the recent stable source packages from the AppSuite servers. For using your namespace as a source for hosting your app, simply add the build-path of your app as an parameter while running appserver.<br />
<br />
=== What's next ===<br />
No Idea what to do first? Read our [[AppSuite:GettingStarted | GettingStarted guide]] to have a step-by-step introduction about how to install the SDK, use the Build System, write your first app and get it running.</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Appserver&diff=16199AppSuite:Appserver2013-10-24T10:10:23Z<p>Mark.schmidts: /* Use with Apache */</p>
<hr />
<div>{{Stability-unstable}}<br />
<br />
<div class="title">Appserver</div><br />
<br />
The <code>appserver</code> tool is used to develop and test the OX App Suite UI and its plugins with a remote backend. <code>appserver</code> acts as a reverse HTTP proxy for an existing OX App Suite installation and injects the tested JavaScript code in its replies.<br />
<br />
== Installation ==<br />
<br />
The core of <code>appserver</code> is a Node.js script, so if your OS does not provide a <code>nodejs</code> package, you will have to install it manually, either as a [https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager 3rd party package] or directly from [http://nodejs.org/ nodejs.org].<br />
<br />
The installation of the script itself depends on whether you want to make changes to the UI or only develop an external app.<br />
<br />
=== For app developers ===<br />
<br />
If you are developing an app, then you only need the OX App Suite SDK version 7.4 or later. On Linux, it is installed with the package <code>open-xchange-appsuite-dev</code>:<br />
<br />
sudo apt-get install open-xchange-appsuite-dev<br />
<br />
The binaries are installed to <code>/opt/open-xchange-appsuite-dev/bin/</code>. To have them available in a shell, add this directory to the <code>PATH</code> environment variable:<br />
<br />
export PATH=$PATH:/opt/open-xchange-appsuite-dev/bin<br />
<br />
=== For UI developers ===<br />
<br />
If you are a UI developer, or if the SDK is not available for your OS, you will need to clone the UI source and use the tools contained in the <code>ui/bin</code> directory.<br />
<br />
git clone --depth 1 -b <var>develop</var> https://code.open-xchange.com/git/wd/frontend/web<br />
export PATH=$PATH:$(pwd)/web/ui/bin<br />
<br />
The option <code>-b <var>develop</var></code> specifies a git branch. Until version 7.4 is released, the full functionality described in this article is only available in the "develop" branch.<br />
<br />
The option <code>--depth 1</code> prevents the download of the entire history, and reduces the download size from hundreds of MB to less than 20MB. It should not be used by OX App Suite developers since it also prevents <code>git push</code> from working properly.<br />
<br />
== Standalone use ==<br />
<br />
In the simplest case of developing an app or a plugin, all that is needed is an existing OX App Suite installation. Point <code>appserver</code> to the URL of OX App Suite and to the build directory of your app. Assuming you are in the top directory of your app's source code and <code>[[AppSuite:UI build system#builddir|$builddir]]</code> is not set:<br />
<br />
appserver [[#server|--server]]=<nowiki>https://www.ox.io/appsuite/</nowiki> build<br />
<br />
If there are no errors, you can point your browser to http://localhost:8337/appsuite/ to test a version of OX App Suite which includes your app. Do not forget the trailing slash in the URL. Otherwise, the server sends a redirect from <code>/appsuite</code> to <code>/appsuite/</code> and includes its own absolute URL in the redirect.<br />
<br />
You do not need to restart anything after re-building the app, a refresh of the browser page should be enough. If your code doesn’t show up after a refresh, our file cache mighgt not be up-to-date. Until this is fixed in appserver, you can append <code>&debug-js=true</code> to your URL to disable the file cache.<br />
<br />
== Use with Apache ==<br />
<br />
For more complex cases involving testing your own build of the UI, or apps which include static resources (e.&nbsp;g. images), a local web server is required to serve static resources. The following examples use the Apache HTTP Server, but any web server which can act as a reverse HTTP proxy should work (assuming the configuration and <code>.htaccess</code> files are adapted, of course).<br />
<br />
First, make your app visible in Apache. The simplest way is to symlink the <code>[[AppSuite:UI build system#builddir|$builddir]]</code> inside the document root. Assuming the app is in <code>/home/user/myapp</code> and the web server's document root is <code>/var/www</code>:<br />
<br />
sudo ln -s /home/user/myapp/build /var/www/myapp<br />
<br />
In case Apache ignores the symlink, ensure that its configuration directive <code><Directory /var/www/></code> contains "<code>Options FollowSymlinks</code>" or something to that effect.<br />
<br />
Second, configure Apache to request from <code>appserver</code> anything that it can't find locally. This configuration requires at least <code>mod_rewrite</code>, <code>mod_proxy</code> and <code>mod_proxy_http</code> to be enabled. Editing a file like <code>/etc/apache2/sites-enabled/000-default</code> containing the proxy configuration, add the following inside an eventual <code><VirtualHost></code> directive, but outside of any <code><Directory></code> directives:<br />
<br />
RewriteEngine On<br />
ProxyPreserveHost On<br />
<br />
ProxyPassMatch ^/((appsuite|ajax|infostore|publications\<br />
|realtime|servlet|usm-json|webservices)(/.*)?)$ \<br />
<nowiki>http://localhost:8337/$1</nowiki><br />
<br />
RewriteCond %{DOCUMENT_ROOT}/myapp/$2 -f<br />
RewriteRule ^/appsuite/(v=[^,/]+/)?(.*)$ /myapp/$2 [PT]<br />
<br />
Take care configuring apache configuration, proxy definitions might take place in several files. For example <code>/etc/apache2/conf.d/proxy_http.conf</code> does also often contain http proxy configuration, which may differ from the definitions in the file edited above.<br />
<br />
If you want to test multiple apps, use a different directory for each, and repeat the last two lines for each app, substituting the proper values for "<code>myapp</code>". If you are using aliases instead of symlinks then replace <code>%{DOCUMENT_ROOT}</code> with the actual file system path from the <code>Alias</code> directive.<br />
<br />
Now, restart Apache and start <code>appserver</code> adding the path to your simlinked build-path of the app as an parameter.<br />
<br />
sudo apachectl restart<br />
appserver [[#server|--server]]=<nowiki>https://www.ox.io/appsuite/</nowiki> /var/www/myapp<br />
<br />
If there are no errors, you can point your browser to http://localhost/appsuite/ to test a version of OX App Suite which includes your app. You do not need to restart anything after re-building the app, a refresh of the browser page should be enough.<br />
<br />
=== Custom UI builds ===<br />
<br />
To test your own build of the core UI, use <code>/var/www/appsuite</code> as directory, but don't add a <code>RewriteRule</code> for it. Instead, replace "<code>appsuite</code>" with "<code>appsuite/api</code>" in the <code>ProxyPassMatch</code> directive and add a <code><Directory></code> directive like for any other OX App Suite installation:<br />
<br />
<Directory /var/www/appsuite/><br />
Options FollowSymlinks<br />
AllowOverride Indexes FileInfo<br />
</Directory><br />
<br />
== Reference ==<br />
<br />
<code>appserver</code> is a reverse HTTP proxy. It accepts HTTP requests and forwards most of them to another HTTP server. There are currently two exceptions:<br />
* <code>api/apps/load</code> is served from a list of local paths. Only files which could not be found are fetched from the remote HTTP server. This allows to inject the code of a tested app without installing it on the remote server. The list of paths is specified as non-option parameters on the command line. Each path should normally have at least the subdirectories <code>apps</code> and <code>manifests</code>. Each injected file is looked up in the <code>apps</code> subdirectory of each path, in the order in which they appear on the command line, and the first found file is used. If a file is not found in any path, and the <code>[[#server|--server]]</code> option is specified, the file is downloaded from the server.<br />
* <code>api/apps/manifests?action=config</code> is extended by local manifests. This is necessary to enable the tested app in the UI. If no <code>[[#manifests|--manifests]]</code> options are specified, then all files from the <code>manifests</code> subdirectory of each path are combined and added to the manifests from the remote server. Each manifest entry overrides any entries with the same <code>path</code> attribute. Similar to the priority for files, manifest entries from earlier paths override entries from later paths, and local entries override remote entries.<br />
<br />
=== help ===<br />
<br />
Displays a short summary of available options:<br />
<br />
Usage: appserver [OPTION]... [PATH]...<br />
<br />
-h, --help print this help message and exit<br />
-m PATH, --manifests=PATH add manifests from the specified path (default:<br />
the "manifests" subdirectory of every file path)<br />
--path=PATH absolute path of the UI (default: /appsuite)<br />
-p PORT, --port=PORT listen on PORT (default: 8337)<br />
-s URL, --server=URL use an existing server as fallback<br />
-v TYPE, --verbose=TYPE print more information depending on TYPE:<br />
local: local files, remote: remote files,<br />
proxy: forwarded URLs, all: shortcut for all three<br />
-z PATH, --zoneinfo=PATH use timezone data from the specified path<br />
(default: /usr/share/zoneinfo/)<br />
<br />
Files are searched in each PATH in order and requested from the server if not<br />
found. If no paths are specified, the default is /var/www/appsuite/.<br />
<br />
=== manifests ===<br />
<br />
By default, the manifests of an app are collected and put into <code>[[AppSuite:UI build system#builddir|$builddir]]/manifests</code>. Therefore, by default, <code>appserver</code> collects manifests from the <code>manifests</code> subdirectoriy of each file path. Since the destination directory for manifests can be changed by setting <code>[[AppSuite:UI build system#manifestDir|$manifestDir]]</code>, the manifest directories can also be changed in <code>appserver</code> by specifying each directory with a separate <code>--manifests</code> option.<br />
<br />
If at least one <code>--manifests</code> option is specified, the default file paths are not used for manifests at all.<br />
<br />
=== path ===<br />
<br />
By default, URLs belonging to the OX App Suite (i.&nbsp;e. starting with <code>/appsuite/</code>) get mapped to the URL of the <code>[[#server|--server]]</code> parameter, while all other paths get mapped to identical paths on that server to allow services like <code>/publications</code> to work.<br />
<br />
This parameter changes the path of the local OX App Suite URL e.&nbsp;g. to allow testing multiple UIs with the same server.<br />
<br />
=== port ===<br />
<br />
Specifies the port to listen on. The default is 8337. This option might be useful to run multiple instances of <code>appserver</code> at once or when port 8337 is already in use.<br />
<br />
=== server ===<br />
<br />
Specifies the URL of an existing OX App Suite installation. The URL must start with <code>http://</code> or <code>https://</code>. To make forwarding of an HTTPS URL over HTTP possible, <code>appserver</code> removes the <code>Secure</code> attribute from all cookies set by the server.<br />
<br />
This option is required for manifest injection to work, since the intercepted request contains more data than just the manifests.<br />
<br />
=== verbose ===<br />
<br />
Enables verbose output. During normal operation, <code>appserver</code> only writes errors to its console. By specifying this option one or more times, additional output can be enabled, depending on the value of each option:<br />
<br />
; local : The name of every read local file is written to standard output.<br />
; remote : The URL of every request for missing local files is written to standard output.<br />
; proxy : The URL of every client request which is forwarded as-is is written to standard output.<br />
; all : This is just a shortcut for <code>-v local -v remote -v proxy</code>.<br />
<br />
Output lines belonging to the same client request are grouped together and separated from the next request by an empty line.<br />
<br />
=== zoneinfo ===<br />
<br />
Specifies the path to the zoneinfo database. On POSIX systems, the default of <code>/usr/share/zoneinfo/</code> should always work. Even on systems without the database everything should just work if <code>[[#server|--server]]</code> is specified, since any missing files will be fetched from the remote server. This option may still be useful when debugging time zone problems caused by different versions of the zoneinfo database.<br />
<br />
[[Category:AppSuite]]<br />
[[Category:UI]]<br />
[[Category:Developer]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Appserver&diff=16198AppSuite:Appserver2013-10-24T10:06:47Z<p>Mark.schmidts: /* Use with Apache */</p>
<hr />
<div>{{Stability-unstable}}<br />
<br />
<div class="title">Appserver</div><br />
<br />
The <code>appserver</code> tool is used to develop and test the OX App Suite UI and its plugins with a remote backend. <code>appserver</code> acts as a reverse HTTP proxy for an existing OX App Suite installation and injects the tested JavaScript code in its replies.<br />
<br />
== Installation ==<br />
<br />
The core of <code>appserver</code> is a Node.js script, so if your OS does not provide a <code>nodejs</code> package, you will have to install it manually, either as a [https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager 3rd party package] or directly from [http://nodejs.org/ nodejs.org].<br />
<br />
The installation of the script itself depends on whether you want to make changes to the UI or only develop an external app.<br />
<br />
=== For app developers ===<br />
<br />
If you are developing an app, then you only need the OX App Suite SDK version 7.4 or later. On Linux, it is installed with the package <code>open-xchange-appsuite-dev</code>:<br />
<br />
sudo apt-get install open-xchange-appsuite-dev<br />
<br />
The binaries are installed to <code>/opt/open-xchange-appsuite-dev/bin/</code>. To have them available in a shell, add this directory to the <code>PATH</code> environment variable:<br />
<br />
export PATH=$PATH:/opt/open-xchange-appsuite-dev/bin<br />
<br />
=== For UI developers ===<br />
<br />
If you are a UI developer, or if the SDK is not available for your OS, you will need to clone the UI source and use the tools contained in the <code>ui/bin</code> directory.<br />
<br />
git clone --depth 1 -b <var>develop</var> https://code.open-xchange.com/git/wd/frontend/web<br />
export PATH=$PATH:$(pwd)/web/ui/bin<br />
<br />
The option <code>-b <var>develop</var></code> specifies a git branch. Until version 7.4 is released, the full functionality described in this article is only available in the "develop" branch.<br />
<br />
The option <code>--depth 1</code> prevents the download of the entire history, and reduces the download size from hundreds of MB to less than 20MB. It should not be used by OX App Suite developers since it also prevents <code>git push</code> from working properly.<br />
<br />
== Standalone use ==<br />
<br />
In the simplest case of developing an app or a plugin, all that is needed is an existing OX App Suite installation. Point <code>appserver</code> to the URL of OX App Suite and to the build directory of your app. Assuming you are in the top directory of your app's source code and <code>[[AppSuite:UI build system#builddir|$builddir]]</code> is not set:<br />
<br />
appserver [[#server|--server]]=<nowiki>https://www.ox.io/appsuite/</nowiki> build<br />
<br />
If there are no errors, you can point your browser to http://localhost:8337/appsuite/ to test a version of OX App Suite which includes your app. Do not forget the trailing slash in the URL. Otherwise, the server sends a redirect from <code>/appsuite</code> to <code>/appsuite/</code> and includes its own absolute URL in the redirect.<br />
<br />
You do not need to restart anything after re-building the app, a refresh of the browser page should be enough. If your code doesn’t show up after a refresh, our file cache mighgt not be up-to-date. Until this is fixed in appserver, you can append <code>&debug-js=true</code> to your URL to disable the file cache.<br />
<br />
== Use with Apache ==<br />
<br />
For more complex cases involving testing your own build of the UI, or apps which include static resources (e.&nbsp;g. images), a local web server is required to serve static resources. The following examples use the Apache HTTP Server, but any web server which can act as a reverse HTTP proxy should work (assuming the configuration and <code>.htaccess</code> files are adapted, of course).<br />
<br />
First, make your app visible in Apache. The simplest way is to symlink the <code>[[AppSuite:UI build system#builddir|$builddir]]</code> inside the document root. Assuming the app is in <code>/home/user/myapp</code> and the web server's document root is <code>/var/www</code>:<br />
<br />
sudo ln -s /home/user/myapp/build /var/www/myapp<br />
<br />
In case Apache ignores the symlink, ensure that its configuration directive <code><Directory /var/www/></code> contains "<code>Options FollowSymlinks</code>" or something to that effect.<br />
<br />
Second, configure Apache to request from <code>appserver</code> anything that it can't find locally. This configuration requires at least <code>mod_rewrite</code>, <code>mod_proxy</code> and <code>mod_proxy_http</code> to be enabled. Editing a file like <code>/etc/apache2/sites-enabled/000-default</code> containing the proxy configuration, add the following inside an eventual <code><VirtualHost></code> directive, but outside of any <code><Directory></code> directives:<br />
<br />
RewriteEngine On<br />
ProxyPreserveHost On<br />
<br />
ProxyPassMatch ^/((appsuite|ajax|infostore|publications\<br />
|realtime|servlet|usm-json|webservices)(/.*)?)$ \<br />
<nowiki>http://localhost:8337/$1</nowiki><br />
<br />
RewriteCond %{DOCUMENT_ROOT}/myapp/$2 -f<br />
RewriteRule ^/appsuite/(v=[^,/]+/)?(.*)$ /myapp/$2 [PT]<br />
<br />
Take care configuring apache configuration, proxy definitions might take place in several files. For example <code>/etc/apache2/conf.d/proxy_http.conf</code> does also often contain http proxy configuration, which may differ from the definitions in the file edited above.<br />
<br />
If you want to test multiple apps, use a different directory for each, and repeat the last two lines for each app, substituting the proper values for "<code>myapp</code>". If you are using aliases instead of symlinks then replace <code>%{DOCUMENT_ROOT}</code> with the actual file system path from the <code>Alias</code> directive.<br />
<br />
Now, restart Apache and start <code>appserver</code>.<br />
<br />
sudo apachectl restart<br />
appserver [[#server|--server]]=<nowiki>https://www.ox.io/appsuite/</nowiki> /var/www/appsuite<br />
<br />
If there are no errors, you can point your browser to http://localhost/appsuite/ to test a version of OX App Suite which includes your app. You do not need to restart anything after re-building the app, a refresh of the browser page should be enough.<br />
<br />
=== Custom UI builds ===<br />
<br />
To test your own build of the core UI, use <code>/var/www/appsuite</code> as directory, but don't add a <code>RewriteRule</code> for it. Instead, replace "<code>appsuite</code>" with "<code>appsuite/api</code>" in the <code>ProxyPassMatch</code> directive and add a <code><Directory></code> directive like for any other OX App Suite installation:<br />
<br />
<Directory /var/www/appsuite/><br />
Options FollowSymlinks<br />
AllowOverride Indexes FileInfo<br />
</Directory><br />
<br />
== Reference ==<br />
<br />
<code>appserver</code> is a reverse HTTP proxy. It accepts HTTP requests and forwards most of them to another HTTP server. There are currently two exceptions:<br />
* <code>api/apps/load</code> is served from a list of local paths. Only files which could not be found are fetched from the remote HTTP server. This allows to inject the code of a tested app without installing it on the remote server. The list of paths is specified as non-option parameters on the command line. Each path should normally have at least the subdirectories <code>apps</code> and <code>manifests</code>. Each injected file is looked up in the <code>apps</code> subdirectory of each path, in the order in which they appear on the command line, and the first found file is used. If a file is not found in any path, and the <code>[[#server|--server]]</code> option is specified, the file is downloaded from the server.<br />
* <code>api/apps/manifests?action=config</code> is extended by local manifests. This is necessary to enable the tested app in the UI. If no <code>[[#manifests|--manifests]]</code> options are specified, then all files from the <code>manifests</code> subdirectory of each path are combined and added to the manifests from the remote server. Each manifest entry overrides any entries with the same <code>path</code> attribute. Similar to the priority for files, manifest entries from earlier paths override entries from later paths, and local entries override remote entries.<br />
<br />
=== help ===<br />
<br />
Displays a short summary of available options:<br />
<br />
Usage: appserver [OPTION]... [PATH]...<br />
<br />
-h, --help print this help message and exit<br />
-m PATH, --manifests=PATH add manifests from the specified path (default:<br />
the "manifests" subdirectory of every file path)<br />
--path=PATH absolute path of the UI (default: /appsuite)<br />
-p PORT, --port=PORT listen on PORT (default: 8337)<br />
-s URL, --server=URL use an existing server as fallback<br />
-v TYPE, --verbose=TYPE print more information depending on TYPE:<br />
local: local files, remote: remote files,<br />
proxy: forwarded URLs, all: shortcut for all three<br />
-z PATH, --zoneinfo=PATH use timezone data from the specified path<br />
(default: /usr/share/zoneinfo/)<br />
<br />
Files are searched in each PATH in order and requested from the server if not<br />
found. If no paths are specified, the default is /var/www/appsuite/.<br />
<br />
=== manifests ===<br />
<br />
By default, the manifests of an app are collected and put into <code>[[AppSuite:UI build system#builddir|$builddir]]/manifests</code>. Therefore, by default, <code>appserver</code> collects manifests from the <code>manifests</code> subdirectoriy of each file path. Since the destination directory for manifests can be changed by setting <code>[[AppSuite:UI build system#manifestDir|$manifestDir]]</code>, the manifest directories can also be changed in <code>appserver</code> by specifying each directory with a separate <code>--manifests</code> option.<br />
<br />
If at least one <code>--manifests</code> option is specified, the default file paths are not used for manifests at all.<br />
<br />
=== path ===<br />
<br />
By default, URLs belonging to the OX App Suite (i.&nbsp;e. starting with <code>/appsuite/</code>) get mapped to the URL of the <code>[[#server|--server]]</code> parameter, while all other paths get mapped to identical paths on that server to allow services like <code>/publications</code> to work.<br />
<br />
This parameter changes the path of the local OX App Suite URL e.&nbsp;g. to allow testing multiple UIs with the same server.<br />
<br />
=== port ===<br />
<br />
Specifies the port to listen on. The default is 8337. This option might be useful to run multiple instances of <code>appserver</code> at once or when port 8337 is already in use.<br />
<br />
=== server ===<br />
<br />
Specifies the URL of an existing OX App Suite installation. The URL must start with <code>http://</code> or <code>https://</code>. To make forwarding of an HTTPS URL over HTTP possible, <code>appserver</code> removes the <code>Secure</code> attribute from all cookies set by the server.<br />
<br />
This option is required for manifest injection to work, since the intercepted request contains more data than just the manifests.<br />
<br />
=== verbose ===<br />
<br />
Enables verbose output. During normal operation, <code>appserver</code> only writes errors to its console. By specifying this option one or more times, additional output can be enabled, depending on the value of each option:<br />
<br />
; local : The name of every read local file is written to standard output.<br />
; remote : The URL of every request for missing local files is written to standard output.<br />
; proxy : The URL of every client request which is forwarded as-is is written to standard output.<br />
; all : This is just a shortcut for <code>-v local -v remote -v proxy</code>.<br />
<br />
Output lines belonging to the same client request are grouped together and separated from the next request by an empty line.<br />
<br />
=== zoneinfo ===<br />
<br />
Specifies the path to the zoneinfo database. On POSIX systems, the default of <code>/usr/share/zoneinfo/</code> should always work. Even on systems without the database everything should just work if <code>[[#server|--server]]</code> is specified, since any missing files will be fetched from the remote server. This option may still be useful when debugging time zone problems caused by different versions of the zoneinfo database.<br />
<br />
[[Category:AppSuite]]<br />
[[Category:UI]]<br />
[[Category:Developer]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:UI_manifests_explained&diff=16197AppSuite:UI manifests explained2013-10-24T09:08:02Z<p>Mark.schmidts: </p>
<hr />
<div>{{Stability-experimental}}<br />
<br />
<div class="title">Manifests</div><br />
<br />
'''Abstract:''' Manifest files in the app suite declare either apps or plugins. They tell the AppSuite runtime which files to load when, so the code in it can take effect at the appropriate time. This document should be read by everyone that wants to either build a plugin or an app and contains a description of how to get app suite to run your code.<br />
<br />
== Declaring apps ==<br />
<br />
The minimal declaration for an app looks like this:<br />
<br />
<pre class="language-javascript"> <br />
{<br />
title: "My App",<br />
path: "com.example/myapp/main"<br />
} <br />
</pre><br />
It consists of a title for the app and the path to the main entry file, by convention always called main.js. This declaration is usually found in the file manifest.json right next to the app in question, but could theoretically be located anywhere. If the file is located in the same directory as the main entry file and the file is, as is the convention, called main.js you can leave out the path as it will be added automatically by the buildsystem, so the minimal definition then becomes:<br />
<br />
<pre class="language-javascript"> <br />
{<br />
title: "My App"<br />
}<br />
</pre><br />
<br />
== Declaring a plugin ==<br />
<br />
In turn, this is the definition of a plugin file:<br />
<pre class="language-javascript"> <br />
{<br />
namespace: "io.ox/contacts/view-detail",<br />
path: "com.example/myapp/contacts/register"<br />
} <br />
</pre><br />
<br />
The namespace contains the name of a frontend module for which the plugin is relevant. Declaring a plugin like this has the effect, that the plugin is loaded before the file named as the namespace is loaded, so it can affect what the core file is doing, commonly by extending an extension point. The convention is to always put plugins into the file register.js, so again, the path can be omitted if the manifest.json is placed alongside the register.js containing the plugin. A plugin may be associated with more than one namespace, in that case, just use a list as the value for the namespace attribute:<br />
<br />
<pre class="language-javascript"> <br />
{<br />
namespace: ["io.ox/contacts/view-detail", "io.ox/contacts/edit/view-form"]<br />
}<br />
</pre><br />
<br />
Whichever module is loaded first will trigger the plugin to be loaded.<br />
Capabilities<br />
<br />
Sometimes a plugin or an app is only available if either the backend has a certain bundle installed or the user must have a certain permission. Both permissions and backend capabilities are rolled into the concept of a "capability". If your plugin, for example, is only relevant when the user has access to the calendar module, you can add a requires attribute to the declaration:<br />
<br />
<pre class="language-javascript"> <br />
{<br />
namespace: "io.ox/contacts/view-detail",<br />
requires: "calendar"<br />
}<br />
</pre> <br />
<br />
Which capabilities are available can be checked by either reading through existing manifests or by running this in the javascript console once logged into appsuite:<br />
<br />
<pre class="language-javascript"> <br />
_(ox.serverConfig.capabilities).pluck("id")<br />
</pre><br />
<br />
== Multiple declarations in one file ==<br />
<br />
If you need more than declaration in a manifest.json file, you can include them in a list:<br />
<pre class="language-javascript"> <br />
[<br />
{<br />
namespace: "io.ox/contacts/view-detail",<br />
path: "com.example/myapp/contacts/viewPlugin"<br />
},<br />
{<br />
namespace: "io.ox/contacts/view-form",<br />
path: "com.example/myapp/contacts/formPlugin"<br />
}<br />
]<br />
</pre><br />
<br />
== What happens to these files? ==<br />
<br />
During a build run the buildsystem picks up these manifest files and consolidates them into a single file build/manifests/[myapp].json. This file, either by creating a symlink to a locally run backend or by installing the app package on a remote backend, winds up in the manifests directory of the backend and is processed and sent to the frontend. You can see all manifest declarations, that have been sent by the backend by looking at<br />
ox.serverConfig.manifests<br />
in the javascript console.<br />
<br />
== Loading custom manifest during development ==<br />
<br />
During development you can use a custom manifest file to avoid restarting the backend or, in case of a remote backend, updating it every time the manifests change. Just add '''customManifests=true''' to the URL so that the UI loads the file '''src/manifests.js'''. All manifests in that file will be added to the ones provided by the backend. The file is supposed to be an anonymous require module that returns the array of manifest entries:<br />
<br />
<pre class="language-javascript"> <br />
define(function () {<br />
return [<br />
{<br />
path: "com.example/main",<br />
title: 'Hello World App'<br />
},<br />
{<br />
path: "com.example/contacts/register",<br />
namespace: "io.ox/contacts/view-detail"<br />
}<br />
];<br />
});<br />
</pre><br />
<br />
Note that the buildsystem doesn't add the path elements for this file. It's useful to have the buildsystem assemble the manifest.json files and then copy the resulting manifest entries into the array returned in the definition function. This file has to be linked into the deployed source folder:<br />
<pre class="language-shell"> <br />
rm /var/www/appsuite/src/manifests.js<br />
ln -s /var/www/appsuite/src/manifests.js /path/to/custom/manifests.js<br />
</pre> <br />
To tell app suite to load the custom manifest file, you have to invoke the frontend with "customManifests=true", e.g. /appsuite/#!&customManifests=true<br />
<br />
== Special namespaces ==<br />
<br />
=== signin ===<br />
<br />
Plugins that choose "signin" as (or amongst) their namespace, are loaded when the login page is shown. The code can be used to rearrange parts of the signin page or add custom behaviour to it.<br />
<br />
=== core ===<br />
<br />
Core plugins are loaded as soon as the frontend starts up after successfully logging in or reauthenticating with the autologin. This is useful if you need to run code very early.<br />
<br />
[[Category:AppSuite]]<br />
[[Category:UI]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:UI_build_system&diff=16186AppSuite:UI build system2013-10-23T15:56:51Z<p>Mark.schmidts: /* Installing */</p>
<hr />
<div>{{Stability-experimental}}<br />
<br />
<div class="title">Build System</div><br />
<br />
'''Abstract:''' This document describes the build system of OX App Suite. It is intended for app developers who use the build system to create apps as well as for OX App Suite developers who not only use the build system but also may wish to extend it.<br />
<br />
The build system is used to create source archives from source files. These source archives can be used to compile installable packages for various Linux distributions. The build system can generate archives for the core UI as well as for independently installed apps.<br />
<br />
The OX App Suite build system uses [https://github.com/mde/jake Jake], a port of Rake from Ruby to [http://nodejs.org Node.js]. Both Rake and Jake are dependency-based build systems like Make, which allows quick incremental builds. But unlike Make, Jake doesn't have its own syntax. Instead, it provides an API in JavaScript. The API is used not only to specify dependencies between files using a full programming language, but also to implement the generation of files in the same language. This allows easy implementation of complex build systems, of which the OX App Suite build system is an example. Using the same language for the developed project and for its build system also allows any core developer to quickly extend the build system without having to switch to another language.<br />
<br />
== Using the Build System ==<br />
<br />
While easily extensible, most of the time the build system will be used as-is. This chapter describes how to set up and use the build system to develop apps and the OX App Suite core.<br />
<br />
All command examples are given for the Debian operating system. The instructions should work similarly on other POSIX systems. The first character of each command indicates whether it should be executed as root (#) or as a normal user ($).<br />
<br />
== Installing ==<br />
<br />
Installing the right environment for running the <code>appserver</code> and the UI build system is described in [[AppSuite:Appserver | the Appserver article]].<br />
<br />
== Running ==<br />
<br />
The build system is executed by invoking the command <code>build-appsuite</code>. Similar to most build systems, the build system can perform multiple tasks, which are specified as parameters on the command line. Each task can require any number of parameters. These parameters can be specified either on the command line, using the syntax <code>name=value</code>, or as environment variables.<br />
<br />
If present, the file <code>local.conf</code> is sourced by a shell script before the build process starts. This file can export environment variables which are specific to the local system, without checking them into a version control system. Typically, it defines values for <code>[[#builddir|builddir]]</code> and <code>[[#debug|debug]]</code>.<br />
<br />
Since the build system is based on Jake, it also accepts all other Jake options. In addition, the environment variable <code>$nodeopts</code> can be used to pass command line parameters to Node.js. One of the most useful parameters is <code>--debug-brk</code>, which can be used to debug the build system.<br />
<br />
When developing external apps, the build system must be run from the top directory of the app's source. As a safety precaution, execution is aborted if the subdirectory <code>apps</code>, which usually contains JavaScript source code, is not found. This Article is written assuming, you're working in your workspace directory, containing the subfolder <code>apps</code>.<br />
<br />
== Workflow ==<br />
<br />
The build system is used not only to create source archives for packaging. It can also directly install and update the built UI in a directory during development, help with the setup of the source of a new external app and more. While all of these tasks are described in the reference section, daily work involves just a few of them.<br />
<br />
=== Create packaging metadata ===<br />
<br />
The first task which should be executed when creating a new external app is <code>[[#init-packaging|init-packaging]]</code>. It creates packaging metadata in the current directory. It requires the parameter <code>package</code> to specify the package name in the generated files. All subsequent tasks will automatically extract the package name from the files generated by <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
Before execution, the <code>apps</code> subdirectory must be created. It indicates that the current directory is actually a valid source directory.<br />
<br />
$ mkdir apps<br />
$ build-appsuite init-packaging package=example-app<br />
Build path: build<br />
Build version: 0.0.1-1.20130424.123835<br />
<br />
Version [0.0.1]: <br />
<br />
Maintainer (Name <e-mail>): Maintainer <maintainer@example.com><br />
<br />
Copyright line [2013 Open-Xchange, Inc]: <br />
<br />
License name [CC-BY-NC-SA-3.0]: <br />
<br />
Short description: Hello World app to demonstrate usage of the build system<br />
<br />
The task presents a number of interactive prompts to get the necessary information about the generated packages. The entered values should follow the Debian Maintainer's Guide. Some or even all prompts can be skipped by explicitly specifying the information as a build variable. The list of variable names is available in the reference of <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
After the task is finished, the generated files can be customized manually to account for any additional packaging requirements.<br />
<br />
=== Building apps ===<br />
<br />
To have an easy example about how to write, build and host your javascript code, please have a look at the [[AppSuite:GettingStarted | GettingStarted article]].<br />
<br />
==== JSHINT ====<br />
<br />
One step of the build process is running jshint to statically analyse the sources for certain errors. JSHint is configured with (what we think) sane defaults, but if you want to configure your own rules, edit <code>.jshintrc</code> in your project`s root folder, according to your needs.<br />
<br />
=== default ===<br />
<br />
The default task is used instead of the app task when building the core OX App Suite. Since it is the default Jake task, it is not necessary to specify it on the command line when it's the only task.<br />
<br />
The top directory of OX App Suite source code includes the script <code>build.sh</code>, which should be used instead of calling a potentially unrelated version of <code>build-appsuite</code>. The script changes the current directory to its own, so that it can be called from any directory.<br />
<br />
$ web/ui/build.sh<br />
<br />
=== clean ===<br />
<br />
The build system uses dependencies and file timestamps to decide which files to rebuild. This assumes that any change to a file increases its timestamp to a value which is greater than the timestamp of any existing file. When this assumption is violated (e.g. after switching to a different source control branch with older files) it may become necessary to rebuild everything to restore the assumption about timestamps. The simplest way to achieve this is the clean task, which simply deletes all generated files.<br />
<br />
WARNING: This can be potentially dangerous, since the clean task simply deletes the directories specified by the variables builddir, destDir, l10nDir, manifestDir, and helpDir.<br />
<br />
=== dist ===<br />
<br />
When the app is ready to be shipped, or rather all the time on a continuous build system, the app needs to be packaged in a format suitable for installation on a production system. Since there already exist tools to create packages from suitably arranged source code archives, the OX App Suite build system merely prepares such source archives.<br />
<br />
The dist task creates an archive with the source (the one ending in .orig.tar.bz2) and a few additional files necessary for Debian packaging. RPM packages can be generated using the same source archive and the .spec file created by init-packaging. The version of the package is extracted from the newest entry in the file debian/changelog.<br />
<br />
Debian packages can also be generated manually either from the temporary directory left behind by dist, or even directly from the source tree. The second option pollutes the source tree with generated files, so it is not recommended, although the .gitignore file created by init-packaging can handle these generated files.<br />
<br />
$ build-appsuite dist<br />
$ ls tmp/packaging/<br />
example-app-0.0.1 example-app_0.0.1-1.dsc<br />
example-app_0.0.1-1.debian.tar.bz2 example-app_0.0.1.orig.tar.bz2<br />
$ cd tmp/packaging/example-app-0.0.1/<br />
$ dpkg-buildpackage -b<br />
<br />
== Reference ==<br />
<br />
=== Variables ===<br />
<br />
==== BASEDIR ====<br />
The top directory of the build system.<br />
<br />
<b>Used by:</b> all tasks.<br />
<br />
<b>Default:</b> installation directory of the build system<br />
<br />
Required to build external apps, since in this case, the build<br />
system is not installed in the current directory. This variable is<br />
automatically set as an environment variable by the build system<br />
executable based on <code>$OX_APPSUITE_DEV</code>.<br />
<br />
==== branch ====<br />
The Subversion branch of the CLDR to checkout.<br />
<br />
<b>Used by:</b> <code>update-i18n</code>.<br />
<br />
==== builddir ====<br />
The target directory for generated files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>, <code>docs</code>,<br />
<code>jakedeps</code>.<br />
<br />
Default: <code>build</code><br />
<br />
==== copyright ====<br />
The copyright line to be included in packaging metadata.<br />
<br />
<b>Used by:</b> <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
<b>Example:</b> <code>2012 Open-Xchange, Inc</code><br />
<br />
==== coreDir ====<br />
Location of OX App Suite UI files.<br />
<br />
<b>Used by:</b> <code>[[#app|app]]</code>, <code>[[#default|default]]</code>.<br />
<br />
<b>Default:</b> same as <code>[[#builddir|builddir]]</code><br />
<br />
Some tasks depend on installed files from the OX App Suite. When building external apps, <code>[[#coreDir|coreDir]]</code> specified the directory which contains these files.<br />
<br />
Currently, this parameter is used to compile <code>.less</code> files for every installed theme. This can be disabled by setting <code>[[#skipLess|skipLess]]</code>.<br />
<br />
==== debug ====<br />
Enables a debug build.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
To simplify debugging of OX App Suite, compression of source code<br />
can be disabled by specifying <code>on</code>, <code>yes</code>,<br />
<code>true</code> or <code>1</code>.<br />
<br />
==== description ====<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
The description of the app to be included in packaging metadata.<br />
<br />
==== destDir ====<br />
Output directory for source archives created by<br />
the <code>dist</code> task.<br />
<br />
<b>Used by:</b> <code>clean</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> <code>tmp/packaging</code><br />
<br />
==== disableStrictMode ====<br />
Removes all <code>"use strict"</code> directives from processed<br />
JavaScript code.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
Some debugging tools which use code instrumentation have problems<br />
when the debugged code uses strict mode. This setting enables code<br />
processing even whe using <code>debug</code> mode, so line numbers<br />
will not match the original source code.<br />
<br />
==== forceDeb ====<br />
Whether an error during the generation of Debian source packages is an error.<br />
<br />
<b>Used by:</b> <code>dist</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This is useful when Debian packages are generated automatically, and a failure of <code>dpkg-source</code> is also a failure of the entire build. By default it merely produces a warning.<br />
<br />
==== from ====<br />
The root of the printed dependency tree between Jake tasks.<br />
<br />
<b>Used by:</b> <code>jakedeps</code>.<br />
<br />
==== helpDir ====<br />
The location of online help files.<br />
<br />
<b>Used by:</b> <code>clean</code>, <code>default</code>,<br />
<code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
If the value contains the string <code>@lang@</code>, it will be<br />
replaced by the lowercase language code (e.g. <code>en-us</code>) to<br />
allow per-language directories.<br />
<br />
==== l10nDir ====<br />
The location of compiled l10n files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
If the value contains the string <code>@lang@</code>, it will be<br />
replaced by the lowercase language code (e.g. <code>en-us</code>) to<br />
allow per-language directories.<br />
<br />
==== license ====<br />
File name of the full text of the distribution license.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Default:</b> based on <code>licenseName</code>.<br />
<br />
==== licenseName ====<br />
Name of the distribution license to be included in packaging<br />
metadata.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Default:</b> <code>CC-BY-NC-SA-3.0</code><br />
<br />
==== manifestDir ====<br />
The location of the combined manifest file.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
==== maintainer ====<br />
Name and email address of the package maintainer.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Format:</b> <code><var>Name</var> &lt;<var>email</var>&gt;</code><br />
<br />
==== package ====<br />
The name of the package for the built app.<br />
<br />
<b>Used by:</b> all tasks.<br />
<br />
<b>Default:</b> the package name in the first line of<br />
<code>debian/changelog</code><br />
<br />
Since the name of the manifest file contains the package name and it<br />
is required to determine build dependencies, the package name must<br />
be always known. This means either <code>debian/changelog</code><br />
must exist and contain at least one entry, or the parameter must be<br />
explicitly specified.<br />
<br />
==== reverse ====<br />
Reverses the direction of printed dependencies.<br />
<br />
<b>Used by:</b> <code>deps</code>.<br />
<br />
When specified, the <code>deps</code> task prints modules which<br />
depend on the specified modules, instead of modules on which<br />
the specified module depends.<br />
<br />
==== revision ====<br />
Revision number of the package for the app.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>,<br />
<code>dist</code>.<br />
<br />
<b>Default:</b> <code>1</code><br />
<br />
The revision number must increase with each rebuild of the same<br />
version to enable the creation of unique version strings. These are<br />
required in package names and to control content caching in clients.<br />
<br />
==== root ====<br />
Specifies for which module to print the dependencies.<br />
<br />
<b>Used by:</b> <code>deps</code>.<br />
<br />
<b>Default:</b> print all roots<br />
<br />
If specified, only the dependencies of the specified module are<br />
printed. Otherwise, the dependencies of all modules are printed.<br />
<br />
==== skipDeb ====<br />
Whether to skip the generation of Debian source packages.<br />
<br />
<b>Used by:</b> <code>dist</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This is useful when Debian packages are not required and/or<br />
<code>dpkg-source</code> is not available, e.g. on RPM based<br />
systems.<br />
<br />
Even when using this flag, at least the file<br />
<code>debian/changelog</code> is still required, because it is used<br />
to store the package name and version. <br />
<br />
==== skipLess ====<br />
Whether to skip the preprocessing of LessCSS files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This flag skips the generation of CSS files in<br />
the <code>apps/themes/*/less</code> directories of all themes.<br />
It is used by the packaging system, where the LessCSS files are<br />
precompiled after installation on the target system instead of<br />
while building the package.<br />
<br />
==== tag ====<br />
The Subversion tag of the CLDR to checkout.<br />
<br />
<b>Used by:</b> <code>update-i18n</code>.<br />
<br />
==== to ====<br />
The leaf task in the printed dependency path between Jake tasks.<br />
<br />
<b>Used by:</b> <code>jakedeps</code>.<br />
<br />
When specified, only a single path from the root to the leaf task is<br />
printed (in reverse order).<br />
<br />
==== version ====<br />
Version number of the app.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>,<br />
<code>dist</code>, <code>init-packaging</code>.<br />
<br />
<b>Default:</b> <code>0.0.1</code><br />
<br />
The version should consist of a major, minor and patch version<br />
separated by dots.<br />
<br />
=== Tasks ===<br />
<p><br />
An up-to-date list of tasks can be printed using the -T command line option.<br />
<br />
==== app ====<br />
Builds an external app.<br />
<br />
<b>Variables:</b> <code>[[#BASEDIR|BASEDIR]]</code>, <code>[[#builddir|builddir]]</code>, <code>[[#coreDir|coreDir]]</code>, <code>[[#debug|debug]]</code>, <code>[[#disableStrictMode|disableStrictMode]]</code>, <code>[[#l10nDir|l10nDir]]</code>, <code>[[#manifestDir|manifestDir]]</code>, <code>[[#package|package]]</code>, <code>[[#revision|revision]]</code>, <code>[[#version|version]]</code>.<br />
<br />
This is the main task used to build external apps.<br />
<br />
It works without explicitly specifying any variables, but during<br />
development, <code>[[#builddir|builddir]]</code> is usually pointed to<br />
the directory of a locally installed OX App Suite UI to avoid<br />
additional copying steps. For debugging, <code>[[#debug|debug]]</code> is also<br />
often used. Note that <code>[[#clean|clean]]</code> must be called when<br />
changing any of the variables.<br />
<br />
==== clean ====<br />
Removes all generated files.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>destDir</code>, <code>l10nDir</code>,<br />
<code>manifestDir</code>, <code>package</code>.<br />
<br />
This task should be executed before a normal build using<br />
<code>app</code> or <code>default</code> after changing any build<br />
variables and after a switch between Git branches. Normal<br />
incremental builds can miss changed files if a branch switch<br />
replaces files by older versions.<br />
<br />
==== default ====<br />
Builds OX App Suite.<br />
<br />
<b>Variables:</b> <code>[[#BASEDIR|BASEDIR]]</code>, <code>[[#builddir|builddir]]</code>, <code>[[#debug|debug]]</code>, <code>[[#disableStrictMode|disableStrictMode]]</code>, <code>[[#l10nDir|l10nDir]]</code>, <code>[[#manifestDir|manifestDir]]</code>, <code>[[#package|package]]</code>, <code>[[#revision|revision]]</code>, <code>[[#version|version]]</code>.<br />
<br />
This is the main task to build OX App Suite. Since it is the default<br />
Jake task, it does not need to be specified explicitly on<br />
the command line when it is the only task.<br />
<br />
It works without explicitly specifying any variables, but during<br />
development, <code>[[#builddir|builddir]]</code> is usually pointed to<br />
a directory which is accessible to a local web server. For<br />
debugging, <code>[[#debug|debug]]</code> is also often used. Note that<br />
<code>[[#clean|clean]]</code> must be called when changing any of<br />
the variables.<br />
<br />
==== deps ====<br />
Prints module dependencies.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>package</code>,<br />
<code>reverse</code>, <code>root</code>.<br />
<br />
This task visualizes dependencies of RequireJS modules. It prints<br />
a tree of dependencies to <code>stdout</code>.<br />
<br />
If <code>root</code> is specified, then only the dependencies of<br />
that module are printed. Otherwise, the dependencies of all modules,<br />
on which no other module depends are printed in sequence. <br />
<br />
If <code>reverse</code> is specified, then this task prints<br />
dependants instead of dependencies, i.e. modules which depend on<br />
the specified module instead of modules on which the specified<br />
module depends.<br />
<br />
==== dist ====<br />
Creates source packages.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>destDir</code>, <code>forceDeb</code>, <code>l10nDir</code>,<br />
<code>manifestDir</code>, <code>package</code>,<br />
<code>revision</code>, <code>skipDeb</code>,<br />
<code>version</code>.<br />
<br />
This task cleans the source tree by calling <code>clean</code> and<br />
packs the source into an archive which can be used to create Debian<br />
and RPM packages. The necessary Debian metadata is created alongside<br />
the source archive. All files necessary for Debian packaging are<br />
placed in the directory specified by <code>destDir</code>.<br />
The generated <code>.orig.tar.bz2</code> archive can also be used<br />
together with the <code>.spec</code> file to generate RPM packages.<br />
<br />
Unless the variable <code>skipDeb</code> is set to<br />
<code>true</code>, the program <code>dpkg-source</code> is required<br />
by this task. It is used to generate Debian-specific packaging<br />
metadata.<br />
<br />
==== init-packaging ====<br />
Initializes packaging information for a new app.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>copyright</code>,<br />
<code>description</code>, <code>license</code>,<br />
<code>licenseName</code>, <code>maintainer</code>,<br />
<code>package</code>, <code>version</code>.<br />
<br />
This task is the first task called when starting with<br />
the development of a new external app. The directory from which it<br />
is called must already contain at least the <code>apps</code><br />
subdirectory. This is also the only task where<br />
the <code>package</code> variable must be specified explicitly.<br />
Afterwards, the package name is looked up automatically in the file<br />
<code>debian/changelog</code>, which is created by this task.<br />
<br />
The variables <code>version</code>, <code>maintainer</code>,<br />
<code>copyright</code>, <code>licenseName</code>,<br />
<code>license</code>, and <code>description</code> are required to<br />
fill out all necessary packaging metadata. Any of these variables<br />
which are not specified explicitly will cause an interactive prompt.<br />
This avoids the need to remember the list of variables before one<br />
can start developing an app.<br />
<br />
==== jakedeps ====<br />
Shows the dependency chain between two Jake tasks.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>from</code>,<br />
<code>package</code>, <code>to</code>.<br />
<br />
This task visualized dependencies between Jake tasks. The variable<br />
<code>from</code> specifies the root of a dependency tree, with all<br />
dependencies of <code>from</code> as inner and leaf nodes. If<br />
<code>to</code> is not specified, then that entire tree is printed.<br />
<br />
If <code>to</code> is also specified, then only the first found<br />
dependency path from <code>from</code> to <code>to</code> is<br />
.printed with <code>to</code> at the top and <code>from</code> at<br />
the bottom.<br />
<br />
==== merge ====<br />
Updates all <code>.po</code> files with the generated<br />
<code>ox.pot</code>.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>debug</code>, <code>package</code>, <code>revision</code>,<br />
<code>version</code>.<br />
<br />
This task updates the list of extracted i18n strings in<br />
<code>ox.pot</code> and calls the GNU Gettext tool<br />
<code>msgmerge</code> for every language in <code>i18n/*.po</code>.<br />
<br />
<code>i18n/en_US.po</code> is not updated by this task because the original strings are already in the <code>en_US</code> locale. It would only end up with every translation mapping every string to itself. The only entries in that file should be for cases when the <code>en_US</code> text is not a suitable fallback for missing translations. The original string in such a case would be something internationally appropriate (e.&nbsp;g. a date written as "2013-01-01" instead of "01/01/2013") and <code>i18n/en_US.po</code> would contain a translation.<br />
<br />
==== update-i18n ====<br />
Updates CLDR data in the source tree.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>branch</code>,<br />
<code>package</code>, <code>tag</code>.<br />
<br />
This task downloads data from the Unicode CLDR and updates date<br />
translations for all languages in <code>i18n/*.po</code>.<br />
<br />
The exact version of CLDR data is specified as Suubversion tag or<br />
branch by the variables <code>tag</code> and <code>branch</code>,<br />
respectively. If neither is specified, then the Subversion trunk is<br />
checked out. If both are specified, <code>tag</code> is used.<br />
<br />
==== verify-doc ====<br />
Generates a documentation skeleton for extension points.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>package</code>.<br />
<br />
This task is still under development. Currently, it creates a list of all extension points, which have a constant name in the source code. In the future it is supposed to update an existing list instead of overwriting it, and to handle non-constant extension point names.<br />
<br />
The list of extension points is stored as an HTML snippet in <code>doc/extensionpoints.html</code>.<br />
<br />
<br />
[[Category:AppSuite]]<br />
[[Category:UI]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:UI_build_system&diff=16185AppSuite:UI build system2013-10-23T15:54:59Z<p>Mark.schmidts: /* Installing */</p>
<hr />
<div>{{Stability-experimental}}<br />
<br />
<div class="title">Build System</div><br />
<br />
'''Abstract:''' This document describes the build system of OX App Suite. It is intended for app developers who use the build system to create apps as well as for OX App Suite developers who not only use the build system but also may wish to extend it.<br />
<br />
The build system is used to create source archives from source files. These source archives can be used to compile installable packages for various Linux distributions. The build system can generate archives for the core UI as well as for independently installed apps.<br />
<br />
The OX App Suite build system uses [https://github.com/mde/jake Jake], a port of Rake from Ruby to [http://nodejs.org Node.js]. Both Rake and Jake are dependency-based build systems like Make, which allows quick incremental builds. But unlike Make, Jake doesn't have its own syntax. Instead, it provides an API in JavaScript. The API is used not only to specify dependencies between files using a full programming language, but also to implement the generation of files in the same language. This allows easy implementation of complex build systems, of which the OX App Suite build system is an example. Using the same language for the developed project and for its build system also allows any core developer to quickly extend the build system without having to switch to another language.<br />
<br />
== Using the Build System ==<br />
<br />
While easily extensible, most of the time the build system will be used as-is. This chapter describes how to set up and use the build system to develop apps and the OX App Suite core.<br />
<br />
All command examples are given for the Debian operating system. The instructions should work similarly on other POSIX systems. The first character of each command indicates whether it should be executed as root (#) or as a normal user ($).<br />
<br />
== Installing ==<br />
<br />
Installing the right environment for running the <tt>appserver</tt> and the UI build system is described in [[AppSuite:Appserver | the Appserver article]].<br />
<br />
== Running ==<br />
<br />
The build system is executed by invoking the command <code>build-appsuite</code>. Similar to most build systems, the build system can perform multiple tasks, which are specified as parameters on the command line. Each task can require any number of parameters. These parameters can be specified either on the command line, using the syntax <code>name=value</code>, or as environment variables.<br />
<br />
If present, the file <code>local.conf</code> is sourced by a shell script before the build process starts. This file can export environment variables which are specific to the local system, without checking them into a version control system. Typically, it defines values for <code>[[#builddir|builddir]]</code> and <code>[[#debug|debug]]</code>.<br />
<br />
Since the build system is based on Jake, it also accepts all other Jake options. In addition, the environment variable <code>$nodeopts</code> can be used to pass command line parameters to Node.js. One of the most useful parameters is <code>--debug-brk</code>, which can be used to debug the build system.<br />
<br />
When developing external apps, the build system must be run from the top directory of the app's source. As a safety precaution, execution is aborted if the subdirectory <code>apps</code>, which usually contains JavaScript source code, is not found. This Article is written assuming, you're working in your workspace directory, containing the subfolder <code>apps</code>.<br />
<br />
== Workflow ==<br />
<br />
The build system is used not only to create source archives for packaging. It can also directly install and update the built UI in a directory during development, help with the setup of the source of a new external app and more. While all of these tasks are described in the reference section, daily work involves just a few of them.<br />
<br />
=== Create packaging metadata ===<br />
<br />
The first task which should be executed when creating a new external app is <code>[[#init-packaging|init-packaging]]</code>. It creates packaging metadata in the current directory. It requires the parameter <code>package</code> to specify the package name in the generated files. All subsequent tasks will automatically extract the package name from the files generated by <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
Before execution, the <code>apps</code> subdirectory must be created. It indicates that the current directory is actually a valid source directory.<br />
<br />
$ mkdir apps<br />
$ build-appsuite init-packaging package=example-app<br />
Build path: build<br />
Build version: 0.0.1-1.20130424.123835<br />
<br />
Version [0.0.1]: <br />
<br />
Maintainer (Name <e-mail>): Maintainer <maintainer@example.com><br />
<br />
Copyright line [2013 Open-Xchange, Inc]: <br />
<br />
License name [CC-BY-NC-SA-3.0]: <br />
<br />
Short description: Hello World app to demonstrate usage of the build system<br />
<br />
The task presents a number of interactive prompts to get the necessary information about the generated packages. The entered values should follow the Debian Maintainer's Guide. Some or even all prompts can be skipped by explicitly specifying the information as a build variable. The list of variable names is available in the reference of <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
After the task is finished, the generated files can be customized manually to account for any additional packaging requirements.<br />
<br />
=== Building apps ===<br />
<br />
To have an easy example about how to write, build and host your javascript code, please have a look at the [[AppSuite:GettingStarted | GettingStarted article]].<br />
<br />
==== JSHINT ====<br />
<br />
One step of the build process is running jshint to statically analyse the sources for certain errors. JSHint is configured with (what we think) sane defaults, but if you want to configure your own rules, edit <code>.jshintrc</code> in your project`s root folder, according to your needs.<br />
<br />
=== default ===<br />
<br />
The default task is used instead of the app task when building the core OX App Suite. Since it is the default Jake task, it is not necessary to specify it on the command line when it's the only task.<br />
<br />
The top directory of OX App Suite source code includes the script <code>build.sh</code>, which should be used instead of calling a potentially unrelated version of <code>build-appsuite</code>. The script changes the current directory to its own, so that it can be called from any directory.<br />
<br />
$ web/ui/build.sh<br />
<br />
=== clean ===<br />
<br />
The build system uses dependencies and file timestamps to decide which files to rebuild. This assumes that any change to a file increases its timestamp to a value which is greater than the timestamp of any existing file. When this assumption is violated (e.g. after switching to a different source control branch with older files) it may become necessary to rebuild everything to restore the assumption about timestamps. The simplest way to achieve this is the clean task, which simply deletes all generated files.<br />
<br />
WARNING: This can be potentially dangerous, since the clean task simply deletes the directories specified by the variables builddir, destDir, l10nDir, manifestDir, and helpDir.<br />
<br />
=== dist ===<br />
<br />
When the app is ready to be shipped, or rather all the time on a continuous build system, the app needs to be packaged in a format suitable for installation on a production system. Since there already exist tools to create packages from suitably arranged source code archives, the OX App Suite build system merely prepares such source archives.<br />
<br />
The dist task creates an archive with the source (the one ending in .orig.tar.bz2) and a few additional files necessary for Debian packaging. RPM packages can be generated using the same source archive and the .spec file created by init-packaging. The version of the package is extracted from the newest entry in the file debian/changelog.<br />
<br />
Debian packages can also be generated manually either from the temporary directory left behind by dist, or even directly from the source tree. The second option pollutes the source tree with generated files, so it is not recommended, although the .gitignore file created by init-packaging can handle these generated files.<br />
<br />
$ build-appsuite dist<br />
$ ls tmp/packaging/<br />
example-app-0.0.1 example-app_0.0.1-1.dsc<br />
example-app_0.0.1-1.debian.tar.bz2 example-app_0.0.1.orig.tar.bz2<br />
$ cd tmp/packaging/example-app-0.0.1/<br />
$ dpkg-buildpackage -b<br />
<br />
== Reference ==<br />
<br />
=== Variables ===<br />
<br />
==== BASEDIR ====<br />
The top directory of the build system.<br />
<br />
<b>Used by:</b> all tasks.<br />
<br />
<b>Default:</b> installation directory of the build system<br />
<br />
Required to build external apps, since in this case, the build<br />
system is not installed in the current directory. This variable is<br />
automatically set as an environment variable by the build system<br />
executable based on <code>$OX_APPSUITE_DEV</code>.<br />
<br />
==== branch ====<br />
The Subversion branch of the CLDR to checkout.<br />
<br />
<b>Used by:</b> <code>update-i18n</code>.<br />
<br />
==== builddir ====<br />
The target directory for generated files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>, <code>docs</code>,<br />
<code>jakedeps</code>.<br />
<br />
Default: <code>build</code><br />
<br />
==== copyright ====<br />
The copyright line to be included in packaging metadata.<br />
<br />
<b>Used by:</b> <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
<b>Example:</b> <code>2012 Open-Xchange, Inc</code><br />
<br />
==== coreDir ====<br />
Location of OX App Suite UI files.<br />
<br />
<b>Used by:</b> <code>[[#app|app]]</code>, <code>[[#default|default]]</code>.<br />
<br />
<b>Default:</b> same as <code>[[#builddir|builddir]]</code><br />
<br />
Some tasks depend on installed files from the OX App Suite. When building external apps, <code>[[#coreDir|coreDir]]</code> specified the directory which contains these files.<br />
<br />
Currently, this parameter is used to compile <code>.less</code> files for every installed theme. This can be disabled by setting <code>[[#skipLess|skipLess]]</code>.<br />
<br />
==== debug ====<br />
Enables a debug build.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
To simplify debugging of OX App Suite, compression of source code<br />
can be disabled by specifying <code>on</code>, <code>yes</code>,<br />
<code>true</code> or <code>1</code>.<br />
<br />
==== description ====<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
The description of the app to be included in packaging metadata.<br />
<br />
==== destDir ====<br />
Output directory for source archives created by<br />
the <code>dist</code> task.<br />
<br />
<b>Used by:</b> <code>clean</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> <code>tmp/packaging</code><br />
<br />
==== disableStrictMode ====<br />
Removes all <code>"use strict"</code> directives from processed<br />
JavaScript code.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
Some debugging tools which use code instrumentation have problems<br />
when the debugged code uses strict mode. This setting enables code<br />
processing even whe using <code>debug</code> mode, so line numbers<br />
will not match the original source code.<br />
<br />
==== forceDeb ====<br />
Whether an error during the generation of Debian source packages is an error.<br />
<br />
<b>Used by:</b> <code>dist</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This is useful when Debian packages are generated automatically, and a failure of <code>dpkg-source</code> is also a failure of the entire build. By default it merely produces a warning.<br />
<br />
==== from ====<br />
The root of the printed dependency tree between Jake tasks.<br />
<br />
<b>Used by:</b> <code>jakedeps</code>.<br />
<br />
==== helpDir ====<br />
The location of online help files.<br />
<br />
<b>Used by:</b> <code>clean</code>, <code>default</code>,<br />
<code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
If the value contains the string <code>@lang@</code>, it will be<br />
replaced by the lowercase language code (e.g. <code>en-us</code>) to<br />
allow per-language directories.<br />
<br />
==== l10nDir ====<br />
The location of compiled l10n files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
If the value contains the string <code>@lang@</code>, it will be<br />
replaced by the lowercase language code (e.g. <code>en-us</code>) to<br />
allow per-language directories.<br />
<br />
==== license ====<br />
File name of the full text of the distribution license.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Default:</b> based on <code>licenseName</code>.<br />
<br />
==== licenseName ====<br />
Name of the distribution license to be included in packaging<br />
metadata.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Default:</b> <code>CC-BY-NC-SA-3.0</code><br />
<br />
==== manifestDir ====<br />
The location of the combined manifest file.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
==== maintainer ====<br />
Name and email address of the package maintainer.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Format:</b> <code><var>Name</var> &lt;<var>email</var>&gt;</code><br />
<br />
==== package ====<br />
The name of the package for the built app.<br />
<br />
<b>Used by:</b> all tasks.<br />
<br />
<b>Default:</b> the package name in the first line of<br />
<code>debian/changelog</code><br />
<br />
Since the name of the manifest file contains the package name and it<br />
is required to determine build dependencies, the package name must<br />
be always known. This means either <code>debian/changelog</code><br />
must exist and contain at least one entry, or the parameter must be<br />
explicitly specified.<br />
<br />
==== reverse ====<br />
Reverses the direction of printed dependencies.<br />
<br />
<b>Used by:</b> <code>deps</code>.<br />
<br />
When specified, the <code>deps</code> task prints modules which<br />
depend on the specified modules, instead of modules on which<br />
the specified module depends.<br />
<br />
==== revision ====<br />
Revision number of the package for the app.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>,<br />
<code>dist</code>.<br />
<br />
<b>Default:</b> <code>1</code><br />
<br />
The revision number must increase with each rebuild of the same<br />
version to enable the creation of unique version strings. These are<br />
required in package names and to control content caching in clients.<br />
<br />
==== root ====<br />
Specifies for which module to print the dependencies.<br />
<br />
<b>Used by:</b> <code>deps</code>.<br />
<br />
<b>Default:</b> print all roots<br />
<br />
If specified, only the dependencies of the specified module are<br />
printed. Otherwise, the dependencies of all modules are printed.<br />
<br />
==== skipDeb ====<br />
Whether to skip the generation of Debian source packages.<br />
<br />
<b>Used by:</b> <code>dist</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This is useful when Debian packages are not required and/or<br />
<code>dpkg-source</code> is not available, e.g. on RPM based<br />
systems.<br />
<br />
Even when using this flag, at least the file<br />
<code>debian/changelog</code> is still required, because it is used<br />
to store the package name and version. <br />
<br />
==== skipLess ====<br />
Whether to skip the preprocessing of LessCSS files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This flag skips the generation of CSS files in<br />
the <code>apps/themes/*/less</code> directories of all themes.<br />
It is used by the packaging system, where the LessCSS files are<br />
precompiled after installation on the target system instead of<br />
while building the package.<br />
<br />
==== tag ====<br />
The Subversion tag of the CLDR to checkout.<br />
<br />
<b>Used by:</b> <code>update-i18n</code>.<br />
<br />
==== to ====<br />
The leaf task in the printed dependency path between Jake tasks.<br />
<br />
<b>Used by:</b> <code>jakedeps</code>.<br />
<br />
When specified, only a single path from the root to the leaf task is<br />
printed (in reverse order).<br />
<br />
==== version ====<br />
Version number of the app.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>,<br />
<code>dist</code>, <code>init-packaging</code>.<br />
<br />
<b>Default:</b> <code>0.0.1</code><br />
<br />
The version should consist of a major, minor and patch version<br />
separated by dots.<br />
<br />
=== Tasks ===<br />
<p><br />
An up-to-date list of tasks can be printed using the -T command line option.<br />
<br />
==== app ====<br />
Builds an external app.<br />
<br />
<b>Variables:</b> <code>[[#BASEDIR|BASEDIR]]</code>, <code>[[#builddir|builddir]]</code>, <code>[[#coreDir|coreDir]]</code>, <code>[[#debug|debug]]</code>, <code>[[#disableStrictMode|disableStrictMode]]</code>, <code>[[#l10nDir|l10nDir]]</code>, <code>[[#manifestDir|manifestDir]]</code>, <code>[[#package|package]]</code>, <code>[[#revision|revision]]</code>, <code>[[#version|version]]</code>.<br />
<br />
This is the main task used to build external apps.<br />
<br />
It works without explicitly specifying any variables, but during<br />
development, <code>[[#builddir|builddir]]</code> is usually pointed to<br />
the directory of a locally installed OX App Suite UI to avoid<br />
additional copying steps. For debugging, <code>[[#debug|debug]]</code> is also<br />
often used. Note that <code>[[#clean|clean]]</code> must be called when<br />
changing any of the variables.<br />
<br />
==== clean ====<br />
Removes all generated files.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>destDir</code>, <code>l10nDir</code>,<br />
<code>manifestDir</code>, <code>package</code>.<br />
<br />
This task should be executed before a normal build using<br />
<code>app</code> or <code>default</code> after changing any build<br />
variables and after a switch between Git branches. Normal<br />
incremental builds can miss changed files if a branch switch<br />
replaces files by older versions.<br />
<br />
==== default ====<br />
Builds OX App Suite.<br />
<br />
<b>Variables:</b> <code>[[#BASEDIR|BASEDIR]]</code>, <code>[[#builddir|builddir]]</code>, <code>[[#debug|debug]]</code>, <code>[[#disableStrictMode|disableStrictMode]]</code>, <code>[[#l10nDir|l10nDir]]</code>, <code>[[#manifestDir|manifestDir]]</code>, <code>[[#package|package]]</code>, <code>[[#revision|revision]]</code>, <code>[[#version|version]]</code>.<br />
<br />
This is the main task to build OX App Suite. Since it is the default<br />
Jake task, it does not need to be specified explicitly on<br />
the command line when it is the only task.<br />
<br />
It works without explicitly specifying any variables, but during<br />
development, <code>[[#builddir|builddir]]</code> is usually pointed to<br />
a directory which is accessible to a local web server. For<br />
debugging, <code>[[#debug|debug]]</code> is also often used. Note that<br />
<code>[[#clean|clean]]</code> must be called when changing any of<br />
the variables.<br />
<br />
==== deps ====<br />
Prints module dependencies.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>package</code>,<br />
<code>reverse</code>, <code>root</code>.<br />
<br />
This task visualizes dependencies of RequireJS modules. It prints<br />
a tree of dependencies to <code>stdout</code>.<br />
<br />
If <code>root</code> is specified, then only the dependencies of<br />
that module are printed. Otherwise, the dependencies of all modules,<br />
on which no other module depends are printed in sequence. <br />
<br />
If <code>reverse</code> is specified, then this task prints<br />
dependants instead of dependencies, i.e. modules which depend on<br />
the specified module instead of modules on which the specified<br />
module depends.<br />
<br />
==== dist ====<br />
Creates source packages.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>destDir</code>, <code>forceDeb</code>, <code>l10nDir</code>,<br />
<code>manifestDir</code>, <code>package</code>,<br />
<code>revision</code>, <code>skipDeb</code>,<br />
<code>version</code>.<br />
<br />
This task cleans the source tree by calling <code>clean</code> and<br />
packs the source into an archive which can be used to create Debian<br />
and RPM packages. The necessary Debian metadata is created alongside<br />
the source archive. All files necessary for Debian packaging are<br />
placed in the directory specified by <code>destDir</code>.<br />
The generated <code>.orig.tar.bz2</code> archive can also be used<br />
together with the <code>.spec</code> file to generate RPM packages.<br />
<br />
Unless the variable <code>skipDeb</code> is set to<br />
<code>true</code>, the program <code>dpkg-source</code> is required<br />
by this task. It is used to generate Debian-specific packaging<br />
metadata.<br />
<br />
==== init-packaging ====<br />
Initializes packaging information for a new app.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>copyright</code>,<br />
<code>description</code>, <code>license</code>,<br />
<code>licenseName</code>, <code>maintainer</code>,<br />
<code>package</code>, <code>version</code>.<br />
<br />
This task is the first task called when starting with<br />
the development of a new external app. The directory from which it<br />
is called must already contain at least the <code>apps</code><br />
subdirectory. This is also the only task where<br />
the <code>package</code> variable must be specified explicitly.<br />
Afterwards, the package name is looked up automatically in the file<br />
<code>debian/changelog</code>, which is created by this task.<br />
<br />
The variables <code>version</code>, <code>maintainer</code>,<br />
<code>copyright</code>, <code>licenseName</code>,<br />
<code>license</code>, and <code>description</code> are required to<br />
fill out all necessary packaging metadata. Any of these variables<br />
which are not specified explicitly will cause an interactive prompt.<br />
This avoids the need to remember the list of variables before one<br />
can start developing an app.<br />
<br />
==== jakedeps ====<br />
Shows the dependency chain between two Jake tasks.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>from</code>,<br />
<code>package</code>, <code>to</code>.<br />
<br />
This task visualized dependencies between Jake tasks. The variable<br />
<code>from</code> specifies the root of a dependency tree, with all<br />
dependencies of <code>from</code> as inner and leaf nodes. If<br />
<code>to</code> is not specified, then that entire tree is printed.<br />
<br />
If <code>to</code> is also specified, then only the first found<br />
dependency path from <code>from</code> to <code>to</code> is<br />
.printed with <code>to</code> at the top and <code>from</code> at<br />
the bottom.<br />
<br />
==== merge ====<br />
Updates all <code>.po</code> files with the generated<br />
<code>ox.pot</code>.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>debug</code>, <code>package</code>, <code>revision</code>,<br />
<code>version</code>.<br />
<br />
This task updates the list of extracted i18n strings in<br />
<code>ox.pot</code> and calls the GNU Gettext tool<br />
<code>msgmerge</code> for every language in <code>i18n/*.po</code>.<br />
<br />
<code>i18n/en_US.po</code> is not updated by this task because the original strings are already in the <code>en_US</code> locale. It would only end up with every translation mapping every string to itself. The only entries in that file should be for cases when the <code>en_US</code> text is not a suitable fallback for missing translations. The original string in such a case would be something internationally appropriate (e.&nbsp;g. a date written as "2013-01-01" instead of "01/01/2013") and <code>i18n/en_US.po</code> would contain a translation.<br />
<br />
==== update-i18n ====<br />
Updates CLDR data in the source tree.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>branch</code>,<br />
<code>package</code>, <code>tag</code>.<br />
<br />
This task downloads data from the Unicode CLDR and updates date<br />
translations for all languages in <code>i18n/*.po</code>.<br />
<br />
The exact version of CLDR data is specified as Suubversion tag or<br />
branch by the variables <code>tag</code> and <code>branch</code>,<br />
respectively. If neither is specified, then the Subversion trunk is<br />
checked out. If both are specified, <code>tag</code> is used.<br />
<br />
==== verify-doc ====<br />
Generates a documentation skeleton for extension points.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>package</code>.<br />
<br />
This task is still under development. Currently, it creates a list of all extension points, which have a constant name in the source code. In the future it is supposed to update an existing list instead of overwriting it, and to handle non-constant extension point names.<br />
<br />
The list of extension points is stored as an HTML snippet in <code>doc/extensionpoints.html</code>.<br />
<br />
<br />
[[Category:AppSuite]]<br />
[[Category:UI]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:UI_build_system&diff=16184AppSuite:UI build system2013-10-23T15:54:25Z<p>Mark.schmidts: /* Installing */</p>
<hr />
<div>{{Stability-experimental}}<br />
<br />
<div class="title">Build System</div><br />
<br />
'''Abstract:''' This document describes the build system of OX App Suite. It is intended for app developers who use the build system to create apps as well as for OX App Suite developers who not only use the build system but also may wish to extend it.<br />
<br />
The build system is used to create source archives from source files. These source archives can be used to compile installable packages for various Linux distributions. The build system can generate archives for the core UI as well as for independently installed apps.<br />
<br />
The OX App Suite build system uses [https://github.com/mde/jake Jake], a port of Rake from Ruby to [http://nodejs.org Node.js]. Both Rake and Jake are dependency-based build systems like Make, which allows quick incremental builds. But unlike Make, Jake doesn't have its own syntax. Instead, it provides an API in JavaScript. The API is used not only to specify dependencies between files using a full programming language, but also to implement the generation of files in the same language. This allows easy implementation of complex build systems, of which the OX App Suite build system is an example. Using the same language for the developed project and for its build system also allows any core developer to quickly extend the build system without having to switch to another language.<br />
<br />
== Using the Build System ==<br />
<br />
While easily extensible, most of the time the build system will be used as-is. This chapter describes how to set up and use the build system to develop apps and the OX App Suite core.<br />
<br />
All command examples are given for the Debian operating system. The instructions should work similarly on other POSIX systems. The first character of each command indicates whether it should be executed as root (#) or as a normal user ($).<br />
<br />
== Installing ==<br />
<br />
Installing the right environment for running the Appserver and the UI build system is described in [[AppSuite:Appserver | the Appserver article]].<br />
<br />
== Running ==<br />
<br />
The build system is executed by invoking the command <code>build-appsuite</code>. Similar to most build systems, the build system can perform multiple tasks, which are specified as parameters on the command line. Each task can require any number of parameters. These parameters can be specified either on the command line, using the syntax <code>name=value</code>, or as environment variables.<br />
<br />
If present, the file <code>local.conf</code> is sourced by a shell script before the build process starts. This file can export environment variables which are specific to the local system, without checking them into a version control system. Typically, it defines values for <code>[[#builddir|builddir]]</code> and <code>[[#debug|debug]]</code>.<br />
<br />
Since the build system is based on Jake, it also accepts all other Jake options. In addition, the environment variable <code>$nodeopts</code> can be used to pass command line parameters to Node.js. One of the most useful parameters is <code>--debug-brk</code>, which can be used to debug the build system.<br />
<br />
When developing external apps, the build system must be run from the top directory of the app's source. As a safety precaution, execution is aborted if the subdirectory <code>apps</code>, which usually contains JavaScript source code, is not found. This Article is written assuming, you're working in your workspace directory, containing the subfolder <code>apps</code>.<br />
<br />
== Workflow ==<br />
<br />
The build system is used not only to create source archives for packaging. It can also directly install and update the built UI in a directory during development, help with the setup of the source of a new external app and more. While all of these tasks are described in the reference section, daily work involves just a few of them.<br />
<br />
=== Create packaging metadata ===<br />
<br />
The first task which should be executed when creating a new external app is <code>[[#init-packaging|init-packaging]]</code>. It creates packaging metadata in the current directory. It requires the parameter <code>package</code> to specify the package name in the generated files. All subsequent tasks will automatically extract the package name from the files generated by <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
Before execution, the <code>apps</code> subdirectory must be created. It indicates that the current directory is actually a valid source directory.<br />
<br />
$ mkdir apps<br />
$ build-appsuite init-packaging package=example-app<br />
Build path: build<br />
Build version: 0.0.1-1.20130424.123835<br />
<br />
Version [0.0.1]: <br />
<br />
Maintainer (Name <e-mail>): Maintainer <maintainer@example.com><br />
<br />
Copyright line [2013 Open-Xchange, Inc]: <br />
<br />
License name [CC-BY-NC-SA-3.0]: <br />
<br />
Short description: Hello World app to demonstrate usage of the build system<br />
<br />
The task presents a number of interactive prompts to get the necessary information about the generated packages. The entered values should follow the Debian Maintainer's Guide. Some or even all prompts can be skipped by explicitly specifying the information as a build variable. The list of variable names is available in the reference of <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
After the task is finished, the generated files can be customized manually to account for any additional packaging requirements.<br />
<br />
=== Building apps ===<br />
<br />
To have an easy example about how to write, build and host your javascript code, please have a look at the [[AppSuite:GettingStarted | GettingStarted article]].<br />
<br />
==== JSHINT ====<br />
<br />
One step of the build process is running jshint to statically analyse the sources for certain errors. JSHint is configured with (what we think) sane defaults, but if you want to configure your own rules, edit <code>.jshintrc</code> in your project`s root folder, according to your needs.<br />
<br />
=== default ===<br />
<br />
The default task is used instead of the app task when building the core OX App Suite. Since it is the default Jake task, it is not necessary to specify it on the command line when it's the only task.<br />
<br />
The top directory of OX App Suite source code includes the script <code>build.sh</code>, which should be used instead of calling a potentially unrelated version of <code>build-appsuite</code>. The script changes the current directory to its own, so that it can be called from any directory.<br />
<br />
$ web/ui/build.sh<br />
<br />
=== clean ===<br />
<br />
The build system uses dependencies and file timestamps to decide which files to rebuild. This assumes that any change to a file increases its timestamp to a value which is greater than the timestamp of any existing file. When this assumption is violated (e.g. after switching to a different source control branch with older files) it may become necessary to rebuild everything to restore the assumption about timestamps. The simplest way to achieve this is the clean task, which simply deletes all generated files.<br />
<br />
WARNING: This can be potentially dangerous, since the clean task simply deletes the directories specified by the variables builddir, destDir, l10nDir, manifestDir, and helpDir.<br />
<br />
=== dist ===<br />
<br />
When the app is ready to be shipped, or rather all the time on a continuous build system, the app needs to be packaged in a format suitable for installation on a production system. Since there already exist tools to create packages from suitably arranged source code archives, the OX App Suite build system merely prepares such source archives.<br />
<br />
The dist task creates an archive with the source (the one ending in .orig.tar.bz2) and a few additional files necessary for Debian packaging. RPM packages can be generated using the same source archive and the .spec file created by init-packaging. The version of the package is extracted from the newest entry in the file debian/changelog.<br />
<br />
Debian packages can also be generated manually either from the temporary directory left behind by dist, or even directly from the source tree. The second option pollutes the source tree with generated files, so it is not recommended, although the .gitignore file created by init-packaging can handle these generated files.<br />
<br />
$ build-appsuite dist<br />
$ ls tmp/packaging/<br />
example-app-0.0.1 example-app_0.0.1-1.dsc<br />
example-app_0.0.1-1.debian.tar.bz2 example-app_0.0.1.orig.tar.bz2<br />
$ cd tmp/packaging/example-app-0.0.1/<br />
$ dpkg-buildpackage -b<br />
<br />
== Reference ==<br />
<br />
=== Variables ===<br />
<br />
==== BASEDIR ====<br />
The top directory of the build system.<br />
<br />
<b>Used by:</b> all tasks.<br />
<br />
<b>Default:</b> installation directory of the build system<br />
<br />
Required to build external apps, since in this case, the build<br />
system is not installed in the current directory. This variable is<br />
automatically set as an environment variable by the build system<br />
executable based on <code>$OX_APPSUITE_DEV</code>.<br />
<br />
==== branch ====<br />
The Subversion branch of the CLDR to checkout.<br />
<br />
<b>Used by:</b> <code>update-i18n</code>.<br />
<br />
==== builddir ====<br />
The target directory for generated files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>, <code>docs</code>,<br />
<code>jakedeps</code>.<br />
<br />
Default: <code>build</code><br />
<br />
==== copyright ====<br />
The copyright line to be included in packaging metadata.<br />
<br />
<b>Used by:</b> <code>[[#init-packaging|init-packaging]]</code>.<br />
<br />
<b>Example:</b> <code>2012 Open-Xchange, Inc</code><br />
<br />
==== coreDir ====<br />
Location of OX App Suite UI files.<br />
<br />
<b>Used by:</b> <code>[[#app|app]]</code>, <code>[[#default|default]]</code>.<br />
<br />
<b>Default:</b> same as <code>[[#builddir|builddir]]</code><br />
<br />
Some tasks depend on installed files from the OX App Suite. When building external apps, <code>[[#coreDir|coreDir]]</code> specified the directory which contains these files.<br />
<br />
Currently, this parameter is used to compile <code>.less</code> files for every installed theme. This can be disabled by setting <code>[[#skipLess|skipLess]]</code>.<br />
<br />
==== debug ====<br />
Enables a debug build.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
To simplify debugging of OX App Suite, compression of source code<br />
can be disabled by specifying <code>on</code>, <code>yes</code>,<br />
<code>true</code> or <code>1</code>.<br />
<br />
==== description ====<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
The description of the app to be included in packaging metadata.<br />
<br />
==== destDir ====<br />
Output directory for source archives created by<br />
the <code>dist</code> task.<br />
<br />
<b>Used by:</b> <code>clean</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> <code>tmp/packaging</code><br />
<br />
==== disableStrictMode ====<br />
Removes all <code>"use strict"</code> directives from processed<br />
JavaScript code.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
Some debugging tools which use code instrumentation have problems<br />
when the debugged code uses strict mode. This setting enables code<br />
processing even whe using <code>debug</code> mode, so line numbers<br />
will not match the original source code.<br />
<br />
==== forceDeb ====<br />
Whether an error during the generation of Debian source packages is an error.<br />
<br />
<b>Used by:</b> <code>dist</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This is useful when Debian packages are generated automatically, and a failure of <code>dpkg-source</code> is also a failure of the entire build. By default it merely produces a warning.<br />
<br />
==== from ====<br />
The root of the printed dependency tree between Jake tasks.<br />
<br />
<b>Used by:</b> <code>jakedeps</code>.<br />
<br />
==== helpDir ====<br />
The location of online help files.<br />
<br />
<b>Used by:</b> <code>clean</code>, <code>default</code>,<br />
<code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
If the value contains the string <code>@lang@</code>, it will be<br />
replaced by the lowercase language code (e.g. <code>en-us</code>) to<br />
allow per-language directories.<br />
<br />
==== l10nDir ====<br />
The location of compiled l10n files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
If the value contains the string <code>@lang@</code>, it will be<br />
replaced by the lowercase language code (e.g. <code>en-us</code>) to<br />
allow per-language directories.<br />
<br />
==== license ====<br />
File name of the full text of the distribution license.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Default:</b> based on <code>licenseName</code>.<br />
<br />
==== licenseName ====<br />
Name of the distribution license to be included in packaging<br />
metadata.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Default:</b> <code>CC-BY-NC-SA-3.0</code><br />
<br />
==== manifestDir ====<br />
The location of the combined manifest file.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>clean</code>,<br />
<code>default</code>, <code>dist</code>.<br />
<br />
<b>Default:</b> same as <code>builddir</code><br />
<br />
==== maintainer ====<br />
Name and email address of the package maintainer.<br />
<br />
<b>Used by:</b> <code>init-packaging</code>.<br />
<br />
<b>Format:</b> <code><var>Name</var> &lt;<var>email</var>&gt;</code><br />
<br />
==== package ====<br />
The name of the package for the built app.<br />
<br />
<b>Used by:</b> all tasks.<br />
<br />
<b>Default:</b> the package name in the first line of<br />
<code>debian/changelog</code><br />
<br />
Since the name of the manifest file contains the package name and it<br />
is required to determine build dependencies, the package name must<br />
be always known. This means either <code>debian/changelog</code><br />
must exist and contain at least one entry, or the parameter must be<br />
explicitly specified.<br />
<br />
==== reverse ====<br />
Reverses the direction of printed dependencies.<br />
<br />
<b>Used by:</b> <code>deps</code>.<br />
<br />
When specified, the <code>deps</code> task prints modules which<br />
depend on the specified modules, instead of modules on which<br />
the specified module depends.<br />
<br />
==== revision ====<br />
Revision number of the package for the app.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>,<br />
<code>dist</code>.<br />
<br />
<b>Default:</b> <code>1</code><br />
<br />
The revision number must increase with each rebuild of the same<br />
version to enable the creation of unique version strings. These are<br />
required in package names and to control content caching in clients.<br />
<br />
==== root ====<br />
Specifies for which module to print the dependencies.<br />
<br />
<b>Used by:</b> <code>deps</code>.<br />
<br />
<b>Default:</b> print all roots<br />
<br />
If specified, only the dependencies of the specified module are<br />
printed. Otherwise, the dependencies of all modules are printed.<br />
<br />
==== skipDeb ====<br />
Whether to skip the generation of Debian source packages.<br />
<br />
<b>Used by:</b> <code>dist</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This is useful when Debian packages are not required and/or<br />
<code>dpkg-source</code> is not available, e.g. on RPM based<br />
systems.<br />
<br />
Even when using this flag, at least the file<br />
<code>debian/changelog</code> is still required, because it is used<br />
to store the package name and version. <br />
<br />
==== skipLess ====<br />
Whether to skip the preprocessing of LessCSS files.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>.<br />
<br />
<b>Default:</b> <code>false</code><br />
<br />
This flag skips the generation of CSS files in<br />
the <code>apps/themes/*/less</code> directories of all themes.<br />
It is used by the packaging system, where the LessCSS files are<br />
precompiled after installation on the target system instead of<br />
while building the package.<br />
<br />
==== tag ====<br />
The Subversion tag of the CLDR to checkout.<br />
<br />
<b>Used by:</b> <code>update-i18n</code>.<br />
<br />
==== to ====<br />
The leaf task in the printed dependency path between Jake tasks.<br />
<br />
<b>Used by:</b> <code>jakedeps</code>.<br />
<br />
When specified, only a single path from the root to the leaf task is<br />
printed (in reverse order).<br />
<br />
==== version ====<br />
Version number of the app.<br />
<br />
<b>Used by:</b> <code>app</code>, <code>default</code>,<br />
<code>dist</code>, <code>init-packaging</code>.<br />
<br />
<b>Default:</b> <code>0.0.1</code><br />
<br />
The version should consist of a major, minor and patch version<br />
separated by dots.<br />
<br />
=== Tasks ===<br />
<p><br />
An up-to-date list of tasks can be printed using the -T command line option.<br />
<br />
==== app ====<br />
Builds an external app.<br />
<br />
<b>Variables:</b> <code>[[#BASEDIR|BASEDIR]]</code>, <code>[[#builddir|builddir]]</code>, <code>[[#coreDir|coreDir]]</code>, <code>[[#debug|debug]]</code>, <code>[[#disableStrictMode|disableStrictMode]]</code>, <code>[[#l10nDir|l10nDir]]</code>, <code>[[#manifestDir|manifestDir]]</code>, <code>[[#package|package]]</code>, <code>[[#revision|revision]]</code>, <code>[[#version|version]]</code>.<br />
<br />
This is the main task used to build external apps.<br />
<br />
It works without explicitly specifying any variables, but during<br />
development, <code>[[#builddir|builddir]]</code> is usually pointed to<br />
the directory of a locally installed OX App Suite UI to avoid<br />
additional copying steps. For debugging, <code>[[#debug|debug]]</code> is also<br />
often used. Note that <code>[[#clean|clean]]</code> must be called when<br />
changing any of the variables.<br />
<br />
==== clean ====<br />
Removes all generated files.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>destDir</code>, <code>l10nDir</code>,<br />
<code>manifestDir</code>, <code>package</code>.<br />
<br />
This task should be executed before a normal build using<br />
<code>app</code> or <code>default</code> after changing any build<br />
variables and after a switch between Git branches. Normal<br />
incremental builds can miss changed files if a branch switch<br />
replaces files by older versions.<br />
<br />
==== default ====<br />
Builds OX App Suite.<br />
<br />
<b>Variables:</b> <code>[[#BASEDIR|BASEDIR]]</code>, <code>[[#builddir|builddir]]</code>, <code>[[#debug|debug]]</code>, <code>[[#disableStrictMode|disableStrictMode]]</code>, <code>[[#l10nDir|l10nDir]]</code>, <code>[[#manifestDir|manifestDir]]</code>, <code>[[#package|package]]</code>, <code>[[#revision|revision]]</code>, <code>[[#version|version]]</code>.<br />
<br />
This is the main task to build OX App Suite. Since it is the default<br />
Jake task, it does not need to be specified explicitly on<br />
the command line when it is the only task.<br />
<br />
It works without explicitly specifying any variables, but during<br />
development, <code>[[#builddir|builddir]]</code> is usually pointed to<br />
a directory which is accessible to a local web server. For<br />
debugging, <code>[[#debug|debug]]</code> is also often used. Note that<br />
<code>[[#clean|clean]]</code> must be called when changing any of<br />
the variables.<br />
<br />
==== deps ====<br />
Prints module dependencies.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>package</code>,<br />
<code>reverse</code>, <code>root</code>.<br />
<br />
This task visualizes dependencies of RequireJS modules. It prints<br />
a tree of dependencies to <code>stdout</code>.<br />
<br />
If <code>root</code> is specified, then only the dependencies of<br />
that module are printed. Otherwise, the dependencies of all modules,<br />
on which no other module depends are printed in sequence. <br />
<br />
If <code>reverse</code> is specified, then this task prints<br />
dependants instead of dependencies, i.e. modules which depend on<br />
the specified module instead of modules on which the specified<br />
module depends.<br />
<br />
==== dist ====<br />
Creates source packages.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>destDir</code>, <code>forceDeb</code>, <code>l10nDir</code>,<br />
<code>manifestDir</code>, <code>package</code>,<br />
<code>revision</code>, <code>skipDeb</code>,<br />
<code>version</code>.<br />
<br />
This task cleans the source tree by calling <code>clean</code> and<br />
packs the source into an archive which can be used to create Debian<br />
and RPM packages. The necessary Debian metadata is created alongside<br />
the source archive. All files necessary for Debian packaging are<br />
placed in the directory specified by <code>destDir</code>.<br />
The generated <code>.orig.tar.bz2</code> archive can also be used<br />
together with the <code>.spec</code> file to generate RPM packages.<br />
<br />
Unless the variable <code>skipDeb</code> is set to<br />
<code>true</code>, the program <code>dpkg-source</code> is required<br />
by this task. It is used to generate Debian-specific packaging<br />
metadata.<br />
<br />
==== init-packaging ====<br />
Initializes packaging information for a new app.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>copyright</code>,<br />
<code>description</code>, <code>license</code>,<br />
<code>licenseName</code>, <code>maintainer</code>,<br />
<code>package</code>, <code>version</code>.<br />
<br />
This task is the first task called when starting with<br />
the development of a new external app. The directory from which it<br />
is called must already contain at least the <code>apps</code><br />
subdirectory. This is also the only task where<br />
the <code>package</code> variable must be specified explicitly.<br />
Afterwards, the package name is looked up automatically in the file<br />
<code>debian/changelog</code>, which is created by this task.<br />
<br />
The variables <code>version</code>, <code>maintainer</code>,<br />
<code>copyright</code>, <code>licenseName</code>,<br />
<code>license</code>, and <code>description</code> are required to<br />
fill out all necessary packaging metadata. Any of these variables<br />
which are not specified explicitly will cause an interactive prompt.<br />
This avoids the need to remember the list of variables before one<br />
can start developing an app.<br />
<br />
==== jakedeps ====<br />
Shows the dependency chain between two Jake tasks.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>from</code>,<br />
<code>package</code>, <code>to</code>.<br />
<br />
This task visualized dependencies between Jake tasks. The variable<br />
<code>from</code> specifies the root of a dependency tree, with all<br />
dependencies of <code>from</code> as inner and leaf nodes. If<br />
<code>to</code> is not specified, then that entire tree is printed.<br />
<br />
If <code>to</code> is also specified, then only the first found<br />
dependency path from <code>from</code> to <code>to</code> is<br />
.printed with <code>to</code> at the top and <code>from</code> at<br />
the bottom.<br />
<br />
==== merge ====<br />
Updates all <code>.po</code> files with the generated<br />
<code>ox.pot</code>.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>builddir</code>,<br />
<code>debug</code>, <code>package</code>, <code>revision</code>,<br />
<code>version</code>.<br />
<br />
This task updates the list of extracted i18n strings in<br />
<code>ox.pot</code> and calls the GNU Gettext tool<br />
<code>msgmerge</code> for every language in <code>i18n/*.po</code>.<br />
<br />
<code>i18n/en_US.po</code> is not updated by this task because the original strings are already in the <code>en_US</code> locale. It would only end up with every translation mapping every string to itself. The only entries in that file should be for cases when the <code>en_US</code> text is not a suitable fallback for missing translations. The original string in such a case would be something internationally appropriate (e.&nbsp;g. a date written as "2013-01-01" instead of "01/01/2013") and <code>i18n/en_US.po</code> would contain a translation.<br />
<br />
==== update-i18n ====<br />
Updates CLDR data in the source tree.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>branch</code>,<br />
<code>package</code>, <code>tag</code>.<br />
<br />
This task downloads data from the Unicode CLDR and updates date<br />
translations for all languages in <code>i18n/*.po</code>.<br />
<br />
The exact version of CLDR data is specified as Suubversion tag or<br />
branch by the variables <code>tag</code> and <code>branch</code>,<br />
respectively. If neither is specified, then the Subversion trunk is<br />
checked out. If both are specified, <code>tag</code> is used.<br />
<br />
==== verify-doc ====<br />
Generates a documentation skeleton for extension points.<br />
<br />
<b>Variables:</b> <code>BASEDIR</code>, <code>package</code>.<br />
<br />
This task is still under development. Currently, it creates a list of all extension points, which have a constant name in the source code. In the future it is supposed to update an existing list instead of overwriting it, and to handle non-constant extension point names.<br />
<br />
The list of extension points is stored as an HTML snippet in <code>doc/extensionpoints.html</code>.<br />
<br />
<br />
[[Category:AppSuite]]<br />
[[Category:UI]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Writing_contact_plugin&diff=16183AppSuite:Writing contact plugin2013-10-23T15:50:38Z<p>Mark.schmidts: Blanked the page</p>
<hr />
<div></div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Writing_contact_plugin&diff=16182AppSuite:Writing contact plugin2013-10-23T15:50:32Z<p>Mark.schmidts: </p>
<hr />
<div>[[]]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Writing_contact_plugin&diff=16181AppSuite:Writing contact plugin2013-10-23T15:50:24Z<p>Mark.schmidts: Replaced content with "[]"</p>
<hr />
<div>[]</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Developing_for_the_UI&diff=16180AppSuite:Developing for the UI2013-10-23T15:50:06Z<p>Mark.schmidts: /* What can i build? */</p>
<hr />
<div><div class="title">UI Development for OX AppSuite</div><br />
<br />
__TOC__<br />
<br />
This page contains articles about the inner workings of the web-based graphical user interface. It is aimed at software developers that want to improve on existing features, implement extensions or just gain a general understanding.<br />
<br />
=== Tech Overview ===<br />
All technologies and frameworks used for developing a new component for the AppSuite UI are listed and described in the following article: [[AppSuite:UI developer primer| Skills needed to develop the UI]]<br />
<br />
=== Developing Guidelines ===<br />
While developing code for OX products [[AppSuite:UI Development Style Guide | the UI Developement Style Guide]] helps you writing safe, clear and functional code.<br />
<br />
Designing apps, plugins and widgets running with the right layout, colors, look and feel is a breeze following the guidelines described in [[AppSuite:UI Design Guide | the UI Design Guide]].<br />
<br />
Always keep in mind, that using OX products should be possible for everyone and therefor it's important to follow simple rules regarding [[AppSuite:Accessibility | accessibility]].<br />
<br />
=== Using extension points ===<br />
<br />
Writing apps or plugins for AppSuite will often include extending the existing user interface. AppSuite provides extension points offering you possibilties to add your own contents.<br />
Beginning to develop using extension points? Read this guide first having [[AppSuite:Extending the UI (Hands-on introduction) | a hands-on introduction]] for extending the OX user interface. Get more information and a complete list of [[AppSuite:Extension points |extension points]] offered by OX products.<br />
<br />
=== How to get code ===<br />
Using git as a version version control system getting the code from existing OX products is quite easy.<br />
Simply clone the [[AppSuite:UI build system#Source | UI]] or the [[AppSuite:Backend build system#Source | backend]] repository and start working with it.<br />
<br />
=== What can i build? ===<br />
<br />
If you want to have a simple introduction following easy steps from creating your workspace to actually performing your source code within AppSuite, read our [[AppSuite:GettingStarted | GettingStarted guide]].<br />
<br />
There are several other possibilities available to develop for AppSuite.<br />
<br />
*[[AppSuite:Writing a portal plugin | A portal plugin]] is a widget, which can be used in the 'portal'-section of AppSuite only. Please just check for the right [[AppSuite:Extension points |extension point]] to write a plugin which extends and interacts with other parts of AppSuite. Configuring portal plugins can be achieved by reading [[AppSuite:Configuring portal plugins | this guide]].<br />
<br />
*[[AppSuite:Writing_a_contacts_plugin | A contacts plugin]] let's you modify parts of AppSuite's contact view.<br />
<br />
*[[AppSuite:Using the Upsell widget | Upsell Widget]], to enable the AppSuite user to purchase additional features. <br />
<br />
*[[AppSuite:Writing a simple application | A real application/module]] for AppSuite, which should be displayed full screen and appear as a bread crump in the title bar, take a look at the article about [[AppSuite:Writing a simple application | 'Writing a simple application']].<br />
<br />
*[[AppSuite:Writing a notification area plugin | A notification plugin]] for AppSuite<br />
<br />
*[[AppSuite:Writing a wizard | A wizard]], which can be first time users to show them important informations or configure initial settings for 3rd party applications.<br />
<br />
*[[AppSuite:Embedding your settings into AppSuite settings | Settings plugin]] to provide a UI for storing settings of your application.<br />
<br />
You got stuck somewhere? There are some hints, which might help you [[AppSuite:Debugging_the_UI | debugging the UI]].<br />
<br />
=== How to get your code running ===<br />
Written your first app/plugin? Using the [[AppSuite:UI build system | UI build system]] will help you to get fast, easy-to-distribute and correct builds running on your AppSuite. The article will show you how to package your code and copy from OX source code / directories.<br />
<br />
Since the AppSuite product consists of a server and a UI, you also need a working backend (AppSuite application server) to communicate with. <br />
Therefor you should run [[AppSuite:Appserver | Appserver]] using an existing OX AppSuite server and (with local parts of the AppSuite) automaticly get the recent stable source packages from the AppSuite servers. For using your namespace as a source for hosting your app, simply add the build-path of your app as an parameter while running appserver.<br />
<br />
=== What's next ===<br />
No Idea what to do first? Read our [[AppSuite:GettingStarted | GettingStarted guide]] to have a step-by-step introduction about how to install the SDK, use the Build System, write your first app and get it running.</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Writing_a_contacts_plugin&diff=16179AppSuite:Writing a contacts plugin2013-10-23T15:49:23Z<p>Mark.schmidts: Created page with "== Where and how to start == Plugins are collected in the folder ui/apps/plugins. Start your new plugin there: Create a folder and in this folder, create two files: <tt>regist..."</p>
<hr />
<div>== Where and how to start ==<br />
Plugins are collected in the folder ui/apps/plugins. Start your new plugin there: Create a folder and in this folder, create two files: <tt>register.js</tt> (where everything happens) and <tt>manifest.json</tt><br />
<br />
<br />
== What are you going to do ==<br />
Your plugin code can interact with the app suite is by way of extension points and extensions. Stated briefly an extension point is an invitation to contributing an implementation to a part of the UI. For example the contact detail view consists of an extension point that receives contributions in the form of renderers, that render different parts of the contact. Say, one for rendering the display name, one for the mail addresses, one for the postal addresses and so on. All these, in turn then, make up the contacts detail view. It is easy for plugins to affect this set of extensions. A plugin can contribute its own extension to an extension point, thereby rendering a different part of a contact or contributing a new button to work on a contact. A plugin can also disable existing extensions, thereby removing parts of the UI.<br />
<br />
== Hans-On ==<br />
=== Register ===<br />
As an example, let's add a new renderer to the contact detail view. Let's create a new file myplugin/apps/com.example/contacts/register.js:<br />
<br />
<pre class="language-javacript"><br />
define('com.example/contacts/register', ['io.ox/core/extensions'], function (ext) {<br />
'use strict';<br />
<br />
ext.point('io.ox/contacts/detail').extend({<br />
id: 'com-example-contact-reversename',<br />
after: 'contact-details',<br />
draw: function (baton) {<br />
<br />
var name = baton.data.display_name;<br />
var rev = name.split("").reverse().join("");<br />
<br />
this.append(<br />
$("<h1>").text(rev)<br />
));<br />
}<br />
});<br />
});<br />
</pre><br />
<br />
=== Manifest ===<br />
Next we have to make sure our code is actually loaded by the UI at the right moment. The right moment in our case is right before it loads the file apps/io.ox/contacts/view-detail, where the extension point is processed. For this, we need another [[AppSuite:UI_manifests_explained | manifest]] file at myplugin/apps/com.example/contacts/manifest.json:<br />
<br />
<pre class="language-javacript"><br />
{<br />
namespace: "io.ox/contacts/view-detail"<br />
}<br />
</pre><br />
<br />
After writing your code, always [[AppSuite:GettingStarted#Building | build]] your javascript code to make apply.<br />
See the [[AppSuite:GettingStarted#Development_cycle | development cycle]] to keep easy steps in mind you need while developing.<br />
<br />
=== Running a local backend? ===<br />
<br />
If using a local backend, restart it to pick up on the changed manifest, or, for a remote backend, edit myplugin/src/manifests.js again so it reads:<br />
<br />
<pre class="language-javacript"><br />
define(function () {<br />
return [<br />
{<br />
path: "com.example/main",<br />
title: 'Hello World App'<br />
},<br />
{<br />
path: "com.example/contacts/register",<br />
namespace: "io.ox/contacts/view-detail"<br />
}<br />
];<br />
});<br />
</pre><br />
<br />
reload the UI and navigate to a contact. It should contain the new section with the display name in reverse.<br />
<br />
== Extension Points ==<br />
Trouble [[AppSuite:Extending_the_UI_(Hands-on_introduction)#Trouble_finding_the_right_extension_point.3F | finding the right extension point]]?<br />
Learn more about Extension points regarding [[AppSuite:Extension_points | these articles]].<br />
== Stuck somewhere? ==<br />
You got stuck with a problem while developing? OXpedia might help you out with the article about [[AppSuite:Debugging_the_UI | debugging the UI]].</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Writing_contact_plugin&diff=16178AppSuite:Writing contact plugin2013-10-23T15:47:30Z<p>Mark.schmidts: </p>
<hr />
<div>== Where and how to start ==<br />
Plugins are collected in the folder ui/apps/plugins. Start your new plugin there: Create a folder and in this folder, create two files: <tt>register.js</tt> (where everything happens) and <tt>manifest.json</tt><br />
<br />
<br />
== What are you going to do ==<br />
Your plugin code can interact with the app suite is by way of extension points and extensions. Stated briefly an extension point is an invitation to contributing an implementation to a part of the UI. For example the contact detail view consists of an extension point that receives contributions in the form of renderers, that render different parts of the contact. Say, one for rendering the display name, one for the mail addresses, one for the postal addresses and so on. All these, in turn then, make up the contacts detail view. It is easy for plugins to affect this set of extensions. A plugin can contribute its own extension to an extension point, thereby rendering a different part of a contact or contributing a new button to work on a contact. A plugin can also disable existing extensions, thereby removing parts of the UI.<br />
<br />
== Hans-On ==<br />
=== Register ===<br />
As an example, let's add a new renderer to the contact detail view. Let's create a new file myplugin/apps/com.example/contacts/register.js:<br />
<br />
<pre class="language-javacript"><br />
define('com.example/contacts/register', ['io.ox/core/extensions'], function (ext) {<br />
'use strict';<br />
<br />
ext.point('io.ox/contacts/detail').extend({<br />
id: 'com-example-contact-reversename',<br />
after: 'contact-details',<br />
draw: function (baton) {<br />
<br />
var name = baton.data.display_name;<br />
var rev = name.split("").reverse().join("");<br />
<br />
this.append(<br />
$("<h1>").text(rev)<br />
));<br />
}<br />
});<br />
});<br />
</pre><br />
<br />
=== Manifest ===<br />
Next we have to make sure our code is actually loaded by the UI at the right moment. The right moment in our case is right before it loads the file apps/io.ox/contacts/view-detail, where the extension point is processed. For this, we need another [[AppSuite:UI_manifests_explained | manifest]] file at myplugin/apps/com.example/contacts/manifest.json:<br />
<br />
<pre class="language-javacript"><br />
{<br />
namespace: "io.ox/contacts/view-detail"<br />
}<br />
</pre><br />
<br />
After writing your code, always [[AppSuite:GettingStarted#Building | build]] your javascript code to make apply.<br />
See the [[AppSuite:GettingStarted#Development_cycle | development cycle]] to keep easy steps in mind you need while developing.<br />
<br />
=== Running a local backend? ===<br />
<br />
If using a local backend, restart it to pick up on the changed manifest, or, for a remote backend, edit myplugin/src/manifests.js again so it reads:<br />
<br />
<pre class="language-javacript"><br />
define(function () {<br />
return [<br />
{<br />
path: "com.example/main",<br />
title: 'Hello World App'<br />
},<br />
{<br />
path: "com.example/contacts/register",<br />
namespace: "io.ox/contacts/view-detail"<br />
}<br />
];<br />
});<br />
</pre><br />
<br />
reload the UI and navigate to a contact. It should contain the new section with the display name in reverse.<br />
<br />
== Extension Points ==<br />
Trouble [[AppSuite:Extending_the_UI_(Hands-on_introduction)#Trouble_finding_the_right_extension_point.3F | finding the right extension point]]?<br />
Learn more about Extension points regarding [[AppSuite:Extension_points | these articles]].<br />
== Stuck somewhere? ==<br />
You got stuck with a problem while developing? OXpedia might help you out with the article about [[AppSuite:Debugging_the_UI | debugging the UI]].</div>Mark.schmidtshttps://oxpedia.org/wiki/index.php?title=AppSuite:Writing_contact_plugin&diff=16177AppSuite:Writing contact plugin2013-10-23T15:47:14Z<p>Mark.schmidts: </p>
<hr />
<div>== Where and how to start ==<br />
Plugins are collected in the folder ui/apps/plugins. Start your new plugin there: Create a folder and in this folder, create two files: <tt>register.js</tt> (where everything happens) and <tt>manifest.json</tt><br />
<br />
<br />
== What are you going to do ==<br />
Your plugin code can interact with the app suite is by way of extension points and extensions. Stated briefly an extension point is an invitation to contributing an implementation to a part of the UI. For example the contact detail view consists of an extension point that receives contributions in the form of renderers, that render different parts of the contact. Say, one for rendering the display name, one for the mail addresses, one for the postal addresses and so on. All these, in turn then, make up the contacts detail view. It is easy for plugins to affect this set of extensions. A plugin can contribute its own extension to an extension point, thereby rendering a different part of a contact or contributing a new button to work on a contact. A plugin can also disable existing extensions, thereby removing parts of the UI.<br />
<br />
== Hans-On ==<br />
=== Register ===<br />
As an example, let's add a new renderer to the contact detail view. Let's create a new file myplugin/apps/com.example/contacts/register.js:<br />
<br />
<pre class="language-javacript"><br />
define('com.example/contacts/register', ['io.ox/core/extensions'], function (ext) {<br />
'use strict';<br />
<br />
ext.point('io.ox/contacts/detail').extend({<br />
id: 'com-example-contact-reversename',<br />
after: 'contact-details',<br />
draw: function (baton) {<br />
<br />
var name = baton.data.display_name;<br />
var rev = name.split("").reverse().join("");<br />
<br />
this.append(<br />
$("<h1>").text(rev)<br />
));<br />
}<br />
});<br />
});<br />
</pre><br />
<br />
=== Manifest ===<br />
Next we have to make sure our code is actually loaded by the UI at the right moment. The right moment in our case is right before it loads the file apps/io.ox/contacts/view-detail, where the extension point is processed. For this, we need another [[AppSuite:UI_manifests_explained | manifest]] file at myplugin/apps/com.example/contacts/manifest.json:<br />
<br />
<pre class="language-javacript"><br />
{<br />
namespace: "io.ox/contacts/view-detail"<br />
}<br />
</pre><br />
<br />
After writing your code, always [[AppSuite:GettingStarted#Building | build]] your javascript code to make apply.<br />
See the [[AppSuite:GettingStarted#Development_cycle | development cycle]] to keep easy steps in mind you need while developing.<br />
<br />
=== Running a local backend? ===<br />
<br />
If using a local backend, restart it to pick up on the changed manifest, or, for a remote backend, edit myplugin/src/manifests.js again so it reads:<br />
<br />
<pre class="language-javacript"><br />
define(function () {<br />
return [<br />
{<br />
path: "com.example/main",<br />
title: 'Hello World App'<br />
},<br />
{<br />
path: "com.example/contacts/register",<br />
namespace: "io.ox/contacts/view-detail"<br />
}<br />
];<br />
});<br />
</pre><br />
<br />
reload the UI and navigate to a contact. It should contain the new section with the display name in reverse.<br />
<br />
=== Extension Points ===<br />
Trouble [[AppSuite:Extending_the_UI_(Hands-on_introduction)#Trouble_finding_the_right_extension_point.3F | finding the right extension point]]?<br />
Learn more about Extension points regarding [[AppSuite:Extension_points | these articles]].<br />
== Stuck somewhere? ==<br />
You got stuck with a problem while developing? OXpedia might help you out with the article about [[AppSuite:Debugging_the_UI | debugging the UI]].</div>Mark.schmidts