Ink JS UI

Beautiful js components to go with your project.

Ink UI Javascript components

Ink offers a great set of Javascript components to enrich your user interface, which are easy to implement, powerful and responsive. We made these components thinking of people who don't know JS but still need to include certain features on their web pages without help from a programmer, but there is also a deep core of JS code to explore, if you're so inclined.

Next, we'll detail each component, explain it as simply as we can, provide you with all the configuration details and also provide you with links to the deeper technical docs, in case you are a developer, looking for more power under the hood.

To get started, you need to include certain scripts which will make your components work. We suggest you place these in your document's <head> and keep them all neatly organised. You will need to include:

  • ink.js which is the core code that makes everything else work
  • the modules you need (eg. Modal, if you need a modal window)
  • autoload.js, which initializes all modules, so you don't have to

Ink's javascript files can be loaded in one of several ways:

Loading from the CDN

You can load Ink's Javascript Core and its UI Components in just one minified file (the complete bundle):

<script type="text/javascript" src="../js/ink-all.min.js"></script>

You can load Ink's Javascript Core Bundle and its UI Components Bundle separately, still minified:

<script type="text/javascript" src="../js/ink.min.js"></script>
<script type="text/javascript" src="../js/ink-ui.min.js"></script>

You can load Ink's Javascript Core Bundle and each UI Component separately (one line per UI Component):

<script type="text/javascript" src="../js/ink.min.js"></script>
<script type="text/javascript" src="../js/ink.someComponent.min.js"></script>
<script type="text/javascript" src="../js/ink.anotherComponent.min.js"></script>

Don't forget to replace the someComponent and the anotherComponent parts of the example for the real names of the components, like modal or progressbar.



Code for loading from your local host

Similarly to the CDN, you can load Ink's Javascript Core and its UI Components in just one minified file (the complete bundle):

<script type="text/javascript" src="/js/ink-all.min.js"></script>

Once again, you can load Ink's Javascript Core Bundle and its UI Components Bundle separately, still minified:

<script type="text/javascript" src="/js/ink.min.js"></script>
<script type="text/javascript" src="/js/ink-ui.min.js"></script>

Finally, you can also load Ink's Javascript Core Bundle and each UI Component separately (one line per UI Component):

<script type="text/javascript" src="/js/ink.min.js"></script>
<script type="text/javascript" src="/js/ink.someComponent.min.js"></script>
<script type="text/javascript" src="/js/ink.anotherComponent.min.js"></script>

Don't forget to replace the someComponent and the anotherComponent parts of the example for the real names of the components, like modal or progressbar.

We'll remind you to load the correct modules for each component, using the local host method, in the documentation below. Just replace the given local host examples with the CDN URL above, if you prefer it.

If you have a better grasp of JS and do not want all components intitialized off the bat, then do not inclue autoload.js, and, instead, initialize each component by hand. You can refer to the technical documentation to see how each initialization is made.

Table

Skip to the code

The table component adds powerful features to a native HTML table, such as sorting and pagination, that will offer improved interactivity with tabular data.

All you need is a table and some simple data-attributes and you're set.

Necessary JS Modules

Before you begin, make sure you're including the necessary Javascript inside your <head>, you'll need ink.js, ink.table.js and autoload.js.

Code

<script type="text/javascript" src="/js/ink.min.js"></script>
<script type="text/javascript" src="/js/ink.table.js"></script>
<script type="text/javascript" src="/js/autoload.js"></script>

If you opted for not using the autoload feature, then you'll need to initialize the Table component by hand. Simply include the following code, at the end of your page, before the closing <body>

<script type="text/javascript">
    // There are two ways to run the code...
    // 1 - If you know you have the component and its dependencies already loaded, just do:
    var table = new Ink.UI.Table( '.ink-table' );

    // 2 - If you're not sure the component or its dependencies are loaded at runtime, do:
    Ink.requireModules( ['Ink.UI.Table_1'], function(Table){
        new Table( '.ink-table' );
    });
</script>

Setting up sorting

To make your table columns sortable, you need to add the data-sortable attribute to your <th> elements. The value must be either "true" or "false" and Ink will just look a the column, figure out what kind of content it contains and then sort it, either alphabetically or numerically, depending on that content.

So, if you have a table with names and ages and you want both columns to be sortable, you simply add the data-attribute in both headers, like this:

Code

<thead>
  <th data-sortable="true">Name</th>
  <th data-sortable="true">Age</th>
</thead>

Setting up pagination

Sometimes, your tables are just too long and you need to split them up by pages, without forcing your user to skip to a different page and load an entirely new table. With Ink, all you need is to specify how many rows per page you want your table to have. If your table grows to more than the specified number of rows, then it will create a new page within the table, which you can access via a pagination-style menu. Check out the Navigation section, under pagination menus to see how they work.

To have pagination, you also need to provide an empty <nav> with an empty <ul> element for Ink to write the page navigation into. They need the .ink-navigation and .pagination classes, respectivelly. Furthermore, you can configure said pagination by adding classes to the <ul> just as detailed in the Navigation section linked above. So, you'll need this:

Code

<table data-page-size="10"> <!--tells your table to break at every 10 rows-->
  ... <!--your table content here-->
</table>
<nav class="ink-navigation"><ul class="pagination"></ul></nav> <!--pagination will be written here, automatically-->

As you can see, it's pretty easy to setup. We suggest you read our Tables section in order to create your Ink tables and then add the JS to make them work better for your users. Here's an example of a sortable and paginated table, just hit the show source code button to copy the code.

Example

Scoville Rating of Peppers

Pepper Scoville Rating
Trinidad Moruga Scorpion 1500000
Bhut Jolokia 1000000
Naga Viper 1463700
Red Savina Habanero 580000
Habanero 350000
Scotch Bonnet 180000
Malagueta 50000
Tabasco 35000
Serrano Chili 27000
JalapeƱo 8000
Poblano 1500
Peperoncino 500

<table class="ink-table alternating" data-page-size="6">
    <thead>
        <tr>
            <th data-sortable="true" width="75%">Pepper</th>
            <th data-sortable="true" width="25%">Scoville Rating</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Trinidad Moruga Scorpion</td>
            <td>1500000</td>
        </tr>
        <tr>
            <td>Bhut Jolokia</td>
            <td>1000000</td>
        </tr>
        <tr>
            <td>Naga Viper</td>
            <td>1463700</td>
        </tr>
        <tr>
            <td>Red Savina Habanero</td>
            <td>580000</td>
        </tr>
        <tr>
            <td>Habanero</td>
            <td>350000</td>
        </tr>
        <tr>
            <td>Scotch Bonnet</td>
            <td>180000</td>
        </tr>
        <tr>
            <td>Malagueta</td>
            <td>50000</td>
        </tr>
        <tr>
            <td>Tabasco</td>
            <td>35000</td>
        </tr>
        <tr>
            <td>Serrano Chili</td>
            <td>27000</td>
        </tr>
        <tr>
            <td>Jalapeño</td>
            <td>8000</td>
        </tr>
        <tr>
            <td>Poblano</td>
            <td>1500</td>
        </tr>
        <tr>
            <td>Peperoncino</td>
            <td>500</td>
        </tr>
    </tbody>
