Captcha, gone wrong

On a Google site this morning, Captcha:

image

As I have a US English keyboard – I was unable to type the first word. (Anyone know what language that is? I thought Greek at first, but the “n” didn’t make sense.)

I then proceeded to skip through 8 more captcha’s before I found one I could actually recognize. Sigh.

JavaScript: isScrolledIntoView

image

I needed a simple way to detect when a placeholder DIV (that would contain an image) had scrolled into the current viewport of the browser. I’ve seen a few solutions that worked, and a few that didn’t (hello? test your code!). Here’s my simple solution:

function isScrolledIntoView(elem) {
    elem = $(elem);
    var win = $(window);
    var docViewTop = win.scrollTop();
    var docViewBottom = docViewTop + win.height();
    var elemTop = elem.offset().top;
    var elemBottom = elemTop + elem.height();

    var a = (elemTop > docViewBottom);
    if (a) { return false; }
    var b = (elemBottom > docViewTop);
    if (!b) { return false; }
    return !(a && b);
}

Nothing fancy, except it does require jQuery.

When one of the place holder DIVs scrolled into view, the code would trigger a queued load of the image.

SmugMupBrowser-live

As the SmugMug API is poorly designed in a few places, in particular as it relates to showing a thumbnail for a gallery/album, when an album/gallery is scrolled into view, the app loads a list of ALL of the images from the now visible album and selects one of them to show as the thumbnail. It’s extremely inefficient unfortunately. Instead, if they could have included that extra piece of data in the gallery list (thumbnail image and thumbnail image key), boom!

I’ve also included a delay so that the auto loading only occurs after a 1 second pause (either the window being resized or scrolling occurring):

function delayLoadNewVisible() {
    if (visibilityDelayTimerId == 0) {
        visibilityDelayTimerId = window.setTimeout(function () {
            visibilityDelayTimerId = 0;
            loadNewVisible();
        }, 1000);
    }
}

I’m not going to post the code for the other useful aspect of this functionality, but I’ll tell you about it, and leave coding it as an exercise for the reader. Smile

When the user scrolls new albums into view, after the pause, they’re added to a load queue. However, as it’s just as likely that the user will scroll the album off the screen, my load code also can remove something from the load queue if it hasn’t been loaded already. This way, visible albums are given precedence. By using the queue in this way, there are a manageable number of outstanding requests at any given time, and ideally only those that are relevant to what’s on the user’s screen.

Knockout.JS: Dictionary/Index and ObservableArray, Part 2

Ryan suggested an alternative in a comment (and corresponding jsFiddle) to the technique that I’d used in my previous Knockout.JS post.

Following his suggestion, I made a few tweaks to my original function (and renamed it yet again):

ko.observableArray.fn.withIndex = function (keyName) {        
    var index = ko.computed(function () {
        var list = this() || [];    // the internal array
        var keys = {};              // a place for key/value
        ko.utils.arrayForEach(list, function (v) {
            if (keyName) {          // if there is a key
                keys[v[keyName]] = v;    // use it
            } else {
                keys[v] = v;
            }
        });
        return keys;
    }, this);

    // also add a handy add on function to find
    // by key ... uses a closure to access the 
    // index function created above
    this.findByKey = function (key) {
        return index()[key];
    };

    return this;
};

To use, just tag on the withIndex function call:

var ViewModel = function () {
    this.uniqueNumber = 0;
    this.list = ko.observableArray([]).withIndex('id');
};

In the example above, the objects stored in the “list” observableArray will be indexed by the “id” property.

By adding the withIndex function call to the observableArray creation, an additional function is added to the array object, findByKey.

$("#btnAdd").on("click", function () {
    var id = vm.uniqueNumber++;
    vm.list.push({
            id: id,
            time: new Date().toLocaleTimeString()});
    var data = vm.list.findByKey(id);
});

In the above example, a new “log” object is added to the list, and then retrieved by the key a moment later (dumb, yes, but hopefully instructive).

I intentionally added the findByKey only to array instances that include the indexing functionality added by withIndex. One reason was to not have the function be available for all arrays (as it doesn’t work for non-indexed arrays) and the second was that it makes possible a bit of slick JavaScript closure value hiding. This way, the index is never stored anywhere on the original view model. Instead, it’s kept entirely within the closure.

But there’s more!

What if you want to have multiple keys or don’t like the name of the find function?

Here’s the kicked up a notch version:

