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.