</table>
<nav class="ink-navigation"><ul class="pagination"></ul></nav>
<script type="text/javascript">
    // There are two ways to run the code...
    // 1 - If you know you have the component and its dependencies already loaded, just do:
    var table = new Ink.UI.Table( '.ink-table' );

    // 2 - If you're not sure the component or its dependencies are loaded at runtime, do:
    Ink.requireModules( ['Ink.UI.Table_1'], function(Table){
        new Table( '.ink-table' );
    });
</script>

Configurable data attributes

Here's a list of the data-attributes you can use to manage your table components.

  • data-page-size defines how many rows per page (not counting headers) your table shows, must be a numeric value. Must be applied to <table> element. Example: data-page-size="20"
  • data-sortable makes a column sortable (toggles between not sorted, ascending and descending), value must be "true" or "false" (default). Must be applied to a <th> element. Example: data-sortable="true"

For more examples, like remote data loading via AJAX, and a list of all supported options, check our technical documentation.

Tree View

Skip to the code

The Tree View component takes a structure of nested lists and transforms it into an interactive tree with expandable and collapsible branches.

Although we recommend you use primarily unordered or ordered lists, this component can be applied to any structured group of DOM elements.

Necessary JS modules

Before you begin, make sure you're including the necessary Javascript inside your <head>, you'll need ink.js, ink.treeview.js and autoload.js if you want your module to be initialized with no hassle.

Code

<script type="text/javascript" src="/js/ink.min.js"></script>
<script type="text/javascript" src="/js/ink.treeview.js"></script>
<script type="text/javascript" src="/js/autoload.js"></script>

If you opted for not using the autoload feature, then you'll need to initialize the Modal component by hand. Simply include the following code, at the end of your page, before the closing <body>

Code

<script>
    // There are two ways to run the code...
    // 1 - If you know you have the component and its dependencies already loaded, just do:
    var treeview = new Ink.UI.TreeView( '.ink-tree-view' );

    // 2 - If you're not sure the component or its dependencies are loaded at runtime, do:
    Ink.requireModules( ['Ink.UI.TreeView_1'], function(TreeView){
        new TreeView( '.ink-tree-view' );
    });
</script>

Building a tree view

To make a tree view, you need to create a list, with sub lists and make sure your first parent list has the .ink-tree-view class.

To add a small state icon, indicating if a node is opened or closed, you need to add an empty <span> in the corresponding list element. The Javascript will write the correct icon into that <span> as required.

To make your lists expand and collapse, make sure you envelop each interactive node in and anchor element with an empty href, like so: <a href="">.

Finally, you can indicate whether each node starts out closed, which is the default, or open, for which you need to simply add the .open class in the corresponding <li>.

If you check the example below, you'll see how the lists are nested, with the first branch being open by defult, then, hit the view source code button to get it. Keep reading below for more details and configurations.

Example

<ul class="ink-tree-view">
  <li class="open"><span></span><a href="#">root</a>
    <ul>
      <li><a href="">child 1</a></li>
      <li><span></span><a href="">child 2</a>
        <ul>
          <li><a href="">grandchild 2a</a></li>
          <li><span></span><a href="">grandchild 2b</a>
            <ul>
              <li><a href="">grandgrandchild 1bA</a></li>
              <li><a href="">grandgrandchild 1bB</a></li>
            </ul>
          </li>
        </ul>
      </li>
      <li><a href="">child 3</a></li>
    </ul>
  </li>
</ul>
<script>
    // There are two ways to run the code...
    // 1 - If you know you have the component and its dependencies already loaded, just do:
    var treeview = new Ink.UI.TreeView( '.ink-tree-view' );

    // 2 - If you're not sure the component or its dependencies are loaded at runtime, do:
    Ink.requireModules( ['Ink.UI.TreeView_1'], function(TreeView){
        new TreeView( '.ink-tree-view' );
    });
</script>

Configurable data attributes

If by any chance you need the functionality of a tree view, with expandable and collapsible branches, but can't use a list, you can still create a functioning structure by using two data-attributes that will define which are the trigger elements and which are the interactive children.

  • data-node Identifies which of your elements are considered nodes, that can be expanded and collapsed. Value must be a valid CSS selector. The default value is li, meaning you don't need this attribute if you're using a nested list. Example: data-node=".myNode"
  • data-child Identifies which of your elements are condidered children elements within your structure. value must be a valid CSS selector. The default value is ul, meaning you don't need this attribute if you're using a nested list. Example: data-node=".myChild"

Note If you need to build a tree view with elements other than lists, then you will not benefit from Ink's defaul styling for this component and you'll have to add your own style.

Specifications and other examples, available in the technical documentation.

Sortable List

Skip to the code

The Sortable List component allows the user to reorder items on a list, by dragging and dropping.

Necessary JS modules

Before you begin, make sure you're including the necessary Javascript inside your <head>, you'll need ink.js, ink.modal.js and autoload.js to initialize the module automatically.

Code

<script type="text/javascript" src="/js/ink.min.js"></script>
<script type="text/javascript" src="/js/ink.sortablelist.js"></script>
<script type="text/javascript" src="/js/autoload.js"></script>

If you opted for not using the autoload feature, then you'll need to initialize the Modal component by hand. Simply include the following code, at the end of your page, before the closing <body>

Code

<script>
    // There are two ways to run the code...
    // 1 - If you know you have the component and its dependencies already loaded, just do:
    var sortablelist = new Ink.UI.SortableList( '.ink-sortable-list' );

    // 2 - If you're not sure the component or its dependencies are loaded at runtime, do:
    Ink.requireModules( ['Ink.UI.SortableList_1'], function(SortableList){
        new SortableList( '.ink-sortable-list' );
    });
</script>

Building a sortable list

Making a sortable list is as easy as using a class. Build a <ul> with the .ink-sortable-list class, and you're set. By default, your <li> elements can be dragged and their order changed by the user.

If you need your sortable list to work differently, check the configurable attributes after the example. Click the view source code button to get a functional snippet.

Example

  • drag hereFirst element
  • drag hereSecond element
  • drag hereThird element

<ul class="unstyled ink-sortable-list" id="slist" data-instance="sortableList9">
    <li><span class="ink-label info"><i class="icon-reorder"></i>drag here</span>primeiro</li>
    <li><span class="ink-label info"><i class="icon-reorder"></i>drag here</span>segundo</li>
    <li><span class="ink-label info"><i class="icon-reorder"></i>drag here</span>terceiro</li>
</ul>
<script>
    // There are two ways to run the code...
    // 1 - If you know you have the component and its dependencies already loaded, just do:
    var sortablelist = new Ink.UI.SortableList( '.ink-sortable-list' );

    // 2 - If you're not sure the component or its dependencies are loaded at runtime, do:
    Ink.requireModules( ['Ink.UI.SortableList_1'], function(SortableList){
        new SortableList( '.ink-sortable-list' );
    });
</script>

Configurable data attributes

  • data-drag-object Allows you to set which element is draggable. Default is <li>, can be set to any CSS selector. Example: data-drag-object=".myClass".

If you check the example code above, you'll see we created a "drag here" label and made that the draggable element with data-drag-object=".ink-label"

Check our technical documentation for further configuration.

Date Picker

Skip to the code

The date picker component adds a flyout calendar to a textbox, within a form, so your users can just click the box and pick a date, visually, instead of having to guess the date format or you having to print specific instructions to explain that format.

Using the date picker also guarantees that you get your dates in the format you need, without extra form validation.

Necessary JS modules

Before you begin, make sure you're including the necessary Javascript inside your <head>, you'll need ink.js, ink.datepicker.js and autoload.js.

Code

