Image carousel – update

In a previous post, I wrote about creating an image carousel using basic web tech: HTML, CSS, and vanilla JavaScript. No frameworks, no jQuery. This is an update to that. The major difference is that it supports multiple carousels on the same page. I also added a try/catch, in case no carousel data is found in the database. I recently used this implementation on a WordPress site. Each carousel was a post (of a custom carousel post-type), that had each image attached. On that post-type archive page, I looped through the posts, and created a separate carousel for each.

Here is the updated JavaScript.

try{
    var galleries = document.getElementsByClassName("carousel-class");
    for(var i = 0; i < galleries.length; i++){
        showGalleries(galleries.item(i), 0);    
    }
}catch(e){
    console.log(e);
}

function showGalleries(gallery, galleryIndex){
    var galleryDots = gallery.getElementsByClassName("dot-button");
    var gallerySlides = gallery.getElementsByClassName("my-slide");
    if (galleryIndex < 0){galleryIndex = gallerySlides.length-1}
    galleryIndex++;
    for(var ii = 0; ii < gallerySlides.length; ii++){ gallerySlides[ii].style.display = "none"; galleryDots[ii].classList.remove('active-dot'); } if (galleryIndex > gallerySlides.length){galleryIndex = 1}
    gallerySlides[galleryIndex-1].style.display = "block";
    var resizeEvent = new Event('resize');
    window.dispatchEvent(resizeEvent);
    galleryDots[galleryIndex-1].classList.add('active-dot');
    //hide gallery navigation, if there is only 1
    if(gallerySlides.length < 2){
        var dotContainer = gallery.getElementsByClassName("dots");
        var arrowContainer = gallery.getElementsByClassName("gallery-arrows");
        dotContainer[0].style.display = "none";
        arrowContainer[0].style.display = "none";
    }
    gallery.setAttribute("data", galleryIndex);
}

//gallery dots
document.addEventListener('click', function (event) {
    if (!event.target.matches('.carousel-class .dot-button')){ return; }
    var index = event.target.getAttribute("data"); 
    var parentGallery = event.target.closest(".carousel-class")
    showGalleries(parentGallery, index);

}, false);

//gallery arrows

//left arrow
document.addEventListener('click', function (event) {
    if (!event.target.matches('.fa-arrow-left')){ return; }
    var parentGallery = event.target.closest(".carousel-class")
    var galleryIndex = parentGallery.getAttribute("data");
    galleryIndex = galleryIndex - 2;
    
    showGalleries(parentGallery, galleryIndex);
}, false);

//right arrow
document.addEventListener('click', function (event) {
    if (!event.target.matches('.fa-arrow-right')){ return; }
    var parentGallery = event.target.closest(".carousel-class")
    var galleryIndex = parentGallery.getAttribute("data");

    showGalleries(parentGallery, galleryIndex);
}, false);

You’ll notice that each carousel section has a data attribute assigned, so our JS knows which one to affect. This version also includes left and right navigation arrows, in addition to the navigation dots we already had.

HTML:

<div class="ap-carousel" data="0">

<?php $num_slides = 0; foreach($posts as $post){ $num_slides++; ?>

	<div class="ap-slide">
		<a href="<?php the_permalink($post->ID); ?>" title="<?php the_title(); ?>">
			<img src="<?php echo esc_url(get_the_post_thumbnail_url($post->ID)); ?>" class="zoom">
		</a>
	</div>

<?php } ?>
<div class="nav-dots">
	<?php $active = "active-dot"; for($x = 0; $x < $num_slides; $x++){ ?>
		<div class="dot"><button data="<?php echo $x; ?>" type="button" class="dot-button <?php echo $active; $active = ''; ?>">b</button></div>
	<?php } ?>
</div>
<div class="gallery-arrows">
    <i class="fas fa-arrow-left"></i>
    <i class="fas fa-arrow-right"></i>
</div>


</div>

Easy image carousel

On a recent project, I needed a simple image carousel on the homepage. And then, on the gallery page I needed a fully polished solution. Sometimes, using a framework is the right choice. Others, a fully built out toolkit can be overkill.

The Vanilla Option

First, here is the home-rolled version that I came up with. It was integrated into a custom WordPress template. I loop through a set of posts within my carousel wrapper, creating a slide div with that record’s featured image. I keep track of how many slides get built. Beneath the carousel wrapper I create a navigation div, and build a dot button for each slide. Each dot gets an index assigned to it, saved to its button’s data attribute.

HTML:


<div class="ap-carousel">

