IOS 7 status bar with fixed footer navbar in Cordova/JQuery Mobile

To avoid your content scrolling underneath the new IOS 7 status bar, you have a few choices but in most situations, org.apache.cordova.statusbar is the best solution.

From the CLI:

$ cordova plugin add org.apache.cordova.statusbar

And you can then turn the transparent IOS7 status bar into one which behaves as it does in IOS6 with the following in your config.xml:

<preference name="StatusBarOverlaysWebView" value="false" />
<preference name="StatusBarBackgroundColor" value="#000000" />

However, if you have a fixed navbar in the footer such as this to approximate the look of a tab bar in the new IOS7  Human Interface Guidelines:

<div data-role="footer" data-id="allot_footer" data-position="fixed">
    <div data-role="navbar" data-iconpos="bottom">
        <ul>
            <li><a href="#browse" data-id="footer_browse" data-theme="d" data-icon="grid">Browse</a></li>
            <li><a href="#find" data-id="footer_find" data-theme="d" data-icon="search">Find</a></li>
        </ul>
    </div>
</div>

then you’ll find that the statusbar plugin pushes the navbar down off the bottom of the page by the height of the status bar. So, for a fixed bottom navbar, the solution I’ve adopted inn the end is to forget the statusbar plugin and to allow the status bar to overlay my content. However, to create a bit of space at the top of the page for it to sit, I used this Gist from Shazron to arrive at:

function onDeviceReady() {
    if (parseFloat(window.device.version) >= 7.0) {
        $("div.ui-header").css("padding-top", "20px"); 
        }
    ...
    }

Note that you’ll need to install org.apache.cordova.device using the CLI:

$ cordova plugin add org.apache.cordova.device

It now looks fine on startup but if you need to scroll your content, it’ll still get overlayed by the IOS7 status bar so make your header fixed too:

<div data-role="header" data-id="allot_header" data-position="fixed" data-theme="d">
    <h1>Browse</h1>
</div>

Hoping that IOS7 issues will all become a distant memory very soon, but this is what works for me at the moment.

QuestionMark Perception’s GetScheduleListByParticipant method in QMWISe

PLEASE NOTE: I’m looking further into why this may be happening after a very useful chat with Questionmark’s Richard Ham so watch this space…

If you’re using QuestionMark Perception’s GetScheduleListByParticipant method through their QMWISe API and the Questionmark Basic LTI Community Connector (I don’t know about the LTI Connector for Questionmark OnDemand) then this is a quick heads up about a problem that I’ve just encountered in v5.4. We use this method to work out whether students are currently scheduled for a given assessment through a (rather inelegant) check of whether the AssessmentID they are trying to access is the same as the AssessmentID of one of the assessments they are scheduled for and, if that schedule is time-limited, whether it is currently open.

The problem is that, for reasons that are probably die to the way that PHP deals with a SOAP return , GetScheduleListByParticipant returns a different object structure depending on whether the one or more schedules are returned. For one schedule (with print_r()):

stdClass Object
(
    [Schedule] => stdClass Object
        (
            [Schedule_ID] => 111111111
            [Assessment_ID] => 1111111111111111 
            [Participant_ID] => 0 
            [Group_ID] => 111111111 
            [Schedule_Name] => Quiz 1 
            [Restrict_Times] => 1 
            [Restrict_Attempts] => 
            [Max_Attempts] => 0 
            [Monitored] => 0 
            [Schedule_Starts] => 2013-12-03T00:00:00 
            [Schedule_Stops] => 2013-12-04T00:00:00 
        )
)

Whereas with more than one schedule:

stdClass Object
(
    [Schedule] => Array
        (
            [0] => stdClass Object
               (
                   [Schedule_ID] => 1111111
                   [Assessment_ID] => 1111111111111111
                   [Participant_ID] => 0
                   [Group_ID] => 111111111
                   [Schedule_Name] => Quiz 1
                   [Restrict_Times] =>
                   [Restrict_Attempts] =>
                   [Max_Attempts] => 0
                   [Monitored] => 0
                   [Schedule_Starts] => 0001-01-01T00:00:00
                   [Schedule_Stops] => 0001-01-01T00:00:00
               )
            [1] => stdClass Object
               (
                   [Schedule_ID] => 2222222
                   [Assessment_ID] => 2222222222222222
                   [Participant_ID] => 0
                   [Group_ID] => 222222222
                   [Schedule_Name] => Quiz 2
                   [Restrict_Times] => 1
                   [Restrict_Attempts] =>
                   [Max_Attempts] => 0
                   [Monitored] => 0
                   [Schedule_Starts] => 2013-12-03T00:00:00
                   [Schedule_Stops] => 2013-12-04T00:00:00
               )
            [n] => and so on...

The real problem with is when you compare desired AssessmentID with scheduled AssessmentID in a for loop:

$schedules = get_schedule_list_by_participant($participant_id)) //method which calls GetScheduleListByParticipant
foreach($schedules->Schedule){
    ... //check each schedule
    }

It works fine until you come across a student with only one schedule, at which point it breaks as it tries to iterate through the properties of the only schedule returned. Until we can work out something else, the simplest solution is to check the number of schedules returned before deciding how to evaluate them:

if(count($schedules->Schedule)>1){ 
    foreach($schedules->Schedule as $schedule){
        ... //check each schedule
        }
    }
elseif(count($schedules->Schedule)==1){ 
    ... //check this schedule
    }

Haven’t checked whether behaviour is the same with the other QMWISe methods but I wouldn’t be surprised….

CKEditor: Use config.allowedContent/extraAllowedContent to stop tags being stripped

I was having an issue with certain tags, e.g. span and div, being stripped out of html by CKEditor. Whether or not I should be using these tags is another issue – in this particular situation it was useful to use span tags to give a class to snippets of text that would be styled in different ways, to indicate different types of text (printed, handwritten or engraved) on historical slides in CSlide.

It turns out that CKEditor (4.1 onwards) has the Advanced Content Filter (ACF), which is a highly configurable filter that allows only certain types of content to be entered into the editor, and removes any html tags that are not allowed by the configuration. The default behaviour (Automatic mode) results in all of the enabled editor features, e.g. styling buttons, formats, etc, adding their rules (i.e. the html associated with the feature) to the filtering rules to allow that type of content. The alternative to this is Custom mode, where the allowed content is defined in the config, using config.allowedContent – see the CKEditor guide on defining allowed content rules.

Turning off the ACF

I wouldn’t advise this (it is much better to configure the ACF), but if you really don’t want CKEditor to do any filtering, you can turn it off by adding the following line to config.js:

config.allowedContent = true;

extraAllowedContent

As well as fully defining the ACF rules using config.allowedContent, it is also possible to extend the current rules using config.extraAllowedContent, and this was the most straightforward solution to my issue. extraAllowedContent allows you to add rules to the current config, which is an easy way to extend, for example, the automatic mode configuration. In my case, I was able to allow span tags, and define a set of classes that these span tags would be allowed to have:

config.extraAllowedContent = 'span(engraved,printed,manuscript,slide_text,label_text)';

This setting means that any other class associated with span tags will be removed (though the span tag will remain). Using ‘span(*)’ allows span tags with any class.