<script type="text/javascript" src="/js/ink.min.js"></script>
<script type="text/javascript" src="/js/ink.datepicker.js"></script>
<script type="text/javascript" src="/js/autoload.js"></script>

If you opted for not using the autoload feature, then you'll need to initialize the component by hand. Simply include the following code, at the end of your page, before the closing <body>

<script>
    // There are two ways to run the code...
    // 1 - If you know you have the component and its dependencies already loaded, just do:
    var datepicker = new Ink.UI.DatePicker( '.ink-date-picker' );

    // 2 - If you're not sure the component or its dependencies are loaded at runtime, do:
    Ink.requireModules( ['Ink.UI.DatePicker_1'], function(DatePicker){
        new DatePicker( '.ink-date-picker' );
    });
</script>

Getting started

Creating a date picker couldn't be easier. All you need is a text input in your form, tagged with the .ink-datepicker class. And that is all.

Like other Ink Javascript components, the date picker is configurable by using data-attributes, which we will detail below. For now, let's see what your code should look like. Remember, you are within a form, so go read up on Ink forms, if you need to.

Code

<input type="text" id="date" class="ink-datepicker">

That is the basic of basics for getting a date picker, but there is a more complete example below, grab the code by hitting the view code button. Then, you can read up on all the ways you can configure your date picker, using data-attributes.

<div class="control-group">
    <label for="dPicker">A date field:</label>
    <div class="control">
        <input id="dPicker" class="ink-datepicker" type="text"></input>
    </div>
</div>
<script>
    // There are two ways to run the code...
    // 1 - If you know you have the component and its dependencies already loaded, just do:
    var datepicker = new Ink.UI.DatePicker( '.ink-date-picker' );

    // 2 - If you're not sure the component or its dependencies are loaded at runtime, do:
    Ink.requireModules( ['Ink.UI.DatePicker_1'], function(DatePicker){
        new DatePicker( '.ink-date-picker' );
    });
</script>

Using the calendar

The calendar has some really useful features you might want to be aware of. On the top left corner you have a link to clear the input box, in case you've entered a wrong date, and on the top right, you can click to close the calendar.

On the next line, you have navigation chevrons on either side, that will allow you to navigate by month and in the center, you can click either the month name to directly pick another month, or the year, to pick a different year, without having to navigate by hand to those dates. When you click a day, the date gets written into the input field. Just click the above example and try it out.

Configurable data attributes

To further configure your date picker, just add data-attributes to your text input field. Here's a comprehensive list of all the attributes you can use on the date picker.

  • data-format sets the date format which will be written into the text input and submitted with the form. The default value is data-format="yyyy-mm-dd" but there are many different options as you can see below:

    • yyyy-mm-dd - Ex: 2013-07-29 (default)
    • yyyy/mm/dd - Ex: 2013/07/29
    • yy-mm-dd Ex: 13-07-29
    • yy/mm/dd Ex: 13/07/29
    • dd-mm-yyyy - Ex: 29-07-2013
    • dd/mm/yyyy - Ex: 29/07/2013
    • dd-mm-yy Ex: 29-07-13
    • dd/mm/yy Ex: 29/07/13
    • mm-dd-yyyy - Ex: 07-29-2013
    • mm/dd/yyyy - Ex: 07/29/2013

  • data-position specifies where the calendar will appear, relative to the input field. Example: data-position="bottom". Possible values are:

    • bottom
    • left

  • data-css-class sets a class for the calendar. The default value is data-css-class="sapo_component_datepicker", but you can change it to any class you need to use in your project to style the calendar.

  • data-start-date sets a start date, that will be selected when you open the calendar. It must be defined in the following format: yyyy-mm-dd. Example: data-start-date="2013-01-01"

There are other configurations, some specific for Javascript, available on the technical documentation.

Tabs

Skip to the code

The Tabs Component offers a simple way to build a tab-separated layout, allowing you to offer multiple content in the same space with intuitive navigation.

Necessary JS modules

Before you begin, make sure you're including the necessary Javascript inside your <head>, you'll need ink.js, ink.tabs.js and autoload.js to initialize the module automatically.

Code

<script type="text/javascript" src="/js/ink.min.js"></script>
<script type="text/javascript" src="/js/ink.modal.js"></script>
<script type="text/javascript" src="/js/autoload.js"></script>

If you opted for not using the autoload feature, then you'll need to initialize the Tabs component by hand. Simply include the following code, at the end of your page, before the closing <body>

Notice that, in this particular case, when initializing the module, you'll have to declare which tab is active on load and which aren't, by using their respective indexes.

Code

<script>
    // There are two ways to run the code...
    // 1 - If you know you have the component and its dependencies already loaded, just do:
    var tabs = new Ink.UI.Tabs( '.ink-tabs',{
        disabled: ['#stuff', '#more_stuff'], 
        active: '#news',
        onBeforeChange: function(tab){
            console.log('beforeChange', tab);
        }, 
        onChange: function(tab){
            console.log('Changed', tab);
        }
    });

    // 2 - If you're not sure the component or its dependencies are loaded at runtime, do:
    Ink.requireModules( ['Ink.UI.Tabs_1'], function(Tabs){
        new Tabs( '.ink-tabs',{
            disabled: ['#stuff', '#more_stuff'], 
            active: '#news',
            onBeforeChange: function(tab){
                console.log('beforeChange', tab);
            }, 
            onChange: function(tab){
                console.log('Changed', tab);
            }
        });
    });
</script>

Building tabs

To make a tabbed view, you'll need a block element with the .ink-tabs class, such as a <div>, within which you'll have a <ul> for your tabbed navigation and a set of <div> elements to hold the content of each tab. Your .ink-tabs element should also have a class to determine where the navigation will be in relation to the content: .top, .bottom, .left or .right

The <ul> must have the .tabs-nav class and each list element must be wrapped in an anchor pointing to a valid ID in the content of the tabs.

Each of the <div> holding the content, must have the .tabs-content class and an ID that matches the navigation anchors.

If you're making a tabbed view with tabs on top, on the left or on the right, put the navigation first in your markup, if you need the tabs at the bottom, then, put the content first and the navigation after.

Examples of each and a full code snippet will follow, but for now, let's look at an example code, just to clarify everything.

Example Code

<div class="ink-tabs top"> <!-- Creates a tabbed view with top nav -->
  <ul class="tabs-nav">
    <li><a href="#item1">Item 1</a></li> <!-- Points to item 1 below -->
    <li><a href="#item2">Item 2</a></li> <!-- Points to item 2 below -->
    ...
  </ul>
  <div id="item1" class="tabs-content"> <!-- Item 1 -->
    ... <!-- Your tab content here -->
  </div>
  <div id="item2" class="tabs-content"> <!-- Item 2 -->
    ... <!-- Your tab content here -->
  </div>
  ...
</div>

Example With top navigation

Shotgun

The shotgun fires once every 500ms. It fires 6 pellets per attack, and each pellet does 4 damage, making for a maximum possible damage of 24. Pellets are arranged in a random pattern around the crosshair.

Range is 2048 units.

The shotgun is a hitscan weapon; when the attacker fires, traces are performed to see what the player is aiming at, in that very same frame. There are no moving projectiles.

Nailgun

The nailgun is a projectile weapon; projectile weapons fire actual objects with a finite speed.

The nailgun may fire every 100ms. Nails travel at 1000ups, and dissappear after 6 seconds if they haven't hit anything.

