Skip to content

Temme inheritance

Oussama Essamadi edited this page Jan 15, 2019 · 3 revisions

Inheritance


Description

Option inheritance is where Temme really shines, much like in object oriented programming with classes, hierarchy objects can inherit each other's options to minimize the need for duplication.

There are three cases of inheritance (Also called hierarchy referencing):

  • Object to Object reference: When a hierarchy object references another hierarchy object with the same or higher scope, in other words, this applies only to sibling reference or child to parent reference, and never vice versa.

  • Object to Template reference: When an object references a template and inherits its options. As templates are never rendered, they make for the perfect dummy hierarchies that are only good for inheritance. Keep in mind that templates can never reference a non-template hierarchy.

  • Template to Template reference: When a template hierarchy references another template hierarchy, the same scoping logic applies here just like the Object-to-Object case.

Only the following options can be inherited:

  • attributes
  • childNodes
  • classes
  • content
  • dataset
  • id
  • name

Syntax

// Some random hierarchy object declaration.
const hierarchy = {

    // The hierarchy's reference, this is mandatory so that
    // the other hierarchies can reference it.
    ref: 'parent',

    // Some option here.
    // Some option here.
    // Some more options here...

    // The children of the hierarchy object.
    childNodes: [
        {
            // The referencing option, this is what basically tells Temme
            // what to reference and how to do the said reference.
            from: {

                // The reference of the hierarchy object to inherit the 
                // options from.
                ref: 'parent'
            }
        }
    ]
}

Just as declared above, the child element that referenced its parent will inherit all of the parent's options, of course, the inheritance can be altered to meet your needs, like changing the mode to be either append or override, include only or exclude some options, inherited the referenced hierarchy's children and more... You can read more about those options here.

Object to Object inheritance

As teased above, you can arrange for as many inheritances as you want, so long they are valid.

// Some random hierarchy object declaration.
const hierarchy = {

    ref: 'parent',
    attributes: { visible: true },
    classes: ['red', 'blue'],
    childNodes: [
        {
            // Inheriting from the parent.
            ref: 'sibling',
            name: 'h1',
            classes: ['yellow']
            dataset: {
                id: 100,
                title: 'Some title'
            },
            from: {
                ref: 'parent'
            }
        },
        {
            // Inheriting from the sibling.
            name: 'p',
            from: {
                ref: 'sibling'
            }
        }
    ]
}

So to simplify it, let's visualize the primary state of the three hierarchy objects along with their set inheritance-allowed options.

  • The parent hierarchy:

    • attributes:
      • visible: true

    • classes:
      • 0: red

      • 1: blue

  • The first sibling:

    • classes:
      • 0: yellow

    • dataset:
      • id: 100

      • title: Some title

  • The second sibling:

    • no options

After all the references are processed and everthing that needed inheritance has been inherited, this would be the resulting hierarchy object:

  • The parent hierarchy:

    • attributes:
      • visible: true

    • classes:
      • 0: red

      • 1: blue

  • The first sibling:

    • attributes:
      • visible: true

    • classes:
      • 0: blue

      • 1: red

      • 2: yellow

    • dataset:
      • id: 100

      • title: Some title

  • The second sibling:

    • attributes:
      • visible: true

    • classes:
      • 0: blue

      • 1: red

      • 2: yellow

    • dataset:
      • id: 100

      • title: Some title

Basically, the first sibling inherited extra options from the parent, and then, the second sibling by inheriting the first sibling ended up getting its options plus the options the first sibling inherited from the parent. And you can only imagine how this can be scaled into a more complex referencing cycle.

If you're wondering why the indexes of the classes changed after the inheritance process, it's because they were sorted by Temme, and of course, if any duplicates are found would be eliminated.

Template to Template inheritance

Much like the previous Object-to-Object inheritance, only between templates.

// Some random hierarchy object declaration.
const hierarchy = {
    templates: [
        {
            ref: 'temp-1',
            classes: ['bold', 'dup', 'dup']
        },
        {
            ref: 'temp-2',
            classes: ['orange', 'dup']
        }
    ],
    from: {
        ref: 'temp-2'
    }
}

