Browse Source

Updates api, state, visibility, visit to latest iteration

pull/912/head
jlukic 10 years ago
parent
commit
174ea2cc06
4 changed files with 295 additions and 104 deletions
  1. 108
      src/definitions/behaviors/api.js
  2. 4
      src/definitions/behaviors/state.js
  3. 223
      src/definitions/behaviors/visibility.js
  4. 64
      src/definitions/behaviors/visit.js

108
src/definitions/behaviors/api.js

@ -112,7 +112,6 @@ $.api = $.fn.api = function(parameters) {
module.debug('Request cancelled previous request is still pending');
return;
}
// pass element metadata to url (value, text)
if(settings.defaultData) {
$.extend(true, settings.urlData, module.get.defaultData());
@ -201,39 +200,71 @@ $.api = $.fn.api = function(parameters) {
add: {
urlData: function(url, urlData) {
var
urlVariables
requiredVariables,
optionalVariables
;
if(url) {
urlVariables = url.match(settings.regExp.required);
urlData = urlData || settings.urlData;
if(urlVariables) {
module.debug('Looking for URL variables', urlVariables);
$.each(urlVariables, function(index, templateValue){
requiredVariables = url.match(settings.regExp.required);
optionalVariables = url.match(settings.regExp.optional);
urlData = urlData || settings.urlData;
if(requiredVariables) {
module.debug('Looking for required URL variables', requiredVariables);
$.each(requiredVariables, function(index, templatedString) {
var
term = templateValue.substr( 2, templateValue.length - 3),
termValue = ($.isPlainObject(urlData) && urlData[term] !== undefined)
? urlData[term]
: ($module.data(term) !== undefined)
? $module.data(term)
: ($context.data(term) !== undefined)
? $context.data(term)
: urlData[term]
// allow legacy {$var} style
variable = (templatedString.indexOf('$') !== -1)
? templatedString.substr(2, templatedString.length - 3)
: templatedString.substr(1, templatedString.length - 2),
value = ($.isPlainObject(urlData) && urlData[variable] !== undefined)
? urlData[variable]
: ($module.data(variable) !== undefined)
? $module.data(variable)
: ($context.data(variable) !== undefined)
? $context.data(variable)
: urlData[variable]
;
module.verbose('Looking for variable', 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(error.missingParameter, term, url);
// remove value
if(value === undefined) {
module.error(error.requiredParameter, variable, url);
url = false;
return false;
}
else {
url = url.replace(templateValue, termValue);
module.verbose('Found required variable', variable, value);
url = url.replace(templatedString, value);
}
});
}
if(optionalVariables) {
module.debug('Looking for optional URL variables', requiredVariables);
$.each(optionalVariables, function(index, templatedString) {
var
// allow legacy {/$var} style
variable = (templatedString.indexOf('$') !== -1)
? templatedString.substr(3, templatedString.length - 4)
: templatedString.substr(2, templatedString.length - 3),
value = ($.isPlainObject(urlData) && urlData[variable] !== undefined)
? urlData[variable]
: ($module.data(variable) !== undefined)
? $module.data(variable)
: ($context.data(variable) !== undefined)
? $context.data(variable)
: urlData[variable]
;
// optional replacement
if(value !== undefined) {
module.verbose('Optional variable Found', variable, value);
url = url.replace(templatedString, value);
}
else {
module.verbose('Optional variable not found', variable);
// remove preceding slash if set
if(url.indexOf('/' + templatedString) !== -1) {
url = url.replace('/' + templatedString, '');
}
else {
url = url.replace(templatedString, '');
}
}
});
}
@ -683,7 +714,8 @@ $.api.settings = {
action : false,
regExp : {
required: /\{\$([A-z]+)\}/g
required: /\{\$*[A-z0-9]+\}/g,
optional: /\{\/\$*[A-z0-9]+\}/g,
},
// data
@ -717,17 +749,17 @@ $.api.settings = {
// errors
error : {
beforeSend : 'The before send function has aborted the request',
error : 'There was an error with your request',
exitConditions : 'API Request Aborted. Exit conditions met',
JSONParse : 'JSON could not be parsed during error handling',
missingSerialize : 'Serializing a Form requires toJSON to be included',
missingAction : 'API action used but no url was defined',
missingParameter : 'Missing an essential URL parameter: ',
missingURL : 'No URL specified for api event',
parseError : 'There was an error parsing your request',
statusMessage : 'Server gave an error: ',
timeout : 'Your request timed out'
beforeSend : 'The before send function has aborted the request',
error : 'There was an error with your request',
exitConditions : 'API Request Aborted. Exit conditions met',
JSONParse : 'JSON could not be parsed during error handling',
missingAction : 'API action used but no url was defined',
missingSerialize : 'Serializing a Form requires toJSON to be included',
missingURL : 'No URL specified for api event',
parseError : 'There was an error parsing your request',
requiredParameter : 'Missing a required URL parameter: ',
statusMessage : 'Server gave an error: ',
timeout : 'Your request timed out'
},
className: {

4
src/definitions/behaviors/state.js

@ -166,13 +166,13 @@ $.fn.state = function(parameters) {
$module.addClass(className.disabled);
},
enableState: function(state) {
setState: function(state) {
if(module.allows(state)) {
$module.addClass( className[state] );
}
},
disableState: function(state) {
removeState: function(state) {
if(module.allows(state)) {
$module.removeClass( className[state] );
}

223
src/definitions/behaviors/visibility.js

@ -65,7 +65,11 @@ $.fn.visibility = function(parameters) {
module.bindEvents();
module.instantiate();
setTimeout(module.checkVisibility, settings.loadWait);
if(settings.type == 'image') {
module.setup.image();
}
requestAnimationFrame(module.checkVisibility);
},
instantiate: function() {
@ -88,6 +92,7 @@ $.fn.visibility = function(parameters) {
},
bindEvents: function() {
module.verbose('Binding visibility events to scroll and resize');
$window
.on('resize', module.event.refresh)
.on('scroll', module.event.scroll)
@ -99,25 +104,99 @@ $.fn.visibility = function(parameters) {
requestAnimationFrame(module.refresh);
},
scroll: function() {
requestAnimationFrame(module.checkVisibility);
module.verbose('Scroll position changed');
if(settings.throttle) {
clearTimeout(module.timer);
module.timer = setTimeout(module.checkVisibility, 200);
}
else {
requestAnimationFrame(module.checkVisibility);
}
}
},
precache: function(images, callback) {
if (!(images instanceof Array)) {
images = [images];
}
var
imagesLength = images.length,
loadedCounter = 0,
cache = [],
cacheImage = document.createElement('img'),
handleLoad = function() {
loadedCounter++;
if (loadedCounter >= images.length) {
if ($.isFunction(callback)) {
callback();
}
}
}
;
while (imagesLength--) {
cacheImage = document.createElement('img');
cacheImage.onload = handleLoad;
cacheImage.onerror = handleLoad;
cacheImage.src = images[imagesLength];
cache.push(cacheImage);
}
},
setup: {
image: function() {
var
src = $module.data('src')
;
if(src) {
module.verbose('Lazy loading image', src);
settings.once = true;
// show when top visible
module.topVisible(function() {
module.precache(src, function() {
module.set.image(src);
settings.onTopVisible = false;
});
});
}
}
},
set: {
image: function(src) {
var
offScreen = (module.cache.screen.bottom + settings.offset < module.cache.element.top)
;
$module
.attr('src', src)
;
if($.fn.transition !== undefined || offScreen) {
$module.transition(settings.transition, settings.duration);
}
else {
$module.fadeIn(settings.duration);
}
}
},
refresh: function() {
module.debug('Refreshing constants (element width/height)');
module.reset();
module.save.position();
module.checkVisibility();
$.proxy(settings.onRefresh, element)();
},
reset: function() {
module.verbose('Reseting all cached values');
module.cache = {
occurred: {},
screen : {},
element : {}
};
},
checkVisibility: function() {
module.verbose('Updating visibility of element', module.cache.element);
module.verbose('Checking visibility of element', module.cache.element);
module.save.scroll();
module.save.direction();
module.save.screenCalculations();
@ -131,24 +210,6 @@ $.fn.visibility = function(parameters) {
module.bottomPassed();
},
passing: function(newCallback) {
var
calculations = module.get.elementCalculations(),
screen = module.get.screenCalculations(),
callback = newCallback || settings.onPassing
;
if(newCallback) {
module.debug('Adding callback for passing', newCallback);
settings.onPassing = newCallback;
}
if(callback && calculations.passing) {
$.proxy(callback, element)(calculations, screen);
}
else {
return calculations.passing;
}
},
passed: function(amount, newCallback) {
var
calculations = module.get.elementCalculations(),
@ -164,26 +225,54 @@ $.fn.visibility = function(parameters) {
else if(calculations.passing) {
$.each(settings.onPassed, function(amount, callback) {
if(calculations.bottomVisible || calculations.pixelsPassed > module.get.pixelsPassed(amount)) {
callback();
module.execute(callback, amount);
}
else {
module.remove.occurred(callback, amount);
}
});
}
},
passing: function(newCallback) {
var
calculations = module.get.elementCalculations(),
callback = newCallback || settings.onPassing,
callbackName = 'passing'
;
if(newCallback) {
module.debug('Adding callback for passing', newCallback);
settings.onPassing = newCallback;
}
if(callback && calculations.passing) {
module.execute(callback, callbackName);
}
else {
module.remove.occurred(callbackName);
}
if(newCallback !== undefined) {
return calculations.passing;
}
},
topVisible: function(newCallback) {
var
calculations = module.get.elementCalculations(),
screen = module.get.screenCalculations(),
callback = newCallback || settings.onTopVisible
callback = newCallback || settings.onTopVisible,
callbackName = 'topVisible'
;
if(newCallback) {
module.debug('Adding callback for top visible', newCallback);
settings.onTopVisible = newCallback;
}
if(callback && calculations.topVisible) {
$.proxy(callback, element)(calculations, screen);
module.execute(callback, callbackName);
}
else {
module.remove.occurred(callbackName);
}
if(newCallback === undefined) {
return calculations.topVisible;
}
},
@ -191,17 +280,20 @@ $.fn.visibility = function(parameters) {
bottomVisible: function(newCallback) {
var
calculations = module.get.elementCalculations(),
screen = module.get.screenCalculations(),
callback = newCallback || settings.onBottomVisible
callback = newCallback || settings.onBottomVisible,
callbackName = 'bottomVisible'
;
if(newCallback) {
module.debug('Adding callback for bottom visible', newCallback);
settings.onBottomVisible = newCallback;
}
if(callback && calculations.bottomVisible) {
$.proxy(callback, element)(calculations, screen);
module.execute(callback, callbackName);
}
else {
module.remove.occurred(callbackName);
}
if(newCallback === undefined) {
return calculations.bottomVisible;
}
},
@ -209,17 +301,20 @@ $.fn.visibility = function(parameters) {
topPassed: function(newCallback) {
var
calculations = module.get.elementCalculations(),
screen = module.get.screenCalculations(),
callback = newCallback || settings.onTopPassed
callback = newCallback || settings.onTopPassed,
callbackName = 'topPassed'
;
if(newCallback) {
module.debug('Adding callback for top passed', newCallback);
settings.onTopPassed = newCallback;
}
if(callback && calculations.topPassed) {
$.proxy(callback, element)(calculations, screen);
module.execute(callback, callbackName);
}
else {
module.remove.occurred(callbackName);
}
if(newCallback === undefined) {
return calculations.topPassed;
}
},
@ -227,22 +322,56 @@ $.fn.visibility = function(parameters) {
bottomPassed: function(newCallback) {
var
calculations = module.get.elementCalculations(),
screen = module.get.screenCalculations(),
callback = newCallback || settings.onBottomPassed
callback = newCallback || settings.onBottomPassed,
callbackName = 'bottomPassed'
;
if(newCallback) {
module.debug('Adding callback for bottom passed', newCallback);
settings.bottomPassed = newCallback;
}
if(callback && calculations.bottomPassed) {
$.proxy(callback, element)(calculations, screen);
module.execute(callback, callbackName);
}
else {
module.remove.occurred(callbackName);
}
if(newCallback === undefined) {
return calculations.bottomPassed;
}
},
execute: function(callback, callbackName) {
var
calculations = module.get.elementCalculations(),
screen = module.get.screenCalculations()
;
if(settings.once && module.get.occurred(callbackName)) {
// multiple callbacks are ignored when times == 'once'
}
else {
module.debug('Conditions met for callback', callbackName, calculations);
$.proxy(callback, element)(calculations, screen);
}
module.save.occurred(callbackName);
},
remove: {
occurred: function(callback) {
if(callback) {
module.cache.occurred[callback] = false;
}
else {
module.cache.occurred = {};
}
}
},
save: {
occurred: function(callback) {
if(callback) {
module.cache.occurred[callback] = true;
}
},
scroll: function() {
module.cache.scroll = $window.scrollTop() + settings.offset;
},
@ -329,8 +458,8 @@ $.fn.visibility = function(parameters) {
}
module.save.direction();
$.extend(module.cache.screen, {
top : scroll + settings.offset,
bottom : scroll + settings.offset + module.cache.screen.height
top : scroll - settings.offset,
bottom : scroll - settings.offset + module.cache.screen.height
});
return module.cache.screen;
},
@ -356,6 +485,12 @@ $.fn.visibility = function(parameters) {
}
return parseInt(amount, 10);
},
occurred: function(callback) {
return (module.cache.occurred !== undefined)
? module.cache.occurred[callback] || false
: false
;
},
direction: function() {
if(module.cache.direction === undefined) {
module.save.direction();
@ -585,12 +720,17 @@ $.fn.visibility.settings = {
verbose : false,
performance : true,
loadWait : 1000,
watch : true,
offset : 0,
includeMargin : false,
// visibility check delay in ms
throttle : false,
// special visibility type
type : false,
transition : 'fade in',
duration : 500,
// array of callbacks
onPassed : {},
@ -601,10 +741,15 @@ $.fn.visibility.settings = {
onTopPassed : false,
onBottomPassed : false,
once : false,
// utility callbacks
onRefresh : function(){},
onScroll : function(){},
// not used currently waiting for (DOM Mutations API adoption)
// https://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#mutation-observers
watch : true,
watchedProperties : [
'offsetWidth',
'offsetHeight',

64
src/definitions/behaviors/visit.js

@ -47,12 +47,12 @@ $.visit = $.fn.visit = function(parameters) {
module = {
initialize: function() {
if(settings.id) {
module.add.id(settings.id);
}
else if(settings.count) {
if(settings.count) {
module.store(settings.key.count, settings.count);
}
else if(settings.id) {
module.add.id(settings.id);
}
else if(settings.increment && methodInvoked !== 'increment') {
module.increment();
}
@ -61,7 +61,7 @@ $.visit = $.fn.visit = function(parameters) {
},
instantiate: function() {
module.verbose('Storing instance of visit', module);
module.verbose('Storing instance of visit module', module);
instance = module;
$module
.data(moduleNamespace, module)
@ -80,8 +80,8 @@ $.visit = $.fn.visit = function(parameters) {
currentValue = module.get.count(),
newValue = +(currentValue) + 1
;
if(id && module.has.visited(id) ) {
module.debug('Unique content already visited, skipping increment', id);
if(id) {
module.add.id(id);
}
else {
if(newValue > settings.limit && !settings.surpass) {
@ -97,8 +97,8 @@ $.visit = $.fn.visit = function(parameters) {
currentValue = module.get.count(),
newValue = +(currentValue) - 1
;
if(id && !module.has.visited(id) ) {
module.debug('Decrement skipped, content has not been visited', id);
if(id) {
module.remove.id(id);
}
else {
module.debug('Removing visit');
@ -110,14 +110,20 @@ $.visit = $.fn.visit = function(parameters) {
count: function() {
return +(module.retrieve(settings.key.count)) || 0;
},
idCount: function(ids) {
ids = ids || module.get.ids();
return ids.length;
},
ids: function(delimitedIDs) {
var
idArray = []
;
delimitedIDs = delimitedIDs || module.retrieve(settings.key.ids);
if(typeof delimitedIDs === 'string') {
return delimitedIDs.split(settings.delimiter);
}
else {
return [];
idArray = delimitedIDs.split(settings.delimiter);
}
module.verbose('Found visited ID list', idArray);
return idArray;
},
storageOptions: function(data) {
var
@ -137,7 +143,6 @@ $.visit = $.fn.visit = function(parameters) {
},
has: {
visited: function(id, ids) {
var
visited = false
@ -152,7 +157,6 @@ $.visit = $.fn.visit = function(parameters) {
}
return visited;
}
},
set: {
@ -178,16 +182,16 @@ $.visit = $.fn.visit = function(parameters) {
: currentIDs + settings.delimiter + id
;
if( module.has.visited(id) ) {
module.debug('Unique content already visited, not adding visit', id);
module.debug('Unique content already visited, not adding visit', id, currentIDs);
}
else if(id === undefined) {
module.debug('ID is not defined');
}
else {
module.debug('Adding visit to unique content', id);
module.increment(id);
module.store(settings.key.ids, newIDs);
}
module.set.count( module.get.idCount() );
},
display: function(selector) {
var
@ -200,7 +204,6 @@ $.visit = $.fn.visit = function(parameters) {
: $element
;
}
module.update.display();
}
},
@ -220,6 +223,22 @@ $.visit = $.fn.visit = function(parameters) {
newIDs = newIDs.join(settings.delimiter);
module.store(settings.key.ids, newIDs );
}
module.set.count( module.get.idCount() );
}
},
check: {
limit: function(value) {
value = value || module.get.count();
if(value >= settings.limit) {
module.debug('Pages viewed exceeded limit, firing callback', value, settings.limit);
$.proxy(settings.onLimit, this)(value);
}
else if(settings.limit) {
module.debug('Limit not reached', value, settings.limit);
}
$.proxy(settings.onChange, this)(value);
module.update.display(value);
}
},
@ -230,11 +249,6 @@ $.visit = $.fn.visit = function(parameters) {
module.debug('Updating displayed view count', $displays);
$displays.html(value);
}
if(value >= settings.limit) {
module.debug('Pages viewed exceeded limit, firing callback', value, settings.limit);
$.proxy(settings.onLimit, this)(value);
}
$.proxy(settings.onChange, this)(value);
}
},
@ -255,7 +269,7 @@ $.visit = $.fn.visit = function(parameters) {
return;
}
if(key == settings.key.count) {
module.update.display(value);
module.check.limit(value);
}
},
retrieve: function(key, value) {
@ -468,7 +482,7 @@ $.fn.visit.settings = {
namespace : 'visit',
increment : true,
increment : false,
surpass : false,
count : false,
limit : false,

Loading…
Cancel
Save