Changelogs: Uploader v4.4.0

A new version of Uploader has been released, version 4.4.0. Please download the new tag or view the documentation. If you have any questions, be sure to send me an email or comment on this post. If you run into any problems, report an issue on the GitHub repository.

Version: 4.4.0
Tested On: PHP 5.4.3, CakePHP 2.3.8, Composer
Requires: PHP 5.3, CakePHP 2.3, Composer
Commit Hash: cd5b91840a6910cd93bfd3a9791285be98460ffe
Changes:

  • Includes changes from previous versions
  • Fixed interface changes for CakePHP 2.4
  • Fixed an issue with file validation failing on PHP 5.3 [#136]
  • Fixed empty upload error logging problem [#152]
  • Fixed record deletion problem because of invalid model ID [#149]
  • Refactored so that defaultPath is applied in afterFind() [#147]
  • Added support for custom transformers and transporters

Environment bootstrapping with Titon\Environment

Handling multiple environments in an application can be tedious as each environment supplies its own set of configuration and unique bootstrapping. The amount of environments can grow to unmanageable numbers when dealing with dev environments, for example, different configuration for each developer. With no external dependencies, and a basic requirement of PHP 5.3, the Titon\Environment package hopes to solve this problem.

Defining Environments

An environment is mapped using an HTTP host or an IP address. During an HTTP request, an environment will be detected that matches the current host/IP, which is then loaded and bootstrapped. But first the environments need to be added through addHost(), which accepts a unique key, an array of hosts and IPs to match against, and finally the type. Out of the box, the package supports 3 types of environments — dev, staging and prod.

use Titon\Environment\Environment;
use Titon\Environment\Host;

// Create an environment instance
$env = new Environment();

// Register a dev env
$env->addHost(new Host('dev', array('127.0.0.1', '::1', 'localhost'), Environment::DEVELOPMENT));

What this did is create a development host environment for the localhost host, the 127.0.0.1 v4 IP, and the ::1 v6 IP. When either of those values are matched against the current request, the environment will be bootstrapped. But where does the bootstrapping take place? We must define it first! This can be accomplished through the setBootstrap() method on the Titon\Environment\Host object. Using the same example above, an absolute path to a bootstrap file can be defined.

$env->addHost(new Host('dev', array('127.0.0.1', '::1', 'localhost'), Environment::DEVELOPMENT))
	->setBootstrap('/absolute/path/to/bootstrap.php');

Now when an environment is detected a bootstrap will occur. This bootstrap file should contain configuration and logic specific to each environment.

Multiple Environments

In the previous example only one environment was added, dev. In standard applications, at minimum 2 environments will exist, dev and prod. Let's add the prod environment through the production domain and include a fallback. A fallback is used when an environment cannot be matched — this usually will fallback to prod as there is no risk of dev code making it into production, or at minimum a dev environment with error reporting turned off.

$env->addHost(new Host('prod', 'website.com', Environment::PRODUCTION))->setBootstrap('/envs/prod.php');

// Set a fallback using the host key
$env->setFallback('prod');

Let's now solve the multiple developer issue mentioned in the opening paragraph.

// Share the default boostrap
$env->addHost(new Host('john', 'john.dev.website.com', Environment::DEVELOPMENT))->setBootstrap('/envs/dev.php');
$env->addHost(new Host('mike', 'mike.dev.website.com', Environment::DEVELOPMENT))->setBootstrap('/envs/dev.php');

// Custom boostrap
$env->addHost(new Host('chris', 'chris.dev.website.com', Environment::DEVELOPMENT))->setBootstrap('/envs/dev-chris.php');

Or perhaps multiple QA staging environments for different regions?

foreach (array('us', 'eu', 'cn', 'au') as $region) {
	$env->addHost(new Host('qa-' . $region, $region. '.qa.website.com', Environment::STAGING))->setBootstrap('/envs/qa-' . $region. '.php');
}
Initializing An Environment

Once all the environment hosts have been defined, the package must be initialized. This can be done through the initialize() method, which will kick-start the matching and bootstrapping process.

$env->initialize();

Once an environment has been chosen, you can access it at anytime.

// Return the current host
$env->current();

// Or values from the host
$env->current()->getKey();
$env->current()->isStaging();

// Or use the convenience methods
$env->isDevelopment();
In Closing

For being such a lightweight class, the Titon\Environment package provides an extremely helpful application pattern. Be sure to give it a try in any MVC framework!

Changelogs: Forum v5.0.0

A new version of Forum has been released, version 5.0.0. Please download the new tag or view the documentation. If you have any questions, be sure to send me an email or comment on this post. If you run into any problems, report an issue on the GitHub repository.

Version: 5.0.0
Tested On: PHP 5.4.3, CakePHP 2.3.8, Composer
Requires: PHP 5.3, CakePHP 2.3, Composer
Commit Hash: d5ad0cdf0a133aef3e4472747242b2331e053339
Changes:

  • New design and layout using Titon Toolkit
  • Integrated more seamlessly with Admin v1.1.0
  • Includes the new post rating and access system from v4.1.0
Developer Notes

This update contains a complete rewrite of all the views. This means that all the old classes, markup and structure has changed. Be sure to update your code if you used custom layouts or views.

If you have not upgraded to 4.1.0 yet, be sure to run the upgrader from the command line or else 5.0.0 won't work correctly! If you are doing a fresh install of 5.0.0, this upgrade is not required.

Console\cake Forum.upgrade

Cascading CSS inheritance with responsive design

Over the past year or two, responsive design has edged its way into the forefront. It allows websites to support multiple device sizes and viewports, all through the CSS layer. So why do so many developers implement their media queries in the most complicated or inefficient ways? If you're curious as to what I'm referring to, check out the code sample below.

@media only screen and (min-device-width : 320px) and (max-device-width : 480px) { }
@media only screen and (min-device-width : 768px) and (max-device-width : 1024px) { }
@media only screen and (min-device-width : 768px) and (max-device-width : 1024px) and (orientation : portrait) { }

The problem with this approach is that rules are defined between 2 ranges (or even more granular when using orientation) instead of inheriting from the highest resolution. What if mobile and tablet both have similar styles that need to be applied? Either the code will be duplicated between 2 media queries, or a 3rd media query would be created to handle this. Both of these approaches are incorrect. The proper way (personal opinion) to handle responsive designs is by cascading inheritance from the highest resolution down to the lowest resolution, or vice versa; not defining rules for specific resolutions.

Largest to Smallest, or Smallest to Largest

When implementing the CSS for a new website, which resolution do you implement first? The answer should always be dependent on the target audience. If you plan to support mobile, then mobile-first with progressive enhancement should be chosen. If your target audience are desktop browsers, then desktop-first with graceful degredation should be chosen.

The pros and cons between each approach differ greatly. There are many great articles on this subject, so I will not go into great detail. However, here are a few key points for each approach, starting with mobile-first.

  1. The bare minimum CSS styles can be used to target mobile devices first (no floats, columns, etc)
  2. The more complicated or advanced CSS can be applied through media queries for tablet and desktop (progressive enhancement)
  3. Improved speed and rendering time for mobile devices since media query styles aren't computed
  4. Stops the loading or inclusion of assets that aren't required by default
  5. Can be extremely difficult or near impossible to do for complex designs

And when designing desktop-first.

  1. Typically the desktop, tablet and mobile designs are based off the same design, with the smaller resolutions simply removing elements or altering styles (graceful degredation)
  2. Much easier to design for when complex designs are used
  3. Also easier to scale fluid websites from a larger size to a smaller one
Cascading Inheritance

As mentioned above, using min-width coupled with max-width doesn't allow for inheritance between resolutions. So what does allow for inheritance? The answer is simple — only use max-width (for desktop-first), or min-width (for mobile-first). When using a max-width media query, all media queries that are larger than the current browser viewport will be inherited. So in layman's terms, tablet will inherit desktop rules (since they are defined by default), and mobile will inherit tablet AND desktop rules (since they are both defined previously). The same concept applies when doing the reverse using min-width. This approach is vastly superior as it reduces code complexity and repetition.

Let's create an desktop-first example for a horizontal three column layout, with the left column containing a vertical menu. When viewed in a tablet, the columns will be displayed vertically and the menu will be switched to horizontal. When viewed in mobile, the menu will hide text and display icons, while also inheriting tablet styles. A similar example can be found on this website, just resize it!

<div class="wrapper">
	<div class="left">
		<ul class="menu">	
			<li><a href="/"><span class="icon"></span> <span class="text">Home</span></a></li>
			<li><a href="/page"><span class="icon"></span> <span class="text">Page</span></a></li>
			<li><a href="/contact"><span class="icon"></span> <span class="text">Contact</span></a></li>
		</ul>
	</div>
	<div class="middle">Middle</div>
	<div class="right">Right</div>
</div>

And the initial CSS that sets the float styles (desktop by default).

.wrapper:after {
	clear: both;
	display: block;
	content: "";
}

.left,
.right {
	float: left;
	width: 25%;
}

.middle {
	float: left;
	width: 50%;
}

.menu {
	list-style: none;
	margin: 0;
	padding: 0;
	/* ... styles ... */
}

.menu li > a { display: block; }
.menu .icon { display: none; }

Pretty simple right? Now let's add tablet support using the landscape breakpoint.

/* Inherits from desktop (default styles above) */
@media only screen and (max-width: 1024px) {
	.left, .right, .middle {
		float: none;
		width: 100%;
	}

	.menu li { display: inline-block; }
}

We now have our columns displaying vertically and the menu horizontally for all devices below a 1024px viewport. These rules will be inherited by any kind of device, whether it's a laptop, smart phone or tablet, just as long as their viewport is no larger than 1024px. And now for mobile support, also using the landscape breakpoint.

/* Inherits from tablet and desktop styles above */
@media only screen and (max-width: 480px) {
	.menu .text { display: none; }
	.menu .icon { display: inline-block; }
}

And now we have mobile styles using only a few lines, easy right? That's what I like to call responsive cascading inheritance. Why not try implementing a mobile-first approach?

Standard Breakpoints

When designing for responsive, I like to support 6 standard breakpoints (not including default styles). These breakpoints cover about 95% of use cases.

  • Large Desktop - Default styles if designing for desktop-first
  • Small Desktop - 1440px width
  • Laptop - 1280px width
  • Tablet Landscape - 1024px width
  • Tablet Portrait - 768px width
  • Mobile Landscape - 480px width
  • Mobile Portrait - 320px width

I use these desktop-first breakpoints in my Titon Toolkit project as Sass mixins; feel free to borrow them. I plan to add another agnostic mixin that handles min width, max width and other options, allowing for easier use case targeting.

@mixin if-desktop {
	@media only screen and (max-width: 1440px) {
		@content;
	}
}

@mixin if-laptop {
	@media only screen and (max-width: 1280px) {
		@content;
	}	
}

@mixin if-tablet-landscape {
	@media only screen and (max-width: 1024px) {
		@content;
	}
}

@mixin if-tablet-portrait {
	@media only screen and (max-width: 768px) {
		@content;
	}
}

@mixin if-mobile-landscape {
	@media only screen and (max-width: 480px) {
		@content;
	}
}

@mixin if-mobile-portrait {
	@media only screen and (max-width: 320px) {
		@content;
	}
}
Do note that I use min-width and max-width which rely on resolution size. If you want to target literal device size, use min-device-width and max-device-width alongside the viewport meta tag.
In Closing

I've used this approach on this website and a few other projects I have worked on and it seems to have worked perfectly. I've also tested it in Firefox, Chrome, IE and even on my Android device with no problems. There is always room for improvements, so if you have a suggestion or correction, be sure to comment below!

Event handling with Titon\Event

Event-driven programming is a popular paradigm that is used in nearly every application. It allows for the manipulation or alteration of an applications process flow. Titon provides a very light-weight and robust event system through the aptly named Event package, which is based off of the observer pattern and requires PHP 5.3. Using the package however, is rather straight forward.

Registering observers

Before an event can be emitted (or dispatched depending on your background), an observer must be registered. In Titon, there are 2 kinds of observers: callbacks which utilize closures or callable references, or listeners which are instances of a class object. Two different approaches that generate the same result in the end. The register() and registerListener() methods can be used to register observers.

The register() method accepts 3 arguments: $event, $callback, and an array of $options (optional). The name of the event is usually a unique dot notated string that represents its purpose. The callback can either by an instance of a closure, an array that contains an object instance and a method name, or the name of a global function. Read up on the callable type for more examples.

use Titon\Event\Event;
use Titon\Event\Emitter;

// Create an emitter instance
$event = new Emitter();

// Register a closure
$event->register('app.beforeDispatch', function(Event $event) {
	// Execute some logic
});

// Or register a callback
$event->register('app.afterDispatch', [$object, 'methodName']);

The third argument accepts an array of options or an integer. Passing an integer is a shortcut for setting the event priority level. The following options are available.

  • priority (int:100) - The order in which observers will be emitted in ascending order
  • overwrite (bool:false) - Overwrite an observer with the same priority level, else shift down
  • once (bool:false) - Emit the observer once and then remove itself from the list
  • exit (bool:false) - Automatically stop the emit process if an observer returns a falsey value
$event->register('app.run', [$foo, 'methodName'], 50); // Register with a priority of 50
$event->register('app.run', [$bar, 'methodName'], 50); // Will shift to 51 since overwrite is false

// Supply multiple options
$event->register('app.run', [$baz, 'methodName'], [
	'priority' => 50,
	'overwrite' => true,
	'once' => true,
	'exit' => true
]);

Registering listeners is slightly different...

Handling listeners

Listeners are class instances that implement the Titon\Event\Listener interface, which in turn registers multiple observers for events when the class instance itself is registered. The interface provides a single method, registerEvents(), which must return a mapping of event to callbacks.

When returning an array, the array key must be the name of an event, and the value should be an array of options or a method name. The available options can be found above for register(). Each event can support a single callback, or multiple callbacks. The following example demonstrates all the possible combinations.

use Titon\Event\Event;
use Titon\Event\Listener;

class Foo implements Listener {
	public function registerEvents() {
		return [
			// Register a single method with no options
			'app.beforeDispatch' => 'beforeDispatch',
			// Register a single method with options
			'app.afterDispatch' => ['method' => 'afterDispatch', 'priority' => 30],
			// Register multiple methods with and without options
			'app.run' => [
				'run',
				['method' => 'runOnce', 'once' => true, 'exit' => true]
			]
		];
	}
	
	// Define the methods being registered.
	public function beforeDispatch(Event $event) {}
	public function afterDispatch(Event $event) {}
	public function run(Event $event) {}
	public function runOnce(Event $event) {}
}

Once the interface has been implemented, the class object can be registered in the Emitter.

$event->registerListener($listener);
Removing observers

Removing a registered observer can be quite tricky, as the original callback must also be used to remove it. When removing a closure, the same instance closure must be used. When removing a callable, the same reference must be used. When removing a listener, the same class instance must be used. The following example demonstrates this.

$closure = function(Event $e) { };
$event->register('event.foo', $closure);
$event->remove('event.foo', $closure); // Same reference

$event->register('event.foo', [$object, 'method']);
$event->remove('event.foo', [$object, 'method']);

$listener = new Foo();
$event->registerListener($listener);
$event->removeListener($listener); // Same reference
Convenience methods

Similar to popular JavaScript frameworks, a few convenience methods exist for observer registering and removing, they are on(), off(), and once(). The on and off methods accept either a callable or a listener, allowing for easier integration. The argument list for these methods is exactly the same as their counterparts.

// Register
$event->on('event.foo', [$object, 'method']);
$event->on('event.foo', $listener);

// Register once
$event->once('event.foo', function(Event $e) {});

// Remove
$event->off('event.foo', [$object, 'method']);
$event->off('event.foo', $listener);
Emitting events

Once observers have been registered, an event can be emitted to loop through and execute its observers. This can be done through the emit() method. The response when emitting will either be a Titon\Event\Event object, or an array of objects, depending on the event scope.

$response = $event->emit('event.foo');

An array of parameters can be supplied as a second argument to emit(), which will be passed on as arguments to the observers. Parameters can also be passed by reference allowing observers to modify data.

$response = $event->emit('event.foo', [&$data, $flag]);

// Available as arguments in the observer callback
function(Event $event, array &$data, $flag) {
	$data['foo'] = 'bar';
}

Multiple events can also be emitted when separating names with a space.

$responses = $event->emit('event.foo event.bar');

Or multiple events can be emitted by using a wildcard. This will resolve all event names that fall under that path.

$responses = $event->emit('event.*');
The Event

When an event is emitted, a Titon\Event\Event object is created, passed through all the observers, and finally returned as a response. The object represents the current state of the event and provides functionality for managing that state — the most popular being the stopping of propagation.

When the propagation is stopped, the event will exit out of the observer loop and cease processing. This can be done by calling stop() on the event object within an observer.

function (Event $event) {
	$event->stop();
}

Communication between observers can also be quite complicated (or never implemented). Titon provides a way of persisting data through the event object using setData() and getData(). This allows for an observer to set data at the beginning of the loop, which in turn can be used by another observer at the end of a loop.

function (Event $event) {
	$event->setData(['foo' => 'bar']);
}

function (Event $event) {
	$data = $event->getData();
}

Data can also be set by returning a value from the observer.

function (Event $event) {
	return ['foo' => 'bar'];
}

There are also times when the priority order of the loop is uncertain. The getCallstack() method can be called to return an array of all observers in order of priority. The getIndex() method returns that position in the loop (not the priority level), and the getTime() method returns the timestamp of when the event started.

Emittable trait

As mentioned above, the package itself requires PHP 5.3. However, there is a PHP 5.4 trait available, Titon\Event\Traits\Emittable, that provides an event managed layer within a class. This allows events to be registered and emitted in context to that class; very useful for classes that require callback hooks. The trait provides the following methods: getEmitter(), setEmitter(), on(), off(), and emit().

use Titon\Event\Traits\Emittable;

class Foo {
	use Emittable;
	
	public function doSomething() {
		$this->emit('foo.do');
	}
}

$foo = new Foo();
$foo->on('foo.do', [$object, 'method']);
$foo->doSomething();
In closing

The Titon\Event package is very powerful and provides additional functionality that other event dispatching libraries do not provide. Some of these features include:

  • Multiple event resolving
  • Wildcard event resolving
  • Event data persistence through the object or observer return
  • Automatic propagation stopping through the exit option
  • Observer once execution through the once option
  • Observer call stack generation
  • Observer priority overwriting
  • Class layer event management through Emittable trait
  • And many more awesome features

So give it a whirl and let me know what you think!

Changelogs: Admin v1.1.0

A new version of Admin has been released, version 1.1.0. Please download the new tag or view the documentation. If you have any questions, be sure to send me an email or comment on this post. If you run into any problems, report an issue on the GitHub repository.

Version: 1.1.0
Tested On: PHP 5.4.3, CakePHP 2.3.8, Composer
Requires: PHP 5.3, CakePHP 2.3, Composer
Commit Hash: dd598ec1074cd2e63fd5ceeea86b838eec3a7c18
Changes:

  • Added ACL and roles detection into the session layer (allows for easy use between plugins)
  • Added ClassRegistry::init() in Admin::introspectModel() as it resolves includes successfully
  • Added a badge counter system to Admin.menu items
  • Replaced Twitter Bootstrap with Titon Toolkit
  • Improved usability and user experience

Changelogs: Forum v4.1.0

A new version of Forum has been released, version 4.1.0. Please download the new tag or view the documentation. If you have any questions, be sure to send me an email or comment on this post. If you run into any problems, report an issue on the GitHub repository.

Version: 4.1.0
Tested On: PHP 5.4.3, CakePHP 2.3.8, Composer
Requires: PHP 5.3, CakePHP 2.3, Composer
Commit Hash: 93d289d69281e1432150fa88d34083a565b1fcab
Changes:

  • Added new access setting to ForumToolbar.verifyAccess()
  • Added a new post rating feature which allows for up down scoring of posts
  • Added email template support to subscriptions through Forum.settings.subscriptionTemplate
  • Added custom image icon support to forums
  • Refactored Forum table so that accessRead, accessPost, accessReply, and accessPoll all point to ARO records
  • Removed aro_id column from Forum (use accessRead instead)
  • Renamed certain session variables to be prefixed with Acl instead of Forum
  • Replaced ForumHelper.gravatar() with UtilityHelper.gravatar()
Developer Notes

A new post rating feature has been implemented, which allows logged in users to rate a post up or down. When posts reach a specific negative threshold, the post will be buried and the avatar and signature of the user will be removed. Five new settings have been added for ratings: enablePostRating, showRatingScore, ratingBuryThreshold, rateUpPoints, and rateDownPoints.

The other major change is the refactoring of the forums table. The old columns accessRead, accessPost, accessReply, and accessPoll were pretty much useless after the 4.0.0 migration to ACL. In 4.1.0 I changed them to point to ARO records allowing full control over who sees and does what. With this change the aro_id column has been removed, which is mimicked by accessRead anyways.

Be sure to run the upgrade script from the command line.

Console\cake Forum.upgrade

Titon

For the past few years I've been working on a project called Titon — a PHP framework and a front-end library built on MooTools. Titon refers to anything back-end related as the "Framework", while anything front-end related as the "Toolkit". The Framework isn't full-stack in the modern sense, it's simply a collection of packages that can be installed through Composer. The Toolkit is a collection of modular UI classes and helpers written in HTML5, CSS3, Sass and MooTools 1.4.

A brief history

I started writing Titon back in September 2009, around the same time PHP 5.3 was released. The idea behind Titon was simply a learning lesson. It gave me a chance to learn namespaces, closures and all the new PHP functionality. It also permitted me to write systems I would never really write, like database abstraction layers, object relational mappers, caching and storage engines, internationalization and localization, routing, so on and so forth. It was also a great learning lesson on how to properly use interfaces and abstraction classes, while also practicing design patterns and improving with design principles like DRY, KISS, YAGNI, and many others.

Over the course of 3 years, the Titon codebase evolved into a fully fledged framework (albeit not 100% runnable). The architecture was rewritten about 3-4 times as I would try new, different and unique approaches. Classes and interfaces came and went. Functionality was stripped (YAGNI) or dumbed down (KISS). Features were completed or backlogged. Roadmaps were created and abruptly forgotten about. Writing a full-stack framework took time and eventually I stopped working on it many months at a time.

It was around 2012 when I jumped back onto Titon. With the recent release of PHP 5.4 and the ever increasing usage of Composer, it felt like the perfect time. Instead of building a full-stack framework (because do we really need another framework) like before, I decided to break it down into multiple smaller packages that can be installed through the Composer. This would encourage usability, promote decoupling and not require a developer to use a heavy framework for certain functionality. Over the course of the next year, I broke it down into 15 primary packages and 4 supporting packages.

Why am I releasing it?

Even though it was a learning lesson, these packages could still be beneficial to someone (or even you), hence the release. I don't expect Titon to compete with Symfony, CakePHP, Zend, or the many other frameworks, nor do I care. If a packages solves a problem you have, then perfect, go ahead and use it! If a package or Titon as a whole is never used, I won't mind either way. In the end, it taught me everything I currently know, and I couldn't be happier.

What are the Framework packages?

Like previously mentioned, Titon is decoupled into 15 primary packages and 4 supporting packages. A primary package is a collection of classes that provide functionality for a specific feature, for example, a model layer, route mapper, or caching engine. A supporting package is an optional dependency for primary packages that include additional functionality, for example, the MySQL driver for the Model package.

The following packages are available, fully functional and tested. They are split between PHP 5.3 and 5.4, as there was no reason to limit simplistic packages to 5.4 only.

PHP 5.3
  • Debug - Provides logging, debugging and advanced error and exception handling
  • Environment - Allows for multiple environment configuration and bootstrapping
  • Event - Notifies a list of objects during an event and allows for listener registration
  • Type - Implements class like functionality for arrays, strings, objects and enums
  • Utility - Provides convenience classes for basic tasks like validation, formatting, sanitization and more
PHP 5.4
  • Cache - Provides a data caching layer that supports multiple storage engines
  • Common - Provides global functionality like class traits and augmentation as well as dependency and configuration management
  • Controller - Provides controllers that handle the HTTP dispatch cycle and are loosely coupled with other packages
  • G11n - Implements localization and internationalization through message and locale bundles
  • HTTP - Provides classes for interacting with sessions, cookies and the request and response
  • IO - Permits file system manipulation through readers, writers and resource bundles
  • Model - Implements a lightweight database abstraction layer and an object relational mapper
    • MySQL - Enables the MySQL database driver
    • PostgreSQL - Enables the PostgreSQL database driver
    • SQLite - Enables the SQLite database driver
    • MongoDB - Enables the MongoDB database driver
  • MVC - Bundles the Model, View and Controller packages while adding support for dispatching and modularization
  • Route - Provides dynamic route handling, matching and mapping
  • View - Allows for template look-up and rendering through engines and helpers
What about the Toolkit?

The Toolkit is a collection of JavaScript classes and CSS modules known as components. Each component provides front-end functionality, like modals, tooltips and buttons. But doesn't this compete with Twitter bootstrap? In a sense yes, however, there are some major differences. The first being that Toolkit uses MooTools instead of jQuery (if you're one of the rare developers like me who don't like jQuery). The second being that Toolkit doesn't provide default styles like Bootstrap, it merely provides the functionality. This allows the developer – you – to integrate and customize the components at will.

The following components are currently available. Each component is either purely CSS or a combination of CSS and JavaScript.

JavaScript
  • Accordion - Provides collapsible support to a list of sections
  • Blackout - Displays a transparent black element over the document
  • Cache - Provides local and session storage within the class layer
  • Flyout - Displays nested flyout menus that appear below an element that activates it
  • LazyLoad - Provides an easy way to lazy-load images (inline and background) while scrolling
  • Modal - Displays dynamic modals that will display above the content
  • Pin - Pin an element in a container that stays within the viewport while scrolling
  • Popover - Displays dynamic notification elements over an element
  • Tabs - Provides tabbed support to an element containing navigation tabs and sections
  • Timers - Provides timer and interval management within the class layer
  • Tooltip - Displays dynamic tooltips over an element or the mouse cursor
  • TypeAhead - Displays a list of possible options below an input while typing
CSS
  • Animations - CSS3 transitions for specific animations: fade, slide, etc
  • Alert - Styles for block level notification messages
  • Button - Styles for generic cross-browser compatible buttons
  • ButtonGroup - Allows for the grouping of multiple buttons into 1 visual styled button
  • Icon - Allows for inline image sprites to be used at 12, 16, 24, 32, and 64 sizes
  • Label - Styles for inline tag labels
  • Badge - Styles for inline notification bubbles
  • Pagination - Styles for pagination lists
  • Visual - Provides visual aesthetics like gloss and glare over elements
What about a full application?

Nothing is stopping you from using Titon as a full application — hell, even the MVC package was built for this purpose. Since Titon is a collection of packages, there's no set guidelines on how to build an application, it's all up to how you want to piece it together. However, to make things easier, I've thrown together a skeleton application that you may use as a base.

What does the future hold?

In regards to the Framework, I have no plans to add anymore primary packages. I do have plans to add minor supporting packages, like Smarty and Twig support for the View layer. Any bugs, issues or feature requests I will handle of course. I would also like to increase unit testing and average around 90% code coverage for all packages.

The Toolkit however will receive full support and the inclusion of many more components. I currently use Toolkit on all my personal websites.

In the off chance that Titon becomes popular, I will provide in-depth documentation, a fully functional website, and reverse my decision on new packages.

How can you start using it?

By installing through Composer, or cloning the repository, or downloading the project. Since no official website exists, nor does any documentation, learning how to use each package can be tricky. Each repository contains a docs folder that provides basic documentation on each class in the repo. For any functionality that is not documented, I highly suggested reading the source code and its comments. And if no documentation exists for a specific class, let me know and I will provide one.

Using Toolkit requires some manual intervention as the source files need to be compiled. This allows for custom Toolkit builds (only requiring certain components) to be generated through Grunt. Instructions on how to do this can be found in the repository.

I will also be blogging about each package and how to use it, so expect those in the near future!

Blue Screens and SSDs

Over the past weekend I spent 3 days troubleshooting a constant blue screen of death problem. It was like no problem I've ever dealt with as the symptoms were very unusual. When I was using the computer, whether playing a game, browsing the internet or simply just working, it would freeze up. It wouldn't freeze in the usual sense, it would freeze up program by program (when I clicked to each one) until I couldn't do anything except move my mouse and wait for the unavoidable BSOD. It would even BSOD while my computer was idle, weird!

Like any competent PC owner, I tested all the hardware piece by piece. I started by disassembling the computer, cleaning everything, checking for damage, and reassembling; all good. I checked all drivers and updates. I tested each memory stick one by one. I monitored the temperature and voltage, and found nothing out of the ordinary. That only left the video card, power supply, hard drives (1 SSD, 2 HDD) and possibly the motherboard. I ruled out the power supply by monitoring the voltage. I ran disk cleanup, disk check and defragment on all the drives and they all passed. I never tested another video card as I believed it wasn't a video issue, since the symptoms had nothing to do with display. That left me with the MOBO, which I was really hoping wasn't the problem.

Before I went any further, I queried all my tech knowledgeable friends for a solution... they had none. They all suggested doing a system wipe, which I think is absurd until you determine whether it's a hardware or software issue. So I enabled BSOD logging which would allow me to read the dumps and discover a solution. However, another problem arose when the BSOD dumps were never written during a crash, and the administrative event logs weren't helpful either. I was at a loss at this point and really didn't want to spend money building a new system.

Since BSOD logs weren't being generated, a friend suggested waiting for a BSOD to occur and to write down the error message that appears. So I did. The following is a summary of the BSOD.

A process or thread crucial to system operation has unexpectedly exited or been terminated. Stop: 0x000000F4 (0x0000000000000003, 0xFFFFFA800C13D060, 0xFFFFFA800C13D340, 0XFFFFF800039D9350).

At a glance it doesn't come off as helpful, but that didn't stop me. I Googled around using "BSOD 0x000000F4" as my term coupled with each piece of hardware I was utilizing, until I found something. It just so happens that my Crucial M4 SSD that I installed a little over a year ago was the culprit. After 5,000 hours of on-time, the SSD will crash unexpectedly. The math since installation checks out: (12 average hours a day * 30 days a month) * 14 months = 5,040. With a little firmware update from the Crucial guys, I've been BSOD free for a couple days now.

I felt the need to blog this as I'm sure it would be helpful to others who encounter such weird issues, especially with new tech like SSDs. You've been warned!

Changelogs: Decoda v6.2.0

A new version of Decoda has been released, version 6.2.0. Please download the new tag or view the documentation. If you have any questions, be sure to send me an email or comment on this post. If you run into any problems, report an issue on the GitHub repository.

Version: 6.2.0
Tested On: PHP 5.4.3, Composer
Requires: PHP 5.3, Composer
Commit Hash: e90e79fddb88aff3928eb74018594b5717080e1b
Changes:

  • Added a newline to line break conversion setting lineBreaks [#48]
  • Added an onlyTags setting to filters that only allow tags and no text nodes as direct descendants
  • Added [*] list item tag to ListFilter (does not support nested lists)
  • Changed utility methods to public from protected
  • Improved newline normalization