TopOfMind Project Template


You've succesfully configured the TopOfMind Project Template! Now you can start building your brand-new website with all the TopOfMind-goodies included!

What is Project Template?

The TopOfMind Project Template is a collection of frequently-used code snippets already combined in a website structure. Let's say you want to build a website on a new webserver, but you don't have the time to setup the basic files. That's where Project Template comes in handy! Most default actions are already included:

  • Check the PHP-server configuration for errors in compatibility
  • Assign cookies and load correct XML-database for multiple languages
  • Load correct page, based on the SEO-friendly link and the XML-entry
  • Show an Old Browser screen, forcing users with ancient browsers to update their system
  • Load most recent CSS- and JS-files (forcing to empty the cache only when the files have changed)
  • Normalize stylesheets out-of-the-box
  • Generate standard files via .htaccess and PHP, while removing the clutter in your root-folder (ex: custom 404-page, robots.txt, humans.txt, crossdomain.xml, sitemap.xml, ...)
  • Automatically download the most recent Modernizr-script for your new project.
  • Create fool-proof forms with built-in validation that send pretty HTML-mails to your clients.
  • Use JEET to create grids with ease, without all the nesting and 12 columns rules other grid-systems seem to require.
  • Automatically creates a sitemap.xml-file every two weeks. Checks every link, image and PDF-file and adds it to the sitemap.
  • Takes care of multilingual websites, by easily adding language selectors and creating fool-proof links automatically.
  • ...

If the above sounds like Chinese to you: feel free to study some HTML in your spare time.

Just to be clear: this is not a UI framework (like Bootstrap), nor is it the definitive guide on how a website should be built. It's tailored specifically to our needs, and features a greatest hits compilation of code snippets we seem to use on every project to date. Depending on what you need to make and your current workflow, the Project Template may make your life harder or easier.

How can I use Project Template?

In the menu (on your left side) you can find more information about each part of the Project Template. Just click on the topic of your choice and be ready to be overwhelmed with information. Let's say 'Initialisation' is a good place to start :).


First things first: if you can view this page, several options have already been configured correctly. We'll still take a look at each option and the correct workflow.

1. Installation

