# Why Stratox

Startox.js enables you to create high-quality Single-Page Applications (SPA) with the power of JavaScript.

Stratox.js is a user-friendly JavaScript framework designed to make building Single-Page Applications (SPA) straightforward and efficient. With just a few core concepts, you can easily create sophisticated features. Stratox.js leverages the latest JavaScript capabilities and follows the Model-View-Controller (MVC) pattern for an organized and maintainable code structure.

Delivering outstanding performance and fast response times across platforms, Stratox.js operates independently of external dependencies. Its UI engine and form builder align with HTML semantics, ensuring simplicity and accessibility. Ideal for building single-page applications (SPAs), Stratox.js is a powerful, versatile tool for modern web development.

### User-Friendly

Stratox.js is built to be a very **user-friendly** JavaScript framework that simplifies the creation of applications. You as a developer only need to know a few stuff from the framework and with that you can build some advance stuff.

### Platform-agnostic nature

Stratox.js doesn't discriminate or judge based on the platform you use, and it works seamlessly on all platforms and depends on nothing but it self.

### Full accessibility support

Moreover, by allowing developers to write regular HTML with the right semantics, Stratox.js ensures that the resulting interfaces are fully accessible. This dual emphasis on simplicity and accessibility makes Stratox.js a powerful tool for creating user-friendly and inclusive web applications.

### Why Stratox.js?

**Performance and Usability**

* **High Performance**: Stratox.js is optimized for top-notch performance.
* **Great Load Speed**: Enjoy swift loading times for a seamless user experience.
* **Optimized**: A finely-tuned library that prioritizes efficiency.
* **User-Friendly**: Intuitive and easy to use, simplifying the development process.

**Flexibility and Accessibility**

* **Platform-Agnostic**: Works seamlessly across all platforms.
* **Full Accessibility Support**: Build inclusive and accessible applications effortlessly.
* **HTML Semantics**: Follow HTML semantics if desired.

**Core Features**

* **Template Engine**: Streamlines the creation of views, components, and UI elements.
* **Form Builder**: Supports nested form names while adhering to HTML semantics.
* **Styled Components**: Add scoped, dynamic styles to your components effortlessly.
* **Container Library**: Enables seamless communication between template views and your project.
* **State Handler**: Manage application state easily with Stratox Pilot.
* **Router**: Simplify navigation within your application.
* **Dispatcher**: Handle custom events and interactions with ease.
* **Fetch API**: Built-in support for API communication.
* **MVC Capabilities**: Out-of-the-box support for the Model-View-Controller architecture.
* **Async and Bundle**: Support for asynchronous loading and bundling of views.

**Development Tools**

* **Vite**: Integrated support for Vite, enabling fast and modern development workflows.

**Optional Enhancements**

* **Tailwind**: Seamlessly integrate with the Tailwind CSS framework.
* **Stratox Design System**: Optionally utilize Stratox’s design system for a cohesive UI.
* **Alpine.js**: Compatible with Alpine.js for added interactivity.

### Targeting

* **Single-Page Application (SPA):** Ideal for creating SPAs with enhanced user experiences.
* **Progressive Web App (PWA):** Make your PWA more app like
* **Cross-Platform Compatibility:** Apache Cordova, Xamarin, Electron, Ionic, and similar.
* **Backend Language Integration:** Very easy to install and work with various backend languages.

> ### Help Shape Stratox
>
> Stratox is an emerging framework with exciting developments underway. Our next milestone is to enable static file generation. We're also building a component library to provide plug-and-play features like sortable and searchable tables and lists for easy integration. If you’d like to suggest a feature, feel free to reach out at <daniel.ronkainen@wazabii.se>.


# Installation

<figure><img src="/files/8m90vfkqxwU8Y6wh4rKL" alt="Installation prompt"><figcaption></figcaption></figure>

### Install

To install Stratox, simply execute the following command:

```
npm create stratox@latest
```

Next, follow the prompted instructions to complete the installation process. If you're a first-time user, I highly recommend reading through the entire guide.

### The installation choises

<details>

<summary>Tailwind</summary>

Tailwind CSS is a utility-first framework with low-level classes for building custom designs directly in HTML. It simplifies responsive design with a comprehensive set of pre-built classes.

</details>

<details>

<summary>Stratox Tailwind design system</summary>

Stratox Tailwind is a super lightweight design system that simplifies CSS and HTML programming. It keeps code minimal by loading only essential Tailwind styles. The system includes normalizations, typography, wrappers, forms, and spacing classes, all responsive for any device.

</details>

<details>

<summary>Alpine.js</summary>

Alpine.js is a lightweight JavaScript framework providing declarative and reactive data-binding directly in HTML. It can be used as a modern alternative to jQuery for interacting with the DOM, adding interactivity with minimal code.

</details>

<details>

<summary>ESlint</summary>

ESLint is a static code analysis tool for identifying and fixing problematic patterns in JavaScript code. It helps developers maintain consistent coding styles and improve code quality by enforcing configurable rules.

</details>

### Updating the framework

To update Stratox, use the following command:

```
npm update
```

This command will ensure that you have the latest version of the framework installed.

<details>

<summary>Help Shape Stratox</summary>

If you’d like to suggest a feature, feel free to reach out at <daniel.ronkainen@wazabii.se>.

</details>

Continue to the Quick start guide or jump to the [Step by Step Tutorial](/router/dispatcher-overview).


# Quick Start (MVC)

This quick start guide will walk you through the best practices for working with the Stratox Framework. We will show you how to create views, controllers, set up routes, and finally connect to a model, to get you started building a dynamic application using Stratox.

### View

First, create a new JavaScript file for your view, for example: `src/views/ShoppingList.js`.

```js
/**
 * This is the main view
 * It will also render the shopping list block component later
 */
export default function ShoppingList({ props }) {
  return `
    <article class="card-1 border-bottom">
      <header class="content-header">
        <h1 class="headline-1 mt-0">${props.title}</h1>
      </header>
    </article>
  `;
}
```

Now that the layout has been created, we just need to display it.

### Controller

Next, we need to add a controller to manage the view. Create a new file named `src/controllers/ShoppingListController.js`.

```js
// Start by importing our view
import ShoppingList from "@/templates/views/ShoppingList";

/**
 * This is a quick start example on how to work with Stratox and MVC
 */
export default class ShoppingListController {
  /**
   * Index page
   */
  index({ http, services, helper, context }) {
    // Render the ShoppingList view with the title "My shopping list"
    this.layout(ShoppingList, { title: 'My shopping list' });

    return this;
  }

  /**
   * Show single page
   */
  show() {
    // You can try to add a single product page here
    // linked from API model at the end of the guide
    return this;
  }
}
```

### Setting Up Routing

To specify where the page should be displayed, use the Stratox router. Open the file `src/routes/app.js` and modify it like below. I also slightly modified the start page example so that it does not take to much place.

```js
import { Router } from '@stratox/pilot';
import HttpStatus from '@/controllers/HttpStatus';
// 1. Import the controller:
import ShoppingListController from '@/controllers/ShoppingListController';

const router = new Router();

router.get('/', function({ http, services, helper, context }) {
  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <h1 class="headline-1">Start</h1>
        <p>Lorem ipsum dolor</p>
      </div>
    </article>
  `;
});

// 2. Connect the controller and page to a GET route
router.get('/list', [ShoppingListController, "index"]);

// Handle 404 and 405 HTTP status errors
router.get('[STATUS_ERROR]', [HttpStatus, "statusError"]);

export default router;
```

Now, visit your development URL with the path `/#list`, for example: `http://localhost:5173/#list`. Your shopping list will be displayed.

### Extending the View with a Component Block

Let's create a dynamic shopping list by modifying the layout and adding a component block called `RenderShoppingList` at the top of the view in `src/views/ShoppingList.js`. Also, make sure to render the block inside the main view so that it is displayed.

```js
/**
 * This is the dynamic list block
 */
function RenderShoppingList({ props, view, context }) {
  // This will set default data for the props if it's parameter "is" missing
  context.setDefault({
    products: []
  });

  // Bind function to add a new item to the list
  const handleAddList = view.bind((props) => {
    const title = `List ${props.products.length + 1}`;
    props.products.push({ title: title });
  });

  // Render the HTML list
  return `
    <section class="product-list">
      <ul class="listing">
        ${props.products.map((product) => `
          <li class="post-item">${product.title}</li>
        `).join("")}
      </ul>
      <button class="button" onclick="${handleAddList}">Add New Product</button>
    </section>
  `;
}

/**
 * This is the main view
 * It will also render the shopping list block component
 */
export default function ShoppingList({ props, view }) {
  // Render the main HTML with the shopping list
  return `
    <article class="card-1 border-bottom">
      <header class="content-header">
        <h1 class="headline-1 mt-0">${props.title}</h1>
      </header>
      <section>
        <h2 class="headline-3 mt-0 pt-6">My list</h2>
        ${view.block(RenderShoppingList)}
      </section>
    </article>
  `;
}
```

Now, visit your development URL with the path `/#list` (e.g., `http://localhost:5173/#list`), and you will see that a click event has been added to create a list. You will use the same bind function for every event (e.g., `onclick`, `onchange`, `oninput`) to automatically trigger changes. If needed, you can disable the automatic updates by passing `false` as the second argument to the bind function.

### Model Example

Let us fetches some data from an API model to display additional information. Let's add a quick example to demonstrate how easy it is to fetch data and use it in our `RenderShoppingList` block component.

Open the file `src/views/ShoppingList.js` and add a ajax fetch request to a dummy API (se the 3 points in example below).

```js
// 1. Import the Stratox fetch library
import { StratoxFetch } from '@stratox/core';

/**
 * This is the dynamic list block
 */
function RenderShoppingList({ props, view, context }) {
  // 2. Return a loading screen if fetch request is currently loading...
  if (context.isLoading()) {
    return `<div class="p-5">Loading...</div>`;
  }

  // This will set default data for the props if it's parameter "is" missing
  context.setDefault({
    products: []
  });

  // Bind function to add a new item to the list
  const handleAddList = view.bind((props) => {
    const title = `Post ${props.products.length + 1}`;
    props.products.push({ title: title });
  });

  // Render the HTML list
  return `
    <section class="product-list">
      <ul class="listing">
        ${props.products.map((product) => `
          <li class="post-item">${product.title}</li>
        `).join("")}
      </ul>
      <button class="button" onclick="${handleAddList}">Add New Product</button>
    </section>
  `;
}

/**
 * This is the main view
 * It will also render the shopping list block component
 */
export default function ShoppingList({ props, view }) {
  // 3. Render the main HTML with the shopping list 
  //    propagated with data using Stratox Fetch library
  return `
    <article class="card-1 border-bottom">
      <header class="content-header">
        <h1 class="headline-1 mt-0">${props.title}</h1>
      </header>
      <section>
        <h2 class="headline-3 mt-0 pt-6">My list</h2>
        ${view.block(RenderShoppingList, StratoxFetch.get("https://dummyjson.com/products?limit=3"))}
      </section>
    </article>
  `;
}
```

Now, visit your development URL with the path `/#list` and you will see the updated list that includes fetched data from the API.

### Summary

This quick start guide showed you how to create a view, a controller, set up routing, and extend functionality using the Stratox Framework. You also learned how to add dynamic components and a modal example to extend the functionality of your views. Stratox provides a simple and user-friendly way to build powerful, dynamic applications with an organized MVC structure.

Feel free to experiment and expand upon these examples to build your application!

Continue to read more about components and features or jump to the [Step by Step Tutorial](/router/dispatcher-overview).


# Layout & Components

### Overview of View Types in Stratox

Stratox supports three primary types of views, designed to help you structure and manage your application's UI efficiently:

