Tag Archives for css
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.
html5 banners, various clients
2016html/css/js, animation with Greensock libraries.
replay
replay
replay
Crossborders – custom cms with flash front-end
2009crossborders.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…).
custom javascript gallery
2005javascript image gallery
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.
<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.
//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
textLeft = new Array();
textRight = new Array();
additionalText = new Array();
images[0] = “maxAndMichael”;
textLeft[0] = “<i>Max & 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/”;
flash & CSS paragraph spacing
I still can’t believe margin-top and margin-bottom aren’t supported, but whatever. Here’s a hack.DOWNLOAD SRC
How it works:
The method you’ll need to modify is setCSS(_css : StyleSheet); For each paragraph style in your XML, call setLineSpacing(_pTag : String, _pSpacing : Number = 0), passing the opening tag of your xml paragraph, and the amount of space, in points, you want above it. The actionscript runs through your xml and prepends a <spacer> tag with fontSize styled to the points specified.
MyTextField.as
package com {
import flash.text.AntiAliasType;
import flash.text.StyleSheet;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
public class MyTextField extends TextField {
private var initCopy : String;
private var modifiedCopy : String;
private var tags : Array;
public function MyTextField(_s : String, _w : Number = 0, _h : Number = 0) {
//trace(‘MyTextField: ‘ + (s));
initCopy = _s;
modifiedCopy = (_s);
if(_w) {
width = _w;
wordWrap = true;
}
if(_h) {
height = _h;
wordWrap = true;
}
antiAliasType = AntiAliasType.ADVANCED;
selectable = false;
autoSize = TextFieldAutoSize.LEFT;
embedFonts = true;
multiline = true;
htmlText = _s;
mouseEnabled = false;
//border = true;
}
override public function setTextFormat(_format : TextFormat, _beginIndex : int = -1, _endIndex : int = -1) : void {
//trace(‘setTextFormat: ‘ + (format.font));
if(_format.italic && !embedFonts) {
htmlText = text + ” “;
}
super.setTextFormat(_format, _beginIndex, _endIndex);
defaultTextFormat = _format;
}
public function setCSS(_css : StyleSheet) : void {
styleSheet = _css;
setLineSpacing(“<pa>”, 5);
setLineSpacing(“<pa class=\”style1\”>”, 10);
setLineSpacing(“<pa class=\”style2\”>”, 20);
htmlText = modifiedCopy;
}
private function setLineSpacing(_pTag : String, _pSpacing : Number = 0) : void {
if (!tags) {
tags = [];
}
tags.push(_pTag);
var _copyElem : Array = modifiedCopy.split(_pTag);
var _newCopy : String;
if (!styleSheet) {
styleSheet = new StyleSheet;
}
var _spacerID:String = “spacer” + tags.length;
var _sTag : String = (“<“ + _spacerID + “> </” + _spacerID + “>” + _pTag);
_newCopy = _copyElem.join(_sTag);
styleSheet.setStyle(_spacerID, {fontSize:String(_pSpacing + “px”), fontFamily:“Arial”});
modifiedCopy = _newCopy;
}
public function shrinkToFit(_w : Number) : void {
while(width > _w) {
scaleX -= 0.1;
scaleY = scaleX;
}
}
public function truncate(_maxWidth : Number = 200, _maxLines : Number = 1, _ellipsis : Boolean = false) : String {
multiline = true;
wordWrap = true;
width = _maxWidth;
//for some reason it does not work unless width gets (evaluated)… weird!
width = (width);
var _newCopy : String = (htmlText);
while(numLines > _maxLines) {
_newCopy = _newCopy.slice(0, _newCopy.length – 2);
htmlText = _newCopy;
setTextFormat(getTextFormat());
}
if (_ellipsis) {
_newCopy = _newCopy.slice(0, _newCopy.length – 3);
_newCopy += “…”;
htmlText = _newCopy;
setTextFormat(getTextFormat());
}
return _newCopy;
}
public function toTitleCase() : String {
var _words : Array = text.split(” “);
for (var i : int = 0;i < _words.length; i++) {
var _word : String = _words[i];
var _newWord : String = _word.charAt(0).toUpperCase() + _word.substr(1, _word.length – 1).toLowerCase();
_words[i] = _newWord;
}
text = _words.join(” “);
setTextFormat(getTextFormat());
return (text);
}
}
}
<?xml version=“1.0” encoding=“UTF-8”?>
<content>
<page><![CDATA[
<pa>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam malesuada elit nec elit luctus aliquam. Nullam a purus ante, quis feugiat leo. Vivamus a quam suscipit tellus vehicula posuere at eu augue.</pa>
<pa class=”style1″>Suspendisse varius fermentum tellus, pharetra luctus velit imperdiet id. Vestibulum fermentum, lorem a facilisis fringilla, turpis est aliquam massa, vel accumsan urna augue vel orci.</pa>
<pa class=”style2″><span class=”ital”>Curabitur tellus quam</span>, pretium vitae commodo quis, ultricies ut velit. Praesent id quam non ante bibendum mattis. Aenean ut sem vitae arcu tincidunt dapibus at at arcu.</pa>
<pa>Integer ut erat nulla, placerat blandit quam. Vivamus id molestie ligula.</pa>
<pa>Curabitur tellus quam, pretium vitae commodo quis, ultricies ut velit. Praesent id quam non ante bibendum mattis. Aenean ut sem vitae arcu tincidunt dapibus at at arcu.</pa>
<pa class=”style2″><span class=”strong”>Fusce scelerisque </span><br/>turpis ac mauris sodales id dignissim enim lobortis. Sed aliquet, ligula non laoreet adipiscing, velit quam placerat quam, sit amet ultrices massa ante nec augue.</pa>
]]>
</page>
</content>
animated twitterfeed js class
2011Atmosphere 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; }
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.
REPLAY
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.
AT&T Network Transformation microsite
2011AT&T Network Transformation
Atmosphere BBDO
Microsite: PHP/HTML/CSS/JS. JWPlayer serving up mp4/flv video depending on flash detection.
kim dane painting portfolio
2012www.kimdane.com
Wordpress framework, custom theme. HTML/CS/JS/PHP/MySQL
To get the main menu to break into user-determined rows, added a DB field for ‘line_break_after’ to the wp posts table, and altered the ‘My Page Order’ plugin to allow user to insert linebreaks where desired. Also a few Walker methods to the WP framework to grab this field and put in the appropriate linebreaks.
Custom JS Effect for the NextGen gallery to populate the scrollable thumbnail menu and incorporate deeplinking using swfAddress.
Social was also interesting. Buttons for FB, Twitter & Google+ pulled in w/JS. Discovered that JS content and FB Like do NOT play nice, mostly due to FB Like API ignoring JS and scraping the page for metatags when posting. So instead of telling FB to just share the page url, had to stitch together a url from the swfaddress deeplink such that it got passed in as a GET variable and the header.php could react appriopriately to return the appropriate metatags. It’s a shame that one should have to choose between smoothly swapping content around clientside and the keeping sharing simple & effective.