Nails do 9 damage per hit, and are fired alternatively from 5u left of the crosshair, then 5u right of the crosshair. Nails are a point.

Rocket Launcher

The rocket launcher may fire every 800ms. Like nails, rockets travel at 1000ups, and are not affected by gravity. A direct hit by a rocket does a random amount of damage between 100 and 120 (or fixed 110 in KTX).

All hits, direct or not, do 120 splash damage (over a 160u radius, like the grenade launcher), however objects that are hit directly are immune to this splash damage.

This avoids making the rocket launcher too destructive.

Lightning Gun

The lightning gun fires every 100ms. It has a range of 600u, and is a hitscan weapon. It does 30 damage per hit, and may damage up to 3 damagable objects in that 600u range per hit.

When fired underwater in deathmatch mode 3, the lightning gun does (35 x number of cells in gun) splash damage, with the firer as the centre. The radius is the damage (35 x cells), plus 40.

A few rules change in DMM4. Discharging only works a random 50% of the time, the rest of the time you do 4000 damage to yourself only. Additionally, the lightning gun is disabled when you obtain Quad.

Shotgun

The shotgun fires once every 500ms. It fires 6 pellets per attack, and each pellet does 4 damage, making for a maximum possible damage of 24. Pellets are arranged in a random pattern around the crosshair.

Range is 2048 units.

The shotgun is a hitscan weapon; when the attacker fires, traces are performed to see what the player is aiming at, in that very same frame. There are no moving projectiles.

Nailgun

The nailgun is a projectile weapon; projectile weapons fire actual objects with a finite speed.

The nailgun may fire every 100ms. Nails travel at 1000ups, and dissappear after 6 seconds if they haven't hit anything.

Nails do 9 damage per hit, and are fired alternatively from 5u left of the crosshair, then 5u right of the crosshair. Nails are a point.

Rocket Launcher

The rocket launcher may fire every 800ms. Like nails, rockets travel at 1000ups, and are not affected by gravity. A direct hit by a rocket does a random amount of damage between 100 and 120 (or fixed 110 in KTX).

All hits, direct or not, do 120 splash damage (over a 160u radius, like the grenade launcher), however objects that are hit directly are immune to this splash damage.

This avoids making the rocket launcher too destructive.

Lightning Gun

The lightning gun fires every 100ms. It has a range of 600u, and is a hitscan weapon. It does 30 damage per hit, and may damage up to 3 damagable objects in that 600u range per hit.

When fired underwater in deathmatch mode 3, the lightning gun does (35 x number of cells in gun) splash damage, with the firer as the centre. The radius is the damage (35 x cells), plus 40.

A few rules change in DMM4. Discharging only works a random 50% of the time, the rest of the time you do 4000 damage to yourself only. Additionally, the lightning gun is disabled when you obtain Quad.

Example With bottom navigation

Shotgun

The shotgun fires once every 500ms. It fires 6 pellets per attack, and each pellet does 4 damage, making for a maximum possible damage of 24. Pellets are arranged in a random pattern around the crosshair.

Range is 2048 units.

The shotgun is a hitscan weapon; when the attacker fires, traces are performed to see what the player is aiming at, in that very same frame. There are no moving projectiles.

Nailgun

The nailgun is a projectile weapon; projectile weapons fire actual objects with a finite speed.

The nailgun may fire every 100ms. Nails travel at 1000ups, and dissappear after 6 seconds if they haven't hit anything.

Nails do 9 damage per hit, and are fired alternatively from 5u left of the crosshair, then 5u right of the crosshair. Nails are a point.

Rocket Launcher

The rocket launcher may fire every 800ms. Like nails, rockets travel at 1000ups, and are not affected by gravity. A direct hit by a rocket does a random amount of damage between 100 and 120 (or fixed 110 in KTX).

All hits, direct or not, do 120 splash damage (over a 160u radius, like the grenade launcher), however objects that are hit directly are immune to this splash damage.

This avoids making the rocket launcher too destructive.

Lightning Gun

The lightning gun fires every 100ms. It has a range of 600u, and is a hitscan weapon. It does 30 damage per hit, and may damage up to 3 damagable objects in that 600u range per hit.

When fired underwater in deathmatch mode 3, the lightning gun does (35 x number of cells in gun) splash damage, with the firer as the centre. The radius is the damage (35 x cells), plus 40.

A few rules change in DMM4. Discharging only works a random 50% of the time, the rest of the time you do 4000 damage to yourself only. Additionally, the lightning gun is disabled when you obtain Quad.

Shotgun

The shotgun fires once every 500ms. It fires 6 pellets per attack, and each pellet does 4 damage, making for a maximum possible damage of 24. Pellets are arranged in a random pattern around the crosshair.

Range is 2048 units.

The shotgun is a hitscan weapon; when the attacker fires, traces are performed to see what the player is aiming at, in that very same frame. There are no moving projectiles.

Nailgun

The nailgun is a projectile weapon; projectile weapons fire actual objects with a finite speed.

The nailgun may fire every 100ms. Nails travel at 1000ups, and dissappear after 6 seconds if they haven't hit anything.

Nails do 9 damage per hit, and are fired alternatively from 5u left of the crosshair, then 5u right of the crosshair. Nails are a point.

Rocket Launcher

The rocket launcher may fire every 800ms. Like nails, rockets travel at 1000ups, and are not affected by gravity. A direct hit by a rocket does a random amount of damage between 100 and 120 (or fixed 110 in KTX).

All hits, direct or not, do 120 splash damage (over a 160u radius, like the grenade launcher), however objects that are hit directly are immune to this splash damage.

This avoids making the rocket launcher too destructive.

Lightning Gun

The lightning gun fires every 100ms. It has a range of 600u, and is a hitscan weapon. It does 30 damage per hit, and may damage up to 3 damagable objects in that 600u range per hit.

When fired underwater in deathmatch mode 3, the lightning gun does (35 x number of cells in gun) splash damage, with the firer as the centre. The radius is the damage (35 x cells), plus 40.

A few rules change in DMM4. Discharging only works a random 50% of the time, the rest of the time you do 4000 damage to yourself only. Additionally, the lightning gun is disabled when you obtain Quad.

Example With left navigation

Shotgun

The shotgun fires once every 500ms. It fires 6 pellets per attack, and each pellet does 4 damage, making for a maximum possible damage of 24. Pellets are arranged in a random pattern around the crosshair.

Range is 2048 units.

The shotgun is a hitscan weapon; when the attacker fires, traces are performed to see what the player is aiming at, in that very same frame. There are no moving projectiles.

Nailgun

The nailgun is a projectile weapon; projectile weapons fire actual objects with a finite speed.

The nailgun may fire every 100ms. Nails travel at 1000ups, and dissappear after 6 seconds if they haven't hit anything.

Nails do 9 damage per hit, and are fired alternatively from 5u left of the crosshair, then 5u right of the crosshair. Nails are a point.

Rocket Launcher

The rocket launcher may fire every 800ms. Like nails, rockets travel at 1000ups, and are not affected by gravity. A direct hit by a rocket does a random amount of damage between 100 and 120 (or fixed 110 in KTX).

All hits, direct or not, do 120 splash damage (over a 160u radius, like the grenade launcher), however objects that are hit directly are immune to this splash damage.

This avoids making the rocket launcher too destructive.

Lightning Gun

The lightning gun fires every 100ms. It has a range of 600u, and is a hitscan weapon. It does 30 damage per hit, and may damage up to 3 damagable objects in that 600u range per hit.

