Pan.js (or P.js) is a light (< 40ko) and simple JS framework made to help you develop well structured web applications quickly.
You can organize your web application into Components and Tools. It comes with some useful premade stuff. Simply include the JS files in your HTML and start using it. P.js is still in development, don't hesitate if you have any advice.
Table of contents
P.js has no dependencies (no, you don't need jQuery).
It's compatible with all modern browsers down to IE8.
Depending on the browsers and classes you are using, you may need polyfills which are included in the src/polyfills folder.
The default build includes all needed polyfills but you can use the no-compatibility version.
There are two ways of using P.js.
You can use it as a simple library by instantiating the tools or you can use it as a Framework by extending P.js to create your own tools and components.
<script src="../../builds/pan-0.3.min.js"></script>var viewport = new P.Tools.Viewport();
viewport.on( 'resize', function( width, height )
{
console.log( width, height );
} );Create your own tools and components based on P.js classes. You can put your components inside P.Components object or you can create your own namespace like Foo.Bar.My_Class.
Inheritance is based on the John Resig code with some improvements like deep property merging, singleton, defualt options, etc.
P.js is developed in strict mode. Do as you whish and feel free to share your custom tools and components.
<script src="../../builds/pan-0.3.min.js"></script>// Create a class wrapping the all application
P.Components.My_App = P.Core.Abstract.extend(
{
construct : function()
{
// Instantiate a sidebar and header
this.sidebar = new P.Components.My_Sidebar( { color : 'blue' } );
this.header = new P.Components.My_Header();
}
} );
// Create a class for the sidebar
P.Components.My_Sidebar = P.Core.Abstract.extend(
{
// Default options
options :
{
colors : 'red'
},
construct : function( options )
{
this._super( options );
this.main = document.querySelector( 'aside' );
console.log( 'Init Sidebar' );
}
} );
// Create a class for the header
P.Components.My_Header = P.Core.Abstract.extend(
{
construct : function()
{
this.main = document.querySelector( 'header' );
console.log( 'Init Header' );
}
} );// Let's rock
var my_app = new P.Components.My_App();Core classes are the foundations of P.js.
Every tool or component inherit from one of those classes and your custom classes should too.
P.Core.Abstract is the default class.
construct method will be called when instantiatedstatic property set the class as a Singleton. That mean that the first instiantiation with new will act normally but every next instiantiation with new will return the first one.options property is an object that will be merge with the options when instantiatedregister property inside the options property will automatically add the instantiation to the Registry tool with the register value as key_super( parameters ) inside a method will call the parent overrided method// Inherit from Abstract
P.Components.Custom_Class = P.Core.Abstract.extend(
{
construct : function()
{
console.log( 'Welcome to my custom class' );
}
} );
var custom_class = new P.Components.Custom_Class();P.Components.Custom_Class = P.Core.Abstract.extend(
{
// Options with random deep properties
options :
{
test :
{
foo : 'bar',
lorem : 'ipsum'
}
},
// Add options argument
construct : function( options )
{
// Pass options to _super
this._super( options );
console.log( 'Options', this.options );
}
} );
// Instantiate by passing different options
var custom_class = new P.Components.Custom_Class( {
test :
{
lorem : 'dolores'
}
} );// Currently, static functionnality is only used for tools
// It's just a matter of organization, do whatever you want.
P.Tools.Custom_Class = P.Core.Event_Emitter.extend(
{
// Chose a name never used
static : 'custom_tool',
construct : function()
{
// Don't forget the _super
this._super();
console.log( 'Init' );
}
} );
// 'custom_class' and 'custom_class_again' will share the same instance
// 'construct' will be called only the first time
var custom_class = new P.Tools.Custom_Class(),
custom_class_again = new P.Tools.Custom_Class();// Create any class you'd like
P.Components.Test_Class = P.Core.Abstract.extend( {} );
// Instantiate and specify the register property in options object
// The value is the key you want to retrieve the instance later
var test_class = new P.Components.Test_Class( { register : 'my_key' } );
// Instantiate the registry tools and get the test_class using the register key
var registry = new P.Tools.Registry(),
test_class_2 = registry.get( 'my_key' );P.Core.Event_Emitter extends P.Core.Abstract with extra event methods.
on, off and trigger methodsevent-name == eventname == event_name)// Create a custom component that extends Event_Emitter
P.Components.Custom_Component = P.Core.Event_Emitter.extend(
{
construct : function()
{
this._super();
// Save context
var that = this;
// Interval every seconds
window.setInterval( function()
{
// Trigger event and pass parameters
that.trigger( 'event-test', [ 'test-1' ] );
}, 1000 );
}
} );
var custom_component = new P.Components.Custom_Component();
// Listen to 'event-text'
custom_component.on( 'event-test', function( value )
{
// Will log 'text-1' every second
console.log( value );
} );// Create a custom component that extends Event_Emitter
P.Components.Custom_Component = P.Core.Event_Emitter.extend(
{
construct : function()
{
this._super();
// Save context
var that = this;
// Wait a second
window.setTimeout( function()
{
// Trigger some events
that.trigger( 'event-1', [ 'test-1' ] );
that.trigger( 'event-2', [ 'test-2' ] );
that.trigger( 'event-3', [ 'test-3' ] );
that.trigger( 'event-4', [ 'test-4' ] );
} );
}
} );
// Try to instantiate twice but get a common object each time
var custom_component = new P.Components.Custom_Component();
// Listen two events
custom_component.on( 'event-1 event-2', function( value )
{
console.log( value );
} );
// Stop listening to 'event-1' event
custom_component.off( 'event-1' );
// Listen to event with namespace
custom_component.on( 'event-2.foo event-3.bar event-4.bar', function( value )
{
console.log( value );
} );
// Stop listening on 'event-2' with 'foo' namespace
custom_component.off( 'event-2.foo' );
// Stop listening on every events with 'bar' namespace
custom_component.off( '.bar' );P.js comes with some premade tools. Each one is a singleton (static). You can instantiate it multiple times, you will always get the first instance.
You can extend those tools if you want.
Breakpoints works a little like width and height for media queries. Specify some breakpoints and it will trigger events when resizing the viewport.
See code
See example
Options
{
breakpoints : [ // Breakpoints
{
name : 'large',
width :
{
value : 960,
extreme : 'min',
included : false
}
},
{
name : 'medium',
width :
{
value : 960,
extreme : 'max',
included : true
}
},
{
name : 'small',
width :
{
value : 500,
extreme : 'max',
included : true
},
height :
{
value : 500,
extreme : 'max',
included : true
}
}
]
}Properties
Methods
breakpoints (object|array) Add one are multiple breakpointssilent (optional, boolean, default: true) Should not trigger eventbreakpoints (string|array) Remove one are multiple breakpoints by namesilent (optional, boolean, default: false) Should not trigger eventbreakpoint (string) Test if breakpoint is curently activecondition (string) Proceed to a classic matchMedia but only return a booleanEvents
breakpoints (array) Currently active breakpointsHelp you convert strings to well formated colors.
Create beautifuls rainbows. ?
See code
See example
Options
{
gradients :
{
parse : true, // Automatically parse, looking for text to convert to gradient
target : document.body, // Default target when parsing
classes :
{
to_convert : 'gradient-text', // Searched class
converted : 'gradient-text-converted' // Converted class
}
}
}Properties
Methods
input (string) Anything that looks like a color (#ff0000,#f00,red,{r:1,g:0,b:1},{h:1,s:1,l:0.5})target (optional, DOM element, default: document.body)selector (string, default: 'to-resize')start (any)end (and)count (number)format (optional, string, values: 'rgb' | 'hsl', default: 'hsl')input (object) RGB objectinput (object) HSL objectEvents
none
Apply CSS on targeted element and automatically add prefixes. Property will automatically be formated.
See code
See example
Options
{
prefixes : [ 'webkit', 'moz', 'o', 'ms', '' ] // Default prefixes
}Properties
none
Methods
target (DOM element|jQuery) Element retrieved with classic fetcher like querySelector or jQueryvalues (object) Value to applyprefixes (optional, boolean|array) True for default prefixes or prefixes arrayEvents
none
Provide informations like engine, browser, system and features.
See code
See example
Options
{
targets : [ 'html' ] // Add detected informations to targets in array (selector or DOM Elements)
}Properties
ie (number)gecko (number)webkit (number)khtml (number)opera (number)version (number)ie (number)firefox (number)safari (number)konq (number)opera (number)chrome (number)version (number)windows (boolean)mac (boolean)osx (boolean)iphone (boolean)ipod (boolean)ipad (boolean)ios (boolean)blackberry (boolean)android (boolean)opera_mini (boolean)windows_mobile (boolean)wii (boolean)ps (boolean)touch (boolean)media_query (boolean)Methods
none
Events
none
Send informations to Google Analytics using the current instance. You must instantiate Google Analytics yourself.
See code
See example
Options
{
send : true, // Should send informations
parse : true, // Automatically parse
true_link_duration : 300, // Wait duration before following the link (enough time to be sure that informations have been well stend)
target : document.body, // Default target when parsing
classes :
{
to_tag : 'tag', // Search class
tagged : 'tagged' // Tagged class
},
logs :
{
warnings : false, // Log warning
send : false // Log sent informations
}
}Properties
none
Methods
target (optional, DOM element, default: document.body)selector (string, default: 'to-resize')datas (object)
category (any)action (any)label (optional, any)value (optional, any)unique (optional, string) Should not send the data more than one time (depending on the string value)Events
Methods, properties and events relatives to the keyboard
See code
See example
Options
none
Properties
Methods
input (number) Keycodeinput (string|number) Keycode or characterinputs (array) Keycodes and/or charactersEvents
keycode (number)character (string)keycode (number)character (string)Know when your users use the konami code ↑ ↑ ↓ ↓ ← → ← → B A
See code
See example
Options
{
reset_duration : 1000, // Time in before reseting
sequence : // Sequence to enter
[
'up',
'up',
'down',
'down',
'left',
'right',
'left',
'right',
'b',
'a'
]
}Properties
none
Methods
none
Events
index (int) Progress before timeoutindex (int) Progress before failingProperties and events relatives to the mouse
See code
See example
Options
none
Properties
Methods
none
Events
position (object) Mouse position informationstarget (DOM element) Direct element under the mouse positionfalse in the callbackposition (object) Mouse position informationstarget (DOM element) Direct element under the mouse positionposition (object) Mouse position informationstarget (DOM element) Direct element under the mouse positionwheel (object) Mouse wheel informationsfalse in the callbackKey/value registry for when you need to store variable and retrieve it anywhere without using ugly global variables.
You may use it to cache variables.
See code
See example
Options
none
Properties
Methods
key (string)callback (optional, function) Called if item not found for specified key and function result returnedkey (string)value (any)Events
key (string)value (any)Resize elements inside containers according to many possible options.
May automatically parse and resize according to classes and attributes on containers.
In order to work, you'll have to specify the following properties on the DOM elements themselves
data-width | width (optional, number)data-height | height (optional, number)data-width | width (number)data-height | height (number)data-fit-type (optional, string, values: 'fill' | 'fit', default: 'fill')data-align-x (optional, string, values: 'left' | 'center' | 'right', default: 'center')data-align-y (optional, string, values: 'top' | 'center' | 'bottom', default: 'center')data-rounding (optional, string, values: 'ceil' | 'floor' | 'round' | none, default: 'ceil')See code
See example
Options
{
force_style : true, // Add 'position' and 'overflow' CSS properties if not set yet
parse : true, // Automatically parse
target : document.body, // Default target when parsing
auto_resize : true, // Resize on browser 'resize' event
classes :
{
to_resize : 'to-resize', // Containers searched class (on the container)
content : 'content' // Content class (must be inside container)
}
}Properties
none
Methods
target (optional, DOM element, default: document.body)selector (string, default: 'to-resize')container (DOM element)content (DOM element)force_style (optional, boolean, default: true) Add 'position' and 'overflow' style properties if not set yetparameters (object)
content_width (number)content_height (number)container_width (number)container_height (number)fit_type (optional, string, default: fill, value: fill | fit)align_x (optional, string, default: center, value: left | center | right)align_y (optional, string, default: center, value: top | center | bottom)rounding (optional, string, default: ceil, value: ceil | floor | round | none)format (optional, string, default: both, value: both | cartesian | css)Events
none
Method to manage strings
See code
See example
Options
none
Properties
none
Methods
value (string) String that need to be case changedformat (string) Wanted case
value (string) String to trimcharacters (string) Characters to trimvalue (string) Smartly convert to boolean with many supported languages
value (string) String to slugifyEvents
none
Run a ticker that trigger events each frame base on requestAnimationFrame.
See code
See example
Options
{
auto_run : true
}Properties
start When did the ticker start lastelapsed Time spentdelta Time spent since last tickcurrent Current timeMethods
run (boolean) Should start running the timerframes_count (number)action (function)after (optional, boolean, values: true | false, default: true) Should apply the function after the tick event is triggeredEvents
time (object) Time informationstime (object) Time informationsGives you informations about viewport like width, height, scroll top, scroll left, scroll delta, etc.
Trigger events on scroll and resize.
Can disable hover on scroll for performance improvement
See code
See example
Options
{
disable_hover_on_scroll : false, // Improve performance when scrolling but disable hovers
initial_triggers : [ 'resize', 'scroll' ] // On the next frame, triggers 'resize' then 'resize' events
}Properties
delta (object)
top | y (number) Scroll delta topleft | x (number) Scroll delta leftdirection (object)
y (string) Vertical scroll directionx (string) Horizontal scroll directionMethods
condition (string) Proceed to a classic matchMedia but only return a booleanEvents
viewport (object)viewport (object)Preferences > Browse Packages...User/ folderbc : Pan Class
P.Components.Class = P.Core.Abstract.extend(
{
static : 'class',
options : {},
construct : function( options )
{
this._super( options );
}
} );bcs : Pan Class Strict
(function()
{
'use strict';
P.Components.Class = P.Core.Abstract.extend(
{
static : 'class',
options : {},
construct : function( options )
{
this._super( options );
}
} );
} )();bfn : Pan Function
/**
* Description
*/
name : function( options )
{
var that = this;
this._super();
}bn : Pan New
new Pan.Namespace.Class();bnc : Pan New Component
new Pan.Components.Class();bnt : Pan New Tool
new Pan.Tools.Class();convert_case with dashedadd_detector methodnone in roundinginit by construct$ property on Abstractp- to default classesnull option bug'use strict'match_breakpoint to Viewportno-features classes not working on Detectorformat parameter on get_sizes method (support "cartesian", "css" or "both")wait methodInit