Skip to content
This repository has been archived by the owner on Dec 26, 2022. It is now read-only.

Commit

Permalink
Added LinkView for route linking
Browse files Browse the repository at this point in the history
  • Loading branch information
RiadhAdrani committed Dec 9, 2021
1 parent d276c08 commit 9aee00d
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 23 deletions.
4 changes: 2 additions & 2 deletions RecursiveDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import handleevents from "./vdom/tools/handleevents.js";

/**
* ## RecursiveDOM
* The heart of the Recursive library that play the role of the VDOM
* The Engine of the Recursive library that play the role of the VDOM
* (Virtual Document Object Model)
* and the CSSOM (Cascading Style Sheet Object Model).
* @global The VDOM will be injected automatically in the `window` object.
Expand Down Expand Up @@ -69,7 +69,7 @@ class RecursiveDOM {
}

/**
* Render the app
* Render the app for the first time.
*/
render() {
const startTime = new Date().getTime();
Expand Down
2 changes: 2 additions & 0 deletions createcomponent/Components.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ import FigureCaptionView from "./components/text/FigureCaptionView.js";
import DescriptionTermView from "./components/text/DescriptionTermView.js";
import DescriptionListView from "./components/text/DescriptionListView.js";
import DescriptionDetailsView from "./components/text/DescriptionDetailsView.js";
import LinkView from "./components/inlinetext/LinkView.js";

export {
LinkView as Link,
DescriptionDetailsView as Dd,
DescriptionListView as Dl,
DescriptionTermView as Dt,
Expand Down
56 changes: 41 additions & 15 deletions createcomponent/CreateComponent.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import RecursiveDOM from "../RecursiveDOM.js";

import applystylesheet from "./tools/applystyle/applystylesheet.js";

import keying from "./tools/keying.js";
Expand All @@ -7,6 +9,7 @@ import initclassname from "./tools/init/initclassname.js";
import initprops from "./tools/init/initprops.js";
import inithooks from "./tools/init/inithooks.js";
import initevents from "./tools/init/initevents.js";
import initflags from "./tools/init/initflags.js";

import renderattributes from "./tools/render/renderattributes.js";
import renderevents from "./tools/render/renderevents.js";
Expand All @@ -16,18 +19,21 @@ import updateattributes from "./tools/update/updateattributes.js";
import updatechildren from "./tools/update/updatechildren.js";
import updateevents from "./tools/update/updateevents.js";
import updatestyle from "./tools/update/updatestyle.js";
import initflags from "./tools/init/initflags.js";

import replaceindom from "./tools/update/_replaceindom.js";

/**
* ## CreateComponent
* Create Web Components for the RecursiveDOM.
* ### The modular unit to build a Recursive Web App.
* CreateComponent is a representation of an HTML element,
* it can update, destroy and update itself according the need of the developer.
* Children component can be injected too, which have the same abilities as their parent,
* and like that, the library got its name.
* @see {@link RecursiveDOM}
*/
class CreateComponent {
/**
* Initiate a new component
* Create a new component
* @param {Object} param
* @param {string} param.tag "Html tag"
* @param {Array} param.children an array of children. A child can be of type `CreateComponent`, `string`, `boolean`, `number`. `null` value will be ignored.
Expand All @@ -39,10 +45,7 @@ class CreateComponent {
* @param {JSON} param.props the equivalent of html attributes
* @param {JSON} param.hooks define lifecycle methods for the component.
* @param {JSON} param.flags define flags for component updating.
* @param {Function} param.hooks.onCreated executes when the component is rendered in the DOM.
* @param {Function} param.hooks.onUpdated executes when the component has been partially changed.
* @param {Function} param.hooks.onDestroyed executes when the component has been destroyed.
* @param {Function} param.hooks.beforeDestroyed executed before the component get destroyed.
* @param {Function} param.hooks define lifecycle methods.
*/
constructor({
tag,
Expand Down Expand Up @@ -106,6 +109,10 @@ class CreateComponent {
// this.keying();
}

/**
* Convert the Recursive representation into a DOM element.
* @returns {HTMLElement} DOM element.
*/
render() {
let render = document.createElement(this.tag);

Expand All @@ -118,13 +125,18 @@ class CreateComponent {
// inject children inside the rendered element
renderchildren(this.children, render);

render.key = this.key;
// render.key = this.key;

this.domInstance = render;

return render;
}

/**
* Compare the current component with another given one and update the `DOM` if needed.
* @param {CreateComponent | string} newComponent
* @returns {boolean} - indicates weather the component did change or not.
*/
update(newComponent) {
let didUpdate = false;

Expand All @@ -136,7 +148,6 @@ class CreateComponent {
}

// FLAGS

// flags.forceRerender
// Just rerender the component
if (this.flags.forceRerender === true) {
Expand Down Expand Up @@ -193,17 +204,26 @@ class CreateComponent {
return didUpdate;
}

// apply keys to elements
/**
* @deprecated
* assign a key to the current component, and its children.
*/
keying() {
keying(this);
}

// execute onUpdate lifecycle method
/**
* Allow the user to execute custom actions if the current component was just updated.
* @param {CreateComponent| string} oldComponent - current component
* @param {CreateComponent | string} newComponent - the new component
*/
$onUpdated(oldComponent, newComponent) {
if (this.onUpdated) this.onUpdated(oldComponent, newComponent);
}

// execute onCreated lifecycle methid
/**
* Allow the user to execute custom actions when the component has been created.
*/
$onCreated() {
if (this.hooks.onCreated) this.hooks.onCreated();

Expand All @@ -216,17 +236,23 @@ class CreateComponent {
}
}

// execute onDestroyed lifecycle method
/**
* Allow the user to execute custom actions when the component has been destroyed.
*/
$onDestroyed() {
if (this.hooks.onDestroyed) this.hooks.onDestroyed();
}

// execute beforedestroyed lifecycle method
/**
* Allow the user to execute custom actions just before the destruction of the component.
*/
$beforeDestroyed() {
if (this.hooks.beforeDestroyed) this.hooks.beforeDestroyed();
}

// add external style
/**
* Send the `styleSheet` object to the RecursiveDOM to be processed.
*/
addExternalStyle() {
applystylesheet(this);
}
Expand Down
36 changes: 36 additions & 0 deletions createcomponent/components/inlinetext/LinkView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import CreateComponent from "../../CreateComponent.js";

/**
* ## AnchorView `<a>`
* *from MDN Docs*
* ### The Anchor element
* The ``<a>`` HTML element (or anchor element), with its href attribute,
* creates a hyperlink to web pages, files, email addresses, locations in the same page,
* or anything else a URL can address.
* Content within each ``<a>`` should indicate the link's destination.
* If the href attribute is present, pressing the enter key while focused on the ``<a>`` element will activate it.
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a
*/
export default ({ children, style, styleSheet, to, id, className, events, hooks, flags }) =>
new CreateComponent({
tag: "a",
children: children,
inlineStyle: style,
props: {
id,
href: to,
},
className: className,
events: {
...events,
onClick: (e) => {
e.preventDefault();
if (router.goTo) {
router.goTo(to);
}
},
},
hooks,
style: styleSheet,
flags,
});
24 changes: 24 additions & 0 deletions router/Route.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
import CreateComponent from "../createcomponent/CreateComponent.js";
import Router from "./Router.js";

/**
* ## Route
* ### Define a directory in your App.
* @see {@link Router}
*/
export default class Route {
/**
* Create a `Route`
* @param {JSON} param props
* @param {string} param.name the name of the directory that will be appended to the url:
* should start with an `\`, and not end with it.
* Valid example: `\a-sample-route`.
* @param {CreateComponent | string} param.component the component representing the directory.
* @param {string} param.title the title of the tab.
* @param {Array} param.subRoutes an array of routes serving as sub-directories.
* @param {Function} param.onLoad method to be executed when the route load.
* @param {Function} param.onExit method to be executed when the route unload.
*/
constructor({ name, component, title, subRoutes, onLoad, onExit }) {
if (!/^\/([a-zA-Z0-9]|-|.|_|~){0,}(\/){0}$/gm.test(name.trim())) {
throw Error(`Invalid route name: ${name}`);
Expand All @@ -14,6 +34,10 @@ export default class Route {
this.onExit = onExit;
}

/**
* Flatten this route and its sub-Routes.
* @param {Array} output an Array that will host the routes.
*/
flatten(output) {
output?.push(this);

Expand Down
36 changes: 30 additions & 6 deletions router/Router.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import RecursiveDOM from "../RecursiveDOM.js";
import CreateComponent from "../createcomponent/CreateComponent.js";
import Route from "./Route.js";

/**
* ## Router
* ### Manage directories in your App.
* @see {@link RecursiveDOM}
* @see {@link Route}
*/
class Router {
/**
* Create a Router to manage App directories.
* @param {Route} routes Define the main route for the App.
*/
constructor(routes) {
this.routes = [];

Expand Down Expand Up @@ -35,6 +47,10 @@ class Router {
});
}

/**
* Create a `Route`
* @see {@link Route}
*/
static Route = ({
name,
component,
Expand All @@ -46,27 +62,35 @@ class Router {
return new Route({ name, title, component, subRoutes, onExit, onLoad });
};

// TODO
/**
* Add a temporary route.
* @not_implemented_yet
*/
addRoute() {
throw "Feature is not yet implemented";
}

/**
* Render the current route.
* @returns {CreateComponent} the representing component element.
*/
render() {
return this.current.component();
}

/**
* Redirect the App to the route with the given name.
* @param {string} name Route exact name.
*/
goTo(name) {
this.routes.forEach((r) => {
if (name === r.name && name !== this.current.name) {
history.pushState({}, this.current.title, `${name}`);
this.stack.push(this.current);
this.current?.onExit();
this.current = r;
if (r.title) {
const titleTag = document.getElementsByTagName("title");
if (titleTag[0]) {
titleTag[0].innerHTML = r.title;
}
if (this.current.title) {
document.title = this.current.title;
}
vDOM.update();

Expand Down

0 comments on commit 9aee00d

Please sign in to comment.