When fired underwater in deathmatch mode 3, the lightning gun does (35 x number of cells in gun) splash damage, with the firer as the centre. The radius is the damage (35 x cells), plus 40.

A few rules change in DMM4. Discharging only works a random 50% of the time, the rest of the time you do 4000 damage to yourself only. Additionally, the lightning gun is disabled when you obtain Quad.

Shotgun

The shotgun fires once every 500ms. It fires 6 pellets per attack, and each pellet does 4 damage, making for a maximum possible damage of 24. Pellets are arranged in a random pattern around the crosshair.

Range is 2048 units.

The shotgun is a hitscan weapon; when the attacker fires, traces are performed to see what the player is aiming at, in that very same frame. There are no moving projectiles.

Nailgun

The nailgun is a projectile weapon; projectile weapons fire actual objects with a finite speed.

The nailgun may fire every 100ms. Nails travel at 1000ups, and dissappear after 6 seconds if they haven't hit anything.

Nails do 9 damage per hit, and are fired alternatively from 5u left of the crosshair, then 5u right of the crosshair. Nails are a point.

Rocket Launcher

The rocket launcher may fire every 800ms. Like nails, rockets travel at 1000ups, and are not affected by gravity. A direct hit by a rocket does a random amount of damage between 100 and 120 (or fixed 110 in KTX).

All hits, direct or not, do 120 splash damage (over a 160u radius, like the grenade launcher), however objects that are hit directly are immune to this splash damage.

This avoids making the rocket launcher too destructive.

Lightning Gun

The lightning gun fires every 100ms. It has a range of 600u, and is a hitscan weapon. It does 30 damage per hit, and may damage up to 3 damagable objects in that 600u range per hit.

When fired underwater in deathmatch mode 3, the lightning gun does (35 x number of cells in gun) splash damage, with the firer as the centre. The radius is the damage (35 x cells), plus 40.

A few rules change in DMM4. Discharging only works a random 50% of the time, the rest of the time you do 4000 damage to yourself only. Additionally, the lightning gun is disabled when you obtain Quad.

Example With right navigation

Shotgun

The shotgun fires once every 500ms. It fires 6 pellets per attack, and each pellet does 4 damage, making for a maximum possible damage of 24. Pellets are arranged in a random pattern around the crosshair.

Range is 2048 units.

The shotgun is a hitscan weapon; when the attacker fires, traces are performed to see what the player is aiming at, in that very same frame. There are no moving projectiles.

Nailgun

The nailgun is a projectile weapon; projectile weapons fire actual objects with a finite speed.

The nailgun may fire every 100ms. Nails travel at 1000ups, and dissappear after 6 seconds if they haven't hit anything.

Nails do 9 damage per hit, and are fired alternatively from 5u left of the crosshair, then 5u right of the crosshair. Nails are a point.

Rocket Launcher

The rocket launcher may fire every 800ms. Like nails, rockets travel at 1000ups, and are not affected by gravity. A direct hit by a rocket does a random amount of damage between 100 and 120 (or fixed 110 in KTX).

All hits, direct or not, do 120 splash damage (over a 160u radius, like the grenade launcher), however objects that are hit directly are immune to this splash damage.

This avoids making the rocket launcher too destructive.

Lightning Gun

The lightning gun fires every 100ms. It has a range of 600u, and is a hitscan weapon. It does 30 damage per hit, and may damage up to 3 damagable objects in that 600u range per hit.

When fired underwater in deathmatch mode 3, the lightning gun does (35 x number of cells in gun) splash damage, with the firer as the centre. The radius is the damage (35 x cells), plus 40.

A few rules change in DMM4. Discharging only works a random 50% of the time, the rest of the time you do 4000 damage to yourself only. Additionally, the lightning gun is disabled when you obtain Quad.

Shotgun

The shotgun fires once every 500ms. It fires 6 pellets per attack, and each pellet does 4 damage, making for a maximum possible damage of 24. Pellets are arranged in a random pattern around the crosshair.

Range is 2048 units.

The shotgun is a hitscan weapon; when the attacker fires, traces are performed to see what the player is aiming at, in that very same frame. There are no moving projectiles.

Nailgun

The nailgun is a projectile weapon; projectile weapons fire actual objects with a finite speed.

The nailgun may fire every 100ms. Nails travel at 1000ups, and dissappear after 6 seconds if they haven't hit anything.

Nails do 9 damage per hit, and are fired alternatively from 5u left of the crosshair, then 5u right of the crosshair. Nails are a point.

Rocket Launcher

The rocket launcher may fire every 800ms. Like nails, rockets travel at 1000ups, and are not affected by gravity. A direct hit by a rocket does a random amount of damage between 100 and 120 (or fixed 110 in KTX).

All hits, direct or not, do 120 splash damage (over a 160u radius, like the grenade launcher), however objects that are hit directly are immune to this splash damage.

This avoids making the rocket launcher too destructive.

Lightning Gun

The lightning gun fires every 100ms. It has a range of 600u, and is a hitscan weapon. It does 30 damage per hit, and may damage up to 3 damagable objects in that 600u range per hit.

When fired underwater in deathmatch mode 3, the lightning gun does (35 x number of cells in gun) splash damage, with the firer as the centre. The radius is the damage (35 x cells), plus 40.

A few rules change in DMM4. Discharging only works a random 50% of the time, the rest of the time you do 4000 damage to yourself only. Additionally, the lightning gun is disabled when you obtain Quad.

<div class="ink-tabs top"> <!-- replace 'top' with 'bottom', 'left' or 'right' to place navigation -->
    
    <!-- put navigation first if using top, left or right positioning -->
    <ul class="tabs-nav">
        <li><a href="#home">Home</a></li>
        <li><a href="#news">News</a></li>
        <li><a href="#description">Description</a></li>
        <li><a href="#stuff">Stuff</a></li>
        <li><a href="#more_stuff">More stuff</a></li>
    </ul>
    
    <!-- Put your content second if using top, left or right navigation -->
    <div id="home" class="tabs-content"><p>Content</p></div>
    <div id="news" class="tabs-content"><p>Content</p></div>
    <div id="description" class="tabs-content"><p>Content</p></div>
    <div id="stuff" class="tabs-content"><p>Content</p></div>
    <div id="more_stuff" class="tabs-content"><p>Content</p></div>
    <!-- If you're using bottom navigation, switch the nav block with the content blocks -->

</div>
<script>
    // There are two ways to run the code...
    // 1 - If you know you have the component and its dependencies already loaded, just do:
    var tabs = new Ink.UI.Tabs( '.ink-tabs',{
        disabled: ['#stuff', '#more_stuff'], 
        active: '#news',
        onBeforeChange: function(tab){
            console.log('beforeChange', tab);
        }, 
        onChange: function(tab){
            console.log('Changed', tab);
        }
    });

    // 2 - If you're not sure the component or its dependencies are loaded at runtime, do:
    Ink.requireModules( ['Ink.UI.Tabs_1'], function(Tabs){
        new Tabs( '.ink-tabs',{
            disabled: ['#stuff', '#more_stuff'], 
            active: '#news',
            onBeforeChange: function(tab){
                console.log('beforeChange', tab);
            }, 
            onChange: function(tab){
                console.log('Changed', tab);
            }
        });
    });
</script>

Configurable Data Attributes

