FLEX

unique template of
your own framework

light

clear

easy

Efficiency - the main priority

Such resources like JS files and CSS files are cached on client-side. It means, that a second loading of page will be much faster.

Does it require modification of server code?

No. A lot of caching systems has a server part. And you have to deploy it, configure it and etc. But flex doesn't need a server part. Whole caching system works on client side.

How it works?

1Don't attach sources directly on page. You should attach via tag <SCRIPT> or <LINK> only two file: core of flex and your settings of flex. Nothing more. There will not any conflicts, if you attach something else, but it's definitely unnecessary.

2Flex will load JS and CSS. In settings file you can define any number of necessary JS files and CSS files. According this list, flex will load these resources. In addition, flex will check references between files and will load an addition necessary resources.

3Flex will save JS and CSS locally. Flex will try parse each your JS or CSS resource and convert it to string. If operation is successful, flex will save such string locally on client-side, using available technology of browser.

4Next time flex will use cache. During each next loading of page, flex will try find cached version of resource and apply it instead loading it from server. In addition, if hash of resource is not actual, flex will reset data and will make new cache for resource.

It's really easy

Just attach to your page a core of flex. And that's all. Other files will be attached automatically.

    <script type="text/javascript" src="/kernel/flex.core.js"></script>

Define settings and references

You can easily change your settings and define list of necessary modules. And all defined modules will be loaded automatically. If some module needs some other one, such missed module will be loaded automatically.

    flex.init({
        resources: {
            MODULES: [
                'flex.ui.window.move',
                'flex.ui.window.resize',
                'flex.ui.templates',
                'flex.ui.scrollbox',
                'flex.program'
            ],
            EXTERNAL: [
                { url: '/web/highlight/highlight.pack.js',  hash: 'HASHPROPERTY' },
                { url: '/web/highlight/styles/github.css',  hash: 'HASHPROPERTY' },
                { url: '/web/css/basic.css',                hash: 'HASHPROPERTY' },
            ]
        },
        paths   : {
            CORE: '/web/kernel'
        },
        events  : {
            finish: function () {
                //What do you want to do at finish?
            }
        }
    });

Cache it!

As you can see, not only internal modules and your modules (which are created via flex-pattern), but also any external modules can be attached via flex-loader. In this case, it will be cached too and during next loading data will be gotten from cache without direct request to server. And pay your attention, it works without any server code - only flex.core.js.

    EXTERNAL: [
        { url: '/web/highlight/highlight.pack.js',  hash: 'HASHPROPERTY' },
        { url: '/web/highlight/styles/github.css',  hash: 'HASHPROPERTY' },
        { url: '/web/css/basic.css',                hash: 'HASHPROPERTY' },
    ]

Cache manager

In your settings file you can define control variable (for any resource) – hash. If value of this variable is changed, flex will "take fresh" version of resource from server. But a basic feature of flex is: flex can update resources automatically. How it works? After all modules are loaded and your application is started, flex in background mode gets information about each your resource. If flex detect some changes of some resource, flex automatically will refresh version of such resource. For user it means, that he always will see actual version of your application (or page).

Initialization (and loading) ordering

You can control of ordering of loading and initialization of external libraries to prevent any possible conflicts between it. And it works really easy - just define URL of library(s), which should be loaded before.

    flex.init({
        resources: {
            ...
            ASYNCHRONOUS    : [
                {
                    resources: [
                        { url: 'http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js' },
                        { url: '/program/highcharts/highcharts.js',         after: ['http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js'] },
                        { url: '/program/highcharts/highcharts-more.js',    after: ['/program/highcharts/highcharts.js'] },
                        { url: '/program/highcharts/exporting.js',          after: ['/program/highcharts/highcharts.js'] },
                    ],
                    storage : true, //cache libraries
                    finish  : function(){ /* do something on finish of this group */ }
                },
                //add any count of resources groups
            ],
        },
        ...
    });

Modularity

1A basic flex's feature is a modularity system. You can build a really heavy web-applications or simple and light. Flex gives you a lot possibilities and maximum freedom.

2You can create bundles of some group of resources. Define such handles like [onFinish], which will be fired, when loading of bundle is finished.

3You can use not only internal modules, but also external JS resources or CSS resources. You can define references between external files; between internal; and between external and internal.

4Flex's modularity system is a great platform not only for your web-application, but also for your own framework.

Central repository

