Tag Archives for javascript

Filipe Bessa – portfolio site

2018

www.filipebessa.com/

Custom responsive wordpress theme developed too allow director to upload and categorize videos of his work, which automatically populate gallery views.

08. May 2020 by admin
Tags: , , , , , | Comments Off on Filipe Bessa – portfolio site

SPARK Mobile App Contest

Q1 2016 – Q4 2018

Responsibilities: HTML CSS/SASS JS/jQuery PHP/MySQL AWS

Traditional wordpress site, I built a custom theme based off llorix. SPARK for Autism needed an accompanying website for the duration of the contest to handle contest registration, announcements, and community app voting. I worked on this during my time as an internal dev at the Simons Foundation.

Notable tasks: I opted for a kanban approach to development given that feature development needed to occur around events and announcements that comprised the contest. For registration I connected a CF7 form template to a Googlesheet, such that as users registered, their data would be entered into the spreadsheet, which was shared with stakeholders so they would always be up-to-date without me spending time on plebian tasks like pulling reports. Students were asked to register themselves and their teammates by entering their emails and setting a team password. Teammates would receive an invite email, as all participants had to register in order to be eligible for prize money. To set up voting I started with a general star-voting plugin, added some authentication which hit the SPARK api to determine voting status and access privileges, and modified the JS and PHP according to aesthetic/functional specifications.

05. February 2019 by admin
Tags: , , , , , , , | Comments Off on SPARK Mobile App Contest

Spectrum News

Q1 2016 – Q4 2018

Responsibilities: HTML CSS/SASS JS/jQuery PHP/MySQL AWS

Traditional wordpress site, with custom theme built by Madwell. I inherited the task of maintenance, bugfixes, new feature implementation during my time as an internal dev at the Simons Foundation.

Notable tasks: Migrating the site off WP Engine and onto AWS. Getting a team new to Agile to adopt a loosely SCRUM process. Shaving about .1 seconds from the pageload DB query duration with a 30% reduction in DB calls by converting some massive reqs to ajax calls when needed and replacing wp methods with cached vars where applicable.

05. February 2019 by admin
Tags: , , , , , , , , , | Comments Off on Spectrum News

Simons Foundation

Q1 2016 – Q4 2018

Responsibilities: HTML CSS/SASS JS/jQuery PHP/MySQL AWS

I inherited the task of maintenance, bugfixes, and new feature implementation during my time as an internal dev at the Simons Foundation. The bugs and tech debt that the initial vendor delivered with the project was a painful reminder of why waterfall development should be avoided at all costs.

Notable tasks: Getting a team new to Agile to adopt a SCRUM process running on 2-week sprints. Diving deeper in MySQL procedures to handle migrations of the alien information schema handed off to us. Migrating an Unfuddle ticket project to our Jira account in a jungle of chunked spreadsheets, field-remapping, and consolidation scripts to preserve ticket comment history. Migrating ACF field schema out of the PHP into which it had been distilled to prevent alteration by non-developer WP admins, back into the DB. Running a strategy-mapping workshop with the team to identify strategic solutions to obstacles (I am forever grateful to Rob Purdie from whom I learned this method). Writing a plugin that works with the arxiv.org api to provide a tool for helping content editors to sync arxiv’s publications authored by foundation scientists with our wordpress publications archive. Restructuring hundreds of daisy-chained SASS files into a more sane and manageable schema.

05. February 2019 by admin
Tags: , , , , , , , , | Comments Off on Simons Foundation

html5 banners, various clients

2016

html/css/js, animation with Greensock libraries.

replay

replay

replay

19. February 2016 by admin
Tags: , , , , , | Leave a comment

Crossborders – custom cms with flash front-end

2009
crossborders.tv (now rain)
website/custom cms

PHP/MySQL backend w/custom DB, XML output for interpretation by flash front-end, Brightcove for video service, though the client insisted on implementing Brightcove in a way tha bypassed the API’s and was never intended (oh if I had a nickel…).

23. June 2014 by admin
Tags: , , , , , , , , , | Leave a comment

custom javascript gallery

2005
javascript image gallery

