Skip to content

Commit

Permalink
[GIT] Initial commit for Frontend-Assets.
Browse files Browse the repository at this point in the history
  • Loading branch information
M001S committed Feb 14, 2021
0 parents commit cb290d8
Show file tree
Hide file tree
Showing 31 changed files with 552 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
js/App/*
!js/App/Project.js
49 changes: 49 additions & 0 deletions assets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Frontend-Assets

Pure vanilla ES6 import/export JavaScript. No frontend framework. No jQuery.
Recommended to read [this tutorial by DigitalOcean](https://www.digitalocean.com/community/tutorials/js-modules-es6) to understand how ES6 and import/export are working!

##### Frontend Frameworks
Frameworks like Vue.js or React-Native are nice, but those heavily depends on the project type you are writing. A new Laravel would fit perfectly into Vue.js frontend as an engine. React to write the perfect hybrid app for Android and iOS at the same time which share the same code. But what for a TYPO3 where the frontend engine can't be rendered by Vue.js as it's made to use their own (Fluid-)Template engine.

##### ES6 as benefit to write OOP JavaScript code:
Since "old" programmers - or those who simply copy&paste and coming up with the argument while using jQuery telling you "it's working" or like "how it always has been done" are those who aren't spending their own time into development.
Anyone in your company or yourself as a single-person programming would definitely benefit from the Frontend-Assets since it's designed as OOP. Obviously it's highly inspired by PHP PSR (PHP Standard Recommendations) where the Symfony application has the perfect packages done e.g. the PSR-11 Container - where in our JavaScript Frontend-Assets it's fetchable by calling:
```js
const App = Application || window.Application;
App.getContainer();
```
This contains all references to created instances which has been done using:
```js
import LoadEvent from './../Event/DOM/LoadEvent';
...
App.add('DOMLoadEvent', new LoadEvent(this));
```
This is a living-example right inside of the `Container.js` class.
#
#### When to use Frontend-Assets
As mentioned before it depends on the type of the project. It's recommended to use it only if:
- You're not writing a Vue.js application
- You're not using react(-native)
- You're on the web (obviously)
- You into OOP and good code-quality 😁
#
### Installation & Extend Frontend-Assets

```sh
git clone https://github.com/iammati/frontend-assets
```

The entire setup is written in Laravel Mix - which uses WebPack - alternatively you can change it to a pure WebPack setup, but it was easier to use Mix since it has no big config js-file as WebPack by default has.

In order to properly extend the Frontend-Assets - which comes with some predefined handy scripts - you can simply look into `assets/js/Project.js` and `assets/js/App/Project.js`.

The former gets `require()`'d inside `assets/js/Application.js`. It predefines e.g. the `const Application` to be accessible inside of your custom project `.js`-files.
The latter is then your actual "main" `.js`-file. Here you can change what happens the first, as second, as third etc. When to do this and that. Anything.
#
### Support
**Frontend-Assets** officially supports only all modern browser based on chromium. Since the Microsoft Edge browser is ending their support on 9th March 2021 while the Internet Explorer will end on August 17th, 2021 there's no reason to support those two browsers at all. The new Edge browser is running on Chromium - which is anyways the standard and state-of-the-arts for now.
#
### License
MIT
Feel free to clone, change the source, re-publish the **Frontend-Assets**. Please only provide a copyright to the source code with a reference to the [origin GitHub repository](https://github.com/iammati/frontend-assets/).
8 changes: 8 additions & 0 deletions assets/js/App/Listener/LoadListener.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Application.getContainer().getInstanceByIdentifier('LoadEvent').addListener(
(...args) => {
// The event itself
const e = args[0];

console.log('LOAD LISTENER BROOOO');
}
);
39 changes: 39 additions & 0 deletions assets/js/App/Listener/ResizeListener.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Application.getContainer().getInstanceByIdentifier('ResizeEvent').addListener(
(...args) => {
// The event itself
const e = args[0];

// Additional Data
const additionalData = args[1];
const width = additionalData['width'];

let __breakpoint = 'xs';

// Read here more about the difference of the 0.02px-gap to the full rounded actual Breakpoints
// https://stackoverflow.com/a/51567792/12100192

if (width >= 575.98) {
__breakpoint = 'sm';
}

if (width >= 767.98) {
__breakpoint = 'md';
}

if (width >= 991.98) {
__breakpoint = 'lg';
}

if (width >= 1199.98) {
__breakpoint = 'xl';
}

if (width >= 1399.98) {
__breakpoint = 'xxl';
}

Application.getVariablesProvider().set('Breakpoint', __breakpoint);

Breakpoint = __breakpoint;
}
);
2 changes: 2 additions & 0 deletions assets/js/App/Project.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require('./Shortcuts');
require('./Listener/ResizeListener');
1 change: 1 addition & 0 deletions assets/js/App/Shortcuts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const Breakpoint = Application.getVariablesProvider().get('Breakpoint');
16 changes: 16 additions & 0 deletions assets/js/Application.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
window.BOOTTIME_START = performance.now();

import Bootstrap from './Bootstrap';
import MiddlewareConfig from './Config/MiddlewareConfig';

new Bootstrap(
MiddlewareConfig()
);

window.BOOTTIME_END = performance.now();

window.MEASURED_TIME = (Math.round(((window.BOOTTIME_END - window.BOOTTIME_START) + Number.EPSILON) * 100) / 100) + 'ms';
console.log(window.MEASURED_TIME);

const Application = window.Application;
require('./Project');
36 changes: 36 additions & 0 deletions assets/js/Bootstrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Container from './Core/Container.js';
import VariablesProvider from './Provider/VariablesProvider.js';
import PageRenderer from './Renderer/PageRenderer.js';

export default class Bootstrap {
constructor (MiddlewareConfig) {
// Instancing and setting the global namespace Application inside the window object.
window.Application = new class Application {
constructor () {
this.container = new Container(this, MiddlewareConfig);

// Runs the Middleware-Stacks
this.getContainer().getInstanceByIdentifier('MiddlewareInstance').go(
{
// default data any middleware has
},

hook => {
// hook represents the object above with the default-comment
// console.log(hook);
}
);

// Variables
this.variablesProvider = new VariablesProvider();

// Renderers
this.page = new PageRenderer();
}

getContainer = () => this.container;

getVariablesProvider = () => this.variablesProvider;
}();
}
}
22 changes: 22 additions & 0 deletions assets/js/Config/MiddlewareConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import AjaxMiddleware from './../Middleware/AjaxMiddleware';
import QueryParametersMiddleware from './../Middleware/QueryParametersMiddleware';

export default function MiddlewareConfig() {
return {
config: {
usePriorities: true
},

middlewares: [
{
instance: new QueryParametersMiddleware,
priority: 1
},

{
instance: new AjaxMiddleware,
priority: 2
}
]
};
};
58 changes: 58 additions & 0 deletions assets/js/Core/Container.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import Middleware from './Middleware';

import LoadEvent from './../Event/DOM/LoadEvent';

export default class Container {
constructor (Application, MiddlewareConfig) {
if (typeof window.Container != 'undefined') {
return window.Container;
}

// Container Instances
this.instances = {};

// Middlewares - Iterating through the stacks and calling each middleware
const MiddlewareInstance = new Middleware();

MiddlewareConfig.middlewares.forEach(middleware => {
MiddlewareInstance.use((hook, next) => {
middleware.instance.call(hook, next);
});
});

this.add('MiddlewareInstance', MiddlewareInstance);

// Event-Registrations
this.add('DOMLoadEvent', new LoadEvent(this));

window.Container = {
instances: this.instances
};
}

getInstanceByIdentifier = identifier => this.instances[identifier];

add = (identifier, instance) => {
if (typeof this.instances[identifier] != 'undefined') {
if (this.instances[identifier] == instance) {
return this.instances[identifier];
}

return console.error(
'Container -> The identifier "' +
identifier +
'" has already registered for the instance: "' +
this.instances[identifier] +
'"'
);
}

this.instances[identifier] = instance;

window.Container = {
instances: this.instances
};

return instance;
}
}
31 changes: 31 additions & 0 deletions assets/js/Core/Middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export default class Middleware {
constructor () {
// Array prototype last
if (!Array.prototype.last) {
Array.prototype.last = function () {
return this[this.length - 1];
}
}

// Array prototype reduceOneRight
if (!Array.prototype.reduceOneRight) {
Array.prototype.reduceOneRight = function () {
return this.slice(0, -1);
}
}
}

use(fn) {
this.go = ((stack) => (...args) => stack(...args.reduceOneRight(), () => {
let _next = args.last();
fn.apply(this, [...args.reduceOneRight(), _next.bind.apply(_next, [null, ...args.reduceOneRight()])]);
}))(this.go);

return this;
}

go(...args) {
let _next = args.last();
_next.apply(this, args.reduceOneRight());
}
}
11 changes: 11 additions & 0 deletions assets/js/Event/AbstractEvent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default class AbstractEvent {
constructor () {
this.listeners = [];
}

addListener = fn => this.listeners.push(fn);

getListeners = () => this.listeners;

exec = (...args) => this.listeners.forEach(listener => listener(...args));
}
17 changes: 17 additions & 0 deletions assets/js/Event/DOM/LoadEvent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import ResizeEvent from '../Window/ResizeEvent';
import AbstractEvent from './../AbstractEvent';

export default class LoadEvent extends AbstractEvent {
constructor (Container) {
super();

window.addEventListener('load', e => {
const width = document.body.clientWidth;
Application.getVariablesProvider().set('Width', width);

this.exec(e);
});

Container.add('ResizeEvent', new ResizeEvent(Container));
}
}
17 changes: 17 additions & 0 deletions assets/js/Event/Window/ResizeEvent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import AbstractEvent from '../AbstractEvent';

export default class ResizeEvent extends AbstractEvent {
constructor () {
super();

window.addEventListener('resize', e => {
const width = document.body.clientWidth;

Application.getVariablesProvider().set('Width', width);

this.exec(e, {
width: width
});
});
}
}
7 changes: 7 additions & 0 deletions assets/js/Listener/AbstractListener.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default class AbstractListener {
constructor () {
this.listeners = [];
}

listener = e => this.listeners.forEach(listener => listener(e));
}
9 changes: 9 additions & 0 deletions assets/js/Listener/DOM/LoadListener.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import AbstractListener from './../AbstractListener';

export default class LoadListener extends AbstractListener {
constructor (Container) {
super(Container);

console.log('HHH LOAD LISTENER');
}
}
9 changes: 9 additions & 0 deletions assets/js/Listener/Window/ResizeListener.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import AbstractListener from './../AbstractListener';

export default class ResizeListener extends AbstractListener {
constructor (Container) {
super(Container);

console.log('HHH RESIZE LISTENER');
}
}
7 changes: 7 additions & 0 deletions assets/js/Middleware/AjaxMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default class AjaxMiddleware {
call = (hook, next) => {
// console.log('AJAX');

next();
}
}
17 changes: 17 additions & 0 deletions assets/js/Middleware/QueryParametersMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export default class QueryParametersMiddleware {
call = (hook, next) => {
// console.log('3AAAAAAA4 QPM');

const queryParams = [];
const searchParams = new URLSearchParams(location.search);

for (const pair of searchParams.entries()) {
let key = pair[0];
let value = pair[1];

queryParams[key] = value;
}

next();
}
}
1 change: 1 addition & 0 deletions assets/js/Project.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require('./App/Project');
13 changes: 13 additions & 0 deletions assets/js/Provider/VariablesProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export default class VariablesProvider {
constructor () {
this.storage = {
Breakpoint: 'xs'
};
}

getStorage = () => this.storage;

set = (identifier, value) => this.storage[identifier] = value;

get = identifier => this.storage[identifier];
}
Empty file.
Loading

0 comments on commit cb290d8

Please sign in to comment.