<?php $num_slides = 0; foreach($posts as $post){ $num_slides++; ?>

	<div class="ap-slide">
		<a href="<?php the_permalink($post->ID); ?>" title="<?php the_title(); ?>">
			<img src="<?php echo esc_url(get_the_post_thumbnail_url($post->ID)); ?>" class="zoom">
		</a>
	</div>

<?php } ?>
<div class="nav-dots">
	<?php $active = "active-dot"; for($x = 0; $x < $num_slides; $x++){ ?>
		<div class="dot"><button data="<?php echo $x; ?>" type="button" class="dot-button <?php echo $active; $active = ''; ?>">b</button></div>
	<?php } ?>
</div>


</div>

CSS:

I used CSS animation to create a fade effect between slides. I position the navigation dots using CSS flexbox layout.

.ap-carousel{
	position: relative;
}
.ap-slide{
	display: none;
	margin: 0 auto;
}	 
.ap-slide img{
	width: auto;
	display: block;
	margin: 0 auto;
	max-height: 90vh;
	-webkit-animation-name: fade;
	-webkit-animation-duration: 1.5s;
	animation-name: fade;
	animation-duration: 1.5s;
}
@-webkit-keyframes fade {
	from {opacity: .4} 
	to {opacity: 1}
}
@keyframes fade {
	from {opacity: .4} 
	to {opacity: 1}
}
.nav-dots{
	display: flex;
	justify-content: center;
}
.dot button{
	display: block;
	border-radius: 100%;
	width: 12px;
	height: 12px;
	margin-right: 10px;
	padding: 0;
	border: none;
	text-indent: -9999px;
	background: black;
	cursor: pointer;
}
.dot button.active-dot{
	background: red;
}

JavaScript:

Finally, I create a JS function to change the slide and active dot based on a timer. I attach an event listener to the dots that will change the active slide based on the saved index data.

var slideIndex = 0;
showSlides();

function showSlides() {
	var i;
	var slides = document.getElementsByClassName("ap-slide");
	var dots = document.getElementsByClassName("dot-button");
	for (i = 0; i < slides.length; i++) { slides[i].style.display = "none"; dots[i].classList.remove("active-dot"); } slideIndex++; if (slideIndex > slides.length) {slideIndex = 1} 
	slides[slideIndex-1].style.display = "block"; 
	dots[slideIndex-1].classList.add("active-dot")
	setTimeout(showSlides, 5000); // Change image every 5 seconds
}

document.addEventListener('click', function(event){
	if(!event.target.matches('.dot-button')) return;

	slideIndex = event.target.getAttribute("data");
	showSlides();
}, false);

That’s a simple and lite solution. It worked fine for the homepage of this recent project, but the main gallery page needed something more complex. I choose Galleria, a JavaScript framework.

The Framework Option

I implemented this option onto the WordPress category archive page. For this project, each piece of artwork is its own post. In my category template file I loop through posts, and populate a JSON object with the data about each slide. Initially, I had built HTML elements for each slide, but that caused slow page load times. The JSON data option is significantly faster. Here’s what my code setup looked like:

<div id="galleria"></div>
<script type="text/javascript">
	window.galleryData = [];
</script>
<?php if (have_posts()): while (have_posts()) : the_post(); 

$featured_img_url = get_the_post_thumbnail_url(); 

?>

<script>
window.galleryData.push({ image: "<?php echo esc_url($featured_img_url); ?>", artinfo: "<div class='galleria-img-info'><h3 class='title'><a href='<?php the_permalink(); ?>'><?php the_title(); ?></a></h3><?php $size=get_post_meta(get_the_ID(), 'size', true);$size=addslashes($size);$date=get_post_meta(get_the_ID(), 'date', true);$materials=get_post_meta(get_the_ID(), 'materials', true);if(! empty ( $size ) ){echo '<p><strong>Dimensions:</strong> ' . $size . '</p>';}if(! empty ( $date ) ){echo '<p><strong>Date:</strong> ' . $date . '</p>';}if(! empty ( $materials ) ){echo '<p><strong>Materials:</strong> ' . $materials . '</p>';} ?><p class='you-can-mouse'>You can click the image to enlarge it. </p></div></div>" })
</script>

<?php } ?>

<script src="/galleria/galleria-1.5.7.js"></script>
<script type="text/javascript">
// Load the classic theme
Galleria.loadTheme('/galleria/galleria.classic.min.js');
//https://docs.galleria.io/collection/25-options
Galleria.configure({
    imageCrop: false,
    transitionSpeed:1000,
    maxScaleRatio:1,
    swipe:true,
    thumbnails: 'none',
    transition: 'fade',
    lightbox: true
});
// Initialize Galleria
Galleria.run('#galleria', {dataSource: window.galleryData, autoplay: 5000, extend: function() {
            // var gallery = this; // "this" is the gallery instance
            // gallery.play(); // call the play method
        }
});

Galleria.ready(function() {
        	
	$(".loading").hide();
		this.bind('image', function(e) {
	});

});
 </script>

Easy hamburger (menu) recipe

I think it’s best to avoid using plug-ins when possible. It reduces bloat and “black-box” code.

The mobile “hamburger” menu is a staple of responsive user interface design. Users know that clicking on that three-lined icon will show a menu. It’s a modern solution to displaying long navigation lists on smaller screens.

A "hamburger" menu is a button (usually in the corner of a screen) that toggles a menu or list of hyperlinks.

Below is a simple rendition using basic web technology. I used this recently as part of  a website that showcases the work of a graphic artist.

mobile menu example

HTML:

Drop this code in your header file for the menu (list of links) itself.

<div class="mobile-menu">
	<span class="close-mobile-menu"><i class="far fa-times-circle"></i></span>

	<ul>
			 
			<li><a href="/biography">Biography</a></li>
			<li><a href="/education">Education & Awards</a></li>
			<li><a href="/reviews?order=asc">Reviews</a></li>
			<li><a href="/etchings">Etchings</a></li>
			<li><a href="/category/paintings/1960s/">Paintings</a></li>
			<li><a href="/mukfa-about">Mukfa</a></li>
			<li><a href="/category/drawings/human-comedy/">Drawings</a></li>
			<li><a href="/exhibitions-and-collections">Exhibitions & Collections</a></li>
			 
	</ul>

</div>

Next, add this to your existing navigation, or wherever you’d like the hamburger button to show.

<div class="mobile-hamburger mobile-only"><i class="fas fa-bars"></i></div>

I used FontAwesome to generate the hamburger icon itself (and the close icon). Alternatively, you can use an image file.

hamburger menu

CSS:

This code sets the hamburger button to only show on mobile devices. Mobile devices are specified at 787px or less by a media query.

.mobile-hamburger{
	font-size: 36px;
	color: #005FAA;
	float: right;
	cursor: pointer;
	margin-right: 16px;
	margin-top: 5px;

}
.mobile-menu{
	display: none;
	width: 100%;
	background: #DCC7AA;
	position: fixed;
	height: 100%;
	right: 0;
	top: 0;
	z-index: 20;
}
.mobile-menu ul{
	list-style-type: none;
	font-size: 16px;
	text-align: left;
	padding: 25px;
	margin: 50px 0px;
}

.mobile-menu ul li{
	margin-top: 15px;
}

.close-mobile-menu{
	position: absolute;
	top: 5px;
	right: 16px;
	font-size: 36px;
	cursor: pointer;
}

@media only screen and (min-width:787px) {
	.mobile-only{display: none;}
}

JavaScript:

With jQuery:

(function ($, root, undefined) {
	
	$(function () {
		
		'use strict';
		
		// DOM ready, take it away
		$(".mobile-hamburger").click(function(){
			$(".mobile-menu").show();
		});

		$(".close-mobile-menu").click(function(){
			$(".mobile-menu").hide();
		});

		 
		
	});
	
})(jQuery, this);

Or, plain vanilla JS:

document.addEventListener('click', function (event) {

	if (!event.target.matches('.mobile-hamburger')){
		return;
	}

	document.getElementsByClassName('mobile-menu')[0].style.display = 'block';

}, false);

document.addEventListener('click', function (event) {

	if (!event.target.matches('.close-mobile-menu')){
		return;
	}

	document.getElementsByClassName('mobile-menu')[0].style.display = 'none';	

}, false);

 


By the way, this is the tool I’ve been using to encode the HTML I paste into my WordPress posts (that way, it doesn’t actually render on page): https://github.com/mathiasbynens/mothereff.in/tree/master/html-entities

html entities encoded and decoded

Develop apps and explore the world (wide web)

I love building software. Writing code is a way to craft experiences that other people can interact with and enjoy. My favorite platform to build for is the world wide web. When I first started programming, I was building for Windows desktop computers. It was mostly utilities and games, and I really didn’t know how to distribute them. The web had always been a place to find information, and even download software, but websites were essentially documents, with little functionality. Now, they can have the full breadth of interactivity that native applications enjoy. Having moved into the age of mobile software, being able to build for the web has many advantages.

The web, as a platform, is open and free. Unlike native app markets, you don’t have to wait for your software to be approved by any third-party. It works across any device or operating system that has a web browser. (Which is why standards across browsers is so important). But, until recently web-apps faced limitations. Not having full access to a device’s hardware and operating system was an issue – but that’s being fixed as more native APIs are being added to modern web browsers.