This drove my site for a long time, and I still prefer the UX and implementation in many ways compared to most of the out-of-the-box gallery plugins I see around, save for the somewhat tedious admin aspect due to it’s entirely front-end nature. Would be nice as a WP plugin, though it would require an entire re-write to get up-to-date.

DOWNLOAD SRC

This is a simplified version of the .HTML containing only the elements that are affected by or required by the functions. galleryFunctions.js and paintings.js are sourced in the tag. The function drawGallery(start, end) is called within the after the necessary DOM elements. Because the script requires a start & end variable it’s possible to break 1 array up into various sections of thumbnails.

<html>

<head>
<title>gallery</title>
<script language=”javascript” src=”../scripts/galleryFunctions.js”></script>
<script language=”javascript” src=”../scripts/paintings.js”></script>

</head>

<body bgcolor=”#ffffff”>

<img src=”images/placeholder.gif” name=”mainImage” border=”0″>

<table><tr>
<td align=”left”>
<span id=”captionLeft” class=”generalText”></span></td>
<td align=”right”>
<span id=”captionRight” class=”generalText”></span></td>
<td align=”left”>
<a onmouseover=”arrowOn(‘Left’)” onmouseout=”arrowOff(‘Left’)” href=”#”>
<img src=”images/arrowLeftGray.gif” alt=”” name=”arrowLeft” height=”18″ width=”9″ border=”0″></a></td>
<td align=”right”>
<a onmouseover=”arrowOn(‘Right’)” onmouseout=”arrowOff(‘Right’)” href=”#”>
<img src=”images/arrowRightGray.gif” alt=”” name=”arrowRight” height=”18″ width=”9″ border=”0″></a></td></tr></table>

<span id=”moreInfo”></span>

<script type=”text/javascript”>loadFirstImage();</script>

<br><br><br>
<span class=”thumbnailArea”>
GALLERY SECTION 1<br>
<script type=”text/javascript”>drawGallery(0,3);</script><br><br>
</span>
</body>

</html>


This is the content of “galleryFunctions.js.”, which contains the drawGallery(); functions.

//ursula’s javascript gallery! source: www.ursart.com.
//free to be modified or shared however u like, but not sold

//determine the initial gallery content & arrow links
function loadFirstImage(){
document.mainImage.src = imgDirectory + images[0] + “.jpg”;
document.getElementById(“captionLeft”).innerHTML = textLeft[0];
document.getElementById(“captionRight”).innerHTML = textRight[0];
document.getElementById(“moreInfo”).innerHTML = additionalText[0];

document.arrowLeft.onclick = function leftArrowLink1(){
changeImage(images[images.length – 1])
}

document.arrowRight.onclick = function rightArrowLink1(){
changeImage(images[1])
}

//check to see if we should get rid of the outline
for (j = 0; j<imagesNoOutline.length; j++){
if (imagesNoOutline[j] == images[0])
break;
}
if (imagesNoOutline[j] == images[0]){
document.mainImage.style.color = “#ffffff”;
} else {
document.mainImage.style.color = “#a9a9a9”;
}
}

// make the thumbnail gallery!
function drawGallery(start,stop){
for (g=start; g<stop; g++){
thumbnail = “<a href=’#’ onClick = ‘changeImage(\””
thumbnail += images[g]
thumbnail += “\”)’>”;

//check to see if the thumbnail is in the no outline array
for (h = 0; h<imagesNoOutline.length; h++){
if (imagesNoOutline[h] == images[g])
break;
}
// determine the thumbnail style
if (images[g] == imagesNoOutline[h]){
thumbnail += “<img class=’galHoverWht galleryThumbnail’ src='”
} else {
thumbnail += “<img class=’galHoverGry galleryThumbnail’ src='”
}

thumbnail += imgDirectory
thumbnail += images[g]
thumbnail += “_sm.jpg’>”;
thumbnail += “</a>”;

document.write(thumbnail);
}
}


//change the content
function changeImage(newImage) {
for (i = 0; i<images.length; i++){
if (images[i] == newImage)
break;
}

document.mainImage.src = imgDirectory + newImage + “.jpg”;
document.getElementById(“captionLeft”).innerHTML = textLeft[i];
document.getElementById(“captionRight”).innerHTML = textRight[i];
document.getElementById(“moreInfo”).innerHTML = additionalText[i];

//change the left arrow link
if (i == 0){
previousImage = images[images.length – 1];
} else {
previousImage = images[i – 1];
}
document.arrowLeft.onclick = function leftArrowLink2(){
changeImage(previousImage);
}

//change the right arrow link
if (i == images.length – 1){
nextImage = images[0];
} else {
nextImage = images[i + 1];
}
document.arrowRight.onclick = function rightArrowLink2(){
changeImage(nextImage);
}

//check to see if we should get rid of the outline
if (imagesNoOutline){
for (j = 0; j<imagesNoOutline.length; j++){
if (imagesNoOutline[j] == newImage)
break;
}
if (imagesNoOutline[j] == newImage){
document.mainImage.style.color = “#ffffff”;
} else {
document.mainImage.style.color = “#a9a9a9”;
}
}

}



Each gallery page then loads a .js file defining the arrays into which you insert all the content for each item in your gallery. In this case, the “paintings.js.” file

images = new Array();
textLeft = new Array();
textRight = new Array();
additionalText = new Array();

images[0] = “maxAndMichael”;
textLeft[0] = “<i>Max &amp; Michael</i><br>oil on linen, 80 x 50 cm”;
textRight[0] = “2005”;
additionalText[0] = “”;

images[1] = “whoreMadonna1”;
textLeft[1] = “<i>Whore Madonna 1</i><br>oil on canvas, 110 x 174 cm”;
textRight[1] = “2006”;
additionalText[1] = “”;

images[2] = “bananaSplit”;
textLeft[2] = “<i>Banana Split</i><br>oil on canvas, 122 x 162 cm”;
textRight[2] = “2005”;
additionalText[2] = “”;

imagesNoOutline = new Array();
imagesNoOutline[0] = “maxAndMichael”;
imagesNoOutline[1] = “whoreMadonna1”;

imgDirectory = “images/paintings/”;

23. June 2014 by admin
Tags: , , | Leave a comment

Brightcove videoplayer accessibility plugin

Q2 2014
Javascript/Actionscript solution to Brightcove player accessibility problems

DOWNLOAD SRC

When I wrote this, Brightcove did have an “Accessible” template – which was not even remotely accessible. Accessible means I should be able to navigate the web page/application with my eyes closed, using only the keyboard, and access the same content in as smooth and efficient an experience as a visually-equipped user.

This solution isn’t perfect – I still received complaints from users about tab-accessibility inconsistency and video control button labels not changing on toggle, which I couldn’t control without access to the video src. Ultimately, we decided to move off of Brightcove as a video solution, but if you’re stuck with it, this will help significantly.

Tabbing into and out of Flash objects embedded on an HTML page is a common problem — if you can’t tab into an embedded application, it doesn’t exist to any user using a screenreader. The solution I stitched together uses a Class from Adobe to setup the tab ordering of clickable elements within the swf, in combination with some javascript by Richard England to handle focus into and out of the swf.

1. Create the swf that will become your custom Brightcove plugin. This is an empty .swf which, upon being added to the stage, will explore the heirarchy of the swf into which is has been imported, find the video controls, will pass those to the SWFFocus class. Below isthe Document class of your .fla.

package {
	import com.adobe.swffocus.SWFFocus;

	import flash.accessibility.AccessibilityProperties;
	import flash.accessibility.Accessibility;
	import flash.display.Sprite;
	import flash.events.Event;
//	import com.richardengland.utils.Tabbing;
	import flash.display.DisplayObjectContainer;
	import flash.display.DisplayObject;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;


	public class SWFFocusFix extends Sprite {
		public function SWFFocusFix() {
			if (stage) {
				init();
			} else {
				addEventListener(Event.ADDED_TO_STAGE, init);
			}
		}

		private function init(event:Event = null):void {
			trace("SWFFocusFix.init");

			var player:Object = parent;
			var counter:Number = 0;

			var buttonContainer:Object;

			while (player.parent) {
				for (var i:uint = 0; i < player.numChildren; i++) {
					var child:DisplayObject = player.getChildAt(i);
					var childClass = getQualifiedClassName(child);

					if (childClass.indexOf("BEMLContainer") != -1) {
						//then this is where we want the tabbing focus to be
						buttonContainer = child;
					}

				}

				player = player.parent;
				counter++;

				if (buttonContainer) {
					break;
				}
			}

			traceDisplayList(DisplayObjectContainer(player));

			if (player) {
				trace("Found player.stage! | " + player.stage);
				if (player.stage) {
					if (hasEventListener(Event.ADDED_TO_STAGE)) {
						removeEventListener(Event.ADDED_TO_STAGE, init);
					}
					/*
					if (buttonContainer) {
					var tabbing = new Tabbing(DisplayObjectContainer(buttonContainer));
					}
					*/
					if (buttonContainer) {
						
							SWFFocus.init(buttonContainer.stage);
					}
				}
			} else {
				if (stage) {
					trace("Using local stage.");
					SWFFocus.init(stage);
				}
			}
		}

		private function traceDisplayList(container:DisplayObjectContainer, indentString:String = ""):void {
			var child:DisplayObject;
			for (var i:uint=0; i < container.numChildren; i++) {
				child = container.getChildAt(i);
				if (child.accessibilityProperties) {
					trace(child.accessibilityProperties.name, child.accessibilityProperties.description );
				}
				trace(indentString, child, child.name);


				if (container.getChildAt(i) is DisplayObjectContainer) {
					traceDisplayList(DisplayObjectContainer(child), indentString + "    ");
				}
				
				
				var childClass = getQualifiedClassName(child);
				//adjustment for the closedCaptions BG
				//if (child.name == "instance137" && childClass.indexOf("GlowingButton") != -1) {
					if (childClass.indexOf("GlowingButton") != -1){
						if (getQualifiedClassName(child.parent.parent.parent).indexOf("CaptionControls") != -1){
							trace("******* removed child " + child.name);
							//child.parent.removeChild(child);
							child.alpha = 0;
							
						}
				}

			}
		}

	}
}
Read More →

16. July 2014 by admin
Tags: , , , , , | Leave a comment

animated twitterfeed js class

2011
Atmosphere BBDO
conference ipad app/site

Javascript class that pulls tweets from the twitter api based on a search term, populates a carousel with results. jQuery used for animation. Unfortunately, it’s about as reliable as Twitter, which, as I’m writing this, isn’t that reliable, so there are times the api just wont’ return any results. CD requested that I hide the first tweet and then reveal upon page load with a delay so it has an ‘active’ feel to it.

DOWNLOAD SRC


This can be implemented using a script node where you want the carousel to appear in your html page:
 <script type="text/javascript">
                               
                                var twitter_test = new TwitterFeed();
                                twitter_test.search("anything", 4,"orange");
                        
                        </script>


Here’s the class:
function TwitterFeed(){
    
    this.searchPrefix = "http://search.twitter.com/search.json?q=";
    this.searchTerm = "";
    this.maxTweetRetrieve = 5;
    this.tweetData = null;
    this.itemHeight = 0;
    this.linkClass = "#000000";
    this.maxTweets = 10;
    this.displayTweets = [];
    
    // how often do you want to get the tweets? (seconds)
    this.updateInterval = 5;
    
    // the latest tweet is hidden initially. How many seconds after loading do you
    // want it to appear?
    this.initialAnimDelay = 1;
    this.firstrun = true;
    this.getTweetsInt = null;
    this.animInterval = .1;
    this.checkInterval;
    this.intervalSet = false;
    this.maxAttempts = 5;
    this.attemptDelay = 1.5;
    this.attempts = 0;

    this.setupComplete = false;

    this.failCopy = "Sorry, Twitter appears to be down:-(";
    this.progressCopy = "Retrieving Twitter Feed...";
    
    this.carouselHolderIdPrefix = "carouselholder_";
    this.carouselIdPrefix = "carousel_";
    
    this.query = "";

}

TwitterFeed.prototype.search = function(_term, _maxDisplay, _linkClass){
    // alert("search");
    if (!this.setupComplete) {
        this.searchTerm = _term;
        this.displayTweets = _maxDisplay;
        this.linkClass = _linkClass;              
        this.maxTweets = _maxDisplay + 1;
        this.linkColor = _linkClass;
         
        var _html = "<div id='"+this.carouselHolderIdPrefix + _term + "' class='tcarousel-holder'><div id='"+this.carouselIdPrefix + _term + "' class='tcarousel'></div></div>";
        document.write(_html);
        
        this.setupComplete = true;
    }

    var _query = this.searchPrefix + _term + "&callback=?&rpp=" + this.maxTweets;
    var self = this;
    $(document).ready(function() {
        jQuery.getJSON(_query, function(data) {
            self.callback(data);
        });
    });
}

TwitterFeed.prototype.callback = function(_tweets){
    
    if (_tweets.results.length > 0) {
                
        var _totalTweets = _tweets.results.length;
        var _results = _tweets.results;
        this.tweetData = [];
       
        for (i = 0; i < _totalTweets; i++) {
            var _data = this.parseResult(_results[i]);
            this.tweetData.push(_data);
            this.addResult(_data.string);
        }
        
        this.itemHeight = Math.ceil(document.getElementById(this.carouselIdPrefix + this.searchTerm).offsetHeight / _results.length);
        document.getElementById(this.carouselHolderIdPrefix+ this.searchTerm).style.height = this.itemHeight * this.displayTweets + "px";
        this.drawList(this.tweetData, 1);

    } else {
        if (!this.intervalSet) {
            this.intervalSet = true;
            // alert("intervalSet: " + intervalSet);
            this.checkInterval = setInterval("reattempt()", this.attemptDelay * 1000);
            this.emptyDisplay(this.progressCopy);
        }
    } 
}

TwitterFeed.prototype.reattempt = function() {

    this.attempts++;
    if (this.attempts < this.maxAttempts) {
        this.search(this.searchTerm, null, null);
    } else {
        window.clearInterval(this.checkInterval);
        this.emptyDisplay(this.failCopy);
    }
}


TwitterFeed.prototype.emptyDisplay = function(_copy) {
        
    var _holder = document.getElementById(this.carouselHolderIdPrefix+ this.searchTerm);
    var _footer = document.getElementById("thefooter");

    _holder.innerHTML = "<div class='tcarousel-item invisible'>" + _copy + "</div>";
    _holder.style.marginTop = "0px";
    _holder.style.height = "auto";

    var _windowHeight = (typeof window.innerHeight != 'undefined' ? window.innerHeight : document.body.offsetHeight);

    _holder.style.height = (_windowHeight - findPosY(_holder) - 112) + "px";

}


TwitterFeed.prototype.parseResult = function(_obj) {

    var _message = this.parseLink(_obj.text);
    _message = this.parseHash(_message);

    var _user = _obj.from_user;
    var _created = _obj.created_at.replace(/(\+\d*\s)/g, "");

    var _date = new Date(_created);
    var _newDateString = this.relativeTime(_date);

    var _id = _obj.id;
    var _string = "<div class='tcarousel-item class='invisible''>" + _message + "<div class='tweet-extras'>" + _user + " <span class='time'>(" + _newDateString + ")</span></div></div>";


    // now put it all into a model
    var _dataObject = new Object();
    _dataObject.originalObject = _obj;
    _dataObject.message = _message;
    _dataObject.user = _user;
    _dataObject.id = _id;
    _dataObject.dateOriginal = _obj._date;
    _dataObject.dateString = _newDateString;
    _dataObject.string = _string;

        
    return _dataObject;
}

TwitterFeed.prototype.drawList = function(_data, _numAdded) {
    
    var _feed = document.getElementById(this.carouselIdPrefix + this.searchTerm);
       
    _feed.innerHTML = "loading...";
   
    var _margin = -this.itemHeight * _numAdded;
    _feed.style.marginTop = _margin + "px";
    
    for (i = 0; i < _data.length; i++) {
        this.addResult(_data[i].string);
    }
   
    if (this.firstrun == false) {
        this.bringToTop();
        for (i = 0; i < _numAdded; i++) {
            this.tweetData.pop();
        }
    } else { 
        
        this.firstrun = false;
        this.initTimers();
        var _self = this;
        setTimeout(function(){
            _self.bringToTop();
        }, this.initialAnimDelay * 1000);
    }
}

TwitterFeed.prototype.initialReveal = function() {
    bringToTop();
}

TwitterFeed.prototype.bringToTop = function() {
    $('#'+this.carouselIdPrefix + this.searchTerm).animate( {
        marginTop : '0px'
    });
    
}

TwitterFeed.prototype.addResult = function(_string) {
    var _feed = document.getElementById(this.carouselIdPrefix + this.searchTerm);
       
    if ( _feed.innerHTML == "loading..."){
        _feed.innerHTML = "";
    };
    
    _feed.innerHTML += _string;

}

TwitterFeed.prototype.parseLink = function(_s) {
    return _s.replace(/((https?|s?ftp|ssh)\:\/\/[^"\s\<\>]*[^.,;'">\:\s\<\>\)\]\!])/g, function(url) {
        return "<a href='" + url + "' >" + url + "</a>";
    });
}

TwitterFeed.prototype.parseHash = function(_s) {
     
    var _new = _s.replace("#" + this.searchTerm, "<a href='http://twitter.com/search?q=%23" + this.searchTerm + "' class='" + this.linkClass + "' target='_blank'>#" + this.searchTerm + "</a>");
    return _new;
}

TwitterFeed.prototype.K = function() {
    var a = navigator.userAgent;
    return {
        ie : a.match(/MSIE\s([^;]*)/)
    };
}

TwitterFeed.prototype.relativeTime = function(a) {
    var b = new Date();
    var c = new Date(a);
    /*
         * if (navigator.userAgent.match(/MSIE\s([^;]*)/)) { c =
         * Date.parse(a.replace(/( \+)/, ' UTC$1')) }
         */
         
    if (this.K.ie) {
        c = Date.parse(a.replace(/( \+)/, ' UTC$1'));
    }
       
    var d = b - c;
    var e = 1000;
    var minute = e * 60;
    var hour = minute * 60;
    var day = hour * 24;
    var week = day * 7;
        
        
    if (isNaN(d) || d < 0) {
        return "";
    }
       
    if (d < e * 7) {
        return "right now";
    }
    if (d < minute) {
        return Math.floor(d / e) + " seconds ago";
    }
    if (d < minute * 2) {
        return "about 1 minute ago";
    }
    if (d < hour) {
        return Math.floor(d / minute) + " minutes ago";
    }
    if (d < hour * 2) {
        return "about 1 hour ago";
    }
    if (d < day) {
        return Math.floor(d / hour) + " hours ago";
    }
    if (d > day && d < day * 2) {
        return "yesterday";
    }
    if (d < day * 365) {
        return Math.floor(d / day) + " days ago";
    } else {
        return "over a year ago";
    }
      
};

TwitterFeed.prototype.initTimers = function() {
    if (!this.getTweetsInt) {
        var _self = this;
        this.getTweetsInt = setInterval(function(){
            _self.getTweets();
        }, this.updateInterval * 1000);
    }
   
}

TwitterFeed.prototype.getTweets = function() {
    // alert("getTweets " + this)
    
    var _query = this.searchPrefix + this.searchTerm + "&callback=?&rpp=" + this.maxTweetRetrieve;
   
    // alert("_query: " + _query) 
    var _self = this;
    $(document).ready(function() {
        jQuery.getJSON(_query, function(data) {
            _self.callback2(data);
        });
    });
}

TwitterFeed.prototype.callback2 = function(_twitter) {
    //alert("callback2 " + this)
    var _totalNew = 0;

    for (i = _twitter.results.length - 1; i >= 0; i--) {
        var _data = this.parseResult(_twitter.results[i]);
        var _exists = false;

        for (j = 0; j < this.tweetData.length; j++) {
            if (this.tweetData[j].id == _data.id) {
                _exists = true;
            }

            // need to update the relative time for all tweets
            var _updatedData = this.parseResult(this.tweetData[j].originalObject);
            this.tweetData[j] = _updatedData;
        }
                
        if (!_exists) {
            this.tweetData.unshift(_data);
            _totalNew++;
        }

    }
    this.drawList(this.tweetData, _totalNew);
}