Installation requires you to copy the files, setup MAMP PRO (for local development), Codekit (for code preprocessing) and Sublime Text (for easy coding).

  • Copy the entire content of the Project Template folder to your development folder.
  • In MAMP PRO:
    • Go to the Hosts-tab and click the '+'-sign at the bottom of the Server name-list
    • Set your server name ( and enter 80 as the Port Number.
    • Click the folder-icon near 'Document Root' and point it to the HTML-folder inside the Project Template-folder.
    • Click Save.
  • In Codekit (Mac OSX only, sorry Windows lovers):
    • Set the HTML-directory as the base for a new project. Set the following options:
    • General Settings: set an icon and the project name
    • Browser Refreshing: enable the External Server and enter the address created in MAMP PRO
    • Frameworks: make sure the TopOfMind Framework v3 is added as a Codekit Framework
  • For Sublime Text:
    • Rename HTML/_development/ProjectTemplate.sublime-project and ProjectTemplate.sublime-workspace to the correct project name.
    • Open RenamedFile.sublime-project with Notepad (or any other simple text editor) and set the "path"-variables to the correct directories. For more information: see the comments in that file.
    • Start Sublime Text and go to Project > Open Project, and select the RenamedFile.sublime-project. Your project should open and the folders on your left should contain a bunch of files in them.

2. Configuration

Configuring Project Template is as easy as taking a look at each file in the project and tweaking it to your wish.

  • Root folder: open index.php in your Sublime Text Project. Only take a look at the top defined variables:
    • $aTaalkeuze is an array with all available languages in. If you add (for example) 3 languages, these must also exist as XML-files in the XML-directory. This is mandatory!
    • $aGoogleWebfonts is an array with all Google Webfonts in. Enter the string that is generated after the ...css?family= code on the Google Fonts website. If you don't add anything, no Google Fonts will be used.
    • $sGoogleAnalyticsCode is your Google Analytics ID (UA-XXXXXXX-XX). If you don't have any yet, leave the string empty and no Analytics will be loaded.
  • Assets folder: contains all standard scripts. There is no need to change anything in here.
  • Img folder: contains all images. Feel free to change your favicon-files (more on that later), Old Browser-logo and Facebook Share Image.
  • PHP folder: contains the editable PHP-scripts. Let's take a look:
    • content_pagename.php : each page must have a content-file linked to it. To do this, create a 'content_pagename.php'-file in this directory (change 'pagename' to something else of course) and open your XML-files. in <base><content> add a new tag with the exact name as your page (minus the 'content_' and '.php' part). Now visit that page in your browser (via the address specified in MAMP PRO, example: et voilà!
    • page_metatags.php : change the metatags used by your website. Check the comments for settings about Mobile Viewports, Facebook Sharing Options and FavIcons.
    • page_modernizr.php : change $sVersionType to 'development' or 'production'. In short: the development version is the complete most-up-to-date script, while the production version should only contain what you need and is version-locked. This is important, so check the comments for more information.
    • page_title.php : set the address bar title for each page. Since you can work with multiple levels (ex:, you need to assign a title manually to each section.
  • XML folder: contains the database and several control points for the website.

Built-in PHP Functions

An overview of the functions found in the assets/PHP/globalFunctions.php-file, supplied to each page.


Returns a valid internal or external link. For external links a check is made if the link starts with 'http(s)://' or not. Internal links are converted for use with the language selector. If a site has more than one language, this function automatically adds the current selected language to the link. For sites with only one language, the initial link is passed back.
Example: addLink('products/category') => "/nl/products/category" addLink('') => ""

addTaalkeuze($aTaalkeuze, $sSeparator);

Creates a standard language choice element, which lists all available languages. The language that is currently selected cannot be clicked, while the other languages have a link that changes the website language. Add an array with all language and the separation icon (optional). The current language is automatically picked from a Global variable.
Example: addTaalkeuze(array('NL, FR, EN'), '-') = NL-FR-EN


Eliminated stubborn cache-problems. Sometimes the webbrowser keeps on loading an older version of your CSS- or JS-files. This function adds the last-modification date for sFileName to the filename, so we are sure we are loading the most recent file. app.js?20150115_1542 loads differently than app.js20150110_1001. Files that haven't been changed keep the same modification date, so the advantages of caching are still valid.
Example: cacheBuster('CSS/stylesheet.css') = "CSS/stylesheet.css?2010123_1258"


Gets the relative path from your current PHP-file to the root of the website. Handy in some cases where you need a PHP script to find a find relative to the root, and not to the server.
Example: getRootPath() = "" (if value is empty = index.php is situated on the root of the site)


Gets the current website address. Handy in some cases where you want to find out on what domain the PHP-script is running. Also detects the difference between a HTTP- and HTTPS-address.
Example: getSiteAddress() = ""

toAscii($sString, $aReplace , $sDelimiter);

Converts any $sString to a basic URL-friendly string. You can set the $sDelimiter optionally, if you don't like dashes between your words.
Example: toAscii('Olé Olà') = "ole-ola"

Built-in CSS Styles

An overview of the pre-styled elements present in the Framework.

@include placeholder { }

SCSS/SASS mixin that defines special CSS-styles for your placeholder text. The placeholder text is used by form-elements to tell what kind of input is needed by automatically entering an example or description into the field.
Usage example:
@include placeholder {
  text-transform: uppercase;
  color: blue;

@include word-break

SCSS/SASS mixin that breaks all words that do not fit into the layout. For example, on mobile versions of websites, some long web addresses can break the layout (forcing horizontal scrollbars etc.). Use this mixin to split the address right where the layout/container ends. This split will not take in account any grammatical rules, and automatically adds a hyphen where necessary!
Usage example:
@include word-break;


The screen that pops up when you have an outdated internet browser doesn't need to be styled separately, it's included in the template. You only have to add a logo, put it in the img/oldbrowser-folder and add the link to the XML-files.

Built-In Javascript Functions

An overview of the special JavaScript functions included in the Framework.


Receives an amount of bytes in nSize and converts it to a better notation.
Example: convertNumberToBytes(987654321) = "941,90 MB"


Looks for every <a>-tag, checks the target destination and opens the link in the same or a new window:

  • If the target is internal (= in the same website/domain), the link is opened in the same browser window.
  • If the target is external (= points to another website), the link is opened in a new browser window/tab.
  • If the attribute data-target is specified on the <a>-tag, this overrides the original target behaviour:
    • data-target='external' : forces the link to open in a new window.
    • data-target='internal' : forces the link to open in the same window.


Creates a smooth scrolling animation to the desired position on the webpage. The function searches for each .smoothscroll-class in your document and adds an onclick()-function. When you click:

  • The function searches for the value in your href-attribute (for <a>-elements). Just use a jQuery-selector (like #index .container div) and the animation will take you to that position.
  • The function searches for the value in the data-target-attribute (for <button>, <div>, ...-elements. As before, just just a jQuery-selector and the animation will do the magic.

tomFramework.initContactForm($form, sMailProcessorPath)

Initialises the contact form. Requires the jQuery-selector to the form and a string containing the path to the mail processor PHP-file. More information about the TopOfMind Mail Template can be found in another section. Includes following functions that you do not need to worry about:

  • checkFormValidation($form) : before sending your form, this function checks all <input> and <textarea>-elements for errors. If no errors are found, the sendMail()-function is launched. The following attributes can be added to each <input> and <textarea>-element:
    • data-required='true' : mandatory input. If nothing is entered, an error is returned.
    • data-minchar='nNumber' : only if data-required='true' : if the number of characters is less than nNumber an error is returned.
    • type='email' : processes the input as an email-address. If anything is wrong with the email-address (no @-sign, no end dot, ...), an error is returned.
    • data-confirm='true' : only if an element with type='email' already exists : compares the value of the original input-element with this value. If the values do not match, an error is returned.
  • sendMail($form, sMailProcessorPath) : after validation, this function sends the mail. It disables the submit-button, adds the correct language-parameter and puts all the form data in one big string before sending it to the mail processor PHP script. If anything goes wrong, you'll get notified.


Checks the document for .unselectable-classes and adds CSS, JavaScript and HTML-attributes to make sure the content cannot be selected. This can be handy for <div>-elements that function as a button (for example).


Uses Modernizr to detect if the browser supports placeholder text for your <input> and <textarea>-elements. If it doesn't, it uses JavaScript to dynamically mimic it.


Checks a variety of Modernizr attributes and standard HTML-classes to determine if the browser is capable of showing this website. sVersion can be the highest Internet Explorer version ("ie7", "ie8", "ie9") that you do not offer support for.
Example: showOldBrowserSupport("ie7") will show a message to each user using Internet Explorer 7 (or lower), telling them that they need to upgrade their system before visiting the website.

The Grid System

Together with Jeet Grid System, the Project Template also supports an easy-to-apply grid system. The basic principle is that you assign a fraction (1/2, 1/4, ...) to an element so that element will be transformed into a grid with that fraction relative to the parent container.
Jeet allows you to create your page grid the same way a human would read it. No more needlessly nesting elements, no more rigid twelve column rules, ... Less code + more flexibility = one happy coder!
Some examples in SCSS:

col(nRatio = 1, nOffset = 0, nCycle = 0, nUncycle = 0, nGutter = 3)

Specify an initial nRatio in fractions or decimals and the element will set its width to that ratio relative to the width of the parent container.
Add an optional nOffset in fractions to add an extra margin left (positive value) or right (negative value).
nCycle defines the maximum amount of items in one row. Use this if you (for example) want to divide an amount of items that are 1/4 wide over an undefined amount of rows, while each row has a maximum of 4 items.
nUncycle is used if you want to undo your previous cycle and append a new one: col(1/4, 0, 2, 4): unsets the previous cycle of 4 items per row, and adds a new cycle of only 2 items per row (maybe usable for a mobile version of the element).
Need to adjust the gutters for a specific container? Use nGutter. IMPORTANT: this value must be in percentages (without the %-sign), not fractions! The difference with nOffset is that nOffset is applied to each element (each element has an offset), while nGutter only applies to the gutter (the only or last element do not have a gutter). Also, your initial ratio is the gutter + the element; while the offset is added to the initial ratio. See the example + source code for a better look.

  • @include col(1);
  • @include col(1/2);
    @include col(1/2);
  • @include col(1/3);
    @include col(1/3);
    @include col(1/3);
  • @include col(1/4, -1/6);
    @include col(1/3, 1/6);
  • Item 1
    @include col(1/4, 0, 4);
    Item 2
    @include col(1/4, 0, 4);
    Item 3
    @include col(1/4, 0, 4);
    item 4
    @include col(1/4, 0, 4);
    Item 5
    @include col(1/4, 0, 4);
    Item 6
    @include col(1/4, 0, 4);
    Item 7
    @include col(1/4, 0, 4);
    Item 8
    @include col(1/4, 0, 4);
    Item 9
    @include col(1/4, 0, 4);
    Item 10
    @include col(1/4, 0, 4);
  • @include col(1/3, 0, 0, 0, 20);
    @include col(1/3, 0, 0, 0, 20);
    @include col(1/3, 0, 0, 0, 20);

span(nRatio = 1, nOffset = 0)

Need a simple colomn-based structure without worrying about gutters and cycles? Use span().
Define the initial nRatio to divide the grid and set an optional nOffset to add an extra margin left or right.
See col() for more information about this behaviour.

  • @include span(1/2);
    @include span(1/2)
  • @include span(1/3, 1/3);
    @include span(1/3);

shift(nRatioPosition = 0, sColSpan = col, nGutter = 3)

Use shift() to reposition elements relative to their current position.
In the example below, item1, item2 and item3 are defined sequentially but they are displayed as item2, item3 and item1.
First, setup the standard col()- or span()-functions. Then, follow that statement with the shift()-function:
nRatioPosition places the position on that ratio relative to the position it had. In our example: item1 needs to move 2 spaces, to position 3. It's current position is the first of the three elements (1/3) and it needs to go to the last of the three elements (3/3). As nRatioPosition we need 2/3 (since 1/3 + 2/3 = 3/3). Same as the second element (2/3), it must go to the first position (1/3), so we enter -1/3 (2/3 - 1/3 = 1/3). To be complete, for the third element (3/3), that needs to go to the second place (2/3) we also use -1/3 as the value (3/3 - 1/3 = 2/3).
sColSpan is a string value where you can optionally change the colomn/span behaviour (= use extra gutter, or not). Usually, you'll use the same value as you've defined before. Only accepts col or span.
Add an optional nGutter, just make sure your gutter sizes matches the gutter sizes of your original elements.(no idea as of yet why you should use this...)

  • item1
    @include col(1/3);
    @include shift(2/3, col);
    @include col(1/3);
    @include shift(-1/3, col);
    @include col(1/3);
    @include shift(-1/3, col);


unshift() is a helper function that disables any form of source ordening (via shift()) you've done, and reverts the element back to the original position.

  • item1
    @include col(1/3);
    @include shift(2/3, col);
    @include unshift();
    @include col(1/3);
    @include shift(-1/3, col);
    @include unshift();
    @include col(1/3);
    @include shift(-1/3, col);
    @include unshift();

edit(sColor = gray)

Edit mode is perfect for developing your structure. It assigns a gray, semi-transparent background to every element on the page.
To change the default color to something else, use sColor and enter a different color (standard string or hexadecimal value).

  • @include edit(#00FF00);

center(nWidth = 1410px, nPadding = 0px)

Need to center a container? Just add the center-function and all is well!
nWidth is the width (in pixels!) you want the element to have.
Add nPadding in pixels to include some padding to the element.

  • @include center(300px)
  • @include center(300px, 75px)

stack(nPadding = 0px, sAlign = center)

An easy way so stack elements on top of each other. The following example creates a 3 colomn-grid, but then stacks the elements. This can be handy in mobile applications where the screen is smaller and elements are ordened vertically instead of horizontal.
To add some padding left and right, add a nPadding-value in pixels.
sAlign doesn't really do anything I think... To change the default center-align, you'll need to add text-align: left !important it seems...

  • @include span(1/3);
    @include stack(100px, left);
    @include span(1/3);
    @include stack(200px, right);
    @include span(1/3);
    @include stack(0px, center);


Cancel that previous stack!
Important: this does not revert the element back to it's previous layout (col()- or span()-calls are ignored). Manually call your layout method again!

  • @include span(1/3);
    @include stack();
    @include unstack();
    @include span(1/3);
    @include span(1/3);
    @include stack();
    @include unstack();
    @include span(1/3);
    @include span(1/3);
    @include stack();
    @include unstack();
    @include span(1/3);

align(sDirection = both))

Align a block relative to a parent container. Only applies to a parent container that has position: relative, or else you'll see some groovy results.
sDirection shows what to align, standard both is used, so the element is aligned vertically and horizontally.

  • @include align();
  • @include align(vertical);
  • @include align(horizontal);


A clearfix, use this to wrap any set of col() or span(). Handy to force a new row, away from the grid. No idea how this exactly works for the moment...

  • @include col(1/2);
    @include col(1/4);
    @include col(1/4);

The Mail Template

Our Mail Template is a handy little something that eliminates the need to program the same %$&# forms over and over again. We've made it easy: the only thing you need to do is fill in some XML-fields and apply some CSS-styles to your liking. Once set, you just call createEmailForm('formname', 'optionalextraclasses') in PHP, and tomFramework.initContactForm($('#form_formname'), sPathToMailProcessorFile); in JS and you are set! The function will look at the <mailserver>-node with matching id='formname'-attribute in your XML file and magically create all input fields (including validation) for your page. Add as many mailforms as you like, as long as you use seperate 'formname'-id-values. When clicking the send-button, all fields are checked for correct input (like email addresses) and everything is sent to Mister Mail Processor. He will take care of a correct HTML-layout and send the mail to everyone that wants it!
See, simple!

Working example

Error: no corresponding mailserver (#template') ID found in XML
Contact your webmaster to fix this!

But how do I set it up?

As we said: simple!
Open up your XML-file and scroll down to the <extra><mailserver>-node. Here you'll find the following:

  • <input>: add nodes that make up your form. Check the source code for the Working Example below.
    • nodeName: the unique name of the form element. Your form will have an id "form_nodeName".
    • @description (optional): a separate field with a description of the form input ("Enter your email address").
    • @minchar (optional | textarea, textinput, email only): if required="true": the least amount of characters the textfield must have before it can be sent.
    • @placeholder (optional | textarea, textinput, email only): this is the placeholder text in a textfield.
    • @required: 'true' or 'false' if you want validation for this field. If 'true', textboxes must have text and email fields must have a valid email address in them.
    • @type: the type of the form element. Choose between textinput (a small textfield), textarea (a larger textarea), email (a small textfield, used only for email addresses), checkbox (a collection of checkboxes), radiobutton (a collection of radiobuttons) and select (a dropdown list of possible values).
    • <confirmation /> (optional | email only): add node to element to generate an extra email input field that asks for an email address again. Both fields will be compared for the exact same content before the form is sent. Handy if you want to make sure your users have entered a correct email address.
      • @required="true": add to force validation of this mailaddress and to compare it to the original value of the other input.
      • @description: a separate field with a description of the form input ("Confirm your email address").
    • <option /> (optional | checkbox, radiobuttons and select only): add a bunch of these nodes to the original node to add checkboxes/radiobuttons/select options in a group.
      • @description: the text that is shown next to the checkbox/radiobutton
    • <submitbutton />: creates a button that sends the form to the mail processor. Add this as the last node to the <input>-node.
      • @title: the text inside the button.
    • <separator />: creates an empty <span class='separator' />-element which you can style in CSS as a separator between form parts.
  • <response>: setup custom feedback messages for when a mail is sent, attention is required or if an error occurs.
    • <sent>: when the message is sent succesfully.
    • <notsent>: when something went wrong and the message hasn't been sent.
    • <required>: when mandatory fields haven't been filled in as required.
    • <faultymail>: when an email address isn't correct.
    • <noconfirmmail>: when the email address and the confirmation address do not match.
    • <nohtml>: when the recipient cannot process HTML-emails and a simplified version of the mail is shown.
  • <message>: setup custom colors and text for the email that will be sent.
    • @backgroundColor: sets the general background color for the email message. Please note that not all email programs show a general background-color. Also important is that the main message will always be black(ish) text on a white background.
    • @lightTextColor: the disclaimer and short content are shown on the background specified in @backgroundColor, so those texts can have another color to match that background color.
    • <title>: the subject of the mail and the title of the message.
    • <shortcontent>: summary of your message, is used by some email software so you quickly know what the mail is about.
    • <header>: the path to a header image, must be 600 pixels wide and must be found on the sending server. Example: <fileitem>img/mail_topofmind.jpg</fileitem>.
    • <introduction>: the introduction text, added before the content of the mail form. A great way to thank the user and tell them their mail is being looked at. Optionally, add some text in a <span />-tag to create some smaller text (as a footnote).
  • <disclaimer>: the boring legal stuff no one will ever read.
    • <copyright>: just the word 'copyright' in the correct language.
    • <text>: the disclaimer text
    • <reason>: a litte explanation about why someone has received this email (in case someone else used their mailaddress).
    • <company>: 'Our company information' in the correct language.

The Backstage

The Backstage is our nifty little backend solution to keep your website up to date at all times! Add images, rearrange product categories, remove unwanted news items, edit company information, ... The Backstage does it all!

  • One Backstage to rule them all! All Backstages are connected to one general system. The great thing about this is that when one Backstage gets an update or bugfix, all Backstages get this at the same time!
  • Easy image upload and cropping tool. If an image doesn't have the correct size, a handy cropping tool appears for you to select what part of the image you want to use in the website.
  • Automatic error and user logging. An administrator gets an overview of every little thing the user has been experiencing. Handy for finding those pesky bugs!
  • Automatic database backup. You never know when disaster strikes and the server goes offline while saving your precious database. Of maybe you've deleted an important part of your website? Give us a call and we'll reset the database back to any previous value (less than a month old).
  • Set restriction-levels for an element (level0-items cannot be seen by level1-users, etc...)
  • Automatic generation of unique filenames: if you upload a file that already exists (= has the same name), a random value will be added to that filename. This way, no images are ever deleted without your permission!
  • And so much more...

So how does it work?

Fire up your favorite XML-editor and open up backstage/XML/driver.xml. Inside, you'll find a bunch of XML-nodes:

<init />

  • <language />: set the basic language for the app.
    • @value: enter a language code to set the Backstage to that language (only "EN" is supported for now).
  • <background />: what background should be used?
    • @type: "local" uses all files found in the directory found defined in @dir, while "bing" takes the daily image found on the Bing-website (mostly nice nature pictures).
    • @dir: if @type is set to "local", the Backstage will look up a directory of files and assign one each day as background image. This path must be relative to (which means that all images must be stored on that server).
  • <client />: for which client is the Backstage?
    • @client: the client code in the TopOfMind Address Book. This value will make sure the correct client logo's are loaded automatically.
  • <brand />: some branding options.
    • @name: the name of the app (Backstage / Menu Generator / etc...)
    • @title: the complete title of the app.
    • @welcome: the little welcome-text on the login screen.

<content />

  • <onderdeel name="Welcome" icon="welcome" />
    A menu item. An endless amount of these nodes can be added. Each Onderdeel-node placed directly inside the Content-node will be shown on the menu at startup. If you place an Onderdeel-node inside another Onderdeel-node, that first Onderdeel will function as a submenu. You can go on and on, and keep putting Onderdeel-nodes inside other Onderdeel-nodes as sub-sub-submenu's (but beware: you CAN, what doesn't mean you SHOULD, since space inside the menu is limited!).
    • @name: the name shown in the menu.
    • @icon (optional): the name of the icon that can be used next to the menu name. The values can be found in the TopOfMind Icon directory, find the files starting with 'menu-' and use the value after that prefix. Upload new icons to that directory and you can use them in every project.
    • <infopanel title="Big title" supertitle="Small subtitle" />
      An extra panel with help and information. It is mandatory to include these for first-level panels (meaning: right after an Onderdeel-node and before a Panel-node). Only add Line- and Text-nodes tot this panel.
      • @title: the big title on the top of the Infopanel.
      • @supertitle: the little title right underneath the big one.
    • <panel title="Big title" supertitle="Small subtitle" size="normal" />
      The part where all the magic happens. Each panel can be filled with all sorts of tools (more on that below), but is mostly made up out of informative text, input fields, upload containers, lists and save buttons.
      • @title: the big title on the top of the Infopanel.
      • @supertitle: the little title right underneath the big one.
      • @size: choose the width of your panel, possible values are normal (default value: 315 pixels wide), extended (a bit wider: 400 pixels wide) and small (tiny panel: 280 pixels wide).
    • <frame source="generator/index.php" />
      Shows an externally loaded iFrame with a custom page in it, so you can add external data to your Backstage (like the amount of downloads for a file, or a separate PHP-script for generating PDF-files, ...).
      • @source: the path to the page that needs to be loaded, relative to the Backstage-folder.

Some terms and definitions

- The breadcrumb system

Traversing through an XML-file is done by the breadcrumb system. Not unlike the fairy tale featuring Tom Thumb, we use little parts of the XML-structure to find our way through the file. There are three types of crumbs:

  • "content,index,welcome,text": each value is a normal string. This means every value can be found as an XML-node name. If we fire up the XML-file, we'll find the node <content /> as a first-level node. The node <index /> will be one of its children, which will have <welcome /> as a child, etc., etc., ... . The <text />-node will be our final destination and (depending on which tool is used) will contain the value we'll need to edit.
  • "content,product,@title": each value is again a normal string, but the final item has the @-sign in front of it. This means we are editing an attribute. In the example, we're traversing to the <product />-node and looking up the title-attribute of that node. Attributes should only contain basic information and cannot contain line breaks or special characters.
  • "content,product,item,4,@keyword": one of the values is a number. This only applies to nodes that have multiple identically named children (here: <product> has at least 5 children named <item />). The number is array-based, so the first value is addressed by using 0, the third item by 2 and the tenth item by 9. The example here goes to <content /> and finds multiple <item />-objects inside the <product />-child. We take the fifth (!) object and read the keyword-attribute.

- Separate languages

Each tool has the ability to add multiple instances for each language available. If your website has 3 languages (for example) you can add the "separatelang='true'"-attribute to your tool to automatically add extra textfields/checkbox/buttons for each language. If you don't use the attribute, only one instance will be shown in the Backstage and that value will be applied to each language-file.

- External content

Some tools (ex. the Checkbox, Selectbox) have the ability to include external content. In short, this means that the Backstage can load an external XML-file and find different values than those mentioned in the driver.xml-file. This way, dynamic data can be added and you don't have to update the driver-file for each addition to a list.
Take a look at an example:

  • <checkbox>
        <multi title="Belgium,Germany,France" values="BE,DE,FR" separatelang="false" default="BE" crumb="@countries"/>
        <externalcontent path="/XML/countries.xml" title="kolom > land[name],@name" values="kolom > land > code, *"/>
    </checkbox >

    If the externalcontent-node is present, the website loads the file found in the path-attribute. Then it replaces each corresponding attribute with new values. In this example both the title- and values-attributes from the original checkbox-element are overwritten by the results found in the new XML-file. These values are built-up by using 2 parts, separated by a comma. The first part (ex: kolom > land[name]) uses a jQuery selector (in this case: inside each kolom-node, find all land-nodes that have an attribute name). If the second part starts with an @-sign, the value of the attribute with that name is used, otherwise the text inside the found node is used. All found values are combined in a comma-separated string. The result is that a dynamic Multi Checkbox is built, featuring as much checkboxes as there are results found in that XML-file.

Another example:

  • <selectbox title="Toestelnamen" values="Toestel ID-nummers" separatelang="false" default="" crumb="type" required="false">
        <externalcontent path="/XML/NL.xml" title="toestel > naam,*" values="toestel > id,*"/>
    </selextbox >

    Here we connect to the same XML-file the website loads up, but we search for every machine name and ID-value and present them in a selection box.

The Toolbox

Every possible tool that can be used in the Backstage (in the Panel-node) is listed here. Use and combine them as you like! Click on the Code Sample to view the options of each tool.

  • <button type='save' title='Save changes' />
    Add a button, and set the button type depending on the function it needs to have. Add this as the very last item from the toolbox (since it's a bit weird to have a 'Save'-button in the middle of your editable options).
    • @type: set the button type:
      • "save": use in a <panel />: button will save changes.
      • "listadd": use in a <list />: show new panel to add new item to list.
      • "listedit": use in a <list />: show panel to edit current item.
      • "listdelete": use in a <list />: delete selected item from list.
    • @title: (optional) replaces the default value (ex. 'Save', 'Add', ...) of button title.
  • <checkbox />
    Shows one or multiple clickable checkboxes with a title
    • <checkbox>
          <single title="Show on site?" separatelang="false" default="true" crumb="@showonsite"/>

      Single checkbox: contains only one title and returns a true or false statement for each box
      • @title: the title of the checkbox.
      • @separatelang: true or false, should each language have a separate value, or can all languages use one and the same value?
      • @default: true or false, should the item be checked by default or not? (only for new items)
      • @crumb: the path from the last crumb-item to the value that needs to be edited.
        • Externalcontent possible.
    • <checkbox>
          <multi title="Nederland,Duitsland,België,Frankrijk" values="NL,DE,BE,FR" separatelang="false" default="BE,NL" required="true" crumb="home,@countries"/>

      Multi checkbox: contains multiple checkboxes and returns a string containing only the checked values (ex.: if "Duitsland" and "België" are checked, "DE,BE" is returned)
      • @title: a comma-separated list of the titles each checkbox will have.
      • @values: a comma-separated list with the value each title should have. *Important*: the amount of items in @values and @title must be the same!
      • @separatelang: true or false, should each language have a separate value, or can all languages use one and the same value?
      • @default: a comma-separated list containing only the values that should be checked. (only for new items)
      • @required: should the item have at least one element checked?
      • @crumb: the path from the last crumb-item to the value that needs to be edited.
        • Externalcontent possible.
  • <colorpicker title="Font color" required="true" separatelang="true" crumb="@kleur" output="hex0x" default="#FFFFFF" />
    Ability to change a color value by editing the value in a textfield, or launch a color spectrum and pick a common color.
    • @title: the main title of the object.
    • @required: true or false, determines if a value is required before saving the database.
    • @separatelang: true or false, should each language have a separate value, or can all languages use one and the same value?
    • @crumb: the path from the last crumb-item to the value that needs to be edited.
    • @output: the way the value needs to be formatted:
      • "hex0x": hex-value with '0x' as start (ex. '0xFF0000').
      • "hex#": hex-value with '#' as start (ex. '#FF0000').
    • @default: the default value for new objects (follow @output for format!)
  • <datepicker title="Start date" separatelang="true" crumb="home,startdate,@date" default="today" startyear="1940" endyear="+50" output="DD.MM.YYYY" />
    Choose a day, month and year from a couple of drop-down boxes and output the date to a string.
    • @title: the main title of the object.
    • @separatelang: true or false, should each language have a separate value, or can all languages use one and the same value?
    • @crumb: the path from the last crumb-item to the value that needs to be edited.
    • @default: the default value for new items:
      • "today": today's date is used.
    • @startyear: the first year in the year picker:
      • "1940": use an exact year.
      • "-50": use a year relative to the current year.
      • "": the default value: the current year - 20 years.
    • @endyear: the last year in the year picker:
      • "2020": use an exact year.
      • "+50": use a year relative to the current year.
      • "": the default value: the current year + 10 years.
    • @output: the way the result string should be written:
      • "DD.MM.YYYY": Day.Month.Year-format (ex. '25.02.2014').
  • <idbox crumb="@idbox" />
    An invisible text field, containing a unique 8-digit number. Use this to add some hidden ID-numbers to your elements. Once the element is made, the value cannot be changed again.
    • @crumb: the path from the last crumb-item to the value that needs to be edited.
  • <line />
    A dividing line, separating content blocks. Use this to create some structure in your layout.
  • <linput title="Description" required="true" separatelang="true" crumb="info,omschrijving" cdata="true" restrict='euro'>
        <default><![CDATA[Default text value]]></default>
    </linput >

    Text input box for big text spread over multiple lines.
    • @title: the main title of the object.
    • @required: true or false, determines if a value is required before saving the database.
    • @separatelang: true or false, should each language have a separate value, or can all languages use one and the same value?
    • @crumb: the path from the last crumb-item to the value that needs to be edited.
    • @cdata: true or false, should the value be written as <![CDATA[...]]>?
    • @restrict: (optional) check the input for certain required values:
      • "mail": only allow a valid emailaddress.
      • "number": only allow numbers.
      • "euro": only valid if value contains a Euro-sign (€).
    • <default>: contains the default text for new elements. Use *|* as a separator for multiple languages and place values in the same order as your language files (ex: <default><![CDATA[yes*|*ja*|*oui*|*jawul]]></default>).
  • <list crumb="content,login,item" namecrumb="@username" sortable="true" minitem="1" autosort="descend" addtotop="true">

    - An overview of matching items in a list. This element is followed by 1 to 3 possible buttons (listadd, listedit or listdelete) to add functionality to the elements of the list.
    - Inside a <list />-node is a <panel />-node. This panel will slide out if a new item is added or if an existing item is edited. This node and the included tools work exactly as before, only the @crumb-values start from the @crumb-value defined in this <list />.
    - If the items in the list have a @showonsite or showitem set to "false", the item will turn red in the list.
    • @crumb: the path from the last crumb-item to the values that need to be listed.
    • @namecrumb: the location to the name of the item in the list, starting from the @crumb-value of this list. Multiple values are possible, just separate them by a comma:
      • "@name": gets the name-attribute from each item in the list.
      • "@name,description": gets the attribute and adds a second value: the content of the description-node. Use multiple values to further define your item in the list.
      • "@name,[image,fileitem]": gets the attribute, and adds a second value by following the crumbs in the array: the value of the fileitem-node inside the image-node. Use the array notation if you need to go deeper into the XML-structure to create your title.
    • @sortable: "true" or "false", determines if the items in the list can be sorted or not. When sorting items, each change is saved intantly.
    • @minitem: enter the amount of minimal items mandatory. When deleting items, it's impossible to have less items that the number specified. "0" equals there is no minimum, "1" needs at least 1 item, etc., ...
    • @autosort: (optional) determine if the list should be sorted automatically. Every new item is added accordingly. Is only possible if @sortable=false and @overview=false. Sort by:
      • "ascend": the list is automatically sorted from A to Z.
      • "descend": this list is automatically sorted from Z to A.
    • @addtotop: (optional) "true" or "false", determines if a new item will be saved as the first item at the top of the list. Default value is "false".

    <list crumb="content,login,item" namecrumb="@username" overview="true" overviewcrumb="subcategory" overviewname="@name">

    A special version of the <list />-element: featuring main categories and subcategories in one list. Use this if you have a bunch of identical content featured over multiple nodes.
    • @overview: "true" or "false", declares the list as an Overview List.
    • @overviewcrumb: extra crumb that needs to be added to the current crumb to get the content of the subcategory. The standard @crumb just points to the main category.
    • @overviewname: like the normal @namecrumb, the location to the name of the subcategory, starting from wherever the @overviewcrumb ends.
  • <passinput title="Password" required="true" separatelang="false" crumb="@paswoord" cdata="true" restrict='' />
    A special case of the <sminput />-element. It's mostly the same, but the value is shown as stars ("****") unless you check the 'Show Password'-box. Then you can see the value as entered. All options for the <sminput />-element also apply here.
  • <radiobutton title="Status" separatelang="true" crumb="@status" values="For sale,For rent,Sold,Rented" default="Sold"/>
    Select one value from a set of multiple values.
    • @title: the main title of the object.
    • @separatelang: true or false, should each language have a separate value, or can all languages use one and the same value?
    • @crumb: the path from the last crumb-item to the value that needs to be edited.
    • @values: comma-separated list of the possible values that will be used.
    • @default: the default value for new objects (must be one of the @values!).
  • <selectbox title="Nalu,Coca-Cola,Fanta,Sprite,Dr. Pepper" values="nalu,cola,fanta,sprite,pepper" separatelang="false" default="sprite" crumb="@favoritebooze" required="true"/>
    Select one value from a set of multiple values. Somewhat the same as a radiobutton and checkbox, but the data is presented in a nice and compact selection box.
    • @title: the titles that you can choose between.
    • @values: the corresponding values that the titles are linked to. This is the value that will be written to the database.
    • @separatelang: true or false, should each language have a separate box, or can all languages use one and the same value?
    • @default: the default value for new objects (must be one of the @values!).
    • @crumb: the path from the last crumb-item to the value that needs to be edited.
    • @required: if false, an extra empty value will be added to the start of the element, so you have the ability to select 'nothing'.
      • Externalcontent possible.
  • <sminput title="Article number" required="true" separatelang="true" crumb="info,@number" cdata="false" restrict="number" default="100" />
    Text input box for small text that fits on one line.
    • @title: the main title of the object.
    • @required: true or false, determines if a value is required before saving the database.
    • @separatelang: true or false, should each language have a separate value, or can all languages use one and the same value?
    • @crumb: the path from the last crumb-item to the value that needs to be edited.
    • @cdata: true or false, should the value be written as <![CDATA[...]]>?
    • @restrict: (optional) check the input for certain required values:
      • "mail": only allow a valid emailaddress.
      • "number": only allow numbers.
      • "euro": only valid if value contains a Euro-sign (€).
    • @default: contains the default text for new elements. Use *|* as a separator for multiple languages and place values in the same order as your language files (ex: default="yes*|*ja*|*oui*|*jawul").
  • <switchselect title="Article Type" crumb="article,@type">
        <option title="meat">
        <option title="fish">

    Choose between multiple values & reveal content depending on that choice.
    • @title: the main title of the object.
    • @crumb: the path from the last crumb-item to the value that needs to be edited.
    • <option />: each choice the user can make:
      • @title: the value that will be written into the @crumb-value.
      • TOOL-nodes: fill each <option />-node with the tools from the toolbox. All options remain valid.
  • <text<![CDATA[...]]></text>
    A text output box, use it to display some more information or a welcome text. Nothing interactive about this element.
    • CDATA: Text that should be shown.
  • <title<![CDATA[Permissions
    Set permissions for the client to download documents.]]></title>

    A title (and optional text) to add between input elements.
    • CDATA: Text, the first line will be used as a TITLE in uppercase, while the remaining lines are optional information (in normal case).
  • <upload title="Main Image" required="true" separatelang="true" crumb="pictures,image" minitem="1" maxitem="5" type="image" forcesize="true,500,1000" filepath="JPG/" sortable="true" />
    Adds a button that, when clicked, opens a new Gallery-panel with a grid of every image/document uploaded.
    • @title: the main title of the object.
    • @required: true or false, determines if there is at least one item uploaded before saving the database.
    • @separatelang: true or false, should each language have a separate value, or can all languages use one and the same value?
    • @crumb: the path from the last crumb-item to the value that needs to be edited.
    • @minitem: the minimum amount of items that needs to be uploaded.
    • @maxitem: the maximum amount of items that can be uploaded. If "0" is entered, there is no limit to the uploads.
    • @type: the type of document that can be uploaded:
      • "image": only upload images, check the image size and enable the Cropping-tool .
      • "document": any document type can be uploaded.
    • @forcesize: (only if @type="image") set if an image needs a specific size:
      • "false": no resizing is needed, the entire image is uploaded.
      • "width,700": the width of the image will be resized to 700 pixels wide.
      • "height,200": the height of the image will be resized to 200 pixels high.
      • "true,700,200": the image will be resized proportionally to 700 pixels wide and 200 pixels high. If the image doesn't have those dimensions, a cropping tool will be shown where the user can select what part of the image needs to be cut and resized.
    • @filepath: the path to where the files are saved, relative to the root of the website. If the directory does not exist, a new one will be created. If the file already exists, a new filename will be generated (no files are ever overwritten).
    • @sortable: "true" or "false", determines if the user is in control of the order of the files.
  • <weblink title="Website link" required="true" separatelang="false" crumb="content,contact,link" cdata="true" type="internal" />
    Add an internal or external website link.
    • @title: the main title of the object.
    • @required: true or false, determines if a value is required before saving the database.
    • @separatelang: true or false, should each language have a separate value, or can all languages use one and the same value?
    • @crumb: the path from the last crumb-item to the value that needs to be edited.
    • @cdata: true or false, should the value be written as <![CDATA[...]]>?
    • @type: determine what kind of link should be available:
      • "internal": no choice possible: "" automatically added, followed by an input field, so anything entered must be part of the main website.
      • "external": no choice possible: "http://" automatically added, followed by an input field, so any internet address can be entered.
      • "": choice available, choose between "http://" or "" as base of the link.

The Checklist

The Checklist is a handy little application that runs on this very page, and features a list of common TO-DO-stuff for every project. Things like "Add favicon", "Add Google Analytics", HTML5 Standards check, etc... that get overlooked quite often. The idea is that each checkbox is linked to a general score. The more checked boxes, the higher your site score gets. When a site gets a certain score it gets the TopOfMind Stamp Of Approval, which just means it's ready to go online :).

1. Code quality

Check your code for common HTML5 errors with the validator. Not all errors can be fixed, use your own judgement to check if your code is valid enough. HTML Validator

Run the Broken Link Checker to see if there are any faulty links on your website.

Broken Links Checker

Check to see if the /humans.txt-file is present. This file gives some basic information about the techniques used and the author of the website. *NOTE*: using the Project Template as base for your website automatically adds this file.

2. Usability

Browser compability

Test the website in every (semi-)modern browser to make sure it works. If something is broken: fix it or display a message for the user to upgrade their system.

Check your website for common compatibility problems with this list of suggested fixes or enhancements. Not all are mandatory, but try to get the results as green as possible.

Microsoft Modern Compatibility Checker

Add a personal Favicon for your website in each possible format. Use the Generator to create one on the fly. This adds a nice, finishing touch to your website and looks great when used as a tile or app-button for smartphones/tablets.

The Real Favicon Generator

Create a more useful 404 'Page Not Found' error page. Use your .htaccess-file to link the error to a custom page, featuring a more meaningfull message and possible links to working pages of your website.

Info about custom 404 pages

Thoroughly reread all text on you website, and correct possible spelling and/or grammar errors. Nothing's worse than launching a brand new site littered with huge verb and noun blunders.

Add a separate CSS-stylesheet for those people who still want to print every page of your website. Remove backgrounds, change colors to black/white, etc ... .

Smashing Magazine: how to set up a print style sheet

Add soms specific options for specific target devices (ex. Live Tile for Windows 8, startup image for iOS, etc...).

Info about iOS Web app icons and startup images
Apple Developer pages
Microsoft Development Library
Pinned Website information

3. Speed and Performance

Add optimal compression for each image on your website. This can only be done at the launch of the site, after that the client is in charge of the images. *NOTE*: use Codekit's built-in image optimalisation function.

Generate your own Modernizr build, so only the elements that are needed are loaded and tested upon.

Modernizr download page

Use this Google tool to check your website for possible fixes in mobile and desktop speed rules. Not all can be applied, so use with your own judgement. A score above 90 is always good.

Google PageSpeed Insights

Another set of speed defining rules, based on Yahoo's rules for high performance web sites. Install this plugin and test your website for possible speed bumps. A score above 85 is perfect.

Yahoo YSlow

Test the current HTTP headers and check if there are any errors or inconsistencies.

Redbot HTTP resource checker

4. Search Engine Optimalisation

Does your website have Search Engine Friendly links? Instead of having links like /page.php?id=23&version=3, use URL Rewrites to make short en clear URLs (like /products/iphone).

Some best practices for SEO friendly URLs

A Firefox-plugin that checks the most important on-page-SEO-criteria and calculates a grade of how good your site fulfills these criteria. Anything above 85 is perfect!

Firefox plugin SenSEO

Use an XML-file to define the structure of your website. *NOTE*: using the Project Template as base for your website automatically adds this file.

Simple XML-sitemap generator

Use a robots.txt-file to clearly define where Search Engines can/cannot search. *NOTE*: using the Project Template as base for your website automatically adds this file.

Information about the Robots-file

The Google Search Console is a handy little tool that analyses your website and focusses purely on how it can be found and crawled. Use this tool to submit your site to the Google database.

Visit the Search Console

Structured data is a way for search engine machines to make sense of content in your HTML. Google and other search engines created a structured data standard called

Information about the
Easy schema creator/generator

5. Monitoring & Statistics

Uptime Robot monitors your websites every 5 minutes and alerts you if your sites are down.

Uptime Robot

Google Analytics keeps a bunch of statistics about your visitors (amount of visitors, most used browsers, screen resolutions, most visited pages, etc...).

Google Analytics

6. Mobile Responsiveness

Check your website's level of mobile-friendliness. A score above 75 is perfect!

W3 Mobile Validator

Check your website using real devices laying around the office.

Correctly use the Viewport-meta tag. This determines how the website should be rendered on smaller screens and sets the default size and zoom level.

Information about the Viewport-meta tag

When using forms, use the correct type for each input field (ex. url, phone, mail, ...). This way, people using mobile devices see the correct keyboards when entering text.

Information about the different input types

Use this tool to check your website using different pre-set device sizes. Convenient when you want to know how your site look like on an iPhone 6 Plus, but you don't have one at the office.


7. Social Media

Create a Twitter account and link it to your website, using a simple button, by embedding some posts or by displaying the entire feed on a page.

Twitter Embed Twitter Cards Embed Twitter Timelines

Create a Facebook account and link it to your website, using a simple button, by displaying the entire feed on a page or by styling your own custom Facebook feed.

Facebook Facebook Page Plugin Neosmart STREAM: embed custom styled Facebook & Twitter feeds ($) Voyager: embed multiple social media streams (beta - not active for now)

Create a Google Plus account and link it to your website, using a simple button or by embedding a post.

Google+ Embed Google+ post

Your website score:


Stuff to do in the future...

  • Hall Monitor: not really part of the Project Template, but something like the Address Book, File Transfer, Backstage, etc... that monitors the data for the different websites we have. Instead of having an Excel-file with all the data in, create an interactive database where we can easily find all website information for a client, access codes, webspace usage, online activity, etc... on.
  • CheckList: a list of common TO-DO-stuff for each website which can be (un)checked so you won't forget any important business. Also features a scorebar to keep you motivated!
  • Automatic sitemap generator: automatically updates the sitemap every time it is read.
  • Add extra chapter: Backstage. With an overview of all possible elements that can be used in the Backstage.
  • Move the crossdomain.xml-file to the assets and make it available via .htaccess.
  • Scrollbar for the left menubar
  • Better navigation: direct links to different sections + start each page at the top!