wiki:ProgrammingGuide

Language Guide

See the Elemental Programming Language documentation and guide.

Writing a Web View

A web view is a URL handler on the server that calls into the library by interpreting a resource in that library named by the requested URL. The Agent System binds to the /page/ site URL and everything else following maps into the library by using it as a slash-separated path indexing an interface or activity document. Navigating and updating the library can be done directly using the website or by uploading a package.

For example, the URL /page/home/Itham/site/search might be constructed by uploading a package like such:

interfaces/home/Itham/site::
    search($view)::
        <input type="text" id="input">
        <button onclick="parent.search(this)">Go</button>

Markup-Defined View

This introduces an upload format and an interface document (YAML, extended) syntax. By default, accessing the URL will render the search $view as HTML, meaning a search bar page with basic functionality. Pages defined like this are typically accessible in a site menu Task Window, meaning the window.parent might expose a search API.

Next we update the interface document with an additional linked resource:

interfaces/home/Itham/site::
    search($view)::
        <script src="/page/home/Itham/site/library.js"
                type="text/javascript" />

        <input type="text" id="input">
        <button onclick="parent.search(getSearchQuery(this))">Go</button>

    library.js($view):
      content-type: text/javascript
      content::
        function getSearchQuery()
        { return btn.ownerDocument.getElementById('input').value; }

The javascript resource URL now responds setting the right content type.

Now we want to access the system more deeply whenever this web view is requested.

interfaces/home/Itham/site::
    data.js($view):
      context($trigger)::
        context['model'] = 'home/Itham/search/model'(':'.join(path))
        response['content_type'] = 'text/javascript'

      template::
        var model = {{ model.json|safe }};

The template is a Django template, but it is only rendered to the response stream after the context $trigger is done evaluating so that the context code can initialize the dataspace before rendering. In this example, the trigger accesses the path parameter set by the server which contains a sequence of all following URL path components that did not match past the library path: home/Itham/site/. In other words, everything after the matching part of the path is then used in constructing an identifier passed to the search/model method.

Alternatively, the template can be omitted by setting the content directly:

data($view):
  context($trigger)::
    model = 'home/Itham/search/model'(':'.join(path))
    response['content_type'] = 'application/json'
    response['content'] = 'text/json/dumps'(model)

Search then becomes:

interfaces:
  home/Itham/site::
    search($view)::
      <script src="/page/org/example/search-interface.js"
              type="text/javascript" />
      <script src="/page/home/Itham/site/library.js"
              type="text/javascript" />

      <script type="text/javascript">
      $.get('/page/home/Itham/search/data',
            function (model) { search = SearchInterface(model); });
      </script>

      <input type="text" id="input">
      <button onclick="search.fromQuery(getSearchQuery(this))">Go</button>

  org/example::
    search-interface.js($view)::
      class SearchInterface {
        function constructor(model)
        { self.data = model; }

        function fromQuery(text)
        { ... }

Security Note

By defining a web view (with $view), this means that its context code will be run whenever the URL is publically accessed. A view should use request.user.checkAccessError whenever protecting a resource's computational charge:

interfaces/home/Itham/public::
    edit($view):
        context($trigger)::
            if request.method == 'POST':
                request.user.checkAccessError('write', 'home/Itham/storage/resource')
                'kernel/structure'('resource').setText('kernel/edit'('home/Itham/storage'), ...)

checkAccessError will raise an NoAccessException if the user of the request doesn't have permission.

Defining a Service

An endpoint can be implemented by simply defining a function in an activity module:

home/Itham/service::
    def endpoint$name(arg1, arg2):
        'kernel/info'('[endpoint] ' + string(arg1) + ': ' + string(arg2))

Then, call the service endpoint:

'home/Itham/service/endpoint$name'('Category', 'Value')

Using a remote interface, call the endpoint on a remote machine:

agent = $.network.portal.session('remote.thetaplane.com', 'itham', 'password')
agent.script("'home/Itham/service/endpoint$name'('Remote-Category', 'Remote-Value')")

Or:

r = initialize('services/source/loopback') \
    .path$bind('services/source/deployment/code')

.(r('services/source/deployment/wiki/programming'))

Documentation

Documentation for a function is provided by defining another function with the same name but followed by '$doc'. This new function returns an InlineText object or string object describing the original function.

Architectural Notes

Last modified 5 days ago Last modified on 09/23/22 11:52:10
Note: See TracWiki for help on using the wiki.