TIBET Logo

TIBET Content Types

Markup

wins

  • Automatic wrapping of raw data in intelligent content containers.
  • Minimize getter/setter code with attribute mapping of data queries.
  • Create specific types to manage complex source data with simple OO.
  • Configuration-driven mapping of new content types to URI patterns.

contents

concepts

cookbook

code


concepts

Content types in TIBET represent intelligent types which give you a way to easily encapsulate your application data and DOM elements and supply them with real functionality.

For example, any element in a visual or non-visual DOM can be managed by writing an intelligent object that's aware of the tree structure of the element but hides it behind a set of smart getters and setters. This encapsulation approach is particularly well-suited to building widgets whose internal markup structures should be hidden, but whose "features" should be exposed in an easy-to-invoke fashion.

Similarly, imagine a block of application JSON with it's own internal nesting and data types. You can access that JSON directly but that opens your application up to potential data corruption as well as long-term maintenance issues. If you need to change the structure or data types in the JSON but have paths hardcoded throughout your code that's a problem. Encapsulating those paths via an object avoids those problems.

TIBET's content types fall into two primary camps, those that handle XML/DOM nodes and those that handle non-Node data, rooted at TP.dom.Node and TP.core.Content respectively.

TP.dom.Node and friends

TP.dom.Node is the root of all custom tags in TIBET and has subtypes for each of the 9 node types found in the DOM specification. Subtypes of TP.dom.ElementNode ultimately provide the core functionality of TIBET's tag system. All custom tag types in the TIBET library and your applications descend from these root types.

You don't have to know about the overwhelming majority of node types since TIBET automatically returns the best-fit type if you're using TIBET URIs or APIs. You simply rely on get() and set() to manage your data along with TIBET Paths and TIBET does the rest.

For example, the URI access below will return an instance of APP.hello.app if you run it within the hello project used by TIBET Quickstart et. al.:

//  Get the content of the '#app' element in the UICANVAS:
tag = TP.uc('#app').getContent();
tag.getTypeName(); // <-- APP.hello.app in a 'hello' project

The TP.wrap and TP.unwrap methods encapsulate and unwrap raw DOM content for you, but they are typically invoked on your behalf rather than you having to invoke them directly. If you have a raw DOM node you can get the best-fit type for it via TP.wrap:

tibetNode = TP.wrap(rawDOMnode);

Although it's a significant feature in its own right, the real value of TIBET's node types goes beyond simply wrapping a DOM node to encapsulate data access.

TIBET's node types, particularly the element types, allow you to treat markup like a form of macro source code, telling TIBET how you want to render that markup, how you want to process it as a set of "instructions" for the TIBET shell, how it responds to common events, etc.

You can create new tags using the TIBET CLI or the TIBET Sherpa.

In the Sherpa you'd use either the dispenser or halo to create your tag (see the Sherpa documentation). In the CLI you'd use the tibet type command.

