Paint the Web - a micro-Blog in .md about Dev, Web and more

Canal\Asset

Flood\Canal's Structure has preconfigured Frontend Build Tasks for Sass to CSS, CSS optimizes, JS concating, JS uglify, image optimizes and a little more.

For the build tools see asset management.

How to install Canal:

composer create-project flood/canal-structure . -s DEV

Pre-installed in Canal, the component's asset files could also be installed with:

composer require flood/canal-asset

Modules

  • GDPR - Social Embed with basic GDPR compliance

Simple Classes

AnimationFlow

Easier way of handling action classes, handles the removing and adding from classes when switching between states

  • relies on the util/Array for Array.proto.diff()

Get a new instance for closing and opening of a button, this removes and adds the needed classes on transition

import AnimationFlow from 'vendor/flood/canal-asset/src/AnimationFlow';

let button_as = new AnimationFlow({
    node: document.querySelector('.nav-service'),
    debug: true,
    current: 'closed',
    class_prefix: '',
    states: {
        closed: {
            class: []
        },
        opening: {
            class: [
                'opening',
                'visible',
            ]
        },
        open: {
            class: [
                'open',
                'visible'
            ]
        },
        closing: {
            class: [
                'closing',
                'visible'
            ]
        }
    }
});
button_as.go('opening');
button_as.go('open');
button_as.go('closing');
button_as.go('closed');

LazyLoad

LazyLoading with either the IntersectionObserver or a very simple Polyfill

import LazyLoad from 'vendor/flood/canal-asset/src/LazyLoad';

new LazyLoad({
        debug: true,
        onetime: true,
    },
    // callback when one element comes visible
    (elem) => {
        gdpr.create(elem);
    })
    // start observing all not already rendered autoload items
    .observe(document.querySelectorAll('.to-lazy-load:not(.rendered)'));

Ready

Executes the callback after the content has been loaded, e.g. after all scripts has been loaded.

import Ready from 'vendor/flood/canal-asset/src/Ready';

new Ready(() => {
});

StateMachine

A callback based state machine for unidirectional transitions.

  • has callbacks for all events that could occure during transitions
  • has callbacks for specific transitions
  • relies on Array.proto.isArray(), add a polyfill for older browser, general support is mostly sufficient

Add states and transitions to a state machine and go from one to another

import StateMachine from 'vendor/flood/canal-asset/src/StateMachine';

let sm = new StateMachine({
    node: document.querySelector('.nav-service'),
    debug: true,
    current: 'closed',
    class_prefix: '',
    states: {
        // here are the states defined
        closed: {
            on: {
                leaving(current, next) {
                    console.log('only executed when `leaving` closed');
                },
                leave(current, next) {},
                leaved(current, next) {},
                entering(current, next) {},
                enter(current, next) {},
                entered(current, next) {}
            }
        },
        opening: {
            on: {
                entering(current, next) {
                    console.log('only executed when `entering` opening');
                }
            }
        },
        open: {},
        closing: {}
    },
    on: {
        leave(current, next) {
            console.log('executed on every leave');
        },
        enter(current, next) {
            console.log('executed on every enter');
        }
    },
    // the transition events are only done when exactly the same transition happens, the transition is the arrow
    transition: {
        'closed->opening': (current, next) => {
            console.log('specific transition: closed-opening');
        },
        '<current.id>-><next.id>': (current, next) => {}
    }
});

sm.go('opening');
sm.go('open');
sm.go('closing');
sm.go('close');

TemplateFetch

Fetches a resource from the server, e.g. pre-rendered template data or moustache templates.

Initialize, recommended as global utility


// Fetch Polyfill
// https://github.com/github/fetch
import 'bower_components/fetch/fetch';

import TemplateFetch from 'vendor/flood/canal-asset/src/TemplateFetch';

window.tf = new TemplateFetch({
    host: window.location.protocol + '//' + window.location.host + '/',
    debug: true
});

will execute in default the url protocol://host(:port)/api/templatefetch//?param=values&used_as=tpl_dat

tf.fetch('hello').then(function (response) {
    document.querySelector('body').insertAdjacentHTML('beforeend', response.html);
});

Fetch and display the pre-rendered view/templatefetch/overlay.twig

tf.fetch('overlay', {
     css: 'example-overlay',
     btn: 'Close',
     content: '<p>Some Content!</p>',
}).then(function (response) {
    document.querySelector('body').insertAdjacentHTML('beforeend', response.html);
});

Api

Connecting Frontend to an Api Backend, supports different type of connections, multiple endpoint to define the target and option for providing header and data for providing data.

Api Quickstart

Set the URL to the Api through API_URL.

import Api, {API_URL, GET} from "./lib/Api";

Api.do(
    api_name,
    type, 
    endpoint, 
    option, 
    data
    ).then((res) => {

    });

Api Options

let option = {
    pagination: {
        page: 3,
        per_page: 10
    },
    sort: {
        field: 'order',
        field1: 'order'      
    },
    filter: {
        id: {
            'id0',
            'id1'
        },
        field: 'condition',
        field1: 'condition'
    }
};

Will be send to server as HEADER X_API_OPTION with the content as this JSON:

let option = {
    range: {
        from: number,
        to: number,
    },
    sort: Object,
    filter: Object,
};
  • pagination
  • sort

Api Types of Connections

  • using HTTP GET
    • GET_ONE - gets one element
    • GET_MANY - get many elements, depending on filter
  • using HTTP PUT
    • CREATE - create one element with data
  • using HTTP POST
    • POST - push data to an endpoint
    • UPDATE - update one element with data
  • using HTTP DELETE
    • DELETE - delete one element
Type: GET_ONE
  • option - not used
  • data - not used
Type: GET_MANY
  • option - used
  • data - not used
Type: UPDATE
  • option - not used
  • data - used
Type: CREATE
  • option - not used
  • data - used

Api must return id containing the primary key of the just created item.

Result holds:

{
  "data":{
    ...input_data,
    "id": "id"
  }
}
Type: POST
  • option - used
  • data - used
Type: DELETE
  • option - not used
  • data - not used

Api Result

let result = {
    data: {
        "response-body-as-json"
    }
};

Worker

Just a scribble, do not use, maybe help implementation?

Util

Array.prototype.diff() returns the difference between two arrays.

import 'vendor/flood/canal-asset/util/Array';

let first = [1,2,3];
let second = [2,3,4];

first.diff(second);
// 1
second.diff(first);
// 4

Polyfill

First level is which file/group, autodetect means the polyfill is only executed when needed.

import 'vendor/flood/canal-asset/polyfill/node-html-foreach';
import 'vendor/flood/canal-asset/polyfill/object-assign';
  • node-html-foreach, autodetect
    • NodeList will get forEach from Array
    • HTMLCollection will get forEach from Array
  • object-assign, autodetect
    • Object will get method assign

Other polyfills recommended: