Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: javascript

  • Chart.js Category Statistics

    Chart.js Category Statistics

    One of the sites I work on is using the Metro Theme by StudioPress Themes for WordPress. And on that site, I have a page dedicated to some odd stats based on the categories and tags and custom taxonomies.

    What I have is a post type ‘shows’ and a custom taxonomy called ‘clichés’ and from that I was easily able to generate a percentage of how many shows use the cliché of queers in law enforcement (38%) or how many have the death of a queer (also 38% right now). But that wasn’t enough. We wanted ‘pretty graphs’ and for that I needed a tool like Chart.js and a little PHP magic.

    How to Chart.js?

    Chart.js is a super cool and super responsive and super flexible way to include a chart. And using it is incredibly easy once I figured out that I could just use inline script tags. A very basic chart that would show you how many days each month has looks like this:

    <script src="Chart.js"></script>
    <canvas id="barDays" width="600" height="400"></canvas>
    
    <script>
    var barDaysData = {
    	labels : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "November", "December"],
    	datasets : [
    		{
    			fillColor : "#7d3255",
    			strokeColor : "#532138",
    			data : ["31","28","31","30","31","30","31","31","30","31","31"]
    		}
    	]
    }
    
    var barDays = document.getElementById("barDays").getContext("2d");
    new Chart(barDays).Bar(barDaysData);
    </script>
    

    If you’re using WordPress, you’ll want to use wp_enqueue_script to call it. Here’s what I did for my theme:

    wp_enqueue_script( 'chart.js', get_bloginfo('stylesheet_directory').'/inc/js/Chart.min.js' , array( 'jquery' ), CHILD_THEME_VERSION );

    But that’s the basics of it. Once I understood that, I was good to go.

    The Code

    Before I can do anything, I need to make sure I have the data I needed. What I wanted was a list of all the shows that were published and a list of all the cliches, ordered in the way I need them. The order is simply comma separated values, enclosed in quotes, enclosed in brackets:

    labels : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "November", "December"],
    

    And the data is similar:

    data : ["31","28","31","30","31","30","31","31","30","31","31"]
    

    Since I’m lazy, I checked that the array worked if it ended in a , and it did! That means my PHP looks like this:

    $count_shows = wp_count_posts( 'post_type_shows' )->publish;
    $cliches = get_terms('cliches');
    
    $barshow_labels = '';
    foreach ( $cliches as $cliche ) {
    		$barshow_labels .= '"'.$cliche->name.'",';
    }
    
    $barshow_data = '';
    foreach ( $cliches as $cliche ) {
    		$barshow_data .= $cliche->count.',';
    }
    

    And my js looks like this:

    <script>
    var barShowsData = {
    	labels : [<?php echo $barshow_labels; ?>],
    	datasets : [
    		{
    			fillColor : "#7d3255",
    			strokeColor : "#532138",
    			data : [<?php echo $barshow_data; ?>]
    		}
    	]
    }
    
    var barShows = document.getElementById("barShows").getContext("2d");
    new Chart(barShows).Bar(barShowsData);
    </script>
    

    You may notice the simple call of <?php echo $barshow_data; ?> in there? That’s where it outputs the data I sorted out in the PHP section. Done. I’m could put it more inline, but I liked to separate them as much as I could.

    Putting it in the theme

    This is a Genesis theme so while I am making use of the Genesis loop, the call to get_template_part can be used by anyone. I’ll explain in a moment. First, here’s the page template:

    <?php
    /**
    * Template Name: Lezbian Stats Template
    * Description: Used as a page template to show page contents, followed by a loop
    * to show the stats of lezbians and what not.
    */
    
    // Show Dead count below the content:
    add_action( 'genesis_entry_footer', 'lez_stats_footer', 9 );
    
    function lez_stats_footer() {
    	get_template_part( 'stats' );
    }
    
    genesis();
    

    This works like any other page template. You make a page, you select the template, and it loads this custom design.

    The magic sauce is in get_template_part( 'stats' ); which calls the file stats.php and that file has all the code you saw above. This means I can edit my post with all the explanations I want, and then it always outputs the stats on the bottom. By calling the Genesis code in the bottom, I retain all of it’s magic while pulling in what I want.

    The Result

    The graph of cliches about queer women on TV

    Looks nice, doesn’t it? I’m quite fond of it.

  • jQuery Toggling

    jQuery Toggling

    I was working on some basic code where I wanted a div to show or hide based on a link. This is simple stuff, but it took me a while to remember it since it’s actually baked into MediaWiki (where I normally use it).

    First up is my HTML code:

    		<h2 class="suggestions-header"><a href="javascript:toggle_visibility('suggestionscontainer');">Suggestions? Click Here!</a></h2>
    		<div style="display:none;" class="sugestions-container" id="suggestionscontainer">
    			<p>I will display when clicked!</p>
    		</div>
    

    Like I said, this is basic stuff. I can get more into it and do things like change the text of the title when you click, but for now this suffices.

    Now for the jquery:

    /**
     * Custom jQuery to toggle visibility
     */
    jQuery( document ).ready(
    
    	function toggle_visibility(id) {
    	       var e = document.getElementById(id);
    	       if(e.style.display == 'block')
    	          e.style.display = 'none';
    	       else
    	          e.style.display = 'block';
    	}
    );
    

    This code got tossed into a toggle.js file and then enqueued with wp_enqueue_script, with a jquery dependancy. Done and done.

    I’m sure this could be done with pure CSS, but I believe in release and iterate.

  • All is Revealed

    All is Revealed

    I had some issues with SEO Slides in the past, mostly around how it’s not quite what I need while also being more than I need and less. I banged around this for a while, before I remembered that I’ve seen a lot of people use WordPress for slides in a way that I never really loved, while others used something decidedly not WordPress.

    Step back.

    I don’t believe that I should use WordPress all the time just because I’m a WordPress person. I thought about what I want from my slides:

    1. A way to load them locally or remotely
    2. A way to control them and see my notes
    3. Usable on mobile
    4. Embed-able by me and me only
    5. “SEO” friendly

    That last one really means “HTML should be readable so a screen reader could make sense of it for the blind.” And that’s really the primary reason I ended up with SEO Slides to begin with. But when I stepped back to really think about what SEO Slides did, and what I needed, I realized that while I really do love it, it made it harder for me to make slides.

    Kid sliding on sand

    Let me explain. SEO Slides’ interface is not the WordPress post editor. I suspect, if it was, I’d be happy since I can mangle HTML there all day long. But SEO Slides doesn’t let you at the source code of the page, you have to use their GUI, and I was having a hell of a time with things like centering and floating and wrapping… All things I’m a boss at with HTML.

    In addition, I’d recently discovered serious limitations with pageload, especially on mobile. The fixes in 1.5.0 didn’t fix it for me (actually it became worse with my slides taking over fifteen minutes to load, at which point I gave up). This is not to say I don’t love SEO Slides and what it does, it just didn’t fit my personal workflow. As much as I loved it when I did my EDD presentation for WP Sessions, I wasn’t satisfied.

    So as I contemplated my vodka over Passover, I came to the possibility that maybe WordPress was totally overkill for slides. Maybe, like with a Gallery, it was too much and too complicated for something that should be more simple. To me, HTML is simple. It’s straight forward, direct, and I still use it every day. With the exception of paragraph tags, I wrote this post in HTML mode.

    I did what comes naturally to me. I went and poked around what some of my friends have done (and kept up or not…) and finally decided that I was going to try out reveal.js.

    Wow.

    Basic HTML Slides? Why not Reveal.js?

    Installing was simple, just a git clone. And while the directions claimed you can’t use speaker notes unless it’s running locally, I found this not to be the case. Maybe it’s because I’m on Chrome, or maybe that’s not updated. Either way, it’s awesome for me since I can suddenly control my slide-deck on my laptop. Making my own slides was also pretty basic, I made a folder for each deck, tossed in the images and the index.html, and went to town. It’s really that easy to do, though I wish there was a basic, example, and not just the big one. Still, a search and replace of HTML is super fast.

    It loads faster than SEO Slides, works better on my iPad, and the only thing I can’t do is embed. I’ll live. I’m also sure it can be done, since http://slides.com/ (the freeium version that hosts it for you) has an embed ability. The other massive gain is that it’s smaller. When you upload media to WordPress, you get multiple images, and I have to pre-load each page (or load it on the go). This gets heavy since I like background images and pretty things.

    With reveal.js, I just upload one image and I’m done. It loads everything at once, since it’s one HTML page, and the image (while large) is just reused. And that was good enough for me. Also I get to use remotes.io to remote control my slides from my notes (I use the iPhone app Scan, by QR Code City, and paid for it because I hate ads).

    I may go back to SEO Slides (who should consider an import from reveal… Hmmmm) but this works for me now. We’ll see if I love it in the long term. I suppose I should actually read stats and see if anyone but me even cares about the slides…

  • New Smilies?

    New Smilies?

    While the arguments for and against are pretty hot and heavy (see the trac ticket for more), it’s no secret I’m pro-new smilies. The old ones are too small, too pixelated, and too (pardon the phrase) web 1.0. They look old and out of date on my site.

    Here they are at normal size:

    Old Smilies, normal sized

    And here’s double:

    The smilies at twice size

    These are both gifs, to illustrate the size issue. Notice how they’re fuzzy?

    I want to make one thing clear, pun intended. None of my issues have to do with Retina. I don’t like ‘small’ anything. The smilies are too small, much like the font on many people’s websites, the pixelization is hard for me to identify. In fact, while I’m using the new smilies here, you’ll notice they’re bigger. Sure, cause I tossed this in my CSS:

    #wp_grins img, img.wp-smiley {
        height: 25px;
    }
    

    And that’s all it took to make them something I felt was readable. But the beauty, and why I like the new SVG images, is that I can make them larger like that, without losing readability.

    Thankfully, due to the curmudgeony efforts of the new smilies’ biggest naysayer, Otto, we have a filter! I’ve talked about this before, in how I handled both SVG and PNG as smilies for IE. I have a couple options here. I could write some code myself, or I could use New WordPress.com Smileys (which is on GitHub for reasons, the code is fine!).

    I like the plugin a lot. I like it so much, I refactored my SSL Grins plugin to use them with the fancy pants new span code (instead of images). But… Well, I already had this done by the time his plugin came out, and I like how I accounted for things differently. The only real difference though is he uses spans, and I just swap out the images:

    <?php
    /*
    Plugin Name: Custom Smilies
    Plugin URI:  https://ipstenu.org
    Description: I like the new smilies, shut up Otto.
    Version: 1.0
    Author: Mika Epstein
    Author URI: https://ipstenu.org/
    */
    
    // Move Smilies
    add_filter('smilies_src','helf_smilies_src', 1, 10);
    function helf_smilies_src($img_src, $img, $siteurl) {
        if ( strpos( $_SERVER&#91;'HTTP_USER_AGENT'&#93;, 'MSIE 8' ) || strpos( $_SERVER&#91;'HTTP_USER_AGENT'&#93;, 'MSIE 7' ) || strpos( $_SERVER&#91;'HTTP_USER_AGENT'&#93;, 'Android' ) ) {
            $img = 'ie/'.$img;
        }
        else {
             $img = str_replace("png", "svg", $img); // Remove PNG
        }
        return $siteurl.'/code/images/smilies/'.$img;
    }
    
    // This is in a paren for my sanity....
    {
        global $wpsmiliestrans;
    
        if ( !get_option( 'use_smilies' ) )
            return;
        
        if ( !isset( $wpsmiliestrans ) ) {
            $wpsmiliestrans = array(
            ':mrgreen:' => 'icon_mrgreen.png',
            ':neutral:' => 'icon_neutral.png',
         // removing b/c new versions
            ':twisted:' => 'icon_evil.png',
              ':arrow:' => 'icon_arrow.png',
              ':shock:' => 'icon_eek.png',
              ':smile:' => 'icon_smile.png',
                ':???:' => 'icon_confused.png',
               ':cool:' => 'icon_cool.png',
               ':evil:' => 'icon_evil.png',
               ':grin:' => 'icon_biggrin.png',
               ':idea:' => 'icon_idea.png',
               ':oops:' => 'icon_redface.png',
               ':razz:' => 'icon_razz.png',
               ':roll:' => 'icon_rolleyes.png',
               ':wink:' => 'icon_wink.png',
                ':cry:' => 'icon_cry.png',
                ':eek:' => 'icon_surprised.png',
                ':lol:' => 'icon_lol.png',
                ':mad:' => 'icon_mad.png',
                ':sad:' => 'icon_sad.png',
                  '8-)' => 'icon_cool.png',
                  '8-O' => 'icon_eek.png',
                  ':-(' => 'icon_sad.png',
                  ':-)' => 'icon_smile.png',
                  ':-?' => 'icon_confused.png',
                  ':-D' => 'icon_biggrin.png',
                  ':-P' => 'icon_razz.png',
                  ':-o' => 'icon_surprised.png',
                  ':-x' => 'icon_mad.png',
                  ':-|' => 'icon_neutral.png',
                  ';-)' => 'icon_wink.png',
            // This one transformation breaks regular text with frequency.
            //     '8)' => 'icon_cool.png',
                   '8O' => 'icon_eek.png',
                   ':(' => 'icon_sad.png',
                   ':)' => 'icon_smile.png',
                   ':?' => 'icon_confused.png',
                   ':D' => 'icon_biggrin.png',
                   ':P' => 'icon_razz.png',
                   ':o' => 'icon_surprised.png',
                   ':x' => 'icon_mad.png',
                   ':|' => 'icon_neutral.png',
                   ';)' => 'icon_wink.png',
                  ':!:' => 'icon_exclaim.png',
                  ':?:' => 'icon_question.png',
            // New for me
                  '>:(' => 'icon_mad.png',
                  'o_O' => 'icon_surprised.png',
                  'O_o' => 'icon_eek.png',
                  '^^‘' => 'icon_redface.png',
                  ':‘(' => 'icon_cry.png',
                  ':’(' => 'icon_cry.png',
       ':whiterussian:' => 'icon_whiterussian.png',
                  '|_|' => 'icon_whiterussian.png',
                   ':/' => 'icon_uneasy.png',
                  ':-/' => 'icon_uneasy.png',
          ':developer:' => 'icon_developer.png',
            ':burrito:' => 'icon_burrito.png',
            ':martini:' => 'icon_martini.png',
                  '>-I' => 'icon_martini.png',
              ':blush:' => 'icon_redface.png',
              ':heart:' => 'icon_heart.png',
                //'&amp;lt;3' => 'icon_heart.png',
               ':bear:' => 'icon_bear.png',
               ':star:' => 'icon_star.png',
                  '(w)' => 'icon_wordpress.png',
                  '(W)' => 'icon_wordpress.png',        
            );
        }
        
        if (count($wpsmiliestrans) == 0) {
            return;
        }
    }
    

    But why don’t they all show up in my comments section? Where’s the martini!? I also upgraded my plugin SSL Grins with an ‘easter egg’ of code that hides anything in this array of smiled_hide. This works on both my version of the smilies plugin and Avryl’s. and looks like this:

    $smiled_hide = array("bear", "wordpress", "martini", "developer", "whiterussian", "burrito","icon_bear.gif", "icon_wordpress.gif", "icon_martini.gif", "icon_developer.gif", "icon_whiterussian.gif", "icon_burrito.gif", "icon_bear.png", "icon_wordpress.png", "icon_martini.png", "icon_developer.png", "icon_whiterussian.png", "icon_burrito.png", "icon_bear.svg", "icon_wordpress.svg", "icon_martini.svg", "icon_developer.svg", "icon_whiterussian.svg", "icon_burrito.svg");
    

    Now this is possibly the jankiest, stupidest, code I’ve written in a while. I’d rather just have the words be there, and filter “If any of the values in this array is a partial match to the name of the smilie we’re looking at right now, don’t show it.” But I’m not clever enough with arrays and preg matching at this point, so I did that ugly list, and used this:

    if (!in_array($grin, $smiled) && !in_array($grin, $smiled_hide) ) {...}
    

    So at this point, pull requests are welcome because I’d love to clean that up!

  • Extending Chrome

    Extending Chrome

    I had a problem.

    If you know me at all, you know this is how 99% of my code lessons start. I have a problem I can’t solve easily, so I dig into it and write about it. In this case, my problem was one of those really stupid, messy things where I needed to force some code to run on certain pages and I didn’t have any access to those pages. Why? Well … let’s just say I wanted to make something like the Hey Girl chrome extension okay? Yes, I need an extension for Google Chrome.

    It doesn’t really matter what you’re making, what matters is how easy it is to make a Chrome Extension. It really only needs two files, a manifest.json and then your content files. Let me explain by making Google Red.

    Manifest

    The manifest is where you list what’s in the Extension. It’s going to have the name, summary, what files to call, when and where. A really simple example would be like this:

    {
    "name": "Half-Elf's Chrome Extension",
    "description": "This is an example extension that doesn't do anything useful at all.",
    "version": "1.0",
    "manifest_version": 2,
    "content_scripts": [
        {
          "matches": [
                     "http://www.google.com/*",
                     "https://www.google.com/*"
                     ],
          "css": ["mystyle.css"],
          "js": ["myscript.js"]
        }
      ]
    }
    

    This is pretty straight forward. Name, description, etc. The value for manifest_version has to be the number 2, no quotes, no matter what. This is mandated by Google. They don’t use it yet, but they will. Then we get to the fun stuff, content_scripts, which is also pretty obvious. Using “matches” says “Only run this when the URL matches…” This is an inclusive match. For a different example, here’s an extension I want to run on every website, but not when I’m in wp-admin:

    "content_scripts": [ {
    	"matches": [ "http://*/*", "https://*/*" ],
    	"exclude_globs": [ "http://*/wp-admin/*"],
    	"css": [ "mystyle.css" ],
    	"js": [ "myscript.js" ]
    } ]
    

    You can take this even further and only have it take action at specific actions (like when you make a tab active). The content_scripts documentation is pretty overwhelming, but it has all sorts of options. Today, though, saying we want to match just Google’s pages is okay.

    In order to do this, I made a blank file called manifest.json and saved it in my ‘Development’ folder called~/Development/Chrome/extensions/GoogleRed but this doesn’t actually matter. Save it anywhere on your computer. Just know where it is. I also put blank files for mystyle.css and mystyle.js in there because they’re my content files! They’re blank, we’ll get to the real code soon.

    Content Files

    This is the fun part. The content files are what makes the magic happen and the super cool thing? It’s all basic JS or CSS or HTML. Seriously. Anything you can do in those languages, you can do in an Extesion and call it a day. For example, here’s one I used to strip referrers from URLs on Facebook (I was experimenting):

    document.body.innerHTML = document.body.innerHTML.replace(new RegExp('?fb_source=pubv1" target="', 'g'), '" target="');
    

    I set this to only run on Facebook.com and it was exactly what I needed. I admit, there are better JS ways to do this, but I suck at JS still, so this was as far as I got.

    The Example

    Google actually already made the files, so you can download them from Chromium “Make Page Red” and toss them in your folder. My files are as follows:

    mainfest.json

    {
    	"name": "Page Redder",
    	"description": "Make the current page red",
    	"version": "2.0",
    	"permissions": [
    		"activeTab"
    	],
    	"background": {
    		"scripts": ["myscript.js"],
    	    "persistent": false
    	},
    	"browser_action": {
    	    "default_title": "Make this page red"
    	},
    	"manifest_version": 2
    }
    

    myscript.js

    // Copyright (c) 2011 The Chromium Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    	
    // Called when the user clicks on the browser action.
    chrome.browserAction.onClicked.addListener(function(tab) {
      // No tabs or host permissions needed!
      console.log('Turning ' + tab.url + ' red!');
      chrome.tabs.executeScript({
      code: 'document.body.style.backgroundColor="red"'
     });
    });
    

    That’s it. Two files. But how do I get it installed?

    Adding it to Google Chrome

    Go to chrome://extensions/ in Chrome and you get this kind of view:

    chrome-extensions

    See the box on the upper right? Developer Mode? Check it. Now you get extra information!

    chrome-extensions-developer

    What interests us the most here is “Load unpacked extension…” but also that ID code jcpmmhaffdebnmkjelaohgjmndeongip is really important. This tells me where the extension lives on my computer, because I can go to ~/Library/Application Support/Google/Chrome/Profile/Extensions/jcpmmhaffdebnmkjelaohgjmndeongip and see all the code for the other extensions. This makes it super easy for me to fork them. Since this is all just for me, and I have no plans to release them, I’m less worried about licenses than I might be, but I still am in the habit of checking what they are and so should you. Your folder locations will vary depending on your OS, and how many Google Profiles you have (I actually have 3 – me, work, fansite).

    Click that “Load unpacked extension…” and select the folder:

    upload

    Once you upload it, you get this:

    sample-ext

    Now you know where the file is, but also you get a special link for Reload (⌘R) which is a life saver. Click that and any changes you made to your source files are re-installed into Chrome! This is great because Google’s example of making pages redder? Doesn’t work.

    Okay, that’s not fair, it does work, just not on every page. It didn’t work on https pages for me until I edited the manifest and changed permissions from "activeTab" to "activeTab", "tabs", "http://*/*", "https://*/*" and then clicking on the magic button worked:

    click-icon

    It’s kind of nice to be able to bully things around that way.

    I’m just dabbling my toes into the Extensions water, and I find it highly powerful to push Chrome into my paths right now. Have you written any extensions?

  • Email PopUp

    Email PopUp

    Edited to note: The popup is NOT on this site. You’re not missing anything.

    Blame Chris Lema. Not for “making” me do anything, but for making a good article that was insightful and inspiring. But then again, he’s good at that.

    When I read the article he wrote about Growing your Email List, I was interested. While I don’t have the same needs he does, I do want to pull in more subscribers to one site. Look, in general, I don’t worry about who’s following me on my personal sites. However I do have a site, one site, where I do care about the followers, especially since I broke my old mailing list a while back.

    Revisiting My Options

    The old mailing list worked, but no one could sign up any more, and it was becoming a hassle. It was finally time to move off the old and embrace some new. But what new? I’m a huge proponent of self hosting, but to be frank, I hated managing email server stuff and Mailman is both long in the tooth and not exactly user friendly for the non-technical people. It was time to accept that this was not my forte, and you know what? I didn’t want to learn it. Since 100% of the news on that site was pushed via WordPress, it was logical to use something I already had: Jetpack. It had subscriptions, done.

    “I broke it.”

    That was in the body of the email I sent.

    I emailed everyone on that old list and explained the situation. I apologized for my screwup, and explained how they could re-subscribe if they wanted. Within 12 hours, 50% of them did. That was good enough for me, and while I’m watching more people trickle in, I think it’s going to top out around a 70% retention rate. That’s not bad at all. A handful of people emailed me back laughing (literally ‘LOL’ was the entirety of more than five replies) and saying it was okay, thank you for letting them know. I was heartfelt, I was honest, and I was deprecating.

    I’ve always had a link to my email list in my sidebar as an alias, domain.com/updates linked to domain.com/mailman/list/updates, so changing that to an actual page all it’s own with a subscription form was crazy simple. New page, delete redirect, done.

    Back to Chris though. See, the most enlightening thing I gleaned from his email was the horrifying fact that pop-ups work. He didn’t give me stats or anything, but I believe him. When I read that, I believed him enough that I went and read other articles about those ‘non-annoying’ pop-ups. Chris and I are vastly different people, passionate about different things, and obsessive about others. But we share a talent for writing, telling stories, and engaging. We also share a hate of pop-ups. His is certainly not annoying.

    Actually I’ve barely noticed his, except to go “Oh, there was a pop-up to get him in my email.” No, I didn’t sign up, I like getting Chris in my RSS box.

    jquery

    This was the hardest part so let’s tackle it first. All I have to do is show it in a pop-up. Except it’s not really a pop-up, it’s a sliding tab. Sure, I could use anything I wanted, but like Chris, I hate pop ups.

    This part stumped me hard. Chris got it easy by having a third-party hand him the code. I, like many people, have an email list and want to use that. But I’m still very much a rookie when it comes to jquery, so when I ran into this information about how to code a wordpress.com follow button and Follow me button on WordPress with MailChimp, I did a little dance.

    The jquery actually comes straight from WordPress.com (I viewed a lot of source to reverse this one):

    jQuery.extend(jQuery.easing,
    {
     easeOutCubic: function (x, t, b, c, d) {
      return c*((t=t/d-1)*t*t + 1) + b;
     }
    });
    jQuery(document).ready(function($) {
    	var isopen = false,
    	    bitHeight = $('#bitsubscribe').height(),
    		$bit = $('#bit');
    	setTimeout(function () {
    		$bit.animate({
    				bottom: '-' + bitHeight - 10 + 'px'
    			}, 200);
    		if ( document.location.href.indexOf('subscribe=') > -1 ) {
    			open();
    		}
    	}, 300);
    	var open = function() {
    		if (isopen) return;
    		isopen = true;
    		$('a.bsub', $bit).addClass('open');
    		$('#bitsubscribe', $bit).addClass('open')
    		$bit.stop();
    		$bit.animate({
    			bottom: '0px'
    		   },{duration:400, easing:"easeOutCubic"});
    	}
    	var close = function() {
    		if (!isopen) return;
    		isopen = false;
    		$bit.stop();
    		$bit.animate({
    			bottom: '-' + bitHeight - 10 + 'px'
    		}, 200, function() { 
    			$('a.bsub', $bit).removeClass('open');
    			$('#bitsubscribe', $bit).removeClass('open');
    		});
    	}
    	$('a.bsub', $bit).click(function () {
    		if ( !isopen )
    			open();
    		else
    			close();
    	});
    	var target = $bit.has('form').length? $bit : $(document);
    	target.keyup(function(e) {
    		if (27 == e.keyCode) close();
    	});
    	
    	$( '#loggedout-follow' ).submit( function() {
    		email = $( '#loggedout-follow-field' ).val();
    		if ( '' === email || !email.match( /^.*@.*\..*$/ ) ) {
    			var error = LoggedOutFollow.invalid_email;
    			$( '#loggedout-follow-error' ).text( error ).css( 'opacity', 1 ).fadeIn( 'slow' );
    			$( '#loggedout-follow-field' ).focus( function() { $('#loggedout-follow-error').fadeOut(); } );
    			return false;
    		}
    		return true;
    	});
    });;
    

    If I enqueued that in my theme, then all I’d have to do is call this somehow in my theme:

    <div id="bit" class=""><a class="bsub" href="javascript:void(0)"><span id="bsub-text">TITLE</span></a><div id="bitsubscribe">CONTENT</div></div>
    

    The jquery would automatically handle placement and everything, so I struck upon the dead-simple solution.

    Widget

    Since I only need to use this on a WordPress site, I put it in a widget, and slapped some CSS around it to make it sexier. The very simple (Genesis skewed) widget is as follows:

    //* Register side-up-bit area
    genesis_register_sidebar( array(
    	'id'            => 'slide-up-bit',
    	'name'          => __( 'Slide Up Bit', 'mygenesis' ),
    	'description'   => __( 'This is a widget area that slides up.', 'mygenesis' ),
    ) );
    
    //* Hook after post widget area after post content
    add_action( 'genesis_after_footer', 'my_slide_up_bit' );
    
    function my_slide_up_bit() {
        genesis_widget_area( 'slide-up-bit', array(
            'before' => '<div id="bit"><a class="bsub" href="javascript:void(0)"><span id="bsub-text">Follow SITE</span></a><div id="bitsubscribe">',
            'after' => '</div></div>',
    	) );
    }
    

    Yes, I hard coded in the “Follow Site” title bit. Couldn’t figure out how not to, since I needed the link in the title. If this was a normal widget, I’d use the ‘before_title’ and ‘after_title’ trick, and while that’s supposed to work with Genesis too, I hit a wall and was in a time-crunch. That said, afterwards, all I had to do was drop Jetpack subscribe widget into the widget area, and the jquery code went into a function to show in my footer. Done. Time for the elf to study up on jquery, though, as I still don’t understand it all.

    Bonus note:

    if (document.location.href.indexOf('subscribe=') !== -1) 
    

    That little bit of code says “If someone has subscribed, make sure the popup is up when they visit.” It shows them that they have subscribed successfully, which is great, but I quickly realized I could tweak that to pop up when someone visited my site from, say, Facebook or RSS links:

    if ( (document.location.href.indexOf('subscribe=') > -1) || (document.location.href.indexOf('fb_source=') > -1) || (document.location.href.indexOf('utm_source=rss') > -1) ) 
    

    The RSS folks are pretty small, and I doubt they care, but the FaceBook people were absolutely delighted. I want to stress that I was doing this specifically because I have very non-technical people, and even having a link for email updates was beyond them. But having this slide-up is non-offensive and apparently much needed. My email subscribers tripled within a week.