-
Notifications
You must be signed in to change notification settings - Fork 1
PluginStructure
A typical plugin has a more-or-less common structure, although (a) it evolved during the course of the original project, 2015–2018; (b) Tim often changed the naming conventions arbitrarily due to forgetting what they were; and (c) some plugins require different resources, such as connections to php
and mySQL
.
Suppose we're looking at a plugin named foo
.
-
foo.html
file defines the overall visual appearance, aided by its associatedfoo.css
. - A
<script>
block infoo.html
executesfoo.initilize()
, which is defined along with the globalfoo
infoo.js
. -
foo.initialize
callsfoo.CODAPconnect.initialize()
, which sets up theiFrame
and creates the initial dataContext. It also restoresfoo.state
if we are using it for saving game state. - A routine in
foo.ui
— possiblyfoo.ui.update()
— adjusts the visibility of DOM elements and their text to reflect the game state. - Event listeners, either explicitly defined or mentioned in the html, for example, in
onclick
clauses, call functions defined in files such asfoo.js
orfoo.userActions.js
. This is how user actions affect the game state. - When an action results in a change in CODAP, for example, a new case to be added, a routine is called in
foo.codapConnect
to perform that task. - When an action is complete, we call
foo.ui.update()
or its equivalent in order to change the display.
Of course, there are many more details, but that's the basic pattern.
A plugin named foo
resides in /plugins/foo/
. Most of the code sits in that directory, with other resources in subfolders such as art/
or data/
.
This is named foo.html
Its <head>
section contains a slew of includes, often looking something like this:
<link href='https://fonts.googleapis.com/css?family=Maven+Pro:700,900' rel='stylesheet'>
<link href='https://fonts.googleapis.com/css?family=Rokkitt:300, 700' rel='stylesheet'>
<link rel='stylesheet' type='text/css' href='foo.css'/>
<link rel='stylesheet' type='text/css' href='../common/jqueryFolder/jquery-ui.min.css'/>
<script src="../common/iframe-phone.js" language="javascript"></script>
<script src="../common/codapInterface.js" language="javascript"></script>
<script src="../common/pluginHelper.js" language="javascript"></script>
<script src="../common/TEEUtils.js" language="javascript"></script>
<script src="../common/jqueryFolder/jquery.min.js" language="javascript"></script>
<script src="../common/jqueryFolder/jquery-ui.min.js" language="javascript"></script>
<script src="foo.js" language="JavaScript"></script>
<script src="fooGameConfigurations.js" language="JavaScript"></script>
<script src="fooStrings.js" language="JavaScript"></script>
<script src="foophpConnector.js" language="JavaScript"></script>
<script src="fooCODAPConnector.js" language="JavaScript"></script>
<script src="fooUI.js" language="JavaScript"></script>
<script src="fooUserActions.js" language="JavaScript"></script>
<script src="fooModel.js" language="JavaScript"></script>
Note that there is usually a foo.css
to style the plugin.
This is a central site for js functionality. As Tim developed a prototype, this was often the first js file he made, and then, as things got more complex, functions and members were offloaded into other files. In a more mature plugin, it functions as a controller, but often also implements functionality that has not yet found a home.
It defines the top-level global named foo
; ideally it's the only one. So we often see:
let foo = { // top level global
state : {},
at the top of this file. Note that this is where foo.state
gets defined.
Sometimes the object foo.constants
gets its own file; sometimes it lives in foo.js
.
Sometimes fooCODAPConnect.js
or simply CODAPconnect.js
or other variants. In ay case, defines the object foo.CODAPConnect
or foo.connector
.
This file has all the routines we use to communicate with CODAP, particularly emitting data we have generated into the platform. Here is an example from fishCODAPConnector.js
:
createFishItems: async function (iValues) {
iValues = pluginHelper.arrayify(iValues);
console.log("Fish ... createFishItems with " + iValues.length + " case(s)");
try {
res = await pluginHelper.createItems(iValues, fish.constants.kFishDataSetName);
console.log("Resolving createFishItems() with " + JSON.stringify(res));
return res;
} catch {
console.log("Problem creating items using iValues = " + JSON.stringify(iValues));
}
},
In this example, we have finally gotten wise to asynchronous coding (note the async function
in the definition and the await
where we ask pluginHelper
to create the items). Earlier plugins do not have this; that's a good project to undertake one day.
If the plugin needs a database (we've used mySQL
during prototyping, but changing to something better would make sense), you will need php to communicate with it.
This file contains routines that set up the parameters for a specific task, and one method that actually makes the call. We are using the Fetch
system of communicating.
See more details in a page about php and mySQL.
This file is responsible for adjusting the UI. This mostly involves
- Changing the text of items, for example, updating the current time, reporting the number of widgets in a bin, or changing the text of a button from
start
tostop
. - Changing the visibility of DOM objects, for example, by hiding buttons that are not relevant.
If a pure model file makes sense, this is a good place to put it.