For example, we could create a new templated tag using tibet type as follows (provided we're a project named hello):

tibet type hello:world --dna templatedtag

See documentation on tibet type for more information on how to create new types (and tag types) using the TIBET CLI.

TP.core.Content et. al.

TP.core.Content has a number of custom subtypes to support adding intelligence to what would otherwise typically be simple string content.

Perhaps the most commonly used content subtype is TP.core.JSONContent which is used to automatically wrap JSON data when no specific type has been given.

A simple example is fetching the tibet.json file for the project:

//  Fetch tibet.json. The "content" will be a TP.core.JSONContent object:
content = TP.uc('~/tibet.json').getContent();

Using TIBET's powerful OO system you can create custom JSON content types to manage your specific application data formats and requirements.

The primary value in custom JSON types is that you can assign specific access paths via setAttribute so that your get() and set() calls work as expected. Thanks to get() and set() the underlying JSON data structure can change without having to alter anything but your setAttribute path definitions. (You can also add regular methods as needed.)

As an example, we can create a subtype of TP.core.JSONContent for the tibet.json file using the TIBET CLI's tibet type command as follows:

$ tibet type ProjectJSON --supertype TP.core.JSONContent
working in: /Users/ss/temporary/hello/public/_ProjectJSON_
processing directories...
processing templates...
templating complete...
positioning files...
positioning complete...
adjusting package entries...
<script src="~app_src/types/APP.hello.ProjectJSON.js"/> (added)
<script src="~app_src/types/APP.hello.ProjectJSON_test.js"/> (added)
New configuration entries created. Review/Rebuild as needed.
Cleaning up working directory.
Type DNA 'default' cloned to ~app_src/types as 'ProjectJSON'.

When the tibet type command is finished our application has a new type, a new test file, and is ready to load the type automatically as part of our appliation's standard build.

We can also immediately test our new type via tibet test:

$ tibet test APP.hello.ProjectJSON
# Loading TIBET platform at 2019-07-20T19:54:00.823Z
# TIBET reflection suite loaded and active in 6895ms
# Running Type tests for APP.hello.ProjectJSON
# TIBET starting test run
# 1 suite(s) found.
1..1
#
# tibet test APP.hello.ProjectJSON.Type --suite='APP.hello.ProjectJSON suite'
ok - Is a TP.core.JSONContent type.
# pass: 1 total, 1 pass, 0 fail, 0 error, 0 skip, 0 todo, 0 only.
#
# PASS: 1 total, 1 pass, 0 fail, 0 error, 0 skip, 0 todo, 0 only.
# Running Inst tests for APP.hello.ProjectJSON
# TIBET starting test run
0..0
# PASS: 0 pass, 0 fail, 0 error, 0 skip, 0 todo.
# Running Local tests for APP.hello.ProjectJSON
# TIBET starting test run
0..0
# PASS: 0 pass, 0 fail, 0 error, 0 skip, 0 todo.

Now we can add a simple attribute mapping for the project name by editing the source file ~app/public/src/types/APP.hello.ProjectJSON.js:

//  Below this line defining the type itself...
TP.core.JSONContent.defineSubtype('APP.hello.ProjectJSON');

//  Add one or more attribute path definitions...
APP.hello.ProjectJSON.Inst.defineAttribute('projectName', TP.apc('$.project.name'));

With the definition above we can now access tibet.json and get a more intelligent type back, one we can leverage in other code but one which fully-encapsulates the actual structure of the data we're accessing:

request = TP.hc('contenttype', APP.hello.ProjectJSON);  //  define content type
content = TP.uc('~/tibet.json').getContent(request);    //  fetch content
content.get('projectName');                             //  query by attr name

hello

You can also define a default content type for a URI instance so you don't need to rely on the request-based approach:

url = TP.uc('~/tibet.json');
url.set('defaultContentType', APP.hello.ProjectJSON);
content = url.getContent();    //  fetch content
content.get('projectName');

Or...you can use TIBET's configuration system to define your desired URI contentTypes (along with other URI values) in a URI map:

"uri": {
    "map": {
        "tibet_json": {
            "pattern": "~/tibet.json",
            "contenttype": "APP.hello.ProjectJSON"
        }
    }
}

Note that the "name" level ("tibet.json") isn't used for matching, just for your own lookups, but it shouldn't include periods to avoid confusing the logic that does configuration lookups.

See the TIBET URIs documentation for more on URI maps.


cookbook

Get A TIBET Node Wrapper

To get a TIBET wrapper for a DOM element use a TIBET URI or TP.wrap.

Any access to a DOM node via TIBET URI will return you a TIBET node instance rather than a raw DOM node:

//  Access a DOM element using a TIBET URI...it will return a TIBET node:
tag = TP.uc('#app').getContent();

If you have a raw DOM node use TP.wrap to get the best wrapper instance:

tibetNode = TP.wrap(rawDOMnode);

Get A Native Node From A TIBET Node

To unwrap a TIBET node (get it's underlying node) you can use TP.unwrap or getNativeNode():

rawNode = TP.unwrap(tibetNode);

//  or

rawNode = tibetNode.getNativeNode();

Get A TIBET Content Wrapper

To get a TIBET content wrapper use a TIBET URI or TP.core.Content.construct.

If you access content via a TIBET URI you will automatically be provided with a TIBET.core.Content subtype instance of some form. If the content is a JSON string you'll receive a TP.core.JSONContent instance:

url = TP.uc('~/tibet.json');
content = url.getContent();

If you want a specific subtype to wrap your content you can define that a number of ways includign putting it in the request object you pass to getContent, defining it as the defaultContentType for the URI instance, or using a URI map entry:

request = TP.hc('contenttype', APP.hello.ProjectJSON);  //  define content type
content = TP.uc('~/tibet.json').getContent(request);    //  fetch content

Get Raw Content From TIBET Content

TIBET Content objects manage their content in the form of a data attribute you can access using get('data'):

dat = contentObj.get('data');

In the case of a JSONContent object the data is the parsed form of the JSON. If you want the string form use asString:

str = contentObj.asString();

Create A New TIBET Node Type

There are four common tag types you can quickly and easily subtype by using the tibet type command line tool:

tibet type hello:world --dna templatedtag
tibet type hello:world --dna computedtag
tibet type hello:world --dna actiontag
tibet type hello:world --dna infotag

If you need a pure element wrapper you can also choose to use tibet type with a simple supertype specification:

tibet type hello:world --supertype TP.dom.UIElementNode

Note that in this latter case your type will not be placed in a "tag bundle", it will be considered a standard type and placed in ~app_src/types.

Create A New TIBET Content Type

To create a new content type you can use tibet type with a simple supertype specification pointing to the content supertype you require:

tibet type ProjectJSON --supertype TP.core.JSONContent

The above syntax will create a standard type and place it in ~app_src/types.


code

Node-related functionality is found in ~lib/src/tibet/kernel/TIBETDOMtypes.js. Additional types are found in ~lib/src/tibet/kernel/TIBETUIDOMTypes.js.

There are also dozens of DOM-related primitive functions found in:

  • ~lib/src/tibet/kernel/TIBETDOMPrimitivesBase.js
  • ~lib/src/tibet/kernel/TIBETDOMPrimitivesPlatform.js
  • ~lib/src/tibet/kernel/TIBETDOMPrimitivesPost.js
  • ~lib/src/tibet/kernel/TIBETDOMPrimitivesPre.js

Non-node content types are defined in ~lib/src/tibet/kernel/TIBETContentTypes.js. There are numerous subtypes of TP.core.Content in other locations in the library.

Non-node content primitives are found in TIBETContentPrimitives.js.