One of ways to build modularity system with flex is use a flex like a central repository of libraries. To do it you should use predefined file [flex.registry.modules.js], where you can define list of all necessary libraries with URL, settings of cache and etc.

    //Declaration of modules
    flex.libraries = {
        //Basic events controller
        events  : {  source: 'KERNEL::flex.events.js'},
        //Collection of tools for management of DOM
        html    : {  source: 'KERNEL::flex.html.js'},
        css     : {
            //Controller CSS animation
            animation   : {  source: 'KERNEL::flex.css.animation.js' },
            //Controller CSS events
            events      : {  source: 'KERNEL::flex.css.events.js'},
        },
        //Collection of UI elements
        ui      : {
            //Controller of window
            window      : {
                //Controller of window movement
                move    : {  source: 'KERNEL::flex.ui.window.move.js'},
                //Controller of window resize
                resize  : {  source: 'KERNEL::flex.ui.window.resize.js'},
                //Controller of window resize
                focus   : {  source: 'KERNEL::flex.ui.window.focus.js' },
                //Controller of window maximize / restore
                maximize: {  source: 'KERNEL::flex.ui.window.maximize.js' },
            },
            //Controller of templates
            templates   : {  source: 'KERNEL::flex.ui.templates.js' },
            //Controller of scrollbox
            scrollbox   : {  source : 'KERNEL::flex.ui.scrollbox.js'},
            //Controller of itemsbox
            itemsbox    : {  source: 'KERNEL::flex.ui.itemsbox.js' },
            //Controller of areaswitcher
            areaswitcher: {  source: 'KERNEL::flex.ui.areaswitcher.js' },
            //Controller of areascroller
            areascroller: {  source: 'KERNEL::flex.ui.areascroller.js' },
            //Controller of arearesizer
            arearesizer : {  source: 'KERNEL::flex.ui.arearesizer.js'},
        },
        program: { settings: true, source: 'web/program/program.js' },
        };
        //"KERNEL::" is just signature. For flex it means, that flex should seach file in same folder
        //where flex.core.js is.

File [flex.registry.modules.js] flex will load automatically and will get all necessary information about your libraries. It will allow you define references to libraries not by URL of library, but by its name.

    flex.init({
        resources: {
            MODULES: [
                //Links to libraries, which should be loaded. Name is same like in register
                'flex.ui.window.move',
                'flex.ui.window.resize',
                'flex.ui.templates',
                'flex.ui.scrollbox',
                'flex.program'
            ],
            ...
        },
        ...
    });

Flex are used namespaces and closed scopes. So all your libraries will be available from this object [flex.libraries]. Method [create] will be generated and attached to each your library automatically.

    //Will create module [flex.libraries.html]
    var HTMLLib         = flex.libraries.html.create();
    //Will create module [flex.libraries.events]
    var DOMEventsLib    = flex.libraries.events.create();

If you are using flex as central repository you have to build your modules according next simple and clear pattern. For your library (module) you can define other resources (like CSS), which will be loaded before module. Also you can define references with other modules.

(function () {
    "use strict";
    //Begin: CLASS of your module
    var protofunction = function () {
        //Constructor
    };
    protofunction.prototype = function () {
        var //Get modules
            html            = flex.libraries.html.create(),
            events          = flex.libraries.events.create();
            //Variables
            ...
        //Some library's methods
        ...
        return {
            //Links to library's methods
        };
    };
    //End: CLASS of your module
    //Attach module into system
    flex.modules.attach({
        //Name of you module
        //Flex loves namespaces, because it allows create self-description names
        //For example: ui.buttons.small -> collection of UI, collection of buttons
        //small button controller.
        name            : 'your.module.name',
        //Link to CLASS of your module. It means, that you can define CONSTRUCTOR
        protofunction   : protofunction,
        //References of your library
        reference       : function () {
            //Pay your attention, you should not define here any paths and URLs.
            //All paths are defined in register [flex.registry.modules.js] and
            //here you just call necessary libraries. Callers are created
            //automatically by flex for each library from register.
            flex.libraries.events   ();
            flex.libraries.html     ();
        },
        //Resources for your library
        resources: [
            { url: 'KERNEL::/css/some.css'          },
            { url: 'www.some.com/some_external.js'  },
        ],
    });
}());

Distributed system

Flex allows you build system within, let's say "RequireJS style". In this case, you can do not have any common register of your modules [flex.registry.modules.js]. You just add module and define links to other resources or modules. Flex will automatically create a map of references between your modules and load it step by step according your order.

_append({
    //Name of you module
    //Flex loves namespaces, because it allows create self-description names
    //For example: ui.buttons.small -> collection of UI, collection of buttons
    //small button controller.
    name            : 'your.one',
    //List of required modules and resources
    require         : [
        { url: 'PATH::your.two.js'          },
        { url: 'PATH::your.three.js'        },
        { url: 'PATH::/css/resource.css'    }
    ],
    //Constructor of your module
    constructor : function () { },
    //Body of your module
    module      : function () {
        var //Get modules
            two     = flex.libraries.your.two.   create(),
            three   = flex.libraries.your.three. create();
            ...
        //Some library's methods
        ...
        return {
            //Links to library's methods
        };
    },
});
//"PATH::" is just signature. You can define via settings folder for this signature.
//Default value is "/app"

Mixed system

It's really cool, that you can mix both systems. You can have some core (collection of resources, which are needed for each page) and add modules (within distributed system) for each page. So, by such way you can build really clear and understandable web-application or client-part of site, where everything is on own places: core is core; page's resources are page's resource.

FLEX templates

Template is HTML

