Skip to content
Browse files

new component structure

  • Loading branch information...
1 parent a2d5bee commit 4449b6da987084b9ae086ddf369910076d8fc86d @nordenmark committed Dec 16, 2011
View
8 jsfw_docs/jsfw_docs.css
@@ -1,11 +1,15 @@
-.code {
+code, .code {
font-family: ‘Lucida Console’, Monaco, monospace;
+ background-color: #DEDEDE;
}
.box {
- background-color: #C9C9C9;
+ background-color: #C7C7C7;
padding: 4px;
border: 1px solid #878787;
+ font-family: ‘Lucida Console’, Monaco, monospace;
+ margin-bottom: 5px;
+ margin-top: 5px;
}
h1 {
View
3 jsfw_docs/jsfw_docs.erl
@@ -5,5 +5,6 @@ get() ->
ErlTemplate = jsfw_utility:read_template(erl),
JSTemplate = jsfw_utility:read_template(js),
HTMLTemplate = jsfw_utility:read_template(html),
- Data = [{erltemplate, ErlTemplate}, {jstemplate, JSTemplate}, {htmltemplate, HTMLTemplate}],
+ HandleTemplate = jsfw_utility:read_template(handle),
+ Data = [{erltemplate, ErlTemplate}, {jstemplate, JSTemplate}, {htmltemplate, HTMLTemplate}, {handletemplate, HandleTemplate}],
Data.
View
97 jsfw_docs/jsfw_docs.html
@@ -2,91 +2,70 @@
<p>In the root of the program where you want to integrate JSFW, there must exist a file named <b>jsfw.config</b>, which must contain tuples according to:</p>
<dl class="box">
- <dt class="code">{webserver_plugins_dir, PATH}</dt>
+ <dt>{webserver_plugins_dir, PATH}</dt>
<dd>PATH - string, the path to the directory holding the webserver plugins</dd>
- <dt class="code">{components_dir, PATH}</dt>
+ <dt>{components_dir, PATH}</dt>
<dd>PATH - string, the path to the directory holding the components</dd>
</dl>
<h1>URL Scheme</h1>
- <div class="box">/component/COMPONENT/RESOURCEPATH</div>
- <p>Returns the file (if it exists) from COMPONENT's dir.</p>
+ <!-- <div class="box">/component/COMPONENT/RESOURCEPATH</div>
+ <p>Returns the file (if it exists) from COMPONENT's dir.</p> -->
<div class="box">/static/RESOURCEPATH</div>
<p>Returns pre-shipped resource file found in priv/RESOURCEPATH</p>
<div class="box">/json/components</div>
<p>Returns a JSON array containing available components and their attributes from their respective component.config files</p>
- <div class="box">/json/pid</div>
- <p>Returns JSON from jsfw_pid:get_json()</p>
+ <!-- <div class="box">/json/pid</div>
+ <p>Returns JSON encoding of jsfw_pid:get()</p>
- <div class="box">/json/pid/PIDARG</div>
- <p>Returns JSON from jsfw_pid:get_json(PIDARG) (PIDARG = 0.1.0 e.g.)</p>
+ <div class="box">/json/pid/PIDARG</div>
+ <p>Returns JSON encoding of jsfw_pid:get(PIDARG) (PIDARG = 0.1.0 e.g.)</p> -->
<div class="box">/json/COMPONENT</div>
- <p>Returns JSON from COMPONENT:get_json()</p>
+ <p>Returns JSON encoding of COMPONENT:get()</p>
<div class="box">/json/COMPONENT/ARG</div>
- <p>Returns JSON from COMPONENT:get_json(ARG)</p>
+ <p>Returns JSON encoding of COMPONENT:get(ARG)</p>
<h1>Component structure</h1>
- <p>Components are placed in the <span class="code">components_dir</span> directory as mentioned above, in a directory named <span class="code">component</span>. Individual components consist of a JavaScript file, an Erlang module, a HTML template and a CSS file and are structured and named in the following manner:</p>
+ <p>Components are placed in the <code>components_dir</code> directory as mentioned above, in a directory named <code>component</code>. This here (jsfw_docs) is actually a component just like any other! Individual components consist of a JavaScript file, an Erlang module, a HTML template, another HTML template to display arguments, a CSS file and are structured and named in the following manner:</p>
+
+
+ <h3>HTML template (COMPONENT.html)</h3>
+ <div class="box" id="htmltemplate"></div>
+ <p>This is the template used when creating a new component. <span class="code">%%COMPONENT%%</span> is then replaced by the name of the new component.
+
+ <h3>Handle template (handle.html)</h3>
+ <div class="box" id="handletemplate"></div>
+ <p>This is the template shown when displaying a component with an argument (i.e. path /COMPONENT/ARG)</p>
<h3>JavaScript file (COMPONENT.js)</h3>
<div class="box" id="jstemplate"></div>
- <p>This is the template used when creating a new component. <span class="code">%%COMPONENT%%</span> is then replaced by the name of the new component. The JavaScript file needs to uphold this basic structure, with the variable declaration on the top level as well as the init function declaration and the (optional) reload function declaration for automatic refreshing of the component.</p>
+ <p>This is the template used when creating a new component. <code>%%COMPONENT%%</code> is then replaced by the name of the new component. The JavaScript file needs to uphold this basic structure, with the variable declaration on the top level as well as the <code>init</code> function declaration and the (optional) <code>refresh</code> function declaration for automatic refreshing of the component. See how jQuery selectors are used to define where to put the JSON data?</p>
<h3>Erlang module (COMPONENT.erl)</h3>
<div class="box" id="erltemplate"></div>
- <p>This is the template used when creating a new component. <span class="code">%%COMPONENT%%</span> is then replaced by the name of the new component. Note how Erlang modules should return {ok, JSON}.</p>
-
- <h3>HTML template (COMPONENT.html)</h3>
- <div class="box" id="htmltemplate"></div>
- <p>This is the template used when creating a new component. <span class="code">%%COMPONENT%%</span> is then replaced by the name of the new component.
+ <p>This is the template used when creating a new component. <span class="code">%%COMPONENT%%</span> is then replaced by the name of the new component. Note how Erlang modules should return data that can be encoded to JSON (see more information further down).</p>
<h3>Config file (component.config)</h3>
<div class="box">
<pre>[{enabled,"true"},{displayname,DISPLAYNAME}]</pre>
</div>
- <p>This file contains the properties specified for the component in question. The value of <span class="code">displayname</span> is a string that is displayed in the component menu.</p>
+ <p>This file contains the properties specified for the component in question. The value of <code>displayname</code> is a string that is displayed in the component menu and <code>enabled</code> decides whether it should show in the menu or not.</p>
<h3>CSS file (COMPONENT.css)</h3>
<p>This is optional and contains any custom styling wanted for the component.</p>
- <p>Components can be created, reloaded and enabled/disabled through the <a href="/jsfw_settings">settings web interface</a>.</p>
+ <p>Components can be created and enabled/disabled through the <a href="/jsfw_settings">settings web interface</a>. Go ahead and create your first example component right away!</p>
<h1>JavaScript API</h1>
- <p>There are plenty of API functions available for developers to present data in the front-end.</p>
-
- <h3 class="box">new Body();</h3>
- <p>This creates and returns a new object of the Body class. This is the top most object that is used when building up the presentation of the component. This class further contains the methods described here.</p>
- <h3 class="box">span(text);</h3>
- <p>Returns a &lt;span&gt; element containing the optional text string sent in as argument.</p>
-
- <h3 class="box">table(headers);</h3>
- <p>Returns a &lt;table&gt; element with headers as specified by the optional array headers.</p>
-
- <h3 class="box">ul(ul_id, ul_class);</h3>
- <p>Returns a &lt;ul&gt; element with id and class as specified by the optional arguments.</p>
-
- <h3 class="box">div(div_id, div_class);</h3>
- <p>Returns a &lt;div&gt; element with id and class as specified by the optional arguments.</p>
+ <p>There is actually only a single JavaScript API function but that should help you complete most of your implementations if you've constructed a clever HTML template.</p>
- <h3 class="box">toggle_button();</h3>
- <p>Returns an &lt;input&gt; element that, when pressed, toggles the automatic refreshing (calling of the refresh() function) on and off.</p>
-
- <h3 class="box">h1(text);</h3>
- <p>Returns a &lt;h1&gt; element containing the optional text string sent in as argument.</p>
-
- <h3 class="box">fill_json(source, element);</h3>
- <p>Used to fill element (which is any element out of the above) with the JSON returned from the source URL (typically "/json/COMPONENT")</p>
-
- <h3 class="box">add(element);</h3>
- <p>Adds element to the body, i.e. make sure it gets printed when print() is called.</p>
-
- <h3 class="box">print();</h3>
- <p>Prints/displays the elements added by add()</p>
+ <h3 class="box">fill_json(source, element); [fill_json("/json/users", $("#usertable"));]</h3>
+ <p>Used to fill element (which is an element selected using jQuery selectors (more on those here: <a href="http://api.jquery.com/category/selectors/">http://api.jquery.com/category/selectors/</a>)) with the JSON returned from the source URL (typically "/json/COMPONENT"). Make sure that you format your output Erlang data so that it suits the element that you wish to put it in (see more on that under Erlang API). In the above example, the data returned from <code>/json/users</code> is inserted into the html &lt;table&gt; element with id 'usertable'. Thus, the Erlang data output from <code>users:get()</code> must be in tabular format.</p>
<h1>Erlang API</h1>
@@ -96,27 +75,25 @@ <h3 class="box">print();</h3>
arg_to_pid(Arg)</pre></div>
<p>Given a binary Arg (e.g. <<"0.1.0">>), returns a PID (<<0.1.0>>)</p>
-
-
- <h2>jsfw_json</h2>
- <div class="box">
- <pre>term() -> binary().
-encode(Term)</pre></div>
- <p>Encodes the argument Term into JSON. Convert strings to binaries before encoding. Below are examples of how Erlang data should be structured before encoding it.</p>
+ <h2>Data structures</h2>
+ <p>Below is a list of how Erlang data should be structured. This is what should be returned from your component's get() and get(Arg) functions. When using <code>fill_json</code>, JSFW will look at the target element to decide how to iterate over the data given to insert it.</p>
<h3>Tabular data (output in a &lt;table&gt;)</h3>
<span class="code">[[row1col1, row1col2, ...], [row2col1, row2col2, ...], ...]</span>
<h3>List data (output in a &lt;ul&gt;)</h3>
<span class="code">[element1, element2, element3, ...]</span>
- <h3>Special case for links (taken from users.erl):</h3>
- <span class="code">[{'$link',<<"3">>,<<"/users/3">>},<<"SARAH">>]</span>
-
+ <h3>Links</h3>
+ <code>{'$link', TEXT, URL}</code>. For example: <code>{'$link',<<"3">>,<<"/users/3">>}</code>
+ <br><br>
<p>This will be printed as:</p>
- <span class="code">&lt;a href="/users/3"&gt;SARAH&lt;/a&gt;</span>
+ <code>&lt;a href="/users/3"&gt;3&lt;/a&gt;</code>
+ <br><br>
+ <p>Clicking on that link when navigating the users component will call the optional <code>handle(argument)</code> javascript function of the component with "3" as argument (in this particular case). Fetching the JSON from <code>/json/users/3</code> will call <code>users:get(<<"3">>)</code> similarily.</p>
- <p>Clicking on that link when navigating the users component will call the optional handle(argument) javascript function of the component with "3" as argument (in this particular case). Fetching the JSON from /json/users/3 will call users:get_json(<<"3">>) similarily.</p>
+ <h3>PIDs</h3>
+ <p>PIDs are treated with special care and taken care of by the included jsfw_pid component. All PIDs printed will be links to /jsfw_pid/PID and when clicked, be displayed by the jsfw_pid component.</p>
View
2 jsfw_docs/jsfw_docs.js
@@ -4,9 +4,11 @@ var jsfw_docs = new function() {
var erltemplate = json.erltemplate;
var jstemplate = json.jstemplate;
var htmltemplate = json.htmltemplate;
+ var handletemplate = json.handletemplate;
$("#jstemplate").html("<pre>" + jstemplate + "</pre>");
$("#erltemplate").html("<pre>" + erltemplate + "</pre>");
$("#htmltemplate").html($("<pre />").text(htmltemplate));
+ $("#handletemplate").html($("<pre />").text(handletemplate));
});
}
}
View
1 jsfw_pid/component.config
@@ -0,0 +1 @@
+[{displayname,"PID"},{enabled,"true"}].
View
3 jsfw_pid/handle.html
@@ -0,0 +1,3 @@
+<h1>Handle template for component: jsfw_pid</h1>
+
+Argument given: <span id="argcontainer"></span>
View
0 moo/moo.css → jsfw_pid/jsfw_pid.css
File renamed without changes.
View
22 jsfw_pid/jsfw_pid.erl
@@ -0,0 +1,22 @@
+-module(jsfw_pid).
+-export([get/0, get/1]).
+
+get() ->
+ PIDs = erlang:processes(),
+ Key = fun(K,PID) -> proplists:get_value(K, erlang:process_info(PID)) end,
+
+ [[
+ PID,
+ % Return initial call if process not registered
+ case Key(registered_name,PID) == undefined of
+ true ->
+ Key(initial_call,PID);
+ false ->
+ Key(registered_name,PID)
+ end,
+ Key(current_function,PID)
+
+ ] || PID <- PIDs ].
+
+get(Arg) ->
+ Arg.
View
11 jsfw_pid/jsfw_pid.html
@@ -0,0 +1,11 @@
+<h2>jsfw_pid</h2>
+
+<table id="jsoncontainer">
+ <thead>
+ <tr>
+ <th>PID</th>
+ <th>Reg. name / initial call</th>
+ <th>Current function</th>
+ </tr>
+ </thead>
+</table>
View
17 jsfw_pid/jsfw_pid.js
@@ -0,0 +1,17 @@
+var jsfw_pid = new function() {
+
+ // This function is called when the component is clicked in the menu
+ this.init = function() {
+ fill_json("/json/jsfw_pid", $("#jsoncontainer"));
+ }
+
+ // This function is called when the component is automatically refreshed
+ this.refresh = function() {
+
+ }
+
+ // This function is called when an argument is clicked on the component's page
+ this.handle = function(arg) {
+ fill_json("/json/jsfw_pid/" + arg, $("#argcontainer"));
+ }
+}
View
1 mario/component.config
@@ -1 +0,0 @@
-[{enabled,"true"},{displayname,"MAAARIO"}].
View
0 mario/mario.css
No changes.
View
5 mario/mario.erl
@@ -1,5 +0,0 @@
--module(mario).
--export([get/0]).
-
-get() ->
- <<"hello world from mario!">>.
View
3 mario/mario.html
@@ -1,3 +0,0 @@
-<h2>mario</h2>
-
-<span id="jsoncontainer"></span>
View
11 mario/mario.js
@@ -1,11 +0,0 @@
-var mario = new function() {
-
- this.init = function() {
- fill_json("/json/mario", $("#jsoncontainer"));
- }
-
- // This function is called when the component is automatically refreshed
- this.refresh = function() {
-
- }
-}
View
1 moo/component.config
@@ -1 +0,0 @@
-[{enabled,"true"},{displayname,"MOO"}].
View
11 moo/moo.erl
@@ -1,11 +0,0 @@
--module(moo).
--export([get/0]).
-
-get() ->
- {_, _, Data} = erlang:now(),
- List = [Data, Data, Data, Data],
- BinData = [ [list_to_binary(integer_to_list(N)),X] || X <- List, N <- lists:seq(1,4) ],
- BinData.
- % Data = ["janne", "mick", "JOHNNY", "peter", "joe"],
- % BinData = [ [list_to_binary(integer_to_list(N)),list_to_binary(X)] || X <- Data, N <- lists:seq(1,4) ],
- % {ok, jsfw_json:encode(BinData)}.
View
14 moo/moo.html
@@ -1,14 +0,0 @@
-this is the template for moo
-
-{{toggle_button}}
-
-<table id="jsoncontainer">
- <thead>
- <tr>
- <th>ID</th>
- <th>Name</th>
- </tr>
- </thead>
-</table>
-
-<!-- Time: <span id="jsoncontainer"></span> -->
View
11 moo/moo.js
@@ -1,11 +0,0 @@
-var moo = new function() {
-
- this.init = function() {
- fill_json("/json/moo", $("#jsoncontainer"));
- }
-
- // This function is called when the component is automatically refreshed
- this.refresh = function() {
- fill_json("/json/moo", $("#jsoncontainer"));
- }
-}
View
3 second/handle.html
@@ -0,0 +1,3 @@
+<h1>Handle template for component: second</h1>
+
+Argument given: <span id="argcontainer"></span>
View
7 second/second.erl
@@ -1,5 +1,8 @@
-module(second).
--export([get/0]).
+-export([get/0, get/1]).
get() ->
- <<"Hello World from SAJDKASJDASKJD!">>.
+ {'$link',<<"This is an example argument">>,<<"/second/3">>}.
+
+get(Arg) ->
+ Arg.
View
4 second/second.html
@@ -1,3 +1,3 @@
-<h2>second component</h2>
+<h2>second</h2>
-<span id="jsoncontainer"></span>
+Click this example argument link: <span id="jsoncontainer"></span>
View
6 second/second.js
@@ -1,5 +1,6 @@
var second = new function() {
+ // This function is called when the component is clicked in the menu
this.init = function() {
fill_json("/json/second", $("#jsoncontainer"));
}
@@ -8,4 +9,9 @@ var second = new function() {
this.refresh = function() {
}
+
+ // This function is called when an argument is clicked on the component's page
+ this.handle = function(arg) {
+ fill_json("/json/second/" + arg, $("#argcontainer"));
+ }
}
View
3 users/users.erl
@@ -27,10 +27,7 @@ users() ->
%% [[row1col1, row1col2, ...], [row2col1, row2col2, ...], ... ]
get() ->
Users = users(),
- % Ints = [ list_to_binary(integer_to_list(I)) || I <- lists:seq(1,length(Users)) ],
Table = [ [{'$link', list_to_binary(integer_to_list(ID)), list_to_binary("/users/" ++ integer_to_list(ID))}, list_to_binary(Rec#user.name)] || {ID, Rec} <- Users ],
- % Table = lists:zipwith(fun(X,Y) -> [X,Y] end, Ints, Users),
- io:format("Table: ~p~n", [Table]),
Table.
%% Here we are given a user id as argument

0 comments on commit 4449b6d

Please sign in to comment.
Something went wrong with that request. Please try again.