In my experience, the big disadvantage of having a web-only app was losing out on the discoverability that comes with having it listed in a searchable marketplace. Also, adding a web-app to your device home screen is not intuitive to average users. As of recent, the Google Play market allows you list your web-app for users to install. The process involves uploading an Android app file (.apk), with the settings configured to target your web-app. It uses a new feature called “Trusted Web Activity” to achieve this, along with “Digital Asset Links“.

I decided to try this out with one of my web-apps, BJJ Tracker. You can read about how I first built it on another blog post. First, I wanted to enhance the experience by making UI/UX upgrades. I recreated the logo, focusing on typography. I also added a textured background to the app’s main view.  I sped things up by removing unused code assets. I even made some updates to help with accessibility (that is, compatibility with screen readers for the visually impaired).

bjj tracker

Next, I wanted to make sure my app had offline support, as well as any other features that would make it “feel” like a native app. Google Chrome’s developer tools as a section called “audit” that helped me identify such opportunities.

progressive web app audit

The first step was to create a “service worker” JavaScript file, and register it when BJJ Tracker loads. This file downloads any vital assets to a user’s device, and later loads them from the cache.

if('serviceWorker' in navigator) {
  navigator.serviceWorker
           .register('/serviceWorker.js')
           .then(function() { console.log("Service Worker Registered"); })
           .catch(error => {
	        	console.log(error.message)
	    	})
}

Here is an example service worker file:

 importScripts('/cache-polyfill.js');


self.addEventListener('install', function(e) {
 e.waitUntil(
   caches.open('bjjtracker').then(function(cache) {
    return cache.addAll([
       '/',
       '/index',
       '/index?login',
       '/create-record?class',
       '/create-record',
       '/create-record?competition',
       '/view-record',
       '/view-month',
       '/privacy-policy',
       '/contact',
       '/view-more-data',
       '/account',
       '/css/bootstrap.min.css',
       '/css/bootstrap.min.css',
       '/css/bootstrap-theme.min.css',
       '/css/main.css',
       '/simpleMobileMenu/styles/jquery-simple-mobilemenu.css',
       'https://use.fontawesome.com/releases/v5.3.1/css/all.css',
       'https://fonts.googleapis.com/css?family=Roboto|Eczar&display=swap',
       'https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js',
        
        
     ]);
    }).catch(error => {
        console.log(error.message)
    })
 );
});

self.addEventListener('fetch', function(event) {

	// console.log(event.request.url);

	event.respondWith(

		caches.match(event.request).then(function(response) {

			return response || fetch(event.request);

		}).catch(error => {
	        console.log(error.message)
	    })

	);

});

You can read more from the documentation: https://developers.google.com/web/ilt/pwa/caching-files-with-service-worker

Next, I created a “manifest” file. This file is written in JSON format. It helps describe how the web-app behaves once “installed”. It handles things such as app icon images and splash screens.

{
  "name": "BJJ Tracker",
  "lang": "en-US",
  "short_name": "BJJ Tracker",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#2a4d69",
  "theme_color": "#2a4d69",
  "description": "Track Brazilian Jiu Jitsu progress and fitness goals.",
  "icons": [{
    "src": "img/homescreen48.png",
    "sizes": "48x48",
    "type": "image/png"
  }, {
    "src": "img/homescreen72.png",
    "sizes": "72x72",
    "type": "image/png"
  }, {
    "src": "img/homescreen96.png",
    "sizes": "96x96",
    "type": "image/png"
  }, {
    "src": "img/homescreen144.png",
    "sizes": "144x144",
    "type": "image/png"
  }, {
    "src": "img/homescreen168.png",
    "sizes": "168x168",
    "type": "image/png"
  }, {
    "src": "img/homescreen192.png",
    "sizes": "192x192",
    "type": "image/png"
  }, {
    "src": "img/homescreen512.png",
    "sizes": "512x512",
    "type": "image/png"
  }]
}

Ok, now I was ready to open Android Studio and generate a .apk file, that I can upload to Google Play. Check out this example from Google Chrome Labs: https://github.com/GoogleChromeLabs/svgomg-twa/. You can clone that repository, and update the “build.gradle” settings to point to your app. You’ll also need to upload an “assetlinks.json” file to your web app’s host to satisfy the Digital Asset Links protocol.

Finally, I headed over to the Google Play Console. Besides uploading the .apk file, I also needed to include screenshots, featured image files, and complete a content rating survey – amongst other things. Now, my app is “pending publication”.

bjj tracker app

This app is a fun side project I use to toy with new web technologies. I’m trying to drive traffic to it so that I can experiment with optimizing conversions. I’m using it as a trial grounds for another software service called SplitWit. SplitWit is focused on optimizing conversions for the web, and helping digital marketers reach their goals. You can read about it on another post from this blog.

