Ink includes a group of UI components out of the box.
Those components depend on Ink's Javascript core, which provides a set of methods and modules that help developers extending the features of this framework.
The Javascript core can be loaded in one of the following forms:
Loading Ink's Javascript core Bundle from CDN
<script type="text/javascript" src="../js/ink.min.js"></script>
Loading Ink's Javascript core Bundle from your localhost
<script type="text/javascript" src="/js/ink.min.js"></script>
This Bundle is a compressed and minified version of the following "methods and modules":
-
Ink - Ink's Javascript ecosystem. Provides the necessary methods to create and load the different Ink's Javascript modules:
- Ink.bind - This method is a cross-browser Function.prototype.bind alternative. Allows the developer to define in which context a function is called.
- Ink.bindEvent - Like Ink.bind this method is a cross-browser Function.prototype.bind alternative. The difference is that it maintains the window.event object as first argument in the function's call.
- Ink.createModule - This method is used to create several of Ink's Javascript components. Want to create a custom component? Check here.
- Ink.extendObj - This method enriches the destination object with values from source object whenever the key is missing in destination.
- Ink.getModule - Synchronous way to use a module. This method assumes that the module is already loaded!
- Ink.getModulesLoadOrder - This method returns a list of module names, ordered by loaded time.
- Ink.i - This method is an alias to document.getElementById
- Ink.loadScript - Method for loading a javascript script in the <head>
- Ink.namespace - Method for creating namespaces inside the Ink's Javascript ecosystem.
- Ink.requireModules - Method used to load modules asynchronously, being able to define a callback function to run whenever the specified modules are loaded. This is the recommended way to load modules, because when the callback runs you know for sure that the modules are loaded.
- Ink.s - Alias for the querySelector method. Fallbacks to Ink.Dom.Selector if querySelector not available.
- Ink.ss - Alias for the querySelectorAll method. Fallbacks to Ink.Dom.Selector if querySelectorAll not available.
-
Ink.Dom - Set of modules that helps the developer navigate and manipulate the DOM:
- Ink.Dom.Browser - This module provides informations about the users' browsers.
- Ink.Dom.Css - This module provides a method for getting, manipulating the CSS features of DOM Elements.
- Ink.Dom.Element - This module provides methods to manipulate the DOM, get and set attributes of DOM elements, amongst others.
- Ink.Dom.Event - This module provides methods for adding and removing event listeners, as well as stopping the propagation ( also known as bubbling) and preventing the default behavior of events.
- Ink.Dom.Loaded - This module provides a method for running functions when the page is loaded ( document.ready ).
- Ink.Dom.Selector - This module provides methods for selecting elements in the DOM.
- Ink.Dom.Loaded - Use this module to add code to be executed when the browser loads your web pages. Handy when you are not sure whether the elements you need are available yet.
- Ink.Dom.FormSerialize - Serialize or unserialize your form data to and from JavaScript object structures. Useful when you want to juice up an existing form using AJAX.
-
Ink.Net - Set of modules related with communication and external requests:
- Ink.Net.Ajax - Cross-browser module that has functions to do AJAX requests.
- Ink.Net.JsonP - This module provides functions to make JSONP requests.
-
Ink.Util - Set of utility modules to assist the developer (and the Javascript components) in some more common tasks:
- Ink.Util.Array - This module provides cross-browser methods to manipulate arrays.
- Ink.Util.Cookie - This module provides cross-browser methods for setting, reading and removing cookies with Javascript.
- Ink.Util.Date - This module provide several utility functions to manipulate dates.
- Ink.Util.Dumper - This module provides methods to assist the developer to dump/profile code.
- Ink.Util.String - This module contains string handling and manipulation functions.
- Ink.Util.Swipe - This module provides a set of cross-browser, cross-device functions to detect swiping. That includes direction, velocity, coordinates.
- Ink.Util.Url - This module provides methods to handle and manipulate URLs.
- Ink.Util.Validator - This module provides methods to help the developer in validation processes.
All of these components are in the Bundle, but in case you don't need all of them, you can load only some.
Loading Javascript components from CDN
This file is required and should always be loaded first:
<script type="text/javascript" src="../js/ink.min.js"></script>
And then the different components... Example:
<script type="text/javascript" src="../js/ink.modal.js"></script>
Ink
API Link
This is the starting point of the Ink's Javascript core. It provides the necessary methods for loading the different modules, extensibility (creation of modules), scope/context manipulation, namespace creation, amongst other things.
requireModules
This method provides an easy way to load any Ink's javascript module.
It receives an array with the modules to be loaded as 1st parameter and a callback function - to be called when all modules from the array are loaded - as 2nd parameter.
<script type="text/javascript" src="../js/ink.min.js"></script>
<script type="text/javascript">
Ink.requireModules(
['Ink.Dom.Loaded_1','Ink.Dom.Selector_1'], // Modules to be loaded
function( Loaded, Selector ){ // Callback function
Loaded.run(
function(){
var bodyEl = Selector.select('body')[0]; // Get the first item of the array.
bodyEl.innerHTML = 'Test!';
}
);
}
);
</script>
As you can see, the names of the modules have the following syntax: Ink.Namespace.Component_Version and are loaded into the callback function as parameters, in the same order as they're listed in the array.
namespace
Let's say you want to create your own namespace, to extend Ink's Javascript core or control other objects.
This method allows you to make sure that the specified namespace exists... In case it doesn't, it'll create it!
<script type="text/javascript" src="../js/ink.min.js"></script>
<script type="text/javascript">
Ink.namespace('MyNamespace');
Ink.MyNamespace.myCustomFunction = function( name ){
console.log('Hello, ' + name);
};
Ink.MyNamespace.myCustomFunction('User');
</script>
As you can see, the names of the modules have the following syntax: Ink.Namespace.Component_Version and are loaded into the callback function as parameters, in the same order as they're listed in the array.
bind and bindEvent
Ink's javascript core has two methods to ease the pain of setting the context (and its arguments) in a function.
While Ink.bindEvent is more directed to functions that handle events - because it sets the context of the function and passes the event object as first parameter - on the other hand, Ink.bind is related to the more common function that you need to set the context and still maintain its arguments as it is.
<script type="text/javascript" src="../js/ink.min.js"></script>
<script type="text/javascript">
// An object
var myObj = {
name: 'User',
age: 27,
comment: 'This is an object with some data'
};
function echoName(){ // A function that logs the name
console.log(this.name);
}
echoName = Ink.bind(echoName,myObj)(); // Usage of Ink.bind
function echoEventAndMyObj(event){
console.log(event);
console.log(this);
}
// Usage of Ink.bindEvent
Ink.requireModules(['Ink.Dom.Event_1'],function(Event){ // Loads the Event component, to handle events
Event.observe(document,'click',Ink.bindEvent(echoEventAndMyObj,myObj)); // Listening to the event 'click' in the page
});
</script>
Dom
The DOM is a mess, you know it and we do too, that's why we've added specialized DOM methods to Ink, it makes your life easier and that makes us happy.
Browser
API Link
Want to know something about the user's browser? Here's how...
<script type="text/javascript">
Ink.requireModules(['Ink.Dom.Browser_1'],function(Browser){
if( Browser.CHROME ){
console.log( 'You are using Google Chrome' );
}
});
</script>
Css
API Link
Give your document some style with our Css class.
<div id="myElement" ></div>
<script type="text/javascript">
Ink.requireModules(['Ink.Dom.Css_1'],function(Css){
var myElement = Ink.i('myElement'); // Same as document.getElementById('myElement')
console.log( Css.hasClassName( myElement, 'myClass' ) ); // Result: false
Css.addClassName( myElement, 'myClass' );
console.log( Css.hasClassName( myElement, 'myClass' ) ); // Result: true
});
</script>
Element
API Link
Not all browsers were created equal, and the DOM is where it shows the most. Get the document just the way you want it with Element.
<div id="myElement" ></div>
<script type="text/javascript">
Ink.requireModules(['Ink.Dom.Element_1'],function(Element){
var myElement = Ink.i('myElement');
var myDiv = Element.create('div', {
class: 'myClass',
id: 'myNewDiv',
'data-attribute': 'my Data Attribute Value'
});
Element.insertAfter(myDiv, myElement);
// Result:
// <div id="myElement" ></div>
// <div class="myClass" id="myNewDiv" data-attribute="my Data Attribute Value"></div>
});
</script>
Event
API Link
Event handling is easy with Ink, using our Event class.
<button id="myButton">Click me!</button>
<script type="text/javascript">
Ink.requireModules(['Ink.Dom.Event_1'],function(Event){
var myElement = Ink.i('myButton');
Event.observe( myElement, 'click', function( e ){
Event.stop(e); // Stopping the event and preventing the bubbling
var target = Event.element(e); // Getting the element that triggered the event
console.log('The element we clicked was: ', target);
});
});
</script>
Selector
API Link
If you've ever worked with CSS then you know how to use our Selector engine, we've enlisted the help of Sizzle to bring you a simple and fast way to get the elements you need.
<div class="myClass" id="myDiv1">myDiv 1</div>
<div class="myClass" id="myDiv2">myDiv 2</div>
<script type="text/javascript">
Ink.requireModules(['Ink.Dom.Selector_1'],function( Selector ){
// There are several ways to select DOM elements...
// One is via Ink.i(), which is basically an alias of document.getElementById()
console.log( Ink.i('myDiv1') ); // Result is the first div
// Another is via Ink.s() which is an alias of document.querySelector()
// In case document.querySelector is not available, it uses the Ink.Dom.Selector
// Like document.querySelector, only returns the first DOM element found.
console.log( Ink.s('.myClass') );
// Another alias is Ink.ss() which is an alias for document.querySelectorAll()
// Like Ink.s() it fallsback to the Ink.Dom.Selector if document.querySelectorAll is not available
// Like document.querySelectorAll(), it returns an array of matching DOM elements
console.log( Ink.ss('.myClass') );
// Last but not least... You can use the Selector.select() method.
// Ink.ss() and Selector.select() produce the same results
console.log( Selector.select('.myClass') );
});
</script>
Loaded
API Link
Whether you're executing code when the document is ready or loaded we've got the tools you need to get your code running when you want.
<script type="text/javascript">
Ink.requireModules(['Ink.Dom.Loaded_1'],function( Loaded ){
Loaded.run( function(){
console.log('The document is ready!');
});
});
</script>
FormSerialize
API Link
This static module contains two functions used to serialize and unserialize a form to and from a JavaScript object.
Serialize a form
This is how you serialize a form into a JavaScript object, possibly to turn into JSON and send over the network:
<form id="frm">
<input type="text" name="field1">
<button type="submit">Submit</button>
</form>
<script type="text/javascript">
Ink.requireModules(['Ink.Dom.FormSerialize_1', 'Ink.Dom.Event_1'], function (FormSerialize, InkEvent) {
InkEvent.observe('frm', 'submit', function (event) {
var formData = FormSerialize.serialize('frm'); // -> {field1:"123"}
InkEvent.stop(event);
});
});
</script>
Fill in a form
You can fill in a form with values from an object by using the fillIn
method.
<form id="frm">
<input type="text" name="field1">
<button type="submit">Submit</button>
</form>
<script type="text/javascript">
Ink.requireModules(['Ink.Dom.FormSerialize_1'], function (FormSerialize) {
var values = {field1: 'CTHULHU'};
FormSerialize.fillIn('frm', values);
// At this point the form is pre-filled with the values above.
});
</script>
Net
Ink's Javascript engine offers you plenty of ways to get your web site communicating with the vast collection of public services available on the web. CORS enabled AJAX and JsonP will get you up and running in no time.
Ajax
API Link
The same AJAX you know and love, now with some extra CORS magic to spice up your cross request filled life.
<script type="text/javascript">
Ink.requireModules(['Ink.Net.Ajax_1'],function(Ajax){
// Here iss a quick way to do a simple GET request:
Ajax.load( '../js/example.json', function( response ){
console.log( response ); // This will log the HTML of the homepage
});
// Now a POST request:
new Ajax('../js/example.json',{
asynchronous: true,
method: 'POST',
onSuccess: function( response ){
console.log( response.responseText );
}
});
});
</script>
JsonP
API Link
Break out of your local domain chains and enjoy the freedom of cross domain requests,
JsonP give you the tools you need to start getting data from any source you want.
<script type="text/javascript">
Ink.requireModules(['Ink.Net.JsonP_1'],function( JsonP ){
new JsonP( 'https://services.sapo.pt/Codebits/session/301',{
callbackParam: 'callback',
onSuccess: function(response){
console.log( response ); // Result: JSON Object
}
});
});
</script>
Util
Even certain bat suit wearing ninjas need to use utilities every one in a while, and what are JavaScript developers if not ninjas without the bat suit? Ink offers those who possess the script-fu ways to take their skills to the next level.
Array
API Link
Utility functions for Array manipulation.
<script type="text/javascript">
// We use InkArray because Array is a reserved keyword. Feel free to use other name...
Ink.requireModules(['Ink.Util.Array_1'],function( InkArray ){
var myArray = [ 'value1','value2','value3' ]; // Array initialization
// Here are some usage examples of methods available in the Array utility component.
InkArray.each( myArray, function( value, index, arr ){
console.log( 'In the index #' + index + ' the value is: ' + value );
});
if( InkArray.inArray( 'value3', myArray ) ){
console.log("\nvalue3 is in the array");
}
var myArrayOfObjects = [
{
'name': 'Peter',
'age': 22,
'gender': 'male'
},
{
'name': 'Maria',
'age': 25,
'gender': 'female'
},
{
'name': 'Jessica',
'age': 33,
'gender': 'female'
},
{
'name': 'Filip',
'age': 19,
'gender': 'male'
}
];
console.log( "\nOrdered by name:" );
InkArray.each( InkArray.sortMulti( myArrayOfObjects, 'name' ), function( value, index, arr ){
console.log( 'In the index #' + index + ' the value is: ', value );
});
console.log( "\nOrdered by age:" );
InkArray.each( InkArray.sortMulti( myArrayOfObjects, 'age' ), function( value, index, arr ){
console.log( 'In the index #' + index + ' the value is: ', value );
});
console.log( "\nOrdered by gender:" );
InkArray.each( InkArray.sortMulti( myArrayOfObjects, 'gender' ), function( value, index, arr ){
console.log( 'In the index #' + index + ' the value is: ', value );
});
});
</script>
Cookie
API Link
Utility functions for Cookie creating, reading and deleting.
<script type="text/javascript">
Ink.requireModules(['Ink.Util.Cookie_1'],function( Cookie ){
// Checking if there is a cookie already set. If so, shows the cookie object
console.log( 'Initial cookie values (if any): ', Cookie.get() );
console.log( 'Just getting our number: ', Cookie.get('myValue') );
// Generates a random number and stores it into the cookie (also displays the generated number)
var random_number = Math.floor((Math.random()*100)+1); // Number between 0 and 100
console.log("\nCookie's new number", random_number);
Cookie.set( 'myValue', random_number, 3600); // Expires in 3600 seconds, or 1 hour.
// Removing the cookie:
Cookie.remove('myValue');
});
</script>
Date
API Link
Utility functions for Date handling.
<script type="text/javascript">
// We use the variable InkDate because Date is a reserved keyword
Ink.requireModules(['Ink.Util.Date_1'],function( InkDate ){
// Formatting a date in a specific format and getting it formatted:
var dateObj_1 = InkDate.get('Y-m-d'); // Current date
var dateObj_2 = InkDate.get('d/m/Y', new Date(2013,0,1)); // 2013-01-01 as date reference.
console.log( dateObj_1 );
console.log( dateObj_2 );
// Making a Date Object based in string and its format:
console.log( InkDate.set('Y-m-d', '2013-07-29') );
console.log( InkDate.set('d/m/Y', '01/01/2013') );
});
</script>
Dumper
API Link
Utility functions for Dumping/Profiling.
<div id="output"></div>
<script type="text/javascript">
Ink.requireModules(['Ink.Util.Dumper_1'],function( Dumper ){
var myObj = {
'key1': 'value1',
'key2': 'value2',
'key3': 'value3'
};
Dumper.alertDump( myObj ); // Makes an alert with the variable structure
Dumper.printDump( myObj, 'output' ); // Prints the variable structure in the given element
console.log( Dumper.returnDump(myObj) ); // Returns the variable structure, and logs it
// Opens a new window with the variable structure
// In this case, the new window might be blocked by the popup if not triggered by a user event
// ... like a mouse click or a touch event.
Dumper.windowDump( myObj );
});
</script>
String
API Link
Examples of some String manipulation functions.
<div id="output"></div>
<script type="text/javascript">
Ink.requireModules(['Ink.Util.String_1'],function( InkString ){
var myObj = {
'key1': 'value1',
'key2': 'value2',
'key3': 'value3',
'htmlContent': ' <p>Some HTML tags</p><p>Not stripped nor encoded</p> <b>And with some extra spaces in the beginning, in the middle and in the end</b> '
};
var jsonVersion = JSON.stringify( myObj );
if( InkString.isJSON( jsonVersion ) ){
console.log( 'This is a JSON Object... Now decoding it back to object');
console.log( InkString.evalJSON( jsonVersion ) );
}
// Placing original HTML in the output div
Ink.i('output').innerHTML = myObj.htmlContent;
// Placing stripped HTML in the output div
Ink.i('output').innerHTML = InkString.stripTags(myObj.htmlContent);
// Placing HTML encoded in the output div...
Ink.i('output').innerHTML = InkString.htmlEntitiesEncode(myObj.htmlContent);
// ... and decodes it
Ink.i('output').innerHTML = InkString.htmlEntitiesDecode(Ink.i('output').innerHTML);
// Now only escaping the unsafe HTML characters:
Ink.i('output').innerHTML = InkString.htmlEscapeUnsafe(myObj.htmlContent);
});
</script>
Swipe
API Link
Usage of the Swipe utility component, to detect swiping on touch-enabled devices.
<div id="swipableArea"></div>
<script type="text/javascript">
Ink.requireModules(['Ink.Util.Swipe_1'],function( Swipe ){
new Swipe( Ink.i('swipableArea'),{
forceAxis: 'x', // It will only detect horizontal swiping
minDist: 20, // Minimum distance that a swipe must have to be detected as such
callback: function( swipeObj, swipeInfo ){
console.log( 'A SWIPE HAS BEEN DETECTED!!!! ');
console.log( swipeObj);
console.log( swipeInfo);
}
})
});
</script>
Url
API Link
Usage of some of the Url utility component functions, to parse and generate URLs.
<div id="swipableArea"></div>
<script type="text/javascript">
Ink.requireModules(['Ink.Util.Url_1'],function( Url ){
var currentURL = Url.getUrl(); // Gets the current URL
console.log( Url.parseUrl( currentURL ) ); // Returns an object with the url info
var params = {
'var1': 'value1',
'var2': 'value2',
'var3': 'value3'
}
console.log( Url.genQueryString( currentURL, params ) ); // Result: http://siteink.local/js/core?var1=value1&var2=value2&var3=value3
});
</script>
Validator
API Link
Usage of some of the Validator utility component functions.
<div id="swipableArea"></div>
<script type="text/javascript">
Ink.requireModules(['Ink.Util.Validator_1'],function( Validator ){
// Validating a Portuguese phone number
console.log( Validator.isPortuguesePhone( '+351213919264' ) ); // Result: true
// Validating e-mails
console.log( Validator.mail( 'agfsdfgfdsgdsf' ) ); // Result: false
console.log( Validator.mail( 'inkdev@sapo.pt' ) ); // Result: true
// Validating URLs
console.log( Validator.url( 'www.sapo.pt' ) ); // Result: true
console.log( Validator.url( 'http://www.sapo.pt', true ) ); // Result: true
console.log( Validator.url( 'meh' ) ); // Result: false
// Validating Colors
console.log( Validator.isColor( '#FF00FF' ) ); // Result: true
console.log( Validator.isColor( '--1231-312' ) ); // Result: false
});
</script>
Custom Components
So you want to extend the core, add your own components? It's very easy.
Using Ink.createModule() you'll have the ability to create your own components, having a private scope and returning only what will be used.
From our perspective, there are two types of components:
Static components
This type of component doesn't need a constructor (or to be prepend with the new keyword).
Here's an example:
<script type="text/javascript">
Ink.createModule(
'Ink.YourNameSpace.YourStaticModuleName', // full module name
'1', // module's version
['Ink.Dom.Event_1', 'Ink.Dom.Css_1'], // array of dependency modules
function(Event, Css) { // this fn will be called async with dependencies as arguments
'use strict';
/**
* This is an awesome set of methods to paint the sky.
*
* @class Ink.YourNamespace.YourStaticModule
* @static
*/
var YourStaticModule = {
/**
* This method returns the string 'foo'.
* (Apparently it is useless, since it is not used, but you get the point)
*
* @method _privateMethod
* @return {String} String 'foo' is returned
*/
_privateMethod: function() {
return 'foo';
},
/**
* @property publicProperty
* @readOnly
*/
publicProperty: 'sky is blue',
/**
* Returns a string 'Hello [name], how are you doing? Your number is [number].'
*
* @method publicMethod
* @param {String} name Name to be placed in the string
* @param {Number} number Number to be placed in the string
* @returns {String} The string correctly parsed.
*/
publicMethod: function(name, number) {
return ['Hello ', name, ', how are you doing? Your number is ', number, '.'].join('');
}
};
return YourStaticModule; // this line is critical, otherwise nothing is bound to the module definition!
}
);
</script>
Save your code as a js file, include it as a <script> tag, and then just use it like a normal component:
<script type="text/javascript">
Ink.requireModules(['Ink.YourNameSpace.YourStaticModuleName_1'],function( yourVar ){
console.log( yourVar.publicMethod( 'User', 23 ) );
});
</script>
Class components
This type of component has a constructor. It's used to create objects of this classe's type.
Here's an example:
<script type="text/javascript">
Ink.createModule(
'Ink.YourNameSpace.YourClassModule', // full module name
'1', // module's version
['Ink.Dom.Event_1', 'Ink.Dom.Css_1'], // array of dependency modules
function(Event, Css) { // this fn will be called async with dependencies as arguments
'use strict';
/**
* Demo case.
*
* @class Ink.YourNamespace.YourClassModule
* @constructor
* @param {DOMElement} element DOM Element to listen the events from
* @param {Object} [options]
* @param {String} [options.opt1] Info about opt1. By default is 'foo'.
* @param {String} [options.opt2] Info about opt2. By default is 'bar'.
*/
var YourModuleName = function(element, options) {
this._element = element;
this._options = Ink.extendObj({
event: 'click'
}, options || {});
this._handler = undefined;
this._init();
};
YourModuleName.prototype = {
/**
* Initialization function. Sets the event listener in the beginning.
*
* @method _init
* @private
*/
_init: function() {
this._setEventListener();
},
/**
* Function that will be executed when the specified event is triggered.
* Logs in the console which event was detected
*
* @method _eventHandler
* @param {Object} event Window.event object
* @private
*/
_eventHandler: function( event ){
Event.stop( event );
console.log( 'The event ', this._options.event, ' was detected!');
},
/**
* Removes the event listening.
*
* @method _stopEventListener
* @private
*/
_stopEventListener: function(){
Event.stopObserving(this._element, this._options.event, this._handler );
},
/**
* Sets the event listening
*
* @method _setEventListener
* @private
*/
_setEventListener: function(){
this._handler = Ink.bindEvent( this._eventHandler, this );
Event.observe(this._element,this._options.event, this._handler);
},
/**
* Changes the event that is listened.
* Stops the previous listener, and starts listening the current one
*
* @method setEvent
* @param {String} event An event string, ex: 'click'
* @public
*/
setEvent: function( event ) {
this._stopEventListener();
this._options.event = event;
this._setEventListener();
},
/**
* Dismisses the event handling.
*
* @method dismiss
* @public
*/
dismiss: function() {
this._stopEventListener();
}
};
return YourModuleName; // this line is critical, otherwise nothing is bound to the module definition!
}
);
</script>
Save your code as a js file, include it as a <script> tag, and then just use it like a normal component:
<script type="text/javascript">
Ink.requireModules(['Ink.YourNameSpace.YourClassModule_1'],function( yourClass ){
window.yourObj = new yourClass( Ink.i('testArea'),{
event: 'mouseover'
} );
});
</script>