Skip to content
This repository has been archived by the owner on Mar 30, 2019. It is now read-only.

DevDocCeci

Pomax edited this page Sep 17, 2014 · 7 revisions

Information for Developers

The appmaker project consists of three parts:

  1. ceci, an implementation of Custom Elements, based on Polymer, defined in the ./public/ceci directory.
  2. A collection of predefined elements (called "bricks" or "components" in most technical discussions relating to appmaker) located in the ./public/bundles/components directory
  3. An app-making single-page designer webapp, with front-end code located in the ./public/designer directory, and backend code located in the usual places for an express app.

Ceci

The ceci framework is a Custom Elements implementation built on top of Polymer that handles data propagation between Appmaker bricks. There are three important files in this framework that define the majority of the functions and APIs that Appmaker bricks can use. Bricks are organised in cards which generally map to the concept of "pages" or "screens" in an app. A ceci app will have at least one card, housing zero or more bricks.

ceci-element-base.html

The ceci-element-base custom element houses all the base functionality that all Appmaker components share. These are things like registering which functions can list or broadcast, using which name, etc.

Note that custom elements do not extend ceci-element-base directly, but instead extend ceci-element.

When you use a component written for the ceci framework, extending ceci-element, it will have access to several functions that help make the component do what it needs to do due to function inheritance that Polymer takes care of for you:

Event handlers

In addition to the standard DOM event handlers that can be bound to any HTML element, ceci-element-base -and by extension anything that's an element based on the ceci framework- has two special event handlers for unifying touch events and mouse events:

on-ceci-pressdown

Registering listeners for this event will run its handling code both when touchdown and mousedown events occur.

on-ceci-pressup

Registering listeners for this event will run its handling code both when touchup and mouseup events occur.

Functions

loadSound : function(soundName, soundPath, [app])

Load a sound file by URL (as soundPath), and store it keyed on a custom name. The app argument is optional, and will resolve to the first ceci-app element on the page if not supplied (which covers the vast majority of cases)

playSound : function(soundName, volume)

Plays a sound file that was loaded with loadSound, with the volume a decimal value between 0 and 1, 0 being "muted" and 1 being "max volume".

ready: function()

This is a special Polymer-level function that gets called when the custom element's prototype has been fully parsed. Think of it as a class initialiser function. You should never call this function directly, but should implement your own components to fall through to it in your own ready function:

ready: function() {
  this.super();
  // your code goes here
}

The ready function also kicks off an asynchronous process for localizing all the strings that can be localized, which end up calling the internal stringsUpdated() and then localized() functions. However, you should generally not need to even have to think about using those.

domReady: function()

This is a special Polymer-level function that gets called when the custom element gets inserted into the DOM. You should never call this function directly, but should implement your own components to fall through to it in your own domReady function:

domReady: function() {
  this.super();
  // your code goes here
}

onready: function(fn)

This function lets you schedule code that will run once the component has finished doing everything it needs to do in order to be considered "done and ready for DOM insertion". This will be after localization has taken place, and is guaranteed asynchronous before the component is ready, and guaranteed synchronous after the component is ready.

gettext: function(key)

This function will return a localized string for anything that has been encoded as localized string in the ./locale/en-US.json file for a component. If the key is unknown or known but an empty string, gettext will return the empty string "".

broadcast: function( broadcastName, broadcastData)

this function will cause data to be sent out by this component as if generated by the broadcastName function, with content broadcastData. note: content is assumed to be a string, and may be coerced to one if it isn't.

showContainingCard: function()

This will cause the card that this brick is in to gain focus, hiding whatever card the user is looking at and showing this one instead.

setListener: function (name, channel)

Bind a listener by name to a channel, also by name. Each listener is represented in a brick by a <ceci-listen on="name" for="channel"> child node.

setBroadcast: function (name, channel)

Bind a broadcast by name to a channel, also by name. Each broadcast is represented in a brick by a <ceci-broadcast on="name" from="channel"> child node.

removeListener: function (name)

Unbind a listener by name from its bound channel.

removeBroadcast: function (name)

Unbind a broadcast by name from its bound channel.

getActiveListeners: function()

Get the array of <ceci-listen> elements that are used by this brick.

getActiveBroadcasts: function()

Get the array of <ceci-broadcast> elements that are used by this brick.

Events

The ceci-element-base code will generate several events during its lifetime. These can be tapped into from other code running in the same context to effect custom behavior.

LocaleStringsUpdated on document