Split testing and marketing optimization

In digital business, driving conversions (getting users to do what you want them to do) is a science. And there are plenty of tools out there that can help. Experimenting should be a constant exercise in this respect. Take any discipline, anything competitive, or life in general and you’ll find benefit in testing the waters and adjusting your sail. Our ability to interpret that data is the bottle neck to making profitable decisions. The best lesson I’ve learned is that intuition is usually not enough. We’re better looking at the numbers and trusting data instead.

Over the years, I’ve used various marketing software for automation and optimization. The overall goal has always been to influence users through a funnel of action, finally leading to a “conversion”. Fundamentally, it’s a lever for persuasion and influence. I’ve been working on a product that focuses on this point. Optimizing conversions, sales, and leads can be broken down into a system based approach. That’s what SplitWit aims to achieve. It is a “software as a service” platform that helps you to split test your website. That means it allows you to make changes to your website, that only half of your visitors will see, and then determines which version leads to better results (be that sales, sign-ups, etc.) Through each campaign, you’ll see an increase in performance.

Here, I’ll highlight some features and talk through its development.

Registration engine and basic template

As a starting point, I used a template to quickly get things prototyped and working. I’ve made a few enhancements to this base code while building SplitWit. I will eventually merge those updates into the template repository – which I’ll highlight in another article.

The front-end design utilizes basic principles that focus on user experience. I iterated through various color pallets, and ended with a blue-shaded scheme. Subtle textured patterns applied to background sections help add a finished look. And of course, FontAwesome is my go-to icon set.

Code-wise, some dependencies include Bootstrap 4, jQuery Simple MobileMenu, and Google Fonts. An awesome CSS technique that I used for the first time was to set the main container of each page to have a minimum height of 100% of the viewport. This ensures that the page footer doesn’t end up in the middle of the screen if there is not enough content.

.main-content.container{
  min-height: 100vh;
}

Visual optimizer and editor

This part was fun to build. After setting up an account, you can create experiments that target certain pages of your website. The visual optimizer lets you make changes easily between the control and variation versions.

visual editor

The editor loads up your website as an iFrame on the right side of the page. Once your page is loaded, SplitWit adds an overlay to the iFrame. This way, instead of interacting with the page, your clicks can be intercepted. Any elements that you click on get loaded up as HTML into the “make a change” section of the editor. Any changes you make get saved to that variation, and will be displayed to half of your visitors.

Here is an example of the code that powers the overlay and connects it to the editor:

pageIframe.contents().find("body").prepend(overlay);
 
pageIframe.contents().find("body *").css("z-index", 1).mouseenter(function(){

  $(this).addClass('highlighted'); 

  testSelectorEl = $(this);
  

}).mouseout(function(){

  $(this).removeClass('highlighted');   

}).click(function(e){

  e.preventDefault();
  var value = testSelectorEl.getPath()
  selectNewElement(value);
  //scroll user to selector input
  $([document.documentElement, document.body]).animate({
    scrollTop: $(".page-editor-info").offset().top
  }, 1000);

});

The editor has lots of built in options, so you can change the style and behavior of your page without needing to know how to code. A marketer can use this tool without the help of a developer – which is clutch!

Metrics and statistical significance

A key feature of SplitWit is to measure conversion metrics and performance indicators. The platform determines which variation is a winner based on the metrics you set. Three types of metrics are offered: page views, click events, and custom API calls.

Algorithms calculate statistical significance based on the number of visitors an experiment receives and the conversion metrics configured. This makes sure that the result is very unlikely to have occurred coincidently.

The code snippet

Each project setup in SplitWit generates a code snippet. Once this snippet is added to a website, SplitWit is able to do its magic. Using JavaScript, it applies variation changes, splits user traffic between versions, and measures key metrics about the experiments running.

The platform uses a relational database structure, powered by MySQL. As you make changes to your experiments, the details are saved and written to your unique snippet file. When the snippet file loads, the first thing is does is check to see if there are any experiments that should be running on the current page. Each experiment can be configured to run on various URLs. The configuration rules contain three parts: a URL pattern, a type (target or exclude), and a match type (exact, basic, or substring). You can read SplitWit documentation to find an explanation of these match types.

experiment settings

Here is the code used to test a URL against an experiment’s configuration rules:

function testUrl(testurl, conditions){
			
	if(testurl.search(/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/) < 0){
		return window.inputError($(".test-url-input"), "Please test a valid URL.");
	}
	var valid = false;
	var arr  = [],
	keys = Object.keys(conditions);

	for(var i=0,n=keys.length;i<n;i++){
		var key  = keys[i];
		arr[i] = conditions[key];
	}

	conditions = arr;
	for (i = 0; i < arr.length; i++) { 
		var url = conditions[i].url;
		var matchtype = conditions[i].matchtype;
		var conditiontype = conditions[i].conditiontype;

		if(matchtype == "exact" && conditiontype == "target" && url == testurl){
			valid = true;
		}
		if(matchtype == "exact" && conditiontype == "exclude" && url == testurl){
			valid = false;
		}

		if(matchtype == "basic"){
			var cleanTestUrl = testurl.toLowerCase();
			var cleanUrl = url.toLowerCase();

			if(cleanTestUrl.indexOf("?") > 0) {
				cleanTestUrl = cleanTestUrl.substring(0, cleanTestUrl.indexOf("?"));
			}
			if(cleanUrl.indexOf("?") > 0) {
				cleanUrl = cleanUrl.substring(0, cleanUrl.indexOf("?"));
			}
			if(cleanTestUrl.indexOf("&") > 0) {
				cleanTestUrl = cleanTestUrl.substring(0, cleanTestUrl.indexOf("&"));
			}
			if(cleanUrl.indexOf("&") > 0) {
				cleanUrl = cleanUrl.substring(0, cleanUrl.indexOf("&"));
			}
			if(cleanTestUrl.indexOf("#") > 0) {
				cleanTestUrl = cleanTestUrl.substring(0, cleanTestUrl.indexOf("#"));
			}
			if(cleanUrl.indexOf("#") > 0) {
				cleanUrl = cleanUrl.substring(0, cleanUrl.indexOf("#"));
			}
			cleanTestUrl = cleanTestUrl.replace(/^(?:https?:\/\/)?(?:www\.)?/i, "");
			cleanUrl = cleanUrl.replace(/^(?:https?:\/\/)?(?:www\.)?/i, "");
			cleanTestUrl = cleanTestUrl.replace(/\/$/, "");
			cleanUrl = cleanUrl.replace(/\/$/, ""); 

			if(conditiontype == "target" && cleanUrl == cleanTestUrl){
				valid = true;
			}
			if(conditiontype == "exclude" && cleanUrl == cleanTestUrl){
				valid = false;
			}

		}
		if(matchtype == "substring"){
			if(testurl.includes(url) && conditiontype == "target"){
				valid = true;
			}
			if(testurl.includes(url) && conditiontype == "exclude"){
				valid = false;
			}
		} 
	}
	
	return valid;

}


A/B split testing

Conducting experiments with the goal of optimizing a metric is a powerful tool, and yields a large return on the time and money you invest in to it. The SplitWit platform can help digital goals come to fruition in short time. As new features are rolled out, I’ll continue posting updates deep diving into how things work behind the scenes. Follow @SplitWit for regular updates.

www.SplitWit.com

Building digital products

When writing about digital problem solving, I tell stories about past projects. On top of a tech perspective, I also dig into the business, design, marketing, and inter-personal aspects. I’ve been fortunate enough to have a wide breadth of tech experience through my career. It has helped me dive deep into principles and ideas about building digital products. This range of experience was afforded by continually pursuing new work. Finding room for side projects and extra gigs is a great way to grow.

After a daily, hour-long commute I could barely sneak an hour or two for my creative projects and side gigs. But I always did. Side projects were often for paying clients, but sometimes just for fun. They would include not just programming, but also design, marketing, networking, and infrastructure. On top of this, I always made sure my hobbies would serve my overall goals. Reading good books, playing quality games, and being physically competitive all lead to a better life and career.

The key take-away is to work on a variety of projects. Be ready to try different technologies and new platforms. In general, keep trying new things.

Understand infrastructure. Survive some horror stories.

Web infrastructure and hosting setup are skills often missed out on by both casual programmers and professionals. Configuring domain names, email, web hosting, and load balancers is usually reserved for system administrators. Working as one-stop-shop, on your own or in a company, can give you the opportunity to manage all of these details.

I’ve gotten to work with many third-party services and vendors. I’ve seen the good and the bad, and even worse. AWS (Amazon Web Services) has been the best infrastructure provider that I have used. I’ve had horrible experiences from other companies.

Once having had my web servers infected by ransom-ware, HostGator wanted to charge nearly a thousand dollars, to solve the problem. This was the only solution they offered while multiple web properties were infected and out of commission. I fixed the issue myself in less than a few hours by purging all data from the servers and redeploying source code from version control. That was a nightmare.

Another time servers provided by OLM went down for multiple days. This was in 2014. During this time, they wouldn’t answer telephones, letting them ring. I stood on hold for at least 30 minutes, multiple times per day trying to get through. After nearly a week, things started working again, with no explanation provided. That was one of the most unprofessional experiences of my career. I will forever shout them out about this.

