Showing posts with label jQuery. Show all posts
Showing posts with label jQuery. Show all posts

Wednesday, 13 November 2013

Developing the Oxford Dictionaries Quick Search app

    Well here we are after what seems like an age of tweaking, the Oxford Dictionaries Quick Search app is finally available for installation. It can be found on the iTunes website here, and on Google Play here. The Windows Phone 8 version should with luck be out in a few days.
    As the developer of course I'm going to say it's a brilliant app, but that would verge on shameless astroturfing. What I can say is that it's a simple and lightweight free English dictionary look-up app that I hope users will find useful.
    Under the hood, it's a client for the Oxford Dictionaries API. This of course means that it requires a data connection to run, but does give the advantage of the app taking very little space and providing the most comprehensive and up-to-date dictionary entries. Though it's hardly a novel use for the API it does demonstrate the functionality and speed of the service, as well as the ease with which the API can be developed against.
    The app uses the PhoneGap cross-platform HTML5 app framework with jQuery and jQuery Mobile providing the Javascript heavy lifting and user interface respectively. These packages have allowed us to deploy the app on three platforms in quick succession with minimal investment, something we could not have done had we been required to write all three versions natively. The quirks of the different HTML5 implementations have caused us a few headaches along the way, but not significantly more than web developers are used to when dealing with different browsers.
    It's been interesting to compare side-by-side the ease of development on the different mobile platforms. Android is the easiest as you'd expect, but with a Wild West of devices and OS versions out there it needs to be. We've been scouring our colleagues for odd Android versions and form factors to try our app on, yet I'm sure we've not tried them all. In particular we decided that with 25% or thereabouts of the Android market we couldn't abandon support for version 2.3, so we've had to contend with its incomplete font support and sometimes shaky HTML5 implementation.
    iOS by comparison with a set number of devices should be easy to develop for but starts to become more effort due to the stringent demands of Apple. Attaching different iOS devices to our development environment can at times be a challenge, and the ballooning demand for supporting resources such as splash screens, icons and screenshots for different resolutions and OS versions sometimes feels as though it is getting out of hand. However the App Store approval process was much quicker than we expected it to be.
    The Windows Phone 8 development environment shows Microsoft's typical attention to detail. The supporting resource requirements are well-thought-out, getting the app on a device is straightforward, and the free version of Visual Studio is a delight to use. However the fact it would only run on 64 bit Windows 8 seems rather strange, and Microsoft have not quite shed their reputation for quirky HTML environments. I didn't expect the problem we had with an animated GIF loading spinner, for instance.
    So it's been an interesting experience. I'd recommend PhoneGap to anyone wanting quick development of multi-platform mobile apps, though it's provided a few learning experiences of its own.

Tuesday, 5 November 2013

Fixed jQuery Mobile footers on Windows Phone 8

    Here's a solution to something which baffled me for a while: making a jQuery Mobile footer that stayed at the bottom of the screen and didn't scroll away with the content in a PhoneGap app on Windows Phone 8.
    jQuery Mobile is usually pretty good at making fixed footers. The code below works fine on Android, using data-role and data-position attributes on the footer div.

<body> 
<div id="container" data-role="page" data-theme="f">
    <div id="header"  data-role="header" data-position="fixed" data-tap-toggle="false">
    Header content here
    </div><!-- /header -->

    <div id="content" data-role="content">
    Page content here
    </div><!-- /content -->

    <div data-role="footer" data-position="fixed" id="footer" data-tap-toggle="false">
     Footer content here
    </div><!-- /footer -->
</div><!-- /page -->
</body>

    Unfortunately, on Windows Phone 8 it places the footer at the base of the screen but does not allow the content to scroll underneath it. Thus your footer scrolls up the screen with the content, hiding a bit of content as it goes and looking really horrible.
    You might think breaking out of jQuery Mobile by losing the data-role and data-position attributes and then applying a fixed position and a z-index to your footer would do the job. After all, it's the standard fix for some of jQuery Mobile's footer quirks on iOS. But sadly all that does on WP8 is anchor the footer to the bottom of the page rather than the bottom of the screen, resulting in a long scroll to see it. Less obviously broken, but still not what we want.
    My solution then was to apply a fixed height to the content div and allow the default WP8 overflow:auto; CSS to make its content scroll out of sight beneath it. I removed the data-role and data-position attributes from the footer and used a little piece of javascript to calculate the height of the content div from the heights of the surrounding divs and set it. Not necessarily the most elegant solution, but one that should reliably work across a range of devices.