As with most Ink JS components, you can add extra features to the tabs via data attributes. Check the following list for attributes you can add to your .ink-tabs <div>

  • data-prevent-url-change Prevents the URL from being changed when navigating between tabs. Value must be boolean, "true" (default) or "false". Example: data-prevent-url-change="false"
  • data-active Allows specifying which of the tabs is open by default. Value must be an ID present in the markup structure of the tabs. Example: data-active="#secondItem"

You can see several examples in the technical documentation.

Draggables

You can have elements which can be dragged around by your user.

Example

Drag me

Code

<div id="drag1">
    Drag me
</div>
<script type="text/javascript">
    Ink.requireModules(['Ink.UI.Draggable_1'], function (Draggable) {
        new Draggable('drag1', {
            revert: false
        });
    });
</script>

Options

Draggable options:

  • constraint Movement constraint. None by default. Can be either vertical or horizontal.
  • top top limit for the draggable area
  • right right limit for the draggable area
  • bottom bottom limit for the draggable area
  • left left limit for the draggable area
  • handler if specified, only this element will be used for dragging instead of the whole target element
  • revert if true, reverts the draggable to the original position when dragging stops
  • cursor cursor type used over the draggable object
  • zindex zindex applied to the draggable element while dragged
  • fps if defined, on drag will run every n frames per second only
  • droppableProxy if set, a shallow copy of the droppableProxy will be put on document.body with transparent bg
  • mouseAnchor defaults to mouse cursor. can be 'left|center|right top|center|bottom'
  • dragClass class to add when the draggable is being dragged.
  • onStart callback called when dragging starts
  • onEnd callback called when dragging stops
  • onDrag callback called while dragging, prior to position updates
  • onChange callback called while dragging, after position updates

More details can be found in the technical documentation.

Droppables

You can have elements which can be dragged around by your user.

Example

Drag me

Drop it here

Code

<div id="drag2" class="acceptme">
    Drag me
</div>
<p>
    Drop it <b id="drop" class="success">here</b>
</p>
<script type="text/javascript">
    Ink.requireModules(['Ink.UI.Draggable_1', 'Ink.UI.Droppable_1'], function (Draggable, Droppable) {
        new Draggable('drag2', {
            revert: false
        });
        Droppable.add('drop', {
            hoverclass: 'ink-label',
            accept: 'acceptme'  // Accept any element with the "acceptme" class.
        });
    });
</script>

Options

Droppable options:

  • element target element
  • options options object
  • hoverclass Classname applied when an acceptable draggable element is hovering the element
  • accept Array or comma separated string of classnames for elements that can be accepted by this droppable
  • onHover callback called when an acceptable draggable element is hovering the droppable. Gets the draggable and the droppable element as parameters.
  • onDrop callback called when an acceptable draggable element is dropped. Gets the draggable, the droppable and the event as parameterse.

More details can be found in the technical documentation.

Tooltips

Tooltips are useful as a means to display information about functionality while avoiding clutter.

Example

What do you want to do now?

  • Talk
  • Fight
  • Run

Code

<h5>What do you want to do now?</h5>
<hr>
<ul>
    <li>
        <span class="tooltip"
            data-tip-text="Attempt to talk to this stranger"
            data-tip-where="up"
            data-tip-color="blue">
            Talk
        </span>
    </li>
    <li>
        <span class="tooltip"
            data-tip-text="Fight this person as an enemy"
            data-tip-where="mousemove"
            data-tip-color="red">
            Fight
        </span>
    </li>
    <li>
        <span class="tooltip"
            data-tip-text="This guy does not seem dangerous. But you can still run for your life."
            data-tip-where="mousefix"
            data-tip-color="orange">
            Run
        </span>
    </li>
</ul>

Hint You can use the [data-tip-text] selector instead of .tooltip above.

Options

You can define options either through the second argument to the Tooltip constructor, or as data-attributes in each target element. Options set through data-attributes all start with data-tip, and are prioritized over options passed into the Tooltip constructor.

Some options:

  • text: Text content for the tooltip.
  • where: Positioning for the tooltip. Can be 'up', 'down', 'left', 'right', 'mousemove' or 'mousefix':
  • color: Color of the tooltip. Options are red, orange, blue, green and black. Default is white.
  • fade: Fade time; Duration of the fade in/out effect.
  • forever: Set to 1/true to prevent the tooltip from being erased when the mouse hovers away from the target
  • timeout: Time for the tooltip to live. Useful together with [options.forever].
  • delay: Time the tooltip waits until it is displayed. Useful to avoid getting the attention of the user unnecessarily
  • template: Element or selector containing HTML to be cloned into the tooltips. Can be a hidden element, because CSS display is set to block.
  • templatefield: Selector within the template element to choose where the text is inserted into the tooltip. Useful when a wrapper DIV is required.

More details can be found in the technical documentation.

Form Validator

Skip to the code

The Form Validator component provides an easy way to validate forms before submitting them. It can:

  • Detect required fields
  • Validate some field types
  • Detect match with password and confirmation password
  • Use custom field types

Necessary JS modules

Before you begin, make sure you're including the necessary Javascript inside your <head>, you'll need ink.js and ink.formvalidator.js.

Code

<script type="text/javascript" src="/js/ink.min.js"></script>
<script type="text/javascript" src="/js/ink.formvalidator.js"></script>

Notice that, contrary to other modules, you don't really need to initialize the Form Validator, as the validation request is made on form submission.

Validating

There are two components that you need to use in order to validate a form using Ink. You'll have to request validation on form submission and you'll have to tag the input elements with certain classes to tell Ink what to validate.

So, start by building your form (make sure you read the sction on Forms), and add the bit of Javascript that tells Ink to do the validation in your <form>, like this:

<form class="ink-form" method="post" action="#" onsubmit="return Ink.UI.FormValidator.validate(this);">

Once you have the onsubmit attribute set, you need to 'tag' each of your input elements (text, radio buttons, select boxes, etc), with one or more validation classes. Refer to the following list to see what they do:

  • .ink-fv-required - Marks a field as required and checks if it has been filled/set.
  • .ink-fv-email - Checks if the form field value is a valid e-mail address.
  • .ink-fv-url - Checks if the form field value is a valid URL.
  • .ink-fv-number - Checks if the form field value is a number.
  • .ink-fv-phone_pt - Checks if the form field value is a valid Portugal phone number.
  • .ink-fv-phone_cv - Checks if the form field value is a valid Cape Verde phone number.
  • .ink-fv-phone_mz - Checks if the form field value is a valid Mozambique phone number.
  • .ink-fv-phone_ao - Checks if the form field value is a valid Angola phone number.
  • .ink-fv-date - Checks if the form field value is a valid date.
  • .ink-fv-confirm - A pair of form fields with this class will be checked to make sure the inputed values match.
  • .ink-fv-custom - Allows custom Javascript validation.

More examples and detailed configurations, in the technical documentation.

Please select one option

