Date Picker

Most of the time dealing with date and time is a pain for software projects, for plugin developers JIRA is not different. JIRA has a build-in date time picker JS component, it is a lot easier to use this component than developing your own or throwing a 3rd party implementation. At leas you will not introduce new js, css to be transferred and users will be familiar with user interface because JIRA itself uses that component in any date field.

Here is the component we are talking about:

Date Time Picker

First of all there are multiple ways of injecting date and time formats into velocity template, below is only one of these.

There are two date/time format one for JavaScript and the other one is for Java. For everything to work correctly both format should mach each other otherwise date/time string passed from user interface to server will not be parseable and will not work. Within JIRA you can change both JavaScript and Java date/time formats so we cannot use a hardcoded date/time format. We have to get JavaScript date/time format from ApplicationSettings of JIRA and pass it to JavaScript. To do this we use hidden input fields. For JS Date Picker to work correctly we need more than date/time format, we have to specify some other parameters too, for example first day of the week (this is also configurable in JIRA). Below code sample shows all parameters needed by JS Date Picker. Also we need to put one <Input> field and one <a> for JS Date Picker to use. Note that “id” of input fields should match the parameters given to JS Date Picker JS function.

##Inject JS Date Picker and its locale specific parts into to current page
$webResourceManager.requireResource("jira.webresources:calendar")
$webResourceManager.requireResource("jira.webresources:calendar-$i18n.getLocale().getLanguage()")

##Provide parameters for Date Picker
#set ($firstDay = $currentCalendar.firstDayOfWeek - 1)
<fieldset class="hidden parameters">
    <input type="hidden" title="worklogDateFormat" value="$dateFormat" />
    <input type="hidden" title="worklogTimeFormat" value="$timeFormat" />
    <input type="hidden" title="worklogCurrentMillis" value="$currentMillis" />
    <input type="hidden" title="worklogFirstDay" value="$firstDay" />
    <input type="hidden" title="worklogUseISO8601" value="$currentCalendar.useISO8601"/>
</fieldset>

##provide the Input field an icon for Date Picker
<div class="field-group">
    <label for="add-reminder-date">$i18n.getText("com.deniz.jira.reminders.date")
        <span class="aui-icon icon-required"> required</span>
    </label>
    <table>
        <tr>
            <td><input class="text medium-field" id="add-reminder-date" name="dateStr" type="text" value="$action.dateStr"/></td>
            <td><a href="#" id="add-reminder-date-icon" title="$i18n.getText("com.deniz.jira.reminders.date")">
                <span class="aui-icon icon-date"></span>
            </a></td>
        </tr>
    </table>
    #error($action.errors.date)
</div>

It is not enough to specify just parameters in the velocity template, we have to provide values of these variables. Easiest way to do it using JIRA’s build in VelocityParamsFactory class. You can inject this class to your own class and just use its getDefaultvelocityParams method. You have to provide JiraAuthenticationContext because some of the injected values may be determined differently according to logged in user.

@Override
    public Map getContextMap(User user, JiraHelper jiraHelper) {
        Issue issue = (Issue) jiraHelper.getContextParams().get("issue");
        List<ReminderImp> remindersForIssue = reminderService.getRemindersForIssue(issue.getId());
        Map<String, Object> context = new HashMap<String, Object>();
        context.put("reminders", remindersForIssue);
        
        //Here we are injecting default velocity parameters which also contains date/time related variable shown at above velocity template. 
        Map<String, Object> defaultVelocityParams = velocityParamFactory.getDefaultVelocityParams(jiraAuthenticationContext);
        context.putAll(defaultVelocityParams);
        return context;
    }

First of all, following code sample is CoffeeScript not JavaScript but it is not important for our learning purpose. This code converts our ordinary <Input> field and <a> combination to JS Date Picker. Since we are providing necessary locale specific information it is fully localized. Value of “button” and “inputField” parameters should match the “id” of corresponding fields in your velocity template.

Calendar.setup
            singleClick: true
            align: "Bl"
            showsTime: true
            firstDay: AJS.$("input[title='worklogFirstDay']").val()
            currentMillis: new Date().getTime()
            useISO8601WeekNumbers: AJS.$("input[title='worklogUseISO8601']").val()
            ifFormat: AJS.$("input[title='worklogDateFormat']").val()
            daFormat: ifFormat
            button: "#add-reminder-date-icon"
            inputField: "#add-reminder-date"