TwitterFeed.prototype.bind = function(scope) {
    var _function = this;
  
    return function() {
        return _function.apply(scope, arguments);
    }
}

TwitterFeed.prototype.findPosX = function(obj) {
    var curleft = 0;
    if (obj.offsetParent)
        while (1) {
            curleft += obj.offsetLeft;
            if (!obj.offsetParent)
                break;
            obj = obj.offsetParent;
        }
    else if (obj.x)
        curleft += obj.x;
    return curleft;
}

TwitterFeed.prototype.findPosY = function(obj) {
    var curtop = 0;
    if (obj.offsetParent)
        while (1) {
            curtop += obj.offsetTop;
            if (!obj.offsetParent)
                break;
            obj = obj.offsetParent;
        }
    else if (obj.y)
        curtop += obj.y;
    return curtop;
}

27. March 2013 by admin
Tags: , , , , , | Leave a comment

animated web banner in html5

2010
[No client]

OH, Advertising. What can I say, banners are still bread and butter at a lot of places, though even now (years after I wrote this banner) it seems we haven’t really gotten away from Flash as the primary IDE. No jQuery here (which makes the total load less than 20K), just intervals with calculated easing, and an event class to handle execution upon the doc becoming ready. Background is Canvas, copy is divs, cta is a png. This is where I found out you can’t layer multiple canvas divs on top of each other and expect what you are undoubtedly expecting.

Click here to find out more.

23. June 2014 by admin
Tags: , , , , , , | Leave a comment

THINK Academy – IBM

Think Academy is a desktop and mobile MOOC application written in HTML/CSS/JS, using IBM Connections’ social API and Brightcove video. Monthly topic deployments to the global IBM community make it highly agile project Read more here.

Role: HTML/CSS/JS, PHP/MySQL, Grunt, Brightcove video, Dotsub closed captions, Accessibility standards




23. June 2014 by admin
Tags: , , , , , , , , , , , , , , , | Leave a comment

THINK Exchange – IBM

think-exchange.com is IBM’s members-only community, events program and content portal for C-level executives. It began with THINK Marketing for CMO’s and has expanded to include Finance and Technology.

Responsive site using PHP/MySQL, HTML/CSS/JS, WordPress, Buddypress, Media element.

23. June 2014 by admin
Tags: , , , , , , , , , , , , , | Leave a comment

AT&T Network Transformation microsite

2011
AT&T Network Transformation
Atmosphere BBDO
Microsite: PHP/HTML/CSS/JS. JWPlayer serving up mp4/flv video depending on flash detection.

23. June 2014 by admin
Tags: , , , , | Leave a comment

I need SPACE: browsing FTP host by directory size

2013

DOWNLOAD SRC

I recently needed to free up some diskspace on my webhost, which sounds simple enough, unless you’re like me and your filesystem looks like a hoarder’s reality show. After unsuccessfully poking around for navigation tools that display directory size and allow sorting by size so I could quickly identify the heaviest culprits, I wrote this utility. See de-fanged demo below.

Feel free to let me know of bugs you find, developed on firefox 17.0.1 and so far tests ok on chrome 24.0.1312.52, safari 6.0, IE 8.

Click on the “+” to expand a directory within this view. Click on the directory name to jump to viewing contents of only that directory. Click on “Size” to sort the list by file size, Click on “Name” to sort by name.

Session login default is user ‘me’ password ‘mypass123’ (See ‘Settings’ line 37 to change… it is highly recommended that you change these), authentication times out after 30 minutes.

Installation:
1. change settings to a unique username and pass
2. upload i_need_space.php to your host (yup, just one file).
3. navigate to it via browser
4. when finished with your cleanup, delete i_need_space.php from your host, you don’t want someone stumbling on it and wreaking havoc.

27. March 2013 by admin
Tags: , , , , , | Leave a comment

bouncing ball in canvas

2010
non-flash banner testing (no client)


Frames created with an illustrator blend, exported to SVG, then converted to canvas. professorcloud.com has a really awesome little utility for converting SVG’s to canvas. Doesn’t handle gradients all that well, as you can tell by the shadow. Output changes with mouseover or mousedown on the ball (if you can catch it;).

23. June 2014 by admin
Tags: , , , , | Leave a comment