1. [**Layout**:](#using-layout-views) Serves is the starting point for you to show views. You then extend your layout views content  with `block` and `partial` views.
2. [**Partial**:](#using-partial-views) Extends the layout with content. Partials are self-contained, but as they are statically loadad and counts as a part of the layout, you will need to update the state to update it's content meaning all views will be refreshed.
3. [**Block**:](#using-block-views) Extends the layout with **dynamic** content. Blocks are self-contained, allowing for updates without refreshing the entire layout.

> **Note:** Layout and Block views are initialized similarly but differ in load functionality.

***

### Using Layout Views

Layout views is the starting point for you to show views. You then extend your layout views content  with `block` and `partial` views.

**Example: Basic Layout Initialization**

```javascript
import ProductPage from "@/templates/views/ProductPage";

const { view, item } = this.layout(ProductPage, {
    title: "My text 1",
    description: "Lorem ipsum dolor",
});
```

This code adds and displays the `ProductPage` view if it exists. The `view` object is the main instance, while `item` represents the view's context. Both can manage or update data in the layout but are optional for most cases.

***

### Using Partial Views

**Example: Adding a Partial View**

```javascript
import Increment from "@/templates/views/blocks/Increment";

export default function ProductPage({ props, view }) {
    return `
        <article class="relative card-1 border-bottom ingress">
            <div class="wrapper md">
                <h1 class="headline-1">${props.title}</h1>
                <p>${props.description}</p>
            </div>
        </article>
        <div class="increment">
            ${view.partial(Increment, { title: "Start incrementing", increment: 0 })}
        </div>
    `;
}
```

Partials update the entire layout when refreshed, making them useful for integrating smaller components within larger views.

***

### Using Block Views

**Example: Adding a Block View**

```javascript
import Increment from "@/templates/views/blocks/Increment";

export default function ProductPage({ props, view }) {
    return `
        <article class="relative card-1 border-bottom ingress">
            <div class="wrapper md">
                <h1 class="headline-1">${props.title}</h1>
                <p>${props.description}</p>
            </div>
        </article>
        <div class="increment">
            ${view.block(Increment, { title: "Start incrementing", increment: 0 })}
        </div>
    `;
}
```

Blocks are dynamic components that can be updated independently, making them ideal for complex, interactive elements like sortable tables or modals.

***

### Protecting Against XSS (Cross-Site Scripting)

To safeguard against XSS vulnerabilities, encapsulate potentially injectable data within double curly braces:

**Example: Escaping Data**

```javascript
export default function TextComponent({ props, view }) {
    return `
        <article class="relative card-1 border-bottom ingress">
            <div class="wrapper md">
                <h1 class="headline-1">${{props.title}}</h1>
                <p>${{props.description}}</p>
            </div>
        </article>
    `;
}
```

This approach is especially crucial for user-generated content, query strings, or third-party data.

***

### Loading Views Multiple Times

To reuse the same view with different data, provide unique names for each instance:

**Example: Reusing Layouts**

```javascript
const { view: view1, item: item1 } = this.layout({ ProductPage1: ProductPage }, {
    title: "My text 1",
    description: "lorem ipsum dolor",
});

const { view: view2, item: item2 } = this.layout({ ProductPage2: ProductPage }, {
    title: "My text 2",
    description: "lorem ipsum dolor",
});
```

By appending unique identifiers (e.g., `ProductPage1`, `ProductPage2`), you can load the same layout multiple times efficiently.

***

### Quick Load View

For simple components, you can define and load views directly within your code:

**Example: Inline Layout**

```javascript
this.layout(() => `
    <header class="ingress mb">
        <h2 class="headline-3 title">Hello World</h2>
        <p>Lorem ipsum dolor sit amet.</p>
    </header>`);

this.partial({
    bindToName: function({ props }) {
        return `
        <header class="ingress mb">
            <h2 class="headline-3 title">${props.title}</h2>
            <p>Lorem ipsum dolor sit amet.</p>
        </header>`;
    }
}, {
    headline: "My text 2",
});

this.block(({ props }) => `
    <header class="ingress mb">
        <h2 class="headline-3 title">${props.title}</h2>
        <p>Lorem ipsum dolor sit amet.</p>
    </header>`, {
    headline: "My text 2",
});
```

This approach is ideal for quick prototyping or when working with minimal HTML components.

***

### Asynchronous Layout Loading

To optimize performance, load layouts asynchronously to reduce the initial bundle size:

**Example: Dynamic Layout Loading**

```javascript
this.layout("Ingress", {
    title: "Welcome!",
    description: "lorem ipsum dolor",
});
```

Ensure the `Ingress.js` module exists in `./src/templates/views/`. It will be dynamically loaded when accessed.

**Example: Reusing Layouts with Identifiers**

```javascript
this.layout("text#ingressView1", {
    title: "My text 1",
    description: "Lorem ipsum dolor",
});

this.layout("text#ingressView2", {
    title: "My text 2",
    description: "Lorem ipsum dolor",
});
```

Appending unique identifiers (e.g., `#ingressView1`, `#ingressView2`) allows efficient reuse of layouts.

***

By following these guidelines, you can fully leverage Stratox's view system for creating dynamic, efficient, and secure web applications.


# Update components

Updating Props, States, and Dispatch Requests.

Stratox provides three key mechanisms to manage data and interactions within your application: **props**, **states**, and the **dispatcher**. While they share similarities, each serves a distinct purpose:

* [**Props**:](#updating-props) Data passed directly to views or components. Props are isolated to their respective view instances, allowing you to update specific parts of a page without affecting the entire layout.
* [**States**:](#updating-states) Globally accessible within the active route and controller method. Updating a state refreshes the entire page, including all nested components, making it suitable for broader application-wide changes.
* [**Dispatcher**:](#dispatching-requests) Handles communication between routes and controller methods. It facilitates making HTTP requests (e.g., GET, POST, PUT, DELETE) and navigating between routes while passing data seamlessly.

Understanding these differences helps you utilize each tool effectively, depending on the scope and requirements of your application.

***

### Updating Props

Props are objects and data passed to your views/components, serving as the primary mechanism for passing and updating data. Unlike global variables, props are contained within a view instance, allowing you to dynamically update parts of your page without reloading the entire page.

**Example: Updating Props**

```javascript
export default function TextComponent({ props, view, update, context }) {

  // Set default values for props
  context.setDefault({ updatedOnce: false });

  // Define click event to update props
  const clickEvent = this.bind((props, view, item, event) => {
    props.title = 'Headline updated in click event';
  });

  // Update props dynamically after a timeout
  if (!props.updatedOnce) setTimeout(() => {
    props.updatedOnce = true;
    update({ title: "Updated through Timeout" });
    //update(string|object|function|StratoxItem, object|function|StratoxItem);
  }, 2000);

  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <h1 class="headline-1">${props.title}</h1>
        <p>${props.description}</p>
        <button class="button bg-primary" onclick="${clickEvent}">Change headline</button>
      </div>
    </article>
  `;
}
```

***

### Updating States

States are global but scoped to the active route and controller function method. You can set, update, and access states across all nested components. When a state is updated, it refreshes the entire page and its nested components.

**Example: Updating States**

```javascript
export default function TextComponent({ props, state }) {

  // Set default values for the state
  state.setDefault({ title: "Hello world" });

  // Dynamically update the state after a timeout
  if (!props.updatedOnce) setTimeout(() => {
    state.update("title", "Updated through Timeout");
    //state.update(string|object, mixed);
  }, 2000);

  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <h1 class="headline-1">${state.get('title')}</h1>
        <p>${props.description}</p>
      </div>
    </article>
  `;
}
```

***

### Dispatching Requests

The dispatcher allows you to manage requests (GET, POST, PUT, DELETE) and pass data between routers and controller methods. If Fetch/Ajax config data is defined in your main config or route, it will trigger automatically.

**Example: Dispatching Requests**

```javascript
export default function TextComponent({ props, dispatch, request, http }) {

  // Navigate to a new route with updated data
  if (!request.get.get("title")) setTimeout(() => {
    dispatch.navigateTo("#start", { title: "<em>Headline updated</em>" });
  }, 2000);

  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <h1 class="headline-1">${{request.get.get("title") ?? "Hello World"}}</h1>
        <p>${props.description}</p>
      </div>
    </article>
  `;
}
```

***

By leveraging props, states, and the dispatcher effectively, you can build dynamic, responsive, and maintainable applications in Stratox. These tools offer flexibility and power to update views and manage application data seamlessly.


# Component argumnets

Component Arguments with Examples

In Stratox, components can utilize various arguments to manage and manipulate data, handle events, and communicate across different parts of the application. Below is a detailed explanation of each argument type, along with quick examples to demonstrate their usage.

***

### 1. **Props**

Props are objects and data passed to views or components. They are isolated within the view instance, allowing for dynamic updates to specific parts of the page.

**Example:**

```javascript
export default function TextComponent({ props }) {
    props.title = "Initial Title";

    return `
        <h1>${props.title}</h1>
        <p>${props.description}</p>
    `;
}
```

***

### 2. **State**

States are global but scoped to the active route and controller method. Updating a state refreshes the entire page and all nested components.

**Example:**

```javascript
export default function StateExample({ state }) {
    state.setDefault({ counter: 0 });

    setTimeout(() => {
        state.update("counter", state.get("counter") + 1);
    }, 1000);

    return `
        <p>Counter: ${state.get("counter")}</p>
    `;
}
```

***

### 3. **Dispatch**

The dispatcher facilitates making requests (GET, POST, PUT, DELETE) and passing data between routers and controller methods.

**Example:**

```javascript
export default function DispatchExample({ dispatch }) {
    dispatch.navigateTo("#about", { message: "Navigated successfully" });

    return `<p>Check console for navigation dispatch.</p>`;
}
```

***

### 4. **Update**

A shortcut for updating and refreshing a view dynamically.

**Example:**

```javascript
export default function UpdateExample({ props, update }) {
    context.setDefault({ counter: 1 });
    props.title = "Dynamic Update";

    setTimeout(() => {
        update({ title: "Updated Title", counter: ++props.counter });
    }, 2000);

    return `
        <h1>${props.title} ${props.counter}</h1>
    `;
}
```

***

#### 5. **HTTP**

Access server-side data such as HTTP methods or status codes.

**Example:**

```javascript
export default function HTTPExample({ http }) {
    return `
        <p>HTTP Method: ${http.method}</p>
        <p>Status Code: ${http.status}</p>
    `;
}
```

***

#### 6. **Request**

Provides access to dispatched requests via `request.get` and `request.post`.

**Example:**

```javascript
export default function RequestExample({ request }) {
    const title = request.get.get("title") || "Default Title";

    return `
        <h1>${{title}}</h1>
    `;
}
```

***Note:** To safeguard against XSS vulnerabilities, encapsulate potentially injectable data within double curly braces.*&#x20;

***

#### 7. **View**

Represents the main view instance, which can handle events and update content.

**Example:**

```javascript
export default function ViewExample({ view }) {
    const clickHandler = view.bind(() => {
        alert("View clicked!");
    }, false);

    return `
        <button onclick="${clickHandler}">Click Me</button>
    `;
}
```

By adding false in second argumnet in bind you will not update and refresh the view.

***

#### 8. **Context**

Access the Stratox context library to manage settings or default values.

**Example:**

```javascript
export default function ContextExample({ context }) {
    context.setDefault({ title: "Hello World" });

    return `
        <p>Default title: ${props.title}</p>
    `;
}
```

***

#### 9. **Services**

Used to access framework functions or communicate externally.

**Example:**

```javascript
export default function ServicesExample({ services }) {
    const dispatch = services.get("dispatch");
    dispatch.navigateTo("#contact");

    return `<p>Check console for service dispatch.</p>`;
}
```

***

By understanding and utilizing these arguments effectively, you can build robust and dynamic applications with Stratox. Each argument serves a specific purpose, enabling a modular and maintainable approach to component development.


# Styled components

Styled components in Stratox allow you to add custom CSS styles directly to your components. These styles are dynamically loaded and unloaded with the component, minimizing the risk of CSS collisions and improving performance.

### Example Usage

You can utilize the `context` argument in your component to manage styles. The `context` represents the component's instance and provides access to methods like `addStyles`.

```javascript
export default function MyComponent({ props, context }) {
  // Add styles to the component
  context.addStyles({
    '.headline-1': {
      fontSize: '3rem',
    },
    '.custom-button': {
      color: '#FFF',
      fontSize: '1.5rem',
      backgroundColor: 'purple',
      padding: '1rem 2rem',
    },
  });

  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <h1 class="headline-1">${props.title}</h1>
        <p>${props.description}</p>
        <a class="custom-button" href="#about">Visit page</a>
      </div>
    </article>
  `;
}
```

**In this example:**

* The `.headline-1` class gets a custom font size.
* The `.custom-button` class gets styled with unique colors, font size, and padding.

### Binding Styles to Components

By default, styles added with `addStyles` are scoped to the component they are defined in. If you call `addStyles` multiple times for the same component, the styles will be overwritten.

To define multiple style blocks within the same component, you can assign a unique identifier to the styles:

```javascript
// 1. Styles bound to the component
context.addStyles({
  '.headline-1': {
    fontSize: '3rem',
  },
  '.custom-button': {
    color: '#FFF',
    fontSize: '1.5rem',
    backgroundColor: 'purple',
    padding: '1rem 2rem',
  },
});

// 2. Additional styles bound to the component with a unique identifier
context.addStyles({
  'p': {
    fontSize: '1.8rem',
  },
}, 'moreStyles');
```

### **Clearing Styles**

You can dynamically clear styles during a component's lifecycle. This is particularly useful for temporary components like modals or popups.

```javascript
// Clear styles bound to the component name
context.clearStyles();

// Clear styles bound to custom name
context.clearStyles('moreStyles');
```

### Why Use Styled Components?

Styled components offer a great way to add complementary styles to your components without bloating your global CSS. They work harmoniously with popular CSS libraries like **Tailwind CSS**, **Bootstrap**, or **Sass**.

Key benefits:

* **Dynamic Loading**: Styles are loaded only when the component is active.
* **Scoped Styles**: Avoid CSS conflicts and ensure styles are isolated.
* **Performance**: Unused styles are unloaded automatically.

With Stratox styled components, you get the flexibility of CSS-in-JS while maintaining simplicity and performance in your applications.


# Events

In Stratox, you only need to memorize one function for binding events: `bind`. This function works by binding a view instance to an event, making it straightforward to modify the view's component properties. It automatically refreshes the component with the updated data, ensuring the UI stays in sync with your application state.

**Creating an Event**

In the example below, when the user clicks the "Increment +" button, a new value is added to the `props` object, and the view is automatically refreshed to reflect the change.

```javascript
export default function Increment({ props, view }) {
  const clickEvent = view.bind((props, view, item, event) => {
    props.increment += 1;
  });

  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <header class="mb">
          <h2 class="headline-2">${props.increment > 0 ? "Incremented" : props.title}</h2>
          <p>Has been incremented <strong>${props.increment}</strong> times!</p>
        </header>
        <a class="button bg-primary sm my-btn" href="#2" onclick="${clickEvent}">Increment +</a>
      </div>
    </article>
  `;
}
```

***

**Manual Updates and Refreshes**

You can disable automatic updates and refreshes by setting the second argument of `bind` to `false`. This allows you to manually control when a view or its components should refresh.

```javascript
// Bind function to add a new item to the list
const handleAddList = this.bind((props, view, item, event) => {
  props.increment += 1;
  // Manually update and refresh the view
  view.update();
}, false);
```

This flexibility gives you full control over your app’s performance, allowing you to refresh components only when necessary.

***

**Why Not Always Refresh the View?**

Refreshing the entire view isn't always desirable. For example, if you bind an `oninput` event to a text field, you wouldn't want the whole view to refresh each time a user types. Instead, you want the text field's value to update without re-rendering the entire view.

Here’s how to handle this scenario:

```javascript
const inputEvent = this.bind((props, view, item, event) => {
  props.value = event.target.value;
}, false);
```

A complete example:

```javascript
export default function Increment({ props, view }) {
  // Bind onclick event with refresh enabled
  const clickEvent = view.bind((props, view, item, event) => {
    props.increment += 1;
  });

  // Bind to oninput event, but with refresh view disabled
  const inputEvent = view.bind((props, view, item, event) => {
    props.value = event.target.value;
  }, false);

  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <header class="mb">
          <h2 class="headline-2">${props.increment > 0 ? "Incremented" : props.title}</h2>
          <p>Has been incremented <strong>${props.increment}</strong> times!</p>
        </header>

        <div class="mb">
          <label>Title</label>
          <input type="text" oninput="${inputEvent}" value="${props.value ?? ""}">
        </div>

        <a class="button bg-primary sm my-btn" href="#2" onclick="${clickEvent}">Increment +</a>
      </div>
    </article>
  `;
}
```

***

**Choosing What View to Bind**

By using `this` with the `bind` function, you can access the current component. This means you can also bind events to child components or specific parts of the layout.

Here’s an example:

```javascript
function IncrementUp({ props }) {
  return `
    <header class="mb">
      <h2 class="headline-2">${props.increment > 0 ? "Incremented" : props.title}</h2>
      <p>Has been incremented <strong>${props.increment}</strong> times!</p>
    </header>
  `;
}

export default function Increment({ props, view }) {
  const { view, item, output: IncrementBlock } = view.block(IncrementUp, props);
  
  // Bind an event to the child view
  const clickEvent = view.bind((props, view, item, event) => {
    props.increment += 1;
  });

  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        ${IncrementBlock}
        <div class="mb">
          <label>Title</label>
          <input type="text" value="">
        </div>
        <a class="button bg-primary sm my-btn" href="#2" onclick="${clickEvent}">Increment +</a>
      </div>
    </article>
  `;
}
```

What’s cool is that in this example, only the `IncrementUp` component will refresh when the event is triggered, even though the button controlling the event is outside the `IncrementUp` component. This allows for efficient updates while maintaining precise control over the layout.


# Services

The container library enables seamless two-way communication between parent and child components, without relying on props. This makes it a powerful tool in your arsenal.

### Set and Get

Below are examples of how to set and retrieve values from the container:

```javascript
// 1. Set a regular value (string/number)
services.set("myContainerName1", "Hello World 1");

console.log(services.get("myContainerName1"));
// Result: Hello World 1

// 2. Set an object
services.set("myContainerName2", {
  title: "Hello World 2",
  description: "Lorem ipsum dolor",
});

console.log(services.get("myContainerName2").title);
// Result: Hello World 2

// 3. Set a function
services.set("myContainerName3", function(arg1, arg2) {
  console.log(`Hello ${arg1} ${arg2}`);
});
// Pass the expected arguments to the function after the first argument
// When get is called, the function is automatically triggered
services.get("myContainerName3", "World!", 3);
// Result: Hello World!
```

### Has and Overwrite

If you try to create a service container with a name that already exists, it will throw an error telling you that the container already exists and that you need to take appropriate action. This is where `has` and `overwrite` come in—a safeguard to avoid collisions.

### Has

```javascript
if (services.has("myContainerName1")) {
  services.set("myContainerName1", "Hello World 1");
}
```

### Overwrite

```javascript
services.set("myContainerName1", "Hello World 1", true);
```

### Example

If you are familiar with the [Step-by-Step tutorial](/step-by-step-tutorial/increment-events), you might recognize the increment example below, but with the exception that we are using the container instead of props to increment the value.

Let's modify our parent view (`src/templates/views/Start.js`):

```javascript
import Increment from "@/templates/views/blocks/Increment";

export default function Start({ props, services, view }) {

  services.set("increment", 0);
  
  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <h1 class="headline-1">${props.title}</h1>
        <p>${props.description}</p>
      </div>
    </article>
    <div class="increment">
      ${view.block(Increment, { title: "Start incrementing" })}
    </div>
  `;
}
```

And let's modify our child component (`src/templates/views/blocks/Increment.js`):

```javascript
export default function Increment({ props, services, view }) {
  // Tell the user that the 'increment' container needs a default value
  if (!services.has("increment")) {
    throw new Error(`Set a default integer value for the 'increment' service container in the parent component!`);
  }

  // Get increment value from container
  const increment = services.get("increment");

  // Set and overwrite the increment value in container
  const clickEvent = view.bind((event) => {
    services.set("increment", increment + 1, true);
  });

  return `
  <article class="relative card-1 border-bottom ingress">
    <div class="wrapper md">
      <header class="mb">
        <h2 class="headline-2">${increment > 0 ? "Incremented" : props.title}</h2>
        <p>Has been incremented <strong>${increment}</strong> times!</p>
      </header>
      <a class="button bg-primary sm my-btn" href="#2" onclick="${clickEvent}">Increment +</a>
    </div>
  </article>
  `;
}
```

### What's the Point?

Now you might be asking yourself what's the point of utilizing the container and not just props. While props can solve many cases, the container facilitates seamless communication with its parent component—in this case, `Start`. You can actually get the increment in `Start` and also increment it there too, as shown below in the `src/templates/views/Start.js` example:

```javascript
import Increment from "@/templates/views/blocks/Increment";

export default function Start({ props, services, view }) {
  if (!services.has("increment")) {
    services.set("increment", 0);
  }

  const clickEvent = this.bind((event) => {
    services.set("increment", services.get("increment") + 1, true);
  });

  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <h1 class="headline-1">${props.title}</h1>
        <p>${props.description}</p>
        <a class="button bg-primary sm my-btn" href="#" onclick="${clickEvent}">Increment from start +</a>
      </div>
    </article>
    <div class="increment">
      ${view.block(Increment, { title: "Start incrementing" })}
    </div>
  `;
}
```

Isn't that cool! We have now created an example where you can seamlessly, between a parent and child component, increment a number with buttons from both the parent and child components.


# Fetch Library (Ajax Requests)

The Stratox framework provides built-in Ajax integration using the JavaScript Fetch API, which you can utilize if needed. While it's not mandatory, you can easily integrate your own Ajax library in the dispatcher within the main JavaScript file, `main.js`.

The Ajax response will be passed to the controllers!

### Triggering Ajax Calls

You can trigger Ajax calls in 3 different ways:

1. **Bind Ajax call to a view and the view's response**
2. **Configure the main app's settings to enable Ajax calls for every router request automatically** (though you can manually disable Ajax calls in each route if necessary).
3. **Manually add Ajax configuration in each route**.
4. **Or all of the above**

### **Import Startox Fetch Library**&#x20;

```javascript
import { StratoxFetch } from '@stratox/core';
```

### 1. Binding Ajax to a View

Binding an Ajax request to a view allows the view to automatically trigger the request upon rendering, updating with the JSON response as soon as it's received.

**Quick Start**

Here’s the fastest way to bind an Ajax request to a view:

```js
const ingressView = this.layout(Ingress, StratoxFetch.get("https://dummyjson.com/products/1"));
```

*That’s it! The view will display the response from the URL as soon as the data is fetched.*

You can make GET, POST, PUT, and DELETE requests by simply changing the `get` method above to the appropriate request type.

```javascript
StratoxFetch.get(url, config);
StratoxFetch.post(url, data, config);
StratoxFetch.put(url, data, config);
StratoxFetch.delete(url, config);
```

* **url:** Expects a string and URL value
* **config:** expects a object and is the [Fetch API config](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
* **data:** expects a object and it is the the parsed body/post request items

**Modifying the Response**

You can modify the Ajax response before passing it to the view. Here’s how:

```js
const fetch = new StratoxFetch("https://dummyjson.com/products/1");
const ingressView = this.layout(Ingress, fetch.execute(function(response) {
    response.title = "Modified title";
}));
```

You can make GET, POST, PUT, and DELETE requests by simply specifying it in the `setMethod` method to the appropriate request type:

```js
fetch.setMethod("POST");
```

If you want to configure the fetch API, you pass an object in second parameter of the class:

```javascript
const fetch = new StratoxFetch(url, config);
```

**Creating the View**

The view function will receive the Ajax response data once the request is complete. While waiting for the data, you can use `context.isLoading()` to manage loading states and display an appropriate message if needed.

Here’s an example:

```js
export function Ingress({ props, context }) {
  // Add loading screen
  if(context.isLoading()) {
    return `<div class="p-5">Loading...</div>`;
  }

  return  `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <h1 class="headline-1">${props.title}</h1>
        <p>${props.description}</p>
      </div>
    </article>
  `
}
```

#### Summary

* **Quick Setup**: Simply pass the Ajax request to `this.layout`.
* **Modify Data**: Use `.execute()` to adjust the response before it reaches the view.
* **Loading State**: Use `context.isLoading()` to manage loading behavior and provide feedback to the user while waiting for the request to complete.

This approach allows for flexible and dynamic updates within your views, with minimal setup.

### 2. Enable Ajax on Every Router Request

To enable Ajax for every router request, open the main JavaScript file `./src/main.js` and add the `request` configuration to the `App` class. Below, I've filled in each config option:

**Note:** The full configuration list is at the end of the guide.

```js
const app = new App({
    request: {
        dataType: "json", // Will set everthing to match json response
        url: "https://example.se/backend-location/",
        //startPath: "home", // Not required, will set a default start path
        config: {
            // The regular Fetch API configs
            headers: {
                // Pass custom headers
            }
        },
        get: function(searchParams) {
            // Middleware for GET requests
            searchParams.append("param", 1);
            return searchParams;
        },
        post: function(object) {
            // Middleware for POST requests
            object.param = 1;
            return object;
        }
    }
});
```

[Click here for full configuration.](#fetch-ajax-configurations)

The `dataType` configuration automatically sets certain headers in the fetch config to correspond to each data type. However, you can overwrite these headers with your own custom headers if needed.

### 3. Enable Ajax Manually on a Router

To enable Ajax manually on a specific router, open the main JavaScript file `./src/routes/app.js` and add the `request` configuration to the route. Below, I've filled in each config option:

```js
router.get('/contact', [PagesController, "contact"], {
    dataType: "json",
    url: "https://example.se/backend-location/", 
    get: function(searchParams) {
        // Add Query string to URL / ?param=998271
        searchParams.append("param", 998271);
        return searchParams;
    }
});
```

[Click here for full configuration.](#fetch-ajax-configurations)

With these configurations, you can easily enable Ajax functionality for your Stratox application, either globally or on specific routes. Adjust the options as needed to suit your application's requirements.

#### Accessing the Ajax Response

Accessing the Ajax response is as simple as accessing the `http` parameter to retrieve the Ajax request body response. This process works the same in controllers.

```js
router.get('/', function({ http, services, helper, context }) {
    console.log(http.response); // The Ajax response
    return this;
});
```

In this example, `http.response` allows you to access the Ajax response data within the router/controller function. You can then use this data as needed in your application logic.

### Fetch Ajax Configurations

For the fetch option 2-3, both approaches use the same object parameters:

* **url**: The URL to your site/API location to access via Ajax.
* **dataType**: Set expected response data type (`json`, `xml`, or `text`). JSON response will be converted to an object, XML to `DOMParser`, and text will be returned as is. (default: `json`)
* **path**: Overwrites the expected URI path. (optional)
* **startPath**: Adds a default start path if the URI path is empty. (optional)
* **config**: Supplies the Fetch API with options. You can read more about these options [here](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch). (optional)
* **get**: Passes or modifies a GET parameter for the controller result. (optional)
* **post**: Passes or modifies a POST parameter for the controller result. (optional)


# Routes and URI

Stratox Pilot is a JavaScript router designed for ease of use and flexibility. It employs regular expressions to offer dynamic routing, allowing for both straightforward and complex navigation paths.

Stratox Pilot can be used as a standalone library. As a universal library, it works across different platforms without needing any external dependencies. This independence makes Stratox Pilot a practical option for developers in search of a dependable routing tool that combines advanced features and modular design in a compact package.

You can find the router file at: `src/routes/app.js`

#### A Really Basic Example

```js
// Possible path: #about
router.get('/about', function({ http, services, helper, context }) {
});
```

You can, of course, add multiple paths:

```js
// Possible path: #about/contact
router.get('/about/contact', function({ http }) {
});
```

#### Using Regular Expressions

To incorporate regular expressions in routing patterns, enclose the expression within curly brackets: `{PATTERN}`. This syntax allows for flexible and powerful URL matching based on specified patterns.

```js
// Possible path: #about/location/stockholm
router.get('/about/location/{[a-z]+}', function({ http }) {
});
```

#### Binding Router Patterns to a Key

It is strongly advised to associate each URI path you wish to access with a specific key. This approach enhances the clarity and manageability of your route definitions.

```js
// Possible path: #about/location/stockholm
router.get('/{page:about}/location/{city:[^/]+}', function({ http }) {
    // http.vars.page[0] is expected to be "about"
    // http.vars.city[0] is expected to be any string value (stockholm, denmark, new-york) from passed URI.
});
```

You can also map an entire path to a key, allowing for more concise and organized route management.

```js
// Possible path: #about/contact
router.get('/{page:about/location}', function({ http }) {
    // http.vars.page[0] is expected to be "about"
    // http.vars.page[1] is expected to be "location"
});
```

#### Combining Pattern with Keywords

Combining patterns with keywords (e.g., `post-[0-9]+`) enables you to create more expressive and versatile route definitions.

```js
// Possible path: #articles/post-824/hello-world
router.get('/articles/{id:post-[0-9]+}/{slug:[^/]+}', function({ http }) {
    // http.vars.id[0] is expected to be "post-824"
    // http.vars.slug[0] is expected to be "hello-world"
});
```

#### Handling Unlimited Nested Paths

To accommodate an unlimited number of nested paths within your routing configuration, you can utilize the pattern `.+`. However, it's strongly advised to precede such a router pattern with a specific prefix to maintain clarity and structure, as demonstrated in the example below with the prefix `/shop`.

```js
// Example of accessing a single category: #shop/furniture
// Example of accessing multiple nested categories: #shop/furniture/sofas/chesterfield
router.get('/shop/{category:.+}', function({ http }) {
    // Retrieves the last category segment from the path
    const category = http.vars.category.pop();
    console.log(`The current category is: ${category}`);
});
```

This approach allows for the dynamic handling of deeply nested routes under a common parent path, offering flexibility in how URLs are structured and processed.

#### Optional URI Paths

To define one or more optional URI paths, enclose the path segment (excluding the slash) in brackets followed by a question mark, for example: `/(PATH_NAME)?`. This syntax allows for flexibility in route matching by making certain path segments non-mandatory.

```js
// Possible path: #articles
// Possible path: #articles/post-824/hello-world
router.get('/articles/({id:post-[0-9]+})?/({slug:[^/]+})?', function(http) {
});
```

It's important to note that you should not enclose the leading slash in brackets. The leading slash is automatically excluded from the pattern, ensuring the correct interpretation of the route.

#### Catch Status Errors

There is an optional and special router pattern that lets you catch HTTP status errors within a router.

```js
router.get('[STATUS_ERROR]', function({ http, services, helper, context }) {
    if (http.status === 404) {
        console.log("404 Page not found", http.status);
    } else {
        console.log("405 Method not allowed", http.status);
    }
});
```

This route can be used to handle specific error codes, such as `404 Not Found` or `405 Method Not Allowed`, providing a better user experience.


# Dispatch States (navigate)

### Push States

The library provides intuitive navigation options to seamlessly transition between pages and initiate GET, POST, PUT and DELETE requests.

#### Page Navigation / GET Request

Initiating a GET request or navigating to a new page is straightforward. Such actions will correspond to a get router, with the request parameter converting into an instance of `URLSearchParams` for the request.

**Arguments**

* **path** (string): Specifies the URI, which can be a regular path or a hash.
* **request** (object): Sends a GET request or query string to the dispatcher. This will be transformed into an instance of `URLSearchParams`. When executed in a browser, the query string will also be appended to the URL in the address field.

**Make GET Request**

```js
// URI hash (fragment with hashtag) navigation
dispatch.navigateTo("#articles/824/hello-world", { test: "A get request" });

// URI path navigation
dispatch.navigateTo("/articles/824/hello-world", { test: "A get request" });
```

**Note**: You can access the container inside all your controllers and component views, meaning you can also access the dispatch!

**The Navigation Result**

The above navigation will trigger the result for the matching router:

```js
// GET: example.se/?test=A+get+request#articles/824/hello-world
router.get('/articles/{id:[0-9]+}/{slug:[^/]+}', function({ http }) {
    const id = http.vars.id.pop();
    const slug = http.vars.slug.pop();
    const test = http.request.get.get("test"); // Get the query string/get request "test"
    console.log(`Article ID: ${id}, Slug: ${slug} and GET Request ${test}.`);
});
```

#### POST Request

Creating a POST request is similarly efficient, targeting a post router. The `http` parameter will be an object to facilitate the request.

**Arguments**

* **path** (string): Defines the URI, which can be a regular path or a hash.
* **request** (object): Submits a POST request to the dispatcher. This will be an object, allowing for detailed and structured data transmission.

**Make POST Request**

```js
dispatch.postTo("#post/contact", { firstname: "John", lastname: "Doe" });
```

**The HTTP POST Request Result**

The above post will trigger the result for the matching router:

```js
// POST: example.se/#post/contact
router.post('/post/contact', function({ http }) {
    const firstname = http.request.post.firstname;
    const lastname = http.request.post.lastname;
    console.log(`The post request, first name: ${firstname}, last name: ${lastname}`);
});
```

#### PUT and DELETE

You can of course also make PUT and DELETE requests.

```js
// PUT - Like POST, it will pass arguments as parsed body
dispatch.putTo("#post/contact", { firstname: "John", lastname: "Doe" });

// DELETE - Like GET, it will pass arguments as query string
dispatch.deleteTo("#post/contact", { id: 98862 });
```

### What is Really Cool

What is really cool is that if you have bound the Stratox Fetch library to the main or to a router that matches the request method and the state path, it will actually also make an Ajax fetch request as specified!

**Example of Ajax Fetch Request for Routes**

You can bind an Ajax fetch request directly to a route. Here's how it works:

```js
// Binding the fetch request to the router
router.put('/contact', [PagesController, "contact"], {
    url: "https://example.se/backend-location/", // Main URL
});
```

In this example,  the state will be `/#contact` , show the right controller page and will also make a PUT ajax request with the Fetch API to the specified URL and router path (`https://example.se/backend-location/contact`).&#x20;

This demonstrates how easy it is to integrate asynchronous data fetching within your Stratox application, making your routes even more dynamic.


# Dispatcher overview

You can find the dispatcher in `src/main.js`. It is where all the JavaScript functionality is initialized, dispatched, and emitted. The dispatcher is essential for identifying and providing the appropriate route from the state handler. Designed for flexibility, it enables the incorporation of custom logic to tailor functionality to specific needs.

```js
app.setup("#app").mount(routes, app.serverParams("fragment"), function(response, request) {
    return `
        <main>
            ${response}
        </main>
    `;
});
```

You could also add things like navigation to the above example.

```js
app.setup("#app").mount(
    Router routerCollection,
    serverParams,
    callable dispatch
);
```

#### Let Us Break Down the Arguments

**Arguments**

* **routerCollection**
* **serverParams**
* **dispatch**

**Router Collection (`routerCollection`)**

This expects a `Router` instance, allowing for customization. You can create your router collection by extending the `Router` class, potentially adding more HTTP methods, structure, or functionality.

**Server Params (`serverParams`)**

Server params indicate the URL segment the dispatcher should utilize. These params dynamically target the specified URI segment. Several built-in options include:

* **URI Fragment**: Represents the URL hash or anchor minus the "#" character.

  ```js
  dispatcher.serverParams("fragment");
  ```
* **URI Path**: The regular URI path segment.

  ```js
  dispatcher.serverParams("path");
  ```
* **Script Path**: Ideal for non-browser environments, supporting backend applications, APIs, or shell command routes.

  ```js
  dispatcher.request("path");
  ```

**Dispatch Function (`dispatch`)**

The `dispatch` argument expects a callable function to process the match result, handling both successful (status code 200) and error outcomes (status code 404 for "page not found" and 405 for "Method not allowed"). The function receives two parameters: `response` (object) and `statusCode` (int).

#### Response Details

* **response** (object): Provides an object with vital response data.
* **statusCode** (int): Indicates the result, either successful (200) or error (404 or 405).

#### Understanding the Response

The response structure, as illustrated with the router pattern `/{page:product}/{id:[0-9]+}/{slug:[^/]+}`, and URI path `/product/72/chesterfield` includes:

```json
{
    "verb": "GET",
    "status": 200,
    "path": ["product", "72", "chesterfield"],
    "vars": {
        "page": "product",
        "id": "72",
        "slug": "chesterfield"
    },
    "form": {},
    "request": {
        "get": "URLSearchParams",
        "post": "FormData"
    }
}
```

* **verb**: The HTTP method (`GET` or `POST`).
* **status**: The HTTP status code (`200`, `404`, or `405`).
* **path**: The URI path as an array.
* **vars**: An object mapping path segments to keys.
* **form**: Captures submitted DOM form elements.
* **request.get**: An instance of `URLSearchParams` for GET requests.
* **request.post**: An object for POST requests.
* **response**: Will propagate if a possible fetch (Ajax) response.


# Deployment Guide

Deploying your Stratox project is straightforward. This guide will walk you through building your project and deploying it to popular services like GitHub Pages, Netlify, Vercel and more.

### Building Your Stratox Project

To build your Stratox project, run the following command in your terminal:

```bash
npm run build
```

This command will compile your app and output the static files into a directory named `dist` located in your project's root directory. These files are ready to be deployed to a hosting service of your choice.

***

### Deploying to GitHub Pages

GitHub Pages is a free hosting service that lets you host static websites directly from your GitHub repository.

#### Steps:

1. **Initialize a Git Repository** (if you haven't already):

   ```bash
   git init
   git add .
   git commit -m "Initial commit"
   ```
2. **Create a `gh-pages` Branch**:

   ```bash
   git checkout -b gh-pages
   ```
3. **Copy the `dist` Contents to the Root**:

   Replace the contents of your repository with the built files:

   ```bash
   rm -rf !(dist)
   cp -r dist/* .
   rm -rf dist
   ```
4. **Commit and Push to `gh-pages` Branch**:

   ```bash
   git add .
   git commit -m "Deploy to GitHub Pages"
   git push origin gh-pages
   ```
5. **Configure GitHub Pages**:
   * Go to your repository on GitHub.
   * Navigate to **Settings** > **Pages**.
   * Under **Source**, select the `gh-pages` branch.
   * Click **Save**.
6. **Access Your Deployed App**:

   Your app will be available at:

   ```
   https://<your-username>.github.io/<your-repository>/
   ```

***

### Deploying to Netlify

Netlify is a popular platform for deploying static websites with continuous deployment and other powerful features.

#### Steps:

1. **Create a Netlify Account**:
   * Sign up at [netlify.com](https://www.netlify.com/).
2. **Install Netlify CLI** (optional but recommended):

   ```bash
   npm install netlify-cli -g
   ```
3. **Login via CLI**:

   ```bash
   netlify login
   ```
4. **Initialize Your Site**:

   ```bash
   netlify init
   ```

   * Choose to create & configure a new site.
   * Select the team (usually your username).
   * Provide a site name (optional).
   * Set the deploy path to `dist`.
5. **Deploy Your Site**:

   ```bash
   netlify deploy --prod
   ```
6. **Access Your Deployed App**:

   Netlify will provide a URL where your app is deployed.

***

### Deploying to Vercel

Vercel offers a seamless experience for deploying static sites and serverless functions.

#### Steps:

1. **Install Vercel CLI**:

   ```bash
   npm install -g vercel
   ```
2. **Login to Vercel**:

   ```bash
   vercel login
   ```
3. **Deploy Your Project**:

   ```bash
   vercel
   ```

   * When prompted, set the output directory to `dist`.
4. **Configure Project Settings** (if needed):
   * You can adjust settings in the `vercel.json` file.
5. **Access Your Deployed App**:

   Vercel will provide a URL where your app is deployed.

***

### Deploying to Other Services

The `dist` folder contains all the static files needed to run your app. You can deploy these files to any static hosting service, such as:

* **Amazon S3 and CloudFront**
* **Firebase Hosting**
* **GitLab Pages**
* **Surge.sh**

#### General Steps:

1. **Sign Up for the Service**:

   Create an account on your chosen hosting platform.
2. **Upload the `dist` Folder**:

   Use the platform's interface or CLI tools to upload your static files.
3. **Configure Domain and Settings**:

   Set up any necessary configurations, such as custom domains or SSL certificates.
4. **Access Your Deployed App**:

   Your app should now be live at the URL provided by the hosting service.

***

### Conclusion

Deploying your Stratox project is as simple as building your app and uploading the contents of the `dist` folder to your preferred hosting service. With platforms like GitHub Pages, Netlify, and Vercel, you can have your app live in just a few minutes.

If you encounter any issues during deployment, consult the documentation of the hosting service or reach out to the Stratox community for support.


# Directory overview

### Directory Structure Overview

Below is an overview of the most important directories and files in your project:

* **dist/**: This directory contains the distribution/production code that you can build when your app is completed.
* **src/**: This is your development directory.
  * **assets/**: Here you'll find your images and CSS styles.
    * **images/**: Images used in your application.
    * **style.css**: The main CSS file for styling your application.
  * **controllers/**: This is where you can add all your controllers.
  * **routes/**: Route definitions for your application.
  * **templates/**: All your templates views and components
    * **views/**: All your views should be located here.
      * **blocks/**: Extend your view with block components.
  * **Fields.js**: This file contains your field components, such as form fields and buttons, your free to modify this as you wish.
* **main.js**: This is the main/index JavaScript file for your Startox application.

This structured approach helps organize your project effectively, making it easier to navigate and maintain.

<details>

<summary>Help Shape Stratox</summary>

If you’d like to suggest a feature, feel free to reach out at <daniel.ronkainen@wazabii.se>.

</details>


# Getting started

We'll create an example that is fully available and installable through the installation process. However, it's recommended that you begin without relying on existing examples, as this tutorial will guide you through building the example step by step.

Let us start with a minor example that we will improve upon throughout the guide.

### Add Routes

Begin by updating the router file located at `src/routes/app.js` as follows:

```js
router.get('/', function() {
  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <h1 class="headline-1">Hello World</h1>
        <p>Lorem ipsum dolor</p>
      </div>
    </article>`;
});

router.get('/about', function() {
  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <h1 class="headline-1">About us</h1>
        <p>Lorem ipsum dolor</p>
      </div>
    </article>`;
});
```

**Visit your browser to see the results.**

There's nothing wrong with managing code this way. However, as the app grows larger, this approach can become challenging, particularly when the router file starts to become lengthy. This is where template layout views and controllers come in handy. They improve the manageability and modularity of your app, making it easier to organize and maintain.

### Creating Your Page

Let's begin by exploring Stratox's template system for creating dynamic layout and block components. Later on, we'll discuss controllers.

Proceed by creating a new template layout file named `src/templates/views/Start.js`.

```js
export default function Start({ props }) {
  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <h1 class="headline-1">${props.title}</h1>
        <p>${props.description}</p>
      </div>
    </article>
  `;
}
```

### Modifying the Router Example

To create dynamic start and about pages, you only need to update the router file `src/routes/app.js` as shown below:

First, add an import statement at the top of the router file to import the view:

```js
import Start from "@/templates/views/Start";
```

Next, integrate the views into each router callable:

```js
router.get('/', function({ http, services, helper, context }) {
  this.layout(Start, {
    title: "Hello world!",
    description: "Lorem ipsum dolor",
  });
  return this;
});

router.get('/about', function() {
  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <h1 class="headline-1">About us</h1>
        <p>Lorem ipsum dolor</p>
      </div>
    </article>`;
});
```

**Note:** You can reuse the same view multiple times within the same method, as explained in more detail in the views section.

Visit your browser to see the results.

<details>

<summary>Response Arguments</summary>

If you want to know more about the response arguments, then visit the [Response Arguments](/configs/response-arguments) page.

</details>

<details>

<summary>Template Layout</summary>

Here are some important options to consider when loading and initializing views:

* **Static Layouts**: These are layouts that are bundled and loaded synchronously with the application. They are commonly used for static content that does not change frequently. [Read more](/views-components/layout-and-components)
* **Asynchronous Layouts**: Asynchronous layouts are loaded dynamically when needed, which can help improve performance by reducing initial load times. They are useful for content that may change frequently or is not required immediately upon application startup. [Read more](broken://pages/GNorYxQO3RaqhliVEBds)

</details>


# Navigation

Let's create a simple navigation view so that we can navigate between the two pages we just created.

### Creating the Navigation View

Create a new directory named "layout" and add a new template view file inside that directory: `src/templates/views/Navigation.js`. You can name the directory whatever you like or add the navigation view inside the "views" directory—it's entirely up to you.

```js
import logo from '@/assets/images/logo-stratox.svg';

export default function Navigation({ props }) {
    const pages = (props.vars?.[0] ?? []);
    const currentPage = pages.pop();

    function isActive(slug) {
        return ((currentPage ?? false) === slug) ? " underline" : "";
    }

    return `
    <header id="header" class="card-4 border-bottom items">
        <figure id="logo" class="headline-6 m-0">
            <img width="150" height="42" src="${logo}" alt="Stratox logotype">
        </figure>
        <nav class="ml-auto">
            <ul class="items gap-x-25">
                <li class="nav-item${isActive(false)}"><a class="nav-to-btn" href="#">Start</a></li>
                <li class="nav-item${isActive("about")}"><a class="nav-to-btn" href="#about">About</a></li>
            </ul>
        </nav>
    </header>
    `;
}
```

I have also added some styles and a logotype to make it look good.

### Showing the Navigation

We want to show the navigation on all the pages, but it is not very efficient to manually add the navigation to every page. Instead, we want to add it to the main global view.

Let's proceed by opening the main JavaScript file: `src/main.js`.

1. Start by importing the navigation at the top:

```js
import Navigation from '@/templates/views/Navigation';
```

2. Edit the mount code by adding the navigation. You can extend Stratox views with  `this.block`.  Block view is a self-contained dynamic view.

```js
app.setup("#app").mount(routes, app.serverParams("fragment"), function(response, request) {
    return `
        ${this.block(Navigation, request)}
        <main>
            ${response}
        </main>
    `;
});
```

**Visit your browser to see the results.**


# Controllers

## Creating a Controller

To further enhance modularity, it's recommended to utilize controllers, especially for larger applications. Let's create a controller file named `src/controllers/PagesController.js` and add the following code to it. Incorporate your view into the controller and pass in template data such as title and description.

### Creating the Controller

Create the file `src/controllers/PagesController.js` and add the following code:

```js
import Start from "@/templates/views/Start";

export default class PagesController {
    
    start() {
        this.layout(Start, {
            title: "Hello world!",
            description: "Lorem ipsum dolor",
        });

        return this;
    }
    
    about({ http, services, helper, context }) {
        return `
        <article class="relative card-1 border-bottom ingress">
            <div class="wrapper md">
                <h1 class="headline-1">About us</h1>
                <p>Lorem ipsum dolor</p>
            </div>
        </article>`;
    }
}
```

**Note:** You can also reuse the same view multiple times within the same method, as explained in more detail in the views section.

### Edit the Router

Now that we have created the controller, we need to establish a connection between it and the router. Let's open up the router example again and make the following changes:

1. Add the import statement for the `PagesController` at the top of the router file `src/routes/app.js`:

```js
import PagesController from '@/controllers/PagesController';
```

2. Update the router routes for the start and about pages as follows, connecting your controller to each route:

```js
router.get('/', [PagesController, "start"]);
router.get('/about', [PagesController, "about"]);
```

### Summary

And that's it! You have now created a highly modular and dynamic app. Visit your browser to see the results.

<details>

<summary>Response Arguments</summary>

If you want to know more about the response arguments, then visit the [Response Arguments](/configs/response-arguments) page.

</details>

<details>

<summary>Template Layouts</summary>

Here are some important options to consider when loading and initializing views:

* **Static Views**: These are views that are bundled and loaded synchronously with the application. They are commonly used for static content that does not change frequently. [Read more](/views-components/layout-and-components)
* **Asynchronous Views**: Asynchronous views are loaded dynamically when needed, which can help improve performance by reducing initial load times. They are useful for content that may change frequently or is not required immediately upon application startup. [Read more](broken://pages/GNorYxQO3RaqhliVEBds)

</details>


# Increment / Events

Let's make the About page more interactive by adding a simple "click and increment" feature. Each click will update the displayed count, showing how many times the button has been clicked.

### Create Your View

First, create a new view template file named `templates/views/blocks/Increment.js`. Define the view function as follows:

```js
export default function Increment({ props, view }) {

  const clickEvent = view.bind((event) => {
    props.increment += 1;
  });
  
  return `
  <article class="relative card-1 border-bottom ingress">
    <div class="wrapper md">
      <header class="mb">
        <h2 class="headline-2">${props.increment > 0 ? "Incremented" : props.title}</h2>
        <p>Has been incremented <strong>${props.increment}</strong> times!</p>
      </header>
      <a class="button bg-primary sm my-btn" href="#2" onclick="${clickEvent}">Increment +</a>
    </div>
  </article>
  `;
}
```

**Note:** We created a new view in the directory `blocks`. Although the increment view can function like any other view, we intend to use it specifically as a block view. This means we will extend a view—specifically, the start view—with the increment.

### Quick Breakdown

* **Event Binding**: We start by binding the click function to a constant named `clickEvent`, which will execute when the button is clicked.
* **Triggering the Event**: We call `clickEvent` in the button's `onclick` attribute, triggering the function whenever the button is clicked, updating the counter and headline dynamically.

**Note:** It will work exactly the same for `onchange`, `oninput`, and other DOM events.

### Controller

Now that we have our increment block view, we need to render it in the start view:

```js
import Increment from "@/templates/views/blocks/Increment";

export default function Start({ props, view }) {
  return `
    <article class="relative card-1 border-bottom ingress">
      <div class="wrapper md">
        <h1 class="headline-1">${props.title}</h1>
        <p>${props.description}</p>
      </div>
    </article>
    <div class="increment">
      ${view.block(Increment, { title: "Start incrementing", increment: 0 })}
    </div>
  `;
}
```

**Visit your browser to see the results!**

<figure><img src="/files/LSy2t3ltwG04Mp3yqbRb" alt=""><figcaption></figcaption></figure>

### Summary

With these modifications, the code appears much cleaner and highly modular. You've now familiarized yourself with the Stratox architecture, and every example in this tutorial serves an essential purpose. You're free to utilize them as you see fit for your application.

<details>

<summary>Response Arguments</summary>

If you want to know more about the response arguments, then visit the [Response Arguments](/configs/response-arguments) page.

</details>

<details>

<summary>Template Layouts</summary>

Here are some important options to consider when loading and initializing views:

* **Static Views**: These are views that are bundled and loaded synchronously with the application. They are commonly used for static content that does not change frequently. [Read more](/views-components/layout-and-components)
* **Asynchronous Views**: Asynchronous views are loaded dynamically when needed, which can help improve performance by reducing initial load times. They are useful for content that may change frequently or is not required immediately upon application startup. [Read more](broken://pages/GNorYxQO3RaqhliVEBds)

</details>


# Form Builder

You can of course create forms with regular HTML if you want, but for your information, Stratox comes with a highly dynamic form builder that helps you create dynamic, responsive, and engaging web forms with ease. Out of the box, there is a form template view that will help you get started, which you can change to suit your needs.

### Setting Up the Form

Begin by opening the controller file `src/controllers/PagesController.js`. Then, import the form view (`src/templates/views/Form.js`) at the top of the document:

```js
import Form from "@/templates/views/blocks/Form";
```

**Note:** The `Form.js` view comes pre-installed, so you do not need to create it yourself.

Then add a `contact` method to the `PagesController`. We will first add the form view and then add form fields to it:

```js
contact({ http, services, helper, context }) {
    const { view, item } = this.layout(Form, {
      action: "#contact",
      method: "post",
      ingress: {
        headline: "Contact us",
        content: "Lorem ipsum dolor"
      }
    });

    item.setFields({
        firstname: {
            type: "text",
            label: "First name",
            conAttr: {
                class: "grow"
            }
        },
        lastname: {
            type: "text",
            label: "Last name",
            conAttr: {
                class: "grow"
            }
        },
        message: {
            type: "textarea",
            label: "Message",
        },
        custom: {
            label: "Contact information",
            type: "group",
            fields: {
                email: {
                    type: "text",
                    label: "E-mail",
                    attr: {
                        type: "email"
                    }
                },
                phone: {
                    type: "text",
                    label: "Phone",
                    attr: {
                        type: "tel"
                    }
                }
            },
            config: {
                // Recommended configs
                nestedNames: true,
                controls: true
            }
        },
        submit: {
            type: "submit",
            value: "Send"
        }
    });

    return this;
}
```

This time, I encourage you to connect the `contact` method in the controller to the router (`router.get('/contact', [PagesController, "contact"])`) and add it to the navigation yourself. Once you're done, visit your browser to see the results.

### Adding the Submit Page

Next, let's add the form submit page to the controller and router.

### **Controller**

First, create a new method called `contactPost` inside the `PagesController`.

```js
contactPost({ http, services, helper, context }) {
    const postData = http.request.post;
    return `
    <div class="wrapper md card-1">
        <header class="mb">
            <h2 class="headline-1">Post request</h2>
            <p>Below is the received request data:</p>
        </header>
        <pre>${JSON.stringify(postData, null, 2)}</pre>
    </div>
    `;
}
```

This view will display the form fields once the form has been submitted.

### **Router**

Next, connect `contactPost` in `PagesController` to a route as follows:

```js
router.post('/contact', [PagesController, "contactPost"]);
```

**Note:** We're using "post" instead of "get" because the form uses `post`, and the router needs to handle `post` requests to catch it. If you have different methods, you can add duplicate URI paths without any risk of collision.

You can add this just below your created route, which hopefully looks like this: `router.get('/contact', [PagesController, "contact"])`.

Visit your browser, and click the submit button on the contact page to see the results.

### Available Form Fields

Available form fields out of the box:

* **text** (password, tel, email, number, etc.)
* **textarea**
* **date**
* **datetime**
* **hidden**
* **select**
* **radio**
* **checkbox**
* **submit** (button)
* **group**
* **views/components**

These fields can be combined with all views and components that you have created!

### Form Field Settings

Available form field settings/configs out of the box. See working examples below:

```js
{
    type: "text", // Default is "text"
    label: "Message",
    description: "Add a field description",
    conAttr: { class: "w-full", ["data-status"]: "1" }, // Create container HTML attributes
    attr: { type: "email", id: "inp-email" },  // Create or overwrite HTML attributes
    config: { pass: "configs" }, // Pass/create configs to your component
    items: { yes: "Yes", no: "No" }, // Add (checkbox, radio, or select list items)
    fields: { ... }, // Group fields, see above example
    value: "Field value"
}
```

### Adding Template Blocks in Form

To pass template layout blocks to a form using Stratox, follow these steps:

1. Import the view at the top of the document/PageController:

```js
import Ingress from "@/templates/views/blocks/Ingress";
```

**Note:** The Ingress component does **not exists** by default, it is just an example. You will need to use a view component that you have created!

2. Utilize the Stratox function `partial` to set the view at your specified position in the form:

```js
const { view, item } = this.layout(Form, {
  action: "#contact",
  method: "post",
  ingress: {
    headline: "Contact us",
    content: "Lorem ipsum dolor"
  }
});

item.setFields({
  textComponent: this.partial(Ingress, {
    title: "Lorem ipsum dolor",
    description: "Lorem ipsum dolor sit amet"
  }).item,
  firstname: {
      type: "text",
      label: "Headline",
  }
});
```


# Building Modal

A guide on building an advanced modal (popup) with just a few lines of code is coming soon


# Design system

Stratox Tailwind is a lightweight design system that makes programming in CSS and HTML enjoyable while optimizing both. It keeps the code minimal by loading only the necessary Tailwind styles and semantical design system classes. The system includes normalizations, typography, wrappers, forms, cards, spacing classes, and more, all tied to media queries for a seamless, responsive design across all devices.

The Stratox Tailwind design system uses rem units in CSS, just like Tailwind, for scalability. However, it simplifies their usage by converting rem units to an intuitive scale: 2.5 rem equals 25 pixels, and .mb-40 represents 40 pixels if **enabled**. This makes achieving pixel-perfect designs effortless for developers without the need for calculations, ensuring consistency for both developers and designers.

### Components

I have more work to do on this guide, but for now, you can visit the site below to view and copy the components using your browser's inspector tool if you wish.

[Startox Tailwind Components](https://wazabii.se/stratox-tailwind/)

### Configure and Manual installation

If you did not install Startox Tailwind during the installation prompt, you can easily install it manually by following these instructions in the guide below and also see configurations:

[Configure Startox Tailwind](https://github.com/stratoxjs/StratoxTailwind)


# Index

The "src/main.js" file is the root JavaScript file, it is where all the JavaScript functionallity is initilized, dispatched end emitted through. It is also here you can make your global configs and changes to your app.

A completly empty installation of Startox framework will come with the minimum required imports out of the box and will look like this.

```javascript
import { App } from '@stratox/core';
import routes from '@/routes/app';
import Fields from '@/templates/Fields';

const app = new App({
    fields: Fields
});

app.setup("#app").mount(routes, app.serverParams("fragment"), function(response, request) {
    return `
        <main>
            ${response}
        </main>
    `;
});
```

You can of course add some functions like tailwind and alpine in the installation process and they will be automatically be installed to the main.js file.

#### Break down

Lets break down the example.

The core and routes has to be imported for the framework to work, the fields is optional.

```javascript
import { App } from '@stratox/core';
import routes from '@/routes/app';
import Fields from '@/templates/Fields';
```

The config has alot more option and vist the config page to read more about that.

```javascript
const app = new App({
    fields: Fields
});
```

You can see the mount method as you apps index file and this is a good place to add your for example navigation. It is allowed to mount multiple indexs or start points if you wish to do that it is up to you but in most cases once will på sufficent. If you install the examples in the installation process you will see what I mean.

```js
app.setup("#app").mount(routes, app.serverParams("fragment"), function(response, request) {
    return `
        <main>
            ${response}
        </main>
    `;
});
```

You can see the mount method as you apps index file and this is a good place to add your for example navigation. It is allowed to mount multiple indexs or start points if you wish to do that it is up to you but in most cases once will på sufficent.

### Router Collection (routerCollection) <a href="#router-collection-routercollection" id="router-collection-routercollection"></a>

This expects a Router instance, allowing for customization. You can create your router collection extending the Router class, potentially adding more HTTP methods, structure, or functionality.

### Server Params (serverParams) <a href="#server-params-serverparams" id="server-params-serverparams"></a>

Server params indicate the URL segment the dispatcher should utilize. These params dynamically target the specified URI segment. Several built-in options include:

**URI Fragment**

Represents the URL hash or anchor minus the "#" character. Will utilize the history pushSate.&#x20;

```javascript
app.serverParams("fragment");
```

**URI Path**

The regular URI path segment. Will utilize the history pushSate.

```javascript
app.serverParams("path");
```

**Script Path**

Will **not** utilize the history pushSate.

```javascript
app.request("path");
```

#### Dispatch Function (dispatch) <a href="#dispatch-function-dispatch" id="dispatch-function-dispatch"></a>

The "dispatch" argument expects a callable function to process the match result, handling both successful (status code 200) and error outcomes (status code 404 for "page not found" and 405 for "Method not allowed"). The function receives two parameters: response (object) and statusCode (int).

* **response (object):** Provides an object with vital response data.
* **statusCode (int):** Indicates the result, either successful (200) or error (404 or 405).


# Configs

### Config example

I will explain every config bellow the example.

```javascript
const app = new App({
    fields: Fields, 
    helper: function() {
        // The Helpers of your choice will be passed to the controllers, views and components
        return {
            yourHelper1: {},
            yourHelper2: {}
        };
    },
    ready: function(builder, observer) {
        //const inst = this; // Stratox main instance
    },
    request: { // Enable Ajax
        dataType: "json",
        url: "https://example.se/backend-location/",
        path: '/api',
        startPath: "home",
        config: {
            headers: {
                'Accept': 'application/json'
            }
        },
        get: function(searchParams) {
            searchParams.append("param", 1);
            return searchParams;
        },
        post: function(object) {
            object.param = 1;
            return object;
        }
    }
});
```

### fields

Fields are loaded by default in the main.js file. You can customize the Fields file "./src/templates/Fields.js" or create a new one. This file contains elements such as form fields and is utilized by the form builder. Note that the form builder will not function without the components. However, if your application does not utilize any forms, you can manage without it. In such cases, you can remove fields from the configuration entirely, thereby reducing the size of your application.

### helper

The helper config allows you to pass all third-party library functions to your routes, controllers, views, and components. This enables you to easily utilize these functions by initializing them in one central location and then distributing them throughout the app.&#x20;

*The helper config accepts any `data type`, but it's highly recommended to structure it as a function that returns an object containing the expected libraries, like bellow.*

```
helper: function() {
    return {
        yourHelper1: {},
        yourHelper2: {}
    };
}
```

### ready

This will be triggered once the main Startox view has finished loading.

### request (Fetch API library / ajax)

Read more about ajax in the [Ajax Integration](/features/fetch-library-ajax-requests) section.

* **url**: The URL to your site/API location to access via Ajax.
* **dataType:** Set expected response data type `json`, `xml` or `text`.  Json response will be converted to `object`, xml to `DOMParser` and text will be text. **(default: json)**
* **path**: Extends the URL with a URI path. **(optional)**
* **startPath**: Adds a default start path if the URI path is empty. **(optional)**
* **config**: Supplies the fetch request with options. You can read more about these options [here](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch). **(optional)**
* **get**: Passes custom or modifies a GET parameter for the controller result. **(optional)**
* **post**: Passes custom or modifies a POST parameter for the controller result. **(optional)**


# Response Arguments

Below is a list of arguments that can be accessed in controller and view responses.

The response arguments are almost the same for controller functions and template views, with one difference: views use the `data` argument instead of `request`. Keep that in mind when reviewing the list below:

### props

This is the object data passed to your template file. It contains information that helps to render the view with dynamic data

*This argument is only accessible by template views.*

### http

This argument provides access to request-related information. For example, consider a request with the URI path `/product/72/chesterfield`:

This argument provides access to request-related information and is used primarily within controller functions.

*This argument is only accessible by controller functions*

```json
{
    "verb": "GET",
    "status": 200,
    "path": ["product", "72", "chesterfield"],
    "vars": {
        "page": "product",
        "id": "72",
        "slug": "chesterfield"
    },
    "form": {},
    "request": {
        "get": "URLSearchParams",
        "post": {}
    }
    "response": {} // If returns a ajax response
}
```

* **verb:** The HTTP method (GET or POST).
* **status:** The HTTP status code (200, 404, or 405).
* **path:** The URI path as an array.
* **vars:** An object mapping path segments to keys.
* **form:** Captures submitted DOM form elements.
* **request.get:** An instance of URLSearchParams for GET requests.
* **request.post:** An object for POST requests.
* **response**: Will propagate if a possible fetch (Ajax) response.

### container

The container can be used to communicate with your template and the outside. You can create your own or access the frameworks functions like bellow.

```javascript
const dispath = container.get("dispatch");
dispath.navigateTo("#about");
```

### helper

Your own possible helper libraries, objects, and functions you passed in the configuration.

### context

Access the Stratox builder context library (you can manage without, only for advanced users; more on this later on).


# Partial view

### **Partial - Example**

```js
import Ingress from "@/templates/views/blocks/Ingress";

const { item: ingressItem } = this.partial({ myText: Ingress }, {
    title: "Lorem ipsum dolor",
    description: "Lorem ipsum dolor sit amet"
});

item.setFields({
    textComponent: ingressItem,
    firstname: {
        type: "text",
        label: "Headline",
    }
});
```


# Stratox.js - Template engine

Stratox.js is a user-friendly JavaScript template engine that helps you easily build template components and views.

The Stratox template library is created using up-to-date methods, keeping its size at around 6 kb when bundled and minimized (gzipped). It works independently, smoothly running on all platforms without needing anything else. Stratox.js is a smart pick for applications and websites, ensuring great performance and quick load time. It's versatile, letting you load views asynchronously (with optional caching) or bundle them conveniently into your main JavaScript file.

### [Startox framework](https://stratox.wazabii.se/)

This is the Startox template engine library. If your looking for the framework, that is fully installable with controllers, routers, template engine, components and design system then [click here](https://stratox.wazabii.se/).

### User-Friendly

Stratox is very user-friendly because it lets you prioritize JavaScript and HTML instead of grappling with the complexities of new markup and platform-specific functions, which in the end only lead to the burden of unnecessary abstractions. Stratox harnesses JavaScript's core capabilities, promoting a practical and fundamental approach to modern web development.

### Platform-agnostic nature

Stratox.js doesn't discriminate or judge based on the platform you use, and it works seamlessly on all platforms and depends on nothing but it self.

### Full accessibility support

Moreover, by allowing developers to write regular HTML with the right semantics, Stratox.js ensures that the resulting interfaces are fully **accessible**. This dual emphasis on simplicity and accessibility makes Stratox.js a powerful tool for creating user-friendly and inclusive web applications.

### Why Stratox.js?

* **High Performance:** Stratox.js is optimized for performance.
* **Great Load Speed:** Experience swift loading times for a seamless user experience.
* **Optimized:** A finely-tuned library that prioritizes efficiency.
* **User-Friendly:** Easy to use, making development a breeze.
* **Platform-Agnostic:** Works seamlessly across all platforms.
* **Template Engine:** Facilitates the creation of Views, components, and UI elements.
* **Form Builder:** Follows HTML semantics, supporting nested form names.
* **HTML Semantics:** Follow HTML semantics if you wish
* **Full Accessibility Support:** You can make your app inclusive and accessible for all.
* **Container Library:** Designed for seamless communication between template views and your project.
* **Async and bundle:** Support asynchronous loading of or bundling of views

### Targeting

* **Single-Page Application (SPA):** Ideal for creating SPAs with enhanced user experiences.
* **Cross-Platform Compatibility:** Apache Cordova (PhoneGap), Xamarin, Electron, Ionic, and similar.
* **Enhancing Static HTML:** Easily integrates with existing static HTML structures.
* **Backend Language Integration:** Communicates seamlessly with various backend languages.


# Installation

Keep in mind that the guide is designed to be read linearly, so try to avoid jumping through it on the first read through. It will only take 30 minutes of your time.

## Installation

```
npm i stratox
```

*Or just download the zip and import Stratox.js file*

### Import Stratox

Start by importing "Stratox.js".

```js
import { Stratox } from './node_modules/stratox/src/Stratox.js';
```

### Config

None of the configs bellow is required for Stratox to work, but they will enable and extends some functionality. Just make sure that the config is executed before any Stratox class instances is called.

```js
Stratox.setConfigs({
    directory: "/absolute/path/to/views/", // Used for autoload
    cache: false, // Automatically clear cache if is false on dynamic import
    handlers: {
    	fields: StratoxTemplate, // Optional: will add form builder (se bellow)
    	helper: function() {
    	    // Pass on helper classes, functions and objects to your views
    	    return {
    		helper1: "Mixed data...",
                helper2: "Could be classes You want to",
                helper3: "Pass on to you components",
    	    };
    	}
    }
});
```

**directory:** Directory path for auto loaded asynchronously or imported templates. Either specify an absolute directory path or if opting for a relative path, **but** keep in mind it starts from the Stratox.js file location meaning if you bundle your files the relative location **will change** to where the bundle file is located at.

**cache:** Automatically clear cache if is false on dynamic import.

**handlers.fields:** Create a custom class handler for creating or modifying form field items, including default fields. The form field handler must extend the "StratoxBuilder" class, which is located in "node\_modules/stratox/src/StratoxBuilder.js". You can also create a new class (or copy the StratoxTemplate.js file) and extend your new class to StratoxTemplate if you want to add default fields or StratoxBuilder if you want to start fresh. Then just create your own form fields in your class. Read more under "Form builder" section.

**handler.helper:** Pass on helper classes, functions and objects to your views. If you are using a DOM traversal enginge then you could pass it on to the helper that in turn passes it on to your components, views and fields.


# Basic example

This is only a quick and basic example to showcase the Stratox template engine. In the next section, I will go in-depth on how it really works.

**I assume that you have read the installation section and that you have initialized and configured Startox.**

### Create component view

Create a template file named "ingress.js" and add the code below.

```javascript
export default function ingressComponent({ props })
{
    return `
    <header class="mb-50 align-center">
        <h1>${props.headline}</h1>
        <p>${props.content}</p>
    </header>
    `;
}
```

### Show component view

I will break down and explain the example in the next page.

```javascript
import ingressComponent from './path/to/ingress.js';

const stratox = new Stratox("#app");

stratox.view(ingressComponent, {
  headline: "Lorem ipsum dolor",
  content: "Lorem ipsum dolor sit amet"
});

stratox.execute();
```

### The result

{% embed url="<https://codepen.io/wazabii8/pen/bGZgPNo>" %}

Let's move on to the next section, where I will go in-depth on how it really works.


# Show views

Stratox.js offers remarkable flexibility. You can use the same component view multiple times in various locations and with varying content.

### How it works

#### 1. Import

Let's start with importing a template view/component. I will begin with the easiest one: the ingress component.

```javascript
import StratoxIngress from './path/to/view/StratoxIngress';
```

#### 2. Initialize instance

Create a class instance and pass a DOM element where you wish to show your template.

```javascript
const stratox = new Stratox("#app");
```

#### 3. Add view

Now, add the view to the class instance and pass in the expected content object data to the view.

```javascript
stratox.view(StratoxIngress, {
  headline: "Lorem ipsum dolor",
  content: "Lorem ipsum dolor sit amet",
});
```

#### 5. Execute

Execute and display the views/components in the expected DOM element.

```javascript
stratox.execute();
```

#### 5. The HTML

The HTML really just need a starting point but that depends completely on your need, building a app or enhancing a regular page.

```html
<html>
  <head>
    <title>Example</title>
    <meta charset="UTF-8" />
  </head>
  <body>
      <div id="app"></div>
  </body>
</html>
```

#### 6. The result

{% embed url="<https://codepen.io/wazabii8/pen/bGZgPNo>" %}

### Combining multiple views

You can combine multiple views, both the same and different, in the same instance. Let's build upon the above example and add the ingress twice, combining them with a new table view:

```javascript
import StratoxIngress from './path/to/view/StratoxIngress';
import StratoxTable from './path/to/view/StratoxTable';

let stratox = new Stratox("#app");

// Add Ingress view: Welcome message
stratox.view(StratoxIngress, {
  headline: "Lorem ipsum dolor",
  content: "Lorem ipsum dolor sit amet"
});

// Add table view A
stratox.view({ tbViewA: StratoxTable }, {
  feed: [
    {
      firstname: "John",
      lastname: "Doe",
      email: "john@gmail.com",
      status: "1",
    },
    {
      firstname: "Fredrik",
      lastname: "Doe",
      email: "fredrik@gmail.com",
      status: "0",
    },
    {
      firstname: "Dave",
      lastname: "Doe",
      email: "dave@gmail.com",
      status: "1",
    },
  ]
});

// Add table view B
stratox.view({ tbViewB: StratoxTable }, {
  feed: [
    {
      firstname: "Jane",
      lastname: "Doe",
      email: "jane@gmail.com",
      status: "1",
    },
    {
      firstname: "Sophia",
      lastname: "Doe",
      email: "sophia@gmail.com",
      status: "0",
    },
    {
      firstname: "Ava",
      lastname: "Doe",
      email: "ava@gmail.com",
      status: "1",
    },
  ]
});

stratox.execute();
```

### Quick create and set component

Can also quick create and set component in one. The setComponent, argument 2 will also take a anonymous function like demonstrated below.

```javascript

const stratox = new Stratox("#app");

stratox.view(({ props }) => `
    <header class="mb-50 align-center">
        <h1>${props.headline}</h1>
        <p>${props.content}</p>
    </header>
`, {
  headline: "Lorem ipsum dolor",
  content: "Lorem ipsum dolor sit amet"
});

stratox.execute();
```

Now let's move on and take a look on how you can build custom templates.


# Create views

It´s super easy to create template views and components and further more add your own custom functionality to them.

**I don't skip sections of the guide. Please keep in mind that the guide is designed to be read linearly, so try to avoid jumping through it on the first read through.**

### Create template

You can easily create your own templates if you know some HTML and JavaScript. I will show you a couple of templates below to get you started.

Create a template file named "ingress.js" and add the boilerplate code below to it.

```javascript
export default function ingressComponent({ 
    props, update, view, context, services, helper 
}) {
    return `
    <header class="mb-50 align-center">
        <h1>${props.headline}</h1>
        <p>${props.content}</p>
    </header>
    `;
}
```

Let's start breaking down the example above. First of all, you will need to create a function that is exported. You can name it whatever you want. The function can utilize four arguments, which I have named: **data, container, helper** and **builder**.

#### The function arguments

* **props:** This is the object data passed to your template file.
* **view:** The main Stratox view instance.
* **update:** can be used to update view, e.g. `update({ headline: "Headline has been updated!" });`
* **context:** Access the Stratox builder library (you can manage without, only for advanced users; more on this later on).
* **services:** The services container where you can add services and communicate with your nested partial views.
* **helper:** Your own possible helper libraries, objects, and functions you passed in the configuration.

#### The content

What you place inside the function (component) doesn't actually matter much. Most of the time, you would probably want to create some kind of view, as I have done above. However, you can place function withing the function to which is a recommended way to organize a more advanced component view. You could also for example use it to create a component that will trigger some kind of function. The only thing that sets the boundaries is your creativity. I will show you a little more advance template bellow.

#### The Return

It is not required to return an output, but if you do, it is expected to return a string value that will automatically be appended to a DOM element if you have specified an element in the Stratox class initialization. If you do not return a value, then your component could handle the appending to DOM part, for example, dynamically append Modals and so on.

### Show the template

Now we only need to use the template, as we already discussed on the previous page. It is not harder than this:

```javascript
import ingressComponent from './path/to/ingressComponent';

let stratox = new Stratox("#app");

stratox.view(ingressComponent", {
  headline: "Lorem ipsum dolor",
  content: "Lorem ipsum dolor sit amet"
});

stratox.execute();
```

#### The result:

{% embed url="<https://codepen.io/wazabii8/pen/bGZgPNo>" %}


# Updating views

You can update views inside of a component and outside.

### Update view 1

Below, I will show you some ways you can update view content outside of the view.

```javascript
let stratox = new Stratox("#app");

const itemA = stratox.view("ingress#itemA", {
    headline: "Lorem ipsum dolor 1",
    content: "Lorem ipsum dolor sit amet",
});

const itemB = stratox.view("ingress#itemB", {
    headline: "Lorem ipsum dolor 2",
    content: "Lorem ipsum dolor sit amet",
});

stratox.execute();

const myBtn = document.getElementById("update-headline-btn");
myBtn.addEventListener("click", function (e) {
    e.preventDefault();
    itemA.set({ headline: "Headline 1 been updated!" }).update();
    itemB.set({ headline: "Headline 2 been updated!" }).update();
});
```

#### Result:

{% embed url="<https://codepen.io/wazabii8/pen/gOEgNrW>" %}

#### Update example 1

The above example is utilizing the components item variable to tell Stratox which component you want to update, e.g.:

```javascript
itemA.set({ headline: "Headline 1 been updated!" }).update();
```

There are tho 2 other ways you can also update the component with.

#### Update example 2

Utilize the view component setter again, but with updated values, and trigger the `stratox.update()` function to push changes to the view.

```javascript
stratox.view("ingress", { headline: "Headline been twice!" });
stratox.update();
```

#### Update example 3

Utilize the `stratox.update()` function and set argument 1 to the expected component name and argument 2 to an anonymous function. The anonymous function, in turn, has one expected object argument where you can access the component's data and modify it.

```javascript
stratox.update("ingress", function(obj) {
    obj.data.headline = "Headline updated thrice!";
});
```

### Update view 2

Below, I will show you some ways you can update view content **inside** of the view.

```javascript
export function custom({ props, view })
{
    // Use the bind function to bind the event to click
    const myClickEvent = view.bind((props) => {
        props.headline = 'Headline has been updated!';
    });
    
    /*
    // Manually trigger update
    const myClickEvent = view.bind((props) => {
        props.headline = 'Headline has been updated!';
        view.update();
    }, false);
    */

    return `
    <article>
        <section class="mb-30">
            <h2 class="title">${props.headline}</h2>
            <p>${props.content}</p>
        </section>
        <a class="button" href="#" onclick="${myClickEvent}">Update headline</a>
    <article>
    `;

    return out;
}
```

#### Result:

{% embed url="<https://codepen.io/wazabii8/pen/OJqgLWY>" %}

And that is that. Let's move on on how you can build to some forms


# Plugins

As I have already mentioned in the first chapters you can install some plugins/pre-made components (ingress, table, and modals), more will certainly come.

As I have already mention previous in the guide that you can install some components that I have already made. Currently, there are only three (ingress, table, and modals), but more will certainly come and I will list them here, at this section of the guide.&#x20;

### Install Startox views/components

```
npm i stratoxcomponents
```

*Every plugin component below you are able to build yourself, and I do recommend that if you're interested, at least take a look at how they are built by navigating to the "./node\_modules/stratoxcomponents/src/" directory and inspecting every component there.*

### Ingress

Add a simple ingress component.

```javascript
import { StratoxIngress } from './node_modules/stratoxcomponents/src/StratoxIngress.js';

Stratox.setComponent("ingress", StratoxIngress);

const stratox = new Stratox("#app");

stratox.view("ingress", {
  headline: "Lorem ipsum dolor",
  content: "Lorem ipsum dolor sit amet",
});

stratox.execute();
```

#### Result:

{% embed url="<https://codepen.io/wazabii8/pen/bGZgPNo>" %}

### Table

Add a sortable table component.

```javascript
import { StratoxTable } from './node_modules/stratoxcomponents/src/StratoxTable.js';

Stratox.setComponent("table", StratoxTable);

const stratox = new Stratox("#app");

stratox.view("table", {
  feed: [
    {
      firstname: "John",
      lastname: "Doe",
      email: "john@gmail.com",
      status: "1",
    },
    {
      firstname: "Jane",
      lastname: "Doe",
      email: "jane@gmail.com",
      status: "0",
    },
    {
      firstname: "Dave",
      lastname: "Doe",
      email: "dave@gmail.com",
      status: "1",
    },
  ],
  thead: [{ firstname: "Name" }, { email: "Email" }, { status: "Status" }],
  tbody: [
    "{{firstname}} {{lastname}}",
    '<a href="mailto:{{email}}">{{email}}</a>',
    "{{status}}",
  ],
});

stratox.execute();
```

#### Result:

{% embed url="<https://codepen.io/wazabii8/pen/Babpgzw>" %}

### Modals

Bellow I will show 5 different modal components.

```javascript
import { StratoxModal } from './node_modules/stratoxcomponents/src/StratoxModal.js';
import { StratoxIngress } from './node_modules/stratoxcomponents/src/StratoxIngress.js';

Stratox.setComponent("modal", StratoxModal);
Stratox.setComponent("ingress", StratoxIngress);

// Show message modal on click
const myBtnMessage = document.getElementById("message-btn");
myBtnMessage.addEventListener("click", function (e) {
    e.preventDefault();

    Stratox.create("modal", {
        headline: "Lorem ipsum dolor",
        content: "Lorem ipsum dolor sit amet"
    });
});


// Show Confirm modal on click
const myBtnConfirm = document.getElementById("confirm-btn");
myBtnConfirm.addEventListener("click", function (e) {
    e.preventDefault();
  
    Stratox.create("modal", {
        type: "confirm",
        headline: "Lorem ipsum dolor",
        content: "Lorem ipsum dolor sit amet"
    }).container().set("confirm", function () {
        // Callback, modal has been confirmed
        alert("Confirmed..");
    });
});

// Show OK modal on click
const myBtnOk = document.getElementById("ok-btn");
myBtnOk.addEventListener("click", function (e) {
    e.preventDefault();

    Stratox.create("modal", {
        type: "ok",
        headline: "Lorem ipsum dolor",
        content: "Lorem ipsum dolor sit amet"
    }).container().set("confirm", function () {
        // Callback, modal has been confirmed
        alert("Confirmed..");
    });
});

// Show opener modal on click
const myBtnOpener = document.getElementById("opener-btn");
myBtnOpener.addEventListener("click", function (e) {
    e.preventDefault();

    Stratox.create("modal", {
        type: "opener",
        headline: "Lorem ipsum dolor",
        content: "Lorem ipsum dolor sit amet"
    });
});

// Show Custom modal on click.
// It is SUPER EASY to add custom content to Modal by adding
// your own compoents to the modal to customize.
const myBtnOpenerCustom = document.getElementById("custom-btn");
myBtnOpenerCustom.addEventListener("click", function (e) {
    e.preventDefault();

    let stratox = new Stratox();
    const modal = stratox.view("modal", {
        type: "opener",
    });

    const ingressA = stratox.view("ingress#ingressA", {
        headline: "Lorem ipsum dolor",
        content: "Lorem ipsum dolor sit amet",
    });

    const ingressB = stratox.view("ingress#ingressB", {
        headline: "Lorem ipsum dolor",
        content: "Lorem ipsum dolor sit amet",
    });

    stratox.execute();
});
```

#### Result:

{% embed url="<https://codepen.io/wazabii8/pen/bGZgPwa>" %}

More component will come in the future.


# Form builder

Create dynamic, responsive, and engaging web forms with ease.

To be able to use the form builder, you will need to specify a form fields template file in your config.

```javascript
import { Stratox } from './node_modules/stratox/src/Stratox.js';
import { StratoxTemplate } from './node_modules/stratox/src/StratoxTemplate.js';

Stratox.setConfigs({
  handlers: {
    fields: StratoxTemplate,
  }
});
```

*Once a instance of StratoxTemplate has been added to the handlers.fields config object you will be able to use the form builder.*

### Available form fields

Available form fields out of the box:

* text (password, tel, email, number... and so on)
* textarea
* date
* datetime
* hidden
* select
* radio
* checkbox
* submit (button)
* group
* views/componets

**And can be combined** with all views and components the you have created!

### Form field settings

Available form fields out of the box. Se working examples bellow.

```javascript
let form = new Stratox('#form');
form.form('theFieldName')
	.setType('checkbox') // Default is "text"
	.setLabel('Label')
	.setDescription('Add field description')
	.setAttr({ type: "email", id: "inp-email" }) // Create or overwrite html attributes
	.setConfig({ pass: "configs" }) // Pass configs
	.setItems({ yes: "Yes", no: "No" }) // Add (checkbox, radio or select list items)
	.setFields({ ... }) // Group fields, see example bellow
	.setValue("Field value");
```

### Example 1

Begin by adding an element to the HTML document. This is where the template will be loaded.

#### HTML:

```javascript

<div id="app"></div>

```

#### Javascript:

```javascript

let form = new Stratox('#app');
form.form('name').setLabel('Name').setValue("Jane doe");
form.form('email').setLabel('Email').setAttr({ type: "email", id: "inp-email" });
form.form('message').setType('textarea').setLabel('Message');
form.execute();

```

#### The result

{% embed url="<https://codepen.io/wazabii8/pen/gOEWBdY>" %}

### Combine template and form

As long as you are using the same instance then you can combine templates with outher template and template with forms.

Lets add our form to the ingress example in prevous page (Views).

#### HTML:

```javascript

<div id="app"></div>

```

#### JavaScript:

```javascript
let form = new Stratox('#app');

form.view("ingress", {
    headline: "Lorem ipsum dolor",
    content: "Lorem ipsum dolor sit amet"
});

form.form('name').setLabel('Name').setValue("Jane doe");
form.form('email').setLabel('Email').setAttr({ type: "email", id: "inp-email" });
form.form('message').setType('textarea').setLabel('Message');
form.execute();
```

#### The result

{% embed url="<https://codepen.io/wazabii8/pen/xxBdymJ>" %}

#### Group form fields

You can even group form fields and components. I will use the ingress as a example again. You can download the CSS class here form my repeat fields:

[repeat-fields.css](https://wazabii.se/stratoxjs/repeat-fields.css)

#### HTML:

```javascript

<div id="app"></div>

```

#### JavaScript:

```javascript
let form = new Stratox("#app");

form.view("ingress", {
    headline: "Advanced forms",
    content: "Lorem ipsum dolor sit amet"
});

form.form('name').setLabel('Name');
form.form('email').setLabel('Email');
form.form('message').setType('textarea').setLabel('Message');

form.form("customField", { type: "group" })
.setFields({
	// To add component in form you just specify the type and data!
	ingress: {
		type: "ingress",
		data: {
		    headline: "Repeatable fields",
		    content: "Even here can i combine the ingress component!"
		}
	},
	// Add form fields with json
	title: {
		type: "text",
		label: "Title"
	},
	description: {
		type: "textarea",
		label: "Description"
	}
})
.setConfig({
	nestedNames: true, // This will nest the form name automatically
	controls: true // Auto add controls (add and delete fields)
})

// You can also set the values of all fields like this 
// (typically passed from a database).
form.setValues({ name: "John Doe", email: "john.doe@gmail.com" });

form.execute();
```

* **nestedNames**:True: This will nest the form name automatically e.g:\
  (customField\[0]\[title], customField\[1]\[title])False: This will not transform the form fields name eg:\
  title, title
* **controls**: Auto add controls (add and delete fields)

#### The result

{% embed url="<https://codepen.io/wazabii8/pen/PoLmyvq>" %}


# Custom form template

Create a custom form template

### Create form template file

The new form field template class needs to extend to StratoxTemplate.

```javascript
import { StratoxTemplate } from '../node_modules/stratox/src/StratoxTemplate.js';

export class FormTemplateFields extends StratoxTemplate {
    
    /**
     * Regular input field
     * @return {string}
     */
    text() {
        let inst = this;
        return this.container(function() {
            return inst.input();
        });
    }

    /**
     * Regular input field
     * @return {string}
     */
    text(arg) {
        let inst = this;
        return this.container(function() {
            return inst.input();
        });
    }

    /**
     * Password input field
     * @return {string}
     */
    password() {
        let inst = this;
        return this.container(function() {
            let out =  inst.input({ type: "password" });
            return out;
        });
    }

    /**
     * Date input field
     * @return {string}
     */
    date() {
        let inst = this;
        return this.container(function() {
            return inst.input({ type: "date" });
        });
    }

    /**
     * Date time input field
     * @return {string}
     */
    datetime() {
        let inst = this;
        return this.container(function() {
            return inst.input({ type: "datetime-local" });
        });
    }

    /**
     * Hidden input field
     * @return {string}
     */
    hidden() {
        let inst = this;
        return inst.input({ type: "hidden" });
    }

    /**
     * Textarea field
     * @return {string}
     */
    textarea() {
        let inst = this, attr = this.getAttr({
            name: this.name,
            "data-index": this.index
        });
        
        return this.container(function() {
            return '<textarea'+attr+'>'+inst.value+'</textarea>';
        }); 
    }
    
    /**
     * Select field
     * @return {string}
     */
    select() {
        let inst = this, attrName = ((this.attr && this.attr.multiple) ? this.name+"[]" : this.name), 
        attr = this.getAttr({
            name: attrName,
            "data-index": this.index
        });

        return this.container(function() {
            let out = '<select'+attr+' autocomplete="off">';
            if(typeof inst.data.items === "object") {
                for(const [value, name] of Object.entries(inst.data.items)) {
                    let selected  = (inst.isChecked(value))  ? ' selected="selected"' : "";
                    out += '<option value="'+value+'"'+selected+'>'+name+'</option>';
                }
            } else {
                console.warn("Object items parameter is missing.");
            }
            out += '</select>';
            return out;
        });
    }

    /**
     * Radio input field
     * @return {string}
     */
    radio() {
        let inst = this, attr = this.getAttr({
            type: "radio",
            name: this.name,
            "data-index": this.index
        });

        return this.container(function() {
            let out = '';
            if(typeof inst.data.items === "object") {
                for(const [value, name] of Object.entries(inst.data.items)) {
                    let checked  = (inst.isChecked(value))  ? ' checked="checked"' : "";
                    out += '<label class="radio item small"><input'+attr+' value="'+value+'"'+checked+'><span class="title">'+name+'</span></label>';
                }
            } else {
                console.warn("Object items parameter is missing.");
            }
            return out;
        });
    }

    /**
     * Checkbox input field
     * @return {string}
     */
    checkbox() {
        let inst = this, length = Object.keys(inst.data.items).length, attr = this.getAttr({
            type: "checkbox",
            name: ((length > 1) ? this.name+"[]" : this.name),
            "data-index": this.index
        });

        return this.container(function() {
            let out = '';
            if(typeof inst.data.items === "object") {
                for(const [value, name] of Object.entries(inst.data.items)) {
                    let checked  = (inst.isChecked(value))  ? ' checked="checked"' : "";
                    out += '<label class="checkbox item small"><input'+attr+' value="'+value+'"'+checked+'><span class="title">'+name+'</span></label>';
                }
            } else {
                console.warn("Object items parameter is missing.");
            }
            return out;
        });
    }

}
```

### Break down

To make a quick breakdown of the above: the functions `container` , `input` and `getAttr` are  helper function, to make it easier for you create an input container that also holds a field label and input, creating the input tag fields or generate HTML attributes. They are not required, and you could just write your own HTML code and return that string, and it will work.

But to make it easier for you to understand let's take a look on how the **textarea** is build:

```javascript
textarea() {
    let inst = this, attr = this.getAttr({
        name: this.name,
        "data-index": this.index
    });
    
    return this.container(function() {
        return '<textarea'+attr+'>'+inst.value+'</textarea>';
    }); 
}
```

#### Helper functions:&#x20;

Bellow is a list on helper functions that you can use in your form field template.

* **getAttr:** It will **merge** specified attributes in the form builder with **default** attributes above, which we will then just add to the **textarea**. It is recommended that you use this function, with at least the name attribute, as shown in the example.
* **container:** Will create input container that holds a label and description for your.
* **input:** Will create input tag fields or generate HTML attributes.
* **isChecked:** Will check if items like radio, checkboxes and select lists is active.
* **getFieldID:** Will get a unique identifier that you can use as a element ID. E.G. the container function will automatically do this for you.

#### Accessible objects:

Bellow is a list on object that you can use in your form field template.

* **label:** Will return the expected form field label
* **description:** Will return a form field description you can use if you want
* **attr:** Will return all expected form field attributes as object (recommended tho that you utilize getAttr function)
* **items:** Will return the expected form field items (radio, checkboxes, and list in select lists).
* **name:** Will return the expected form field attribute name
* **value:** Will return the expected form field value
* **config:** Will return the expected form field custom configs that is passable

### Initialize the new template

You can now tell Stratox which form template file which is expected in the configuration.

<pre class="language-javascript"><code class="lang-javascript"><strong>import { FormTemplateFields } from './src/FormTemplateFields.js';
</strong><strong>
</strong>Stratox.setConfigs({
    handlers: {
    	fields: FormTemplateFields
    }
});
<strong>
</strong></code></pre>

Done you can now use your own form template!


# Container

Stratox also comes with a specialized JavaScript container library designed for seamless communication between template views and the application. It allows for efficient data exchange.

### Access container

A new container instance will be binded to each Stratox class instance. You can then access the container instance both inside a component and outside of it.

#### 1. Inside component

```javascript
export function custom({ services })
{
    if (services.has("fallback")) {
        services.get("fallback");
    }
    ...
```

#### 2. Outside of component

```javascript
const stratox = new Stratox("#ingress");
const serviceContainer = stratox.container();
```

### Container usage

Bellow is some quick example on different ways you can use the container.

```javascript
// Example 1
serviceContainer.set("someObject", { test: "Container 1" });

console.log(serviceContainer.get("someObject").test);
// Log response: Container 1

// Example 2
serviceContainer.set("passingAFunction", function(arg1, arg2) {
	alert(arg1+" "+arg2);
});

serviceContainer.get("passingAFunction", "Hello", "world!");
// Alert response: Hello world!
```

### Stand alone

You can also use the container in other projects.

```javascript
import { StratoxContainer } from 'stratox/StratoxContainer';
const container = new StratoxContainer();
```

### Method list

**Set a container or factory**

```
set(key, value, overwrite);
```

* **key:** Unique container key/string identifier
* **value:** Mixed value of whatever you want to share, e.g. String, number, object, function.&#x20;
* **overwrite:** Attempting to set a container multiple times will trigger a warning unless manual consent is provided by setting "overwrite" to true.

**Set factory only**

```
setFactory(key, value, overwrite);
```

* **key:** Unique factory key/string identifier&#x20;
* **value:** callable
* **overwrite:** Attempting to set a container multiple times will trigger a warning unless manual consent is provided by setting "overwrite" to true.

**Get a container or factory**

```
get(key, ...args);
```

* **key:** Unique container key/string identifier
* **args:** pass arguments to possible factory/function

**Check if container/factory exists**

```
has(key);
```

* **key:** Unique container key/string identifier

**Check if is strict a "container".**

```
isContainer(key);
```

* **key:** Unique container key/string identifier

**Check if is strict a "factory/function".**

```
isFactory(key);
```

* **key:** Unique factory key/string identifier


# Template view functions

Here will be an over view list over all template views that you can use.

**This guide is not complete and more will come.**

#### eventOnload

This will ensure that the script inside the `eventOnload` will execute after the component has been executed.

```javascript
this.eventOnload(() => {
    // Your code here
});
```

#### update

You can trigger `this.update` function inside a view to update the component views content.&#x20;

```javascript
this.update();
```

#### setElement

You can set a new or change the current expected **Main** element inside your template view.

```javascript
this.setElement("#your-element");
```


# Issues

For possible bugs and issues please contact me.

You can contact me at:

**Email:** <daniel.ronkainen@wazabii.se>


# Stratox router

Startox Pilot is a JavaScript router designed for ease of use and flexibility. It employs regular expressions to offer dynamic routing, allowing for both straightforward and complex navigation paths. As a universal library, it works across different platforms without needing any external dependencies. This independence makes Startox Pilot a practical option for developers in search of a dependable routing tool that combines advanced features and modular design in a compact package.

## A basic example

Below is a simple yet comprehensive example. Each component will be explored in further detail later in this guide.

```javascript
import { Router, Dispatcher } from '@stratox/pilot';

const router = new Router();
const dispatcher = new Dispatcher();

// GET: example.se/
router.get('/', function() {
    console.log("Start page");
});

// GET: example.se/#about 
// REGULAR URI paths (example.se/about) is of course also supported!
router.get('/about', function(vars, request, path) {
    const page = vars[0].pop();
    console.log(`The current page is: ${page}`);
});

// GET: example.se/#articles/824/hello-world
router.get('/articles/{id:[0-9]+}/{slug:[^/]+}', function(vars, request, path) {
    const id = vars.id.pop();
    const slug = vars.slug.pop();
    console.log(`Article post ID is: ${id} and post slug is: ${slug}.`);
});

// POST: example.se/#post/contact
router.post('/post/contact', function(vars, request, path) {
    console.log(`Contact form catched with post:`, request.post);
});

// Will catch 404 and 405 HTTP Status Errors codes
// Not required you can also handle it directly in the dispatcher
router.get('[STATUS_ERROR]', function(vars, request, path, statusCode) {
    if(statusCode === 404) {
        console.log("404 Page not found", statusCode);
    } else {
        console.log("405 Method not allowed", statusCode);
    }
});

dispatcher.dispatcher(router, dispatcher.serverParams("fragment"), function(response, statusCode) {
    // response.controller is equal to what the routers second argument is being fed with.
    // You can add Ajax here if you wish to trigger a ajax call.
    response.controller(response.vars, response.request, response.path, statusCode);
});
// URI HASH: dispatcher.serverParams("fragment") // Fragment is HASH without "#" character.
// URI PATH: dispatcher.serverParams("path") // Regular URI path
// SCRIPT PATH: dispatcher.request("path") // Will work without browser window.history support
```


# Installation

## Installation

```javascript
npm install @stratox/pilot
```

### Initialize

```javascript
import { Router, Dispatcher } from '@stratox/pilot';

const router = new Router();
const dispatcher = new Dispatcher();
```

## Configuration options

The dispatcher offers several configuration options to tailor its behavior to your application's needs.

```javascript
const dispatcher = new Dispatcher({
    catchForms: false, // Toggle form submission catching
    root: "", // Set a root directory
    fragmentPrefix: "" // Define a prefix for hash/fragment navigation
});
```

### Configuration Parameters

* **catchForms (bool):** When set to `true`, enables the dispatcher to automatically intercept and route form submissions. This feature facilitates seamless integration of form-based navigation within your application.
* **root (string):** This parameter allows you to specify a root directory using an **absolute path**. This setting is crucial for defining where simulated or "pretty" URI paths begin. The necessity of this configuration depends on your specific deployment environment.
* **fragmentPrefix (string):** This option lets you prepend a prefix to fragment or hash navigation calls. For instance, adding the "!" character means the URL's hash will be expected to appear as "#!your-hash", modifying the default behavior to accommodate specific routing schemes or to enhance compatibility with certain browsers or frameworks.

## Defining routes

In Stratox Pilot, there are two primary router types: `get` and `post`. Both types follow the same structural format, as illustrated below, with the key difference being that they will expect different request (see navigation for more information)

```
router.get(string pattern, mixed call);
router.post(string pattern, mixed call);
```

#### Arguments

* **pattern (string):** This parameter expects a URI path in the form of a string, which may include regular expressions for more complex matching criteria.
* **call (mixed):** This parameter can accept any data type, such as a callable, anonymous function, string, number, or boolean. However, it is most common to use a function. For the purposes of this guide, I use a regular callable function in my examples.


# Add routes

### A really Basic example

```javascript
// Possible path: #about
router.get('/about', function(vars, request, path) {
});
```

And you can of course **add multiple** paths.

```javascript
// Possible path: #about/contact
router.get('/about/contact', function(vars, request, path) {
});
```

### Using Regular Expressions

To incorporate regular expressions in routing patterns, enclose the expression within **curly brackets: `{PATTERN}`**. This syntax allows for flexible and powerful URL matching based on specified patterns.

```javascript
// Possible path: #about/location/stockholm
router.get('/about/location/{[a-z]+}', function(vars, request, path) {
});
```

### Binding Router Patterns to a Key

It is strongly advised to associate each URI path you wish to access with a specific **key**. This approach enhances the clarity and manageability of your route definitions.

```javascript
// Possible path: #about/location/stockholm
router.get('/{page:about}/location/{city:[^/]+}', function(vars, request, path) {
    //vars.page[0] is expected to be "about"
    //vars.city[0] is expected to be any string value (stockholm, denmark, new-york) from passed URI.
});
```

You can also map an entire path to a **key**, allowing for more concise and organized route management.

```javascript
// Possible path: #about/contact
router.get('/{page:about/location}', function(vars, request, path) {
    //vars.page[0] is expected to be "about"
    //vars.page[1] is expected to be "location"
});
```

### Combining pattern with keywords

Combining patterns with keywords e.g. (**post-**\[0-9]+) enables you to create more expressive and versatile route definitions.

```javascript
// Possible path: #articles/post-824/hello-world
router.get('/articles/{id:post-[0-9]+}/{slug:[^/]+}', function(vars, request, path) {
    //vars.id[0] is expected to be "post-824"
    //vars.slug[0] is expected to be "hello-world"
});
```

### Handling Unlimited Nested Paths

To accommodate an unlimited number of nested paths within your routing configuration, you can utilize the pattern `".+"`. However, it's strongly advised to precede such a router pattern with a specific prefix to maintain clarity and structure, as demonstrated in the example below with the prefix `/shop`.

```javascript
// Example of accessing a single category: #shop/furniture
// Example of accessing multiple nested categories: #shop/furniture/sofas/chesterfield
router.get('/shop/{category:.+}', function(vars, request, path) {
    // Retrieves the last category segment from the path
    const category = vars.category.pop();
    console.log(`The current category is: ${category}`);
});
```

This approach allows for the dynamic handling of deeply nested routes under a common parent path, offering flexibility in how URLs are structured and processed.

### Optional URI Paths

To define one or more optional URI paths, enclose the path segment (excluding the slash) in brackets followed by a question mark, for example: **/(PATH\_NAME)?**. This syntax allows for flexibility in route matching by making certain path segments non-mandatory.

```javascript
// Possible path: #articles
// Possible path: #articles/post-824/hello-world
router.get('/articles/({id:post-[0-9]+})?/({slug:[^/]+})?', function(vars, request, path) {
});
```

It's important to note that you should not enclose the **leading slash** in brackets. The leading slash is automatically excluded from the pattern, ensuring the correct interpretation of the route.

### Catch status errors

There is an optional and special router pattern that let's you catch HTTP Status Errors with in a router.

```javascript
router.get('[STATUS_ERROR]', function(vars, request, path, statusCode) {
    if(statusCode === 404) {
        console.log("404 Page not found", statusCode);
    } else {
        console.log("405 Method not allowed", statusCode);
    }
});
```


# Dispatcher

## Dispatcher overview

The dispatcher is essential for identifying and providing the appropriate route from the state handler. Designed for flexibility, it enables the incorporation of custom logic, such as AJAX, to tailor functionality to specific needs.

```javascript
dispatcher.dispatcher(Router routerCollection, serverParams, callable dispatch);
```

#### Arguments

* [**routerCollection**](#router-collection-routercollection)
* [**serverParams**](#server-params-serverparams)
* [**dispatch**](#dispatch-function-dispatch)

### Router Collection (routerCollection)

This expects a Router instance, allowing for customization. You can create your router collection extending the Router class, potentially adding more HTTP methods, structure, or functionality.

### Server Params (serverParams)

Server params indicate the URL segment the dispatcher should utilize. These params dynamically target the specified URI segment. Several built-in options include:

#### URI Fragment

Represents the URL hash or anchor minus the "#" character.

```javascript
dispatcher.serverParams("fragment");
```

#### URI Path

The regular URI path segment.

```javascript
dispatcher.serverParams("path");
```

#### Script Path

Ideal for non-browser environments, supporting backend applications, APIs, or shell command routes.

```javascript
dispatcher.request("path");
```

### Dispatch Function (dispatch)

The "dispatch" argument expects a callable function to process the match result, handling both successful (status code 200) and error outcomes (status code 404 for "page not found" and 405 for "Method not allowed"). The function receives two parameters: response (object) and statusCode (int).

#### Response Details

* **response (object):** Provides an object with vital response data.
* **statusCode (int):** Indicates the result, either successful (200) or error (404 or 405).

### Basic Dispatcher Example

Below is an excerpt from the example at the start of the guide:

```javascript
dispatcher.dispatcher(router, dispatcher.serverParams("fragment"), function(response, statusCode) {
    response.controller(response.vars, response.request, response.path, statusCode);
});
```

### Understanding the Response

The response structure, as illustrated with the router pattern `"/{page:product}/{id:[0-9]+}/{slug:[^/]+}"`, and URI path **/product/72/chesterfield** includes:

```json
{
    "verb": "GET",
    "status": 200,
    "path": ["product", "72", "chesterfield"],
    "vars": {
        "page": "product",
        "id": "72",
        "slug": "chesterfield"
    },
    "form": {},
    "request": {
        "get": "URLSearchParams",
        "post": {}
    }
}
```

* **verb:** The HTTP method (GET or POST).
* **status:** The HTTP status code (200, 404, or 405).
* **path:** The URI path as an array.
* **vars:** An object mapping path segments to keys.
* **form:** Captures submitted DOM form elements.
* **request.get:** An instance of URLSearchParams for GET requests.
* **request.post:** An object for POST requests.


# Navigation

## Navigation

The library provides intuitive navigation options to seamlessly transition between pages and initiate GET or POST requests.

### Page Navigation / GET Request

Initiating a GET request or navigating to a new page is straightforward. Such actions will correspond to a `get` router, with the request parameter converting into an instance of URLSearchParams for the request.

#### Arguments

* **path (string):** Specifies the URI, which can be a **regular path** or a **hash**.
* **request (object):** Sends a GET request or query string to the dispatcher. This will be transformed into an instance of [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams). When executed in a browser, the query string will also be appended to the URL in the address field.

#### Make get request

```javascript
// URI hash (fragment with hashtag) navigation
dispatcher.navigateTo("#articles/824/hello-world", { test: "A get request" });

// URI path navigation
// dispatcher.navigateTo("/articles/824/hello-world", { test: "A get request" });
```

#### The navigation result

The above navigation will trigger the result for the matching router:

```javascript
// GET: example.se/?test=A+get+request#articles/824/hello-world
router.get('/articles/{id:[0-9]+}/{slug:[^/]+}', function(vars, request, path) {
    const id = vars.id.pop();
    const slug = vars.slug.pop();
    const test = request.get.get("test"); // Get the query string/get request "test"
    console.log(`Article ID: ${id}, Slug: ${slug} and GET Request ${test}.`);
});
```

### POST Request

Creating a POST request is similarly efficient, targeting a `post` router. The request parameter will be an object to facilitate the request.

#### Arguments

* **path (string):** Defines the URI, which can be a **regular path** or a **hash**.
* **request (object):** Submits a POST request to the dispatcher. This will be an object, allowing for detailed and structured data transmission.

#### Make post request

```javascript
dispatcher.postTo("#post/contact", { firstname: "John", lastname: "Doe" });
```

#### The post request result

The above post will trigger the result for the matching router:

```javascript
// POST: example.se/#post/contact
router.post('/post/contact', function(vars, request, path) {
    const firstname = request.post.firstname;
    const lastname = request.post.lastname;
    console.log(`The post request, first name: ${firstname}, last name: ${lastname}`);
});
```


# Form submission

Stratox Pilot supports automatic form submission handling through routers, a feature that must be explicitly enabled in the Dispatcher's configuration.

### 1. Enable Form Submission

To allow automatic catching and routing of form submissions, enable the `catchForms` option in the Dispatcher configuration:

```javascript
const dispatcher = new Dispatcher({
    catchForms: true
});
```

### 2. Define Routes

Next, define the routes that will handle form submissions. For example, to handle a POST request:

```javascript
// POST: example.se/#post/contact
router.post('/post/contact', function(vars, request, path) {
    console.log('Contact form posted with form request:', request.post);
});
```

### 3. Implement Form Submission

Forms can use both GET and POST methods. Below is an example of a form designed to submit via POST:

```html
<form action="#post/contact" method="post">
    <div>
        <label>First name</label>
        <input type="text" name="firstname" value="">
    </div>
    <div>
        <label>Last name</label>
        <input type="text" name="lastname" value="">
    </div>
    <div>
        <label>E-mail</label>
        <input type="email" name="email" value="">
    </div>
    <input type="submit" name="submit" value="Send">
</form>
```

With these settings, the dispatcher will automatically capture and route submissions to the corresponding handler if a matching route is found.

## Have any questions

If there's anything unclear or you have further questions, feel free to reach out via email at <daniel.ronkainen@wazabii.se>.