This event is generated when localization forces an update of the string data used in the brick

CeciElementReady on document

This event is generated when the brick is ready for actual use in the DOM. The brick listens to this event as well to ensure that functions queued by calls to onready get processed.

CeciChannelUpdated on `document

This event is generated when a change is made to either listening or broadcasting channel bindings. It has an event.detail object of the form:

{
  name: listen or broadcast function name
  channel: channel name
  type: string data: 'listen' or 'broadcast'
  original: the original channel name, if the channel update was an unassignment 
}

CeciElementAdded on document

This event is generated when the brick is actually inserted into the DOM. This event has a reference to the brick itself bound to event.detail.

ceci-element.html

This component is used as extension basis for all "real" components, and doesn't have any own code. It exists purely to make it possible for other tools to load the ceci-element-base from the ceci framework, but define their own ceci-element custom element, so that any "real" ceci elements loaded onto a page/into an app have additional functionality specific to the needs of whoever relies on the ceci framework.

In Appmaker we rely on this, by using a special ceci-element-designer.html file that defines a ceci-element that is far from empty, and adds lots of user interface options like channel selection UI and drag and drop that is only relevant for when elements are used in the Appmaker designer, but not in the final published app.

ceci-card-base.html

This component defines a "page" or "screen" in an app. It has very little functionality, and similar to ceci-element-base vs. ceci-element, defines the functionality that a <ceci-card> element inherits. Other applications are free to create their own ceci-card implementation, as long as it inherits from ceci-card-base.

Functions

show: function()

Force this card into focus. This will hide any other card currently visible.

Events

cardShown on window

This event is generated when a card gains focus through an API call either to the card itself, or to the ceci-app function for showing cards. The event.detail property will be a reference to this card.

ceci-card.html

Like ceci-element this is a stub implementation and can be alternatively defined by applications that need custom functionality from cards.

ceci-app.html

This component defines the "master container" that is an Appmaker app. Ceci-apps have an API that is mostly about card administration. The ceci-app element is not intended to be extended from.

Functions

addCard: function()

Create a new card and add it to the set of cards for this app.

removeCard: function(index)

Remove card number index from this app, with the first card being card number 0, not 1.

countCards: function()

Returns the (integer) number of cards used by this app.

clearCards: function()

Remove all cards from this app. Note that this will leave the app in an unusable state for the purpose of adding components, and requires you call addCard() at least once to ensure there's a card into which to add bricks.

addComponentToCard: function(name, optionsObject)

Create a brick, by name (similar to creating an HTML element by name) and add it to the app's currently active/visible card.

Firebase functions

For data persistency, ceci-app elements can interface with Firebase. For more details about these functions, please see the ceci-app.html source code.

Events

ceci-app elements can generate the following events:

CeciAppCreated on window

This event is generated when an app is created, but is not necessarily ready for use yet. Its event.detail object has the form:

{
  source: reference to the ceci-app element just created
}

When this event is handled, it may not yet be possible to add cards and/or components to this app.

Calling document.querySelector('ceci-app') will not find this ceci-app element yet.

CeciAppReady on window

This event is generated when the ceci-app element is ready for use, but has not necessarily been inserted into the DOM yet.

When this event is handler, it is possible to add cards and/or components to this app.

Calling document.querySelector('ceci-app') will not find this ceci-app element yet.

CeciAppAttached on window

This event is generated when the app has been inserted into the DOM and counts as active document content.

Calling document.querySelector('ceci-app') will find this ceci-app element.

Cards and bricks that are housed inside the <ceci-app> may not be ready yet.

CeciAppDOMReady on window

This event is generated when the app has been inserted into the DOM and counts as finalised active document content.

Calling document.querySelector('ceci-app') will find this ceci-app element.

Cards and bricks that are housed inside the <ceci-app> are also ready.

cardAdded on window

This event is generated when a new card is added to the app's list of cards. The event.detail property is a reference to the just added card.

cardRemoved on window

This event is generated when a card is removed from the app's list of cards. The event.detail property is a reference to the just removed card.

Element call order

When you create an element that extends from the <ceci-element>, the code calls will (or, should) bubble up the hierarchy chain in a manner that is both complex and mostly irrelevant. All you need to know is that your createElement("...") causes the Polymer library to build your element, and at some point in the future it'll be ready. In order to schedule code that should trigger when that's the case (or immediately, after the element was marked ready) you simply pass functions into the element's onready() scheduler. As a diagram the flow is roughly as follows:

link

Clone this wiki locally