This JavaScript bookmarklet will enhance the macro target section of the custom goal editor  in MyFitnessPal with some advanced features that allow you to set up a more complex macro strategy.

Features:

  • Set percentages in 1% increments
  • Set targets in grams rather than percentage
  • Set one of the three macros to  automatically fill any remaining calories in your daily goal that are not allocated to the other two macros
  • Remember your advanced settings as long as you do not overwrite your changes with the default MFP 5% scheme

Screen Shot 2013-08-13 at 9.22.29 AM
Example - Specify protein in grams, fat as a percentage, fill remaining calories with carbs

 

How To Install The Script

 

The script is available as a userscript for use in browser extensions like Greasemonkey (for FireFox) and Tampermonkey (for Chrome). Running like this, the fix is always there, even after you update, and you never have to manually run anything. You can install the script here:

http://karoshiethos.com/js/MFP_Macro_Fix.user.js

Internet Explorer and Safari users need to add the bookmarklet below to their bookmarks. When you are on the MyFitnessPal custom goal screen, click on the bookmark, and the form will be enhanced with these features. After you save your changes, the form will revert back to the default 5% increments, but your gram counts will be correct. The mobile apps will display your chosen percentages and grams properly. You will need to click the bookmark each time you want to change your macros.

Internet explorer users, right click the link in the blue box below and click "Add to Favorites". Safari users, drag the link up to your bookmarks bar.

 

MyFitnessPal Macro Enhancements

 

 

How does it work?

The script is a small JavaScript class that adds components and logic, and integrates with the existing logic in the custom goals screen. When you are finished with your changes and submit the form, the grams for each macro are translated into high-resolution percentages (Example: Carb=44.56666666666666%, Protein=30.533333333333335%, Fat=24.9%), which are saved exactly the same way the default 5% increment percentages would be. MyFitnessPal will round the percentages to the nearest 1% when displaying percentages on the website and in the mobile apps, but they appear to use the high resolution percentages for calculating grams. In my testing, the gram counts always come out as specified.

I’m not sure why this functionality is not already available in MyFitnessPal, I think most users who are serious about their diet probably set up their macros by the gram, or in some combination of grams and percentages.

This is a quick fix I put together in my spare time. It may have bugs. If so, I may or may not fix them. I have tested this in Chrome, Firefox, Safari, and IE10 and 11 - it may not work in IE6, IE4 for Mac, NCSA Mosaic, Lynx, etc. in other words, if you are not running an up to date browser, YMMV. If you need help and your questions are not already answered in the comments, you can find me on Twitter at @robruchte or email me at rob.ruchte@gmail.com

,

HTML5 Portfolio Project – Part 5

When I start a project, I like to tackle the parts that are new to me first. Obviously, I enjoy the dopamine hit from exploring something unfamiliar, but also, I've found that this is a great way to catch "gotchas" early, rather than waiting until the end when work-arounds might require substancial changes to parts of the code that would otherwise be more pedestrian.

With that approach in mind, I've spent a ridiculous amount of the last couple weeks hacking on a circular mask transition effect. I'd gotten this to work fine in the past for image content, but I wanted to be sure it would support other types of content too—a video player for instance. Ideally, I'd end up with a jQuery effect that could handle an arbitrary <div>. It should work on the latest version of any browser (and degrade gracefully in IE7/8).

This has proved itself a challenge several orders of magnitude larger than I'd expected.

The Big Deal