Get your hands dirty

Looking forward, I’m excited to explore more of AWS. I’m currently learning through online courses from Udemy: “Certified Solutions Architect” and “Certified Developer”, and plan to take the certification tests. Next, I want to jump into their “Machine Learning” and “Internet of Things” services.

I regularly use AWS services for cloud computing, storage, and databases. My go-to for a new project is to spin up a EC2 instance. If I know I’m using WordPress, I may use a Bitnami AMI. Other times, I’ll create a basic Linux box, and setup Apache, MySql, and PHP myself. Here is the documentation I regularly reference: Install a LAMP Web Server on Amazon Linux 2. This process usually includes configuring a domain name, and setting up SSL: Configure SSL/TLS on Amazon Linux 2.

I’ll continue this post as a series. I plan tell stories about my experiences in building digital products. I’ll cover topics such as design, marketing software, customization, and APIs. Follow me on Instagram for regular updates: @AntPace87

Remove subdirectories from a URL string

I use GitHub to manage code that I’ll want to re-use. I had trouble finding a canned function to remove the subdirectory path from a URL string – so I wrote one and added it to my latest public repository: https://github.com/pacea87/ap-utils

I’ll keep adding useful code to it – and feel free to make a pull request and contribute yourself. This code should focus on utility functions for manipulating data in interesting ways. Below is the JavaScript code for removing the subdirectories from a URL string. This will also strip away any query string parameters.

function removeSubdirectoryFromUrlString(url){
  
  var ssl = false;
  if(url.indexOf("https://")){
    ssl = true;
  }

  url = url.replace("http://", "");
  url = url.replace("https://", "");
  var pathArray = url.split("/")
  url = pathArray[0];
  if(ssl){
    url = "https://" + url;
  }else{
    url = "http://" + url;
  }

  return url;
}

Now, you can get the current page’s URL, and strip off everything after the host name:

var url = window.location.href;
var baseUrl = removeSubdirectoryFromUrlString(url);
console.log(baseUrl);

Another example:

var url = "https://www.antpace.com/blog/index.php/2018/12/";
var baseUrl = removeSubdirectoryFromUrlString(url);

//This will return "https://www.antpace.com"
console.log(baseUrl); 

I used this code to re-write all URL references in an iFrame to be absolute. My implementation loops through all image, anchor, and script tags on the source site. It determines if each uses an absolute reference, and if not re-writes it as one. This was part of a project that uses a visual editor to allow users to manipulate a remote site. Check out my source code below.

pageIframe.contents().find("img").each(function(){
  var src = $(this).attr("src");
  if(src && src.length > 0 && src.indexOf("//") == -1){  //if not absolute reference
    var url = iframeUrlString;
    if(src.charAt(0) == "/"){ //only do this if the src does not start with a slash
      url = removeSubdirectoryFromUrlString(url); 
    }
    src = url+"/"+src
  }
  $(this).attr("src", src);
});

pageIframe.contents().find("script").each(function(){
  var src = $(this).attr("src");
  if(src && src.length > 0 && src.indexOf("//") == -1){
    var url = iframeUrlString;
    if(src.charAt(0) == "/"){
      url = removeSubdirectoryFromUrlString(url); 
    }
    src = url+"/"+src
  }
  $(this).attr("src", src);
});

pageIframe.contents().find("link").each(function(){
  var src = $(this).attr("href");
  if(src && src.length > 0 && src.indexOf("//") == -1){
    var url = iframeUrlString;
    if(src.charAt(0) == "/"){
      url = removeSubdirectoryFromUrlString(url); 
    }
    src = url+"/"+src
  }
  $(this).attr("href", src);
});

If you liked this, check out my other post about my reusable code framework for web apps, A framework for web apps and startups.

Writing, engineering, and creativity

It was 2006 and I had just installed WordPress on a web server. I would draft blog posts nightly, before getting ready for bed. At the time I was a philosophy major and wrote prose more than code. That was my first venture into web development and digital marketing. It started with writing.

Writing blog posts and publishing software have a lot in common. For both, “perfect” is the opposite of ready. It’s easy to keep editing your own work. It’s even easier to keep adding half-done features and clutter. That’s why having a plan before you start helps so much. When I write, my first draft tends to be bullet points and a vague outline. The same goes for software. If I’m building something complex, I write comments explaining its functionality before any code. It’s my way of “thinking out loud”, and making sure that what I plan on doing even makes sense.