ko.observableArray.fn.withIndex = function (keyName, useName) {
    /// keyName == the name of the property used as the index
    ///            value.
    /// useName == when false, a function named findByKey 
    ///            is added to the observableArray.
    ///            when true, the function is named based
    ///            on the name of the index property &
    ///            capitalized (like id becomes findById)
    var index = ko.computed(function () {
        var list = this() || [];    // the internal array
        var keys = {};              // a place for key/value
        ko.utils.arrayForEach(list, function (v) {
            if (keyName) {          // if there is a key
                keys[v[keyName]] = v;    // use it
            } else {
                keys[v] = v;
            }
        });
        return keys;
    }, this);

    var fnName = "";
    if (useName && keyName) {
        var cap = keyName.substr(0, 1).toUpperCase();
        if (keyName.length > 1) {
            fnName = cap + keyName.substring(1);
        } else {
            fnName = cap;
        }
    } else {
        fnName = "Key";
    }

    var fnName = "findBy" + fnName;
    this[fnName] = function (key) {
        return index()[key];
    };

    return this;
};

This optionally uses the name of the key parameter to build a findByXYZ function using the pattern of findBy{KeyName}. It also capitalizes the function name to follow typical JavaScript coding conventions. Here it is in when initialized:

this.list = ko.observableArray([])
                .withIndex('id', true)
                .withIndex('time', true);

(note that they’re chained above) … and in use:

var data = vm.list.findById(id);
data = vm.list.findByTime(time);

You’ll see how the “findBy” functions are named “findById” and “findByTime” as the original call to “withIndex” used the optional second parameter set to true. I suppose this follows a tiny bit of the automatic mix-in style of Ruby on Rails (but is optional).

Knockout.JS: AsDictionary

I frequently find that I have an array of objects in JavaScript that I want to display in a particular order and also have the ability to quickly locate an object by an ID or a key (and not use the indexOf function). As my recent project is using Knockout.JS, I decided to throw together a function that makes having keyed lookups based on an array simple to maintain.

Here’s an example ViewModel definition:

var ViewModel = function () {
    this.uniqueNumber = ko.observable();
    this.list = ko.observableArray([]);      
    this.list_by_keys = this.list.asDictionary('id');
};

The definition includes an array, a unique number (more on that a bit later), the list (to which the code will bind the UI to), and finally the keyed list.

After a few attempts at a good name, I settled for something that I hated the least. Smile In any case, usage is simple.

After creating the observable array:

this.list = ko.observableArray([]); 

The code creates a second field which will contain all of the objects in the original array, but in a quickly accessible index (thanks to the nature of JavaScript objects).

this.list_by_keys = this.list.asDictionary('id');

In the preceding line, the asDictionary function (which I’ve added to the observableArray definition as you’ll see below) is used and passed the string ‘id’. The ‘id’ is the name of the property of the JavaScript object that is later added to the list that will contain the key (the primary key, although it’s not checked for duplicates).

As you’ll note below, an instance of the ViewModel is created and bound to the UI.

var vm = new ViewModel();
ko.applyBindings(vm);

$("#btnAdd").on("click", function () {
    var id = vm.uniqueNumber.inc()();
    vm.list.push({ id: id, 
                   time: new Date().toLocaleTimeString() }); });

With a click of a button (using jQuery syntax), a new sample object containing an ‘id’ and ‘time’ property is added to the master list. When the new object is added, the asDictionary code is executed. Why? Because of the use of the computed function as shown below. Knockout.JS has computed observables which automatically track dependencies and execute any time that the source property changes. In this case, it’s tracking the “this” object, which just happens to be the observableArray (list).

ko.observableArray.fn.asDictionary = function (keyName) {
    return ko.computed(function () {
        var list = this() || [];    // the internal array
        var keys = {};              // a place for key/value
        ko.utils.arrayForEach(list, function (v) {
            if (keyName) {          // if there is a key
                keys[v[keyName]] = v;    // use it
            } else {
                keys[v] = v;
            }
        });
        return keys;
    }, this);
};

The function loops through each of the elements of the array and stores each object by the key (if provided, otherwise by the value).  Unfortunately, because there are many ways to adjust an array in JavaScript, this isn’t as efficient as I’d like. Every time something is added to the array, the entire “dictionary” is recreated. While this isn’t terrible in reasonable cases, it’s still a bit annoying. You could add a bit of code to disable the rebuilding conditionally though if performance is going to be a big concern.

I also was experimenting with a unique number generator. It’s really quite dumb, but I ‘m posting in nonetheless.

ko.observable.fn.inc = function (incExtra) {
    incExtra = incExtra || 1;            
    var current = this() || 0;
    current += incExtra;            
    this(current);
    return this;
};

ko.observable.fn.dec = function (decExtra) {
    return ko.observable.fn.inc(decExtra || -1);
};

To use it and retrieve the value, call it like this:

var id = vm.uniqueNumber.inc()();

imageThe odd syntax calls the inc (increment) function which returns the original object (in support of chaining). Then, to get the value, it calls the properties’ getter function (the second set of parentheses).  (As I said, it was just messing around).