<form id="myform" class="ink-form" method="post" action="#" onsubmit="return Ink.UI.FormValidator.validate(this);">
    <fieldset>
        <div class="control-group required">
            <label for="name">Name:</label>
            <div class="control">
                <input type="text" name="name" id="name" class="ink-fv-required" />
            </div>
        </div>
        
        <div class="control-group required">
            <label for="mail">Email:</label>
            <div class="control">
                <input type="text" name="mail" id="mail" class="ink-fv-required ink-fv-email" />
            </div>
        </div>
        
        <div class="control-group required">
            <label for="pass">Password: </label>
            <div class="control">
                <input type="password" name="pass" id="pass" class="ink-fv-required ink-fv-confirm" />
            </div>
        </div>
        
        <div class="control-group required">
            <label for="confpass">Confirm Password:</label>
            <div class="control">
                <input type="password" name="confpass" id="confpass" class="ink-fv-required ink-fv-confirm" />
            </div>
        </div>
        
        <div class="control-group required">
            <p class="label">Please select one option</p>
            <ul class="control unstyled">
                <li><input type="radio" name="radio1" id="radio1_g" value="1" class="ink-fv-required" /> <label for="radio1_g">radio 1</label> </li>
                <li><input type="radio" name="radio1" id="radio2_g" value="2" class="ink-fv-required" /> <label for="radio2_g">radio 2</label> </li>
                <li><input type="radio" name="radio1" id="radio3_g" value="3" class="ink-fv-required" /> <label for="radio3_g">radio 3</label> </li>
            </ul>
        </div>
    </fieldset>
    <div>
        <input type="submit" name="sub" value="Submit" class="ink-button success" />
    </div>
</form>

Progress bar

Skip to the code

The progress bar component allows you to animate a progress bar using JavaScript. This component requires a knowledge of Javascript to read and write the events that will make the progress bar fill up.

Necessary JS modules

Before you begin, make sure you're including the necessary Javascript inside your <head>, you'll need ink.js, ink.progressbar.js and autoload.js to initialize the module automatically.

Code

<script type="text/javascript" src="/js/ink.min.js"></script>
<script type="text/javascript" src="/js/ink.progressbar.js"></script>
<script type="text/javascript" src="/js/autoload.js"></script>

If you opted for not using the autoload feature, then you'll need to initialize the Progress Bar component by hand. Simply include the following code, at the end of your page, before the closing <body>

Code

<script>
    // There are two ways to run the code...
    // 1 - If you know you have the component and its dependencies already loaded, just do:
    var progressbar = new Ink.UI.ProgressBar( '.ink-progress-bar' );

    // 2 - If you're not sure the component or its dependencies are loaded at runtime, do:
    Ink.requireModules( ['Ink.UI.ProgressBar_1'], function(ProgressBar){
        new ProgressBar( '.ink-progress-bar' );
    });
</script>

Building a progress bar

Ink gives you basic styles to create a progress bar to which you can apply the Javascript to obtain the animation based on a set value.

To create a bar, you need the outter shell, which is done with a <div> with the .ink-progress-bar class. Next, you'll need another <div> within the first one, with the .bar and a color class. Valid colors are .grey, .green, .blue, .red, .orange and .black.

You can also add some text to your progress bar, using a <span> with the .caption class.

Example

My Progress Bar

Code

<div class="ink-progress-bar">
  <span class="caption">My Progress Bar</span>
  <div class="bar red"></div>
</div>