It’s been over a decade since I’ve maintained a blog. Creative tasks require hard work, lest they bear no fruit. (“Writer’s block is for amateurs”). Problem solving, in its many shapes, is the highest form of creativity. It’s how we build our reality. Modern technology gives us creative leverage through tools, knowledge, and community. We’re being given opportunities to build and create things, to grow and be better, at an unprecedented scale. It’s the best time in history to be CEO of your own life; creative director of your destiny. This also sets the bar higher to stand out.

My plan here is to write regularly, and discuss what I’ve been working on and learning, as well as what’s next. This gives me a chance to explore my thoughts, and prune the branches from which they stem. Hopefully, working at this will help to make me a better storyteller too.

Top 3 graphic design apps for social media marketing

Modern software has given creators the tools they need to showcase their work to the world. Here are the best free apps that I’ve been using that will help your talent shine in 2019:

AppWrap – Do you want to feature your latest website or app design to your followers? Are you building a portfolio for the UI/UX projects you worked on? This app is a great way to wrap your screenshots in a mobile device view. You can add effects, backgrounds, and text to really polish the look and feel. Their template gallery will give you inspiration to make something gorgeous. http://www.appwrap.in/

AntPace.com mobile device view

Canva – This is one of my favorites. With a library of over 60,000+ templates, this app has something for every platform. Whether you need to create a great looking post, story, or cover image, this app has designs for Instagram, Facebook, YouTube and much more. If you want your online presence to look professionally designed, check this one out! https://www.canva.com/

Anthony Pace creativity takes courage

Hatchful – Do you need a logo for your brand, business, or product? This app let’s you create one quickly. By customizing templates, you can draft, and iterate designs. Having logo design done fast, cheap, and easily allows you to focus on the actual product. It’s important to not get hung up on the logo, especially early into your venture, and instead focus on the actual value your service proposes. https://hatchful.shopify.com/

antpace.com

I’ve used all of these apps, and personally gained value from them. What apps do you use for your graphic design?

BJJ Tracker, a fitness app

www.BJJTracker.com

BJJ Tracker is a fitness app for tracking Brazilian jiu jitsu training. It’s the sort of fitness app I was looking for, but couldn’t find. Version 1.0 is a bare bones MVP, but has a list of features on the way. Future versions will add gamification (including challenges and goals), UX/UI enhancements, training recommendations, and more.

The app allows users to record their training sessions, with details about drilling and sparring, as well as competition. This data is visualized over charts and calendars. The idea started from physically writing my training sessions onto an actual calendar, with a minimum goal per week. Building it has been a great exercise in digital product development, software design, and UI/UX strategy.

fitness tracker calendar

Software

BJJ Tracker is a web app, hosted on a AWS Linux server, running Apache, PHP, and MySql. I used Initializr to generate a bootstrap template to get my front-end started. One goal of this project was to build a web app framework that I could use to quickly get future projects running. This code would include user registration and login services, as well as other back-end concerns, on top of a front-end. I’ve cleaned most of this code into a generic repo on GitHub. You can read my post explaining its features.

Design

This app was designed with “mobile first” in mind, assuming that most users will be on a smart phone. The look and feel of the color palette, font-choice, and UI layout took some experimenting and visual research. It’s not final, and will be subject to split testing over time. I used Font Awesome to add icons as visual cues, giving the app a more finished look. The three lined (hamburger) menu in the top right comes as standard UI, using Simple MobileMenu, a jQuery plugin. Other UI elements include a top status message, and “In-Your-Face” status message, both of which are custom built notifications that I’ve wrapped as javascript plugins. Having a calendar section was important to me, and I consider to be a primary feature of the app. I use Full Calendar to generate the full month view. The homepage (dashboard) focuses on a week view. Google charts is used for the “techniques” graph.

logo design

The logo is a work-in-progress. The textual part was easy – pick a font, add a sharp outline, and a drop shadow. I always start with a 1024×1024 canvas. The symbol begins with simple shapes, triangles and circles. I left this process for last, saving my focus for the actual product. This allowed me to rapidly iterate design versions, and see how it would look directly in the user interface. Below is the current portrayal – and I’m excited for next versions.

bjj tracker

Challenges and next steps

One goal of this project was to get started fast, so people could begin using it. Deciding what to include out of a long list of ideas proved challenging. I could have kept adding features, and never been ready to make the site public. I meant to keep functionality basic, but still wanted the thing to be useful. The design needed to be simple, yet still had to look finished. I won’t know how close I came to getting this right until I analyze user feedback. The real plan is to do a little bit better next time, and to keep iterating. Using this as foundation will let future ventures start a step ahead. Already, I’ve begun implementing updates, and getting ready to deploy to the App Store and Google Play. Look out for coming updates and other products that are in the works! Don’t forget to visit the BJJ Tracker blog.

bjj tracker