The HTML for the data binding looked like this:

<div class="log" data-bind="foreach: list" >
    <div class="item">
        <span data-bind="text: id" class="id"></span>
        <span data-bind="text: time"></span>
    </div>
</div>

Some code from SnugUp.Browser (an album browser for SmugMug)

I’ve been doing some tinkering recently with SmugMug again.

Through testing SnugUp for the past 4 years, I’ve made quite the mess of my SmugMug account. Literally hundreds of poorly organized and often completely junk albums. I’ve been wanting to clean it up, but SmugMug’s UI for that is so obnoxiously slow and tedious that I decided I wanted to write a tool to make it easier to manage.

Admittedly, given the amount of time I’ve spent on writing the tool (which I’m not yet finished with), I could have cleaned up my SmugMug account dozens of times. However, with my developer hat on, I thought, how fun would that be? Smile

 

image

So, I’ve started to create the SnugUp.Browser. It’s a bit of an interesting beast in that it is a Windows application that hosts a web browser to display its UI. I’d tried using WPF/XAML and just couldn’t get the look I was wanting in a reasonable amount of time and effort.

<RANT>WPF desperately needs a VirtualizingWrapPanel. Microsoft needs to ship it. </RANT>

So, I created a WinForms project to host the IE Web Browser. (Arrgh, the WPF WebBrowser sucks still. It’s not nearly as feature complete as the one from WinForms!). Internally, the web pages are served via an HttpListener.

try { int portSuggest = GetAvailablePort(); portSuggest = 40000; _listener.Prefixes.Add(string.Format("http://localhost:{0}/", portSuggest)); _listener.Start(); while (maxConnections-- > 0) { _listener.BeginGetContext(HandleRequest, _listener); } } catch (Exception ex) { Debug.WriteLine(ex); }

The HandleRequest method responds in two ways:

  1. Respond with JSON data (as if it were a web service). 99% of the code needed to access SmugMug’s APIs was already written in a C# library I wrote for SnugUp.
  2. Respond with binary data, providing a “proxy” to a service. This was needed to handle downloading images from the application. When the request was directly made from the WebBrowser to SmugMug, it was refused as the http-referer header was not a valid source apparently (SmugMug didn’t like “http://localhost:####” as the referrer.
resourceRequested = context.Request.Url.LocalPath.Replace('/', '.'); if (resourceRequested.StartsWith(".")) { resourceRequested = resourceRequested.Substring(1); } Debug.WriteLine(string.Format("Requested: {0}", resourceRequested)); using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(string.Format("SnugUp.Resources.{0}", resourceRequested))) { if (stream == null) { //context.Response.StatusCode = 404; if (url.LocalPath.StartsWith("/proxy")) { var proxyUrl = url.Query.Substring("?url=".Length); extension = Path.GetFileName(proxyUrl); try { WebClient client = new WebClient(); byte[] buffer = client.DownloadData(proxyUrl); context.Response.Headers.Add("Expires", DateTime.UtcNow.AddDays(30).ToString("R")); context.Response.ContentType = GetContentType(context, extension); context.Response.OutputStream.Write(buffer, 0, buffer.Length); } catch { context.Response.StatusCode = 404; } } } else { string contentType = GetContentType(context, extension); context.Response.ContentType = contentType; stream.CopyTo(context.Response.OutputStream); } // Close the Response to send it to the client. // } }

If the resource can’t be found as an Embedded Resource, it tries a proxy.

I built a tiny router for the web services so that I could easily plug-n-play new functionality:

public virtual object Route(string path, dynamic data) { if (path.StartsWith("/")) { path = path.Substring(1); } var paths = path.Split('/'); if (paths.Length > 0) { var controllerName = paths[0]; var controllerType = Type.GetType(string.Format("SnugUp.Controller.{0}Controller", controllerName), false, true); if (controllerType != null) { var instance = InitializeControllerInstance(controllerType); // default? if (paths.Length > 1) { MethodInfo method = controllerType.GetMethod(paths[1]); if (method != null) { try { object results = method.Invoke(instance, new object[] {data}); return results; } catch (Exception ex) { Debug.WriteLine(ex); } } } } } return null; }

It just looks up a request dynamically, maps to a method, and calls it (the response is eventually serialized as JSON).

For UI, I’m currently using Bootstrap (although that may be removed), Knockout.JS, and jQuery. I’m doing a bit of trickery to make sure that only what’s visible on the screen is loaded (even when the user scrolls up and down … it’s pretty smart).  I’ll likely post more about that in a future update.

The app is becoming larger… and bloated a bit when compared to my original needs. Smile

 

image

It now can show the images from the gallery as well. Smile

image