Forget about unclear pieces of layout or code. Just create a separate HTML file for each your template: button, dialog window, arrow - doesn't matter. You can without any problem open such template separately and work with it. Forget about unclear solutions.

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Template of window</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <link rel="stylesheet" type="text/css" href="http://localhost:6434/templates/window/template.css" />
    </head>
    <body>
        <div data-type="Window.Container" data-flex-ui-window-move-container="[@@]id[/@@]" data-flex-ui-window-resize-container="[@@]id[/@@]">
            <div data-type="Window.Container.Overflow">
                <div data-type="Window.Title" data-flex-ui-window-move-hook="[@@]id[/@@]">
                    <p data-type="Window.Title">[@@]title[/@@]</p>
                </div>
                <div data-type="Window.Content">
                    <div data-type="Window.Content.Value" data-window-content="[@@]id[/@@]">[@@]content[/@@]</div>
                    <div data-type="Window.Controls">[@@]buttons[/@@]</div>
                </div>
                <div data-type="Window.Bottom">
                    <p data-type="Window.Information">[@@]bottom_area[/@@]</p>
                </div>
                <div data-type="Window.Resize.Coner"></div>
            </div>
        </div>
    </body>
    </html>

Make your template and use it

Once created your template, you can use it anywhere and anyhow. Sure you can include templates into each other. You have two ways to add it in your page. Create dynamically via simple JavaScript code.

    var templates = flex.libraries.ui.templates.create();
    templates.preload(
        [
            'web/templates/window/template.html',
            'web/templates/button/template.html',
        ],
        {
            success: function () {
                var nodes = templates.render({
                    url     : 'web/templates/window/template.html',
                    node    : document.body,
                    hooks   : {
                        id          : 'window_0',
                        title       : function () { return 'This is title';},
                        bottom_area : 'Here is some static information',
                        buttons     : templates.render({
                            url     : 'web/templates/button/template.html',
                            hooks   :[
                                { title: 'ok',      id: '0' },
                                { title: 'cancel',  id: '1' },
                            ]
                        }),
                    },
                    callbacks : {
                        success: function () {
                            //What do you want to do at finish?
                        }
                    }
                });
                //nodes -> here are result nodes (root level od DOM of your template);
            }
        }
    );

Template inside layout

Or you can include your template inside layout of your page. In this case your template will be loaded automatically.

    <flex-template src="web/templates/window/template.html">
        <id>window_0</id>
        <title>My title from layout</title>
        <buttons>
            <flex-template src="web/templates/button/template.html">
                <id>0</id>
                <title>OK</title>
            </flex-template>
            <flex-template src="web/templates/button/template.html">
                <id>1</id>
                <title>CANCEL</title>
            </flex-template>
        </buttons>
        <content></content>
        <bottom_area>Here is bottom information</bottom_area>
    </flex-template>

How templates works?

1Parsing. Flex's template module will load your template via AJAX and get from it <BODY>. After it, flex try to get all your hooks and add into template defined values.

2Resources. Flex will find in your template all <LINK> and its sources. After flex will attach necessary CSS to basic page (where template is applied).

3Virtual cache. All templates (include content of CSS resources) will be storage in memory. So, each next using of template will not require loading of it via AJAX.

4Local cache. In addition, flex will save all data (layout of template and CSS content) locally. It means that second and next loading of page will not require loading of it via AJAX - all templates will be loaded quickly from storage.

No borders for style of developing

JQ style or chain

You can use chains, like with JQ. Intellisense of Visual Studio supports flex and you will easily get necessary information about available methods. Pay your attention, flex uses an explicit call of chains. To get it for some HTMLElement you use: [_node]; for several elements: [_nodes]; for array: [_array] and simular for other types. Such scheme makes code and logic more understandable.

    //Attach event's handle to button "a[id="button"]"
    _node('a[id="button"]').events().add('click', function () { });
    //Attach event's handles to all buttons "a"
    _nodes('a').events().add('click', function () { });
    //Get size of element 'div[id="target"]'
    var size        = _node('div[id="target"]').html().size().get();
    //Get position of element on page
    var positon     = _node('div[id="target"]').html().position().byPage();
    //Find element inside element
    var sub_nodes   = _node('div[id="target"]').html().find().nodes('.buttons');

Pure JS style

Or you can use "standard" JavaScript style without chains (like in JQ). There are no right style or right way. Each way is good for some purpose. But flex gives to developer a choice.

    var //Get libraries
        HTMLLib         = flex.libraries.html.create(),
        DOMEventsLib    = flex.libraries.events.create(),
        //Get modules
        Selector        = HTMLLib.select.bySelector(),
        Events          = DOMEventsLib.DOMEvents(),
        //Get all [a] in target node
        buttons         = Selector.all('div[id="target"] a');
    Array.prototype.forEach.call(buttons, function (button, index) {
        //Attach event for each button
        Events.add(
            button,                     //Link to node (element)
            'click',                    //Event name
            'button_event_' + index,    //Event ID
            true                        //Allows attach analog event for touch devices
        );
    });

GitHub

You can discover a code and take a last version of flex on GitHub. Also you can contact with author of flex.

License

All files are released under the BSD License.

Copyright (c) 2015, Dmitry Astafyev. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

* Neither the name of flex nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.