<body> 
<div id="container" data-role="page" data-theme="f">
    <div id="header"  data-role="header" data-position="fixed" data-tap-toggle="false">
    Header content here
    </div><!-- /header -->

    <div id="content" data-role="content">
    Page content here
    </div><!-- /content -->

    <div data-role="footer">
     Footer content here
    </div><!-- /footer -->
</div><!-- /page -->
<script>

//NB the code below references jQuery, not included in this HTML for simplicity

var headerSpace = parseInt($('#header').css("height")) + parseInt($('#header').css("marginTop")) + parseInt($('#header').css("marginBottom")) + parseInt($('#header').css("paddingTop")) + parseInt($('#header').css("paddingBottom"));

var contentSpace = parseInt($('#content').css("marginTop")) + parseInt($('#content').css("marginBottom")) + parseInt($('#content').css("paddingTop")) + parseInt($('#content').css("paddingBottom"));

var footerSpace = parseInt($('#footer').css("height")) + parseInt($('#footer').css("marginTop")) + parseInt($('#footer').css("marginBottom")) +
parseInt($('#footer').css("paddingTop")) + parseInt($('#footer').css("paddingBottom");

var contentHeight = window.innerHeight-headerSpace-contentSpace-footerSpace;


$('#content').css("height", contentHeight + "px");

</script>
</body>

    I hope this helps put you on the right path. There seems to be frustratingly little documentation out there on what WP8 does and does not support, and on workarounds for what seem to be common problems. With luck this fix has plugged one such hole.

Wednesday, 15 February 2012

An AJAX and jQuery driven web feature, the OxfordWords Text Analyser

    If you are a follower of the OxfordWords Blog, you may have seen the launch of the OxfordWords Text Analyser, coinciding with the 200th anniversary of Charles Dickens. Here follows a technical description of the feature, what it does and how it works.
    The challenge was to show the logophile visitors to OxfordWords some of the computational linguistic techniques used in the preparation of the Oxford English Corpus, and thus give some insight into the preparation of a modern dictionary.
    Finding ourselves unable to share the corpus itself with the public, we settled on the idea of  delivering a much smaller text with similar analytical techniques applied to it to those used by our corpus analysis software. Since we already publish a huge range of classic texts in the Oxford World's Classics range it made the most sense to use those as our sources and provide collocate and frequency analysis as well as example sentences for each text. This presented a data problem: to incorporate all this in a single web page would mean adding several megabytes of data to the page, resulting in an unsustainable page load time.
    The obvious solution was to create a lightweight page containing just the Javascript display code, and deliver all the data on an as-needed basis via AJAX calls. There was a time when writing this to work reliably on all browsers would have been the bane of a programmer's life, but fortunately we now have the jQuery library to abstract such nasty jobs from the programmer, so taking that route was a no-brainer decision.
    AJAX having been decided upon, the next decision related to the server-side component. I wrote a piece about this last summer, about how experience of database driven back-ends for language analysis had led me to precomputing data as json files rather than querying a database. Disk space is fast and cheap, server processing power isn't. So my next task was to write a set of command-line PHP scripts that generated a tree of JSON files for each word in the source text, containing collocates, frequencies and example sentences.
    While these tasks are essentially simple ones, they are quite computationally intensive. In a typical Dickens novel for instance, there will be as many as 20000 unique words, and every one of those words needs to be searched for across the whole text and the frequency of its colloscates in all the locations it appears in computed. The whole process takes about six hours, and produces a roughly 20Mb tree of thousands of tiny JSON files which are then uploaded to the web server.
    So that's the surprisingly low-tech backend for the feature, how about the front end?
    The core functionality of jQuery makes coding an application like this very simple. The three main parts of the feature live in hidden DIVs which are shuffled using the jQuery show() and hide() functions. TheJSON data is pulled in using jQuery's getJSON() function. Collocates are shown in a word cloud courtesy of the excellent jQCloud plugin, example sentences are simply loaded into an unordered list, and frequency graphs are created using Google's Image Chart API.
    These plugins and code made a working feature. But to make a single-page jQuery application like this one feel like a proper application, there was one further component required. Users expect to be able to use the back button, and to be able to return to a particular part of the application by URL alone. Miss Havisham's dress needs to be readily conjoured up by linking directly to the word "bridal".
     We thus used the jQuery-BBQ plugin to provide URL and history functionality through the use of in-page anchors. Because the page can't be reloaded, the plugin appends the word to the end of the URL after a # symbol as it triggers any changes to what is displayed.
    In summary, the use of precomputed JSON files made the server-side compontnet of this feature very simple at the expense of using more filesystem space, and the use of jQuery and its plugins made client-side development a lot faster and more reliable across browsers. Sometimes libraries like jQuery are used for the sake of it when simple Javascript would have sufficed, but in this case I believe its use made for a far better application.