Perhaps the HTML spec isn't as clear as it ought to be: if you specify overflow: hidden, the clipping region should take border-radius into account. Firefox and IE9 do. That leaves a whole lot of everything else. As long as your content is an image, you can apply a border-radius to that, and the clipping looks OK as long as the image is square (IE7/8 notwithstanding). But you can't properly offset the image in its container (we'll get to why we need that eventually) unless you apply the image as a background.

In the interest of moving forward, I'm going to use the background-image technique, but that isn't going to help for videos etc. I also evaluated webkit-mask-image (webkit-only obviously) and using a canvas buffer (doesn't seem to work in Safari). Now, if you're paying attention, a combination of all-of-the-above would let us support all browsers, but I'm calling "scope creep" and deferring this to version 1.1. In the meantime, I'll probably use a lightbox for videos.

It hasn't been a complete waste. On the contrary, I learned quite a bit about CSS PIE and ExplorerCanvas.

Schedule

Speaking of which, multiple commercial projects are conflicting with my original release schedule. June 1 is going to come and go, so I'm setting a new goal of July 1.

I'm not doing so well keeping to the hourly budget either. I burned through the original estimate just trying to get this effect working (everywhere). I'd originally estimated 3 hours and spent closer to 30. Ouch!

Like I said, warts and all.

Stay Tuned

Next time I'll show the sunburst background (a canvas-based effect) and the aforementioned circular mask (of doom) with compound borders. I already have this working, but I want to clean up the code before doing a write-up.

 

I wanted to share some quick notes on how to get JavaScript code assist "working" under the latest version of Aptana Studio.

Note: As far as I can tell, this feature is very buggy, and as such, YMMV.

There are three features that I find particularly desirable:

  • Jump-to-definition: A Command-Click opens the file to the location where the highlighted function (etc) is defined. Probably the most important / useful.
  • Code-completion: a drop-down of possible entries appears as you type / upon pressing Control-Space.
  • Code-hints: Class constructor and method signatures appear as you type / upon mouse hover, displaying helpful information about method signatures & parameters.

Sounds pretty awesome, huh? Too bad it doesn't work as advertised. Let's talk about what's busted.

  • The SDocGen tool only seems to catch classes that are defined globally, so if you're organizing your functions (as you should) into requirejs define calls (for instance), your comments won't get picked up.
  • Using a @return tag inside a constructor function will seem to work ok, but it tramples the class's method definitions, so I avoid it in that context. The same @return tag inside method functions doesn't seem to have this issue.
  • The opening documentation tag is "/**" (Note: that's 2 asterisks). The closing documentation tag is "*/". Nothing else seems to work.
  • I've seen code hints (eg for google maps) that seemed to work using the object-literal syntax. I never got this to work. Lucky for me, I don't define my classes that way.

That first bullet is nearly impossible to work around, and I eventually quit trying. Instead, I hacked around it by appending the following structure to the bottom of my file:

if (false)
{
  MyClass = function (xyz)
  {
    /**
      Documentation here
      @param {String} xyz This text appears as a hint while you enter the xyz parameter
    */
  }
  
  MyClass.prototype.method = function ()
  {
    /**
      Method documentation here
      @return {Number}
    */
  }
}

Unfortunately, that means repeating yourself a bit, but everything seems to work. The "if (false)" pattern keeps this code from executing at runtime, but SDocGen will pick up your comments for documentation. When you Command-click (I'm on OS X) a class or method name in your code, it will jump to the first occurrence in the definition file, ie the correct one. Provided you're defining one class per file, you shouldn't have any collisions.

I discovered that a limited set of HTML tags are supported. I've had success with UL/LI, STRONG, EMPHASIS, BR, TABLE/TR/TD. I was even able to get a simple style-sheet to work, but that was nearly useless. The only thing that worked reliably was colors, and it was necessary to omit the '#' from my hexadecimal colors. HTML did not work for method-parameter pop-up help. I'll probably avoid this feature for now.

SDocGen is available on github; maybe someone can fix it?

Good luck!

HTML5 Portfolio Project – Part 4

I'm structuring the project folder like this:

/portfolio
  /deploy
    /css
    /img
      /icons
        /link.png
        /video.png
        /pic.png
    /js
      /framework
      /lib
        /jquery.js 
   
    /background.png
    /index.html

    /contact
      /thumb.png
      /bio_contact.html
    /projects
      /project1
        /thumb.png
        /video.html
        /description.html
      /project2
        /thumb.png
        /video.html
        /description.html
    
  /src
    /project1
      /video

  /notes

If your information architecture is tight, you'll likely see echoes of your file hierarchy in your data hierarchy and echoes from both in your code's object hierarchy. Guess that means we're going to need some code then.

Stay Tuned:

In the next installment, we're going to spend a little time playing with jQuery-based animation so that we're comfortable with it before trying to integrate the effect into the site itself.

HTML5 Portfolio Project – Part 3

Don Your Project Manager Hat

A week with no updates?! ... And things are about to get more busy, not less.

Plus, upon reviewing the project plan, I noticed an omission: there's no specific line item for the mask transition. It seemed so obvious, I neglected to capture it in the schedule. I'm adding 3 hours to account for it (new total: 44 hrs).

Ok, To Work Then

Last time, I talked a bit about the data model. Since then, I've thought of some improvements. Just because the Flash version worked a certain way doesn't mean I shouldn't re-evaluate my assumptions.

First, the home screen ought to be treated as a node. It has a url and graphical content, just like the portfolio pieces. It's button-ness behaves a little differently, and it's sized larger, but we should be able to abstract away the differences. In theory, it would be nice to allow unlimited node nesting. This would allow projects to have sub-projects (for example) and enable a lot more organizational flexibility, extending the useful lifetime of the site. We'll see if we can squeeze it in. (Google: YAGNI)

[
  {
    "url"         : "/",
    "title"       : "shovemedia portfolio 2012",
    "content"     : "homepage.html",
    "sections"     : [
          {
            "url"         : "contact",
            "client"      : "Email:<br />jon@shovemedia.com",
            "title"       : "contact info",
            "date"        : "01/01/2011",
            "role"        : "developer",
            "link"        : "mailto:jon@shovemedia.com?subject=New Business",
            "thumbnail"   : "thumbnails/email.jpg",
            "content"     : "contact.html"
          },
          {
            "url"         : "3D",
            "client"      : "Photobiz",
            "title"       : "3D Templates",
            "date"        : "01/01/2011",
            "role"        : "developer",
            "link"        : "http://photobiz.com",
            "thumbnail"   : "thumbnails/3d-templates.jpg",
            "sections"        : [
                    {
                      "url"     : "video",
                      "title"   : "watch!",
                      "icon"    : "video",
                      "content" : "papervision/videoPlayer.html"
                    },
                    {
                      "url"     : "image1",
                      "title"   : "Image 1",
                      "icon"    : "pic",
                      "content" : "papervision/image1.jpg"
                    },
                    {
                      "url"     : "description",
                      "icon"    : "description",
                      "content" : "papervision/description.html",
                    }
                  ]
          }
        ]
  }
]

Don't get lost in the braces. Deeper nesting is a necessary evil, I think. Otherwise, I'm going to end up with redundant references to "link" all the flattened elements.

I've also changed some of my naming conventions. Each nodes stores its child nodes in an Array called "sections".

HTML5 Portfolio Project – Part 2

Jump to Part 1 here.

Today, we're going to define the data format for our portfolio. Back in 2005, XML was the last data format we were ever going to need, so that's what I used. It must have been second-to-last, because today, everyone seems to prefer JSON. I'm more than happy to commiserate about the pros and cons over beers sometime, but I've moved on. We're doing this in JSON. Afterall, the portfolio is going to be driven by JavaScript; I doubt much justification is warranted.

Don Your Information Architect Hat

A portfolio is a list of projects. Each project has a bunch of properties like a title and a URL. Each project will also have some media (like pictures and/or video) and a brief, text-based description.

Here's what I came up with originally:

  • client - eg. Microsoft
  • title - eg. Micro-site
  • description - eg. "Lorem ipsum..."
  • date - eg. January 2011
  • role - eg. developer
  • link - eg. http://microsoft.com/someMicroSite
  • thumbnail - eg. thumbnails/3d-templates.jpg
  • media - eg. microsite/image1.jpg, microsite/image2.jpg, microsite/image3.jpg, microsite/video.mov

All fairly straight-forward, I hope.

I did over-simplify the items in the media section. In order to make this work, we need to know a little more than just what URL has the media.

  • title - eg. Image 1
  • icon type - eg. pic / video
  • content - eg. microsite/image1.jpg

Turning all of this into JSON should be easy. First, double-check to make sure our names make sense and are consistent. ... Then, we need to decide whether it makes sense to encode items with more than one value as an Array or as an Object (hash). There are two spots in this project where this comes into play. One should be obvious. Can you spot the second?

  1. The list of projects
  2. The list of media belonging to each project

Above all else, it pays to be consistent. The two items above are similar enough that, whether we choose to store them in an Array or an Object, we'll probably want to use the same approach for both.

Array is Best

You'll want to use an Array when you have a list of things and their order matters. We want to display projects in a specific order, so let's use an Array. That was easy! Wait...

No, Object is Best

You want to use an Object when you have a list of things and the order doesn't necessarily matter, and each item can be identified by some sort of unique key. An Array (a type of Object afterall) often does this automatically. It uses numeric keys.

Come to think of it, each of our projects will be accessible via a unique URL. And, hey, the media items will have URLs as well. But wait, we didn't show "url" anywhere in our list of properties. Where should it go? If I use an Object to store my list items, I could use the URL fragment as the key, or I could go back to the Array (preserving the order of my list) and add a "url" property to each item...

Just Pick One Already

Hopefully you're starting to see that there's no one right way to do this. I want to be able to control the order of my items, but I also need to access each item by a unique key (its URL). Here's a sample of what I think my data will look like (so far).

[
  {
    "url"         : "contact",
    "client"      : "Email:<br />jon@shovemedia.com",
    "title"       : "contact info",
    "description" : "content/contact.html",
    "date"        : "01/01/2011",
    "role"        : "developer",
    "link"        : "mailto:jon@shovemedia.com?subject=New Business",
    "thumbnail"   : "thumbnails/email.jpg",
    "pics"        : []
  },
  {
    "url"         : "3D",
    "client"      : "Photobiz",
    "title"       : "3D Templates",
    "description" : "content/3d.html",
    "date"        : "01/01/2011",
    "role"        : "developer",
    "link"        : "http://photobiz.com",
    "thumbnail"   : "thumbnails/3d-templates.jpg",
    "pics"        : [
            {
              "url"     : "video",
              "title"   : "watch!",
              "icon"    : "video",
              "content" : "papervision/videoPlayer.html"
            },
            {
              "url"     : "image1",
              "title"   : "Image 1",
              "icon"    : "pic",
              "content" : "papervision/image1.jpg"
            }
          ]
  }
]

Most of this is identical to the XML format I've been using. I've introduced one small change for the "description" field. Rather than trying to embed HTML within a JSON document (and spending a tutorial or three to explain it), I'm going to place that in an external document and load it on request. That's "lazy initialization" for the initiated.

Stay Tuned:

In the next episode, we'll decide how best to organize everything into folders at the file system level. If you take a close look at the JSON above, you'll should be able to spot a hint or two in some of the example values that contain file paths.

HTML5 Portfolio Project – Part 1

Introduction

I built a Flash-based portfolio back in 2005. It was itself a nice example of the kind of work that kept new projects coming: back-button & bookmarking support, raw content visible to Google & non-Flash browsers, Google Analytics tracking, easily updatable via an XML file, etc. All at a time when most people believed it couldn't be done. For better or worse, it's functional enough that it still drives my portfolio today.

In the seven years since, browsers have done a great deal to catch up. Canvas, web fonts, and CSS enhancements have expanded the possibilities so that I'm confident I can rebuild the whole thing in HTML5. I still get compliments on the minimalist design, and I think I'd get even more if it worked on iPads and iPhones. ;)

This move is long overdue, and I've decided, not only does it make sense to open source the final template, but there's value in letting you follow my process. I will make mistakes, but I'll probably learn something from them, and in turn, so might you.

The Plan

We won't be doing any coding today. Instead, I'll start where all projects ought to start: with a plan. The numbers in parenthesis represent the estimated number of hours required.

  • (1) Project Plan
  • (1) Define JSON format
  • (1) Assemble project file structure
  • (4) Scale transition
  • (4) Navigation
  • (4) Canvas-based Tooltip
  • (6) Text in circle
  • (3) Media Player (video)
  • (2) Background gradient effect
  • (4) Preloader animation
  • (1) CSS / media queries
  • (1) Google Analytics integration
  • (1) Fonts (Typekit?)
  • (8) Bug Fixes

Total: 41 hours

These estimates don't include the time required to write up the accompanying blog-posts or answer your questions. That's probably another 15-20 hours. In addition, I usually multiply my initial estimate by two to account for the Murphy-factor. Also, I've got three other projects right now, and this isn't the most important, so it's going to take a lot longer than a week. Let's schedule launch for June 1st, that sounds nice, doesn't it?

Stay Tuned:

In the next episode, we'll define a JSON format for each project in our portfolio and start thinking about how those will get transformed in to richer JavaScript structures and HTML elements.

Automatic Value-Object Mediation with JS Signals

Just a little something I cooked up tonight after a few beers with Lee:

ModelMediator = function (model) {
  this.__onChanged__ = new Dictionary();

  for (var key in model)
  {
    this.__defineSetter__(key, function (arg) { this.set(model, key, arg) });
    this.__defineGetter__(key, function () { this.get(model, key) });
    this.__onChanged__.set(key, new signals.Signal());
  }
}

ModelMediator.prototype.get = function (model, key)
{
  return model[key]
}

ModelMediator.prototype.set = function (model, key, value)
{
  model[key] = value;
  this.__onChanged__.get(key).dispatch({model:model, key:key, value:value});
}

Dictionary class here

Downloading and understanding JS Signals is left as an exercise for the reader.

Dictionary Class (JavaScript / JS)

I sorely miss the Dictionary class from AS3, but wasn't excited by what my Googles led to and figured I'd learn more by rolling my own.

JavaScript Arrays can be used as a hash, but only with String or Numeric keys. This class lets you use any Object. A function, an Array, a class ... anything. It could be faster, among other possible improvements, but this implementation has been coming in handy all over.

Dictionary = function ()
{
  this.keys = [];
  this.values = [];
}

Dictionary.prototype.get = function (key)
{
  var index = this.keys.indexOf(key);
  if (index != -1)
  {
    return this.values[index];
  }
}

Dictionary.prototype.set = function (key, value)
{
  var index = this.keys.indexOf(key);
  if (index == -1)
  {
    this.keys.push(key);
    index = this.keys.length - 1;
  }

  this.values[index] = value;
}

Dictionary.prototype.remove = function (key)
{
  var index = this.keys.indexOf(key);
  if (index == -1)
  {
      return undefined;
  }

  var value = this.values[index];

  delete(this.values[index]);
  delete(this.keys[index]);

  return value;
}

Removing Trace and Logging Statements for Production

I'm saving these recipes here so I can bookmark, and I'm sure someone else will find them useful.

I decided to convert calls to trace or my logging framework to use conditional compilation so that they won't be included when I do a production build, but are included when I do a debug build.

The Flex compiler supports this by allowing you to set a variable at compile-time, eg:

-define=CONFIG::debug,true

In your code, simply wrap the code to be conditionally compiled in curly braces, prepended with this variable, eg:

CONFIG::Debug
{
	trace( 'Debug' );
}

I spent some time writing a regular expression that finds trace statements, and wraps them in this block. In plain English, start at the beginning of the line, match zero or more whitespace, the word "trace", zero or more whitespace, an open parenthesis, the rest of the line.

Search for: ^([ \t]*)(trace[ \t]*\(.*)$
Replace with: $1CONFIG::debug { $2 }

FDT's internal parser doesn't like the conditional compilation syntax, so we need to change our replacement text slightly to wrap that part in markers instructing it to ignore them.

Search for: ^([ \t]*)(trace[ \t]*\(.*)$
Replace with: $1/*FDT_IGNORE*/ CONFIG::debug /*FDT_IGNORE*/ { $2 }

The same recipe for any call to logger, eg: logger.debug, logger.info, logger.warn, etc.

Search for: ^([ \t]*)(logger\..*)$
Replace with: $1/*FDT_IGNORE*/ CONFIG::debug /*FDT_IGNORE*/ { $2 }