Browse Source
Former-commit-id: 9fe80ef6c97b7c52cca61f9a066d9c6a5704b8f0 Former-commit-id: 0afd7e867a17a12e3b00c46376b538320ea20a37beta
Jack Lukic
12 years ago
89 changed files with 7701 additions and 329 deletions
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 5.5 KiB |
@ -0,0 +1,196 @@ |
|||
/* ****************************** |
|||
Accordion |
|||
Author: Jack Lukic |
|||
Notes: First Commit July 19, 2012 |
|||
|
|||
Simple accordion design |
|||
****************************** */ |
|||
|
|||
;(function ($, window, document, undefined) { |
|||
|
|||
$.fn.accordion = function(parameters) { |
|||
var |
|||
settings = $.extend(true, {}, $.fn.accordion.settings, parameters), |
|||
// hoist arguments
|
|||
moduleArguments = arguments || false |
|||
; |
|||
$(this) |
|||
.each(function() { |
|||
|
|||
var |
|||
$module = $(this), |
|||
$title = $module.find(settings.selector.title), |
|||
$icon = $module.find(settings.selector.icon), |
|||
$content = $module.find(settings.selector.content), |
|||
|
|||
instance = $module.data('module'), |
|||
className = settings.className, |
|||
module |
|||
; |
|||
|
|||
module = { |
|||
|
|||
initialize: function() { |
|||
// initializing
|
|||
$title |
|||
.on('click', module.change) |
|||
; |
|||
$module |
|||
.data('module', module) |
|||
; |
|||
}, |
|||
|
|||
change: function() { |
|||
var |
|||
$activeTitle = $(this), |
|||
$activeContent = $activeTitle.next($content), |
|||
contentIsOpen = $activeTitle.hasClass(className.active) |
|||
; |
|||
if(contentIsOpen) { |
|||
if(settings.collapsible) { |
|||
$.proxy(module.close, $activeTitle)(); |
|||
} |
|||
} |
|||
else { |
|||
$.proxy(module.open, $activeTitle)(); |
|||
} |
|||
}, |
|||
|
|||
open: function() { |
|||
var |
|||
$activeTitle = $(this), |
|||
$activeContent = $activeTitle.next($content), |
|||
$currentTitle = $title.filter('.' + className.active), |
|||
$currentContent = $currentTitle.next($title) |
|||
; |
|||
if(settings.exclusive && $currentTitle.size() > 0) { |
|||
|
|||
$currentTitle |
|||
.removeClass('active') |
|||
; |
|||
$currentContent |
|||
.stop() |
|||
.slideUp(settings.speed , settings.easing, function() { |
|||
$(this) |
|||
.removeClass('active') |
|||
.removeAttr('style') |
|||
; |
|||
}) |
|||
; |
|||
} |
|||
$activeTitle |
|||
.addClass(className.active) |
|||
; |
|||
$activeContent |
|||
.hide() |
|||
.addClass(className.active) |
|||
.stop() |
|||
.slideDown(settings.speed, settings.easing, function() { |
|||
$(this) |
|||
.removeAttr('style') |
|||
; |
|||
}) |
|||
; |
|||
}, |
|||
|
|||
close: function() { |
|||
var |
|||
$activeTitle = $(this), |
|||
$activeContent = $activeTitle.next($content) |
|||
; |
|||
$activeTitle |
|||
.removeClass(className.active) |
|||
; |
|||
$activeContent |
|||
.removeClass(className.active) |
|||
.show() |
|||
.stop() |
|||
.slideUp(settings.speed, settings.easing, function(){ |
|||
$(this) |
|||
.removeAttr('style') |
|||
; |
|||
}) |
|||
; |
|||
}, |
|||
|
|||
debug: function(message) { |
|||
if(settings.debug) { |
|||
console.info(settings.moduleName + ': ' + message); |
|||
} |
|||
}, |
|||
error: function(errorMessage) { |
|||
console.warn(settings.moduleName + ': ' + errorMessage); |
|||
}, |
|||
invoke: function(methodName, context, methodArguments) { |
|||
var |
|||
method |
|||
; |
|||
methodArguments = methodArguments || Array.prototype.slice.call( arguments, 2 ); |
|||
if(typeof methodName == 'string' && instance !== undefined) { |
|||
methodName = methodName.split('.'); |
|||
$.each(methodName, function(index, name) { |
|||
if( $.isPlainObject( instance[name] ) ) { |
|||
instance = instance[name]; |
|||
return true; |
|||
} |
|||
else if( $.isFunction( instance[name] ) ) { |
|||
method = instance[name]; |
|||
return true; |
|||
} |
|||
module.error(settings.errors.method); |
|||
return false; |
|||
}); |
|||
} |
|||
if ( $.isFunction( method ) ) { |
|||
return method.apply(context, methodArguments); |
|||
} |
|||
// return retrieved variable or chain
|
|||
return method; |
|||
} |
|||
|
|||
}; |
|||
|
|||
// calling a method
|
|||
if(instance !== undefined && moduleArguments) { |
|||
// simpler than invoke realizing to invoke itself (and losing scope due prototype.call()
|
|||
if(moduleArguments[0] == 'invoke') { |
|||
moduleArguments = Array.prototype.slice.call( moduleArguments, 1 ); |
|||
} |
|||
return module.invoke(moduleArguments[0], this, Array.prototype.slice.call( moduleArguments, 1 ) ); |
|||
} |
|||
// initializing
|
|||
module.initialize(); |
|||
|
|||
}) |
|||
; |
|||
return this; |
|||
}; |
|||
|
|||
$.fn.accordion.settings = { |
|||
moduleName : 'Accordion', |
|||
debug : false, |
|||
|
|||
exclusive : true, |
|||
collapsible : true, |
|||
|
|||
errors: { |
|||
method : 'The method you called is not defined' |
|||
}, |
|||
|
|||
className : { |
|||
active : 'active', |
|||
hover : 'hover' |
|||
}, |
|||
|
|||
selector : { |
|||
title : '.title', |
|||
icon : '.icon', |
|||
content : '.content' |
|||
}, |
|||
|
|||
speed : 500, |
|||
easing : 'easeInOutQuint' |
|||
|
|||
}; |
|||
|
|||
})( jQuery, window , document ); |
@ -0,0 +1,247 @@ |
|||
/* ****************************** |
|||
Animation |
|||
Author: Jack Lukic |
|||
Notes: First Commit May 24, 2012 |
|||
|
|||
A collection of FX/Animations |
|||
|
|||
****************************** */ |
|||
|
|||
;(function ( $, window, document, undefined ) { |
|||
|
|||
|
|||
// handles simplification of animation settings
|
|||
$.animationSettings = function(settings, duration, easing, complete) { |
|||
// no parameters
|
|||
if(duration === undefined) { |
|||
settings = settings; |
|||
} |
|||
// duration is actually settings object
|
|||
else if(typeof duration == 'object') { |
|||
settings = $.extend({} , settings, duration); |
|||
} |
|||
// easing is actually complete callback
|
|||
else if(typeof easing == 'function') { |
|||
settings = $.extend({} , settings, { |
|||
duration: duration, |
|||
complete: easing |
|||
}); |
|||
} |
|||
// easing is actually settings
|
|||
else if(typeof easing == 'object') { |
|||
settings = $.extend(true, {} , settings, {duration: duration}, easing); |
|||
} |
|||
//
|
|||
else { |
|||
settings = $.extend({} , settings, { |
|||
duration : duration, |
|||
easing : easing, |
|||
complete : complete |
|||
}); |
|||
} |
|||
return settings; |
|||
}; |
|||
|
|||
/* ****************************** |
|||
Pop In - |
|||
Animates one at a time |
|||
scaling in |
|||
****************************** */ |
|||
|
|||
$.fn.popIn = function(duration, easing, complete) { |
|||
var |
|||
settings = $.animationSettings($.fn.popIn.settings, duration, easing, complete), |
|||
|
|||
$this = $(this), |
|||
totalElements = $this.size(), |
|||
currentElement = 0, |
|||
callback = function() { |
|||
var |
|||
elementsDoneAnimating = ($this.filter(':animated').size() == 0) |
|||
; |
|||
currentElement++; |
|||
$(this) |
|||
.css('transform', '') |
|||
.removeClass(settings.className.init) |
|||
; |
|||
$.proxy(settings.eachComplete, this)(); |
|||
if(currentElement == totalElements) { |
|||
$.proxy(settings.complete, $this)(); |
|||
} |
|||
}, |
|||
animate = function(index) { |
|||
$(this) |
|||
.delay(settings.delay * index) |
|||
.animate({ |
|||
opacity : settings.endOpacity, |
|||
transform : 'scale('+ settings.endScale +')' |
|||
}, settings.duration, settings.easing, callback) |
|||
; |
|||
} |
|||
; |
|||
if(settings.isLegacyBrowser) { |
|||
$this |
|||
.show() |
|||
; |
|||
} |
|||
else { |
|||
$this |
|||
.addClass(settings.className.init) |
|||
.show() |
|||
.css({ |
|||
opacity : settings.startOpacity, |
|||
transform : 'scale('+ settings.startScale +')' |
|||
}) |
|||
.each(animate) |
|||
; |
|||
} |
|||
return $(this); |
|||
}; |
|||
|
|||
$.fn.popOut = function(duration, easing, complete) { |
|||
var |
|||
parameters = $.animationSettings($.fn.popIn.settings, duration, easing, complete), |
|||
// flip some defaults
|
|||
defaults = { |
|||
complete: function() { |
|||
$(this).hide(); |
|||
$.proxy(parameters.complete, this)(); |
|||
}, |
|||
startOpacity : parameters.endOpacity, |
|||
endOpacity : 0, |
|||
startScale : parameters.endScale, |
|||
endScale : parameters.startScale |
|||
}, |
|||
settings = $.extend(true, {}, parameters, defaults) |
|||
; |
|||
$(this) |
|||
.popIn(settings) |
|||
; |
|||
}; |
|||
|
|||
$.fn.popIn.settings = { |
|||
|
|||
// legacy browser
|
|||
isLegacyBrowser: ($.browser.msie && parseInt($.browser.version) <= 8), |
|||
|
|||
// class given until animation ends
|
|||
className: { |
|||
init : 'init' |
|||
}, |
|||
// duration of each animation
|
|||
duration : 450, |
|||
// easing for animation
|
|||
easing : 'easeOutExpo', |
|||
// delay before each
|
|||
delay : 100, |
|||
|
|||
startOpacity : 0, |
|||
endOpacity : 1, |
|||
|
|||
startScale : 0.7, |
|||
endScale : 1, |
|||
// called after each element completes
|
|||
eachComplete : function(){}, |
|||
// called after entire chain of animation completes
|
|||
complete : function(){} |
|||
}; |
|||
|
|||
|
|||
$.fn.kenBurns = function(duration, easing, complete) { |
|||
var |
|||
settings = $.animationSettings($.fn.kenBurns.settings, duration, easing, complete), |
|||
module = { |
|||
|
|||
randomPosition: function(starting, rangeMin, rangeMax) { |
|||
var |
|||
rangeMax = (rangeMax !== undefined) |
|||
? rangeMax |
|||
: rangeMin, |
|||
number = Math.random() * ((starting + rangeMax) - (starting - rangeMin) ) + (starting - rangeMin) |
|||
; |
|||
return parseInt(number, 10); |
|||
}, |
|||
|
|||
animate: function() { |
|||
var |
|||
startingPosition = {}, |
|||
endingPosition = {}, |
|||
startingScale, |
|||
endingScale |
|||
; |
|||
|
|||
startingPosition = (settings.useStartPosition) |
|||
? { |
|||
x: parseInt( $(this).css('background-position-x'), 10), |
|||
y: parseInt( $(this).css('background-position-y'), 10) |
|||
} |
|||
: { |
|||
x: module.randomPosition(50, settings.xRange), |
|||
y: module.randomPosition(50, settings.yRange) |
|||
} |
|||
; |
|||
// determine direction of animation based on origin position
|
|||
endingPosition.x = (startingPosition.x > 50) |
|||
? module.randomPosition(startingPosition.x, settings.xMaxTravelDistance, -settings.xMinTravelDistance) |
|||
: module.randomPosition(startingPosition.x, -settings.xMinTravelDistance, settings.xMaxTravelDistance) |
|||
; |
|||
endingPosition.y = (startingPosition.y > 50) |
|||
? module.randomPosition(startingPosition.y, settings.yMaxTravelDistance, -settings.yMinTravelDistance) |
|||
: module.randomPosition(startingPosition.y, -settings.yMinTravelDistance, settings.yMaxTravelDistance) |
|||
; |
|||
|
|||
/*console.log(startingPosition.x + '% ' + startingPosition.y + '%'); |
|||
console.log(endingPosition.x + '% ' + endingPosition.y + '%');*/ |
|||
|
|||
$(this) |
|||
.css({ |
|||
backgroundPosition: startingPosition.x + '%', |
|||
backgroundPositionY: startingPosition.y + '%' |
|||
}) |
|||
.stop() |
|||
.animate({ |
|||
backgroundPosition: endingPosition.x + '%', |
|||
backgroundPositionY: endingPosition.y + '%' |
|||
}, settings.duration, settings.easing, settings.complete) |
|||
; |
|||
} |
|||
|
|||
} |
|||
; |
|||
if(!settings.isLegacyBrowser) { |
|||
$(this) |
|||
.each(module.animate) |
|||
; |
|||
} |
|||
return $(this); |
|||
}; |
|||
|
|||
$.fn.kenBurns.settings = { |
|||
|
|||
// legacy browser
|
|||
isLegacyBrowser : ($.browser.msie && parseInt($.browser.version, 10) <= 8), |
|||
|
|||
// duration of animation
|
|||
duration : 10000, |
|||
// easing for animation
|
|||
easing : 'linear', |
|||
useStartPosition : false, |
|||
|
|||
xRange : 40, |
|||
yRange : 20, |
|||
|
|||
xMinTravelDistance : 30, |
|||
xMaxTravelDistance : 60, |
|||
|
|||
yMinTravelDistance : 20, |
|||
yMaxTravelDistance : 40, |
|||
|
|||
// not yet implemented, need css hook for background-size
|
|||
scale : 0.1, |
|||
|
|||
// called after entire chain of animation completes
|
|||
complete : function(){} |
|||
}; |
|||
|
|||
|
|||
})( jQuery, window , document ); |
@ -0,0 +1,515 @@ |
|||
/* ****************************** |
|||
API |
|||
Author: Jack Lukic |
|||
Notes: First Commit May 08, 2012 |
|||
|
|||
These are modules which bind API functionality to the DOM |
|||
|
|||
Requires: nada |
|||
|
|||
Initialization: |
|||
$('.button') |
|||
.apiButton({ |
|||
success: function() {} |
|||
}) |
|||
; |
|||
|
|||
in our example api is automapped to an object literal |
|||
@ quirky.config.endpoint.api |
|||
|
|||
HTML: |
|||
<div class="button" action="follow" data-id="5"> |
|||
|
|||
URL : quirky.config.endpoint.api.follow |
|||
Given Value: /follow/{$id}/ |
|||
Sent Value : /follow/5/ |
|||
|
|||
(4 ways to map api endpoint, each will be looked for in succession) |
|||
url mapping order: |
|||
first : defined in plugin init as url (arbitrary url) |
|||
second : defined in plugin init as action (action in obj literal grouping 'api') |
|||
third : defined in data-url |
|||
fourth : defined in data-action |
|||
|
|||
beforeSend: |
|||
this callback can be used to modify request settings before XHR |
|||
it also can be used to look for for pre-conditions to prevent API |
|||
call by returning "false" |
|||
|
|||
****************************** */ |
|||
|
|||
;(function ( $, window, document, undefined ) { |
|||
|
|||
$.api = $.fn.api = function(parameters) { |
|||
|
|||
var |
|||
settings = $.extend(true, {}, $.api.settings, parameters), |
|||
|
|||
// if this keyword isn't a jQuery object, create one
|
|||
context = (typeof this != 'function') |
|||
? this |
|||
: $('<div/>'), |
|||
// context defines the element used for loading/error state
|
|||
$context = (settings.stateContext) |
|||
? $(settings.stateContext) |
|||
: $(context), |
|||
// module is the thing that initiates the api action, can be independent of context
|
|||
$module = typeof this == 'object' |
|||
? $(context) |
|||
: $context, |
|||
|
|||
action = $module.data(settings.metadata.action) || settings.action || false, |
|||
|
|||
className = settings.className, |
|||
metadata = settings.metadata, |
|||
errors = settings.errors, |
|||
module |
|||
; |
|||
|
|||
module = { |
|||
initialize: function() { |
|||
var |
|||
exitConditions = false, |
|||
|
|||
runSettings, |
|||
|
|||
loadingTimer = new Date().getTime(), |
|||
loadingDelay, |
|||
|
|||
promise, |
|||
url, |
|||
urlVariables, |
|||
|
|||
formData = {}, |
|||
data, |
|||
|
|||
ajaxSettings = {}, |
|||
xhr, |
|||
|
|||
errors = settings.errors |
|||
; |
|||
|
|||
// serialize parent form if requested!
|
|||
if(settings.serializeForm && $(this).toJSON() !== undefined) { |
|||
formData = $module |
|||
.closest('form') |
|||
.toJSON() |
|||
; |
|||
$.extend(true, settings.data, formData); |
|||
module.debug('Adding form data to API Request', formData); |
|||
} |
|||
|
|||
// let beforesend change settings object
|
|||
runSettings = $.proxy(settings.beforeSend, $module)(settings); |
|||
|
|||
// check for exit conditions
|
|||
if(runSettings !== undefined && !runSettings) { |
|||
module.error(errors.beforeSend); |
|||
module.reset(); |
|||
return; |
|||
} |
|||
|
|||
if(action) { |
|||
module.debug('Initializing API Request for: ', action); |
|||
if(settings.api[action] !== undefined) { |
|||
url = settings.api[action]; |
|||
} |
|||
else { |
|||
module.error(errors.missingAction); |
|||
} |
|||
} |
|||
// override with url if specified
|
|||
if(settings.url) { |
|||
url = settings.url; |
|||
module.debug('Using specified url: ', url); |
|||
} |
|||
|
|||
if(!url) { |
|||
module.error(errors.missingURL); |
|||
module.reset(); |
|||
} |
|||
|
|||
// replace url data in url
|
|||
urlVariables = url.match(settings.regExpTemplate); |
|||
|
|||
if(urlVariables) { |
|||
module.debug('Looking for URL variables', urlVariables); |
|||
$.each(urlVariables, function(index, templateValue){ |
|||
var |
|||
term = templateValue.substr( 2, templateValue.length - 3), |
|||
termValue = ($.isPlainObject(parameters.urlData) && parameters.urlData[term] !== undefined) |
|||
? parameters.urlData[term] |
|||
: ($module.data(term) !== undefined) |
|||
? $module.data(term) |
|||
: settings.urlData[term] |
|||
; |
|||
module.verbose('Looking for variable', term, $module, $module.data(term), settings.urlData[term]); |
|||
// remove optional value
|
|||
if(termValue === false) { |
|||
module.debug('Removing variable from URL', urlVariables); |
|||
url = url.replace('/' + templateValue, ''); |
|||
} |
|||
// undefined condition
|
|||
else if(termValue === undefined || !termValue) { |
|||
module.error(errors.missingParameter + term); |
|||
exitConditions = true; |
|||
} |
|||
else { |
|||
url = url.replace(templateValue, termValue); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
// exit conditions reached from missing url parameters
|
|||
if( exitConditions ) { |
|||
module.reset(); |
|||
return; |
|||
} |
|||
|
|||
// promise handles notification on api request, so loading min. delay can occur for all notifications
|
|||
promise = |
|||
$.Deferred() |
|||
.always(function() { |
|||
if(settings.stateContext) { |
|||
$context |
|||
.removeClass(className.loading) |
|||
; |
|||
} |
|||
$.proxy(settings.complete, $module)(); |
|||
}) |
|||
.done(function(response) { |
|||
module.debug('API request successful'); |
|||
// take a stab at finding success state if json
|
|||
if(settings.dataType == 'json') { |
|||
if(response.success === true) { |
|||
$.proxy(settings.success, $context)(response, settings, $module); |
|||
} |
|||
else { |
|||
module.debug('JSON success flag is not set.'); |
|||
if (response.error !== undefined) { |
|||
$.proxy(settings.failure, $context)(response.error, settings, $module); |
|||
} |
|||
else if ($.isArray(response.errors)) { |
|||
$.proxy(settings.failure, $context)(response.errors[0], settings, $module); |
|||
} |
|||
else if(response.message !== undefined) { |
|||
$.proxy(settings.failure, $context)(response.message, settings, $module); |
|||
} |
|||
else { |
|||
$.proxy(settings.failure, $context)(errors.error, settings, $module); |
|||
} |
|||
} |
|||
} |
|||
// otherwise
|
|||
else { |
|||
$.proxy(settings.success, $context)(response, settings, $module); |
|||
} |
|||
}) |
|||
.fail(function(xhr, status, httpMessage) { |
|||
var |
|||
errorMessage = (settings.errors[status] !== undefined) |
|||
? settings.errors[status] |
|||
: httpMessage, |
|||
response |
|||
; |
|||
// let em know unless request aborted
|
|||
if(xhr !== undefined) { |
|||
// readyState 4 = done, anything less is not really sent
|
|||
if(xhr.readyState !== undefined && xhr.readyState == 4) { |
|||
|
|||
// if http status code returned and json returned error, look for it
|
|||
if( xhr.status != 200 && httpMessage !== undefined && httpMessage !== '') { |
|||
module.error(errors.statusMessage + httpMessage); |
|||
} |
|||
else { |
|||
if(status == 'error' && settings.dataType == 'json') { |
|||
try { |
|||
response = $.parseJSON(xhr.responseText); |
|||
if(response && response.error !== undefined) { |
|||
errorMessage = response.error; |
|||
} |
|||
} |
|||
catch(error) { |
|||
module.error(errors.JSONParse); |
|||
} |
|||
} |
|||
} |
|||
$context |
|||
.removeClass(className.loading) |
|||
.addClass(className.error) |
|||
; |
|||
// show error state only for duration specified in settings
|
|||
if(settings.errorLength > 0) { |
|||
setTimeout(function(){ |
|||
$context |
|||
.removeClass(className.error) |
|||
; |
|||
}, settings.errorLength); |
|||
} |
|||
module.debug('API Request error:', errorMessage); |
|||
$.proxy(settings.failure, $context)(errorMessage, settings, this); |
|||
} |
|||
else { |
|||
module.debug('Request Aborted (Most likely caused by page change)'); |
|||
} |
|||
} |
|||
}) |
|||
; |
|||
|
|||
// look for params in data
|
|||
$.extend(true, ajaxSettings, settings, { |
|||
type : settings.method || settings.type, |
|||
data : data, |
|||
url : url, |
|||
beforeSend : settings.beforeXHR |
|||
}); |
|||
|
|||
if(settings.stateContext) { |
|||
$context |
|||
.addClass(className.loading) |
|||
; |
|||
} |
|||
|
|||
if(settings.progress) { |
|||
module.verbose('Adding progress events'); |
|||
$.extend(true, ajaxSettings, { |
|||
xhr: function() { |
|||
var |
|||
xhr = new window.XMLHttpRequest() |
|||
; |
|||
xhr.upload.addEventListener('progress', function(event) { |
|||
var |
|||
percentComplete |
|||
; |
|||
if (event.lengthComputable) { |
|||
percentComplete = Math.round(event.loaded / event.total * 10000) / 100 + '%'; |
|||
$.proxy(settings.progress, $context)(percentComplete, event); |
|||
} |
|||
}, false); |
|||
xhr.addEventListener('progress', function(event) { |
|||
var |
|||
percentComplete |
|||
; |
|||
if (event.lengthComputable) { |
|||
percentComplete = Math.round(event.loaded / event.total * 10000) / 100 + '%'; |
|||
$.proxy(settings.progress, $context)(percentComplete, event); |
|||
} |
|||
}, false); |
|||
return xhr; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
module.verbose('Creating AJAX request with settings: ', ajaxSettings); |
|||
xhr = |
|||
$.ajax(ajaxSettings) |
|||
.always(function() { |
|||
// calculate if loading time was below minimum threshold
|
|||
loadingDelay = ( settings.loadingLength - (new Date().getTime() - loadingTimer) ); |
|||
settings.loadingDelay = loadingDelay < 0 |
|||
? 0 |
|||
: loadingDelay |
|||
; |
|||
}) |
|||
.done(function(response) { |
|||
var |
|||
context = this |
|||
; |
|||
setTimeout(function(){ |
|||
promise.resolveWith(context, [response]); |
|||
}, settings.loadingDelay); |
|||
}) |
|||
.fail(function(xhr, status, httpMessage) { |
|||
var |
|||
context = this |
|||
; |
|||
// page triggers abort on navigation, dont show error
|
|||
if(status != 'abort') { |
|||
setTimeout(function(){ |
|||
promise.rejectWith(context, [xhr, status, httpMessage]); |
|||
}, settings.loadingDelay); |
|||
} |
|||
else { |
|||
$context |
|||
.removeClass(className.error) |
|||
.removeClass(className.loading) |
|||
; |
|||
} |
|||
}) |
|||
; |
|||
if(settings.stateContext) { |
|||
$module |
|||
.data(metadata.promise, promise) |
|||
.data(metadata.xhr, xhr) |
|||
; |
|||
} |
|||
}, |
|||
|
|||
// reset api request
|
|||
reset: function() { |
|||
$module |
|||
.data(metadata.promise, false) |
|||
.data(metadata.xhr, false) |
|||
; |
|||
$context |
|||
.removeClass(className.error) |
|||
.removeClass(className.loading) |
|||
; |
|||
module.error(errors.exitConditions); |
|||
}, |
|||
|
|||
/* standard module */ |
|||
setting: function(name, value) { |
|||
if(value === undefined) { |
|||
return settings[name]; |
|||
} |
|||
settings[name] = value; |
|||
}, |
|||
verbose: function() { |
|||
if(settings.verbose) { |
|||
module.debug.apply(this, arguments); |
|||
} |
|||
}, |
|||
debug: function() { |
|||
var |
|||
output = [], |
|||
message = settings.moduleName + ': ' + arguments[0], |
|||
variables = [].slice.call( arguments, 1 ), |
|||
log = console.info || console.log || function(){} |
|||
; |
|||
log = Function.prototype.bind.call(log, console); |
|||
if(settings.debug) { |
|||
output.push(message); |
|||
log.apply(console, output.concat(variables) ); |
|||
} |
|||
}, |
|||
error: function() { |
|||
var |
|||
output = [], |
|||
errorMessage = settings.moduleName + ': ' + arguments[0], |
|||
variables = [].slice.call( arguments, 1 ), |
|||
log = console.warn || console.log || function(){} |
|||
; |
|||
log = Function.prototype.bind.call(log, console); |
|||
if(settings.debug) { |
|||
output.push(errorMessage); |
|||
output.concat(variables); |
|||
log.apply(console, output.concat(variables) ); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
module.initialize(); |
|||
return this; |
|||
}; |
|||
|
|||
// handle DOM attachment to API functionality
|
|||
$.fn.apiButton = function(parameters) { |
|||
$(this) |
|||
.each(function(){ |
|||
var |
|||
// if only function passed it is success callback
|
|||
$module = $(this), |
|||
element = this, |
|||
selector = $(this).selector || '', |
|||
|
|||
settings = ( $.isFunction(parameters) ) |
|||
? $.extend(true, {}, $.api.settings, $.fn.apiButton.settings, { stateContext: this, success: parameters }) |
|||
: $.extend(true, {}, $.api.settings, $.fn.apiButton.settings, { stateContext: this}, parameters), |
|||
module |
|||
; |
|||
module = { |
|||
initialize: function() { |
|||
if(settings.context && selector !== '') { |
|||
$(settings.context) |
|||
.on(selector, 'click.' + settings.namespace, module.click) |
|||
; |
|||
} |
|||
else { |
|||
$module |
|||
.on('click.' + settings.namespace, module.click) |
|||
; |
|||
} |
|||
}, |
|||
click: function() { |
|||
if(!settings.filter || $(this).filter(settings.filter).size() === 0) { |
|||
$.proxy( $.api, this )(settings); |
|||
} |
|||
} |
|||
}; |
|||
module.initialize(); |
|||
}) |
|||
; |
|||
return this; |
|||
}; |
|||
|
|||
$.api.settings = { |
|||
moduleName : 'API Module', |
|||
namespace : 'api', |
|||
|
|||
verbose : true, |
|||
debug : true, |
|||
|
|||
api : {}, |
|||
|
|||
beforeSend : function(settings) { |
|||
return settings; |
|||
}, |
|||
beforeXHR : function(xhr) {}, |
|||
|
|||
success : function(response) {}, |
|||
complete : function(response) {}, |
|||
failure : function(errorCode) {}, |
|||
progress : false, |
|||
|
|||
errors : { |
|||
missingAction : 'API action used but no url was defined', |
|||
missingURL : 'URL not specified for the API action', |
|||
missingParameter : 'Missing an essential URL parameter: ', |
|||
|
|||
timeout : 'Your request timed out', |
|||
error : 'There was an error with your request', |
|||
parseError : 'There was an error parsing your request', |
|||
JSONParse : 'JSON could not be parsed during error handling', |
|||
statusMessage : 'Server gave an error: ', |
|||
beforeSend : 'The before send function has aborted the request', |
|||
exitConditions : 'API Request Aborted. Exit conditions met' |
|||
}, |
|||
|
|||
className: { |
|||
loading : 'loading', |
|||
error : 'error' |
|||
}, |
|||
|
|||
metadata: { |
|||
action : 'action', |
|||
promise : 'promise', |
|||
xhr : 'xhr' |
|||
}, |
|||
|
|||
regExpTemplate: /\{\$([A-z]+)\}/g, |
|||
|
|||
action : false, |
|||
url : false, |
|||
urlData : false, |
|||
serializeForm : false, |
|||
|
|||
stateContext : false, |
|||
|
|||
method : 'get', |
|||
data : {}, |
|||
dataType : 'json', |
|||
cache : true, |
|||
|
|||
loadingLength : 200, |
|||
errorLength : 2000 |
|||
|
|||
}; |
|||
|
|||
$.fn.apiButton.settings = { |
|||
filter : '.disabled, .loading', |
|||
context : false, |
|||
stateContext : false |
|||
}; |
|||
|
|||
})( jQuery, window , document ); |
@ -0,0 +1,271 @@ |
|||
/* ****************************** |
|||
Colorizer |
|||
Author: Jack Lukic |
|||
Notes: First Commit June 06, 2012 |
|||
|
|||
Tooltip Wrapper for loading |
|||
colorizes of ideations, concepts and users |
|||
|
|||
Will eventually rewrite to use own tooltip lib |
|||
|
|||
****************************** */ |
|||
|
|||
;(function ( $, window, document, undefined ) { |
|||
|
|||
$.fn.colorize = function(parameters) { |
|||
var |
|||
settings = $.extend(true, {}, $.fn.colorize.settings, parameters), |
|||
// hoist arguments
|
|||
moduleArguments = arguments || false |
|||
; |
|||
$(this) |
|||
.each(function(instanceIndex) { |
|||
|
|||
var |
|||
$module = $(this), |
|||
|
|||
mainCanvas = $('<canvas />')[0], |
|||
imageCanvas = $('<canvas />')[0], |
|||
overlayCanvas = $('<canvas />')[0], |
|||
|
|||
backgroundImage = new Image(), |
|||
|
|||
// defs
|
|||
mainContext, |
|||
imageContext, |
|||
overlayContext, |
|||
|
|||
image, |
|||
imageName, |
|||
|
|||
width, |
|||
height, |
|||
|
|||
// shortucts
|
|||
colors = settings.colors, |
|||
paths = settings.paths, |
|||
namespace = settings.namespace, |
|||
errors = settings.errors, |
|||
|
|||
// boilerplate
|
|||
instance = $module.data('module-' + namespace), |
|||
module |
|||
; |
|||
|
|||
module = { |
|||
|
|||
checkPreconditions: function() { |
|||
module.debug('Checking pre-conditions'); |
|||
|
|||
if( !$.isPlainObject(colors) || $.isEmptyObject(colors) ) { |
|||
module.error(errors.undefinedColors); |
|||
return false; |
|||
} |
|||
return true; |
|||
}, |
|||
|
|||
async: function(callback) { |
|||
if(settings.async) { |
|||
setTimeout(callback, 0); |
|||
} |
|||
else { |
|||
callback(); |
|||
} |
|||
}, |
|||
|
|||
getMetadata: function() { |
|||
module.debug('Grabbing metadata'); |
|||
image = $module.data('image') || settings.image || undefined; |
|||
imageName = $module.data('name') || settings.name || instanceIndex; |
|||
width = settings.width || $module.width(); |
|||
height = settings.height || $module.height(); |
|||
if(width === 0 || height === 0) { |
|||
module.error(errors.undefinedSize); |
|||
} |
|||
}, |
|||
|
|||
initialize: function() { |
|||
module.debug('Initializing with colors', colors); |
|||
if( module.checkPreconditions() ) { |
|||
|
|||
module.async(function() { |
|||
module.getMetadata(); |
|||
module.canvas.create(); |
|||
|
|||
module.draw.image(function() { |
|||
module.draw.colors(); |
|||
module.canvas.merge(); |
|||
}); |
|||
$module |
|||
.data('module-' + namespace, module) |
|||
; |
|||
}); |
|||
} |
|||
}, |
|||
|
|||
redraw: function() { |
|||
module.debug('Redrawing image'); |
|||
module.async(function() { |
|||
module.canvas.clear(); |
|||
module.draw.colors(); |
|||
module.canvas.merge(); |
|||
}); |
|||
}, |
|||
|
|||
change: { |
|||
color: function(colorName, color) { |
|||
module.debug('Changing color', colorName); |
|||
if(colors[colorName] === undefined) { |
|||
module.error(errors.missingColor); |
|||
return false; |
|||
} |
|||
colors[colorName] = color; |
|||
module.redraw(); |
|||
} |
|||
}, |
|||
|
|||
canvas: { |
|||
create: function() { |
|||
module.debug('Creating canvases'); |
|||
|
|||
mainCanvas.width = width; |
|||
mainCanvas.height = height; |
|||
imageCanvas.width = width; |
|||
imageCanvas.height = height; |
|||
overlayCanvas.width = width; |
|||
overlayCanvas.height = height; |
|||
|
|||
mainContext = mainCanvas.getContext('2d'); |
|||
imageContext = imageCanvas.getContext('2d'); |
|||
overlayContext = overlayCanvas.getContext('2d'); |
|||
|
|||
$module |
|||
.append( mainCanvas ) |
|||
; |
|||
mainContext = $module.children('canvas')[0].getContext('2d'); |
|||
}, |
|||
clear: function(context) { |
|||
module.debug('Clearing canvas'); |
|||
overlayContext.fillStyle = '#FFFFFF'; |
|||
overlayContext.fillRect(0, 0, width, height); |
|||
}, |
|||
merge: function() { |
|||
if( !$.isFunction(mainContext.blendOnto) ) { |
|||
module.error(errors.missingPlugin); |
|||
return; |
|||
} |
|||
mainContext.putImageData( imageContext.getImageData(0, 0, width, height), 0, 0); |
|||
overlayContext.blendOnto(mainContext, 'multiply'); |
|||
} |
|||
}, |
|||
|
|||
draw: { |
|||
|
|||
image: function(callback) { |
|||
module.debug('Drawing image'); |
|||
callback = callback || function(){}; |
|||
if(image) { |
|||
backgroundImage.src = image; |
|||
backgroundImage.onload = function() { |
|||
imageContext.drawImage(backgroundImage, 0, 0); |
|||
callback(); |
|||
}; |
|||
} |
|||
else { |
|||
module.error(errors.noImage); |
|||
callback(); |
|||
} |
|||
}, |
|||
|
|||
colors: function() { |
|||
module.debug('Drawing color overlays', colors); |
|||
$.each(colors, function(colorName, color) { |
|||
settings.onDraw(overlayContext, imageName, colorName, color); |
|||
}); |
|||
} |
|||
|
|||
}, |
|||
|
|||
debug: function(message, variableName) { |
|||
if(settings.debug) { |
|||
if(variableName !== undefined) { |
|||
console.info(settings.moduleName + ': ' + message, variableName); |
|||
} |
|||
else { |
|||
console.info(settings.moduleName + ': ' + message); |
|||
} |
|||
} |
|||
}, |
|||
error: function(errorMessage) { |
|||
console.warn(settings.moduleName + ': ' + errorMessage); |
|||
}, |
|||
invoke: function(methodName, context, methodArguments) { |
|||
var |
|||
method |
|||
; |
|||
methodArguments = methodArguments || Array.prototype.slice.call( arguments, 2 ); |
|||
|
|||
if(typeof methodName == 'string' && instance !== undefined) { |
|||
methodName = methodName.split('.'); |
|||
$.each(methodName, function(index, name) { |
|||
if( $.isPlainObject( instance[name] ) ) { |
|||
instance = instance[name]; |
|||
return true; |
|||
} |
|||
else if( $.isFunction( instance[name] ) ) { |
|||
method = instance[name]; |
|||
return true; |
|||
} |
|||
module.error(settings.errors.method); |
|||
return false; |
|||
}); |
|||
} |
|||
return ( $.isFunction( method ) ) |
|||
? method.apply(context, methodArguments) |
|||
: false |
|||
; |
|||
} |
|||
|
|||
}; |
|||
if(instance !== undefined && moduleArguments) { |
|||
// simpler than invoke realizing to invoke itself (and losing scope due prototype.call()
|
|||
if(moduleArguments[0] == 'invoke') { |
|||
moduleArguments = Array.prototype.slice.call( moduleArguments, 1 ); |
|||
} |
|||
return module.invoke(moduleArguments[0], this, Array.prototype.slice.call( moduleArguments, 1 ) ); |
|||
} |
|||
// initializing
|
|||
module.initialize(); |
|||
}) |
|||
; |
|||
return this; |
|||
}; |
|||
|
|||
$.fn.colorize.settings = { |
|||
moduleName : 'Image Colorizer', |
|||
debug : true, |
|||
namespace : 'colorize', |
|||
|
|||
onDraw: function(overlayContext, imageName, colorName, color) {}, |
|||
|
|||
// whether to block execution while updating canvas
|
|||
async: true, |
|||
// object containing names and default values of color regions
|
|||
colors: {}, |
|||
|
|||
metadata: { |
|||
image : 'image', |
|||
name : 'name' |
|||
}, |
|||
|
|||
errors: { |
|||
noImage : 'No tracing image specified', |
|||
undefinedColors : 'No default colors specified.', |
|||
missingColor : 'Attempted to change color that does not exist', |
|||
missingPlugin : 'Blend onto plug-in must be included', |
|||
undefinedHeight : 'The width or height of image canvas could not be automatically determined. Please specify a height.' |
|||
} |
|||
|
|||
}; |
|||
|
|||
})( jQuery, window , document ); |
@ -0,0 +1,104 @@ |
|||
/* ****************************** |
|||
Default Text (Form) |
|||
Author: Jack Lukic |
|||
Notes: First Commit April 08, 2012 |
|||
|
|||
Refactored Aug 13, 2012 |
|||
|
|||
allows you to set a default text value which will be added and removed on form field focus |
|||
|
|||
****************************** */ |
|||
;(function ( $, window, document, undefined ) { |
|||
|
|||
$.fn.defaultText = function(parameters) { |
|||
var |
|||
// overload for shorthand to default value
|
|||
settings = (typeof parameters == 'string') |
|||
? $.extend({}, $.fn.defaultText.settings, { defaultValue: parameters }) |
|||
: $.extend(true, {}, $.fn.defaultText.settings, parameters) |
|||
; |
|||
// overload function
|
|||
if(typeof parameters == 'string') { |
|||
parameters = { defaultValue: parameters }; |
|||
} |
|||
$.extend(settings, parameters); |
|||
$(this) |
|||
.each(function() { |
|||
var |
|||
$element = $(this), |
|||
module = { |
|||
|
|||
checkDefault: function() { |
|||
if($element.val().toLowerCase() != settings.defaultValue.toLowerCase()) { |
|||
$element.addClass(settings.filledClass); |
|||
} |
|||
}, |
|||
|
|||
placeholder: { |
|||
add: function(){ |
|||
if( $element.filter(settings.disabledClassList).size() === 0 ) { |
|||
if( $element.val() == settings.replaceValue ) { |
|||
if(settings.alwaysReplace) { |
|||
$element |
|||
.removeClass(settings.filledClass) |
|||
.val($element.attr('last')) |
|||
.removeAttr('last') |
|||
; |
|||
} |
|||
else { |
|||
$element |
|||
.removeClass(settings.filledClass) |
|||
.val(settings.defaultValue) |
|||
; |
|||
} |
|||
} |
|||
else { |
|||
$element |
|||
.addClass(settings.filledClass) |
|||
; |
|||
} |
|||
} |
|||
}, |
|||
remove: function() { |
|||
if( $element.filter(settings.disabledClassList).size() === 0 ) { |
|||
if(settings.alwaysReplace) { |
|||
$element |
|||
.attr('last', $element.val()) |
|||
.val(settings.replaceValue) |
|||
; |
|||
} |
|||
else { |
|||
if( $element.val().toLowerCase() == settings.defaultValue.toLowerCase() ) { |
|||
$element |
|||
.val(settings.replaceValue) |
|||
; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
; |
|||
if(settings.defaultValue == 'auto') { |
|||
settings.defaultValue = $(this).val(); |
|||
} |
|||
$element |
|||
.on('focus', module.placeholder.remove) |
|||
.on('blur', module.placeholder.add) |
|||
; |
|||
// check for user value on load
|
|||
module.checkDefault(); |
|||
}) |
|||
; |
|||
return this; |
|||
}; |
|||
|
|||
$.fn.defaultText.settings = { |
|||
defaultValue : 'auto', |
|||
replaceValue : '', |
|||
alwaysReplace : false, |
|||
disabledClassList : '.readonly, .disabled', |
|||
filledClass : 'filled' |
|||
}; |
|||
|
|||
})( jQuery, window , document ); |
@ -0,0 +1,649 @@ |
|||
/* ****************************** |
|||
Module |
|||
State |
|||
Change text based on state context |
|||
Hover/Pressed/Active/Inactive |
|||
Author: Jack Lukic |
|||
Last revision: May 2012 |
|||
|
|||
State text module is used to apply text to a given node |
|||
depending on the elements "state" |
|||
|
|||
State is either defined as "active" or "inactive" depending |
|||
on the returned value of a test function |
|||
|
|||
Usage: |
|||
|
|||
$button |
|||
.state({ |
|||
states: { |
|||
active: true |
|||
}, |
|||
text: { |
|||
inactive: 'Follow', |
|||
active : 'Following', |
|||
enable : 'Add', |
|||
disable : 'Remove' |
|||
} |
|||
}) |
|||
; |
|||
|
|||
"Follow", turns to "Add" on hover, then "Following" on active |
|||
and finally "Remove" on active hover |
|||
|
|||
This plugin works in correlation to API module and will, by default, |
|||
use deffered object accept/reject to determine state. |
|||
|
|||
****************************** */ |
|||
|
|||
;(function ( $, window, document, undefined ) { |
|||
|
|||
$.fn.state = function(parameters) { |
|||
var |
|||
|
|||
$allModules = $(this), |
|||
|
|||
// make available in scope
|
|||
selector = $allModules.selector || '', |
|||
query = arguments[0], |
|||
passedArguments = [].slice.call(arguments, 1), |
|||
|
|||
// set up performance tracking
|
|||
time = new Date().getTime(), |
|||
performance = [], |
|||
|
|||
invokedResponse |
|||
; |
|||
$allModules |
|||
.each(function() { |
|||
var |
|||
$module = $(this), |
|||
|
|||
settings = $.extend(true, {}, $.fn.state.settings, parameters), |
|||
|
|||
element = this, |
|||
instance = $module.data('module-' + settings.namespace), |
|||
methodInvoked = (typeof query == 'string'), |
|||
|
|||
// shortcuts
|
|||
namespace = settings.namespace, |
|||
metadata = settings.metadata, |
|||
className = settings.className, |
|||
states = settings.states, |
|||
text = settings.text, |
|||
|
|||
module |
|||
; |
|||
module = { |
|||
|
|||
initialize: function() { |
|||
module.verbose('Initializing module', element); |
|||
|
|||
// allow module to guess desired state based on element
|
|||
if(settings.automatic) { |
|||
module.add.defaults(); |
|||
} |
|||
|
|||
// bind events with delegated events
|
|||
if(settings.context && selector !== '') { |
|||
if( module.allows('hover') ) { |
|||
$(element, settings.context) |
|||
.on(selector, 'mouseenter.' + namespace, module.hover.enable) |
|||
.on(selector, 'mouseleave.' + namespace, module.hover.disable) |
|||
; |
|||
} |
|||
if( module.allows('pressed') ) { |
|||
$(element, settings.context) |
|||
.on(selector, 'mousedown.' + namespace, module.pressed.enable) |
|||
.on(selector, 'mouseup.' + namespace, module.pressed.disable) |
|||
; |
|||
} |
|||
if( module.allows('focus') ) { |
|||
$(element, settings.context) |
|||
.on(selector, 'focus.' + namespace, module.focus.enable) |
|||
.on(selector, 'blur.' + namespace, module.focus.disable) |
|||
; |
|||
} |
|||
$(settings.context) |
|||
.on(selector, 'mouseenter.' + namespace, module.text.change) |
|||
.on(selector, 'mouseleave.' + namespace, module.text.reset) |
|||
.on(selector, 'click.' + namespace, module.toggle) |
|||
; |
|||
|
|||
} |
|||
else { |
|||
if( module.allows('hover') ) { |
|||
$module |
|||
.on('mouseenter.' + namespace, module.hover.enable) |
|||
.on('mouseleave.' + namespace, module.hover.disable) |
|||
; |
|||
} |
|||
if( module.allows('pressed') ) { |
|||
$module |
|||
.on('mousedown.' + namespace, module.pressed.enable) |
|||
.on('mouseup.' + namespace, module.pressed.disable) |
|||
; |
|||
} |
|||
if( module.allows('focus') ) { |
|||
$module |
|||
.on('focus.' + namespace, module.focus.enable) |
|||
.on('blur.' + namespace, module.focus.disable) |
|||
; |
|||
} |
|||
$module |
|||
.on('mouseenter.' + namespace, module.text.change) |
|||
.on('mouseleave.' + namespace, module.text.reset) |
|||
.on('click.' + namespace, module.toggle) |
|||
; |
|||
} |
|||
$module |
|||
.data('module-' + namespace, module) |
|||
; |
|||
}, |
|||
|
|||
destroy: function() { |
|||
module.verbose('Destroying previous module', element); |
|||
$module |
|||
.off('.' + namespace) |
|||
; |
|||
}, |
|||
|
|||
refresh: function() { |
|||
module.verbose('Refreshing selector cache', element); |
|||
$module = $(element); |
|||
}, |
|||
|
|||
add: { |
|||
defaults: function() { |
|||
var |
|||
userStates = parameters && $.isPlainObject(parameters.states) |
|||
? parameters.states |
|||
: {} |
|||
; |
|||
$.each(settings.defaults, function(type, typeStates) { |
|||
if( module.is[type] !== undefined && module.is[type]() ) { |
|||
module.verbose('Adding default states', type, element); |
|||
$.extend(settings.states, typeStates, userStates); |
|||
} |
|||
}); |
|||
} |
|||
}, |
|||
|
|||
is: { |
|||
|
|||
active: function() { |
|||
return $module.hasClass(className.active); |
|||
}, |
|||
loading: function() { |
|||
return $module.hasClass(className.loading); |
|||
}, |
|||
inactive: function() { |
|||
return !( $module.hasClass(className.active) ); |
|||
}, |
|||
|
|||
enabled: function() { |
|||
return !( $module.is(settings.filter.active) ); |
|||
}, |
|||
disabled: function() { |
|||
return ( $module.is(settings.filter.active) ); |
|||
}, |
|||
textEnabled: function() { |
|||
return !( $module.is(settings.filter.text) ); |
|||
}, |
|||
|
|||
// definitions for automatic type detection
|
|||
button: function() { |
|||
return $module.is('.button:not(a, .submit)'); |
|||
}, |
|||
input: function() { |
|||
return $module.is('input'); |
|||
} |
|||
}, |
|||
|
|||
allows: function(state) { |
|||
return states[state] || false; |
|||
}, |
|||
enable: function(state) { |
|||
if(module.allows(state)) { |
|||
$module.addClass( className[state] ); |
|||
} |
|||
}, |
|||
disable: function(state) { |
|||
if(module.allows(state)) { |
|||
$module.removeClass( className[state] ); |
|||
} |
|||
}, |
|||
textFor: function(state) { |
|||
return text[state] || false; |
|||
}, |
|||
|
|||
focus : { |
|||
enable: function() { |
|||
$module.addClass(className.focus); |
|||
}, |
|||
disable: function() { |
|||
$module.removeClass(className.focus); |
|||
} |
|||
}, |
|||
|
|||
hover : { |
|||
enable: function() { |
|||
$module.addClass(className.hover); |
|||
}, |
|||
disable: function() { |
|||
$module.removeClass(className.hover); |
|||
} |
|||
}, |
|||
|
|||
pressed : { |
|||
enable: function() { |
|||
$module |
|||
.addClass(className.pressed) |
|||
.one('mouseleave', module.pressed.disable) |
|||
; |
|||
}, |
|||
disable: function() { |
|||
$module.removeClass(className.pressed); |
|||
} |
|||
}, |
|||
|
|||
// determines method for state activation
|
|||
toggle: function() { |
|||
var |
|||
apiRequest = $module.data(metadata.promise) |
|||
; |
|||
if( module.allows('active') && module.is.enabled() ) { |
|||
module.refresh(); |
|||
if(apiRequest !== undefined) { |
|||
module.listenTo(apiRequest); |
|||
} |
|||
else { |
|||
module.change(); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
listenTo: function(apiRequest) { |
|||
module.debug('API request detected, waiting for state signal', apiRequest); |
|||
if(apiRequest) { |
|||
if(text.loading) { |
|||
module.text.update(text.loading); |
|||
} |
|||
$.when(apiRequest) |
|||
.then(function() { |
|||
if(apiRequest.state() == 'resolved') { |
|||
module.debug('API request succeeded'); |
|||
settings.activateTest = function(){ return true; }; |
|||
settings.deactivateTest = function(){ return true; }; |
|||
} |
|||
else { |
|||
module.debug('API request failed'); |
|||
settings.activateTest = function(){ return false; }; |
|||
settings.deactivateTest = function(){ return false; }; |
|||
} |
|||
module.change(); |
|||
}) |
|||
; |
|||
} |
|||
// xhr exists but set to false, beforeSend killed the xhr
|
|||
else { |
|||
settings.activateTest = function(){ return false; }; |
|||
settings.deactivateTest = function(){ return false; }; |
|||
} |
|||
}, |
|||
|
|||
// checks whether active/inactive state can be given
|
|||
change: function() { |
|||
module.debug('Determining state change direction'); |
|||
// inactive to active change
|
|||
if( module.is.inactive() ) { |
|||
module.activate(); |
|||
} |
|||
else { |
|||
module.deactivate(); |
|||
} |
|||
if(settings.sync) { |
|||
module.sync(); |
|||
} |
|||
settings.onChange(); |
|||
}, |
|||
|
|||
activate: function() { |
|||
if( $.proxy(settings.activateTest, element)() ) { |
|||
module.debug('Setting state to active'); |
|||
$module |
|||
.addClass(className.active) |
|||
; |
|||
module.text.update(text.active); |
|||
} |
|||
}, |
|||
|
|||
deactivate: function() { |
|||
if($.proxy(settings.deactivateTest, element)() ) { |
|||
module.debug('Setting state to inactive'); |
|||
$module |
|||
.removeClass(className.active) |
|||
; |
|||
module.text.update(text.inactive); |
|||
} |
|||
}, |
|||
|
|||
sync: function() { |
|||
module.verbose('Syncing other buttons to current state'); |
|||
if( module.is.active() ) { |
|||
$allModules |
|||
.not($module) |
|||
.state('activate'); |
|||
} |
|||
else { |
|||
$allModules |
|||
.not($module) |
|||
.state('deactivate') |
|||
; |
|||
} |
|||
}, |
|||
|
|||
text: { |
|||
|
|||
// finds text node to update
|
|||
get: function() { |
|||
return (settings.selector.text) |
|||
? $module.find(settings.selector.text).text() |
|||
: $module.html() |
|||
; |
|||
}, |
|||
|
|||
flash: function(text, duration) { |
|||
var |
|||
previousText = module.text.get() |
|||
; |
|||
text = text || settings.text.flash; |
|||
duration = duration || settings.flashDuration; |
|||
module.text.update(text); |
|||
setTimeout(function(){ |
|||
module.text.update(previousText); |
|||
}, duration); |
|||
}, |
|||
|
|||
change: function() { |
|||
module.verbose('Checking if text should be changed'); |
|||
if( module.is.textEnabled() ) { |
|||
if( module.is.active() ) { |
|||
if(text.hover) { |
|||
module.verbose('Changing text to hover text', text.hover); |
|||
module.text.update(text.hover); |
|||
} |
|||
else if(text.disable) { |
|||
module.verbose('Changing text to disable text', text.disable); |
|||
module.text.update(text.disable); |
|||
} |
|||
} |
|||
else { |
|||
if(text.hover) { |
|||
module.verbose('Changing text to hover text', text.disable); |
|||
module.text.update(text.hover); |
|||
} |
|||
else if(text.enable){ |
|||
module.verbose('Changing text to enable text', text.disable); |
|||
module.text.update(text.enable); |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
|
|||
// on mouseout sets text to previous value
|
|||
reset : function() { |
|||
var |
|||
activeText = text.active || $module.data(metadata.storedText), |
|||
inactiveText = text.inactive || $module.data(metadata.storedText) |
|||
; |
|||
if( module.is.textEnabled() ) { |
|||
if( module.is.active() && activeText) { |
|||
module.verbose('Resetting active text', activeText); |
|||
module.text.update(activeText); |
|||
} |
|||
else if(inactiveText) { |
|||
module.verbose('Resetting inactive text', activeText); |
|||
module.text.update(inactiveText); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
update: function(text) { |
|||
var |
|||
currentText = module.text.get() |
|||
; |
|||
if(text && text !== currentText) { |
|||
module.debug('Updating text', text); |
|||
if(settings.selector.text) { |
|||
$module |
|||
.data(metadata.storedText, text) |
|||
.find(settings.selector.text) |
|||
.text(text) |
|||
; |
|||
} |
|||
else { |
|||
$module |
|||
.data(metadata.storedText, text) |
|||
.html(text) |
|||
; |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
/* standard module */ |
|||
setting: function(name, value) { |
|||
if(value === undefined) { |
|||
return settings[name]; |
|||
} |
|||
settings[name] = value; |
|||
}, |
|||
performance: { |
|||
log: function(message) { |
|||
var |
|||
currentTime, |
|||
executionTime |
|||
; |
|||
if(settings.performance) { |
|||
currentTime = new Date().getTime(); |
|||
executionTime = currentTime - time; |
|||
time = currentTime; |
|||
performance.push({ |
|||
'Name' : message, |
|||
'Execution Time' : executionTime |
|||
}); |
|||
clearTimeout(module.performance.timer); |
|||
module.performance.timer = setTimeout(module.performance.display, 100); |
|||
} |
|||
}, |
|||
display: function() { |
|||
var |
|||
title = settings.moduleName + ' Performance (' + selector + ')', |
|||
caption = settings.moduleName + ': ' + selector + '(' + $allModules.size() + ' elements)' |
|||
; |
|||
if(console.group !== undefined && performance.length > 0) { |
|||
console.groupCollapsed(title); |
|||
if(console.table) { |
|||
console.table(performance); |
|||
} |
|||
else { |
|||
$.each(performance, function(index, data) { |
|||
console.log(data['Name'] + ':' + data['Execution Time']); |
|||
}); |
|||
} |
|||
console.groupEnd(); |
|||
performance = []; |
|||
} |
|||
} |
|||
}, |
|||
verbose: function() { |
|||
if(settings.verbose && settings.debug) { |
|||
module.performance.log(arguments[0]); |
|||
module.verbose = Function.prototype.bind.call(console.info, console, settings.moduleName + ':'); |
|||
} |
|||
}, |
|||
debug: function() { |
|||
if(settings.debug) { |
|||
module.performance.log(arguments[0]); |
|||
module.verbose = Function.prototype.bind.call(console.info, console, settings.moduleName + ':'); |
|||
} |
|||
}, |
|||
error: function() { |
|||
if(console.log !== undefined) { |
|||
module.error = Function.prototype.bind.call(console.log, console, settings.moduleName + ':'); |
|||
} |
|||
}, |
|||
invoke: function(query, context, passedArguments) { |
|||
var |
|||
maxDepth, |
|||
found |
|||
; |
|||
passedArguments = passedArguments || [].slice.call( arguments, 2 ); |
|||
if(typeof query == 'string' && instance !== undefined) { |
|||
query = query.split('.'); |
|||
maxDepth = query.length - 1; |
|||
$.each(query, function(depth, value) { |
|||
if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) { |
|||
instance = instance[value]; |
|||
return true; |
|||
} |
|||
else if( instance[value] !== undefined ) { |
|||
found = instance[value]; |
|||
return true; |
|||
} |
|||
module.error(settings.errors.method); |
|||
return false; |
|||
}); |
|||
} |
|||
if ( $.isFunction( found ) ) { |
|||
return found.apply(context, passedArguments); |
|||
} |
|||
// return retrieved variable or chain
|
|||
return found; |
|||
} |
|||
}; |
|||
|
|||
// check for invoking internal method
|
|||
if(methodInvoked) { |
|||
invokedResponse = module.invoke(query, this, passedArguments); |
|||
} |
|||
// otherwise initialize
|
|||
else { |
|||
if(instance !== undefined) { |
|||
module.destroy(); |
|||
} |
|||
module.initialize(); |
|||
} |
|||
}) |
|||
; |
|||
// chain or return queried method
|
|||
return (invokedResponse !== undefined) |
|||
? invokedResponse |
|||
: this |
|||
; |
|||
}; |
|||
|
|||
$.fn.state.settings = { |
|||
|
|||
// module info
|
|||
moduleName : 'State Module', |
|||
|
|||
// debug output
|
|||
debug : true, |
|||
|
|||
// verbose debug output
|
|||
verbose : false, |
|||
|
|||
// namespace for events
|
|||
namespace : 'state', |
|||
|
|||
// debug data includes performance
|
|||
performance: true, |
|||
|
|||
// callback occurs on state change
|
|||
onChange: function() {}, |
|||
|
|||
// state test functions
|
|||
activateTest : function() { return true; }, |
|||
deactivateTest : function() { return true; }, |
|||
|
|||
// whether to automatically map default states
|
|||
automatic : true, |
|||
|
|||
// activate / deactivate changes all elements instantiated at same time
|
|||
sync : false, |
|||
|
|||
// default flash text duration, used for temporarily changing text of an element
|
|||
flashDuration : 3000, |
|||
|
|||
// selector filter
|
|||
filter : { |
|||
text : '.loading, .disabled', |
|||
active : '.disabled' |
|||
}, |
|||
|
|||
context : false, |
|||
// errors
|
|||
errors: { |
|||
method : 'The method you called is not defined.' |
|||
}, |
|||
|
|||
// metadata
|
|||
metadata: { |
|||
promise : 'promise', |
|||
storedText : 'stored-text' |
|||
}, |
|||
|
|||
// change class on state
|
|||
className: { |
|||
focus : 'focus', |
|||
hover : 'hover', |
|||
pressed : 'down', |
|||
active : 'active', |
|||
loading : 'loading' |
|||
}, |
|||
|
|||
selector: { |
|||
// selector for text node
|
|||
text: false |
|||
}, |
|||
|
|||
defaults : { |
|||
input: { |
|||
hover : true, |
|||
focus : true, |
|||
pressed : true, |
|||
loading : false, |
|||
active : false |
|||
}, |
|||
button: { |
|||
hover : true, |
|||
focus : false, |
|||
pressed : true, |
|||
active : false, |
|||
loading : true |
|||
} |
|||
}, |
|||
|
|||
states : { |
|||
hover : true, |
|||
focus : true, |
|||
pressed : true, |
|||
loading : false, |
|||
active : false |
|||
}, |
|||
|
|||
text : { |
|||
flash : false, |
|||
hover : false, |
|||
active : false, |
|||
inactive : false, |
|||
enable : false, |
|||
disable : false |
|||
} |
|||
|
|||
}; |
|||
|
|||
|
|||
|
|||
})( jQuery, window , document ); |
@ -0,0 +1,408 @@ |
|||
/* ****************************** |
|||
Form Validation Components |
|||
Author: Jack Lukic |
|||
Notes: First Commit April 08, 2012 |
|||
|
|||
Refactored Feb 22, 2012 |
|||
|
|||
Allows you to validate forms based on a form validation object |
|||
Form validation objects are bound by either data-validate="" metadata, or form id or name tags |
|||
|
|||
****************************** */ |
|||
|
|||
;(function ( $, window, document, undefined ) { |
|||
|
|||
$.fn.validateForm = function(fields, parameters) { |
|||
var |
|||
$allModules = $(this), |
|||
|
|||
settings = $.extend(true, {}, $.fn.validateForm.settings, parameters), |
|||
// make arguments available
|
|||
query = arguments[0], |
|||
passedArguments = [].slice.call(arguments, 1), |
|||
invokedResponse |
|||
; |
|||
$allModules |
|||
.each(function() { |
|||
var |
|||
$module = $(this), |
|||
$group = $(this).find(settings.selector.group), |
|||
$field = $(this).find(settings.selector.field), |
|||
$errorPrompt = $(this).find(settings.selector.prompt), |
|||
|
|||
formErrors = [], |
|||
|
|||
selector = $module.selector || '', |
|||
element = this, |
|||
instance = $module.data('module-' + settings.namespace), |
|||
methodInvoked = (typeof query == 'string'), |
|||
|
|||
namespace = settings.namespace, |
|||
metadata = settings.metadata, |
|||
className = settings.className, |
|||
errors = settings.errors, |
|||
module |
|||
; |
|||
|
|||
module = { |
|||
|
|||
initialize: function() { |
|||
module.verbose('Initializing form validation'); |
|||
if(fields !== undefined || !$.isEmptyObject(fields) ) { |
|||
// add default text if set
|
|||
if($.fn.defaultText !== undefined) { |
|||
$.each(fields, function(fieldName, field) { |
|||
module.field.add.defaultText(field); |
|||
}); |
|||
} |
|||
// attach event handler
|
|||
$module |
|||
.on('submit.' + namespace, module.validate.form) |
|||
; |
|||
} |
|||
else { |
|||
module.error(errors.noFields, $module); |
|||
} |
|||
}, |
|||
|
|||
destroy: function() { |
|||
$module |
|||
.off(namespace) |
|||
; |
|||
}, |
|||
|
|||
field: { |
|||
find: function(identifier) { |
|||
var |
|||
$field = $module.find(settings.selector.field) |
|||
; |
|||
if( $field.filter('#' + identifier).size() > 0 ) { |
|||
return $field.filter('#' + identifier); |
|||
} |
|||
else if( $field.filter('[name="' + identifier +'"]').size() > 0 ) { |
|||
return $field.filter('[name="' + identifier +'"]'); |
|||
} |
|||
else if( $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]').size() > 0 ) { |
|||
return $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]'); |
|||
} |
|||
return $('<input/>'); |
|||
}, |
|||
add: { |
|||
defaultText: function(field) { |
|||
var |
|||
$field = module.field.find(field.identifier) |
|||
; |
|||
if(field.defaultText !== undefined) { |
|||
$field.defaultText(field.defaultText); |
|||
} |
|||
}, |
|||
error: function(field, errors) { |
|||
var |
|||
$field = module.field.find(field.identifier), |
|||
$errorGroup = $field.closest($group), |
|||
$errorPrompt = $group.find($errorPrompt), |
|||
promptExists = ($errorPrompt.size() !== 0) |
|||
; |
|||
$errorGroup |
|||
.addClass(className.error) |
|||
; |
|||
if(settings.inlineError) { |
|||
// create message container on first invalid validation attempt
|
|||
if(!promptExists) { |
|||
$errorPrompt = $('<div />') |
|||
.addClass(className.prompt) |
|||
.insertBefore($field) |
|||
; |
|||
} |
|||
// add prompt message
|
|||
$errorPrompt |
|||
.html(errors[0]) |
|||
.fadeIn(settings.animateSpeed) |
|||
; |
|||
} |
|||
} |
|||
}, |
|||
remove: { |
|||
error: function(field) { |
|||
var |
|||
$field = module.field.find(field.identifier), |
|||
$errorGroup = $field.closest($group), |
|||
$errorPrompt = $group.find($errorPrompt) |
|||
; |
|||
$errorGroup |
|||
.removeClass(className.error) |
|||
; |
|||
if(settings.inlineError) { |
|||
$errorPrompt.hide(); |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
|
|||
validate: { |
|||
|
|||
form: function(event) { |
|||
var |
|||
allValid = true |
|||
; |
|||
// reset errors
|
|||
formErrors = []; |
|||
$.each(fields, function(fieldName, field){ |
|||
// form is invalid after first bad field, but keep checking
|
|||
if( !( module.validate.field(field) ) ) { |
|||
allValid = false; |
|||
} |
|||
}); |
|||
// Evaluate form callbacks
|
|||
return (allValid) |
|||
? $.proxy(settings.onSuccess, this)(event) |
|||
: $.proxy(settings.onFailure, this)(formErrors) |
|||
; |
|||
}, |
|||
|
|||
// takes a validation object and returns whether field passes validation
|
|||
field: function(field) { |
|||
var |
|||
$field = module.field.find(field.identifier), |
|||
fieldValid = true, |
|||
fieldErrors = [] |
|||
; |
|||
if(field.rules !== undefined) { |
|||
// iterate over all validation types for a certain field
|
|||
$.each(field.rules, function(index, rule) { |
|||
if( !( module.validate.rule(field, rule) ) ) { |
|||
module.debug('Field is invalid', field.identifier, rule.type); |
|||
fieldErrors.push(rule.prompt); |
|||
fieldValid = false; |
|||
} |
|||
}); |
|||
} |
|||
if(fieldValid) { |
|||
module.field.remove.error(field, fieldErrors); |
|||
settings.onValid($field); |
|||
} |
|||
else { |
|||
formErrors = formErrors.concat(fieldErrors); |
|||
module.field.add.error(field, fieldErrors); |
|||
$.proxy(settings.onInvalid, $field)(fieldErrors); |
|||
return false; |
|||
} |
|||
return true; |
|||
}, |
|||
|
|||
// takes validation rule and returns whether field passes rule
|
|||
rule: function(field, validation) { |
|||
var |
|||
$field = module.field.find(field.identifier), |
|||
type = validation.type, |
|||
defaultText = (field.defaultText !== undefined) |
|||
? field.defaultText |
|||
: false, |
|||
value = ($field.val() == defaultText) |
|||
? '' |
|||
: $field.val(), |
|||
|
|||
bracketRegExp = /\[(.*?)\]/i, |
|||
bracket = bracketRegExp.exec(type), |
|||
isValid = true, |
|||
ancillary, |
|||
functionType |
|||
; |
|||
// if bracket notation is used, pass in extra parameters
|
|||
if(bracket !== undefined && bracket != null) { |
|||
ancillary = bracket[1]; |
|||
functionType = type.replace(bracket[0], ''); |
|||
isValid = $.proxy(settings.rules[functionType], $module)(value, ancillary); |
|||
} |
|||
// normal notation
|
|||
else { |
|||
isValid = (type == 'checked') |
|||
? $field.filter(':checked').size() > 0 |
|||
: settings.rules[type](value) |
|||
; |
|||
} |
|||
return isValid; |
|||
} |
|||
}, |
|||
|
|||
/* standard module */ |
|||
setting: function(name, value) { |
|||
if(value === undefined) { |
|||
return settings[name]; |
|||
} |
|||
settings[name] = value; |
|||
}, |
|||
verbose: function() { |
|||
if(settings.verbose) { |
|||
module.debug.apply(this, arguments); |
|||
} |
|||
}, |
|||
debug: function() { |
|||
var |
|||
output = [], |
|||
message = settings.moduleName + ': ' + arguments[0], |
|||
variables = [].slice.call( arguments, 1 ), |
|||
log = console.info || console.log || function(){} |
|||
; |
|||
log = Function.prototype.bind.call(log, console); |
|||
if(settings.debug) { |
|||
output.push(message); |
|||
log.apply(console, output.concat(variables) ); |
|||
} |
|||
}, |
|||
error: function() { |
|||
var |
|||
output = [], |
|||
errorMessage = settings.moduleName + ': ' + arguments[0], |
|||
variables = [].slice.call( arguments, 1 ), |
|||
log = console.warn || console.log || function(){} |
|||
; |
|||
log = Function.prototype.bind.call(log, console); |
|||
if(settings.debug) { |
|||
output.push(errorMessage); |
|||
output.concat(variables); |
|||
log.apply(console, output.concat(variables) ); |
|||
} |
|||
}, |
|||
invoke: function(query, context, passedArguments) { |
|||
var |
|||
maxDepth, |
|||
found |
|||
; |
|||
passedArguments = passedArguments || [].slice.call( arguments, 2 ); |
|||
if(typeof query == 'string' && instance !== undefined) { |
|||
query = query.split('.'); |
|||
maxDepth = query.length - 1; |
|||
$.each(query, function(depth, value) { |
|||
if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) { |
|||
instance = instance[value]; |
|||
return true; |
|||
} |
|||
else if( instance[value] !== undefined ) { |
|||
found = instance[value]; |
|||
return true; |
|||
} |
|||
module.error(errors.method); |
|||
return false; |
|||
}); |
|||
} |
|||
if ( $.isFunction( found ) ) { |
|||
return found.apply(context, passedArguments); |
|||
} |
|||
// return retrieved variable or chain
|
|||
return found; |
|||
} |
|||
}; |
|||
|
|||
// check for invoking internal method
|
|||
if(methodInvoked) { |
|||
invokedResponse = module.invoke(query, this, passedArguments); |
|||
} |
|||
// otherwise initialize
|
|||
else { |
|||
module.initialize(); |
|||
} |
|||
|
|||
}) |
|||
; |
|||
// chain or return queried method
|
|||
return (invokedResponse !== undefined) |
|||
? invokedResponse |
|||
: this |
|||
; |
|||
}; |
|||
|
|||
$.fn.validateForm.settings = { |
|||
|
|||
// module info
|
|||
moduleName : 'Validate Form Module', |
|||
debug : true, |
|||
verbose : false, |
|||
namespace : 'validate', |
|||
|
|||
animateSpeed : 150, |
|||
inlineError : false, |
|||
|
|||
onValid : function() {}, |
|||
onInvalid : function() {}, |
|||
onSuccess : function() { return true; }, |
|||
onFailure : function() { return false; }, |
|||
|
|||
metadata : { |
|||
validate: 'validate' |
|||
}, |
|||
|
|||
// errors
|
|||
errors: { |
|||
method : 'The method you called is not defined.', |
|||
noFields : 'No validation object specified.' |
|||
}, |
|||
|
|||
|
|||
selector : { |
|||
group : '.field', |
|||
prompt : '.prompt', |
|||
field : 'input, textarea, select' |
|||
}, |
|||
|
|||
className : { |
|||
error : 'error', |
|||
prompt : 'prompt' |
|||
}, |
|||
|
|||
rules: { |
|||
empty: function(value) { |
|||
return !(value === undefined || '' === value); |
|||
}, |
|||
email: function(value){ |
|||
var |
|||
emailRegExp = new RegExp("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?") |
|||
; |
|||
return emailRegExp.test(value); |
|||
}, |
|||
length: function(value, requiredLength) { |
|||
return (value !== undefined) |
|||
? (value.length >= requiredLength) |
|||
: false |
|||
; |
|||
}, |
|||
not: function(value, notValue) { |
|||
return (value != notValue); |
|||
}, |
|||
maxLength: function(value, maxLength) { |
|||
return (value !== undefined) |
|||
? (value.length <= maxLength) |
|||
: false |
|||
; |
|||
}, |
|||
match: function(value, matchingField) { |
|||
// use either id or name of field
|
|||
var |
|||
$form = $(this), |
|||
matchingValue |
|||
; |
|||
if($form.find('#' + matchingField).size() > 0) { |
|||
matchingValue = $form.find('#' + matchingField).val(); |
|||
} |
|||
else if($form.find('[name=' + matchingField +']').size() > 0) { |
|||
matchingValue = $form.find('[name=' + matchingField + ']').val(); |
|||
} |
|||
else if( $form.find('[data-validate="'+ matchingField +'"]').size() > 0 ) { |
|||
matchingValue = $form.find('[data-validate="'+ matchingField +'"]').val(); |
|||
} |
|||
return (matchingValue !== undefined) |
|||
? ( value.toString() == matchingValue.toString() ) |
|||
: false |
|||
; |
|||
}, |
|||
url: function(value) { |
|||
var |
|||
urlRegExp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/ |
|||
; |
|||
return urlRegExp.test(value); |
|||
} |
|||
} |
|||
|
|||
}; |
|||
|
|||
})( jQuery, window , document ); |
@ -0,0 +1,697 @@ |
|||
/* ****************************** |
|||
Module - Chat Room |
|||
Author: Jack Lukic |
|||
Notes: First Commit Aug 8, 2012 |
|||
|
|||
Designed as a simple modular chat component |
|||
****************************** */ |
|||
|
|||
;(function ($, window, document, undefined) { |
|||
|
|||
$.fn.chat = function(key, channelName, parameters) { |
|||
var |
|||
settings = $.extend(true, {}, $.fn.chat.settings, parameters), |
|||
// hoist arguments
|
|||
moduleArguments = arguments || false |
|||
; |
|||
$(this) |
|||
.each(function() { |
|||
var |
|||
$module = $(this), |
|||
$expandButton = $module.find(settings.selector.expandButton), |
|||
$userListButton = $module.find(settings.selector.userListButton), |
|||
$userList = $module.find(settings.selector.userList), |
|||
$room = $module.find(settings.selector.room), |
|||
$userCount = $module.find(settings.selector.userCount), |
|||
|
|||
$log = $module.find(settings.selector.log), |
|||
$message = $module.find(settings.selector.message), |
|||
|
|||
$messageInput = $module.find(settings.selector.messageInput), |
|||
$messageButton = $module.find(settings.selector.messageButton), |
|||
|
|||
instance = $module.data('module'), |
|||
|
|||
className = settings.className, |
|||
namespace = settings.namespace, |
|||
|
|||
html = '', |
|||
users = {}, |
|||
loggedInUser, |
|||
|
|||
message, |
|||
count, |
|||
|
|||
height, |
|||
|
|||
pusher, |
|||
module |
|||
; |
|||
|
|||
module = { |
|||
|
|||
channel: false, |
|||
width: { |
|||
log : $log.width(), |
|||
userList : $userList.outerWidth() |
|||
}, |
|||
|
|||
initialize: function() { |
|||
|
|||
// check error conditions
|
|||
if(Pusher === undefined) { |
|||
module.error(settings.errors.pusher); |
|||
} |
|||
if(key === undefined || channelName === undefined) { |
|||
module.error(settings.errors.key); |
|||
return false; |
|||
} |
|||
else if( !(settings.endpoint.message || settings.endpoint.authentication) ) { |
|||
module.error(settings.errors.endpoint); |
|||
return false; |
|||
} |
|||
|
|||
// define pusher
|
|||
pusher = new Pusher(key); |
|||
Pusher.channel_auth_endpoint = settings.endpoint.authentication; |
|||
|
|||
module.channel = pusher.subscribe(channelName); |
|||
|
|||
module.channel.bind('pusher:subscription_succeeded', module.user.list.create); |
|||
module.channel.bind('pusher:subscription_error', module.error); |
|||
module.channel.bind('pusher:member_added', module.user.joined); |
|||
module.channel.bind('pusher:member_removed', module.user.left); |
|||
module.channel.bind('update_messages', module.message.receive); |
|||
|
|||
$.each(settings.customEvents, function(label, value) { |
|||
module.channel.bind(label, value); |
|||
}); |
|||
|
|||
// expandable with states
|
|||
if( $.fn.hoverClass !== undefined && $.fn.downClass !== undefined ) { |
|||
$expandButton |
|||
.hoverClass() |
|||
.downClass() |
|||
; |
|||
$userListButton |
|||
.hoverClass() |
|||
.downClass() |
|||
; |
|||
$messageButton |
|||
.hoverClass() |
|||
.downClass() |
|||
; |
|||
} |
|||
// bind module events
|
|||
$userListButton |
|||
.on('click.' + namespace, module.event.toggleUserList) |
|||
; |
|||
$expandButton |
|||
.on('click.' + namespace, module.event.toggleExpand) |
|||
; |
|||
$messageInput |
|||
.on('keydown.' + namespace, module.event.input.keydown) |
|||
.on('keyup.' + namespace, module.event.input.keyup) |
|||
; |
|||
$messageButton |
|||
.on('mouseenter.' + namespace, module.event.hover) |
|||
.on('mouseleave.' + namespace, module.event.hover) |
|||
.on('click.' + namespace, module.event.submit) |
|||
; |
|||
// scroll to bottom of chat log
|
|||
$log |
|||
.animate({ |
|||
scrollTop: $log.prop('scrollHeight') |
|||
}, 400) |
|||
; |
|||
$module |
|||
.data('module', module) |
|||
.addClass(className.loading) |
|||
; |
|||
|
|||
}, |
|||
|
|||
// refresh module
|
|||
refresh: function() { |
|||
// reset width calculations
|
|||
$userListButton |
|||
.removeClass(className.active) |
|||
; |
|||
module.width = { |
|||
log : $log.width(), |
|||
userList : $userList.outerWidth() |
|||
}; |
|||
if( $userListButton.hasClass(className.active) ) { |
|||
module.user.list.hide(); |
|||
} |
|||
$module.data('module', module); |
|||
}, |
|||
|
|||
user: { |
|||
|
|||
updateCount: function() { |
|||
if(settings.userCount) { |
|||
users = $module.data('users'); |
|||
count = 0; |
|||
$.each(users, function(index){ |
|||
count++; |
|||
}); |
|||
$userCount |
|||
.html( settings.templates.userCount(count) ) |
|||
; |
|||
} |
|||
}, |
|||
|
|||
// add user to user list
|
|||
joined: function(member) { |
|||
users = $module.data('users'); |
|||
if(member.id != 'anonymous' && users[ member.id ] === undefined ) { |
|||
users[ member.id ] = member.info; |
|||
if(settings.randomColor && member.info.color === undefined) { |
|||
member.info.color = settings.templates.color(member.id); |
|||
} |
|||
html = settings.templates.userList(member.info); |
|||
if(member.info.isAdmin) { |
|||
$(html) |
|||
.prependTo($userList) |
|||
.preview({ |
|||
type : 'user', |
|||
placement : 'left' |
|||
}) |
|||
; |
|||
} |
|||
else { |
|||
$(html) |
|||
.appendTo($userList) |
|||
.preview({ |
|||
type : 'user', |
|||
placement : 'left' |
|||
}) |
|||
; |
|||
} |
|||
if( $.fn.preview !== undefined ) { |
|||
$userList |
|||
.children() |
|||
.last() |
|||
.preview({ |
|||
type: 'user', |
|||
placement: 'left' |
|||
}) |
|||
; |
|||
} |
|||
if(settings.partingMessages) { |
|||
$log |
|||
.append( settings.templates.joined(member.info) ) |
|||
; |
|||
module.message.scroll.test(); |
|||
} |
|||
module.user.updateCount(); |
|||
} |
|||
}, |
|||
|
|||
// remove user from user list
|
|||
left: function(member) { |
|||
users = $module.data('users'); |
|||
if(member !== undefined && member.id !== 'anonymous') { |
|||
delete users[ member.id ]; |
|||
$module |
|||
.data('users', users) |
|||
; |
|||
$userList |
|||
.find('[data-id='+ member.id + ']') |
|||
.remove() |
|||
; |
|||
if(settings.partingMessages) { |
|||
$log |
|||
.append( settings.templates.left(member.info) ) |
|||
; |
|||
module.message.scroll.test(); |
|||
} |
|||
module.user.updateCount(); |
|||
} |
|||
}, |
|||
|
|||
list: { |
|||
|
|||
// receives list of members and generates user list
|
|||
create: function(members) { |
|||
users = {}; |
|||
members.each(function(member) { |
|||
if(member.id !== 'anonymous' && member.id !== 'undefined') { |
|||
if(settings.randomColor && member.info.color === undefined) { |
|||
member.info.color = settings.templates.color(member.id); |
|||
} |
|||
// sort list with admin first
|
|||
html = (member.info.isAdmin) |
|||
? settings.templates.userList(member.info) + html |
|||
: html + settings.templates.userList(member.info) |
|||
; |
|||
users[ member.id ] = member.info; |
|||
} |
|||
}); |
|||
$module |
|||
.data('users', users) |
|||
.data('user', users[members.me.id] ) |
|||
.removeClass(className.loading) |
|||
; |
|||
$userList |
|||
.html(html) |
|||
; |
|||
if( $.fn.preview !== undefined ) { |
|||
$userList |
|||
.children() |
|||
.preview({ |
|||
type: 'user', |
|||
placement: 'left' |
|||
}) |
|||
; |
|||
} |
|||
module.user.updateCount(); |
|||
$.proxy(settings.onJoin, $userList.children())(); |
|||
}, |
|||
|
|||
// shows user list
|
|||
show: function() { |
|||
$log |
|||
.animate({ |
|||
width: (module.width.log - module.width.userList) |
|||
}, { |
|||
duration : settings.speed, |
|||
easing : settings.easing, |
|||
complete : module.message.scroll.move |
|||
}) |
|||
; |
|||
}, |
|||
|
|||
// hides user list
|
|||
hide: function() { |
|||
$log |
|||
.stop() |
|||
.animate({ |
|||
width: (module.width.log) |
|||
}, { |
|||
duration : settings.speed, |
|||
easing : settings.easing, |
|||
complete : module.message.scroll.move |
|||
}) |
|||
; |
|||
} |
|||
|
|||
} |
|||
|
|||
}, |
|||
|
|||
message: { |
|||
|
|||
// handles scrolling of chat log
|
|||
scroll: { |
|||
test: function() { |
|||
height = $log.prop('scrollHeight') - $log.height(); |
|||
if( Math.abs($log.scrollTop() - height) < settings.scrollArea) { |
|||
module.message.scroll.move(); |
|||
} |
|||
}, |
|||
|
|||
move: function() { |
|||
height = $log.prop('scrollHeight') - $log.height(); |
|||
$log |
|||
.scrollTop(height) |
|||
; |
|||
} |
|||
}, |
|||
|
|||
// sends chat message
|
|||
send: function(message) { |
|||
if( !module.utils.emptyString(message) ) { |
|||
$.api({ |
|||
url : settings.endpoint.message, |
|||
method : 'POST', |
|||
data : { |
|||
'chat_message': { |
|||
content : message, |
|||
timestamp : new Date().getTime() |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
}, |
|||
|
|||
// receives chat response and processes
|
|||
receive: function(response) { |
|||
message = response.data; |
|||
users = $module.data('users'); |
|||
loggedInUser = $module.data('user'); |
|||
if(users[ message.userID] !== undefined) { |
|||
// logged in user's messages already pushed instantly
|
|||
if(loggedInUser === undefined || loggedInUser.id != message.userID) { |
|||
message.user = users[ message.userID ]; |
|||
module.message.display(message); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
// displays message in chat log
|
|||
display: function(message) { |
|||
$log |
|||
.append( settings.templates.message(message) ) |
|||
; |
|||
module.message.scroll.test(); |
|||
$.proxy(settings.onMessage, $log.children().last() )(); |
|||
} |
|||
|
|||
}, |
|||
|
|||
expand: function() { |
|||
$module |
|||
.addClass(className.expand) |
|||
; |
|||
$.proxy(settings.onExpand, $module )(); |
|||
module.refresh(); |
|||
}, |
|||
|
|||
contract: function() { |
|||
$module |
|||
.removeClass(className.expand) |
|||
; |
|||
$.proxy(settings.onContract, $module )(); |
|||
module.refresh(); |
|||
}, |
|||
|
|||
event: { |
|||
|
|||
input: { |
|||
|
|||
keydown: function(event) { |
|||
if(event.which == 13) { |
|||
$messageButton |
|||
.addClass(className.down) |
|||
; |
|||
} |
|||
}, |
|||
|
|||
keyup: function(event) { |
|||
if(event.which == 13) { |
|||
$messageButton |
|||
.removeClass(className.down) |
|||
; |
|||
module.event.submit(); |
|||
} |
|||
} |
|||
|
|||
}, |
|||
|
|||
// handles message form submit
|
|||
submit: function() { |
|||
var |
|||
message = $messageInput.val(), |
|||
loggedInUser = $module.data('user') |
|||
; |
|||
if(loggedInUser !== undefined && !module.utils.emptyString(message)) { |
|||
module.message.send(message); |
|||
// display immediately
|
|||
module.message.display({ |
|||
user: loggedInUser, |
|||
text: message |
|||
}); |
|||
module.message.scroll.move(); |
|||
$messageInput |
|||
.val('') |
|||
; |
|||
|
|||
} |
|||
}, |
|||
|
|||
// handles button click on expand button
|
|||
toggleExpand: function() { |
|||
if( !$module.hasClass(className.expand) ) { |
|||
$expandButton |
|||
.addClass(className.active) |
|||
; |
|||
module.expand(); |
|||
} |
|||
else { |
|||
$expandButton |
|||
.removeClass(className.active) |
|||
; |
|||
module.contract(); |
|||
} |
|||
}, |
|||
|
|||
// handles button click on user list button
|
|||
toggleUserList: function() { |
|||
if( !$log.is(':animated') ) { |
|||
if( !$userListButton.hasClass(className.active) ) { |
|||
$userListButton |
|||
.addClass(className.active) |
|||
; |
|||
module.user.list.show(); |
|||
} |
|||
else { |
|||
$userListButton |
|||
.removeClass('active') |
|||
; |
|||
module.user.list.hide(); |
|||
} |
|||
} |
|||
|
|||
} |
|||
}, |
|||
|
|||
utils: { |
|||
|
|||
emptyString: function(string) { |
|||
if(typeof string == 'string') { |
|||
return (string.search(/\S/) == -1); |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
}, |
|||
|
|||
// standard methods
|
|||
debug: function(message) { |
|||
if(settings.debug) { |
|||
console.info(settings.moduleName + ': ' + message); |
|||
} |
|||
}, |
|||
error: function(errorMessage) { |
|||
console.warn(settings.moduleName + ': ' + errorMessage); |
|||
}, |
|||
invoke: function(methodName, context, methodArguments) { |
|||
var |
|||
method |
|||
; |
|||
methodArguments = methodArguments || Array.prototype.slice.call( arguments, 2 ); |
|||
if(typeof methodName == 'string' && instance !== undefined) { |
|||
methodName = methodName.split('.'); |
|||
$.each(methodName, function(index, name) { |
|||
if( $.isPlainObject( instance[name] ) ) { |
|||
instance = instance[name]; |
|||
return true; |
|||
} |
|||
else if( $.isFunction( instance[name] ) ) { |
|||
method = instance[name]; |
|||
return true; |
|||
} |
|||
module.error(settings.errors.method); |
|||
return false; |
|||
}); |
|||
} |
|||
return ( $.isFunction( method ) ) |
|||
? method.apply(context, methodArguments) |
|||
: false |
|||
; |
|||
} |
|||
|
|||
}; |
|||
|
|||
if(instance !== undefined && moduleArguments) { |
|||
// simpler than invoke realizing to invoke itself (and losing scope due prototype.call()
|
|||
if(moduleArguments[0] == 'invoke') { |
|||
moduleArguments = Array.prototype.slice.call( moduleArguments, 1 ); |
|||
} |
|||
return module.invoke(moduleArguments[0], this, Array.prototype.slice.call( moduleArguments, 1 ) ); |
|||
} |
|||
// initializing
|
|||
module.initialize(); |
|||
}) |
|||
; |
|||
|
|||
return this; |
|||
}; |
|||
|
|||
$.fn.chat.settings = { |
|||
|
|||
moduleName : 'Chat Module', |
|||
debug : false, |
|||
namespace : 'chat', |
|||
|
|||
onJoin : function(){}, |
|||
onMessage : function(){}, |
|||
onExpand : function(){}, |
|||
onContract : function(){}, |
|||
|
|||
customEvents : {}, |
|||
|
|||
partingMessages : false, |
|||
userCount : true, |
|||
|
|||
randomColor : true, |
|||
|
|||
speed : 300, |
|||
easing : 'easeOutQuint', |
|||
|
|||
// pixels from bottom of chat log that should trigger auto scroll to bottom
|
|||
scrollArea : 9999, |
|||
|
|||
endpoint : { |
|||
message : false, |
|||
authentication : false |
|||
}, |
|||
|
|||
errors: { |
|||
method : 'The method you called is not defined', |
|||
endpoint : 'Please define a message and authentication endpoint.', |
|||
key : 'You must specify a pusher key and channel.', |
|||
pusher : 'You must include the Pusher library.' |
|||
}, |
|||
|
|||
className : { |
|||
expand : 'expand', |
|||
active : 'active', |
|||
hover : 'hover', |
|||
down : 'down', |
|||
loading : 'loading' |
|||
}, |
|||
|
|||
selector : { |
|||
userCount : '.actions .message', |
|||
userListButton : '.actions .button.user-list', |
|||
expandButton : '.actions .button.expand', |
|||
room : '.room', |
|||
userList : '.room .user-list', |
|||
log : '.room .log', |
|||
message : '.room .log .message', |
|||
author : '.room log .message .author', |
|||
messageInput : '.talk input', |
|||
messageButton : '.talk .send.button' |
|||
}, |
|||
|
|||
templates: { |
|||
|
|||
userCount: function(number) { |
|||
return number + ' users in chat'; |
|||
}, |
|||
|
|||
color: function(userID) { |
|||
var |
|||
colors = [ |
|||
'#000000', |
|||
'#333333', |
|||
'#666666', |
|||
'#999999', |
|||
'#CC9999', |
|||
'#CC6666', |
|||
'#CC3333', |
|||
'#993333', |
|||
'#663333', |
|||
'#CC6633', |
|||
'#CC9966', |
|||
'#CC9933', |
|||
'#999966', |
|||
'#CCCC66', |
|||
'#99CC66', |
|||
'#669933', |
|||
'#669966', |
|||
'#33A3CC', |
|||
'#336633', |
|||
'#33CCCC', |
|||
'#339999', |
|||
'#336666', |
|||
'#336699', |
|||
'#6666CC', |
|||
'#9966CC', |
|||
'#333399', |
|||
'#663366', |
|||
'#996699', |
|||
'#993366', |
|||
'#CC6699' |
|||
] |
|||
; |
|||
return colors[ Math.floor( Math.random() * colors.length) ]; |
|||
}, |
|||
|
|||
message: function(message) { |
|||
var |
|||
html = '' |
|||
; |
|||
if(message.user.isAdmin) { |
|||
message.user.color = '#55356A'; |
|||
html += '<div class="admin message">'; |
|||
html += '<span class="quirky ui flag team"></span>'; |
|||
} |
|||
/* |
|||
else if(message.user.isPro) { |
|||
html += '<div class="indent message">'; |
|||
html += '<span class="quirky ui flag pro"></span>'; |
|||
} |
|||
*/ |
|||
else { |
|||
html += '<div class="message">'; |
|||
} |
|||
html += '<p>'; |
|||
if(message.user.color !== undefined) { |
|||
html += '<span class="author" style="color: ' + message.user.color + ';">' + message.user.name + '</span>: '; |
|||
} |
|||
else { |
|||
html += '<span class="author">' + message.user.name + '</span>: '; |
|||
} |
|||
html += '' |
|||
+ message.text |
|||
+ ' </p>' |
|||
+ '</div>' |
|||
; |
|||
return html; |
|||
}, |
|||
|
|||
joined: function(member) { |
|||
return (typeof member.name !== undefined) |
|||
? '<div class="status">' + member.name + ' has joined the chat.</div>' |
|||
: false |
|||
; |
|||
}, |
|||
left: function(member) { |
|||
return (typeof member.name !== undefined) |
|||
? '<div class="status">' + member.name + ' has left the chat.</div>' |
|||
: false |
|||
; |
|||
}, |
|||
|
|||
userList: function(member) { |
|||
var |
|||
html = '' |
|||
; |
|||
if(member.isAdmin) { |
|||
member.color = '#55356A'; |
|||
} |
|||
html += '' |
|||
+ '<div class="user" data-id="' + member.id + '">' |
|||
+ ' <div class="image">' |
|||
+ ' <img src="' + member.avatarURL + '">' |
|||
+ ' </div>' |
|||
; |
|||
if(member.color !== undefined) { |
|||
html += ' <p><a href="/users/' + member.id + '" target="_blank" style="color: ' + member.color + ';">' + member.name + '</a></p>'; |
|||
} |
|||
else { |
|||
html += ' <p><a href="/users/' + member.id + '" target="_blank">' + member.name + '</a></p>'; |
|||
} |
|||
html += '</div>'; |
|||
return html; |
|||
} |
|||
|
|||
} |
|||
|
|||
}; |
|||
|
|||
})( jQuery, window , document ); |
@ -0,0 +1,216 @@ |
|||
/* ****************************** |
|||
Semantic Module: Checkbox |
|||
Author: Jack Lukic |
|||
Notes: First Commit March 25, 2013 |
|||
|
|||
Simple plug-in which maintains the state for ui checkbox |
|||
This can be done without javascript, only in instances |
|||
where each checkbox is assigned a unique ID. This provides a separate |
|||
programmatic option when that is not possible. |
|||
|
|||
****************************** */ |
|||
|
|||
;(function ( $, window, document, undefined ) { |
|||
|
|||
$.fn.checkbox = function(parameters) { |
|||
var |
|||
$allModules = $(this), |
|||
|
|||
settings = $.extend(true, {}, $.fn.checkbox.settings, parameters), |
|||
// make arguments available
|
|||
query = arguments[0], |
|||
passedArguments = [].slice.call(arguments, 1), |
|||
invokedResponse |
|||
; |
|||
$allModules |
|||
.each(function() { |
|||
var |
|||
$module = $(this), |
|||
$input = $(this).find(settings.selector.input), |
|||
|
|||
selector = $module.selector || '', |
|||
element = this, |
|||
instance = $module.data('module-' + settings.namespace), |
|||
methodInvoked = (typeof query == 'string'), |
|||
|
|||
className = settings.className, |
|||
namespace = settings.namespace, |
|||
errors = settings.errors, |
|||
module |
|||
; |
|||
|
|||
module = { |
|||
|
|||
initialize: function() { |
|||
if(settings.context && selector !== '') { |
|||
module.verbose('Initializing checkbox with delegated events', $module); |
|||
$(element, settings.context) |
|||
.on(selector, 'click.' + namespace, module.toggle) |
|||
; |
|||
} |
|||
else { |
|||
module.verbose('Initializing checkbox with bound events', $module); |
|||
$module |
|||
.on('click.' + namespace, module.toggle) |
|||
; |
|||
} |
|||
}, |
|||
|
|||
destroy: function() { |
|||
module.verbose('Destroying previous module for', $module); |
|||
$module |
|||
.off(namespace) |
|||
; |
|||
}, |
|||
|
|||
toggle: function() { |
|||
if( $input.prop('checked') === undefined || !$input.prop('checked') ) { |
|||
module.enable(); |
|||
} |
|||
else { |
|||
module.disable(); |
|||
} |
|||
}, |
|||
|
|||
enable: function() { |
|||
module.debug('Enabling checkbox'); |
|||
$module |
|||
.addClass(className.active) |
|||
; |
|||
$input |
|||
.prop('checked', true) |
|||
; |
|||
$.proxy(settings.onChange, $input.get())(); |
|||
$.proxy(settings.onEnable, $input.get())(); |
|||
}, |
|||
|
|||
disable: function() { |
|||
module.debug('Disabling checkbox'); |
|||
$module |
|||
.removeClass(className.active) |
|||
; |
|||
$input |
|||
.prop('checked', false) |
|||
; |
|||
$.proxy(settings.onChange, $input.get())(); |
|||
$.proxy(settings.onDisable, $input.get())(); |
|||
}, |
|||
|
|||
/* standard module */ |
|||
setting: function(name, value) { |
|||
if(value === undefined) { |
|||
return settings[name]; |
|||
} |
|||
settings[name] = value; |
|||
}, |
|||
verbose: function() { |
|||
if(settings.verbose) { |
|||
module.debug.apply(this, arguments); |
|||
} |
|||
}, |
|||
debug: function() { |
|||
var |
|||
output = [], |
|||
message = settings.moduleName + ': ' + arguments[0], |
|||
variables = [].slice.call( arguments, 1 ), |
|||
log = console.info || console.log || function(){} |
|||
; |
|||
log = Function.prototype.bind.call(log, console); |
|||
if(settings.debug) { |
|||
output.push(message); |
|||
log.apply(console, output.concat(variables) ); |
|||
} |
|||
}, |
|||
error: function() { |
|||
var |
|||
output = [], |
|||
errorMessage = settings.moduleName + ': ' + arguments[0], |
|||
variables = [].slice.call( arguments, 1 ), |
|||
log = console.warn || console.log || function(){} |
|||
; |
|||
log = Function.prototype.bind.call(log, console); |
|||
if(settings.debug) { |
|||
output.push(errorMessage); |
|||
output.concat(variables); |
|||
log.apply(console, output.concat(variables) ); |
|||
} |
|||
}, |
|||
invoke: function(query, context, passedArguments) { |
|||
var |
|||
maxDepth, |
|||
found |
|||
; |
|||
passedArguments = passedArguments || [].slice.call( arguments, 2 ); |
|||
if(typeof query == 'string' && instance !== undefined) { |
|||
query = query.split('.'); |
|||
maxDepth = query.length - 1; |
|||
$.each(query, function(depth, value) { |
|||
if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) { |
|||
instance = instance[value]; |
|||
return true; |
|||
} |
|||
else if( instance[value] !== undefined ) { |
|||
found = instance[value]; |
|||
return true; |
|||
} |
|||
module.error(errors.method); |
|||
return false; |
|||
}); |
|||
} |
|||
if ( $.isFunction( found ) ) { |
|||
return found.apply(context, passedArguments); |
|||
} |
|||
// return retrieved variable or chain
|
|||
return found; |
|||
} |
|||
}; |
|||
|
|||
// check for invoking internal method
|
|||
if(methodInvoked) { |
|||
invokedResponse = module.invoke(query, this, passedArguments); |
|||
} |
|||
// otherwise initialize
|
|||
else { |
|||
module.initialize(); |
|||
} |
|||
|
|||
}) |
|||
; |
|||
// chain or return queried method
|
|||
return (invokedResponse !== undefined) |
|||
? invokedResponse |
|||
: this |
|||
; |
|||
}; |
|||
|
|||
$.fn.checkbox.settings = { |
|||
|
|||
// module info
|
|||
moduleName : 'Checkbox Module', |
|||
verbose : false, |
|||
debug : true, |
|||
namespace : 'checkbox', |
|||
|
|||
// delegated event context
|
|||
context : false, |
|||
|
|||
onChange : function(){}, |
|||
onEnable : function(){}, |
|||
onDisable : function(){}, |
|||
|
|||
// errors
|
|||
errors : { |
|||
method : 'The method you called is not defined.' |
|||
}, |
|||
|
|||
selector : { |
|||
input : 'input' |
|||
}, |
|||
|
|||
className : { |
|||
active : 'active' |
|||
} |
|||
|
|||
}; |
|||
|
|||
})( jQuery, window , document ); |
@ -0,0 +1,354 @@ |
|||
/* ****************************** |
|||
Modal |
|||
Author: Jack Lukic |
|||
Notes: First Commit May 14, 2012 |
|||
|
|||
Manages modal state and |
|||
stage dimming |
|||
|
|||
****************************** */ |
|||
|
|||
;(function ( $, window, document, undefined ) { |
|||
|
|||
$.dimScreen = function(parameters) { |
|||
var |
|||
// if parameter is string it is callback function
|
|||
settings = (typeof parameters == 'function') |
|||
? $.extend({}, $.fn.modal.settings, { dim: parameters }) |
|||
: $.extend({}, $.fn.modal.settings, parameters), |
|||
|
|||
$context = $(settings.context), |
|||
$dimmer = $context.children(settings.selector.dimmer), |
|||
dimmerExists = ($dimmer.size() > 0), |
|||
currentOpacity = $dimmer.css('opacity') |
|||
; |
|||
if(!dimmerExists) { |
|||
$dimmer = $('<div/>') |
|||
.attr('id','dimmer') |
|||
.html('<div class="content"></div>') |
|||
; |
|||
$context |
|||
.append($dimmer) |
|||
; |
|||
} |
|||
if(currentOpacity != settings.opacity) { |
|||
$dimmer |
|||
.one('click', function() { |
|||
settings.unDim(); |
|||
$.unDimScreen(); |
|||
}) |
|||
; |
|||
if(settings.duration === 0) { |
|||
$dimmer |
|||
.css({ |
|||
visibility : 'visible' |
|||
}) |
|||
.find('.content') |
|||
.css({ |
|||
opacity : settings.opacity, |
|||
visibility : 'visible' |
|||
}) |
|||
; |
|||
} |
|||
else { |
|||
$dimmer |
|||
.css({ |
|||
visibility : 'visible' |
|||
}) |
|||
.find('.content') |
|||
.css({ |
|||
opacity : 0, |
|||
visibility : 'visible' |
|||
}) |
|||
.fadeTo(settings.duration, settings.opacity, settings.dim) |
|||
; |
|||
} |
|||
} |
|||
return this; |
|||
}; |
|||
$.unDimScreen = function(parameters) { |
|||
var |
|||
settings = (typeof parameters == 'function') |
|||
? $.extend({}, $.fn.modal.settings, { unDim: parameters }) |
|||
: $.extend({}, $.fn.modal.settings, parameters), |
|||
|
|||
$context = $(settings.context), |
|||
$dimmer = $context.children(settings.selector.dimmer), |
|||
dimmerExists = ($dimmer.size() > 0) |
|||
; |
|||
if(dimmerExists) { |
|||
// callback before unDim
|
|||
settings.unDim(); |
|||
if(settings.duration === 0) { |
|||
$dimmer |
|||
.css({ |
|||
visibility: 'hidden' |
|||
}) |
|||
.remove() |
|||
; |
|||
} |
|||
else { |
|||
$dimmer |
|||
.find('.content') |
|||
.fadeTo(settings.duration, 0, function(){ |
|||
$dimmer.remove(); |
|||
}) |
|||
; |
|||
} |
|||
} |
|||
return this; |
|||
}; |
|||
|
|||
$.fn.modal = function(parameters) { |
|||
var |
|||
settings = $.extend(true, {}, $.fn.modal.settings, parameters), |
|||
// make arguments available
|
|||
query = arguments[0], |
|||
passedArguments = [].slice.call(arguments, 1), |
|||
invokedResponse |
|||
; |
|||
|
|||
$(this) |
|||
.each(function() { |
|||
var |
|||
$modal = $(this), |
|||
|
|||
$closeButton = $modal.find(settings.selector.closeButton), |
|||
$dimmer = $(settings.context).find(settings.selector.dimmer), |
|||
$modals = $(settings.context).children(settings.selector.modal), |
|||
$otherModals = $modals.not($modal), |
|||
|
|||
instance = $modal.data('module-' + settings.namespace), |
|||
methodInvoked = (typeof query == 'string'), |
|||
|
|||
className = settings.className, |
|||
namespace = settings.namespace, |
|||
|
|||
module |
|||
; |
|||
|
|||
module = { |
|||
|
|||
initialize: function() { |
|||
// attach events
|
|||
$modal |
|||
.on('modalShow.' + namespace, module.show) |
|||
.on('modalHide.' + namespace, module.hide) |
|||
.data('module-' + namespace, module) |
|||
; |
|||
}, |
|||
|
|||
show: function() { |
|||
var |
|||
modalHeight = $modal.outerHeight(), |
|||
windowHeight = $(window).height(), |
|||
|
|||
cantFit = (modalHeight > windowHeight), |
|||
modalType = (cantFit) |
|||
? 'absolute' |
|||
: 'fixed', |
|||
topCentering = (cantFit) |
|||
? '0' |
|||
: '50%', |
|||
offsetTop = (cantFit) |
|||
? (windowHeight / 8) |
|||
: -( (modalHeight - settings.closeSpacing) / 2), |
|||
|
|||
finalPosition = ($modal.css('position') == 'absolute') |
|||
? offsetTop + $(window).prop('pageYOffset') |
|||
: offsetTop, |
|||
startPosition = finalPosition + settings.animationOffset |
|||
; |
|||
// set top margin as offset
|
|||
if($.fn.popIn !== undefined) { |
|||
$modal |
|||
.addClass(modalType) |
|||
.css({ |
|||
display : 'block', |
|||
opacity : 0, |
|||
top: topCentering, |
|||
marginTop : finalPosition + 'px' |
|||
}) |
|||
.popIn() |
|||
; |
|||
} |
|||
else { |
|||
$modal |
|||
.addClass(modalType) |
|||
.css({ |
|||
display : 'block', |
|||
opacity : 0, |
|||
top: topCentering, |
|||
marginTop : startPosition + 'px' |
|||
}) |
|||
.animate({ |
|||
opacity : 1, |
|||
marginTop : finalPosition + 'px' |
|||
}, (settings.duration + 300), settings.easing) |
|||
; |
|||
} |
|||
if( $otherModals.is(':visible') ) { |
|||
$otherModals |
|||
.filter(':visible') |
|||
.hide() |
|||
; |
|||
} |
|||
$.dimScreen({ |
|||
context : settings.context, |
|||
duration : 0, |
|||
dim : function() { |
|||
$(document) |
|||
.on('keyup.' + namespace, function(event) { |
|||
var |
|||
keyCode = event.which, |
|||
escapeKey = 27 |
|||
; |
|||
switch(keyCode) { |
|||
case escapeKey: |
|||
$modal.trigger('modalHide'); |
|||
event.preventDefault(); |
|||
break; |
|||
} |
|||
}) |
|||
; |
|||
$closeButton |
|||
.one('click', function() { |
|||
$modal.trigger('modalHide'); |
|||
}) |
|||
; |
|||
settings.dim(); |
|||
}, |
|||
unDim: function() { |
|||
$modal.trigger('modalHide'); |
|||
$closeButton.unbind('click'); |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
hide: function() { |
|||
// remove keyboard detection
|
|||
$(document) |
|||
.off('keyup.' + namespace) |
|||
; |
|||
$.unDimScreen({ |
|||
duration: 0, |
|||
unDim: function() { |
|||
$modal |
|||
.popOut(200) |
|||
; |
|||
settings.unDim(); |
|||
} |
|||
}); |
|||
}, |
|||
/* standard module */ |
|||
setting: function(name, value) { |
|||
if(value === undefined) { |
|||
return settings[name]; |
|||
} |
|||
settings[name] = value; |
|||
}, |
|||
debug: function() { |
|||
var |
|||
output = [], |
|||
message = settings.moduleName + ': ' + arguments[0], |
|||
variables = [].slice.call( arguments, 1 ), |
|||
log = console.info || console.log || function(){} |
|||
; |
|||
if(settings.debug) { |
|||
output.push(message); |
|||
log.apply(console, output.concat(variables) ); |
|||
} |
|||
}, |
|||
error: function() { |
|||
var |
|||
output = [], |
|||
errorMessage = settings.moduleName + ': ' + arguments[0], |
|||
variables = [].slice.call( arguments, 1 ), |
|||
log = console.warn || console.log || function(){} |
|||
; |
|||
if(settings.debug) { |
|||
output.push(errorMessage); |
|||
output.concat(variables); |
|||
log.apply(console, output.concat(variables) ); |
|||
} |
|||
}, |
|||
invoke: function(query, context, passedArguments) { |
|||
var |
|||
maxDepth, |
|||
found |
|||
; |
|||
passedArguments = passedArguments || [].slice.call( arguments, 2 ); |
|||
if(typeof query == 'string' && instance !== undefined) { |
|||
query = query.split('.'); |
|||
maxDepth = query.length - 1; |
|||
$.each(query, function(depth, value) { |
|||
if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) { |
|||
instance = instance[value]; |
|||
return true; |
|||
} |
|||
else if( instance[value] !== undefined ) { |
|||
found = instance[value]; |
|||
return true; |
|||
} |
|||
module.error(settings.errors.method); |
|||
return false; |
|||
}); |
|||
} |
|||
if ( $.isFunction( found ) ) { |
|||
return found.apply(context, passedArguments); |
|||
} |
|||
// return retrieved variable or chain
|
|||
return found; |
|||
} |
|||
}; |
|||
|
|||
// check for invoking internal method
|
|||
if(methodInvoked) { |
|||
invokedResponse = module.invoke(query, this, passedArguments); |
|||
} |
|||
// otherwise initialize
|
|||
else { |
|||
module.initialize(); |
|||
} |
|||
}) |
|||
; |
|||
// chain or return queried method
|
|||
return (invokedResponse !== undefined) |
|||
? invokedResponse |
|||
: this |
|||
; |
|||
}; |
|||
|
|||
$.fn.modal.settings = { |
|||
|
|||
moduleName : 'Modal', |
|||
debug : false, |
|||
namespace : 'modal', |
|||
|
|||
errors: { |
|||
method : 'The method you called is not defined' |
|||
}, |
|||
|
|||
dim : function(){}, |
|||
unDim : function(){}, |
|||
hide : function(){}, |
|||
show : function(){}, |
|||
|
|||
context : 'body', |
|||
opacity : 0.8, |
|||
|
|||
closeSpacing : 25, |
|||
animationOffset : 15, |
|||
|
|||
duration : 400, |
|||
easing : 'easeOutExpo', |
|||
|
|||
selector : { |
|||
dimmer : '#dimmer', |
|||
modal : '.modal', |
|||
closeButton : '.close' |
|||
} |
|||
}; |
|||
|
|||
|
|||
})( jQuery, window , document ); |
@ -0,0 +1,350 @@ |
|||
/* ****************************** |
|||
Nag |
|||
Author: Jack Lukic |
|||
Notes: First Commit July 19, 2012 |
|||
|
|||
Simple fixed position nag |
|||
****************************** */ |
|||
|
|||
;(function ($, window, document, undefined) { |
|||
|
|||
$.fn.nag = function(parameters) { |
|||
var |
|||
settings = $.extend(true, {}, $.fn.nag.settings, parameters), |
|||
// hoist arguments
|
|||
moduleArguments = arguments || false |
|||
; |
|||
$(this) |
|||
.each(function() { |
|||
var |
|||
$module = $(this), |
|||
$close = $module.find(settings.selector.close), |
|||
|
|||
$context = $(settings.context), |
|||
|
|||
instance = $module.data('module'), |
|||
className = settings.className, |
|||
|
|||
moduleOffset, |
|||
moduleHeight, |
|||
|
|||
contextWidth, |
|||
contextHeight, |
|||
contextOffset, |
|||
|
|||
yOffset, |
|||
yPosition, |
|||
|
|||
timer, |
|||
module, |
|||
|
|||
requestAnimationFrame = window.requestAnimationFrame |
|||
|| window.mozRequestAnimationFrame |
|||
|| window.webkitRequestAnimationFrame |
|||
|| window.msRequestAnimationFrame |
|||
|| function(callback) { setTimeout(callback, 0); } |
|||
; |
|||
module = { |
|||
|
|||
initialize: function() { |
|||
// calculate module offset once
|
|||
moduleOffset = $module.offset(); |
|||
moduleHeight = $module.outerHeight(); |
|||
contextWidth = $context.outerWidth(); |
|||
contextHeight = $context.outerHeight(); |
|||
contextOffset = $context.offset(); |
|||
|
|||
$module |
|||
.data('module', module) |
|||
; |
|||
$close |
|||
.on('mouseenter mouseleave', module.event.hover) |
|||
.on('click', module.dismiss) |
|||
; |
|||
// lets avoid javascript if we dont need to reposition
|
|||
if(settings.context == window && settings.position == 'fixed') { |
|||
$module |
|||
.addClass(className.fixed) |
|||
; |
|||
} |
|||
if(settings.sticky) { |
|||
// retrigger on scroll for absolute
|
|||
if(settings.position == 'absolute') { |
|||
$context |
|||
.on('scroll resize', module.event.scroll) |
|||
; |
|||
} |
|||
// fixed is always relative to window
|
|||
else { |
|||
$(window) |
|||
.on('scroll resize', module.event.scroll) |
|||
; |
|||
} |
|||
// fire once to position on init
|
|||
$.proxy(module.event.scroll, this)(); |
|||
} |
|||
if(settings.followLink) { |
|||
$module |
|||
.on('mouseenter mouseleave', module.event.hover) |
|||
.on('click', module.followLink) |
|||
; |
|||
} |
|||
|
|||
if(settings.displayTime > 0) { |
|||
setTimeout(module.hide, settings.displayTime); |
|||
} |
|||
if(module.should.show()) { |
|||
if( !$module.is(':visible') ) { |
|||
module.show(); |
|||
} |
|||
} |
|||
else { |
|||
module.hide(); |
|||
} |
|||
}, |
|||
|
|||
refresh: function() { |
|||
moduleOffset = $module.offset(); |
|||
moduleHeight = $module.outerHeight(); |
|||
contextWidth = $context.outerWidth(); |
|||
contextHeight = $context.outerHeight(); |
|||
contextOffset = $context.offset(); |
|||
}, |
|||
|
|||
show: function() { |
|||
if($.fn.popIn !== undefined) { |
|||
$module |
|||
.popIn(settings.duration) |
|||
; |
|||
} |
|||
else { |
|||
$module |
|||
.fadeIn(settings.duration, settings.easing) |
|||
; |
|||
} |
|||
}, |
|||
hide: function() { |
|||
$module |
|||
.fadeOut(settings.duration, settings.easing) |
|||
; |
|||
}, |
|||
|
|||
stick: function() { |
|||
module.refresh(); |
|||
|
|||
if(settings.position == 'fixed') { |
|||
var |
|||
windowScroll = $(window).prop('pageYOffset') || $(window).scrollTop(), |
|||
fixedOffset = ( $module.hasClass(className.bottom) ) |
|||
? contextOffset.top + (contextHeight - moduleHeight) - windowScroll |
|||
: contextOffset.top - windowScroll |
|||
; |
|||
$module |
|||
.css({ |
|||
position : 'fixed', |
|||
top : fixedOffset, |
|||
left : contextOffset.left, |
|||
width : contextWidth - settings.scrollBarWidth |
|||
}) |
|||
; |
|||
} |
|||
else { |
|||
$module |
|||
.css({ |
|||
top : yPosition |
|||
}) |
|||
; |
|||
} |
|||
}, |
|||
unStick: function() { |
|||
$module |
|||
.css({ |
|||
top : '' |
|||
}) |
|||
; |
|||
}, |
|||
dismiss: function() { |
|||
if(settings.storageMethod) { |
|||
module.storage.set(settings.storedKey, settings.storedValue); |
|||
} |
|||
module.hide(); |
|||
}, |
|||
|
|||
should: { |
|||
show: function() { |
|||
if( module.storage.get(settings.storedKey) == settings.storedValue) { |
|||
return false; |
|||
} |
|||
return true; |
|||
}, |
|||
stick: function() { |
|||
yOffset = $context.prop('pageYOffset') || $context.scrollTop(); |
|||
yPosition = ( $module.hasClass(className.bottom) ) |
|||
? (contextHeight - $module.outerHeight() ) + yOffset |
|||
: yOffset |
|||
; |
|||
// absolute position calculated when y offset met
|
|||
if(yPosition > moduleOffset.top) { |
|||
return true; |
|||
} |
|||
else if(settings.position == 'fixed') { |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
}, |
|||
|
|||
followLink: function() { |
|||
if($.fn.followLink !== undefined) { |
|||
$module |
|||
.followLink() |
|||
; |
|||
} |
|||
}, |
|||
|
|||
storage: { |
|||
|
|||
set: function(key, value) { |
|||
if(settings.storageMethod == 'local' && store !== undefined) { |
|||
store.set(key, value); |
|||
} |
|||
// store by cookie
|
|||
else if($.cookie !== undefined) { |
|||
$.cookie(key, value); |
|||
} |
|||
else { |
|||
module.error(settings.errors.noStorage); |
|||
} |
|||
}, |
|||
get: function(key) { |
|||
if(settings.storageMethod == 'local' && store !== undefined) { |
|||
return store.get(key); |
|||
} |
|||
// get by cookie
|
|||
else if($.cookie !== undefined) { |
|||
return $.cookie(key); |
|||
} |
|||
else { |
|||
module.error(settings.errors.noStorage); |
|||
} |
|||
} |
|||
|
|||
}, |
|||
|
|||
event: { |
|||
hover: function() { |
|||
$(this) |
|||
.toggleClass(className.hover) |
|||
; |
|||
}, |
|||
scroll: function() { |
|||
if(timer !== undefined) { |
|||
clearTimeout(timer); |
|||
} |
|||
timer = setTimeout(function() { |
|||
if(module.should.stick() ) { |
|||
requestAnimationFrame(module.stick); |
|||
} |
|||
else { |
|||
module.unStick(); |
|||
} |
|||
}, settings.lag); |
|||
} |
|||
}, |
|||
|
|||
error: function(error) { |
|||
console.log('Nag Module:' + error); |
|||
}, |
|||
|
|||
// allows for dot notation method calls
|
|||
invoke: function(methodName, context, methodArguments) { |
|||
var |
|||
method |
|||
; |
|||
methodArguments = methodArguments || Array.prototype.slice.call( arguments, 2 ); |
|||
if(typeof methodName == 'string' && instance !== undefined) { |
|||
methodName = methodName.split('.'); |
|||
$.each(methodName, function(index, name) { |
|||
if( $.isPlainObject( instance[name] ) ) { |
|||
instance = instance[name]; |
|||
return true; |
|||
} |
|||
else if( $.isFunction( instance[name] ) ) { |
|||
method = instance[name]; |
|||
return true; |
|||
} |
|||
module.error(settings.errors.method); |
|||
return false; |
|||
}); |
|||
} |
|||
if ( $.isFunction( method ) ) { |
|||
return method.apply(context, methodArguments); |
|||
} |
|||
// return retrieved variable or chain
|
|||
return method; |
|||
} |
|||
|
|||
}; |
|||
|
|||
if(instance !== undefined && moduleArguments) { |
|||
if(moduleArguments[0] == 'invoke') { |
|||
moduleArguments = Array.prototype.slice.call( moduleArguments, 1 ); |
|||
} |
|||
return module.invoke(moduleArguments[0], this, Array.prototype.slice.call( moduleArguments, 1 ) ); |
|||
} |
|||
module.initialize(); |
|||
|
|||
}) |
|||
; |
|||
return this; |
|||
}; |
|||
|
|||
$.fn.nag.settings = { |
|||
|
|||
// set to zero to manually dismiss, otherwise hides on its own
|
|||
displayTime : 0, |
|||
|
|||
// if there is a link to follow
|
|||
followLink : true, |
|||
|
|||
// method of stickyness
|
|||
position : 'fixed', |
|||
scrollBarWidth : 18, |
|||
|
|||
// type of storage to use
|
|||
storageMethod : 'cookie', |
|||
|
|||
// value to store in dismissed localstorage/cookie
|
|||
storedKey : 'nag', |
|||
storedValue : 'dismiss', |
|||
|
|||
// need to calculate stickyness on scroll
|
|||
sticky : true, |
|||
|
|||
// how often to check scroll event
|
|||
lag : 0, |
|||
|
|||
// context for scroll event
|
|||
context : window, |
|||
|
|||
errors: { |
|||
noStorage : 'Neither $.cookie or store is defined. A storage solution is required for storing state', |
|||
followLink : 'Follow link is set but the plugin is not included' |
|||
}, |
|||
|
|||
className : { |
|||
bottom : 'bottom', |
|||
hover : 'hover', |
|||
fixed : 'fixed' |
|||
}, |
|||
|
|||
selector : { |
|||
close: '.icon.close' |
|||
}, |
|||
|
|||
speed : 500, |
|||
easing : 'easeOutQuad' |
|||
|
|||
}; |
|||
|
|||
})( jQuery, window , document ); |
@ -0,0 +1,590 @@ |
|||
/* ****************************** |
|||
Tooltip / Popup |
|||
Author: Jack Lukic |
|||
Notes: First Commit Sep 07, 2012 |
|||
****************************** */ |
|||
|
|||
;(function ($, window, document, undefined) { |
|||
|
|||
$.fn.popup = function(parameters) { |
|||
var |
|||
settings = $.extend(true, {}, $.fn.popup.settings, parameters), |
|||
// make arguments available
|
|||
moduleArguments = arguments || false, |
|||
invokedResponse |
|||
; |
|||
$(this) |
|||
.each(function() { |
|||
var |
|||
$module = $(this), |
|||
$window = $(window), |
|||
$offsetParent = $module.offsetParent(), |
|||
$popup = (settings.inline) |
|||
? $module.next(settings.selector.popup) |
|||
: $window.children(settings.selector.popup).last(), |
|||
|
|||
timer, |
|||
recursionDepth = 0, |
|||
|
|||
instance = $module.data('module-' + settings.namespace), |
|||
methodInvoked = (instance !== undefined && typeof parameters == 'string'), |
|||
|
|||
selector = settings.selector, |
|||
className = settings.className, |
|||
errors = settings.errors, |
|||
metadata = settings.metadata, |
|||
namespace = settings.namespace, |
|||
module |
|||
; |
|||
|
|||
module = { |
|||
|
|||
// binds events
|
|||
initialize: function() { |
|||
if(settings.event == 'hover') { |
|||
$module |
|||
.on('mouseenter.' + namespace, module.event.mouseenter) |
|||
.on('mouseleave.' + namespace, module.event.mouseleave) |
|||
; |
|||
} |
|||
else { |
|||
$module |
|||
.on(settings.event + '.' + namespace, module.event[settings.event]) |
|||
; |
|||
} |
|||
$window |
|||
.on('resize.' + namespace, module.event.resize) |
|||
; |
|||
$module |
|||
.data('module-' + namespace, module) |
|||
; |
|||
}, |
|||
|
|||
refresh: function() { |
|||
$popup = (settings.inline) |
|||
? $module.next(selector.popup) |
|||
: $window.children(selector.popup).last() |
|||
; |
|||
$offsetParent = $module.offsetParent(); |
|||
}, |
|||
|
|||
destroy: function() { |
|||
module.debug('Destroying existing popups'); |
|||
$module |
|||
.off('.' + namespace) |
|||
; |
|||
$popup |
|||
.remove() |
|||
; |
|||
}, |
|||
|
|||
event: { |
|||
mouseenter: function(event) { |
|||
var element = this; |
|||
timer = setTimeout(function() { |
|||
$.proxy(module.toggle, element)(); |
|||
if( $(element).hasClass(className.active) ) { |
|||
event.stopPropagation(); |
|||
} |
|||
}, settings.delay); |
|||
}, |
|||
mouseleave: function(event) { |
|||
clearTimeout(timer); |
|||
if( $module.is(':visible') ) { |
|||
module.hide(); |
|||
} |
|||
}, |
|||
click: function(event) { |
|||
$.proxy(module.toggle, this)(); |
|||
if( $(this).hasClass(className.active) ) { |
|||
event.stopPropagation(); |
|||
} |
|||
}, |
|||
resize: function() { |
|||
if( $popup.is(':visible') ) { |
|||
module.position(); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
// generates popup html from metadata
|
|||
create: function() { |
|||
module.debug('Creating pop-up content'); |
|||
var |
|||
html = $module.data(metadata.html) || settings.html, |
|||
title = $module.data(metadata.title) || settings.title, |
|||
content = $module.data(metadata.content) || $module.attr('title') || settings.content |
|||
; |
|||
if(html || content || title) { |
|||
if(!html) { |
|||
html = settings.template({ |
|||
title : title, |
|||
content : content |
|||
}); |
|||
} |
|||
$popup = $('<div/>') |
|||
.addClass(className.popup) |
|||
.html(html) |
|||
; |
|||
if(settings.inline) { |
|||
$popup |
|||
.insertAfter($module) |
|||
; |
|||
} |
|||
else { |
|||
$popup |
|||
.appendTo( $('body') ) |
|||
; |
|||
} |
|||
} |
|||
else { |
|||
module.error(errors.content); |
|||
} |
|||
}, |
|||
|
|||
remove: function() { |
|||
$popup |
|||
.remove() |
|||
; |
|||
}, |
|||
|
|||
get: { |
|||
offstagePosition: function() { |
|||
var |
|||
boundary = { |
|||
top : $(window).scrollTop(), |
|||
bottom : $(window).scrollTop() + $(window).height(), |
|||
left : 0, |
|||
right : $(window).width() |
|||
}, |
|||
popup = { |
|||
width : $popup.outerWidth(), |
|||
height : $popup.outerHeight(), |
|||
position : $popup.offset() |
|||
}, |
|||
offstage = {}, |
|||
offstagePositions = [] |
|||
; |
|||
if(popup.position) { |
|||
offstage = { |
|||
top : (popup.position.top < boundary.top), |
|||
bottom : (popup.position.top + popup.height > boundary.bottom), |
|||
right : (popup.position.left + popup.width > boundary.right), |
|||
left : (popup.position.left < boundary.left) |
|||
}; |
|||
} |
|||
// return only boundaries that have been surpassed
|
|||
$.each(offstage, function(direction, isOffstage) { |
|||
if(isOffstage) { |
|||
offstagePositions.push(direction); |
|||
} |
|||
}); |
|||
return (offstagePositions.length > 0) |
|||
? offstagePositions.join(' ') |
|||
: false |
|||
; |
|||
}, |
|||
nextPosition: function(position) { |
|||
switch(position) { |
|||
case 'top left': |
|||
position = 'bottom left'; |
|||
break; |
|||
case 'bottom left': |
|||
position = 'top right'; |
|||
break; |
|||
case 'top right': |
|||
position = 'bottom right'; |
|||
break; |
|||
case 'bottom right': |
|||
position = 'top center'; |
|||
break; |
|||
case 'top center': |
|||
position = 'bottom center'; |
|||
break; |
|||
case 'bottom center': |
|||
position = 'right center'; |
|||
break; |
|||
case 'right center': |
|||
position = 'left center'; |
|||
break; |
|||
case 'left center': |
|||
position = 'top center'; |
|||
break; |
|||
} |
|||
return position; |
|||
} |
|||
}, |
|||
|
|||
// determines popup state
|
|||
toggle: function() { |
|||
$module = $(this); |
|||
module.debug('Toggling pop-up'); |
|||
// refresh state of module
|
|||
module.refresh(); |
|||
if($popup.size() === 0) { |
|||
module.create(); |
|||
} |
|||
if( !$module.hasClass(className.active) ) { |
|||
if( module.position() ) { |
|||
module.show(); |
|||
} |
|||
} |
|||
else { |
|||
module.hide(); |
|||
} |
|||
}, |
|||
|
|||
position: function(position, arrowOffset) { |
|||
var |
|||
windowWidth = $(window).width(), |
|||
windowHeight = $(window).height(), |
|||
width = $module.outerWidth(), |
|||
height = $module.outerHeight(), |
|||
popupWidth = $popup.outerWidth(), |
|||
popupHeight = $popup.outerHeight(), |
|||
|
|||
offset = (settings.inline) |
|||
? $module.position() |
|||
: $module.offset(), |
|||
parentWidth = (settings.inline) |
|||
? $offsetParent.outerWidth() |
|||
: $window.outerWidth(), |
|||
parentHeight = (settings.inline) |
|||
? $offsetParent.outerHeight() |
|||
: $window.outerHeight(), |
|||
|
|||
positioning, |
|||
offstagePosition |
|||
; |
|||
position = position || $module.data(metadata.position) || settings.position; |
|||
arrowOffset = arrowOffset || $module.data(metadata.arrowOffset) || settings.arrowOffset; |
|||
module.debug('Calculating offset for position', position); |
|||
switch(position) { |
|||
case 'top left': |
|||
positioning = { |
|||
top : 'auto', |
|||
bottom : parentHeight - offset.top + settings.distanceAway, |
|||
left : offset.left + arrowOffset |
|||
}; |
|||
break; |
|||
case 'top center': |
|||
positioning = { |
|||
bottom : parentHeight - offset.top + settings.distanceAway, |
|||
left : offset.left + (width / 2) - (popupWidth / 2) + arrowOffset, |
|||
top : 'auto', |
|||
right : 'auto' |
|||
}; |
|||
break; |
|||
case 'top right': |
|||
positioning = { |
|||
bottom : parentHeight - offset.top + settings.distanceAway, |
|||
right : parentWidth - offset.left - width - arrowOffset, |
|||
top : 'auto', |
|||
left : 'auto' |
|||
}; |
|||
break; |
|||
case 'left center': |
|||
positioning = { |
|||
top : offset.top + (height / 2) - (popupHeight / 2), |
|||
right : parentWidth - offset.left + settings.distanceAway - arrowOffset, |
|||
left : 'auto', |
|||
bottom : 'auto' |
|||
}; |
|||
break; |
|||
case 'right center': |
|||
positioning = { |
|||
top : offset.top + (height / 2) - (popupHeight / 2), |
|||
left : offset.left + width + settings.distanceAway + arrowOffset, |
|||
bottom : 'auto', |
|||
right : 'auto' |
|||
}; |
|||
break; |
|||
case 'bottom left': |
|||
positioning = { |
|||
top : offset.top + height + settings.distanceAway, |
|||
left : offset.left + arrowOffset, |
|||
bottom : 'auto', |
|||
right : 'auto' |
|||
}; |
|||
break; |
|||
case 'bottom center': |
|||
positioning = { |
|||
top : offset.top + height + settings.distanceAway, |
|||
left : offset.left + (width / 2) - (popupWidth / 2) + arrowOffset, |
|||
bottom : 'auto', |
|||
right : 'auto' |
|||
}; |
|||
break; |
|||
case 'bottom right': |
|||
positioning = { |
|||
top : offset.top + height + settings.distanceAway, |
|||
right : parentWidth - offset.left - width - arrowOffset, |
|||
left : 'auto', |
|||
bottom : 'auto' |
|||
}; |
|||
break; |
|||
} |
|||
// true width on popup
|
|||
$.extend(positioning, { |
|||
width: $popup.width() |
|||
}); |
|||
// tentatively place on stage
|
|||
$popup |
|||
.removeAttr('style') |
|||
.removeClass('top right bottom left center') |
|||
.css(positioning) |
|||
.addClass(position) |
|||
.addClass(className.loading) |
|||
; |
|||
// check if is offstage
|
|||
offstagePosition = module.get.offstagePosition(); |
|||
// recursively find new positioning
|
|||
if(offstagePosition) { |
|||
module.debug('Element is outside boundaries ', offstagePosition); |
|||
if(recursionDepth < settings.maxRecursion) { |
|||
position = module.get.nextPosition(position); |
|||
recursionDepth++; |
|||
module.debug('Trying new position: ', position); |
|||
return module.position(position); |
|||
} |
|||
else { |
|||
module.error(errors.recursion); |
|||
recursionDepth = 0; |
|||
return false; |
|||
} |
|||
} |
|||
else { |
|||
module.debug('Position is on stage', position); |
|||
recursionDepth = 0; |
|||
return true; |
|||
} |
|||
}, |
|||
|
|||
show: function() { |
|||
module.debug('Showing pop-up'); |
|||
$(selector.popup) |
|||
.filter(':visible') |
|||
.stop() |
|||
.fadeOut(200) |
|||
.prev($module) |
|||
.removeClass(className.active) |
|||
; |
|||
$module |
|||
.addClass(className.active) |
|||
; |
|||
$popup |
|||
.removeClass(className.loading) |
|||
; |
|||
if(settings.animation == 'pop' && $.fn.popIn !== undefined) { |
|||
$popup |
|||
.stop() |
|||
.popIn(settings.duration, settings.easing) |
|||
; |
|||
} |
|||
else { |
|||
$popup |
|||
.stop() |
|||
.fadeIn(settings.duration, settings.easing) |
|||
; |
|||
} |
|||
if(settings.event == 'click' && settings.clicktoClose) { |
|||
module.debug('Binding popup close event'); |
|||
$(document) |
|||
.on('click.' + namespace, module.gracefully.hide) |
|||
; |
|||
} |
|||
$.proxy(settings.onShow, $popup)(); |
|||
}, |
|||
|
|||
hide: function() { |
|||
$module |
|||
.removeClass(className.active) |
|||
; |
|||
if($popup.is(':visible') ) { |
|||
module.debug('Hiding pop-up'); |
|||
if(settings.animation == 'pop' && $.fn.popOut !== undefined) { |
|||
$popup |
|||
.stop() |
|||
.popOut(settings.duration, settings.easing, function() { |
|||
$popup.hide(); |
|||
}) |
|||
; |
|||
} |
|||
else { |
|||
$popup |
|||
.stop() |
|||
.fadeOut(settings.duration, settings.easing) |
|||
; |
|||
} |
|||
} |
|||
if(settings.event == 'click' && settings.clicktoClose) { |
|||
$(document) |
|||
.off('click.' + namespace) |
|||
; |
|||
} |
|||
$.proxy(settings.onHide, $popup)(); |
|||
if(!settings.inline) { |
|||
module.remove(); |
|||
} |
|||
}, |
|||
|
|||
gracefully: { |
|||
hide: function(event) { |
|||
// don't close on clicks inside popup
|
|||
if( $(event.target).closest(selector.popup).size() === 0) { |
|||
module.hide(); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
/* standard module */ |
|||
setting: function(name, value) { |
|||
if(value === undefined) { |
|||
return settings[name]; |
|||
} |
|||
settings[name] = value; |
|||
}, |
|||
debug: function() { |
|||
var |
|||
output = [], |
|||
message = settings.moduleName + ': ' + arguments[0], |
|||
variables = [].slice.call( arguments, 1 ), |
|||
log = console.info || console.log || function(){} |
|||
; |
|||
if(settings.debug) { |
|||
output.push(message); |
|||
log.apply(console, output.concat(variables) ); |
|||
} |
|||
}, |
|||
error: function() { |
|||
var |
|||
output = [], |
|||
errorMessage = settings.moduleName + ': ' + arguments[0], |
|||
variables = [].slice.call( arguments, 1 ), |
|||
log = console.warn || console.log || function(){} |
|||
; |
|||
if(settings.debug) { |
|||
output.push(errorMessage); |
|||
output.concat(variables); |
|||
log.apply(console, output.concat(variables) ); |
|||
} |
|||
}, |
|||
invoke: function(query, context, passedArguments) { |
|||
var |
|||
maxDepth, |
|||
found |
|||
; |
|||
passedArguments = passedArguments || [].slice.call( arguments, 2 ); |
|||
if(typeof query == 'string' && instance !== undefined) { |
|||
query = query.split('.'); |
|||
maxDepth = query.length - 1; |
|||
$.each(query, function(depth, value) { |
|||
if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) { |
|||
instance = instance[value]; |
|||
return true; |
|||
} |
|||
else if( instance[value] !== undefined ) { |
|||
found = instance[value]; |
|||
return true; |
|||
} |
|||
module.error(settings.errors.method); |
|||
return false; |
|||
}); |
|||
} |
|||
if ( $.isFunction( found ) ) { |
|||
return found.apply(context, passedArguments); |
|||
} |
|||
// return retrieved variable or chain
|
|||
return found; |
|||
} |
|||
|
|||
}; |
|||
// check for invoking internal method
|
|||
if(methodInvoked) { |
|||
invokedResponse = module.invoke(moduleArguments[0], this, Array.prototype.slice.call( moduleArguments, 1 ) ); |
|||
} |
|||
// otherwise initialize
|
|||
else { |
|||
if(instance) { |
|||
module.destroy(); |
|||
} |
|||
module.initialize(); |
|||
} |
|||
}) |
|||
; |
|||
// chain or return queried method
|
|||
return (invokedResponse !== undefined) |
|||
? invokedResponse |
|||
: this |
|||
; |
|||
}; |
|||
|
|||
$.fn.popup.settings = { |
|||
|
|||
moduleName : 'Pop-up Module', |
|||
debug : true, |
|||
namespace : 'popup', |
|||
|
|||
onShow : function(){}, |
|||
onHide : function(){}, |
|||
|
|||
content : false, |
|||
html : false, |
|||
title : false, |
|||
|
|||
position : 'top center', |
|||
delay : 0, |
|||
inline : true, |
|||
|
|||
duration : 250, |
|||
easing : 'easeOutQuint', |
|||
animation : 'pop', |
|||
|
|||
errors: { |
|||
content : 'Warning: Your popup has no content specified', |
|||
method : 'The method you called is not defined.', |
|||
recursion : 'Popup attempted to reposition element to fit, but could not find an adequate position.' |
|||
}, |
|||
|
|||
distanceAway : 2, |
|||
arrowOffset : 0, |
|||
|
|||
maxRecursion : 10, |
|||
|
|||
event : 'hover', |
|||
clicktoClose : true, |
|||
|
|||
metadata: { |
|||
content : 'content', |
|||
html : 'html', |
|||
title : 'title', |
|||
position : 'position', |
|||
arrowOffset : 'arrowOffset' |
|||
}, |
|||
|
|||
className : { |
|||
popup : 'ui popup', |
|||
active : 'active', |
|||
loading : 'loading' |
|||
}, |
|||
|
|||
selector : { |
|||
popup : '.ui.popup' |
|||
}, |
|||
|
|||
template: function(text) { |
|||
var html = ''; |
|||
if(typeof text !== undefined) { |
|||
if(typeof text.title !== undefined && text.title) { |
|||
html += '<h2>' + text.title + '</h2>'; |
|||
} |
|||
if(typeof text.content !== undefined && text.content) { |
|||
html += '<div class="content">' + text.content + '</div>'; |
|||
} |
|||
} |
|||
return html; |
|||
} |
|||
|
|||
}; |
|||
|
|||
})( jQuery, window , document ); |
@ -0,0 +1,670 @@ |
|||
/* ****************************** |
|||
Search Prompt |
|||
Author: Jack Lukic |
|||
Notes: First Commit July 19, 2012 |
|||
|
|||
Designed to be used as an autocomplete |
|||
or to deliver quick inline search results |
|||
****************************** */ |
|||
|
|||
;(function ($, window, document, undefined) { |
|||
|
|||
$.fn.searchPrompt = function(source, parameters) { |
|||
var |
|||
settings = $.extend(true, {}, $.fn.searchPrompt.settings, parameters), |
|||
// make arguments available
|
|||
query = arguments[0], |
|||
passedArguments = [].slice.call(arguments, 1), |
|||
invokedResponse |
|||
; |
|||
$(this) |
|||
.each(function() { |
|||
var |
|||
$module = $(this), |
|||
$searchPrompt = $module.find(settings.selector.searchPrompt), |
|||
$searchButton = $module.find(settings.selector.searchButton), |
|||
$searchResults = $module.find(settings.selector.searchResults), |
|||
$result = $module.find(settings.selector.result), |
|||
$category = $module.find(settings.selector.category), |
|||
$emptyResult = $module.find(settings.selector.emptyResult), |
|||
$resultPage = $module.find(settings.selector.resultPage), |
|||
|
|||
element = this, |
|||
selector = $module.selector || '', |
|||
instance = $module.data('module-' + settings.namespace), |
|||
methodInvoked = (instance !== undefined && typeof query == 'string'), |
|||
|
|||
className = settings.className, |
|||
namespace = settings.namespace, |
|||
errors = settings.errors, |
|||
module |
|||
; |
|||
module = { |
|||
|
|||
initialize: function() { |
|||
var |
|||
searchPrompt = $searchPrompt[0], |
|||
inputEvent = (searchPrompt.oninput !== undefined) |
|||
? 'input' |
|||
: (searchPrompt.onpropertychange !== undefined) |
|||
? 'propertychange' |
|||
: 'keyup' |
|||
; |
|||
// attach events
|
|||
$searchPrompt |
|||
.on('focus.' + namespace, module.event.focus) |
|||
.on('blur.' + namespace, module.event.blur) |
|||
.on('keydown.' + namespace, module.handleKeyboard) |
|||
; |
|||
if(settings.automatic) { |
|||
$searchPrompt |
|||
.on(inputEvent + '.' + namespace, module.search.throttle) |
|||
; |
|||
} |
|||
$searchButton |
|||
.on('click.' + namespace, module.search.query) |
|||
; |
|||
$searchResults |
|||
.on('click.' + namespace, settings.selector.result, module.results.select) |
|||
; |
|||
$module |
|||
.data('module-' + namespace, module) |
|||
; |
|||
}, |
|||
event: { |
|||
focus: function() { |
|||
$module |
|||
.addClass(className.focus) |
|||
; |
|||
module.results.show(); |
|||
}, |
|||
blur: function() { |
|||
module.search.cancel(); |
|||
$module |
|||
.removeClass(className.focus) |
|||
; |
|||
module.results.hide(); |
|||
} |
|||
}, |
|||
handleKeyboard: function(event) { |
|||
var |
|||
// force latest jq dom
|
|||
$result = $module.find(settings.selector.result), |
|||
$category = $module.find(settings.selector.category), |
|||
keyCode = event.which, |
|||
keys = { |
|||
backspace : 8, |
|||
enter : 13, |
|||
escape : 27, |
|||
upArrow : 38, |
|||
downArrow : 40 |
|||
}, |
|||
activeClass = className.active, |
|||
currentIndex = $result.index( $result.filter('.' + activeClass) ), |
|||
resultSize = $result.size(), |
|||
newIndex |
|||
; |
|||
// search shortcuts
|
|||
if(keyCode == keys.escape) { |
|||
$searchPrompt |
|||
.trigger('blur') |
|||
; |
|||
} |
|||
// result shortcuts
|
|||
if($searchResults.filter(':visible').size() > 0) { |
|||
if(keyCode == keys.enter) { |
|||
if( $result.filter('.' + activeClass).exists() ) { |
|||
$.proxy(module.results.select, $result.filter('.' + activeClass) )(); |
|||
event.preventDefault(); |
|||
return false; |
|||
} |
|||
} |
|||
else if(keyCode == keys.upArrow) { |
|||
newIndex = (currentIndex - 1 < 0) |
|||
? currentIndex |
|||
: currentIndex - 1 |
|||
; |
|||
$category |
|||
.removeClass(activeClass) |
|||
; |
|||
$result |
|||
.removeClass(activeClass) |
|||
.eq(newIndex) |
|||
.addClass(activeClass) |
|||
.closest($category) |
|||
.addClass(activeClass) |
|||
; |
|||
event.preventDefault(); |
|||
} |
|||
else if(keyCode == keys.downArrow) { |
|||
newIndex = (currentIndex + 1 >= resultSize) |
|||
? currentIndex |
|||
: currentIndex + 1 |
|||
; |
|||
$category |
|||
.removeClass(activeClass) |
|||
; |
|||
$result |
|||
.removeClass(activeClass) |
|||
.eq(newIndex) |
|||
.addClass(activeClass) |
|||
.closest($category) |
|||
.addClass(activeClass) |
|||
; |
|||
event.preventDefault(); |
|||
} |
|||
} |
|||
else { |
|||
// query shortcuts
|
|||
if(keyCode == keys.enter) { |
|||
module.search.query(); |
|||
$searchButton |
|||
.addClass(className.down) |
|||
; |
|||
$searchPrompt |
|||
.one('keyup', function(){ |
|||
$searchButton |
|||
.removeClass(className.down) |
|||
; |
|||
}) |
|||
; |
|||
} |
|||
} |
|||
}, |
|||
search: { |
|||
cancel: function() { |
|||
var |
|||
xhr = $module.data('xhr') || false |
|||
; |
|||
if( xhr && xhr.state() != 'resolved') { |
|||
xhr.abort(); |
|||
} |
|||
}, |
|||
throttle: function(event) { |
|||
var |
|||
searchTerm = $searchPrompt.val(), |
|||
numCharacters = searchTerm.length, |
|||
timer |
|||
; |
|||
clearTimeout($module.data('timer')); |
|||
if(numCharacters >= settings.minCharacters) { |
|||
timer = setTimeout(module.search.query, settings.searchThrottle); |
|||
$module |
|||
.data('timer', timer) |
|||
; |
|||
} |
|||
else { |
|||
module.results.hide(); |
|||
} |
|||
}, |
|||
query: function() { |
|||
var |
|||
searchTerm = $searchPrompt.val(), |
|||
cachedHTML = module.search.cache.read(searchTerm) |
|||
; |
|||
if(cachedHTML) { |
|||
module.debug("Reading result for '" + searchTerm + "' from cache"); |
|||
module.results.add(cachedHTML); |
|||
} |
|||
else { |
|||
module.debug("Querying for '" + searchTerm + "'"); |
|||
if(typeof source == 'object') { |
|||
module.search.local(searchTerm); |
|||
} |
|||
else { |
|||
module.search.remote(searchTerm); |
|||
} |
|||
$.proxy(settings.onSearchQuery, $module)(searchTerm); |
|||
} |
|||
}, |
|||
local: function(searchTerm) { |
|||
var |
|||
searchResults = [], |
|||
fullTextResults = [], |
|||
searchFields = $.isArray(settings.searchFields) |
|||
? settings.searchFields |
|||
: [settings.searchFields], |
|||
|
|||
searchRegExp = new RegExp('(?:\s|^)' + searchTerm, 'i'), |
|||
fullTextRegExp = new RegExp(searchTerm, 'i'), |
|||
searchHTML |
|||
; |
|||
$module |
|||
.addClass(className.loading) |
|||
; |
|||
// iterate through search fields in array order
|
|||
$.each(searchFields, function(index, field) { |
|||
$.each(source, function(label, thing) { |
|||
if(typeof thing[field] == 'string' && ($.inArray(thing, searchResults) == -1) && ($.inArray(thing, fullTextResults) == -1) ) { |
|||
if( searchRegExp.test( thing[field] ) ) { |
|||
searchResults.push(thing); |
|||
} |
|||
else if( fullTextRegExp.test( thing[field] ) ) { |
|||
fullTextResults.push(thing); |
|||
} |
|||
} |
|||
}); |
|||
}); |
|||
searchHTML = module.results.generate({ |
|||
results: $.merge(searchResults, fullTextResults) |
|||
}); |
|||
$module |
|||
.removeClass(className.loading) |
|||
; |
|||
module.search.cache.write(searchTerm, searchHTML); |
|||
module.results.add(searchHTML); |
|||
}, |
|||
remote: function(searchTerm) { |
|||
var |
|||
xhr = ($module.data('xhr') !== undefined) |
|||
? $module.data('xhr') |
|||
: false, |
|||
apiSettings = { |
|||
stateContext : $module, |
|||
url : source, |
|||
urlData: { query: searchTerm }, |
|||
success : function(response) { |
|||
searchHTML = module.results.generate(response); |
|||
module.search.cache.write(searchTerm, searchHTML); |
|||
module.results.add(searchHTML); |
|||
}, |
|||
failure : module.error |
|||
}, |
|||
searchHTML |
|||
; |
|||
// api attaches xhr event to context, use this to prevent overlapping queries
|
|||
if( xhr && xhr.state() != 'resolved') { |
|||
xhr.abort(); |
|||
} |
|||
$.extend(true, apiSettings, settings.apiSettings); |
|||
$.api(apiSettings); |
|||
}, |
|||
|
|||
cache: { |
|||
read: function(name) { |
|||
var |
|||
cache = $module.data('cache') |
|||
; |
|||
return (settings.cache && (typeof cache == 'object') && (cache[name] !== undefined) ) |
|||
? cache[name] |
|||
: false |
|||
; |
|||
}, |
|||
write: function(name, value) { |
|||
var |
|||
cache = ($module.data('cache') !== undefined) |
|||
? $module.data('cache') |
|||
: {} |
|||
; |
|||
cache[name] = value; |
|||
$module |
|||
.data('cache', cache) |
|||
; |
|||
} |
|||
} |
|||
}, |
|||
|
|||
results: { |
|||
generate: function(response) { |
|||
module.debug('Generating html from response', response); |
|||
var |
|||
template = settings.templates[settings.type], |
|||
html = '' |
|||
; |
|||
if(($.isPlainObject(response.results) && !$.isEmptyObject(response.results)) || ($.isArray(response.results) && response.results.length > 0) ) { |
|||
if(settings.maxResults > 0) { |
|||
response.results = $.makeArray(response.results).slice(0, settings.maxResults); |
|||
} |
|||
if(response.results.length > 0) { |
|||
if($.isFunction(template)) { |
|||
html = template(response); |
|||
} |
|||
else { |
|||
module.error(errors.noTemplate, false); |
|||
} |
|||
} |
|||
} |
|||
else { |
|||
html = module.message(errors.noResults, 'empty'); |
|||
} |
|||
$.proxy(settings.onSearchResults, $module)(response); |
|||
return html; |
|||
}, |
|||
add: function(html) { |
|||
if(settings.onResultsAdd == 'default' || $.proxy(settings.onResultsAdd, $searchResults)(html) == 'default') { |
|||
$searchResults |
|||
.html(html) |
|||
; |
|||
} |
|||
module.results.show(); |
|||
}, |
|||
show: function() { |
|||
if( ($searchResults.filter(':visible').size() === 0) && ($searchPrompt.filter(':focus').size() > 0) && $searchResults.html() !== '') { |
|||
$searchResults |
|||
.stop() |
|||
.fadeIn(200) |
|||
; |
|||
$.proxy(settings.onResultsOpen, $searchResults)(); |
|||
} |
|||
}, |
|||
hide: function() { |
|||
if($searchResults.filter(':visible').size() > 0) { |
|||
$searchResults |
|||
.stop() |
|||
.fadeOut(200) |
|||
; |
|||
$.proxy(settings.onResultsClose, $searchResults)(); |
|||
} |
|||
}, |
|||
followLink: function() { |
|||
|
|||
}, |
|||
select: function(event) { |
|||
module.debug('Search result selected'); |
|||
var |
|||
$result = $(this), |
|||
$title = $result.find('.title'), |
|||
title = $title.html() |
|||
; |
|||
if(settings.onSelect == 'default' || $.proxy(settings.onSelect, this)(event) == 'default') { |
|||
var |
|||
$link = $result.find('a[href]').eq(0), |
|||
href = $link.attr('href'), |
|||
target = $link.attr('target') |
|||
; |
|||
try { |
|||
module.results.hide(); |
|||
$searchPrompt |
|||
.val(title) |
|||
; |
|||
if(target == '_blank' || event.ctrlKey) { |
|||
window.open(href); |
|||
} |
|||
else { |
|||
window.location.href = (href); |
|||
} |
|||
} |
|||
catch(error) {} |
|||
} |
|||
} |
|||
}, |
|||
|
|||
/* standard module */ |
|||
setting: function(name, value) { |
|||
if(value === undefined) { |
|||
return settings[name]; |
|||
} |
|||
settings[name] = value; |
|||
}, |
|||
debug: function() { |
|||
var |
|||
output = [], |
|||
message = settings.moduleName + ': ' + arguments[0], |
|||
variables = [].slice.call( arguments, 1 ), |
|||
log = console.info || console.log || function(){} |
|||
; |
|||
log = Function.prototype.bind.call(log, console); |
|||
if(settings.debug) { |
|||
output.push(message); |
|||
log.apply(console, output.concat(variables) ); |
|||
} |
|||
}, |
|||
// displays mesage visibly in search results
|
|||
message: function(text, type) { |
|||
type = type || 'standard'; |
|||
module.results.add( settings.templates.message(text, type) ); |
|||
return settings.templates.message(text, type); |
|||
}, |
|||
// update view with error message
|
|||
error: function(errorMessage, escalate) { |
|||
// show user error message
|
|||
escalate = (escalate !== undefined) |
|||
? escalate |
|||
: true |
|||
; |
|||
console.warn(settings.moduleName + ': ' + errorMessage); |
|||
if(escalate && errorMessage !== undefined) { |
|||
module.message(errorMessage, 'error'); |
|||
} |
|||
}, |
|||
invoke: function(query, context, passedArguments) { |
|||
var |
|||
maxDepth, |
|||
found |
|||
; |
|||
passedArguments = passedArguments || [].slice.call( arguments, 2 ); |
|||
if(typeof query == 'string' && instance !== undefined) { |
|||
query = query.split('.'); |
|||
maxDepth = query.length - 1; |
|||
$.each(query, function(depth, value) { |
|||
if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) { |
|||
instance = instance[value]; |
|||
return true; |
|||
} |
|||
else if( instance[value] !== undefined ) { |
|||
found = instance[value]; |
|||
return true; |
|||
} |
|||
module.error(errors.method); |
|||
return false; |
|||
}); |
|||
} |
|||
if ( $.isFunction( found ) ) { |
|||
return found.apply(context, passedArguments); |
|||
} |
|||
// return retrieved variable or chain
|
|||
return found; |
|||
} |
|||
}; |
|||
|
|||
// check for invoking internal method
|
|||
if(methodInvoked) { |
|||
invokedResponse = module.invoke(query, element, passedArguments); |
|||
} |
|||
// otherwise initialize
|
|||
else { |
|||
module.initialize(); |
|||
} |
|||
}) |
|||
; |
|||
// chain or return queried method
|
|||
return (invokedResponse !== undefined) |
|||
? invokedResponse |
|||
: this |
|||
; |
|||
}; |
|||
|
|||
$.fn.searchPrompt.settings = { |
|||
|
|||
moduleName : 'Search Module', |
|||
debug : true, |
|||
namespace : 'search', |
|||
|
|||
// onSelect default action is defined in module
|
|||
onSelect : 'default', |
|||
onResultsAdd : 'default', |
|||
|
|||
onSearchQuery : function(){}, |
|||
onSearchResults : function(response){}, |
|||
|
|||
onResultsOpen : function(){}, |
|||
onResultsClose : function(){}, |
|||
|
|||
automatic : 'true', |
|||
type : 'simple', |
|||
minCharacters : 3, |
|||
searchThrottle : 300, |
|||
maxResults : 7, |
|||
cache : true, |
|||
|
|||
searchFields : ['title', 'description'], |
|||
|
|||
// api config
|
|||
apiSettings: { |
|||
|
|||
}, |
|||
|
|||
className: { |
|||
active : 'active', |
|||
down : 'down', |
|||
focus : 'focus', |
|||
empty : 'empty', |
|||
loading : 'loading' |
|||
}, |
|||
|
|||
errors : { |
|||
noResults : 'Your search returned no results', |
|||
logging : 'Error in debug logging, exiting.', |
|||
noTemplate : 'A valid template name was not specified.', |
|||
serverError : 'There was an issue with querying the server.', |
|||
method : 'The method you called is not defined.' |
|||
}, |
|||
|
|||
selector : { |
|||
searchPrompt : '.prompt', |
|||
searchButton : '.search.button', |
|||
searchResults : '.results', |
|||
|
|||
category : '.category', |
|||
result : '.result', |
|||
|
|||
emptyResult : '.results .message', |
|||
resultPage : '.results .page' |
|||
}, |
|||
|
|||
templates: { |
|||
message: function(message, type) { |
|||
var |
|||
html = '' |
|||
; |
|||
if(message !== undefined && type !== undefined) { |
|||
html += '' |
|||
+ '<div class="message ' + type +'">' |
|||
+ '<div class="text">' |
|||
; |
|||
// message type
|
|||
if(type == 'empty') { |
|||
html += '' |
|||
+ '<h2>No Results</h2>' |
|||
+ '<p>' + message + '</p>' |
|||
; |
|||
} |
|||
else { |
|||
html += ' <div class="text">' + message + '</div>'; |
|||
} |
|||
html += '</div>'; |
|||
} |
|||
return html; |
|||
}, |
|||
categories: function(response) { |
|||
var |
|||
html = '' |
|||
; |
|||
if(response.results !== undefined) { |
|||
// each category
|
|||
$.each(response.results, function(index, category) { |
|||
if(category.results !== undefined && category.results.length > 0) { |
|||
html += '' |
|||
+ '<div class="category">' |
|||
+ '<div class="name">' + category.name + '</div>' |
|||
+ '<ul>' |
|||
; |
|||
// each item inside category
|
|||
$.each(category.results, function(index, result) { |
|||
html += '<li class="result">'; |
|||
html += '<a href="' + result.url + '"></a>'; |
|||
if(result.image !== undefined) { |
|||
html+= '' |
|||
+ '<div class="image">' |
|||
+ ' <img src="' + result.image + '">' |
|||
+ '</div>' |
|||
; |
|||
} |
|||
html += (result.image !== undefined) |
|||
? '<div class="indented info">' |
|||
: '<div class="info">' |
|||
; |
|||
if(result.price !== undefined) { |
|||
html+= '<div class="price">' + result.price + '</div>'; |
|||
} |
|||
if(result.title !== undefined) { |
|||
html+= '<div class="title">' + result.title + '</div>'; |
|||
} |
|||
if(result.description !== undefined) { |
|||
html+= '<div class="description">' + result.description + '</div>'; |
|||
} |
|||
html += '' |
|||
+ '</div>' |
|||
+ '</li>' |
|||
; |
|||
}); |
|||
html += '' |
|||
+ '</ul>' |
|||
+ '</div>' |
|||
; |
|||
} |
|||
}); |
|||
if(response.resultPage) { |
|||
html += '' |
|||
+ '<a href="' + response.resultPage.url + '" class="result-page">' |
|||
+ response.resultPage.text |
|||
+ '</a>'; |
|||
} |
|||
return html; |
|||
} |
|||
return false; |
|||
}, |
|||
simple: function(response) { |
|||
var |
|||
html = '' |
|||
; |
|||
if(response.results !== undefined) { |
|||
html += '<ul>'; |
|||
// each result
|
|||
$.each(response.results, function(index, result) { |
|||
html += '<li class="result">'; |
|||
|
|||
if(result.url !== undefined) { |
|||
html += '<a href="' + result.url + '"></a>'; |
|||
} |
|||
if(result.image !== undefined) { |
|||
html+= '' |
|||
+ '<div class="image">' |
|||
+ ' <img src="' + result.image + '">' |
|||
+ '</div>' |
|||
; |
|||
} |
|||
html += (result.image !== undefined) |
|||
? '<div class="indented info">' |
|||
: '<div class="info">' |
|||
; |
|||
if(result.price !== undefined) { |
|||
html+= '<div class="price">' + result.price + '</div>'; |
|||
} |
|||
if(result.title !== undefined) { |
|||
html+= '<div class="title">' + result.title + '</div>'; |
|||
} |
|||
if(result.description !== undefined) { |
|||
html+= '<div class="description">' + result.description + '</div>'; |
|||
} |
|||
html += '' |
|||
+ '</div>' |
|||
+ '</li>' |
|||
; |
|||
}); |
|||
html += '</ul>'; |
|||
|
|||
if(response.resultPage) { |
|||
html += '' |
|||
+ '<a href="' + response.resultPage.url + '" class="result-page">' |
|||
+ response.resultPage.text |
|||
+ '</a>'; |
|||
} |
|||
return html; |
|||
} |
|||
return false; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
})( jQuery, window , document ); |
@ -0,0 +1,640 @@ |
|||
/* ******************************************************************************************* |
|||
|
|||
Shape - A 3D Animation Plugin |
|||
Version 0.1 |
|||
(built using Semantic module spec) |
|||
|
|||
Author : Jack Lukic |
|||
Last revision : April 2013 |
|||
|
|||
********************************************************************************************* */ |
|||
|
|||
;(function ( $, window, document, undefined ) { |
|||
|
|||
$.fn.shape = function(parameters) { |
|||
var |
|||
$allModules = $(this), |
|||
|
|||
settings = $.extend(true, {}, $.fn.shape.settings, parameters), |
|||
|
|||
// define namespaces for modules
|
|||
eventNamespace = '.' + settings.namespace, |
|||
moduleNamespace = 'module-' + settings.namespace, |
|||
|
|||
// allow methods to be queried directly
|
|||
query = arguments[0], |
|||
queryArguments = [].slice.call(arguments, 1), |
|||
methodInvoked = (typeof query == 'string'), |
|||
invokedResponse |
|||
; |
|||
|
|||
$allModules |
|||
.each(function() { |
|||
var |
|||
// selector cache
|
|||
$module = $(this), |
|||
$shape = $module.find(settings.selector.shape), |
|||
$side = $module.find(settings.selector.side), |
|||
|
|||
// private variables
|
|||
$activeSide, |
|||
$nextSide, |
|||
endTransition = 'transitionend msTransitionEnd oTransitionEnd', |
|||
|
|||
// standard module
|
|||
selector = $module.selector || '', |
|||
element = this, |
|||
instance = $module.data(moduleNamespace), |
|||
|
|||
// internal aliases
|
|||
namespace = settings.namespace, |
|||
error = settings.error, |
|||
className = settings.className, |
|||
|
|||
module |
|||
; |
|||
|
|||
module = { |
|||
|
|||
initialize: function() { |
|||
module.verbose('Initializing module for', element); |
|||
module.set.defaultSide(); |
|||
instance = module; |
|||
$module |
|||
.data(moduleNamespace, instance) |
|||
; |
|||
}, |
|||
|
|||
destroy: function() { |
|||
module.verbose('Destroying previous module for', element); |
|||
$module |
|||
.removeData(moduleNamespace) |
|||
.off(eventNamespace) |
|||
; |
|||
}, |
|||
|
|||
refresh: function() { |
|||
module.verbose('Refreshing selector cache for', element); |
|||
$module = $(element); |
|||
$shape = $(this).find(settings.selector.shape); |
|||
$side = $(this).find(settings.selector.side); |
|||
}, |
|||
|
|||
repaint: function() { |
|||
module.verbose('Forcing repaint event'); |
|||
var |
|||
shape = $shape.get(0) || document.createElement('div'), |
|||
fakeAssignment = shape.offsetWidth |
|||
; |
|||
}, |
|||
|
|||
animate: function(propertyObject, callback) { |
|||
module.verbose('Animating box with properties', propertyObject); |
|||
callback = callback || function(event) { |
|||
module.reset(); |
|||
module.set.active(); |
|||
$.proxy(settings.onChange, $nextSide)(); |
|||
event.stopImmediatePropagation(); |
|||
}; |
|||
if(settings.useCSS) { |
|||
module.verbose('Starting CSS animation'); |
|||
$module |
|||
.addClass(className.animating) |
|||
; |
|||
module.set.stageSize(); |
|||
module.repaint(); |
|||
$module |
|||
.addClass(className.css) |
|||
; |
|||
$activeSide |
|||
.addClass(className.hidden) |
|||
; |
|||
$shape |
|||
.css(propertyObject) |
|||
.one(endTransition, callback) |
|||
; |
|||
} |
|||
else { |
|||
// not yet supported until .animate() is extended to allow RotateX/Y
|
|||
module.verbose('Starting javascript animation'); |
|||
$module |
|||
.addClass(className.animating) |
|||
.removeClass(className.css) |
|||
; |
|||
module.set.stageSize(); |
|||
module.repaint(); |
|||
$activeSide |
|||
.animate({ |
|||
opacity: 0 |
|||
}, settings.duration, settings.easing) |
|||
; |
|||
$shape |
|||
.animate(propertyObject, settings.duration, settings.easing, callback) |
|||
; |
|||
} |
|||
}, |
|||
|
|||
queue: function(method) { |
|||
module.debug('Queueing animation of', method); |
|||
$shape |
|||
.one(endTransition, function() { |
|||
module.debug('Executing queued animation'); |
|||
$module.shape(method); |
|||
}) |
|||
; |
|||
}, |
|||
|
|||
reset: function() { |
|||
module.verbose('Animating states reset'); |
|||
$module |
|||
.removeClass(className.css) |
|||
.removeClass(className.animating) |
|||
.removeAttr('style') |
|||
; |
|||
$shape |
|||
.removeAttr('style') |
|||
; |
|||
$side |
|||
.removeAttr('style') |
|||
.removeClass(className.hidden) |
|||
; |
|||
$nextSide |
|||
.removeClass(className.animating) |
|||
.removeAttr('style') |
|||
; |
|||
}, |
|||
|
|||
is: { |
|||
|
|||
animating: function() { |
|||
return $module.hasClass(className.animating); |
|||
} |
|||
|
|||
}, |
|||
|
|||
get: { |
|||
|
|||
nextSide: function() { |
|||
return ( $activeSide.next(settings.selector.side).size() > 0 ) |
|||
? $activeSide.next(settings.selector.side) |
|||
: $module.find(settings.selector.side).first() |
|||
; |
|||
} |
|||
|
|||
}, |
|||
|
|||
set: { |
|||
|
|||
defaultSide: function() { |
|||
$activeSide = $module.find('.' + settings.className.active); |
|||
$nextSide = ( $activeSide.next(settings.selector.side).size() > 0 ) |
|||
? $activeSide.next(settings.selector.side) |
|||
: $module.find(settings.selector.side).first() |
|||
; |
|||
module.verbose('Active side set to', $activeSide); |
|||
module.verbose('Next side set to', $nextSide); |
|||
}, |
|||
|
|||
stageSize: function() { |
|||
var |
|||
stage = { |
|||
width : $nextSide.outerWidth(), |
|||
height : $nextSide.outerHeight() |
|||
} |
|||
; |
|||
module.verbose('Resizing stage to fit new content', stage); |
|||
$module |
|||
.css({ |
|||
width : stage.width, |
|||
height : stage.height |
|||
}) |
|||
; |
|||
}, |
|||
|
|||
nextSide: function(selector) { |
|||
$nextSide = $module.find(selector); |
|||
if($nextSide.size() === 0) { |
|||
module.error(error.side); |
|||
} |
|||
module.verbose('Next side manually set to', $nextSide); |
|||
}, |
|||
|
|||
active: function() { |
|||
module.verbose('Setting new side to active', $nextSide); |
|||
$side |
|||
.removeClass(className.active) |
|||
; |
|||
$nextSide |
|||
.addClass(className.active) |
|||
; |
|||
module.set.defaultSide(); |
|||
} |
|||
}, |
|||
|
|||
flip: { |
|||
|
|||
up: function() { |
|||
module.debug('Flipping up', $nextSide); |
|||
if( !module.is.animating() ) { |
|||
module.stage.above(); |
|||
module.animate( module.getTransform.up() ); |
|||
} |
|||
else { |
|||
module.queue('flip.up'); |
|||
} |
|||
}, |
|||
|
|||
down: function() { |
|||
module.debug('Flipping down', $nextSide); |
|||
if( !module.is.animating() ) { |
|||
module.stage.below(); |
|||
module.animate( module.getTransform.down() ); |
|||
} |
|||
else { |
|||
module.queue('flip.down'); |
|||
} |
|||
}, |
|||
|
|||
left: function() { |
|||
module.debug('Flipping left', $nextSide); |
|||
if( !module.is.animating() ) { |
|||
module.stage.left(); |
|||
module.animate(module.getTransform.left() ); |
|||
} |
|||
else { |
|||
module.queue('flip.left'); |
|||
} |
|||
}, |
|||
|
|||
right: function() { |
|||
module.debug('Flipping right', $nextSide); |
|||
if( !module.is.animating() ) { |
|||
module.stage.right(); |
|||
module.animate(module.getTransform.right() ); |
|||
} |
|||
else { |
|||
module.queue('flip.right'); |
|||
} |
|||
}, |
|||
|
|||
over: function() { |
|||
module.debug('Flipping over', $nextSide); |
|||
if( !module.is.animating() ) { |
|||
module.stage.behind(); |
|||
module.animate(module.getTransform.behind() ); |
|||
} |
|||
else { |
|||
module.queue('flip.over'); |
|||
} |
|||
} |
|||
|
|||
}, |
|||
|
|||
getTransform: { |
|||
|
|||
up: function() { |
|||
var |
|||
translate = { |
|||
y: -(($activeSide.outerHeight() - $nextSide.outerHeight()) / 2), |
|||
z: -($activeSide.outerHeight() / 2) |
|||
} |
|||
; |
|||
return { |
|||
transform: 'translateY(' + translate.y + 'px) translateZ('+ translate.z + 'px) rotateX(-90deg)' |
|||
}; |
|||
}, |
|||
|
|||
down: function() { |
|||
var |
|||
translate = { |
|||
y: -(($activeSide.outerHeight() - $nextSide.outerHeight()) / 2), |
|||
z: -($activeSide.outerHeight() / 2) |
|||
} |
|||
; |
|||
return { |
|||
transform: 'translateY(' + translate.y + 'px) translateZ('+ translate.z + 'px) rotateX(90deg)' |
|||
}; |
|||
}, |
|||
|
|||
left: function() { |
|||
var |
|||
translate = { |
|||
x : -(($activeSide.outerWidth() - $nextSide.outerWidth()) / 2), |
|||
z : -($activeSide.outerWidth() / 2) |
|||
} |
|||
; |
|||
return { |
|||
transform: 'translateX(' + translate.x + 'px) translateZ(' + translate.z + 'px) rotateY(90deg)' |
|||
}; |
|||
}, |
|||
|
|||
right: function() { |
|||
var |
|||
translate = { |
|||
x : -(($activeSide.outerWidth() - $nextSide.outerWidth()) / 2), |
|||
z : -($activeSide.outerWidth() / 2) |
|||
} |
|||
; |
|||
return { |
|||
transform: 'translateX(' + translate.x + 'px) translateZ(' + translate.z + 'px) rotateY(-90deg)' |
|||
}; |
|||
}, |
|||
|
|||
behind: function() { |
|||
var |
|||
translate = { |
|||
x : -(($activeSide.outerWidth() - $nextSide.outerWidth()) / 2) |
|||
} |
|||
; |
|||
return { |
|||
transform: 'translateX(' + translate.x + 'px) rotateY(180deg)' |
|||
}; |
|||
} |
|||
|
|||
}, |
|||
|
|||
stage: { |
|||
|
|||
above: function() { |
|||
var |
|||
box = { |
|||
origin : (($activeSide.outerHeight() - $nextSide.outerHeight()) / 2), |
|||
depth : { |
|||
active : ($nextSide.outerHeight() / 2), |
|||
next : ($activeSide.outerHeight() / 2) |
|||
} |
|||
} |
|||
; |
|||
module.verbose('Setting the initial animation position as above', $nextSide, box); |
|||
$activeSide |
|||
.css({ |
|||
'transform' : 'rotateY(0deg) translateZ(' + box.depth.active + 'px)' |
|||
}) |
|||
; |
|||
$nextSide |
|||
.addClass(className.animating) |
|||
.css({ |
|||
'display' : 'block', |
|||
'top' : box.origin + 'px', |
|||
'transform' : 'rotateX(90deg) translateZ(' + box.depth.next + 'px)' |
|||
}) |
|||
; |
|||
}, |
|||
|
|||
below: function() { |
|||
var |
|||
box = { |
|||
origin : (($activeSide.outerHeight() - $nextSide.outerHeight()) / 2), |
|||
depth : { |
|||
active : ($nextSide.outerHeight() / 2), |
|||
next : ($activeSide.outerHeight() / 2) |
|||
} |
|||
} |
|||
; |
|||
module.verbose('Setting the initial animation position as below', $nextSide, box); |
|||
$activeSide |
|||
.css({ |
|||
'transform' : 'rotateY(0deg) translateZ(' + box.depth.active + 'px)' |
|||
}) |
|||
; |
|||
$nextSide |
|||
.addClass(className.animating) |
|||
.css({ |
|||
'display' : 'block', |
|||
'top' : box.origin + 'px', |
|||
'transform' : 'rotateX(-90deg) translateZ(' + box.depth.next + 'px)' |
|||
}) |
|||
; |
|||
}, |
|||
|
|||
left: function() { |
|||
var |
|||
box = { |
|||
origin : ( ( $activeSide.outerWidth() - $nextSide.outerWidth() ) / 2), |
|||
depth : { |
|||
active : ($nextSide.outerWidth() / 2), |
|||
next : ($activeSide.outerWidth() / 2) |
|||
} |
|||
} |
|||
; |
|||
module.verbose('Setting the initial animation position as left', $nextSide, box); |
|||
$activeSide |
|||
.css({ |
|||
'transform' : 'rotateY(0deg) translateZ(' + box.depth.active + 'px)' |
|||
}) |
|||
; |
|||
$nextSide |
|||
.addClass(className.animating) |
|||
.css({ |
|||
'display' : 'block', |
|||
'left' : box.origin + 'px', |
|||
'transform' : 'rotateY(-90deg) translateZ(' + box.depth.next + 'px)' |
|||
}) |
|||
; |
|||
}, |
|||
|
|||
right: function() { |
|||
var |
|||
box = { |
|||
origin : ( ( $activeSide.outerWidth() - $nextSide.outerWidth() ) / 2), |
|||
depth : { |
|||
active : ($nextSide.outerWidth() / 2), |
|||
next : ($activeSide.outerWidth() / 2) |
|||
} |
|||
} |
|||
; |
|||
module.verbose('Setting the initial animation position as left', $nextSide, box); |
|||
$activeSide |
|||
.css({ |
|||
'transform' : 'rotateY(0deg) translateZ(' + box.depth.active + 'px)' |
|||
}) |
|||
; |
|||
$nextSide |
|||
.addClass(className.animating) |
|||
.css({ |
|||
'display' : 'block', |
|||
'left' : box.origin + 'px', |
|||
'transform' : 'rotateY(90deg) translateZ(' + box.depth.next + 'px)' |
|||
}) |
|||
; |
|||
}, |
|||
|
|||
behind: function() { |
|||
var |
|||
box = { |
|||
origin : ( ( $activeSide.outerWidth() - $nextSide.outerWidth() ) / 2), |
|||
depth : { |
|||
active : ($nextSide.outerWidth() / 2), |
|||
next : ($activeSide.outerWidth() / 2) |
|||
} |
|||
} |
|||
; |
|||
module.verbose('Setting the initial animation position as behind', $nextSide, box); |
|||
$activeSide |
|||
.css({ |
|||
'transform' : 'rotateY(0deg)' |
|||
}) |
|||
; |
|||
$nextSide |
|||
.addClass(className.animating) |
|||
.css({ |
|||
'display' : 'block', |
|||
'left' : box.origin + 'px', |
|||
'transform' : 'rotateY(-180deg)' |
|||
}) |
|||
; |
|||
} |
|||
}, |
|||
|
|||
/* standard module */ |
|||
setting: function(name, value) { |
|||
if( $.isPlainObject(name) ) { |
|||
$.extend(true, settings, name); |
|||
} |
|||
else if(value === undefined) { |
|||
return settings[name]; |
|||
} |
|||
else { |
|||
settings[name] = value; |
|||
} |
|||
}, |
|||
|
|||
verbose: function() { |
|||
if(settings.verbose) { |
|||
module.debug.apply(this, arguments); |
|||
} |
|||
}, |
|||
|
|||
debug: function() { |
|||
var |
|||
output = [], |
|||
message = settings.moduleName + ': ' + arguments[0], |
|||
variables = [].slice.call( arguments, 1 ), |
|||
log = console.info || console.log || function(){} |
|||
; |
|||
log = Function.prototype.bind.call(log, console); |
|||
if(settings.debug) { |
|||
output.push(message); |
|||
log.apply(console, output.concat(variables) ); |
|||
} |
|||
}, |
|||
|
|||
error: function() { |
|||
var |
|||
output = [], |
|||
errorMessage = settings.moduleName + ': ' + arguments[0], |
|||
variables = [].slice.call( arguments, 1 ), |
|||
log = console.warn || console.log || function(){} |
|||
; |
|||
log = Function.prototype.bind.call(log, console); |
|||
if(settings.debug) { |
|||
output.push(errorMessage); |
|||
output.concat(variables); |
|||
log.apply(console, output.concat(variables) ); |
|||
} |
|||
}, |
|||
|
|||
invoke: function(query, passedArguments, context) { |
|||
var |
|||
maxDepth, |
|||
found |
|||
; |
|||
passedArguments = passedArguments || queryArguments || [].slice.call( arguments, 2 ); |
|||
context = element || context; |
|||
if(typeof query == 'string' && instance !== undefined) { |
|||
query = query.split('.'); |
|||
maxDepth = query.length - 1; |
|||
$.each(query, function(depth, value) { |
|||
if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) { |
|||
instance = instance[value]; |
|||
return true; |
|||
} |
|||
else if( instance[value] !== undefined ) { |
|||
found = instance[value]; |
|||
return true; |
|||
} |
|||
module.error(error.method); |
|||
return false; |
|||
}); |
|||
} |
|||
if ( $.isFunction( found ) ) { |
|||
module.verbose('Executing invoked function', found); |
|||
return found.apply(context, passedArguments); |
|||
} |
|||
// return retrieved variable or chain
|
|||
return found || false; |
|||
} |
|||
}; |
|||
|
|||
// check for invoking internal method
|
|||
if(methodInvoked) { |
|||
if(instance === undefined) { |
|||
module.initialize(); |
|||
} |
|||
invokedResponse = module.invoke(query); |
|||
} |
|||
// otherwise initialize
|
|||
else { |
|||
if(instance !== undefined) { |
|||
module.destroy(); |
|||
} |
|||
module.initialize(); |
|||
} |
|||
}) |
|||
; |
|||
// chain or return queried method
|
|||
return (invokedResponse) |
|||
? invokedResponse |
|||
: this |
|||
; |
|||
}; |
|||
|
|||
$.fn.shape.settings = { |
|||
|
|||
// module info
|
|||
moduleName : 'Shape Module', |
|||
|
|||
// debug content outputted to console
|
|||
debug : true, |
|||
|
|||
// verbose debug output
|
|||
verbose : true, |
|||
|
|||
// event namespace
|
|||
namespace : 'shape', |
|||
|
|||
// callback occurs on side change
|
|||
beforeChange : function() {}, |
|||
onChange : function() {}, |
|||
|
|||
// use css animation (currently only true is supported)
|
|||
useCSS : true, |
|||
|
|||
// animation duration (useful only with future js animations)
|
|||
duration : 1000, |
|||
easing : 'easeInOutQuad', |
|||
|
|||
// possible errors
|
|||
error: { |
|||
side : 'You tried to switch to a side that does not exist.', |
|||
method : 'The method you called is not defined' |
|||
}, |
|||
|
|||
// classnames used
|
|||
className : { |
|||
css : 'css', |
|||
animating : 'animating', |
|||
hidden : 'hidden', |
|||
active : 'active' |
|||
}, |
|||
|
|||
// selectors used
|
|||
selector : { |
|||
shape : '.shape', |
|||
side : '.side' |
|||
} |
|||
|
|||
}; |
|||
|
|||
|
|||
})( jQuery, window , document ); |
@ -0,0 +1,180 @@ |
|||
/* ****************************** |
|||
Star Review |
|||
Author: Jack Lukic |
|||
Notes: First Commit Sep 04, 2012 |
|||
|
|||
Simple rating module |
|||
****************************** */ |
|||
|
|||
;(function ($, window, document, undefined) { |
|||
|
|||
$.fn.starReview = function(parameters) { |
|||
var |
|||
settings = $.extend(true, {}, $.fn.starReview.settings, parameters), |
|||
// hoist arguments
|
|||
moduleArguments = arguments || false |
|||
; |
|||
$(this) |
|||
.each(function() { |
|||
var |
|||
$module = $(this), |
|||
$star = $module.find(settings.selector.star), |
|||
|
|||
className = settings.className, |
|||
namespace = settings.namespace, |
|||
instance = $module.data('module'), |
|||
module |
|||
; |
|||
|
|||
module = { |
|||
|
|||
settings: settings, |
|||
|
|||
initialize: function() { |
|||
if(settings.rateable) { |
|||
// expandable with states
|
|||
if($.fn.state !== undefined) { |
|||
$module |
|||
.state() |
|||
; |
|||
$star |
|||
.state() |
|||
; |
|||
} |
|||
$star |
|||
.bind('mouseenter.' + namespace, module.event.mouseenter) |
|||
.bind('mouseleave.' + namespace, module.event.mouseleave) |
|||
.bind('click.' + namespace, module.event.click) |
|||
; |
|||
} |
|||
$module |
|||
.addClass(className.initialize) |
|||
.data('module', module) |
|||
; |
|||
}, |
|||
|
|||
setRating: function(rating) { |
|||
var |
|||
$activeStar = $star.eq(rating - 1) |
|||
; |
|||
$module |
|||
.removeClass(className.hover) |
|||
; |
|||
$star |
|||
.removeClass(className.hover) |
|||
; |
|||
$activeStar |
|||
.nextAll() |
|||
.removeClass(className.active) |
|||
; |
|||
$activeStar |
|||
.addClass(className.active) |
|||
.prevAll() |
|||
.addClass(className.active) |
|||
; |
|||
$.proxy(settings.onRate, $module)(); |
|||
}, |
|||
|
|||
event: { |
|||
mouseenter: function() { |
|||
var |
|||
$activeStar = $(this) |
|||
; |
|||
$activeStar |
|||
.nextAll() |
|||
.removeClass(className.hover) |
|||
; |
|||
$module |
|||
.addClass(className.hover) |
|||
; |
|||
$activeStar |
|||
.addClass(className.hover) |
|||
.prevAll() |
|||
.addClass(className.hover) |
|||
; |
|||
}, |
|||
mouseleave: function() { |
|||
$star |
|||
.removeClass(className.hover) |
|||
; |
|||
}, |
|||
click: function() { |
|||
var |
|||
$activeStar = $(this) |
|||
; |
|||
module.setRating( $star.index($activeStar) + 1); |
|||
} |
|||
}, |
|||
|
|||
// handle error logging
|
|||
error: function(errorMessage) { |
|||
console.warn(settings.moduleName + ': ' + errorMessage); |
|||
}, |
|||
|
|||
// allows for dot notation method calls
|
|||
invoke: function(methodName, context, methodArguments) { |
|||
var |
|||
method |
|||
; |
|||
methodArguments = methodArguments || Array.prototype.slice.call( arguments, 2 ); |
|||
if(typeof methodName == 'string' && instance !== undefined) { |
|||
methodName = methodName.split('.'); |
|||
$.each(methodName, function(index, name) { |
|||
if( $.isPlainObject( instance[name] ) ) { |
|||
instance = instance[name]; |
|||
return true; |
|||
} |
|||
else if( $.isFunction( instance[name] ) ) { |
|||
method = instance[name]; |
|||
return true; |
|||
} |
|||
module.error(settings.errors.method); |
|||
return false; |
|||
}); |
|||
} |
|||
return ( $.isFunction( method ) ) |
|||
? method.apply(context, methodArguments) |
|||
: false |
|||
; |
|||
} |
|||
|
|||
}; |
|||
|
|||
if(instance !== undefined && moduleArguments) { |
|||
// simpler than invoke realizing to invoke itself (and losing scope due prototype.call()
|
|||
if(moduleArguments[0] == 'invoke') { |
|||
moduleArguments = Array.prototype.slice.call( moduleArguments, 1 ); |
|||
} |
|||
return module.invoke(moduleArguments[0], this, Array.prototype.slice.call( moduleArguments, 1 ) ); |
|||
} |
|||
// initializing
|
|||
module.initialize(); |
|||
}) |
|||
; |
|||
|
|||
return this; |
|||
}; |
|||
|
|||
$.fn.starReview.settings = { |
|||
|
|||
moduleName : 'Star Module', |
|||
namespace : 'star', |
|||
|
|||
rateable : true, |
|||
onRate : function(){}, |
|||
|
|||
className : { |
|||
initialize : 'initialize', |
|||
loading : 'loading', |
|||
active : 'active', |
|||
hover : 'hover', |
|||
down : 'down' |
|||
}, |
|||
|
|||
selector : { |
|||
star : 'i' |
|||
} |
|||
|
|||
}; |
|||
|
|||
})( jQuery, window , document ); |
@ -0,0 +1,523 @@ |
|||
/* ****************************** |
|||
Module - Simple Tab Navigation |
|||
Author: Jack Lukic |
|||
Notes: First Commit Aug 15, 2012 |
|||
|
|||
History based tab navigation |
|||
****************************** */ |
|||
|
|||
;(function ($, window, document, undefined) { |
|||
|
|||
$.fn.tabNavigation = function(parameters) { |
|||
|
|||
var |
|||
settings = $.extend(true, {}, $.fn.tabNavigation.settings, parameters), |
|||
|
|||
$tabNavigation = $(this), |
|||
$tabs = $(settings.context).find(settings.selector.tabs), |
|||
|
|||
firstLoad = true, |
|||
cache = {}, |
|||
recursionDepth = 0, |
|||
|
|||
activeTabPath, |
|||
parameterArray, |
|||
historyEvent, |
|||
|
|||
className = settings.className, |
|||
metadata = settings.metadata, |
|||
namespace = settings.namespace, |
|||
errors = settings.errors, |
|||
|
|||
instance = $tabNavigation.data('module'), |
|||
|
|||
query = arguments[0], |
|||
methodInvoked = (instance !== undefined && typeof query == 'string'), |
|||
passedArguments = [].slice.call(arguments, 1), |
|||
|
|||
module, |
|||
invokedResponse |
|||
; |
|||
|
|||
module = { |
|||
|
|||
initialize: function() { |
|||
module.debug('Initializing Tabs', $tabNavigation); |
|||
// attach history events
|
|||
if(settings.history && settings.path !== false) { |
|||
if( $.address !== undefined ) { |
|||
module.verbose('Address library found adding state change event'); |
|||
$.address |
|||
.state(settings.path) |
|||
.change(module.event.history.change) |
|||
; |
|||
} |
|||
else { |
|||
module.error(errors.state); |
|||
} |
|||
} |
|||
// attach events if navigation wasn't set to window
|
|||
if( !$.isWindow( $tabNavigation.get(0) ) ) { |
|||
$tabNavigation |
|||
.on('click.' + namespace, module.event.click) |
|||
; |
|||
} |
|||
$tabNavigation |
|||
.data('module', module) |
|||
; |
|||
}, |
|||
|
|||
destroy: function() { |
|||
module.debug('Destroying tabs', $tabNavigation); |
|||
$tabNavigation |
|||
.off('.' + namespace) |
|||
; |
|||
}, |
|||
|
|||
event: { |
|||
click: function() { |
|||
module.debug('Navigation clicked'); |
|||
var |
|||
tabPath = $(this).data(metadata.tab) |
|||
; |
|||
if(tabPath !== undefined) { |
|||
if(tabPath !== activeTabPath) { |
|||
if(settings.history) { |
|||
$.address.value(tabPath); |
|||
} |
|||
else { |
|||
module.change(tabPath); |
|||
} |
|||
} |
|||
} |
|||
else { |
|||
module.debug('No tab specified'); |
|||
} |
|||
}, |
|||
history: { |
|||
change: function(event) { |
|||
var |
|||
tabPath = event.pathNames.join('/') || module.get.initialPath(), |
|||
pageTitle = settings.templates.determineTitle(tabPath) || false |
|||
; |
|||
module.debug('History change event', tabPath, event); |
|||
historyEvent = event; |
|||
if(tabPath !== undefined) { |
|||
module.change(tabPath); |
|||
} |
|||
if(pageTitle) { |
|||
$.address.title(pageTitle); |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
|
|||
refresh: function() { |
|||
if(activeTabPath) { |
|||
module.debug('Refreshing tab', activeTabPath); |
|||
module.change(activeTabPath); |
|||
} |
|||
}, |
|||
|
|||
cache: { |
|||
read: function(tabPath) { |
|||
return (tabPath !== undefined) |
|||
? cache[tabPath] |
|||
: cache |
|||
; |
|||
}, |
|||
add: function(tabPath, content) { |
|||
tabPath = tabPath || activeTabPath; |
|||
module.debug('Adding cached content for', tabPath); |
|||
cache[tabPath] = content; |
|||
}, |
|||
remove: function(tabPath) { |
|||
tabPath = tabPath || activeTabPath; |
|||
module.debug('Removing cached content for', tabPath); |
|||
delete cache[tabPath]; |
|||
} |
|||
}, |
|||
|
|||
change: function(tabPath) { |
|||
var |
|||
pathArray = module.get.defaultPathArray(tabPath) |
|||
; |
|||
module.deactivate.all(); |
|||
$.each(pathArray, function(index, tab) { |
|||
var |
|||
currentPathArray = pathArray.slice(0, index + 1), |
|||
currentPath = module.utils.arrayToPath(currentPathArray), |
|||
|
|||
isLastTab = (module.utils.last(pathArray) == currentPath), |
|||
isTab = module.is.tab(currentPath), |
|||
isParam = !(isTab), |
|||
|
|||
pushStateAvailable = (window.history && window.history.pushState), |
|||
shouldIgnoreLoad = (pushStateAvailable && settings.ignoreFirstLoad && firstLoad), |
|||
remoteContent = $.isPlainObject(settings.apiSettings), |
|||
|
|||
$tab = module.get.tabElement(currentPath) |
|||
; |
|||
module.verbose('Looking for tab', tab); |
|||
if(isParam) { |
|||
module.verbose('Tab is not found, assuming it is a parameter', tab); |
|||
return true; |
|||
} |
|||
else if(isTab) { |
|||
// scope up
|
|||
module.verbose('Tab was found', tab); |
|||
activeTabPath = currentPath; |
|||
parameterArray = module.utils.filterArray(pathArray, currentPathArray); |
|||
if(isLastTab && remoteContent) { |
|||
if(!shouldIgnoreLoad) { |
|||
module.activate.navigation(currentPath); |
|||
module.content.fetch(currentPath, settings.onTabLoad); |
|||
} |
|||
else { |
|||
module.debug('Ignoring remote content on first tab load', currentPath); |
|||
firstLoad = false; |
|||
cache[tabPath] = $tab.html(); |
|||
module.activate.all(currentPath); |
|||
$.proxy(settings.onTabInit, $tab)(currentPath, parameterArray, historyEvent); |
|||
} |
|||
} |
|||
else { |
|||
module.debug('Opened tab', currentPath); |
|||
module.activate.all(currentPath); |
|||
$.proxy(settings.onTabLoad, $tab)(currentPath, parameterArray, historyEvent); |
|||
} |
|||
|
|||
} |
|||
}); |
|||
}, |
|||
|
|||
content: { |
|||
|
|||
fetch: function(tabPath) { |
|||
var |
|||
$tab = module.get.tabElement(tabPath), |
|||
cachedContent = cache[tabPath] || false, |
|||
apiSettings = { |
|||
dataType : 'html', |
|||
stateContext : $tab, |
|||
success : function(response) { |
|||
cache[tabPath] = response; |
|||
module.content.update(tabPath, response); |
|||
if(tabPath == activeTabPath) { |
|||
module.debug('Content loaded', tabPath); |
|||
module.activate.tab(tabPath); |
|||
} |
|||
else { |
|||
module.debug('Content loaded in background', tabPath); |
|||
} |
|||
$.proxy(settings.onTabInit, $tab)(tabPath, parameterArray, historyEvent); |
|||
}, |
|||
urlData: { tab: tabPath } |
|||
}, |
|||
request = $tab.data(metadata.promise) || false, |
|||
existingRequest = ( request && request.state() === 'pending' ) |
|||
; |
|||
if(settings.cache && cachedContent) { |
|||
module.debug('Showing existing content', tabPath); |
|||
// module.content.update(tabPath, cachedContent);
|
|||
module.activate.tab(tabPath); |
|||
$.proxy(settings.onTabLoad, $tab)(tabPath, parameterArray, historyEvent); |
|||
} |
|||
else if(existingRequest) { |
|||
module.debug('Content is already loading', tabPath); |
|||
$tab |
|||
.addClass(className.loading) |
|||
; |
|||
} |
|||
else if($.api !== undefined) { |
|||
module.debug('Retrieving content', tabPath); |
|||
$.api( $.extend(true, {}, settings.apiSettings, apiSettings) ); |
|||
} |
|||
else { |
|||
module.error(errors.api); |
|||
} |
|||
}, |
|||
|
|||
update: function(tabPath, html) { |
|||
module.debug('Updating html for', tabPath); |
|||
var |
|||
$tab = module.get.tabElement(tabPath) |
|||
; |
|||
$tab |
|||
.html(html) |
|||
; |
|||
} |
|||
}, |
|||
|
|||
activate: { |
|||
all: function(tabPath) { |
|||
module.activate.tab(tabPath); |
|||
module.activate.navigation(tabPath); |
|||
}, |
|||
tab: function(tabPath) { |
|||
var |
|||
$tab = module.get.tabElement(tabPath) |
|||
; |
|||
module.verbose('Showing tab content for', $tab); |
|||
$tab.addClass(className.active); |
|||
}, |
|||
navigation: function(tabPath) { |
|||
var |
|||
$nav = module.get.navElement(tabPath) |
|||
; |
|||
module.verbose('Activating tab navigation for', $nav); |
|||
$nav.addClass(className.active); |
|||
} |
|||
}, |
|||
|
|||
deactivate: { |
|||
all: function() { |
|||
module.deactivate.navigation(); |
|||
module.deactivate.tabs(); |
|||
}, |
|||
navigation: function() { |
|||
$tabNavigation |
|||
.removeClass(className.active) |
|||
; |
|||
}, |
|||
tabs: function() { |
|||
$tabs |
|||
.removeClass(className.active + ' ' + className.loading) |
|||
; |
|||
} |
|||
}, |
|||
|
|||
is: { |
|||
tab: function(tabName) { |
|||
return ( module.get.tabElement(tabName).size() > 0 ); |
|||
} |
|||
}, |
|||
|
|||
get: { |
|||
initialPath: function() { |
|||
return $tabNavigation.eq(0).data(metadata.tab) || $tabs.eq(0).data(metadata.tab); |
|||
}, |
|||
// adds default tabs to tab path
|
|||
defaultPathArray: function(tabPath) { |
|||
return module.utils.pathToArray( module.get.defaultPath(tabPath) ); |
|||
}, |
|||
defaultPath: function(tabPath) { |
|||
var |
|||
$defaultNav = $tabNavigation.filter('[data-' + metadata.tab + '^="' + tabPath + '/"]').eq(0), |
|||
defaultTab = $defaultNav.data(metadata.tab) || false |
|||
; |
|||
if( defaultTab ) { |
|||
module.debug('Found default tab', defaultTab); |
|||
if(recursionDepth < settings.maxDepth) { |
|||
recursionDepth++; |
|||
return module.get.defaultPath(defaultTab); |
|||
} |
|||
module.error(errors.recursion); |
|||
} |
|||
recursionDepth = 0; |
|||
return tabPath; |
|||
}, |
|||
navElement: function(tabPath) { |
|||
tabPath = tabPath || activeTabPath; |
|||
return $tabNavigation.filter('[data-' + metadata.tab + '="' + tabPath + '"]'); |
|||
}, |
|||
tabElement: function(tabPath) { |
|||
var |
|||
$fullPathTab, |
|||
$simplePathTab, |
|||
tabPathArray, |
|||
lastTab |
|||
; |
|||
tabPath = tabPath || activeTabPath; |
|||
tabPathArray = module.utils.pathToArray(tabPath); |
|||
lastTab = module.utils.last(tabPathArray); |
|||
$fullPathTab = $tabs.filter('[data-' + metadata.tab + '="' + lastTab + '"]'); |
|||
$simplePathTab = $tabs.filter('[data-' + metadata.tab + '="' + tabPath + '"]'); |
|||
return ($fullPathTab.size() > 0) |
|||
? $fullPathTab |
|||
: $simplePathTab |
|||
; |
|||
}, |
|||
tab: function() { |
|||
return activeTabPath; |
|||
} |
|||
}, |
|||
|
|||
utils: { |
|||
filterArray: function(keepArray, removeArray) { |
|||
return $.grep(keepArray, function(keepValue) { |
|||
return ( $.inArray(keepValue, removeArray) == -1); |
|||
}); |
|||
}, |
|||
last: function(array) { |
|||
return $.isArray(array) |
|||
? array[ array.length - 1] |
|||
: false |
|||
; |
|||
}, |
|||
pathToArray: function(pathName) { |
|||
if(pathName === undefined) { |
|||
pathName = activeTabPath; |
|||
} |
|||
return typeof pathName == 'string' |
|||
? pathName.split('/') |
|||
: [pathName] |
|||
; |
|||
}, |
|||
arrayToPath: function(pathArray) { |
|||
return $.isArray(pathArray) |
|||
? pathArray.join('/') |
|||
: false |
|||
; |
|||
} |
|||
}, |
|||
|
|||
/* standard module */ |
|||
setting: function(name, value) { |
|||
if(value === undefined) { |
|||
return settings[name]; |
|||
} |
|||
settings[name] = value; |
|||
}, |
|||
verbose: function() { |
|||
if(settings.verbose) { |
|||
module.debug.apply(this, arguments); |
|||
} |
|||
}, |
|||
debug: function() { |
|||
var |
|||
output = [], |
|||
message = settings.moduleName + ': ' + arguments[0], |
|||
variables = [].slice.call( arguments, 1 ), |
|||
log = console.info || console.log || function(){} |
|||
; |
|||
log = Function.prototype.bind.call(log, console); |
|||
if(settings.debug) { |
|||
output.push(message); |
|||
log.apply(console, output.concat(variables) ); |
|||
} |
|||
}, |
|||
error: function() { |
|||
var |
|||
output = [], |
|||
errorMessage = settings.moduleName + ': ' + arguments[0], |
|||
variables = [].slice.call( arguments, 1 ), |
|||
log = console.warn || console.log || function(){} |
|||
; |
|||
log = Function.prototype.bind.call(log, console); |
|||
if(settings.debug) { |
|||
output.push(errorMessage); |
|||
output.concat(variables); |
|||
log.apply(console, output.concat(variables)); |
|||
} |
|||
}, |
|||
invoke: function(query, context, passedArguments) { |
|||
var |
|||
maxDepth, |
|||
found |
|||
; |
|||
passedArguments = passedArguments || [].slice.call( arguments, 2 ); |
|||
if(typeof query == 'string' && instance !== undefined) { |
|||
query = query.split('.'); |
|||
maxDepth = query.length - 1; |
|||
$.each(query, function(depth, value) { |
|||
if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) { |
|||
instance = instance[value]; |
|||
return true; |
|||
} |
|||
else if( instance[value] !== undefined ) { |
|||
found = instance[value]; |
|||
return true; |
|||
} |
|||
module.error(settings.errors.method); |
|||
return false; |
|||
}); |
|||
} |
|||
if ( $.isFunction( found ) ) { |
|||
return found.apply(context, passedArguments); |
|||
} |
|||
// return retrieved variable or chain
|
|||
return found; |
|||
} |
|||
}; |
|||
|
|||
// check for invoking internal method
|
|||
if(methodInvoked) { |
|||
invokedResponse = module.invoke(query, this, passedArguments); |
|||
} |
|||
// otherwise initialize
|
|||
else { |
|||
module.initialize(); |
|||
} |
|||
|
|||
return (invokedResponse !== undefined) |
|||
? invokedResponse |
|||
: this |
|||
; |
|||
|
|||
}; |
|||
|
|||
// shortcut for tabbed content with no defined navigation
|
|||
$.tabNavigation = function(settings) { |
|||
$(window).tabNavigation(settings); |
|||
}; |
|||
|
|||
$.fn.tabNavigation.settings = { |
|||
|
|||
moduleName : 'Tab Module', |
|||
verbose : false, |
|||
debug : true, |
|||
namespace : 'tab', |
|||
|
|||
// only called first time a tab's content is loaded (when remote source)
|
|||
onTabInit : function(tabPath, parameterArray, historyEvent) {}, |
|||
// called on every load
|
|||
onTabLoad : function(tabPath, parameterArray, historyEvent) {}, |
|||
|
|||
templates: { |
|||
determineTitle: function(tabArray) {} |
|||
}, |
|||
|
|||
history : false, |
|||
path : false, |
|||
|
|||
context : 'body', |
|||
|
|||
// max depth a tab can be nested
|
|||
maxDepth : 25, |
|||
// dont load content on first load
|
|||
ignoreFirstLoad : true, |
|||
// load tab content new every tab click
|
|||
alwaysRefresh : false, |
|||
// cache the content requests to pull locally
|
|||
cache : true, |
|||
// settings for api call
|
|||
apiSettings : false, |
|||
|
|||
errors: { |
|||
api : 'You attempted to load content without API module', |
|||
noContent : 'The tab you specified is missing a content url.', |
|||
method : 'The method you called is not defined', |
|||
state : 'The state library has not been initialized', |
|||
missingTab : 'Missing tab: ', |
|||
recursion : 'Max recursive depth reached' |
|||
}, |
|||
|
|||
metadata : { |
|||
tab : 'tab', |
|||
loaded : 'loaded', |
|||
promise: 'promise' |
|||
}, |
|||
|
|||
className : { |
|||
loading : 'loading', |
|||
active : 'active' |
|||
}, |
|||
|
|||
selector : { |
|||
tabs : '.tab' |
|||
} |
|||
|
|||
}; |
|||
|
|||
})( jQuery, window , document ); |
@ -0,0 +1,391 @@ |
|||
/* ****************************** |
|||
Module - Video Component |
|||
Author: Jack Lukic |
|||
Notes: First Commit June 30, 2012 |
|||
|
|||
This is a video playlist and video embed plugin which helps |
|||
provide helpers for adding embed code for vimeo and youtube and |
|||
abstracting event handlers for each library |
|||
|
|||
****************************** */ |
|||
|
|||
;(function ($, window, document, undefined) { |
|||
|
|||
$.fn.video = function(parameters) { |
|||
|
|||
var |
|||
settings = $.extend(true, {}, $.fn.video.settings, parameters), |
|||
// make arguments available
|
|||
moduleArguments = arguments || false, |
|||
invokedResponse |
|||
; |
|||
|
|||
$(this) |
|||
.each(function() { |
|||
var |
|||
$module = $(this), |
|||
$placeholder = $module.find(settings.selector.placeholder), |
|||
$playButton = $module.find(settings.selector.playButton), |
|||
$embed = $module.find(settings.selector.embed), |
|||
|
|||
element = this, |
|||
instance = $module.data('module-' + settings.namespace), |
|||
methodInvoked = (typeof parameters == 'string'), |
|||
|
|||
namespace = settings.namespace, |
|||
metadata = settings.metadata, |
|||
className = settings.className, |
|||
|
|||
module |
|||
; |
|||
|
|||
module = { |
|||
|
|||
initialize: function() { |
|||
module.debug('Initializing video'); |
|||
$placeholder |
|||
.off('.video') |
|||
.on('click.' + namespace, module.play) |
|||
; |
|||
$playButton |
|||
.off('.video') |
|||
.on('click.' + namespace, module.play) |
|||
; |
|||
$module |
|||
.data('module-' + namespace, module) |
|||
; |
|||
}, |
|||
|
|||
// sets new video
|
|||
change: function(source, flv) { |
|||
module.debug('Changing video to ', flv); |
|||
$module |
|||
.data(metadata.source, source) |
|||
.data(metadata.flv, flv) |
|||
; |
|||
settings.onChange(); |
|||
}, |
|||
|
|||
// clears video embed
|
|||
reset: function() { |
|||
module.debug('Clearing video embed and showing placeholder'); |
|||
$module |
|||
.removeClass(className.active) |
|||
; |
|||
$embed |
|||
.html(' ') |
|||
; |
|||
$placeholder |
|||
.show() |
|||
; |
|||
settings.onReset(); |
|||
}, |
|||
|
|||
// plays current video
|
|||
play: function() { |
|||
module.debug('Playing video'); |
|||
var |
|||
source = $module.data(metadata.source), |
|||
flv = $module.data(metadata.flv) |
|||
; |
|||
$embed |
|||
.html( module.generate.html(source, flv) ) |
|||
; |
|||
$module |
|||
.addClass(className.active) |
|||
; |
|||
settings.onPlay(); |
|||
}, |
|||
|
|||
generate: { |
|||
// generates iframe html
|
|||
html: function(source, flv) { |
|||
module.debug('Generating embed html'); |
|||
var |
|||
width = (settings.width == 'auto') |
|||
? $module.width() |
|||
: settings.width, |
|||
height = (settings.height == 'auto') |
|||
? $module.height() |
|||
: settings.height, |
|||
html |
|||
; |
|||
if(source == 'vimeo') { |
|||
html = '' |
|||
+ '<iframe src="http://player.vimeo.com/video/' + flv + '?=' + module.generate.url(source) + '"' |
|||
+ ' width="' + width + '" height="' + height + '"' |
|||
+ ' frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>' |
|||
; |
|||
} |
|||
else if(source == 'youtube') { |
|||
html = '' |
|||
+ '<iframe src="http://www.youtube.com/embed/' + flv + '?=' + module.generate.url(source) + '"' |
|||
+ ' width="' + width + '" height="' + height + '"' |
|||
+ ' frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>' |
|||
; |
|||
} |
|||
return html; |
|||
}, |
|||
|
|||
// generate url parameters
|
|||
url: function(source) { |
|||
var |
|||
api = (settings.api) |
|||
? 1 |
|||
: 0, |
|||
autoplay = (settings.autoplay) |
|||
? 1 |
|||
: 0, |
|||
hd = (settings.hd) |
|||
? 1 |
|||
: 0, |
|||
showUI = (settings.showUI) |
|||
? 1 |
|||
: 0, |
|||
// opposite used for some params
|
|||
hideUI = !(settings.showUI) |
|||
? 1 |
|||
: 0, |
|||
url = '' |
|||
; |
|||
if(source == 'vimeo') { |
|||
url = '' |
|||
+ 'api=' + api |
|||
+ '&title=' + showUI |
|||
+ '&byline=' + showUI |
|||
+ '&portrait=' + showUI |
|||
+ '&autoplay=' + autoplay |
|||
; |
|||
if(settings.color) { |
|||
url += '&color=' + settings.color; |
|||
} |
|||
} |
|||
else if(source == 'youtube') { |
|||
url = '' |
|||
+ 'enablejsapi=' + api |
|||
+ '&autoplay=' + autoplay |
|||
+ '&autohide=' + hideUI |
|||
+ '&hq=' + hd |
|||
+ '&modestbranding=1' |
|||
; |
|||
if(settings.color) { |
|||
url += '&color=' + settings.color; |
|||
} |
|||
} |
|||
return url; |
|||
} |
|||
}, |
|||
|
|||
/* standard module */ |
|||
debug: function(message, variableName) { |
|||
if(settings.debug) { |
|||
if(variableName !== undefined) { |
|||
console.info(settings.moduleName + ': ' + message, variableName); |
|||
} |
|||
else { |
|||
console.info(settings.moduleName + ': ' + message); |
|||
} |
|||
} |
|||
}, |
|||
error: function(errorMessage) { |
|||
console.warn(settings.moduleName + ': ' + errorMessage); |
|||
}, |
|||
invoke: function(methodName, context, methodArguments) { |
|||
var |
|||
method |
|||
; |
|||
methodArguments = methodArguments || Array.prototype.slice.call( arguments, 2 ); |
|||
if(typeof methodName == 'string' && instance !== undefined) { |
|||
methodName = methodName.split('.'); |
|||
$.each(methodName, function(index, name) { |
|||
if( $.isPlainObject( instance[name] ) ) { |
|||
instance = instance[name]; |
|||
return true; |
|||
} |
|||
else if( $.isFunction( instance[name] ) ) { |
|||
method = instance[name]; |
|||
return true; |
|||
} |
|||
module.error(settings.errors.method); |
|||
return false; |
|||
}); |
|||
} |
|||
if ( $.isFunction( method ) ) { |
|||
return method.apply(context, methodArguments); |
|||
} |
|||
// return retrieved variable or chain
|
|||
return method; |
|||
} |
|||
}; |
|||
// check for invoking internal method
|
|||
if(methodInvoked) { |
|||
invokedResponse = module.invoke(moduleArguments[0], this, Array.prototype.slice.call( moduleArguments, 1 ) ); |
|||
} |
|||
// otherwise initialize
|
|||
else { |
|||
if(instance) { |
|||
module.destroy(); |
|||
} |
|||
module.initialize(); |
|||
} |
|||
|
|||
}) |
|||
; |
|||
// chain or return queried method
|
|||
return (invokedResponse !== undefined) |
|||
? invokedResponse |
|||
: this |
|||
; |
|||
}; |
|||
|
|||
|
|||
$.fn.videoPlaylist = function(video, parameters) { |
|||
var |
|||
$allModules = $(this), |
|||
$video = $(video), |
|||
$iframe = $video.find('.embed iframe'), |
|||
|
|||
settings = $.extend({}, $.fn.videoPlaylist.settings, parameters, true) |
|||
; |
|||
$allModules |
|||
.each(function() { |
|||
var |
|||
$element = $(this), |
|||
|
|||
metadata = settings.metadata, |
|||
namespace = settings.namespace, |
|||
className = settings.className, |
|||
|
|||
module = { |
|||
initialize: function() { |
|||
$element |
|||
.on('click.' + namespace , module.changeVideo) |
|||
; |
|||
}, |
|||
changeVideo: function() { |
|||
var |
|||
flv = $element.data(metadata.flv) || false, |
|||
source = $element.data(metadata.source) || false, |
|||
placeholder = $element.data(metadata.placeholder) || false |
|||
; |
|||
if(flv && source) { |
|||
$video |
|||
.data(metadata.source, source) |
|||
.data(metadata.flv, flv) |
|||
; |
|||
if(settings.showPlaceholder) { |
|||
$video |
|||
.removeClass(className.active) |
|||
.find($.fn.video.selector.placeholder) |
|||
.attr('src', placeholder) |
|||
; |
|||
} |
|||
else { |
|||
try { |
|||
$video |
|||
.video('play') |
|||
; |
|||
} |
|||
catch(error) { |
|||
console.warn('Video Playlist Module: ' + settings.error.init); |
|||
} |
|||
} |
|||
$allModules |
|||
.removeClass(className.active) |
|||
; |
|||
$element |
|||
.addClass(className.active) |
|||
; |
|||
} |
|||
} |
|||
} |
|||
; |
|||
module.initialize(); |
|||
}) |
|||
; |
|||
|
|||
if(settings.playFirst) { |
|||
$allModules |
|||
.eq(0) |
|||
.trigger('click') |
|||
; |
|||
// we all like a good hack
|
|||
if($iframe.size() > 0) { |
|||
$iframe |
|||
.attr('src', $iframe.attr('src').replace('autoplay=1', 'autoplay=0') ) |
|||
; |
|||
} |
|||
|
|||
} |
|||
|
|||
}; |
|||
|
|||
$.fn.video.settings = { |
|||
|
|||
moduleName : 'Video', |
|||
namespace : 'video', |
|||
debug : false, |
|||
|
|||
metadata : { |
|||
source : 'source', |
|||
flv : 'flv' |
|||
}, |
|||
|
|||
onPlay : function(){}, |
|||
onReset : function(){}, |
|||
onChange : function(){}, |
|||
|
|||
// callbacks not coded yet (needs to use jsapi)
|
|||
play : function() {}, |
|||
pause : function() {}, |
|||
stop : function() {}, |
|||
|
|||
width : 'auto', |
|||
height : 'auto', |
|||
|
|||
autoplay : false, |
|||
color : '#442359', |
|||
hd : true, |
|||
showUI : false, |
|||
api : true, |
|||
|
|||
errors : { |
|||
method : 'The method you called is not defined' |
|||
}, |
|||
|
|||
className : { |
|||
active : 'active' |
|||
}, |
|||
|
|||
selector : { |
|||
embed : '.embed', |
|||
placeholder : '.placeholder', |
|||
playButton : '.play' |
|||
} |
|||
}; |
|||
|
|||
$.fn.videoPlaylist.settings = { |
|||
moduleName : 'Video Playlist', |
|||
namespace : 'videoPlaylist', |
|||
|
|||
source : 'vimeo', |
|||
showPlaceholder : false, |
|||
playFirst : true, |
|||
|
|||
metadata: { |
|||
flv : 'flv', |
|||
source : 'source', |
|||
placeholder : 'placeholder' |
|||
}, |
|||
|
|||
errors: { |
|||
init : 'The video player you specified was not yet initialized' |
|||
}, |
|||
|
|||
className : { |
|||
active : 'active' |
|||
} |
|||
|
|||
}; |
|||
|
|||
})( jQuery, window , document ); |
Loading…
Reference in new issue