Notice the duplicate in the classes options of both templates, that's for Temme to take care of. The following is the visualization of the hierarchy object on its primary state:

  • The first template:

    • attributes:
    • classes:
      • 0: bold

      • 1: dup

      • 2: dup

  • The second template:

    • classes:
      • 0: orange

      • 1: dup

  • The hierarchy object:

    • no options

After Temme has done it's thing, this would be the result:

  • The first template:

    • attributes:
    • classes:
      • 0: bold

      • 1: dup

  • The second template:

    • classes:
      • 0: bold

      • 1: dup

      • 2: orange

  • The hierarchy object:

    • classes:
      • 0: bold

      • 1: dup

      • 2: orange

As you can see, all duplicates removed, arrays sorted, and properly inherited.

Inheritance range

With Temme, not only can you inherited options blind-folded, but you can also specify what to inherit and what to ignore. Say you want to inherit only the classes option and the dataset option from a hierarchy object, and ignore everything else? Easy:

// Some random hierarchy object declaration.
const hierarchy = {
    templates: [
        {
            ref: 'temp-1',
            attributes: {
                visible: true,
                counter: 56
            },
            classes: ['some-class'],
            dataset: { id: 814 }
        }
    ],
    from: {
        ref: 'temp-1',
        include: ['classes', 'dataset']
    }
}

With that, only the classes and dataset options will be inherited and nothing else. Say you want to ignore just a select range of options? Just as easy:

// Some random hierarchy object declaration.
const hierarchy = {
    templates: [
        {
            ref: 'temp-1',
            attributes: {
                visible: true,
                counter: 56
            },
            classes: ['some-class'],
            dataset: { id: 814 }
        }
    ],
    from: {
        ref: 'temp-1',
        exclude: ['dataset']
    }
}

With that, we basically inherited everything but the dataset option. Keep in mind that you can only use either include and exclude and never both at the same time.

Children inheritance

By default, inheriting the childNodes option is disabled by Temme, but of course, if needed, it can easily be toggled ON. In addition to that, you can also specify whether the inherited children must come before or after the inheriting object's own children.

// Some random hierarchy object declaration.
const hierarchy = {
    from: {
        childNodes: [
            {
                ref: 'list',
                name: 'ul',
                childNodes: [
                    {
                        name: 'li'
                    },
                    {
                        name: 'li'
                    }
                ]
            },
            {
                from: {
                    ref: 'list',
                    children: {
                        allow: true
                    }
                },
                childNodes: [
                    {
                        name: 'span'
                    }
                ]
            }
        ]
    }
}

With that, we allow children inheritance for a specific hierarchy object so that it can inherit all of the children of the hierarchy object it references. By default, they will be appended to the end of the referencing hierarchy object's own childNodes option. To change that, simply utilize the placement sub-option like the following.

// Inside of the referencing object.
from: {
    ref: 'list',
    children: {
        allow: true,
        // This controls how the inherited children are appened.
        // It accepts either “before” or “after” and nothing else.
        // It's by default set to “after”.
        placement: 'before'
    }
},

Inheritance mode

Probably the most powerful feature as far as inheritance goes is controlling how options are inherited. Sometimes when inheriting a hierarchy object, Temme is had to deal with matching options from both sides, for example, the inheriting object already has a defined id option and then receives another value from the referenced object due to inheritance, so which one of them is kept?

  • Append mode: This is the default inheritance mode that tells Temme to:

    • If the option is of a primitive type (string, number, boolean): keep the original option intact and ignore the inheritance for that option.
    • If the option is of type array: Concatenate both options together.
    • If the option is of type object: Append-only the key/value pair that doesn't already exist in the inheriting object's targeted option.
  • Override mode:

    • If the option is of a primitive type (string, number, boolean): Override the said option no matter what.
    • If the option is of type array: Override the said option no matter what.
    • If the option is of type object: Override the matching key-value pairs and append the non-matching ones.