diff --git a/DOCS.md b/DOCS.md index 0228d39..3931b3f 100644 --- a/DOCS.md +++ b/DOCS.md @@ -119,7 +119,8 @@ groucho.config = { ] } ``` -To write your own features, grab browsing history and work with it like this... + +To write your own features, grab browsing history and work with it. You'll need to use a little structure to define the condition, in this case: the name of the tracking group... ```javascript $.each(groucho.getActivities('browsing'), function (key, record) { @@ -270,45 +271,65 @@ var favCategoryTerms = groucho.getFavoriteTerms('*', false, 7); You can register your own tracking activities like this... ```javascript -// Track your own activities. -$('.my-special-links').bind('click', function (e) { - myObj.linkText = $(this).text() - myObj.myProperty = $(this).attr('data-property'); - groucho.createActivity('my_activity', myObj); +$('.videos a.play').bind('click', function() { + groucho.createActivity('watch', { + 'videoId' : $(this).data('videoId'), + 'category' : $(this).data('category'), + 'videoTitle' : $(this).text() + }); }); ``` -They will be stored as key/value in jStorage. But can be returned as an array, filtered down to the group specified. +They will be stored as key/value in jStorage. But can be returned as an array, filtered down to the group specified. Remember to structure the condition. ```javascript -var myActivities = groucho.getActivities('my_activity'); +var myActivities = groucho.getActivities('watch'); ``` + ```json [{ - "_key" : "track.my_activity.398649600", - "linkText" : "Link text from page", - "myProperty" : "the-property-value" + "_key" : "track.watch.398649600", + "videoId" : 456, + "category" : "tutorial", + "videoTitle" : "Learn About Something" }, { - "_key" : "track.my_activity.398649999", - "linkText" : "Other link text", - "myProperty" : "this-property-value" + "_key" : "track.watch.398649999", + "videoId" : 789, + "category" : "fun", + "videoTitle" : "Be Entertained" }] ``` -You can work directly with tracking activites and create your own smart functions... +You can work directly with tracking activites and create your own smart functions. This example finds tutorial videos watched in the last week... + ```javascript -function myActivitySmarts () { - var myActivities = groucho.getActivities('my_activity'), - record; - - for (i in myActivities) { - record = myActivities[i]; - if (myComparison(record.property, record.url, record._key.split('.')[2])) { - count++; +function recentVideos(timeframe, category) { + var conditions = [{'type' : [category]}], + activityList = groucho.getActivities('watch', conditions), + now = new Date().getTime(), + recentList = [], + timestamp; + + for (var i in activityList) { + timestamp = activityList[i]._key.split('.')[2]); + if (timestamp > (now - timeframe)) { + recentList.push({ + 'videoTitle' : activityList[i].videoTitle, + 'url' : activityList[i].url + }); } } - return count; + + return recentList; } + +$.each(recentVideos(604800, 'tutorial'), function() { + newItem = '
  • ' + this.videoTitle + '
  • '; + $('ul.recentlyWatched').append(newItem); +}); ``` +_...but you shouldn't insert HTML this way._ + + ### Local Storage This library uses in-browser key/value localStorage with the convenient jStorage abstraction library. If you're new to localStorage, it's no big deal and is a new tool we should all be using. diff --git a/README.md b/README.md index e726074..c58df65 100644 --- a/README.md +++ b/README.md @@ -100,11 +100,11 @@ if (groucho.favoriteTerms.hasOwnProperty(taxonomy)) { ### Pageview Tracking Use page view activity tracking to dig through history and alter UX. - ```javascript var history = groucho.getActivities('browsing'), links = $('a.promoted'), count = 0; + for (var i in history) { // Determine if they've seen a page with a specific property. if (history[i].hasOwnProperty('myProperty') count++; @@ -114,37 +114,32 @@ if (count < 2) links.addClass('featured'); else if (count >= 2 && count < 7) links.addClass('reduced'); else links.addClass('hidden'); ``` -Show the last viewed item of a given type. Example is last watched video... - -```javascript -var history = groucho.getActivities('watch'); -if (history.length) { - $.get("videos.json?id=" + history[0].videoId, function(data) { - $('.recent').html(displayVideo(data)); - }); -} -``` ## Custom Activies Register your own tracking activities like this... +```javascript +$('.videos a.play').bind('click', function() { + groucho.createActivity('watch', {'videoId' : 789}); +}); +``` +Retrieve activities later to personalize pages. Example swaps in the last watched video... ```javascript -// Track your own activities. -$('.my-special-links').bind('click', function (e) { - groucho.createActivity('my_activity', { - 'linkText' : $(this).text(), - 'myProperty' : $(this).attr('data-property') +var history = groucho.getActivities('watch'); + +if (history.length) { + $.get("videos.json?id=" + history[0].videoId, function(data) { + $('.recent').find('.title').text(data.title) + .find('.graphic').text(data.graphic) + .find('a').attr('href', data.url); }); -}); -// Later... -myActivites = groucho.getActivities('my_activity'); +} ``` ### Basic User Info Wait for data availability and user basic user info. - ```javascript (function ($) { $(document).ready(function(){ diff --git a/groucho.json b/groucho.json index 02bd53b..f93f572 100644 --- a/groucho.json +++ b/groucho.json @@ -2,7 +2,7 @@ "name": "groucho", "title": "Groucho", "description": "Know more about your anonymous users. In-browser storage tracking tool.", - "version": "0.2.1", + "version": "0.3.0", "homepage": "https://github.com/tableau-mkt/groucho", "author": { "name": "Josh Lind", diff --git a/src/groucho.js b/src/groucho.js index da90ea9..bd15afd 100644 --- a/src/groucho.js +++ b/src/groucho.js @@ -117,35 +117,106 @@ var groucho = window.groucho || {}; * Access records of a specific tracking group. * * @param {string} group - * Name of the tracking group to return values for. + * Strucutured conditions for activity lookup: {type, [conditionList]}. + * @param {array} conditions + * List of acceptable property [key/[values]] objects. * * return {array} * List of tracking localStorage entries. */ - groucho.getActivities = function getActivities(group) { + groucho.getActivities = function getActivities(type, conditionList) { - var results = $.jStorage.index(), + // Optional params. + var group = type || false, + conditions = conditionList || false, + groupMatch = new RegExp("^track." + group + ".", "g"), + results = $.jStorage.index(), returnVals = [], - matchable = new RegExp("^track." + group + ".", "g"), record; + /** + * Confirm properties are of desired values. + * NOTE: String comparisons only! + * + * @param {array} conditions + * List of acceptable property [key/[values]] objects. + * @param {string} record + * History record to check against. + * + * @return {boolean} + * Result of match check. + */ + function checkProperties(conditions, record) { + // Check all conditions, be picky about type. + if (conditions && conditions instanceof Array) { + for (var i in conditions) { + // Confirm an acceptable value. + if (checkValues(i, conditions[i], record)) { + addRecord(record); + } + + } + } + else { + // No conditions, or wrong type-- add everything. + addRecord(record); + } + } + + /** + * Confirm one of values matches the record. + * NOTE: String comparisons only! + * + * @param {string} property + * Property to check. + * @param {array} values + * List of acceptable values. + * @param {string} record + * History record to check against. + * + * @return {boolean} + * Result of match check. + */ + function checkValues(property, values, record) { + // Check all values, be picky about type. + if (values instanceof Array) { + for (var i in values) { + // Confirm an acceptable value. + if (record.hasOwnProperty(property) && record.property === values[i]) { + addRecord(record); + // Only need one match per value set. + break; + } + } + } + } + + /** + * Grab record from storage, add to returns. + * + * @param string key + * Browser storage lookup key. + */ + function addRecord(key) { + record = $.jStorage.get(key); + // Move key to special property. + record._key = key; + returnVals.push(record); + } + + + // Look through storage index. for (var i in results) { // Remove unwanted types and return records. if (group) { - if (results[i].match(matchable) !== null) { - // Collect relevant. - record = $.jStorage.get(results[i]); - // Move key to property. - record._key = results[i]; - returnVals.push(record); + if (results[i].match(groupMatch) !== null) { + // Move on to checking conditions (potentially just add it). + checkProperties(conditions, results[i]); } } else { - // Collect and return all. - record = $.jStorage.get(results[i]); - // Move key to property. - record._key = results[i]; - returnVals.push(record); + // Just check property or just add. + checkProperties(conditions, results[i]); } } diff --git a/test/groucho_test.js b/test/groucho_test.js index b008719..3f2782f 100644 --- a/test/groucho_test.js +++ b/test/groucho_test.js @@ -127,7 +127,7 @@ timeout = i * 150; stop(); setTimeout(function () { - groucho.createActivity('fake_thing', fakeData); + groucho.createActivity('fake_thing', fakeData); start(); }, timeout); } @@ -158,6 +158,119 @@ }); + //@todo Confirm granular activity request work. + test('Activity retrieval', 0, function() { + + // Mock functions. + var counters = { + 'checkProperties': 0, + 'checkValues': 0, + 'addRecord': 0 + }; + groucho.getActivities.checkProperties = function() { + counters[this.name]++ + }; + groucho.getActivities.checkValues = function() { + counters[this.name]++ + }; + groucho.getActivities.addRecord = function() { + counters[this.name]++ + }; + + // Create activities! + groucho.createActivity('testThingy', { + 'neato' : 'definately', + 'yep' : 'probably' + }); + groucho.createActivity('testStuff', { + 'neato' : 'definately', + 'yep' : 'probably' + }); + groucho.createActivity('testThingy', { + 'neato' : 'unclear' + }); + groucho.createActivity('testThingy', { + 'wow' : 'indeed', + 'yep' : 'probably' + }); + + // Tests... + groucho.getActivities('testThingy'); + + groucho.getActivities('testStuff'); + + groucho.getActivities('testThingy', [ + {'neato' : ['definately']} + ]); + + groucho.getActivities('testThingy', [ + {'neato' : ['definately', 'unclear']} + ]); + + groucho.getActivities('testThingy', [ + {'neato' : ['definately']}, + {'wow' : ['indeed']} + ]); + + groucho.createActivity('testStuff', [ + {'neato' : ['unclear']}, + {'neato' : ['definately']} + ]); + + + + +/* + + groucho.getActivities(); + + groucho.getActivities('fake_thing'); + + groucho.getActivities('wrong'); + + groucho.getActivities( + 'fake_thing', + [{'entityBundle'}] + }); + + groucho.getActivities({ + 'fake_thing', + [{'entityBundle' : 'article'}] + }); + + groucho.getActivities({ + 'fake_thing', + [{entityBundle' : ['article']}] + }); + + groucho.getActivities({ + 'fake_thing', + [{'entityBundle' : ['wrong', 'article']}} + }); + + groucho.getActivities({ + 'fake_thing', + ['entityBundle' : ['wrong']}] + }); + + groucho.getActivities({ + 'fake_thing', + [ + {entityBundle' : ['article']}, + {entityBundle' : ['article']} + ] + }); + + groucho.getActivities({ + 'fake_thing', + [ + {entityBundle' : ['article']}, + {entityBundle' : ['profile', 'blog']} + ] + }); +*/ + + }); module('Favorites');