Extending and Adapting a.js

The extension system in a.js allows developers to define custom behaviors, inject new functionalities, and override existing ones. It offers flexibility for advanced customization while maintaining the reactive and modular nature of a.js.


Extensions with <script a-extension>

Description:

The <script a-extension> tag is used to define extensions in a.js. These extensions allow developers to add, replace, or inject functions into the A global object or any custom tags defined in a.js.

Syntax:

<script a-extension>
  // Define or override functions here
</script>

Behavior:

  1. Extensions are processed during the initialization phase of a.js.
  2. The script tag is associated with an _AExtension object containing extension-specific properties and tasks.

Example:

<script a-extension>
  function f(elem) {
    let src = A.getSourceContent(elem).txt;
    console.log(src);
  }
  document.currentScript._AExtension = {
    AParsedTagsTasks: [
      { selector: "console", function: f }
    ]
  };
</script>

A.extend Object

The A.extend object provides methods to add or override internal functions in a.js during an extension's execution.

addInitWait(promise)

Adds a promise to the initialization process, ensuring specific tasks are completed before a.js is considered fully initialized.

Parameters:

Example:

A.extend.addInitWait(new Promise((resolve) => setTimeout(resolve, 1000)));

getInternalFunction(AFunctionName)

Retrieves the internal implementation of an existing function.

Parameters:

Returns:

Example:

const getJSONPath = A.extend.getInternalFunction("getJSONPath");
console.log(getJSONPath);

replaceInternalFunction(AFunctionName, newFunction)

Replaces an existing internal function with a new implementation.

Parameters:

Example:

A.extend.replaceInternalFunction("getJSONPath", function (obj, path) {
  console.log("Custom behavior");
  return path.split(".").reduce((o, p) => o && o[p], obj);
});

addInternalFunction(AFunctionName, newFunction)

Adds a new internal function to a.js.

Parameters:

Returns:

Example:

const newFunc = A.extend.addInternalFunction("myNewFunction", () => {
  console.log("This is a new function.");
});
newFunc();

Using _AExtension

The _AExtension object in an extension script can define tasks that are executed when custom tags are parsed.

AParsedTagsTasks

Description:

The AParsedTagsTasks property defines tasks to execute for specific tags when they are parsed.

Properties:

Example:

function logSourceContent(elem) {
  const src = A.getSourceContent(elem).txt;
  console.log("Source content:", src);
}

document.currentScript._AExtension = {
  AParsedTagsTasks: [
    { selector: "console", function: logSourceContent }
  ]
};

PostImportFetchTasks

Description:

The PostImportFetchTasks property in _AExtension allows developers to process imported content after it has been fetched and before it is parsed or rendered.

Properties:

Example:

function cleanUnwantedTags(txt) {
  if (txt.startsWith("<!DOCTYPE ")) {
    let pos = txt.indexOf(">");
    txt = txt.substring(pos + 1);
  }
  let re = /<!--AUnwanted-->.*?<!--\/AUnwanted-->/gims;
  txt = txt.replace(re, "");
  return { txt };
}

document.currentScript._AExtension = {
  PostImportFetchTasks: [
    { function: cleanUnwantedTags }
  ]
};

TagCreationTasks

Description:

The TagCreationTasks property defines tasks that modify or initialize elements as they are created.

Properties:

Example:

function initializeCustomTag(element) {
  element.setAttribute("initialized", "true");
  console.log("Tag initialized:", element.tagName);
}

document.currentScript._AExtension = {
  TagCreationTasks: [
    { selector: "custom-element", function: initializeCustomTag }
  ]
};

Adapting Default Configurations

AConfig Object

The AConfig object allows for overriding default behaviors and settings in a.js.

Modifiable Properties:

Example:

<script>
  AConfig.addSourceMaps = true;
  AConfig.keepCustomTagsInitState = false;
</script>

Best Practices for Extensions

  1. Avoid Collisions: Use unique names for new functions to prevent overwriting existing implementations unintentionally.
  2. Test Extensions Thoroughly: Extensions can have far-reaching effects, especially when replacing internal functions.
  3. Follow Dependency Order: Use addInitWait to ensure dependencies are resolved before your extension executes.
  4. Use Namespaces: Scope variables and keys within namespaces to avoid conflicts in dynamic contexts.

> Examples