You can configure where the bar begins (the default is an empty bar), using the data-start-value attribute, which must be an integer between 0 and 100, for example: data-start-value="50", produces a progress bar that starts half-full (or half empty, if you're a pessimist).

Besides that, the component provides - for those who code in Javascript - a public method for setting the value in runtime. The public method is setValue and accepts an integer, within the range 0-100. More info, see the source code example below.

<div class="ink-progress-bar" data-start-value="50%">
    <span class="caption">I am a red progress bar</span>
    <div class="bar red"></div>
</div>
<script>
    // There are two ways to run the code...
    // 1 - If you know you have the component and its dependencies already loaded, just do:
    var progressbar = new Ink.UI.ProgressBar( '.ink-progress-bar' );

    // 2 - If you're not sure the component or its dependencies are loaded at runtime, do:
    Ink.requireModules( ['Ink.UI.ProgressBar_1'], function(ProgressBar){
        new ProgressBar( '.ink-progress-bar' );
    });
</script>

For more examples and a list of all supported options, check our technical documentation.

Image Query

Skip to the code

The Image Query component allows you to load different versions of an image, depending on the viewport width. This is great when building for various devices, as you can load a smaller image for smaller screens and a bigger one for larger screens, meaning you'll save your users bandwidth on their mobile devices by loading an image which is appropriate for their screensize.

This component always loads the smaller image first, then, if it detects a larger screen width, it will load the appropriate, larger, image. This certifies that a smaller, probably mobile, device will get the small image.

The Image Query component is also Retina-screen ready, and can serve an image specifically prepared for those screens.

Tip You can use this component to serve up three different sizes of the same image, but you can also use it creatively to serve three different images, according to screen width. This allows for great creative flexibility.

Necessary JS modules

Before you begin, make sure you're including the necessary Javascript inside your <head>. This component works in a slightly different way and requires you to add some extra code. But don't fret, it's pretty simple.

Code

<script type="text/javascript" src="/js/ink.min.js"></script>
<script type="text/javascript" src="/js/ink.imagequery.js"></script>

Using the Image Query

To use this component, you need to declare your image as you normally would in HTML, and then reference it with Javascript and indicate where the alternative images are and at what screen widths they should be shown.

There are many ways you can reference your images with the component, but as an example, let's say you add an .imagequery class to your <img> element. Then, you can add a template-style bit of code that will take care of the rest, you just need to create a directory structure to hold your images and reference it in the code.

Let's start with the image.

Code

<img src="./imgs/small/image.png" class="imagequery"> <!-- Make sure you always load your small image first -->

Now, add the Javascript. See the following code for a commented example, and scroll down to the View Source Code button to get the functinal example show on this page.

Code

First create a new instance of the ImageQuery component referencing the CSS selector we used, in this case, the .imagequery class, can be any valid selector

<script type="text/javascript">
    var imagequery = new Ink.UI.ImageQuery('.imagequery',{        

Then, setup the template that will give ImageQuery the correct path for each image. {:label} will read whatever value you give label afterwards, {:file} will read the original filename and look for the same filename in each of the referenced directories.

In the example, ImageQuery will look in the ./imgs/ directory for a {:label} sub-directory, containing an image.png file.

src: './imgs/{:label}/{:file}',

Finally, we need to define each of the {:label} elements, according to our directory structure and declare the corresponding screen width.

queries: [
        {
            label: 'small',
            width: 480
        },
        {
            label: 'medium',
            width: 640
        },
        {
            label: 'large',
            width: 1024
        }
    ]
});
</script>

If you're using images for Retina Displays, then add an extra line, after the src: declaration, with a retina: declaration, indicating the path of that particular asset, for example:

src: './imgs/{:label}/{:file}', <!-- The original src declaration -->
retina: './imgs/retina/{:label}/{:file}', <!-- The retina declaration -->

This works independent of screen size, because we detect whether or not you have a retina display.

Example

Below, you can see how different images are being loaded according to your screen width. Hit the Show Source Code button to get the fully functional example.

<img src="http://imgs.sapo.pt/ink/assets/imgs/imagequery/small/image.jpg" class="large-100 medium-100 small-100 vspace imagequery"/>

<script type="text/javascript">
    Ink.requireModules( ['Ink.UI.ImageQuery_1'], function( ImageQuery ){
        var tv1 = new Ink.UI.ImageQuery('.imagequery',{
            src: 'http://imgs.sapo.pt/ink/assets/imgs/imagequery/{:label}/{:file}',
            retina: 'http://imgs.sapo.pt/ink/assets/imgs/imagequery/retina/{:file}',
            queries: [
                {
                    label: 'small',
                    width: 480
                },
                {
                    label: 'medium',
                    width: 640
                },
                {
                    label: 'large',
                    width: 1024
                }
            ]
        });
    });
</script>

More specifications and other examples, available in the technical documentation.

Behaviors

Dismiss

This behavior allows you to dismiss an element from your markup by using a class in a child element. It's used for closing Modal Windows as well as Alerts in Ink, but you can use it to remove any parent container from your document.

Necessary JS modules

Before you begin, make sure you're including the necessary Javascript inside your <head>, you only need ink.js for the dismiss behavior and there is no intialization needed.

Code

<script type="text/javascript" src="/js/ink.min.js"></script>

Using Dismiss

To use dismiss, simply add a child element to the one you want dismissed, and give it the .ink-dismiss class.

Example

Click the × below, to dismiss the notification, using the Dismiss behavior.

This is a simple notification

Code

<div class="ink-alert basic info">
    <button class="ink-dismiss">&times;</button>
    <p>This is a simple notification</p>
</div>

Check the technical documentation for more details, and read the Alerts section to see more examples like the one above.

Spy

The Spy behavior looks for a specified element to see if it's visible in the viewport and changes a second element to an active state. You can see this working in the side menu in medium and large screens: as you scroll past each section, its corresponding link in the menu becomes highlighted.

Necessary Javascript Modules

Before you begin, make sure you're including the necessary Javascript inside your <head>, you'll need ink.js, ink.spy.js and autoload.js to initialize the module automatically.

Code

<script type="text/javascript" src="/js/ink.min.js"></script>
<script type="text/javascript" src="/js/ink.spy.js"></script>
<script type="text/javascript" src="/js/autoload.js"></script>

If you opted for not using the autoload feature, then you'll need to initialize the Spy behavior by hand. Simply include the following code, at the end of your page, before the closing <body>

Code

<script>
  var spyObj = new Ink.UI.Spy('#mySpy');
</script>

Using Spy

Spy is used in long pages with anchors linked from a menu. So you'll begin by building your menu, with each item pointing to a specific id down the page. To learn how to build menus with Ink, read the Navigation section, for the sake of example, we'll use an ultra-simplified model.

You jsut need to build your menu, using and use a unique ID, such as #myMenu in the example below.

Code

<nav class="ink-navigation" id="myMenu">
   <ul class="menu">
      <li><a href="#section1">Item 1</a></li>
      <li><a href="#section2">Item 2</a></li>
   </ul>
</nav>

Notice how each item points to a specific ID. Now, we build our content and identify each section with corresponding IDs, making them "spyable". First, you need to identify the begining of the section (in the example we used the <section> element, but this can be any element), with an ID that corresponds to one item in your menu, in our case: #section1 and #section2.

Then, you need to add two data-attributes to the section element:

  • data-spy Marks the element as spyable, value must be boolean (true or false). Example: data-spy="true"
  • data-target Identifies the menu where the links to the sections are located. Must be a CSS selector. Example data-target="myMenu"

Code

<section data-spy="true" data-target="myMenu" id="section1">
    <p>Your content here</p>
</section>
<section data-spy="true" data-target="myMenu" id="section2">
    <p>More content here</p>
</section>

Check the technical documentation for more details.

<nav class="ink-navigation" id="myMenu">
   <ul class="menu">
      <li><a href="#section1">Item 1</a></li>
      <li><a href="#section2">Item 2</a></li>
   </ul>
</nav>

<section data-spy="true" data-target="myMenu" id="section1">
    <p>Your content here</p>
</section>
<section data-spy="true" data-target="myMenu" id="section2">
    <p>More content here</p>
</section>

Sticky

The Sticky behavior keeps an element "stuck" as you scroll the rest of the page. The best example is the side menu on this website, if you see it in medium or large screens.

Necessary Javascript Modules

Before you begin, make sure you're including the necessary Javascript inside your <head>, you'll need ink.js, ink.sticky.js and autoload.js to initialize the module automatically.

Code

<script type="text/javascript" src="/js/ink.min.js"></script>
<script type="text/javascript" src="/js/ink.sticky.js"></script>
<script type="text/javascript" src="/js/autoload.js"></script>

If you opted for not using the autoload feature, then you'll need to initialize the Sticky behavior by hand. Simply include the following code, at the end of your page, before the closing <body>

Code

<script>
  var stickyObj = new Ink.UI.Sticky('#myDiv');
</script>

Using Sticky

It couldn't be easier to use Sticky: just add the .sticky class on any block level element and it will stick, remaining in sight as you scroll.

There are a few configurable options, to make Sticky more useful, to use them, just add the necessary data-attribute to the block level element you wish to make stiky. Here's a list.

  • data-top-element - Specifies an element the sticky object must be aware of when scrolling to the top of the page. Must be a CSS selector. Default is value is body. Example: data-top-element="body"
  • data-bottom-element - Specifies an element the sticky object must be aware of when scrolling to the bottom of the page. Must be a CSS selector. Default is body. Example: data-top-element="body"
  • data-offset-top - Defines an offset, in pixels, that the sticky object must respect, relative to the data-top-element. Must be a number and unit combination. Example: data-offset-top="50px"
  • data-offset-bottom - Defines an offset, in pixels, that the sticky object must respect, relative to the data-bottom-element. Must be a number and unit combination. Example: data-offset-bottom="50px"

Check the technical documentation for more details.

<div id="myDiv" data-offset-top="20px" data-offset-bottom="20px" class="sticky">
    <p>Your content here</p>
</div>

Toggle

The Toggle behavior allows to easily show and hide elements using another element as trigger. It's used and explained in-depth in the Navigation > Dropdowns section and a good example is the View Source Button in this page, that shows/hides the full code examples.

Necessary Javascript Modules

Before you begin, make sure you're including the necessary Javascript inside your <head>, you'll need ink.js, ink.toggle.js and autoload.js to initialize the module automatically.

Code

<script type="text/javascript" src="/js/ink.min.js"></script>
<script type="text/javascript" src="/js/ink.toggle.js"></script>
<script type="text/javascript" src="/js/autoload.js"></script>

If you opted for not using the autoload feature, then you'll need to initialize the Toggle behavior by hand. Simply include the following code, at the end of your page, before the closing <body>

Code

<script>
  var toggleObj = new Ink.UI.Toggle( '#myButton' );
</script>

Using Toggle

You need two elements to use toggle: the trigger element, and the element you want to show and hide with that trigger.

The first one needs a .toggle class and the data-target attribute set to the ID of the element it will toggle.

The second one needs to have its ID set to that same value. If you want the element to start off hidden, you also need to add the .hide-all class.

So, here's a button showing and hiding a div

Example

Here's my togglable content

Code

<button class="toggle" data-target="#myContent">Toggle</button>
<div class="hide-all" id="myContent">
  <p>Here's my togglable content</p>
</div>

You can configure some attributes of the Toggle behavior, by adding any of the following to the trigger element:

  • data-target - Sets which element is to be shown/hidden. Must be a CSS selector. Example: data-target="#myStuff"
  • data-trigger-event - Defines which event will trigger the toggle. Must be a valid event type, default value is click. Example: data-trigger-event="mousedown". Possible values are:
    • click
    • mousedown
    • mouseup
    • dblclick
    • mouseover
    • mouseover
  • data-close-on-click - Defines whether or not the togglable element changes state when the user clicks anywhere outside the trigger element. Must be a boolean value (true or false), default is true. Example: data-close-on-click="false"

Check the technical documentation for more details.