{ "version": "https://jsonfeed.org/version/1.1", "title": "Craveytrain", "language": "en", "home_page_url": "https://craveytrain.com/", "feed_url": "https://craveytrain.com/feed.json", "description": "The personal site of Mike Cravey (@craveytrain).", "author": { "name": "Mike Cravey", "url": "https://craveytrain.com/" }, "items": [ { "id": "https://craveytrain.com/posts/webmentions-support/", "url": "https://craveytrain.com/posts/webmentions-support/", "title": "Webmentions Support", "content_html": "
All this talk about web standards and owning your own data inspired me to support webmentions on this blog. I'm not treading any new ground here, so I won't bother you with another post describing the process. Instead, I'd like to treat this more like a link farm, referencing those I learned from and where I chose to coincide with or deviate from. Maybe someone will find this useful when evaluating their own options.
\nFirst off, I want to say, this would not have been even in my purview if not for the encouragement of IndieWeb standard bearer Tantek Çelik. He originally put me on this idea of owning your own content years ago, when I would notice his Twitter posts had links back to his site, where a full copy of his message was stored. I was always impressed by this, even if I wasn't initially motivated by it. It wouldn't be until years later, spurred by the push of returning to web standards movement gaining so much momentum on Mastodon, that I decided to start making steps towards owning my own data.
\nRecently I polished off the old blog (which hadn't seen a new post in years), and most recently have added support for webmentions. I was finally inspired into action by a post by Nicolas Hoizey. And like any good web citizen, he cited his inspirations, a primer on webmentions in Eleventy by Max Böck and a really thorough walk through of setting up webmentions in Eleventy by Sia Karamalegos. Also, none of this would be possible without the awesome services of Bridgy to crawl my accounts on other sites, looking for mentions and posting them to webmention.io, an endpoint to receive and return webmentions upon request.
\nGenerally, my setup lines up with Nicolas' post. I like the idea of committing the webmentions as data in my repo, because it is content used to generate the site. If something were to happen to the source for those webmentions, I would not want to lose them, so I'm keeping them. Here's the basic process:
\nAnd while conceptually I made the same trade-offs as Nicolas, I followed all the code samples from Sia's post. She wrote the most thorough and understandable post on the subject I've seen to date, replete with code samples in the article and sample code in gists. I really appreciated her approach and the way she explained things made it pretty straight forward to add them to my site.
\nWhile I didn't use Max's post as reference as much as the other 2 on this subject, his additional post on webmentions analytics is fascinating and inspiring work. I look forward to taking a swing at it myself in the future.
\nFinally, for the style of likes and reposts, I was inspired by, tried to change, but ultimately took wholesale, Zach Leatherman's implementation of a facepile. I really like the look of it and I tried to make it work with what I felt was more semantic markup of avatars in a list. However, I ended up using his code pretty liberally after I wasn't able to make my preferred syntax work. I don't have any replies, yet, so I'm unsure of how that will look, but when I get some, I'm sure I will be quickly adjusting the style of them.
\nHope you found this useful and I highly recommend all the links I shared in this post.
\n", "date_published": "2023-02-16T00:00:00Z" } , { "id": "https://craveytrain.com/posts/verified-masto-link/", "url": "https://craveytrain.com/posts/verified-masto-link/", "title": "Verified Mastodon Link", "content_html": "Like many others, I've been called by the siren song of Mastodon and have created an account (@craveytrain@hachyderm.io) in the fediverse to check it out. One of the things that interests me is the ability to self-verify the links I reference, as a way to say I am who I say I am (as much as anyone can do on the internet).
\nThe recommended way to achieve that verification status on a link from Mastodon is to link back to your Mastodon account from the linked page. They even (helpfully) give an example on the link page:
\n<a rel=\"me\" href=\"https://hachyderm.io/@craveytrain\">Mastodon</a>
\nThe problem I have with this is I don't want a link to my Mastodon account on my home page. That's not my ideal IA (let's just assume I actually have an IA for now). A lot of people seem to solve this with adding a link on their home page but hiding it visually. I don't love this cause, it's hacky, and stinks of bot tricks, not to mention users who access your site with a device that would read that link aloud (think text only browsers or screen readers).
\nSo, I did a little digging on Mastodon's Profile Link Verification page and discovered a little line:
\n\n\nthe resolved page contains at least one
\na
orlink
tag with arel="me"
Of course, a link
tag! So, instead of putting an a href
on my home page and hiding it, I can put a link
tag in my header and all is well. So, here is what I put in my header to get me the nice little green checkmark:
<link rel=\"me\" href=\"https://hachyderm.io/@craveytrain\" />
\n",
"date_published": "2022-12-22T00:00:00Z"
}
,
{
"id": "https://craveytrain.com/posts/version-8/",
"url": "https://craveytrain.com/posts/version-8/",
"title": "Version 8",
"content_html": "After a long hiatus, I have finally gotten around to rebuilding on the site. The colophon has been updated but I figured I'd spend a bit of time explaining the why.
\nThe biggest change is moving to Svelte. I've been hearing a lot about it and wanted to give it a shot. I've been moving more and more towards CSS Modules (or Styled Components, depending on the stack) and Svelte is like an all in version of that. JS, CSS, and HTML are all packaged up in a single module.
\nWhile I'm branching out to a new stack, I am still a big fan of statically generated sites so I'm using Sapper, thanks to some tips from Level Up Tutorials, to generate the site.
\nAs a big fan of Syntax.fm I created a Uses page for me to detail the tools I'm currently using. Here's hoping I continue to refine it.
\nI've made some small design changes as, hopefully, a precursor to more updates. I'm hoping to treat this site less a a blog and more as a personal space on the web that I tinker with more.
\nHere's hoping...
\n", "date_published": "2019-09-09T00:00:00Z" } , { "id": "https://craveytrain.com/posts/going-live-with-es2015/", "url": "https://craveytrain.com/posts/going-live-with-es2015/", "title": "Going live with es2015", "content_html": "Last night, I gave a talk at JS Monthly London on Going live with ES2015. It was my first talk since moving to London in August. It was nice to dust the cobwebs off my public speaking, but I'm glad it wasn't recorded.
\nWhile I covered a few of the parts of ES2015 we use, and how we setup the build process, the meat of the talk was about how we went about choosing the technologies and getting it into production. Given that my role these days is more about process and mentoring, I thought I would elaborate on that portion of my talk for whoever might find it helpful. This is from the perspective of a manager. I hope you find it useful in convincing yours.
\nWhen trying to introduce new technologies to your stack, resist the temptation to "solve all the problems". It's easy to get bogged down in the details of how something will integrate into your system, how it will consume your data, etc. This is the path to the dark side. You can solve all those problems in due time, but first, make sure the idea holds water. You will learn things from solving each problem that you can apply to the next one.
\nThis also allows you to mitigate your risk of failure. Throwing away a few hours of work is, usually, much more palatable than a few days, or even weeks. Start small and build up, with checkpoints along the way. This is being responsible with your, and your company's time.
\nIt starts with a problem. We had race conditions. We had regressions in what we thought were "untouched" code. We had code that was just concatted together, registering itself globally, in a random order and auto-invoking. This let to all sorts of unintended consequences. This was not a position we could maintain.
\nWe stepped back from our problem and thought about what goals we would have for our code. In short order, we came up with a short list.
\nWe wanted code that was small, simple, and did a single purpose. We wanted a dependency graph so we could know what could be impacted by code changes.
\nWe wanted to be more intentional and explicit about our code. When more DOM gets loaded into the tree, we wanted to be able to run our code against that new DOM exclusively, not just "reload" the module.
\nWe also wanted to override our, hopefully, sensible defaults.
\nPossibly the most important one of the list, we wanted to have confidence that when we shipped our code, we knew what it was doing, and, more importantly, what it was not doing.
\nOne thing that becomes a real pain in testing JavaScript is testing code that interacts with the DOM. To isolate it, we created a pub/sub interface that all modules use to talk to each other. That way DOM-sensitive code can attach to DOM fixtures, listen for events, mutate the DOM and have the other side of the module exposed to the pub/sub for testing. Likewise, code on the other side that did service level things, maybe talk to the server, maybe do model work, could also have a clear separation point to attach testing to.
\nI feel very strongly that technology decisions should be made as a team, by the people who are going to use it every day. That doesn't mean I'm a silent bystander (those that know me are well acquainted my utter lack of ability to be silent), but my voice, even as the manager, doesn't weigh more than anyone else's. In fact, in many ways, it weighs less.
\nWe talked about pros and cons of several ways to achieve our goals. We even added a couple on the spot:
\nWouldn't it be great if we didn't have to transpile into something else to make the code work in the browser? One can dream.
\nCode should strive towards obviousness, easy to grok. We want to include more developers, not create a walled garden.
\nIf we are going to use this code every day, it should be something that we are excited to use. If it's boring and no one finds it interesting, why the hell are we using it?
\nSo we made a decision, how do we know if it was a good one? We had to start putting it through it's paces. We created a POC that would prove if the idea could work. It had to solve those goals and nothing more. This is a hard thing to do. Again, resist the urge to figure out how it will work in your build system. Just focus on making the basic idea work first. Knowing how it will integrate in your system ultimately just isn't valuable at this juncture and what you learn in the process will help inform how to solve that problem later.
\n", "date_published": "2016-01-27T22:30:35Z" } , { "id": "https://craveytrain.com/posts/how-i-interview/", "url": "https://craveytrain.com/posts/how-i-interview/", "title": "How i interview", "content_html": "As engineers, when we are asked to interview someone our primary directive is to assess someone's technical abilities. In fact, not just a passing assessment, but an assessment with a high degree of confidence. We need to know with as much certainty as possible this person is capable of doing the job. This is a team member, someone who will be relied upon and if they can't pull their own weight it will be felt by everyone else on the team.
\nThere are many different ways people can interview and I feel like I've been through them all. I was once asked to write up a sample DNS record on a white board when interviewing for a design/front end position because I had server admin with dns and others listed as experience on my resume. Pro tip: cull your resume to be relevant to the position you are applying for. Showing breadth of experience is great but make sure it's focused to the gig.
\nI have seen people do the white board thing, ask all sorts of academic questions, look at portfolios live in the interview, pair program and even give written tests. I think people sometimes get caught up in the position of power that comes with being an interviewer and use that to pass judgement on others. That's where I lose my patience with this whole thing. The goal here is to find someone you want to work with and wants to work with you. I submit to you there are at least a few better ways which I currently use.
\nI was inspired by the way frog interviewed me (despite not offering me the job). It was conversational, comforting even. We talked about various things I had done, occassionally drilling down into details of why or how I did something. They got me talking about my experience and got a gauge of my technical acumen without ever grilling me. This has influenced my interview process heavily. My current personal technique is based heavily on that.
\nThe other interview that helped form my ideology was at GLG. One of the engineers came in with a laptop, sat it down and told me had setup an endpoint to POST a form to and mocked up a loose form. He wanted to sit with me while I coded up an XHR submit, take the response and show it on the page. He had a few text editors and an IDE. I asked a few questions about intents and constraints and then started. Right off the bat, I couldn't remember the XHR method signature. "That's ok, we have internet", he said. I pulled up the reference and we're off. Along the way he asked me a few questions about my methodology and I explained at various places the shortcuts I was taking for the purposes of an interview that I wouldn't do in a production environment (and what I would do in said environment). We knocked it out in about 10 minutes and spent the rest of the time talking about the company, various challenges of the gig, etc.
\nI'm constantly working on my process and am really liking this new project from who else but Rebecca Murphey. I like it so much I'm going through it myself and doing pull requests for things. It's a fantastic little project and I intend to start working it into my rotation.
\nAfter all this prattling, my message is simple, you can gauge people's skill level without having to exert your power over someone or asking them to memorize inane details or pass some sort of academic exercise that just isn't relevant in the real world. Eyes on the prize, finding a new great team member.
\n", "date_published": "2012-12-16T00:00:00Z" } , { "id": "https://craveytrain.com/posts/moving-to-octopress/", "url": "https://craveytrain.com/posts/moving-to-octopress/", "title": "Moving to octopress", "content_html": "I'm following the trend and moving over to Octopress. While I do love my custom node blog, the amount of work it took to get a new post up and the stack it required for a simple blog was just overkill. It was a fun experiment and I will continue to play with node in all sorts of varieties, I just am not interested in rolling my own blog in it for now. Enter Octopress.
\nOctopress is billed as a hacker's blog tool. It met my rather modest criteria:
\nOn top of that were some things I hadn't really given creedence to. Things such as prerendering the blog. When ya think about a blog in it's most basic form, it makes total sense. It just took me a while to get on board. It's got good syntax highlighting built in. It uses SASS (another thing I didn't know I wanted until I used it).
\nThe thing is, now I have extended/altered Octopress so much there is no easy merging back when they make more changes. I have my own theme, I have ripped out all of the asides, I have adjusted the Rakefile to add minification of scripts, hashing of static file names so I could have very long expires headers on them and thrown out the entire concept of custom includes and styles. The whole thing is custom at this point. I may have painted myself back into the same hole but even so, it has been fun getting here. I'm looking forward to doing a few things with regards to search auto-suggest, better theming and maybe some social integration (activity on github repos comes to mind).
\nIf you are interested in seeing what I have done (and hopefully will be doing) to the codebase, please check out my octopress fork and my octopress theme.
\nOh, and I turned comments off. Still deciding if I want to turn them back on or use something with regards to twitter or github discussions on the markdown pages that generate the posts for that or just do away with them all together. We shall see.
\n", "date_published": "2012-05-07T00:00:00Z" } , { "id": "https://craveytrain.com/posts/js-is-your-friend/", "url": "https://craveytrain.com/posts/js-is-your-friend/", "title": "JS is your friend", "content_html": "A week ago (8-16-11) at Austin JavaScript I gave a presentation about the basics of JavaScript and jQuery. In case anyone is interested I have made the slides available.
\n", "date_published": "2011-08-23T00:00:00Z" } , { "id": "https://craveytrain.com/posts/db-gone/", "url": "https://craveytrain.com/posts/db-gone/", "title": "DB gone", "content_html": "So, I upgraded the db version on this blog and in doing so, I forgot to backup the comments. I apologize to both of you that lost your comments. Lesson learned, back up the db before I upgrade it.
\n", "date_published": "2011-06-17T00:00:00Z" } , { "id": "https://craveytrain.com/posts/cors/", "url": "https://craveytrain.com/posts/cors/", "title": "CORS", "content_html": "Recently I had to learn a little bit about CORS (cross origin resource sharing). I had sites on different domains I had to get data in between. I like to try to be forward thinking, so when I learned about a better option than JSONP, I jumped all over it. Nicholas Zakas explains is very well on his article about CORS. Like all the other new, fun technologies, it's not supported by all older browsers. So I had to find a way to be forward thinking but have a fallback. What I ended up with is a CORS xhr that falls back to JSONP if CORS is not natively supported.
\nWe are using jQuery on this project so it made it even simpler to do. I used the new $.preFilter to make it even easier.
\n$.ajaxPrefilter('json', function (options, orig, jqXHR) {\n\tif (options.crossDomain && !$.support.cors) return 'jsonp'\n})\n\n$.ajax({\n\turl: 'http://nodeserver:3000',\n\tdataType: 'json',\n\tsuccess: callback,\n\txhrFields: {\n\t\twithCredentials: true,\n\t},\n})\n\nfunction callback(d) {\n\tconsole.log(d)\n}
\nThe prefilter is just taking the dataType attribute, doing a check to see if the request is crossDomain (an internal jQuery property) and if the browser support CORS. If it is cross domain but the browser does not support CORS, it changes the dataType to JSONP. It's really that simple. jQuery does everything else behind the scenes. It takes care of the request, and if XHR, calls the success callback with the response payload of the request. If it's JSONP request, it calls the success callback with the same data as the XHR response passed in as a parameter.
\nI also threw together a sample server:
\nThe server just does a detection for the callback request param (the default request param name used if it's a JSONP request), and if so, it sends the response back as JSONP, using the value of the callback param as the function name and making sure to set the Content-Type
to applicastion/javascript
. If the request is XHR, it gives a Content-Type
of application/json
and sets a header of Access-Control-Allow-Origin
to (preferably) the host making the request. For this example I am using a wildcard. You may not want to do that in a production environment.
If you read the explanation article above, you will notice it says that by default, auth items are not sent over on cross domain XHR requests. Missed that little note? Yeah, I did too the first time. That's why I'm writing this, to help it sink in. So, in the event you need to send over cookies or something along those lines, you just need to add withCredentials: true
to the native XHR object. jqXHR makes that available via the xhrFields
object.
The server just requires 1 more header in the response.
\nAccess-Control-Allow-Credentials: true
\nAnd that's it. I hope this was beneficial to ya. If you have any questions, feel free to lemme know.
\n", "date_published": "2011-06-17T00:00:00Z" } , { "id": "https://craveytrain.com/posts/oauth/", "url": "https://craveytrain.com/posts/oauth/", "title": "OAuth", "content_html": "I had been trying to decide what to do with comments. I like to give the ability to people to make comments but I just did not want to deal with keeping track of people's username, passwords, etc. Furthermore, I absolutely abhor CAPTCHA or anything of the sort. I got to thinking about using something like OpenID. The main problem I have with that is adoption. I don't want to make it hard for people to comment, but I don't want to deal with user info. Then I read Chris Shiflett write about using Twitter for comments and I knew that was the key for me.
\nThere are several popular oauth networks out there but Twitter seems to make the most sense for my audience (both of you) and my subject matter (primarily technical blatherings). So, I set out to learn oauth and use Twitter. Had I known how long it would take me, I might have gone another route. But I'm here with lots of lessons learned and a much stronger understanding of the oauth paradigm. And that is the real reason I rolled my own blog: to give myself the reason to go learn new things.
\nBasically, the oauth process breaks down into 3 major steps:
\nThen it's just the matter of caching that access token (I chose a cookie which I bring into session on the first page load) and requesting the user's pertinent information. Currently, I am grabbing their Twitter screen name, id, url (which I piece together based on the standard twitter user page and their screen name) and their image. I use this information to attribute the comments on the blog.
\nAs for comment contents, I knew I didn't want to bother with whitelisting tags or anything like that, so I just did the simple thing and went with Markdown. I have really come to love Markdown as a simple tool for authoring content. That's what I write my blog posts in. To help the users write in markdown I linked up the syntax reference.
\nWhat I'm particularly proud of is the realtime comment previewer. It shows the author's comment, right in line with the other comments and I think does a good job showing them exactly how their comment will look. Right now this is written as a call back to the server because I haven't found a good client side lib to parse markdown on the fly. Showdown seemed to crap out on < & >. I will look into it some more in the future. But let's be honest, it's not like I have enough commenters right now to really put a strain on my server. Famous last words? I can only hope.
\nObviously I didn't code everything from scratch, cause, that's just loco, ese. For the basic oauth work, I used the excellent oauth wrapper for node.js. I'm still using express for my basic framework with jade for templates.
\nIf you have any comments, questions or concerns, hey, you can voice them now, so feel free.
\n", "date_published": "2011-05-24T00:00:00Z" } , { "id": "https://craveytrain.com/posts/dotfiles/", "url": "https://craveytrain.com/posts/dotfiles/", "title": "Dotfiles", "content_html": "I've been helping some of the guys at work get acclimated to macs and with that, helping them customize their bash prompt. With much thanks due to mschout, I have finally got mine setup more or less how I like it (until I change it again).
\nI want to give a quick rundown of what I am using and why. The code is in my local-config repo on github (with basic install instructions), so I won't go line for line through the configs, just an overview of why I do the voodoo that I do.
\nNo one wants to dupe their code, and your bash prompt is no different. I use iTerm2 as my terminal which does some nifty things, not the least of which is give the ability to open up a new tab at the same path as the previous tab's path. However, when doing this, it will only run the .bashrc file, not the .bash_prompt. The reasons why are beyond the scope of this post but are at least highlighted at server fault. Point being: write your code once, and just call it up.
\nThere are a couple files associated with this feature and a lot more scripts I am not using. This is a pretty sweet little script for allowing tab completion of git commands as well as branch information in your prompt (if you are in a git branch). I took the stock one and adjusted it to color the branch name based on whether it was clean or not. There are other bash_completion scripts, I just haven't gotten around to trying them out yet.
\nI didn't originally have this one in there, but a lot of people started asking me how I had my git setup. So, here's what I have and why:
\nTurn 'em on, all of 'em
\nI like co for checkout, br for branch, st for status and lg for this funky, pretty little log format I found on stack overflow.
\nYeah, I'm lazy, I am using opendiff (aka file merge)
\nTextmate, though I am considering to going back to just using vim or whatever was default
\ninput.
\nThis one sparks some conversation. It's my belief that we should be using lf in the repo, cause that's how Linus intended it. The real issue here is I work with windows developers and occasionally work in windows myself. This will change anything I commit into lf but won't mess with the checkout. So, in theory, I could cause myself a lot of hell on commits of files I changing but it has yet to bite me so far. I know it's just a waiting game.
\nHere is some stuff that only works if you are on a mac, which I am:
\nJust run (or script) growl text
and you'll see a growl notification with text.
Basically instead of delete it now moves to the trash. I'm used to the trash and I want it available on the command line. There is plenty of hard drive space, if it gets full, I'll dump it, but I want the ability to have that buffer.
\nI just setup browser aliases so I could start the main browsers I use from the command line and give it a URL or the more likely scenario, a local file.
\nHere's where the magic happens. All the other files we have been talking about culiminate in here. The top is some basic filler: source the skel bashrc (if it exists) & create some path adding and deleting functions.
\nWe add in paths for the bin directory local to the user for things like the bash_completion scripts. In theory there will be more, but the idea is it's a local bin dir for the user. Also, we add in /usr/local/bin and sbin. I personally subscribe to a lot of the POSIX ideas about where to put things and I like the idea of putting local execution files installed by the user in those directories. I use homebrew and they put their stuff there. I also roll my own nodejs and that goes there.
\nI honestly don't know why this is there. I think it just sounded like something I might need.
\nVIM is better (hence the name).
\nSome really interesting stuff goes on here, and frankly, some if it I'm still just copying and pasting. Basically, I'm telling it to show dirty state, show stashed files, show untracked files and then sending it some colors to shade the branch info from the bash_completion script. I'm setting my basic prompt to:
\nuser@host:/full/path (git branch)\n$
\nNotice the prompt wraps to the second line cause that path can get lengthy.
\nI love me some RVM. I really enjoy working in Ruby and RVM has saved me so much hassle while working on projects and not messing with the local installed ruby versions. Cannot recommend it enough.
\nThat's about it. If you have any questions or find any issues, please reach out to me at the local-config issue tracker. Thanks and I hope y'all enjoy it.
\n", "date_published": "2011-04-27T00:00:00Z" } , { "id": "https://craveytrain.com/posts/relaunching-with-node/", "url": "https://craveytrain.com/posts/relaunching-with-node/", "title": "Relaunching with nodejs", "content_html": "So, over the weekend, I relaunched my blog on Node.js. I tried Tumblr, Blogger, Wordpress (hosted and self), Django, Rails and was just about to rebuild it in Sinatra when a friend suggested I just build it in Node. Of course! Why didn't I think of that?
\nAs for what drove me to roll my own blog when there are plenty of solutions that do it just fine, it was 1 part being anal about URLs (which Tumblr and Wordpress just wouldn't give me the level of control I wanted), 1 part wanting to serve up different types of content (ala Tumblr) and 1 part "why the hell not"?
\nAs for the stack, I'm using Express for the framework, Jade for the templating, Markdown for the content and CouchDB for the document store. I'm using git to deploy to prod with the help of a little post-receive hook. I'm replicating my db locally to my prod box. This provides me with local copies of my site and my data.
\nI have a lot of things I want to do. I have gists I want to find a way to proxy the content for, I want to allow comments and am thinking of using Twitter for my OAuth provider. I want to host links as well as posts, with a nod to Jeremy Keith. Microformats. I love microformats and have none on the site. This will be remedied shortly.
\nI have a lot of things I need to fix. My content propagation isn't as clean as I would like. My design, well, let's just say it needs some love. Unfortunately, I don't know if I am the person who can give it that love. I tried to spend a good amount of time focusing on the readability and the font stack.
\nFor anyone that happens to subscribe to my feed or link to my old posts, I apologize for the constant switching of URLs. One of the big reasons I went to this solution was to solidify my URL scheme. So I hope to be done with that. I will see about putting on some perm redirects for the old URLs.
\nLove it, hate or mildly ambivalent towards it, here it is. I have put both my content and my app on github for all to see. Check it out. I'm interested in your feedback.
\n", "date_published": "2011-04-19T00:00:00Z" } , { "id": "https://craveytrain.com/posts/learning-rails/", "url": "https://craveytrain.com/posts/learning-rails/", "title": "Learning rails", "content_html": "So, I've been doing this Rails tutorial off and on for the last month or so, time permitting. People ask me "Why are you learning Rails?". I tell them it's an easy way for me to get introduced to Ruby. I'm not a proper developer by training. I don't think in the same terms most developers do. I can't just sit down, learn a new syntax and then wield the awesome powers of the new language. I have to relate it to something I know. I know web apps. So Rails teaches me some of the Ruby basics while letting me relate everything back to something I feel comfortable with. Yes, I know there are differing opinions on Rails and there is a bunch of stuff it adds to Ruby that isn't really Ruby itself, but that's ok. It's just a starting point.
\nI usually then get asked "Why Ruby?". Good question. Cause Java pisses me off, the community around C#/.Net is frustrating to me and Objective C is not widely used enough. Ignoring a lot of other cool technologies out there (such as Erlang) that I have on my list to learn as I get a good foundation, the big one people ask me about is Python. I have a love/hate relationship with Python. I won't get into the nitty gritty details, cause honestly, I don't have the chops. Let's just say there are many things about Python I really like and a few I don't. Ruby is intriguing to me. It's shiny and has huge community support.
\nSo, back to Rails. My end goal is to rewrite my blog in something like Rails (or Django if I end up going back to Python). Wordpress is great, and could be extended to do everything I need. However, there is a lot there. A lot I don't need. Plus, honestly, I am drawn to the MVC structure and while PHP can work that way, Wordpress does not, not without extensive hacking. I want little things like having infinite control over my URLs, being able to cache all sorts of data locally and expose out APIs for other services to consume (and consume their services). Basically, Wordpress is too canned and I want something to tinker with.
\nSo, my plan is to get a critical mass on building a blog in Rails and then go from there. I'll keep both of you posted.
\n", "date_published": "2010-12-30T00:00:00Z" } , { "id": "https://craveytrain.com/posts/new-design/", "url": "https://craveytrain.com/posts/new-design/", "title": "New design", "content_html": "Yes, it's that time of the year. Time for me to do another half assed design. This one looks particularly half baked, I know. But this one has rhyme and reason where the others were just laziness. This is still a transitional design, but instead of going naked, I'm going for a few simple design principles and then will fill in the rest as I go.
\nThe main goal of the new design is legibility. Large font sizes, large leading, serif fonts, liquid but liberal measure. Content first, right there on the left. Headline at the top. Content is given the primary position, with nav and branding (or the eventual spot where branding hopes to be) is secondary, out of the way. Granted, it's fixed, so it stays with the user but it's definitely secondary.
\nSerifs are back in. Headlines are in the beautiful slab serif Rockwell. Body text is in the venerable Georgia. Subheadlines and nav went old school with Berthold Akzidenz Grotesk for a little change of pace. This is probably the first font stack I've ever put together I'm truly proud of. I know, it needs a little work in the leading and some of the kerning is erratic depending on browser and OS, but I think in essence, it's solid.
\nI am trying out the golden ratio and a liquid layout. I'm no designer but I like to think I understand the basics. There is something oddly pleasing about the proportions. It just feels right.
\nI struggled with measure. Optimal legibility says it's something like 66 characters wide. I already stated I was going for optimal legibility. But something wasn't sitting well with me. If someone viewed the site in a wide screen monitor there is just so much wasted space. So, I decided to hell with measure. The width is just a raw percentage. If you want to look at this blog in a full width widescreen window, first off, thanks for reading, and secondly, you should have the right to take advantage of all that space. Maybe when I get some content I'll think about capping the measure and doing a more columned approach, but for now, power to the reader!
\nI'm also accounting for the minimum thresholds. I'm using media queries to handle tablet and mobile device layouts. Eventually I'll get around to doing a proper mobile site, but until this media queries will have to work.
\nAnd don't I know it. The site is missing a lot. I took it way, way down. It's more basic than the out of the box template. It doesn't have the archives, it doesn't have search, it doesn't have much of anything other than the blog post content. I'm still playing with all those other things but I thought I would go ahead and launch the new template anyways.
\nSo, I hope you enjoy and I'll be posting updates as I update something worthy of a post (which is honestly a pretty low bar).
\n", "date_published": "2010-12-13T00:00:00Z" } , { "id": "https://craveytrain.com/posts/getting-the-gist/", "url": "https://craveytrain.com/posts/getting-the-gist/", "title": "Getting the gist", "content_html": "I really like Gist, a lot. They are full on git repos and as such have version control, remote updating, all of the things you would expect out of a github repo including most of the social aspects. They also have the best syntax highlighting I have seen. Yes, there are other libs that do it in various languages, but I really like theirs and I like having my code in 1 place.
\nI've made several gists since I have become a member and expect that I will be making more now that I have gotten this down. The main complaint I have with gists is that to embed them in your blog you have to include a script tag that does a document.write. Aside from my misgivings about document.write, this poses a performance and user experience issue. Consider on a blog post with multiple snippets of code, the page stops loading until the scripts are downloaded and executed. Nevermind anything they may clobber during the process. And finally, I end up with a stylesheet in the DOM for each included gist that are all the exact same. So, I did:
\n<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>Gist Fetch</title>\n\t</head>\n\t<body>\n\t\t<h1>Separate Files</h1>\n\t\t<h2>Contact_form.html</h2>\n\t\t<a\n\t\t\tclass=\"gistPlaceholder\"\n\t\t\thref=\"https://gist.github.com/476405#file_contact_form.html\"\n\t\t\t>contact_form.html</a\n\t\t>\n\n\t\t<h2>overlay.js</h2>\n\t\t<a\n\t\t\tclass=\"gistPlaceholder\"\n\t\t\thref=\"https://gist.github.com/476405#file_overlay.js\"\n\t\t\t>overlay.js</a\n\t\t>\n\n\t\t<h2>style.css</h2>\n\t\t<a\n\t\t\tclass=\"gistPlaceholder\"\n\t\t\thref=\"https://gist.github.com/476405#file_style.css\"\n\t\t\t>style.css</a\n\t\t>\n\n\t\t<h1>Combo File</h1>\n\t\t<a class=\"gistPlaceholder\" href=\"https://gist.github.com/476405\"\n\t\t\t>Accessible Inline Form Labels</a\n\t\t>\n\n\t\t<script src=\"http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js\"></script>\n\t\t<script src=\"jquery-gistFetch.js\"></script>\n\t\t<script>\n\t\t\t$(document).ready(function () {\n\t\t\t\t$('.gistPlaceholder').gistFetch()\n\t\t\t})\n\t\t</script>\n\t</body>\n</html>
\n;(function ($) {\n\t// Fetch Gist and drop it into page\n\t$.fn.gistFetch = function (options) {\n\t\tvar opts = $.extend({}, $.fn.gistFetch.defaults, options)\n\n\t\t// Duck punch document.write\n\t\tdocument.oldWrite = document.write\n\t\tdocument.write = $.fn.gistFetch.docOverwrite\n\n\t\treturn this.each(function () {\n\t\t\tvar $this = $(this)\n\n\t\t\t// Support for the Metadata Plugin.\n\t\t\tvar o = $.meta ? $.extend({}, opts, $this.data()) : opts,\n\t\t\t\taURL = this.href.split(/[\\/#]/),\n\t\t\t\tgistId = aURL[3],\n\t\t\t\tfileName = aURL[4] ? aURL[4].substring(5) : '',\n\t\t\t\tgistURL = o.gistURL + gistId + '.js',\n\t\t\t\tsnipId = gistId + fileName\n\n\t\t\tgistURL += fileName ? '?file=' + fileName : ''\n\n\t\t\t// Store a pointer to the gist place holder\n\t\t\t$(document).data(snipId, $this)\n\n\t\t\t$.getScript(gistURL)\n\t\t})\n\t}\n\n\t$.fn.gistFetch.docOverwrite = function (/* String */ markup) {\n\t\t$gist = $(markup)\n\t\t// If the code in the document.write starts with a link and is from gist.github.com\n\t\tif (\n\t\t\tmarkup.substring(1, 5).toLowerCase() === 'link' &&\n\t\t\t$gist.attr('href').match('gist.github.com')\n\t\t) {\n\t\t\tif (!$(document).data('gisted')) {\n\t\t\t\t$('head').append(markup)\n\t\t\t\t$(document).data('gisted', true)\n\t\t\t}\n\t\t\t// If the code in document.write has a class of 'gist' assume it's a gist\n\t\t} else if ($gist.hasClass('gist')) {\n\t\t\tvar gistId = $gist.attr('id').substring('5'),\n\t\t\t\tfileName = $gist.find('.gist-meta a:eq(1)').text(),\n\t\t\t\tsnipId = gistId + fileName,\n\t\t\t\t$link = $(document).data(snipId)\n\n\t\t\t// If the pointer for the gistId and fileName exists (meaning file specfic gist)\n\t\t\tif (typeof $link !== 'undefined') {\n\t\t\t\t$link.replaceWith($gist)\n\t\t\t\t$(document).removeData(snipId)\n\t\t\t\t// Else assumes gist link of whole gist with no fileName specified\n\t\t\t} else {\n\t\t\t\t$(document).data(gistId).replaceWith($gist)\n\t\t\t\t$(document).removeData(gistId)\n\t\t\t}\n\t\t\t// Else just run plain old document.write\n\t\t} else {\n\t\t\tdocument.oldWrite.apply(document, arguments)\n\t\t}\n\t}\n\n\t// default options\n\t$.fn.gistFetch.defaults = {\n\t\tgistURL: 'https://gist.github.com/',\n\t}\n})(jQuery)
\nIronically enough, I made a gist about it. As usual, it's using jQuery (cause that's my fav little DOM manip/XHR lib) and it's just a simple little plugin that looks for links to gists, parses out the gist id and file name (if provided), fetches the gist, and duck punches document.write to replace said link with the code and drop the css file into the head (only once). This is all after DOM ready, so the page will load up just fine, only applying these things after the fact.
\nSo, I know what you are thinking "Whoa, whoa, whoa! Duck punching document.write?!" Honestly, I wish I could have avoided it. I tried various techniques to leave document.write alone but I just couldn't find another way to make it work. Eventually I decided this was the easiest way to do it. I really despise document.write, so I only feel partially guilty about this. That and this plugin was developed for my site. If I don't want you using document.write on my website, well, that's my prerogative. If you use this plugin, know that.
\nFeel free to update or give feedback.
\n", "date_published": "2010-12-10T00:00:00Z" } , { "id": "https://craveytrain.com/posts/character-countdown/", "url": "https://craveytrain.com/posts/character-countdown/", "title": "Character countdown", "content_html": "I had some spare time today, a really nasty plugin I had written for jQuery a while back to do character count downs and a desire to play with the widget factory. Let's get it on!
\nFirst things first, I have give thanks to Adam J. Sontag for showing me the way with the widget factory. I had tried it before but was missing something (namely, the scope of this in event handlers was eluding me). Then I saw an example in Adam's slides. $.proxy!
So that's what that does. He caused my eureka moment, and for that I am grateful (just missed Thanksgivings by a few days, sorry Adam).
Basically on a litany of events it counts the characters in a form field and compares it to the specified max (either a config property or maxlength value). It can do the threshold coloring like twitter does. Actually, it was modeled a lot after twitter.
\nYou can check it out at the GLGUI Toolbox and there is even an example page.
\n", "date_published": "2010-12-06T00:00:00Z" } , { "id": "https://craveytrain.com/posts/prototype-methods/", "url": "https://craveytrain.com/posts/prototype-methods/", "title": "Prototype methods", "content_html": "When I mentioned the GLGUI Toolbox repo I failed to mention some of the content already in it. I'm gonna give a quick rundown of the two prototype methods I contributed.
\nThis is a prototype method from the Date object that just puts the Date out to a string formatted like '10/10/2010 21:15:07'. That's it, nothing special, just was a specific format I needed a lot on a project we are working on so I thought I would share.
\nOk, I'm actually rather proud of this one, which is sad, because it's pretty trivial, but it just works and works well. That is not always the case with my code upon first release. Essentially you call it off a singular version of a string and pass it the integer you are referencing and it will perform some basic plural rules on it.
\nHowever, coding the English language can be tricky, so in observation of that, you can optionally pass it the plural form of the word and that will override the rules in the method.
\n", "date_published": "2010-12-03T00:00:00Z" } , { "id": "https://craveytrain.com/posts/glgui-toolbox/", "url": "https://craveytrain.com/posts/glgui-toolbox/", "title": "Glgui toolbox", "content_html": "As you may or may not know, I work for Gerson Lehrman Group as a UI Engineer. While this is more of my professional site, I don't talk a lot about my work. Truth is, I really dig it here. I work with some fantastic fellow UI Engineers: Garann Means, Zubin Tiku and Chris Bosco (and some others but I don't know their blog URLs, hint, hint).
\nAs you can imagine, we are all big advocates of open source and have been looking for a way to give back to the community at large. So, we started a GLGUI Toolbox repo on Github. So far, it's pretty remedial stuff on it but we hope to start putting out some of our more interesting work in the near future.
\nCheck it out occasionally, watch it, let us know of any issues you find with it or just give us feedback if you think it's useful (or not).
\n", "date_published": "2010-12-02T00:00:00Z" } , { "id": "https://craveytrain.com/posts/back-to-wordpress/", "url": "https://craveytrain.com/posts/back-to-wordpress/", "title": "Back to wordpress", "content_html": "So, a quick note letting you know (in case you couldn't tell) I moved the blog back to Wordpress. I tried out Tumblr because it is very convenient and simple. I wanted something with less upkeep. But the lack of flexibility really started to bother me. It's a great blogging system, but as it turns out, I wanted more features. So, I'm back to WordPress. That is all.
\n", "date_published": "2010-11-30T00:00:00Z" } , { "id": "https://craveytrain.com/posts/austin-metro-init/", "url": "https://craveytrain.com/posts/austin-metro-init/", "title": "Austin metro init", "content_html": "Since Austin has opened up their rail "system" I have really embraced mass transit. I happen to be in the sweet spot of living 3 miles from the park and ride and working 3 blocks from the downtown station. However, I noticed that for Austin being such a tech savvy town, the mass transit mobile app situation is awful. Sure, Google Maps work great if you want to get from one place to another and don't know how to get there, but for people who know the routes and just want to see when the next train is running, you have to go to Cap Metro's site. Their site leaves a little to be desired, especially when viewed on a mobile device. So, I decided to do something about it.
\nThis is by no means a finished product but this gave me the opportunity to play with a few technologies and techniques I hadn't prior. Based on some of the features I am using I made some pretty advanced assumptions on clients. I may very well refactor this to generate more code server side to support more clients and be more accessible, but honestly, at this point, this was fun to do mostly client side.
\nGeolocation is something I have been wanting to play with as a native function of the browser, not relying on mobile device features. It was reasonable cut and dry but it's important to consider that due to being on a mobile device, you may have intermittent connectivity. So you have to feature detect and still do the actual getting of the location inside of a try/catch.
\nI've been reading about pub/sub a lot and have been wanting to try it. I slightly refactored Pete Higgin's jQuery pub/sub to work without a library.
\nI am not currently using a library. Just basic DOM scripting. I'm not handling the IE exceptions right now, and it's glorious. I may or may decide to support IE.
\nI've put it on GitHub for anyone that wants to check it out.
\nIf you want to use the site.
\n", "date_published": "2010-11-22T00:00:00Z" } , { "id": "https://craveytrain.com/posts/resilient-modals/", "url": "https://craveytrain.com/posts/resilient-modals/", "title": "Resilient modals", "content_html": "Modals: Love them, hate them they are a current fad (and have been for a while). Modals are usually implemented via javascript for older browser support (though there are some cool things being done with CSS3 on the matter). I've seen it done lots of ways, but here's a simple way to make modals "work" on a browser without javascript.
\nMake the trigger link link to the hashtag of the id of the modal.
\nSounds too simple, I know. And in truth, that is slightly oversimplified, but given the assumption that the contents of the modal are not dynamic but are known at initial download of the page, this is the most resilient way to make a modal.
\nSince I know that's a little light on the implementation details, lemme throw together a quick code example. For the purpose of this example, we are using jQuery, but apply what ever JS method makes you happy.
\n<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>modals</title>\n\t\t<link rel=\"stylesheet\" href=\"style.css\" media=\"screen\" />\n\t\t<script src=\"http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js\"></script>\n\t\t<script src=\"modal.js\"></script>\n\t\t<noscript>\n\t\t\t<style>\n\t\t\t\t.modal {\n\t\t\t\t\tdisplay: block;\n\t\t\t\t\tposition: relative;\n\t\t\t\t\ttop: auto;\n\t\t\t\t\tleft: auto;\n\t\t\t\t\tmargin-left: 0;\n\t\t\t\t\twidth: auto;\n\t\t\t\t}\n\t\t\t</style>\n\t\t</noscript>\n\t</head>\n\t<body>\n\t\t<p>\n\t\t\tThis is text that <a href=\"#modal\" class=\"trigger\">will link</a> to the\n\t\t\tmodal.\n\t\t</p>\n\n\t\t<div id=\"modal\" class=\"modal\">\n\t\t\t<p>This is the modal, baby.</p>\n\t\t\t<a href=\"#\" class=\"close\">Back to top</a>\n\t\t</div>\n\t</body>\n</html>
\nbody {\n\tmargin: 0;\n}\n\n.modal {\n\tdisplay: none;\n\tposition: absolute;\n\ttop: 0;\n\tleft: 50%;\n\tmargin-left: -100px;\n\twidth: 200px;\n\tbackground: #fff;\n}\n\n#backdrop {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tdisplay: block;\n\twidth: 100%;\n\theight: 100%;\n\tbackground: rgba(0, 0, 0, 0.8);\n}
\n$(document).ready(function () {\n\t$('.trigger').click(function (e) {\n\t\te.preventDefault()\n\t\tvar id = $(this).attr('href').substring(1),\n\t\t\t$modal = $('#' + id),\n\t\t\t$backdrop = $('#backdrop').length\n\t\t\t\t? $('#backdrop').show()\n\t\t\t\t: $('<div>', { id: 'backdrop' }).prependTo('body')\n\n\t\t$modal\n\t\t\t.show()\n\t\t\t.find('.close')\n\t\t\t.text('close')\n\t\t\t.click(function (e) {\n\t\t\t\te.preventDefault()\n\t\t\t\t$('#backdrop').hide()\n\t\t\t\t$(this).closest('.modal').hide()\n\t\t\t})\n\t})\n})
\nAnd before you rail on me, this is proof of concept code. This is in no way considered production ready.
\n", "date_published": "2010-11-16T00:00:00Z" } , { "id": "https://craveytrain.com/posts/git-svn-setup/", "url": "https://craveytrain.com/posts/git-svn-setup/", "title": "Git SVN setup", "content_html": "So I've been using Git-SVN for about a month at work now thanks largely to a gist put together by the magnanimous Lachlan Hardy. Honestly, if you are getting started and have a standard SVN layout, that has all you are gonna need. Naturally, where I work doesn't exactly have a standard layout so I had to adjust the instructions a little bit. I wanted to help explain to others how to handle these other variants I have encountered.
\nWindows users, don't despair, there is hope. However, I encourage you to embrace the command line. TortoiseGit does many features but it leaves you working in a SVN mindset and you don't necessarily know all the functions that are running behind the scenes. Personally, I sometimes use TortoiseSVN for commits and diffs but that's about it.
\nFirst things first, install msysgit.
\nFirst off, let me explain, what you are doing here is creating a clone of the svn repo on your box, in Git. You will be completely autonomous from the SVN repo sending and getting data (or committing and updating using the SVN nomenclature) with a couple commands.
\nFirst things first, create the directory you want your Git repo in and go into that directory. Now open up the the Git Bash in that directory (yes, you can use command prompt, but why on earth would you?) and let's evaluate this command:
\ngit svn init http://svnserver.yourdomain.tld/path/to/specific/project --prefix=appName/ --trunk=Trunk --tags=Tags --branches=Branches
\nYou can probably gather that we are telling Git where the specific SVN structured directories are. The keen among you may notice that --stdlayout or -s would do this for us. Honestly, I have found that flag to be flaky so I like to spell it out. YMMV. Also, others may mention we can run clone, I don't advise this for one major reason, clone does and init and the next command we are going to run (fetch) together. If you have a large repo (which we do) this will take ages. You want to make sure you have your configs setup right before you set that off.
\nNow, you will notice there is a .git folder in this location. Go into that folder and open the config file in the text editor of your choice. It may look something like this:
\n[svn-remote \"svn\"]\n\turl = http://svnserver.yourdomain.tld\n\tfetch = path/to/specific/project/Trunk:refs/remotes/appName/trunk\n\tbranches = path/to/specific/project/Branches/*:refs/remotes/appName/*\n\ttags = path/to/specific/project/Tags/*:refs/remotes/appName/tags/*
\nNow, that's great if you use the standard layout. If you have some variables, you may have to adjust this. For example, we use a directories under Branches for types of branches (Hotfix, Feature, etc). Git won't recursively look for branches in that directory so we have to adjust the config. The line we are looking for is below:
\nbranches = path/to/specific/project/Branches/*:refs/remotes/appName/*
\nSo, for our config, I made a slight adjustment:
\nbranches = path/to/specific/project/Branches/*/*:refs/remotes/appName/*
\nNotice the extra slash and asterisk before the colon. That is basically telling Git to check in all subdirectories of the Branch directory for branches for actual branches but go ahead and bubble them up to the namespace on the right. On to the pain.
\nNow, fetches should be pretty simple. It grabs every checkin in your repo in the directory you specified earlier and commits them into your local Git repo. Now, these are local commits, so they are fast, but if you are like us and have over 140,000 versions in your SVN repo, well, it takes a bit. Takes at bit as in, set it to go for the afternoon or before you leave for the day. The command is simply:
\ngit svn fetch
\nYou can only fetch from a certain record and later if you like. This works great if you don't change the branch you are working out of. You just have to find a version number that has a file change in the directory you are grabbing. So, if you don't care about anything any earlier than version 120,000, you could go grab the most recent version that is commited to the folder you are getting after that and fetch from there. If the first commit to that directory after 120,000 is 120,653 your fetch command would look like this.
\ngit svn fetch -r120653
\nAlas, if you are like us and delete and recreate the branch you are looking for, this does not work very well. Also, the first time you forget to fetch based on that record number, it will go all the way back severely throwing off your workflow. I found it's just easier to get it out of the way to begin with. You have been warned.
\nThat gets you to a working Git repo cloned off your svn repo. That Gist linked up top has a great workflow that I more or less mimic to do my work. And that's basically how I do it.
\n", "date_published": "2010-11-11T00:00:00Z" } , { "id": "https://craveytrain.com/posts/craveytrain-progress-content/", "url": "https://craveytrain.com/posts/craveytrain-progress-content/", "title": "Craveytrain progress content", "content_html": "So, as it makes sense, I'm gonna blog about the progression of my site. First things first, I am working on the content. First, I'm trying to write it. Nothing groundbreaking, but worthwhile, hopefully. The content is structured in HTML5 (hopefully semantically). Basic navigational elements? Check. Pithy Bio? Check. My profiles on other sites? Check. So what's missing?
\nContact form for one. I got tired of fighting the spam battle, so now I just link to my profiles on other sites with social features. If you want to reach out to me and don't already have my contact info, hit me up on one of those networks. They do the hard work for me, so use them for what they are good for.
\nPortfolio. I'm not looking for work. There's not much to show in my portfolio that's particularly groundbreaking. So, it's gone, for now. Maybe it will be back when it's worth looking at. Until then, no need taking up space with it.
\nStill considering adding my twitter feed. Not sure if that brings much value to this site though. Especially since I tweet some of my new blog posts. Just not convinced of the value add.
\n", "date_published": "2010-07-27T00:00:00Z" } , { "id": "https://craveytrain.com/posts/making-inputs-behave/", "url": "https://craveytrain.com/posts/making-inputs-behave/", "title": "Making inputs behave", "content_html": "Anyone who has styled forms understands the frustration that is the input/textarea (or whatever your weapon of choice for masochism). They can be frustrating to make behave consistently. I found a technique I used today that I thought I would share. I seriously doubt I'm the first to use it but none-the-less maybe someone hasn't seen this before.
\nI had always assumed inputs (from here on out, when input is used, assume all inputable form elements) act weirdly. They aren't inline, they aren't block, they are just... weird. While most of us have become accustomed to dealing with this, this can be particularly troublesome making them do things like behave like a block level element but have padding.
\nIn a proper block level element, if you want it to take up the full available width and have padding, it does that by default. Maybe you have to set width: auto. But even when you set an input to block level element, it won't behave like one.
\nCSS3 introduced a nice little property called box-sizing. Essentially with a value of border-box this can make an element behave like Quirks mode in IE. Initially my response to this was "WTF?! Why?!". But this allows you to turn it on for 1 element. 1 element that normally won't adhere to the box model for block level elements. So, without further ado, full width inputs with padding:
\ninput {\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box;\n\twidth: 100%;\n}
\n",
"date_published": "2010-07-26T00:00:00Z"
}
,
{
"id": "https://craveytrain.com/posts/july-austin-js-meetup/",
"url": "https://craveytrain.com/posts/july-austin-js-meetup/",
"title": "July austin JS meetup",
"content_html": "Tonight I made it to my second Austin JavaScript Meetup and I left thinking "Dammit! Why have I been missing these?!" Well, I know why but the point is, I'm there now and plan on making the rest of them.
\nTonight Joe McCann gave a talk (with attempted demo) of node.js. Things went wrong as coding live is often prone to do and we were left with more of an explanation than a demo. Still, Joe's an excellent speaker, engages the audience well and does a good job of keeping the banter going while working through the issues. I've learned the JS group has no lack of banter.
\nAndrew Dupont gave a detailed demo about scripty2, the successor to script.aculo.us with specific highlighting of the trials and tribulations of CSS Transitions. The picture he painted was grim and discouraging for blazing out on your own and doing the CSS Animations yourself. Of course, that's where scripty2 comes to save the day. It normalizes the behavior across all reasonable browsers. It's still in alpha but has some promising merits. I'll be interested to see where this ends up going.
\nAll in all, this was a fruitful meeting and I may break down and present something next month. To be certain, I don't have the polish of these presenters so it's something I will have to give some thought to. We'll see...
\n", "date_published": "2010-07-21T00:00:00Z" } , { "id": "https://craveytrain.com/posts/naked/", "url": "https://craveytrain.com/posts/naked/", "title": "Naked", "content_html": "You may have noticed the new digs. You may have noticed I actually posted something. You may have a noticed a terrible mental visual in your head. Yeah, sorry about that last one. I am starting my blog anew. I have ported over the last few posts that were worthwhile and am primed to get going. However, I made some changes I feel are worth sharing.
\nI am not going to try to scope the content of this blog. That is a mistake I have made several times and it just never works out. This is going to be a blog about whatever I feel like posting about. Tech, personal, photos, videos, quotes, code, whatever. My only rule is the general rule I have about putting things in writing (only do it if you don't mind being quoted on it).
\nI have finally moved off Wordpress. I have used Wordpress for many years and have loved it, but it's time for me to try something new. I like the idea of making my content easily accessible, easily postable and some incidental social aspects to it. So I moved my blog over to Tumblr. However, for blogs about code, code samples and whatnot, I have decided to use GitHub. I like the idea of people looking at the code I have written, being able to download it succinctly, do whatever they want with it and even easily recontribute it to the world. GitHub does all these things very well. However, I want to show code examples in my posts. This is where Gist comes in. I can put files, snippets of files, whatever on their site and just embed them here. Yes, it's a script tag. I'm hoping it won't be too big of an issue, because the convenience for me and I believe for anyone that wants to use the code should be worth whatever compromise I have had to make around progressive enhancement. Github even styles the code for me.
\nWhich brings me to my last point. Style, I have none. Well, more specifically, my blog has none but hey... if the shoe fits... I will eventually style this blog but I didn't want it to get in the way of my content or hold me up. So I have decided to launch the site naked. This will force me to concentrate on markup and content of the site, making sure I have things as appropriate as possible, then layering on the design.
\nSo, here's to hoping I actually stick with it this time. Oh, and stop picturing my site naked.
\n", "date_published": "2010-07-15T00:00:00Z" } , { "id": "https://craveytrain.com/posts/styling-the-stove/", "url": "https://craveytrain.com/posts/styling-the-stove/", "title": "Styling the stove", "content_html": "I would have never guessed I would be blow drying my range out this evening. The cleaning lady came today and while she does a fantastic job, apparently she got the cooktop too wet. When electronic ignitor switches get too wet, they just start igniting. No gas leak, nothing else wrong other than the ignitors were firing. Turns out a little blow dry session dries them all out and it's right as rain.
\nThe thing is, I found this out by Googling for it. I even talked to my dad who is my go to person when I need to know how to fix something and he had never heard of it. I just wonder what would have happened had I not had the internet to figure this out. I suppose I would have paid way too much for a technician to come out and be victim to his or her whim.
\nLong live the internet!
\n", "date_published": "2010-01-22T00:00:00Z" } , { "id": "https://craveytrain.com/posts/accessible-inline-form-labels/", "url": "https://craveytrain.com/posts/accessible-inline-form-labels/", "title": "Accessible inline form labels", "content_html": "Update: Added the check to make sure the input is empty before showing the overlayed label the first time.
\nI recently read Trevor Davis‘ post on inline form labels. First off, I have the utmost respect for TD. I read his blog regularly and have learned a lot from his posts. While I respect the work he has done for his plugin, I approach things differently. I am a UX Architect for a government site so I have significant concerns about accessibility, semantics and progressive enhancement.
\nMy approach differs from him in 2 main facets:
\nThat is not to say my technique is not without issue. It relies on good support of the CSS box model.
\n<form id=\"contact\">\n\t<ul>\n\t\t<li>\n\t\t\t<label for=\"name\">Name</label>\n\t\t\t<input type=\"text\" id=\"name\" name=\"name\" value=\"\" />\n\t\t</li>\n\t\t<li>\n\t\t\t<label for=\"email\">Email</label>\n\t\t\t<input type=\"text\" id=\"email\" name=\"email\" value=\"\" />\n\t\t</li>\n\t\t<li>\n\t\t\t<label for=\"verbiage\">Message…</label>\n\t\t\t<textarea id=\"verbiage\" name=\"verbiage\" rows=\"5\" cols=\"25\"></textarea>\n\t\t</li>\n\t</ul>\n</form>
\nSimple markup, just your basic form. I’m an unordered list guy for forms, but certainly your favorite method of marking up forms should be fine. Except for tables, cause that’s just wrong.
\nform li {\n\tline-height: 1.5;\n\tmargin-bottom: 1.5em;\n\tposition: relative;\n}\n\nform label.overlayed {\n\tposition: absolute;\n\ttop: 0.15em;\n\tleft: 0.5em;\n\twhite-space: nowrap;\n\tcolor: #999;\n}
\nAgain, simple stuff, note the position: relative on the li. That’s sets a bounding box for everything inside of it. Then we are free to use position:absolute for the label (when overlayed). That effectively removes it from layout allowing the inputs to slide left (or up, depending on your form layout).
\nvar oTxtFields = $('input,textarea')\n$.each(oTxtFields, function () {\n\tvar label = $('label[for=' + $(this).attr('id') + ']')\n\tlabel.addClass('overlayed')\n\tif (!$(this).val() == '') {\n\t\tlabel.hide()\n\t}\n\t$(this)\n\t\t.focus(function (e) {\n\t\t\t$('label[for=' + $(e.target).attr('id') + ']').hide()\n\t\t})\n\t\t.blur(function (e) {\n\t\t\tif ($(e.target).val() == '') {\n\t\t\t\t$('label[for=' + $(e.target).attr('id') + ']').show()\n\t\t\t}\n\t\t})\n})
\nNotice the use of the overlayed class. I could just style the labels this way by default, but the whole technique here needs javascript. As a general rule of thumb, I use the same technology to add something as I use to manipulate it. Since I will need JavaScript to manipulate the label visibility, I will use JavaScript to put it in position to begin with. I could have styled the label in a default manner (left of the input, above the input, etc) but chose not to for simplicity’s sake.
\nThis code is relatively simple as well but let me point out a few things. Obviously this is assuming jQuery is loaded. Setting a native object for the form elements saves a lot of processing time. Doing the jQuery lookup every time you reference the object is very expensive. Do it once and store it to an object.
\nMoving on, for each form element set a label variable based on the associated label tag then add the class overlayed to the label. This will position the label inside the form field. Since JavaScript is needed for this technique, we want to initialize the whole thing with JavaScript. You don’t want to end up in a situation where the user has stylesheets capabilities but not Javascript leaving them with an overlayed label and no way to hide it.
\nFinally we add some event listeners for each form field. The first is a focus which does a lookup on the label associated with the field that has focus and hides it using jQuery’s hide method.
\nThe second event listener added is for blur. If, on blur, the form field value attribute is empty we show the associated label using jQuery’s show method.
\nThat’s about it. I hope you found this technique useful. If nothing else, maybe you found this to be an alternative to Trevor’s inline form label technique. If I get enough interest I will look into creating a jQuery plugin for this. Feel free to wholesale reuse this technique. I hardly coined it, I just blogged it.
\n", "date_published": "2009-06-17T00:00:00Z" } , { "id": "https://craveytrain.com/posts/bidet/", "url": "https://craveytrain.com/posts/bidet/", "title": "Bidet", "content_html": "We are back and it was a great, albeit long, trip. It was a beautiful wedding and a blissful honeymoon. However, I have tales to tell. Really, just my perspective on things. Though these aren’t in chronological order, I thought I would start with the story that has been told a couple times already so it has some form.
\n“And here is your bidet” our butler told us as he gave us a tour of our villa. I had heard of a bidet, but I had never actually seen one. See, down in Texas, we uh… just use paper. And admittedly, even in my time traveling, I have never happened across one. I knew what it was for, and honestly, I was curious. I was determined to figure it out.
\nI took a gander at it, it had a hot water knob on the left, a cold water knob on the right and a knob in the middle. Ok, not unlike a shower. There’s a bulbous looking water spout in the bottom of the bowl. It’s like an upside down shower head. Ok, I see where this is going. Or so I thought.
\nAfter dancing around the idea of trying it out for a day or so, the humidity and just perpetual sweating got the best of me. I was gonna give it a shot (no pun intended). So, turn on the hot water, it starts filling up the bowl from the sides similar to how a toilet does when you flush it. Well, I do know what this device is for, and I’m not about to stick my hands down in that bowl. So I add a little cold to try to get a warm water. I turn the middle knob just a bit, to try to get a water fountain effect. Just high enough for me to feel the water without having to dunk my hand in the bowl. Seemed ok.
\nThen I really started to consider how to use this apparatus. I mean, how do you mount this thing? I see the knobs are in the back, do you face the knobs so you have control? But it’s shaped like a toilet bowl, so I sit like I would on a toilet bowl? But that means I have to reach behind me to control the temperature and water pressure. That doesn’t seem natural. Then I really notice something that threw me off and ended up being my demise.
\nThere is no seat on this thing. It’s like a toilet without a seat. Just a porcelain bowl. I have visions of what the toilet bowl can look like in my house with the seat up and decide, there is no way I’m sitting directly on that. It looks clean enough, sure. But still, no way. Turns out, that was exactly what I should have done.
\nSo, I decide to do the chick thing and squat over it. Unfortunately, I forgot to take gravity into consideration in all this. I got into what I thought was position and turned up the water pressure. That’s where things got messy.
\nFirst off, I initially missed. When I say I missed, I mean I was soaking my inner thigh. Just totally missed the important parts all together. Ok, adjust. But wait, why was my calf wet? Crap, I didn’t squat down far enough, the water is running down my leg. And into my shoes. Yes, at my ankles were my underwear, my pants, socks and shoes, now totally soaked. So now I’m reaching behind me, looking for the water pressure knob to turn it off and that is causing me to move and water is spraying everywhere. Both legs, up my shirt, up my nose, even in my hair (turns out I had the water pressure up way higher than it needed to be). By the time I get it turned off, I am completely soaked from head to toe and there is standing water in the toilet room. It’s leaking out under the door and my wife is asking what the hell I am doing in there. Thankfully I had the door locked so she couldn’t come in and see for herself. I went straight to the shower, did not pass go, did not collect $200.
\nSince then I have looked up how to use it and if I encounter one again, I may actually try it again, maybe.
\n", "date_published": "2006-12-06T00:00:00Z" } ] }