home, version 18 authored by Marcel Rieger's avatar Marcel Rieger
Other Module Systems
====================
Extensions on client-side (JavaScript)
======================================
Ziemlich gut:
http://www.synthtopia.com/content/2012/05/30/audulus-modular-audio-processor-for-mac/
Content
-------
Bestes:
http://alex4d.files.wordpress.com/2008/12/quartz-composer-ui.jpg
- [Introduction](Extensions\_on\_client-side\_(JavaScript)\#Introduction)
- [Extension
Mechanism](Extensions\_on\_client-side\_(JavaScript)\#Extension-Mechanism)
- [Api](Extensions\_on\_client-side\_(JavaScript)\#Api)
- [Example](Extensions\_on\_client-side\_(JavaScript)\#Example)
- [Troubleshooting](Extensions\_on\_client-side\_(JavaScript)\#Troubleshooting)
http://lithosphere.codeflow.org/screenshots/desert.jpg
Introduction
------------
http://www.mapzoneeditor.com/?PAGE=DOCUMENTATION.IvyLeafKr
TODO
http://commons.wikimedia.org/wiki/File:CompositeNode-Settings\_withText\_BlenderMistTutorial.jpg
Extension Mechanism
-------------------
http://images-l3.native-instruments.com/typo3temp/pics/3\_87d27267c9.png?1314198777
Extensions basically consist of three components - the extension
**Main** object, a **Config** object and a **Content** object.
http://www.bmc.de/ckfinder/userfiles/images/Glossar/DASYLab/Schaltbildansicht.jpg
The **Main** object of an extension contains basic information such as
`name`, `mainMenuEntries` or (and most important) the `content`.
`content` stores references to **Config** objects as key-value pairs:
http://synthmaker.co.uk/images/components%20L.png
<code class="javascript">
this.content = {
tabA: new TestTabA(),
frameB: new TestFrameA(),
...
};
</code>
**Config** objects are instanced at the time, the `content` is set
(unlike **Content** objects). The example above demonstrates that a
**Main** object can have multiple **Config** objects which contain
further information describing the behavior and appearance of content,
e.g. `stlye`, `label` or `maxInstances`. The most important parameters
are `behavior` and `constructor`. `behavior` decides whether the content
is displayed in a *tab* or as a *frame*. `constructor` stores a
reference the the content constructor; the **Content** object. Instances
of this class/object are created dynamically on (user) demand. Its
function `getContent()` is supposed to deliver arbitrary content which
is then used as the visible content.
The hierarchical structuring into these three objects allows one single
extension (**Main**) to have multiple ways (**Config**) of displaying
arbitrary, parallel content (**Content**). The resulting two-step *1:n*
relationship is capable of hosting various types of extensions with
basic or even more sophisticated purposes.
#### Data access inside your Extension
TODO
Api
---
Each of the three objects has two types of members. Members with a
leading *underscore* have a *private* state. They are set by the
extension manager but can be accessed in your extension. Members without
the *underscore* are treated as normal variables.
#### Class `Extension`
- **`name`**
>MANDATORY! The unique name of the extension. Supposed to be the
same name as used as the folder name in the `extensions` folder or
as returned by `getName()` in your `extensions.py`. Case sensitive!
<!-- -->
- **`fileExtensions`**
>File extensions that can be handled by your extension passed as
a map with callbacks:
<code class="javascript">
this.fileExtensions = {
txt: function(path){/* foo */},
xml: function(path){/* bar */},
defaults: {txt: 1, xml: 9}
};
</code>
>The `defaults` entry registers the corresponding file extension
with its callback at a given preference to the extension manager.
LIFO in case of same preference.
<!-- -->
- **`urlCallbacks`**
>URL channels that the extension listens to in a map with
callbacks:
<code class="javascript">
this.urlCallbacks = {
channelABC: function(path){/* foo */},
channelXYZ: function(path){/* bar */},
generators: ["channelABC", ...]
...
};
</code>
>A call to `vispadomain.tld/?channelABC=somestring` will cause
the function `function(path){/* foo */}` to be fired. The
`generators` entry defines channels for which a URL can be generated
dynamically (e.g. from within the `Analysis Designer`). (Also see
`ExtensionContent.getUrlChannelValue()`)
<!-- -->
- **`mainMenuEntries`**
>The main menu entries as an array of `dijit.MenuItem`’s. Please
use `onClick` events. They are automatically converted to `Tap`
events by the platform.
<!-- -->
- **`mainMenuPreference`**
>This preference value (integer) steers the position of main
menu entries in the associated menu. No preference means
“sort-by-extension-name”. Same preferences are handled as LIFO.
<!-- -->
- **`content`**
>The config classes passed with a key, e.g.:
<code class="javascript">
this.content = {
tabA: new TestTabA(),
frameB: new TestFrameA(),
...
};
</code>
#### Class `ExtensionConfig`
- **`_ext`**
>Private. Set by the extension manager. Stores a reference to
the extension main object for data access reasons.
<!-- -->
- **`_key`**
>Private. Set by the extension manager. Stores the key with
which this config object is stored in the `content` object of the
extension main class.
<!-- -->
- **`_lastId`**
>Private. Set by the extension manager. Stores the iterator that
is used to generate continuously running ids.
<!-- -->
- **`_instances`**
>Private. Set by the extension manager. Stores the instances of
the referenced content constructor.
<!-- -->
- **`_create()`**
>Private. Set by default. Creates new content instances.
<!-- -->
- **`maxInstances`**
>The maximum number of parallel instances. 0 means infinit.
<!-- -->
- **`showEmptyTab`**
>‘tab’ BEHAVIOR ONLY. Decides whether empty tabs are shown.
Overrides the global behavior when set.
<!-- -->
- **`label`**
>‘tab’ behavior: used as the extension tab title.
>‘frame’ behavior: used as the frame title. Can be overridden by
the content function `getLabel()`.
<!-- -->
- **`badgeIcon`**
>‘tab’ BEHAVIOR ONLY. The icon that is used in the badge when a
content instance is passive. Can be overridden by the content
function `getBadgeIcon()`. (HxW 45X45)
<!-- -->
- **`menuIcon`**
>The menu icon of the extension menu.
<!-- -->
- **`style`**
>Additional css styles for the content passed as a string.
<!-- -->
- **`behavior`**
>Supposed to be ‘tab’ (default) or ‘frame’, dependent on the
manner of representation of the extension content.
<!-- -->
- **`constructor`**
>A reference to the class/the constructor that creates a new
content instance.
#### Class `ExtensionContent`
- **`_config`**
>Private. Set by the extension manager. Stores a reference to
the config objects that owns this instance.
<!-- -->
- **`_id`**
>Private. Set by the extension manager. Stores a unique id for
this instance.
<!-- -->
- **`_close()`**
>Private. Set by default. Closes this instance and handles all
following steps.
<!-- -->
- **`getLabel()`**
>‘tab’ behavior: used as the title of the badge when this
instance is passive.
>‘frame’ behavior: overrides `label` of the config. Used as the
frame title.
<!-- -->
- **`getBadgeIcon()`**
>‘tab’ BEHAVIOR ONLY. Overrides `badgeIcon` of the config. Can
be used to dynamically set the badge icon. (HxW 45X45)
<!-- -->
- **`extMenuEntries`**
>‘tab’ BEHAVIOR ONLY. Same as `mainMenuEntries` of the main
object but used to define the menu entries of the extension menu.
<!-- -->
- **`getUrlChannelValue(channel)`**
>Returns a value for a URL-`channel` during dynamic URL
generation. (Also see `ExtensionConfig.urlChannels`)
<!-- -->
- **`getContent()`**
>**Used to deliver the content**. Can be a string, a dom node or
even a dojo object.
<!-- -->
- **`beforeFirst()`**
>What happens before the first instance is created? Return false
to prevent the action.
<!-- -->
- **`beforeOpen()`**
>What happens before the instance is opened? Return false to
prevent the action.
<!-- -->
- **`afterOpen`**
>What happens after the instance is opened?
<!-- -->
- **`beforeClose()`**
>What happens before the instance is closed? Return false to
prevent the action.
<!-- -->
- **`afterClose()`**
>What happens after the instance is closed?
<!-- -->
- **`beforeShow()`**
>‘tab’ BEHAVIOR ONLY. What happens before the instance is shown?
Return false to prevent the action.
<!-- -->
- **`afterShow()`**
>‘tab’ BEHAVIOR ONLY. What happens after the instance is shown?
<!-- -->
- **`beforeHide()`**
>‘tab’ BEHAVIOR ONLY. What happens before the instance is
hidden? Return false to prevent the action.
<!-- -->
- **`afterHide()`**
>‘tab’ BEHAVIOR ONLY. What happens after the instance is hidden?
<!-- -->
- **`onResize()`**
>‘tab’ BEHAVIOR ONLY. What happens when the window is resized?
<!-- -->
- **`ready()`**
>**What happens when the content of the instance is loaded?**
This function should be used to render content, to bind events or to
execute other functions that have to be called only once at the very
beginning. Don’t mix with events that should be called in
‘afterShow’ or ‘afterOpen’ which can be fired multiple times!
Example
-------
This minimal example summarizes the basic usage of Extensions on
client-side.
It simply demonstrates the way to setup your Extension and thus, has no
further functionality.
All available options that implement individual behavior are listed in
the [Api](Extensions\_on\_client-side\_(JavaScript)\#Api).
### The Main Config Class
<code class="javascript">
function ExampleExtension ()
{
//inheritance
this.__proto__ = new Extension(this);
//lexical scope
var self = this;
//the name (must be set)
this.name = "example";
//menu entries for the main menu
//passed as a list of dijit.MenuItem's
this.mainMenuEntries = [
new dijit.MenuItem({label: "new Example Tab ...", iconClass: "vispa_icon vispa_icon_plus", onClick: function ()
{
//create a new tabA instance
self.content.tabA._create();
}}),
new dijit.MenuItem({label: "new Example Frame ...", iconClass: "vispa_icon vispa_icon_frame", onClick: function()
{
//create a new frameB instance
self.content.frameB._create();
}})
];
//the content
this.content = {
tabA: new ExampleExtensionTabA(),
frameB: new ExampleExtensionFrameB()
};
}
</code>
### The Config Classes
<code class="javascript">
function ExampleExtensionTabA ()
{
//inheritance
this.__proto__ = new ExtensionConfig(this);
//the reference to the Content Class (no instance!)
this.constructor = ExampleExtensionTabAContent;
}
function ExampleExtensionFrameB ()
{
//inheritance
this.__proto__ = new ExtensionConfig(this);
//the reference to the Content Class (no instance!)
this.constructor = ExampleExtensionFrameBContent;
//'behavior' defaults to 'tab', but this one will be a 'frame', so set it
this.behavior = "frame";
}
</code>
### The Content Classes
<code class="javascript">
function ExampleExtensionTabAContent ()
{
//inheritance
this.__proto__ = new ExtensionContent(this);
//the content
this.getContent = function ()
{
return "TabA Content";
}
}
function ExampleExtensionFrameBContent ()
{
//inheritance
this.__proto__ = new ExtensionContent(this);
//the content
this.getContent = function ()
{
return "FrameB Content";
}
}
</code>
### The Registration
<code class="javascript">
//Proceed when dojo is loaded
dojo.ready(function ()
{
//register the Extension
vispa.ExtensionManager.registerExtension(new ExampleExtension());
});
</code>
The final call `vispa.ExtensionManager.registerExtension()` can also be
replaced by a call to the channel `registerExtension`:
<code class="javascript">
dojo.publish("registerExtension", [new ExampleExtension()]);
</code>
For further details on dojo’s publish/subscribe event mechanism, [click
here](http://livedocs.dojotoolkit.org/dojo/publish) .
Troubleshooting
---------------
- JavaScript’s `this` is (in some cases) tricky. For a distinct usage
of class variables use a lexical scope and define
<code class="javascript">
var self = this;
</code>
at the beginning of a class.