/****** begin global default HPE page initialization JS for pages with HP.com CaaS header/footer (caas-globals.js) ******/ // Note: This file is used for global initialization code only, on pages that // use the HP.com content-as-a-service header and footer. // Set global variables to values appropriate for default HPE installations. // Only do this if they are not already set: if (typeof(HPUI_URL) == 'undefined') var HPUI_URL = "/"; if (typeof(HPUI_LOCALE_COOKIE) == 'undefined') var HPUI_LOCALE_COOKIE = ""; if (typeof(HPUI_LOCALE) == 'undefined') var HPUI_LOCALE = ""; // Deprecated (but still supported): if (typeof(HPUI_CSS_URL) == 'undefined') var HPUI_CSS_URL = "/hpui/hpe/css"; if (typeof(HPUI_IMG_URL) == 'undefined') var HPUI_IMG_URL = "/hpui/hpe/images"; if (typeof(HPUI_JS_URL) == 'undefined') var HPUI_JS_URL = "/hpui/hpe/js"; /****** end global default HPE page initialization JS for pages with HP.com CaaS header/footer (caas-globals.js) ******/ /****** begin HPE buttons JS (buttons.js) ******/ /*** "Public" functions - may be used by feature developers ***/ /*** "Private" functions not for direct use by feature developers ***/ // Initialize all buttons in the given context. function initButtons(context) { // Ensure all buttons support event handlers to set disabled/enabled. var allButtons = jQuery('input[type=button].hpui-critical-button,input[type=button].hpui-critical-slim-button,' + 'input[type=submit].hpui-critical-button,input[type=submit].hpui-critical-slim-button,' + 'input[type=reset].hpui-critical-button,input[type=reset].hpui-critical-slim-button,' + 'input[type=button].hpui-primary-button,input[type=button].hpui-primary-slim-button,' + 'input[type=submit].hpui-primary-button,input[type=submit].hpui-primary-slim-button,' + 'input[type=reset].hpui-primary-button,input[type=reset].hpui-primary-slim-button,' + 'input[type=button].hpui-secondary-button,input[type=button].hpui-secondary-slim-button,' + 'input[type=submit].hpui-secondary-button,input[type=submit].hpui-secondary-slim-button,' + 'input[type=reset].hpui-secondary-button,input[type=reset].hpui-secondary-slim-button', context); allButtons.off('hpui-disable.hpui-button'); allButtons.on('hpui-disable.hpui-button', function(event) { var button = jQuery(this); // Set disabled attr - no need for screenreader text at this time. button.attr('disabled', ''); // Let event propagate - if surrounded by link, then link handler // set in initLinks (links.js) will take care of the rest. }); allButtons.off('hpui-enable.hpui-button'); allButtons.on('hpui-enable.hpui-button', function(event) { var button = jQuery(this); // Remove disabled attr - no need for screenreader text at this time. button.removeAttr('disabled'); // Let event propagate - if surrounded by link, then link handler // set in initLinks (links.js) will take care of the rest. }); // Ensure all button links support event handlers to set disabled/enabled. // Only need to perform button specific actions; general link event handler // set in initLinks (links.js) will take care of the link itself. var allButtonLinks = jQuery('a.hpui-critical-button,a.hpui-critical-slim-button,' + 'a.hpui-primary-button,a.hpui-primary-slim-button,' + 'a.hpui-secondary-button,a.hpui-secondary-slim-button', context); allButtonLinks.off('hpui-disable.hpui-button'); allButtonLinks.on('hpui-disable.hpui-button', function(event) { var button = jQuery(this).children('input[type=button]'); // Set disabled attr - no need for screenreader text at this time. if (button && button.length) button.attr('disabled', ''); }); allButtonLinks.off('hpui-enable.hpui-button'); allButtonLinks.on('hpui-enable.hpui-button', function(event) { var button = jQuery(this).children('input[type=button]'); //Remove disabled attr - no need for screenreader text at this time. if (button && button.length) button.removeAttr('disabled'); }); // Initialize button links. allButtonLinks.each(function() { var link = jQuery(this); var button = link.children('input[type=button]'); if (button && button.length) { // Ensure that initially button links and enclosed buttons are // in consistent state. if (link.attr('disabled')) button.attr('disabled', ''); else button.removeAttr('disabled'); // Button links do not need to be in the tab flow (the button // inputs already are). link.attr('tabindex', '-1'); } }); } /****** end HPE buttons JS (buttons.js) ******/ /****** begin HPE date picker JS (datepicker.js) ******/ /*** "Public" date picker methods ***/ // This hash maps lowercase locales (format ll eg "fr" or ll-cc, eg "zh-tw") to provided // JQuery UI datepicker JS file tags (format ll eg "fr" or ll-CC, eg "zh-TW"). var HPUI_LOCALES_TO_DATEPICKER_MESSAGES = { 'en-au':'en-AU', 'en-ca':'en-CA', 'en-gb':'en-GB', 'en-ie':'en-IE', 'en-in':'en-IN', 'en-nz':'en-NZ', 'en-za':'en-ZA', 'es-ar':'es-AR', 'es-bo':'es-BO', 'es-cl':'es-CL', 'es-co':'es-CO', 'es-ec':'es-EC', 'es-mx':'es-MX', 'es-pe':'es-PE', 'es-pr':'es-PR', 'es-py':'es-PY', 'es-uy':'es-UY', 'es-ve':'es-VE', 'br-be':'fr-BE', 'fr-ca':'fr-CA', 'pt-br':'pt-BR', 'zh-hk':'zh-HK', 'zh-tw':'zh-TW', 'cs': 'cs', 'de': 'de', 'el': 'el', 'es': 'es', 'fr': 'fr', 'hu': 'hu', 'it': 'it', 'ja': 'ja', 'ko': 'ko', 'pl': 'pl', 'pt': 'pt', 'ru': 'ru', 'tr': 'tr', 'zh': 'zh' }; /* Add the localization JS file. */ function hpuiAddDatepickerResources() { // First determine the locale being requested: either the HPUI_LOCALE or the // value of the HPUI_LOCALE_COOKIE or English by default. From init.js. var requestedLocale = typeof (determineLocale) == 'function' ? determineLocale() : "en"; // From the locale being requested, determine the locale to actually use. var localeToUse = ""; var requestedLanguage = requestedLocale; if (requestedLocale.length > 2) requestedLanguage = requestedLocale.substring(0, 2); if (HPUI_LOCALES_TO_DATEPICKER_MESSAGES[requestedLocale.toLowerCase()]) // We will use the full locale if it is supported localeToUse = HPUI_LOCALES_TO_DATEPICKER_MESSAGES[requestedLocale.toLowerCase()]; else if (HPUI_LOCALES_TO_DATEPICKER_MESSAGES[requestedLanguage.toLowerCase()]) // Else we will use the language if it is supported localeToUse = HPUI_LOCALES_TO_DATEPICKER_MESSAGES[requestedLanguage.toLowerCase()]; else // Else we will use English if neither full locale nor language are supported localeToUse = "en"; // No need to proceed if locale has already been loaded. if (loadedDatepickerResourcesForLocale == localeToUse) return; // Map locale into URL and add that JS into the DOM and return the URL. // HPUI_JS_URL is a global variable for the root URL to the JS folder. // From init.js. var baseUrl = typeof (determineBaseJsUrl) == 'function' ? determineBaseJsUrl() : ""; var url = baseUrl + 'ui/i18n/jquery.ui.datepicker' + '-' + localeToUse + '.js'; var script = document.createElement('script'); script.type = 'text/javascript'; script.src = url; document.getElementsByTagName('head')[0].appendChild(script); loadedDatepickerResourcesForLocale = localeToUse; return url; } /* Add screenreader messages to basic datepickers. */ function hpuiAddBasicDatepickerResources(context) { // Get the message resources. if (typeof(hpuiAddMessageResources) == 'function') { hpuiAddMessageResources(); } // Determine the context (if not given). if (!context || !context.length || (typeof context != 'object') || !(context instanceof jQuery)) { if (context && typeof context == 'string') { context = jQuery('#' + context); } else { context = document; } } // For each preloader icon set the screenreader message if there is no content exist in it. jQuery('input[type=text].hpui-datepicker,input[type=text].hpui-slim-datepicker', context).each(function() { var textInput = jQuery(this); if (!textInput.attr('id')) { // Generate random ID if there was none (should never happen because JQuery UI // generates one automatically) textInput.attr('id', Math.floor(Math.random()*Math.pow(10,6))); } var label = jQuery("label[for='" + textInput.attr('id') + "']"); if (typeof label == "undefined" || label.length == 0) { // if no label for the dropdown then make an empty one and insert it after the select label = jQuery(""); textInput.parent('span.hpui-datepicker,span.hpui-slim-datepicker').prepend(label); } var labelText = jQuery.trim(label.text()); if ((typeof datepicker_screenreader == "string") && datepicker_screenreader) { // non-empty screenreader text - add it to the label unless already present if (!labelText || (labelText.indexOf(datepicker_screenreader) == -1)) { label.append("" + datepicker_screenreader + ""); } } }); } /* Dynamically set the restricted date criteria. */ function hpuiRestrictDatepicker(id, val) { var el = id; var minDate = val ? val.minDate : null; var maxDate = val ? val.maxDate : null; var blockDates = val ? val.blockDates : null; var blockWeekends = val ? val.blockWeekends : null; // If passed a string, use it as an ID to select a JQuery object. if (id && (typeof id == 'string')) el = jQuery('#' + id); // Return short if not provided with a JQuery datepicker. if (!el || !el.length || !(typeof el == 'object') || !(el instanceof jQuery) || !el.is(':data(datepicker)')) return; var optionObject = {}; // If the minDate after the maxDate, block all day and display current month. if ( minDate && typeof minDate == 'string' && maxDate && typeof maxDate == 'string' && minDate > maxDate){ var today = dateToString(new Date()); minDate = maxDate = today; blockDates = [today]; } // Set the minimum date, if any. This must be a YYYYMMDD string. if (minDate && typeof minDate == 'string') { try { minDate = jQuery.datepicker.parseDate(el.datepicker('option', 'altFormat'), minDate); optionObject['minDate'] = minDate; optionObject['hideIfNoPrevNext'] = true; } catch (e) { } } // Set the maximum date, if any. This must be a YYYYMMDD string. if (maxDate && typeof maxDate == 'string') { try { maxDate = jQuery.datepicker.parseDate(el.datepicker('option', 'altFormat'), maxDate); optionObject['maxDate'] = maxDate; optionObject['hideIfNoPrevNext'] = true; } catch (e) { } } // Set a function to evaluate whether a given date should be selectable in // the calendar or not, if restricted dates or weekends have been passed. // Restricted dates must be YYYYMMDD strings. if ((blockDates && jQuery.isArray(blockDates)) || blockWeekends) { el.data('blockDates', blockDates); el.data('blockWeekends', blockWeekends); optionObject['beforeShowDay'] = function(date) { var ok = [true, '', '']; var no = [false, '', '']; var datepicker = jQuery(this); if (isRestrictedDate(datepicker, date)) { return no; } else { return ok; } } } el.datepicker('option', optionObject); // Finally, now we have restricted the date range, make sure any // previously-selected date still falls within that range. Clear it if not. // Do this while any callback function is temporarily disabled. el.each(function() { var datepicker = jQuery(this); if (isRestrictedDate(datepicker, datepicker.attr('value'))) { var placeholder = datepicker.datepicker('option', 'onSelect'); datepicker.datepicker('option', 'onSelect', null); datepicker.trigger('hpui-clear'); if (placeholder && typeof(placeholder) == 'function') { datepicker.datepicker('option', 'onSelect', placeholder); } } }); } /* Bind a datepicker to an element with an optional callback function for when a date is selected. */ function hpuiBindDatepicker(id, val) { var el = id; // If passed a string, use it as an ID to select a JQuery object. if (id && (typeof id == 'string')) el = jQuery('#' + id); // Return short if not provided with a JQuery object. if (!el || !el.length || !(typeof el == 'object') || !(el instanceof jQuery)) return; // Generate the base ID and name for the inputs to be created. var baseID = val && typeof(val.baseID) == 'string' ? val.baseID : null; if (!baseID && el.attr('id')) baseID = el.attr('id'); var baseName = val && typeof(val.baseName) == 'string' ? val.baseName : null; if (!baseName && el.attr('name')) baseName = el.attr('name'); // Check for existing datepicker and alternate date hidden inputs. If // forcible create option was specified, remove them. var altInput = null; var dateInput = el.prev('input[type=hidden].hpui-datepicker.hasDatepicker'); if (dateInput && dateInput.length) { if (val && val.create) { altInput = dateInput.prev('input[type=hidden].hpui-datepicker'); if (altInput && altInput.length) altInput.remove(); dateInput.remove(); dateInput = altInput = null; } } // To bind a datepicker to the given element, we create two hidden inputs // before that element. One input is for tracking the display date and the // datepicker is bound to it. The other is for tracking the internal date // as an alternate date field. var firstTime = false; if (!dateInput || dateInput.length != 1) { firstTime = true; // Generate the main input for the displayable date value. dateInput = jQuery(''); if (baseID) dateInput.attr('id', baseID + '_date'); if (baseName) dateInput.attr('name', baseName + '_altDate'); dateInput.insertBefore(el); // Instantiate a datepicker on the second input. JQuery UI gives it the // 'hasDatepicker' class at that point. dateInput.datepicker(); } altInput = dateInput.prev('input[type=hidden].hpui-datepicker'); if (!altInput || altInput.length != 1) { // Generate the alt input for the internal date value. altInput = jQuery(''); if (baseID) altInput.attr('id', baseID + '_altDate'); if (baseName) altInput.attr('name', baseName + '_altDate'); altInput.insertBefore(dateInput); } // Determine initial state (first time is always enabled). var currentState = dateInput.attr('disabled') ? 'disable' : 'enable'; // Determine initial value (first time is the initial date option if any). var currentValue = val && typeof(val.date) == 'string' ? val.date : ''; if (dateInput.attr('value')) currentValue = dateInput.attr('value'); if (altInput.attr('value')) currentValue = altInput.attr('value'); // Set options on the datepicker. // dateFormat not set here - see the localization files. var optionObject = { 'altFormat': 'yymmdd', 'altField': altInput, 'changeMonth': true, 'changeYear': true }; // If given a callback function, set it to onSelect. if (val && val.callback && typeof(val.callback) == 'function') optionObject['onSelect'] = val.callback; // Make the datepicker draggable if requested. if (val && val.draggable) { dateInput.addClass('hpui-draggable'); } else { dateInput.removeClass('hpui-draggable'); } // Set before-show and on-close callbacks to adjust the datepicker when it // is opened and closed. optionObject['beforeShow'] = function(input, datepicker) { // Make the datepicker draggable if requested. if (jQuery(this).hasClass('hpui-draggable')) jQuery('#ui-datepicker-div').draggable(); } optionObject['onClose'] = function(date) { if (jQuery(this).hasClass('hpui-draggable')) jQuery('#ui-datepicker-div').draggable('destroy'); } // Register keydown event on the datepicker. Note the JQuery UI datepicker // built-in keydown handler will already execute by the time this does. // We just want to stop any further propagation up the DOM. dateInput.off('keydown.hpui-datepicker'); dateInput.on('keydown.hpui-datepicker', function(event) { event.stopImmediatePropagation(); event.preventDefault(); }); // Register the custom enable event on the datepicker. dateInput.off('hpui-enable.hpui-datepicker'); dateInput.on('hpui-enable.hpui-datepicker', function() { return function() { var dateInput = jQuery(this); var altInput = dateInput.prev('input[type=hidden].hpui-datepicker'); var el = dateInput.next(); dateInput.datepicker('enable'); dateInput.removeAttr('disabled'); if (altInput && altInput.length) altInput.removeAttr('disabled'); if (el && el.length) el.removeAttr('disabled'); } }()); // Register the custom disable event on the datepicker. dateInput.off('hpui-disable.hpui-datepicker'); dateInput.on('hpui-disable.hpui-datepicker', function() { return function() { var dateInput = jQuery(this); var altInput = dateInput.prev('input[type=hidden].hpui-datepicker'); var el = dateInput.next(); dateInput.datepicker('disable'); dateInput.attr('disabled', ''); if (altInput && altInput.length) altInput.attr('disabled', ''); if (el && el.length) el.attr('disabled', ''); } }()); // Register the custom set value event on the datepicker. dateInput.off('hpui-value.hpui-datepicker'); dateInput.on('hpui-value.hpui-datepicker', function(event, val) { var dateInput = jQuery(this); if (val) { // Set the datepicker to the given value. First try our // canonical YYYYMMDD format. Then try the localized // displayable format. Finally validate the date. If all // of this fails, clear the datepicker using another trigger. var date = stringToDate(dateInput, val); if (date && !isRestrictedDate(dateInput, date)) dateInput.datepicker('setDate', date); else dateInput.trigger('hpui-clear'); } else { // Clear the datepicker if not given a value. dateInput.datepicker('setDate', null); } // If there is an on-select callback, invoke it - set the // flag to tell the callback it was invoked from here, in case it // cares. var callback = dateInput.datepicker('option', 'onSelect'); if (typeof(callback) == 'function') callback(dateInput.attr('value'), dateInput[0], true); }); // Register the custom clear event on the datepicker. dateInput.off('hpui-clear.hpui-datepicker'); dateInput.on('hpui-clear.hpui-datepicker', function() { return function() { var dateInput = jQuery(this); // Clear is same as setting a blank value. dateInput.trigger('hpui-value', ''); } }()); // Finally register the custom hpui-reset event on the datepicker. Only // do this first time, since its parameters depend on the initial values. if (firstTime) { dateInput.off('hpui-reset.hpui-datepicker'); dateInput.on('hpui-reset.hpui-datepicker', function(initValue, initState) { return function() { var dateInput = jQuery(this); dateInput.trigger('hpui-value', initValue); dateInput.trigger('hpui-' + initState); } }(currentValue, currentState)); } // Set the current value and state into the datepicker, with callbacks // temporarily disabled. var placeholder = optionObject.onSelect; optionObject['onSelect'] = null; dateInput.trigger('hpui-value', currentValue); dateInput.trigger('hpui-' + currentState); if (placeholder && typeof(placeholder) == 'function') { optionObject['onSelect'] = placeholder; } dateInput.datepicker('option',optionObject); return dateInput; } /* Set the position for datepicker and open it. */ function hpuiShowDatepicker(id, position){ // Try to set focus on an element. function tryFocus(focal) { var hasTabIndex = focal.attr('tabindex'); if (!hasTabIndex) focal.attr('tabindex', '0'); // tabindex makes it focusable focal.focus(); if (!hasTabIndex) focal.removeAttr('tabindex'); } var el = id; // If passed a string, use it as an ID to select a JQuery object. if (id && (typeof id == 'string')) el = jQuery('#' + id); // Return short if not provided with a JQuery datepicker. if (!el || el.length != 1 || !(typeof el == 'object') || !(el instanceof jQuery) || !el.is(':data(datepicker)')) return; // Find the originally bound element (its just the next one). var orig = el.next(); if (!orig || !orig.length) return; // By default, position the calendar at right bottom of the closest aligned // element (ie closest element marked with class="hpui-datepicker-align") // with flip enabled. If so such element, then launch from the next element // after the enclosing span, presumed to be the original binded DOM element. // This is just by default; passed-in properties can override. if (!position || (typeof(position) != 'object')) position = {}; if (!position.my || (typeof(position.my) != 'string')) position.my = 'right top'; if (!position.at || (typeof(position.at) != 'string')) position.at = 'right bottom'; if (!position.collision || (typeof(position.collision) != 'string')) position.collision = 'flip'; var launch = el.closest('.hpui-datepicker-align'); if (!launch || !launch.length) launch = orig; if (!position.of) position.of = launch; else launch = position.of; // Make sure focus is established and keydown event handlers are set, so // keystrokes are diverted into the datepicker. First try to set focus // on original bound element; otherwise try to set it on the launch point. var focal = orig; if (!focal.is(':focus')) tryFocus(focal); if (!focal.is(':focus')) { focal = launch; focal.css('outline', 'none'); // no outline when focus on launch point tryFocus(focal); } // Register keydown event on the focal element, to clear datepicker // when backspace/delete keys are trapped, hide datepicker when tab key // is detected, and divert all other keys to the datepicker itself. focal.off('keydown.hpui-datepicker'); focal.on('keydown.hpui-datepicker', function(event) { if (event.keyCode == 8 || event.keyCode == 46) { // 'Backspace', 'Delete' keys erase the date (ignore on // disabled datepickers). if (!el.attr('disabled')) { el.trigger('hpui-clear'); el.datepicker('hide'); } event.preventDefault(); event.stopImmediatePropagation(); } else if (event.keyCode == 9) { // 'Tab' closes the datepicker. if (!el.attr('disabled')) el.datepicker('hide'); } else { // Other keys get diverted to the datepicker. event.target = el[0]; event.relatedTarget = focal[0]; el.trigger(event); } }); // Remove that keydown event handler when the datepicker is closed. el.datepicker('option', 'onClose', function() { focal.off('keydown.hpui-datepicker'); }); // Finally show the datepicker in the proper position. // There is a corner-case timing bug: if the user clicks again (or double // clicks) on the bound DOM element for this datepicker, then the datepicker // will close (on mousedown) and then open again (on mouseup). When the // close and open are very rapid, the close is still executing while the // open is trying to execute, and consequently the position is mis- // calculated, so the datepicker appears to flicker and jump to another // place in the UI. Setting even a very short timeout will take care of // that: 50 milliseconds. var doShow = function() { try { el.datepicker('show'); jQuery('#ui-datepicker-div').position(position); } catch (e) { } } // UPADTE: The timeout workaround would cause the datepicker to not appear // at all when launched from an action menu. doShow(); setTimeout(doShow, 50); } /* Convert a YYYYMMDD or display-date string into a JS Date object, returning * null if the conversion cannot proceed. */ function hpuiStringToDate(datepicker, val) { return stringToDate(datepicker, val); } /* Convert a JS Date object to a YYYYMMDD string, returning null if the * conversion cannot proceed. */ function hpuiDateToString(date) { return dateToString(date); } /*** "Private" date picker methods ***/ // Global variable for tracking datepicker resources already loaded on this page. var loadedDatepickerResourcesForLocale = ""; /* Convert a YYYYMMDD or display-date string into a JS Date object, returning * null if the conversion cannot proceed. */ function stringToDate(datepicker, val) { var date = null; try { date = jQuery.datepicker.parseDate(datepicker.datepicker('option', 'altFormat'), val); } catch (e) { try { date = jQuery.datepicker.parseDate(datepicker.datepicker('option', 'dateFormat'), val); } catch (e) { } } return date; } /* Convert a JS Date object to a YYYYMMDD string, returning null if the * conversion cannot proceed. */ function dateToString(date) { if (!date || typeof(date) != 'object' || !(date instanceof Date)) return null; var mm = (date.getMonth() + 1) > 9 ? (date.getMonth() + 1) : '0' + (date.getMonth() + 1); var dd = date.getDate() > 9 ? date.getDate() : '0' + date.getDate(); var yyyy = date.getFullYear(); var yyyymmdd = yyyy.toString() + mm.toString() + dd.toString(); return yyyymmdd; } /* Return true/false indicating whether the given Date object is in the * datepicker's restricted range. Instead of a Date object, a string can be * given. */ function isRestrictedDate(datepicker, date) { // Normalize parameters. if (date && typeof(date) == 'string') date = stringToDate(datepicker, date); if (!date || typeof(date) != 'object' || !(date instanceof Date)) return false; if (!datepicker || !datepicker.length || (typeof(datepicker) != 'object') || !(datepicker instanceof jQuery) || !(datepicker.is(':data(datepicker)'))) return false; // Check if it is on or after the minimum date. var minDate = datepicker.datepicker('option', 'minDate'); if (minDate && (date < minDate)) return true; // Check if it is on or before the maximum date. var maxDate = datepicker.datepicker('option', 'maxDate'); if (maxDate && (date > maxDate)) return true; // Check if it is a weekend. var blockWeekends = datepicker.data('blockWeekends'); if (blockWeekends) { var weekend = !(jQuery.datepicker.noWeekends(date)[0]); if (weekend) return true; } // Finally check if it is a specific blocked date. var blockDates = datepicker.data('blockDates'); if (blockDates && jQuery.isArray(blockDates)) { var mmddyyyy = dateToString(date); if (jQuery.inArray(mmddyyyy, blockDates) > -1) return true; } // If survived all these checks, then the date is not restricted. return false; } // Initialize date picker function initDatepicker(baseDatepickerClass, baseTextClass, context) { var spanSelector = 'span.' + baseDatepickerClass; var hiddenInputSelector = 'input[type=hidden].' + baseDatepickerClass; var textInputSelector = 'input[type=text].' + baseDatepickerClass; var iconSelector = 'img.ui-datepicker-trigger'; // Find and process datepicker text inputs (phase 2). var textInputs = jQuery(textInputSelector, context); if (textInputs && textInputs.length) { for (var i = 0; i < textInputs.length; i++) { var textInput = jQuery(textInputs[i]); var error = textInput.hasClass('hpui-error'); var disabled = textInput.attr('disabled'); var readonly = textInput.attr('readonly'); var currentValue = textInput.attr('value'); var currentState = readonly ? 'readonly' : 'enable'; currentState = disabled ? 'disable' : currentState; // Check if a hidden input was provided by the feature developer. // Its value, if any, becomes the initial value (trumping the one in // the text input). var hiddenInput = textInput.prev(hiddenInputSelector); if (hiddenInput && hiddenInput.length) if (hiddenInput.attr('value')) currentValue = hiddenInput.attr('value'); // Generate a span container for the hidden and text inputs, and add // it to the DOM, if not already there. (The span container ensures // nowrap on the contained elements: the text input and the image // tag that JQuery UI datepicker will insert next to it.) var span = textInput.parent(spanSelector); if (!span || !span.length) { span = jQuery(''); textInput.wrap(span); if (hiddenInput && hiddenInput.length) { hiddenInput.detach(); hiddenInput.insertBefore(textInput); } span = textInput.parent(spanSelector); } // Finally force this text input to the proper text input class. if (!textInput.hasClass(baseTextClass)) { textInput.removeClass('hpui-input hpui-slim-input').addClass(baseTextClass); // Reinitialize now we have added the text class - afterward // this datepicker is fully initialized (even the below logic // will have run), so just continue to the next. if (typeof(hpuiInitialize) == 'function') hpuiInitialize(span); continue; } else textInput.removeClass('hpui-input hpui-slim-input').addClass(baseTextClass); // Now instantiate a new datepicker on this datepicker text input. textInput.datepicker(); // dateFormat not set here - see the localization files. var optionObject = { 'altFormat' : 'yymmdd', 'showOn' : 'both', 'buttonImageOnly' : true, 'buttonText': '', 'changeMonth': true, 'changeYear': true } if (hiddenInput && hiddenInput.length) optionObject['altField'] = hiddenInput; // On show, the datepicker needs to be made draggable if // hpui-draggable class was requested. optionObject['beforeShow'] = function(input, datepicker) { var textInput = jQuery(this); if (textInput.hasClass('hpui-draggable')) jQuery('#ui-datepicker-div').draggable(); } // On select, the datepicker will now automatically update the text // input value with the displayable localized date, and the hidden // input value with the YYYYMMDD date. All we need to explicitly // do is set the entered classname. optionObject['onSelect'] = function(date) { var textInput = jQuery(this); if (!textInput.hasClass('hpui-error')) textInput.addClass('hpui-entered'); } // On close, we need to check and clear the entered classname if the // datepicker is blank; also blur the focus. optionObject['onClose'] = function(date) { var textInput = jQuery(this); if (!date) textInput.removeClass('hpui-entered'); // Remove draggability if it was set on the calendar overlay. if (textInput.hasClass('hpui-draggable')) jQuery('#ui-datepicker-div').draggable('destroy'); } // Register the custom enable event on the datepicker text input. // Remember the text input assigns an event handler of its own; both will run. // This one only needs to do the extra steps the basic text input one does not. textInput.off('hpui-enable.hpui-datepicker'); textInput.on('hpui-enable.hpui-datepicker', function() { return function() { var textInput = jQuery(this); var hiddenInput = textInput.prev(hiddenInputSelector); var imageUrl = typeof (determineBaseImagesUrl) == 'function' ? determineBaseImagesUrl() : ""; // from init.js textInput.datepicker('enable'); // HPUI_IMG_URL is a global variable for the root URL to the images folder. textInput.datepicker('option','buttonImage',imageUrl + 'calendar.png'); if (hiddenInput && hiddenInput.length) hiddenInput.removeAttr('disabled').removeAttr('readonly'); var icon = textInput.next(iconSelector); if (icon && icon.length) icon.removeAttr('disabled'); } }()); // Register the custom disable event on the datepicker text input. // Remember the text input assigns an event handler of its own; both will run. // This one only needs to do the extra steps the basic text input one does not. textInput.off('hpui-disable.hpui-datepicker'); textInput.on('hpui-disable.hpui-datepicker', function() { return function() { var textInput = jQuery(this); var hiddenInput = textInput.prev(hiddenInputSelector); var imageUrl = typeof (determineBaseImagesUrl) == 'function' ? determineBaseImagesUrl() : ""; // from init.js textInput.datepicker('disable'); // HPUI_IMG_URL is a global variable for the root URL to the images folder. textInput.datepicker('option','buttonImage', imageUrl + 'calendar_disabled.png'); if (hiddenInput && hiddenInput.length) hiddenInput.attr('disabled', '').removeAttr('readonly'); var icon = textInput.next(iconSelector); if (icon && icon.length) icon.attr('disabled', ''); } }()); // Register the custom readonly event on the datepicker text input. // Remember the text input assigns an event handler of its own; both will run. // This one only needs to do the extra steps the basic text input one does not. textInput.off('hpui-readonly.hpui-datepicker'); textInput.on('hpui-readonly.hpui-datepicker', function() { return function() { var textInput = jQuery(this); var hiddenInput = textInput.prev(hiddenInputSelector); var imageUrl = typeof (determineBaseImagesUrl) == 'function' ? determineBaseImagesUrl() : ""; // from init.js // A readonly datepicker is same as disabled so far as the calendar widget goes. textInput.datepicker('disable'); textInput.removeAttr('disabled'); // HPUI_IMG_URL is a global variable for the root URL to the images folder. textInput.datepicker('option','buttonImage', imageUrl + 'calendar_disabled.png'); if (hiddenInput && hiddenInput.length) hiddenInput.attr('readonly', '').removeAttr('disabled'); var icon = textInput.next(iconSelector); if (icon && icon.length) icon.attr('disabled', ''); } }()); textInput.off('click.hpui-datepicker'); textInput.on('click.hpui-datepicker', function (){ return function() { jQuery(this).datepicker( "show" ); } }()); // Forbid the keyboard events for date picker except 'Backspace', // 'Delete', 'Shift', 'Tab', 'Enter'. textInput.off('keydown.hpui-datepicker'); textInput.on('keydown.hpui-datepicker', function(event) { var textInput = jQuery(this); if (event.keyCode == 8 || event.keyCode == 46) { // 'Backspace', 'Delete' keys erase the date (ignore on // disabled and readonly datepickers). if (!textInput.attr('readonly') && !textInput.attr('disabled')) { textInput.trigger('hpui-clear'); textInput.datepicker('hide'); } event.preventDefault(); event.stopImmediatePropagation(); } else if (event.keyCode == 9) { // 'Tab' behaves as usual. } else if (event.keyCode == 13) { event.preventDefault(); textInput.datepicker( "show" ); } else { event.preventDefault(); } }); // Forbid all paste content into input text. textInput.off('paste'); textInput.on('paste.hpui-datepicker', function(event) { event.preventDefault(); }); // Forbid all cut content into input text. textInput.off('cut'); textInput.on('cut.hpui-datepicker', function(event) { event.preventDefault(); }); // Bind value event to this datepicker text input. // Remember the text input assigns an event handler of its own; both will run. // This one only needs to do the extra steps the basic text input one does not. textInput.off('hpui-value.hpui-datepicker'); textInput.on('hpui-value.hpui-datepicker', function(event, val) { var textInput = jQuery(this); if (val) { // Set the datepicker to the given value. First try our // canonical YYYYMMDD format. Then try the localized // displayable format. Finally validate the date. If all // of this fails, clear the datepicker using another trigger. var date = stringToDate(textInput, val); if (date && !isRestrictedDate(textInput, date)) textInput.datepicker('setDate', date); else textInput.trigger('hpui-clear'); } else { // Clear the datepicker if not given a value. textInput.datepicker('setDate', null); } }); // Register the custom clear event on the datepicker. textInput.off('hpui-clear.hpui-datepicker'); textInput.on('hpui-clear.hpui-datepicker', function() { return function() { var textInput = jQuery(this); // Clear is same as setting a blank value. textInput.trigger('hpui-value', ''); } }()); // Register the custom reset event on the input element. // Remember the text input assigns an event handler of its own; both will run. // This one only needs to do the extra steps the basic text input one does not. textInput.off('hpui-reset.hpui-datepicker'); textInput.on('hpui-reset.hpui-datepicker', function(initValue, initState) { return function() { var textInput = jQuery(this); // Reset the text input value to the initial value which may // have come from the hidden input. (The text input handler // for this event only takes the value from the text input // itself.) textInput.trigger('hpui-value', initValue); } }(currentValue, currentState)); // For fix accessibility issue. textInput.off('click.hpui-datepicker'); textInput.on('click.hpui-datepicker', function (){ return function() { jQuery(this).datepicker( "show" ); } }()); // Finish initializing this datepicker by setting its value and // state (disabled, readonly, enabled) according to the value and // state of the text input. The reset event handles this. textInput.trigger('hpui-reset'); textInput.datepicker('option',optionObject); } } } /****** end HPE date picker JS (datepicker.js) ******/ /****** begin HPE dropdowns JS (dropdowns.js) ******/ /*** "Public" functions - may be used by feature developers ***/ // Add screenreader messages for the given locale into the dropdowns // within the given context (may be a JQuery Object, a string HTML ID, or the whole // page by default). function hpuiAddDropdownResources(context) { // Get the message resources. if (typeof(hpuiAddMessageResources) == 'function') { hpuiAddMessageResources(); } // Determine the context (if not given). if (!context || !context.length || (typeof context != 'object') || !(context instanceof jQuery)) { if (context && typeof context == 'string') { context = jQuery('#' + context); } else { context = document; } } jQuery("select.hpui-select, select.hpui-action-menu, select.hpui-slim-select, select.hpui-critical-link-menu, " + "select.hpui-primary-link-menu, select.hpui-secondary-link-menu, select.hpui-filter-menu, " + "select.hpui-sort-menu, select.hpui-multi-select, select.hpui-slim-multi-select", context).each(function() { var dropdown = jQuery(this); if (!dropdown.attr('id')) // if no ID for the dropdown then skip it (should never happen // as MSDropdown auto-generates ID when it doesn't exist) return; var label = jQuery("label[for='" + dropdown.attr('id') + "']"); if (typeof label == "undefined" || label.length == 0) { // if no label for the dropdown then make an empty one and insert it after the select label = jQuery(""); dropdown.after(label); } var labelText = jQuery.trim(label.text()); if (!labelText) { // if new or existing label is empty, add screenreader text to it if (dropdown.hasClass('hpui-select') || dropdown.hasClass('hpui-slim-select') || dropdown.hasClass('hpui-multi-select') || dropdown.hasClass('hpui-slim-multi-select')) { if ((typeof dropdown_single_multi_select_screenreader == "string") && dropdown_single_multi_select_screenreader) { //non-empty screenreader text label.append("" + dropdown_single_multi_select_screenreader + ""); } } else if (dropdown.hasClass('hpui-action-menu')) { if ((typeof dropdown_actionmenu_screenreader == "string") && dropdown_actionmenu_screenreader) { //non-empty screenreader text label.append("" + dropdown_actionmenu_screenreader + ""); } } else if (dropdown.hasClass('hpui-critical-link-menu') || dropdown.hasClass('hpui-primary-link-menu') || dropdown.hasClass('hpui-secondary-link-menu')) { if ((typeof dropdown_linkmenu_screenreader == "string") && dropdown_linkmenu_screenreader) { //non-empty screenreader text label.append("" + dropdown_linkmenu_screenreader + ""); } } else if (dropdown.hasClass('hpui-filter-menu')) { if ((typeof dropdown_filterselect_screenreader == "string") && dropdown_filterselect_screenreader) { //non-empty screenreader text label.append("" + dropdown_filterselect_screenreader + ""); } } else if (dropdown.hasClass('hpui-sort-menu')) { if ((typeof dropdown_sortselect_screenreader == "string") && dropdown_sortselect_screenreader) { //non-empty screenreader text label.append("" + dropdown_sortselect_screenreader + ""); } } } }); } /*** "Private" functions not for direct use by feature developers ***/ // Initialize all stateful dropdowns in the given context. function initDropdowns(context) { // Utility function to generate the readonly input structure as needed. function generateReadonlyInputs(dropdown) { var id = dropdown.attr('id'); var name = dropdown.attr('name'); // get the options that will need hidden inputs var optionsNeeded = []; var options = dropdown.get(0).options; if (dropdown.attr('readonly')) // get all non-disabled, selected options when the dropdown as a // whole is readonly - these are the ones for the hidden inputs for (var i = 0; i < options.length; i++) { var option = options[i]; if (option.selected && (jQuery(option).attr('readonly') || !jQuery(option).attr('disabled'))) optionsNeeded.push(option); } else if (!dropdown.attr('disabled')) // when the dropdown is enabled, just get the selected options // that are readonly for (var j = 0; j < options.length; j++) { var option = options[j]; if (option.selected && jQuery(option).attr('readonly')) optionsNeeded.push(option); } // remove any existing hidden input structure jQuery('#' + id + "_msddnone").remove(); // generate the replacement structure, if any needed if (optionsNeeded.length > 0) { var div = jQuery('
'); div.attr('id', id + "_msddnone"); dropdown.parent().after(div); for (var k = 0; k < optionsNeeded.length; k++) { var option = jQuery(optionsNeeded[k]); var input = jQuery(''); input.attr('name', name); input.attr('value', option.val()); div.append(input); } } } // If there are any hpui-select or hpui-slim-select with "multiple" set, // convert them to hpui-multi-select or hpui-slim-multi-select. var wannaBeMultiple = jQuery('select[multiple].hpui-select,' + 'select[multiple].hpui-slim-select', context); wannaBeMultiple.each(function() { var dropdown = jQuery(this); if (dropdown.hasClass('hpui-select')) dropdown.removeClass('hpui-select').addClass('hpui-multi-select'); if (dropdown.hasClass('hpui-slim-select')) dropdown.removeClass('hpui-slim-select').addClass('hpui-slim-multi-select'); }); // If there are any hpui-multi-select set, make sure "multiple" is set. wannaBeMultiple = jQuery('select.hpui-multi-select,' + 'select.hpui-slim-multi-select', context); wannaBeMultiple.attr('multiple', ''); // Various initialization properties for the different types of stateful dropdown, // including multi-selects (that is why we normalized above, first). var dropdownTypeArray = [{className: "hpui-select", isTitleSupported: true, isMultiple: false}, {className: "hpui-slim-select", isTitleSupported: true, isMultiple: false}, {className: "hpui-multi-select", isTitleSupported: false, isMultiple: true}, {className: "hpui-slim-multi-select", isTitleSupported: false, isMultiple: true}, {className: "hpui-filter-menu", isTitleSupported: true, isMultiple: false}, {className: "hpui-sort-menu", isTitleSupported: true, isMultiple: false} ]; // Initialize each of the types of stateful dropdown. for (var _index = 0; _index < dropdownTypeArray.length; _index++) { var dropdownType = dropdownTypeArray[_index]; var hpui_dropdowns_self = jQuery('select.' + dropdownTypeArray[_index].className, context); if (hpui_dropdowns_self && hpui_dropdowns_self.length) { for (i = 0; i < hpui_dropdowns_self.length; i++) { var hpui_dropdown_self_obj = jQuery(hpui_dropdowns_self[i]); var currentSelectedIndex = []; var currentErrorIndex = []; var currentDisabledIndex = []; var currentReadonlyIndex = []; var isMultiple = dropdownType.isMultiple; var currentError = hpui_dropdown_self_obj.hasClass('hpui-error'); var disabled = hpui_dropdown_self_obj.attr('disabled'); var readonly = hpui_dropdown_self_obj.attr('readonly'); var currentState = readonly ? 'readonly' : 'enable'; currentState = disabled ? 'disable' : currentState; // Remember which options are initially selected, error, // disabled, and/or readonly. Error options are only supported // for multi-select. Single selects can have only one (the // last) selected option. Disabled and readonly are mutually // exclusive (disabled trumps readonly). var options = hpui_dropdown_self_obj.get(0).options; for (var j = 0; j < options.length; j++) { var option = jQuery(options[j]); if (option.get(0).selected) { if (isMultiple) currentSelectedIndex.push(j); else currentSelectedIndex[0] = j; } if (option.hasClass('hpui-error')) { if (isMultiple) currentErrorIndex.push(j); else option.removeClass('hpui-error'); } if (option.attr('disabled')) { currentDisabledIndex.push(j); } else if (option.attr('readonly')) { currentReadonlyIndex.push(j); } // Title allowed: Strip hpui-heading from any option but the first. // Title not allowed: strip hpui-heading throughout. if (!dropdownType.isTitleSupported || j > 0) option.removeClass('hpui-heading'); } var visibleRows = getVisibleRows(hpui_dropdown_self_obj); var isQualifiedFlag = checkVisibleRowIsQualified(visibleRows); // Register custom reset event handler on the stateful dropdown. hpui_dropdown_self_obj.off('hpui-reset.hpui-select'); hpui_dropdown_self_obj.on('hpui-reset.hpui-select', {initSelectedIndex: currentSelectedIndex, initError: currentError, initState: currentState, initErrorIndex: currentErrorIndex, initDisabledIndex: currentDisabledIndex, initReadonlyIndex: currentReadonlyIndex, initVisibleRows: visibleRows, initIsQualifiedFlag: isQualifiedFlag}, function(event) { // 'this' is the element. var option = null; var dropdown = jQuery(this); var visibleRows = event.data.initVisibleRows; var isQualifiedFlag = event.data.initIsQualifiedFlag; // were we triggered on an option and bubbled-up here? if (jQuery('#' + event.target.id).is('option')) option = jQuery('#' + event.target.id); // disable option or whole select as appropriate: if (option && option.length) { option.attr('disabled', ''); option.removeAttr('readonly'); } else { // set disabled and clear readonly dropdown.attr('disabled', ''); dropdown.removeAttr('readonly'); // set the label (if any) to indicate disabled if (typeof(disableLabel) == 'function') disableLabel(dropdown); } // teardown and rebuild the MS dropdown structure dropdown.msDropdown().data("dd").destroy(); if(typeof visibleRows != "undefined" && visibleRows && isQualifiedFlag) { // Call msDropdown function to construct the dropdown. dropdown.msDropdown({visibleRows: visibleRows}); }else { // Call msDropdown function to construct the dropdown. dropdown.msDropdown(); } // if this dropdown is in the readonly state, we must // rebuild its hidden inputs now, since the set of // readonly selected options may have changed generateReadonlyInputs(dropdown); }); // Register custom readonly event handler on the stateful dropdown. hpui_dropdown_self_obj.off('hpui-readonly.hpui-select'); hpui_dropdown_self_obj.on('hpui-readonly.hpui-select', {initVisibleRows: visibleRows, initIsQualifiedFlag: isQualifiedFlag}, function(event) { // 'this' is the element. var option = null; var dropdown = jQuery(this); var visibleRows = event.data.initVisibleRows; var isQualifiedFlag = event.data.initIsQualifiedFlag; // were we triggered on an option and bubbled-up here? if (jQuery('#' + event.target.id).is('option')) option = jQuery('#' + event.target.id); // enable option or whole select as appropriate: if (option && option.length) { option.removeAttr('disabled'); option.removeAttr('readonly'); } else { // clear disabled and readonly state attributes dropdown.removeAttr('disabled'); dropdown.removeAttr('readonly'); // set the label (if any) to indicate not disabled if (typeof(enableLabel) == 'function') enableLabel(dropdown); } // teardown and rebuild the MS dropdown structure dropdown.msDropdown().data("dd").destroy(); if(typeof visibleRows != "undefined" && visibleRows && isQualifiedFlag) { // Call msDropdown function to construct the dropdown. dropdown.msDropdown({visibleRows: visibleRows}); }else { // Call msDropdown function to construct the dropdown. dropdown.msDropdown(); } // if this dropdown is in the readonly state, we must // rebuild its hidden inputs now, since the set of // readonly selected options may have changed generateReadonlyInputs(dropdown); }); // Register custom toggle event handler on stateful dropdowns. hpui_dropdown_self_obj.off('hpui-toggle.hpui-select'); hpui_dropdown_self_obj.on('hpui-toggle.hpui-select', {}, function(event, val) { // 'this' is the element. var option = null; var dropdown = jQuery(this); var visibleRows = event.data.initVisibleRows; var isQualifiedFlag = event.data.initIsQualifiedFlag; // were we triggered on an option and bubbled-up here? if (jQuery('#' + event.target.id).is('option')) option = jQuery('#' + event.target.id); // set the selection as needed: if (option && option.length) { // if triggered on an option, select that option option.get(0).selected = true; } else { // if triggered on the select, select the option // with the given value (if no such option, this // does nothing; or if undefined value, this clears // the select). dropdown.val(val); } // do not reset error state! // tear-down and rebuild the MS dropdown structure. dropdown.msDropdown().data("dd").destroy(); if(typeof visibleRows != "undefined" && visibleRows && isQualifiedFlag) { // Call msDropdown function to construct the dropdown. dropdown.msDropdown({visibleRows: visibleRows}); }else { // Call msDropdown function to construct the dropdown. dropdown.msDropdown(); } // if this dropdown is in the readonly state, we must // rebuild its hidden inputs now, since the set of // readonly selected options may have changed generateReadonlyInputs(dropdown); }); } else { // single select hpui_dropdown_self_obj.off('hpui-value.hpui-select'); hpui_dropdown_self_obj.on('hpui-value.hpui-select', {}, function(event, val) { // 'this' is the element. var option = null; var dropdown = jQuery(this); var visibleRows = event.data.initVisibleRows; var isQualifiedFlag = event.data.initIsQualifiedFlag; // were we triggered on an option and bubbled-up here? if (jQuery('#' + event.target.id).is('option')) option = jQuery('#' + event.target.id); // clear the selection as needed: if (option && option.length) { // if triggered on an option, deselect that option option.get(0).selected = false; // and set OK on that option option.trigger('hpui-ok'); // tear-down and rebuild the MS dropdown structure. dropdown.msDropdown().data("dd").destroy(); if(typeof visibleRows != "undefined" && visibleRows && isQualifiedFlag) { // Call msDropdown function to construct the dropdown. dropdown.msDropdown({visibleRows: visibleRows}); }else { // Call msDropdown function to construct the dropdown. dropdown.msDropdown(); } } else { // if triggered on the select, deselect all options var nextSelectedIndex = dropdown.get(0).selectedIndex; while (nextSelectedIndex > -1) { dropdown.children("option")[nextSelectedIndex].selected = false; nextSelectedIndex = dropdown.get(0).selectedIndex; } // and set OK now on the select - this rebuilds // the MS dropdown structure too dropdown.trigger('hpui-ok'); } // if this dropdown is in the readonly state, we must // rebuild its hidden inputs now, since the set of // readonly selected options may have changed generateReadonlyInputs(dropdown); }); } else { hpui_dropdown_self_obj.off('hpui-clear.hpui-select'); hpui_dropdown_self_obj.on('hpui-clear.hpui-select', {}, function(event) { // 'this' is the element. var option = null; var dropdown = jQuery(this); var visibleRows = event.data.initVisibleRows; var isQualifiedFlag = event.data.initIsQualifiedFlag; // were we triggered on an option and bubbled-up here? if (jQuery('#' + event.target.id).is('option')) option = jQuery('#' + event.target.id); // set error status on the option or select level: if (option && option.length) { // option level // add error status at select level, and at // option level if selected dropdown.addClass("hpui-error"); if (option.get(0).selected) option.addClass("hpui-error"); } else { // select level dropdown.addClass("hpui-error"); } // teardown and rebuild MS dropdown structure dropdown.msDropdown().data("dd").destroy(); if(typeof visibleRows != "undefined" && visibleRows && isQualifiedFlag) { // Call msDropdown function to construct the dropdown. dropdown.msDropdown({visibleRows: visibleRows}); }else { // Call msDropdown function to construct the dropdown. dropdown.msDropdown(); } }); } else { // single-select hpui_dropdown_self_obj.off('hpui-error.hpui-select'); hpui_dropdown_self_obj.on('hpui-error.hpui-select', {initVisibleRows: visibleRows, initIsQualifiedFlag: isQualifiedFlag}, function(event) { // 'this' is the element. var option = null; var dropdown = jQuery(this); var visibleRows = event.data.initVisibleRows; var isQualifiedFlag = event.data.initIsQualifiedFlag; // were we triggered on an option and bubbled-up here? if (jQuery('#' + event.target.id).is('option')) option = jQuery('#' + event.target.id); // drop error status on the option or select level: if (option && option.length) { // option level // reset error on the option option.removeClass("hpui-error"); // if no error options remain, reset error on the select var options = dropdown.children("option"); var stillError = false; for (var k = 0; k < options.length; k++) if (jQuery(options[k]).hasClass("hpui-error")) stillError = true; if (!stillError) dropdown.removeClass("hpui-error"); } else { // select level // drop error class at select and option levels dropdown.children("option").removeClass("hpui-error"); dropdown.removeClass("hpui-error"); } // teardown and rebuild MS dropdown structure dropdown.msDropdown().data("dd").destroy(); if(typeof visibleRows != "undefined" && visibleRows && isQualifiedFlag) { // Call msDropdown function to construct the dropdown. dropdown.msDropdown({visibleRows: visibleRows}); }else { // Call msDropdown function to construct the dropdown. dropdown.msDropdown(); } }); } else { // single-select hpui_dropdown_self_obj.off('hpui-ok.hpui-select'); hpui_dropdown_self_obj.on('hpui-ok.hpui-select', {initVisibleRows: visibleRows, initIsQualifiedFlag: isQualifiedFlag}, function(event) { // 'this' is the '); hpui_text_input.attr('tabindex', '-1'); // disable tab key hpui_text_input.addClass(baseTextClass).addClass(baseFileClass); if (error) hpui_text_input.addClass('hpui-error'); if (disabled) hpui_text_input.attr('disabled', ''); else hpui_text_input.attr('readonly', 'readonly'); if (width) hpui_text_input.css('width', width); if (size) hpui_text_input.attr('size', size); // Generate a default-text span for this file input, if any. var hpui_default_text = hpui_file_input_self_obj.next('.hpui-default-text'); if (hpui_default_text && hpui_default_text.length) hpui_default_text = hpui_default_text.detach(); // Generate a new browse button for this file input. Different // technique depending on browser - IE8 needs a fake (span) button, // but we prefer to use a real button input for other browsers. var hpui_button, hpui_button_text; if (ieVersion > 0 && ieVersion < 9) { hpui_button_text = hpui_file_input_self_obj.attr('title'); if (hpui_button_text) hpui_file_input_self_obj.removeAttr('title'); else hpui_button_text = ""; hpui_button = jQuery('' + hpui_button_text + ''); hpui_button.addClass(baseButtonClass).addClass(baseFileClass); if (disabled) hpui_button.attr('disabled', ''); else hpui_button.attr('tabindex', '0'); buttonSelector = 'span.' + baseButtonClass + '.' + baseFileClass; } else { hpui_button = jQuery(''); hpui_button.addClass(baseButtonClass).addClass(baseFileClass); if (disabled) hpui_button.attr('disabled', ''); hpui_button_text = hpui_file_input_self_obj.attr('title'); if (hpui_button_text) { hpui_button.attr('value', hpui_button_text); hpui_file_input_self_obj.removeAttr('title'); } buttonSelector = 'input[type=button].' + baseButtonClass + '.' + baseFileClass; } // Generate a span container for the above. hpui_file_span = jQuery(''); // IE 10, 9, and 8 only: generate a fake label container for the text // and button inputs. This is to workaround a security constraint // in IE prior to version 11: these versions of IE only allow a file // input to be legally triggered from the original file input itself // or an associated label. Since this code hides the original file // input and generates a visible text and button input for the user // to interact with instead, in these versions of IE this is not legal, // and the file input will be ignored and reset, and the form submit // aborted, when the form is submitted. But since these versions of // IE allow anything declared a label for the file input to legally // trigger the file input, if we wrap our text and button inputs in // a label, this will satisfy IE. Since this is an IE-specific hack, // we only do this for the needed versions of IE: 10 and earlier. The // "hpui-fake" class means this label will not be selected later (see // getLabel(...) function). if (ieVersion > 0 && ieVersion < 11) { var ieID = generateId(hpui_file_input_self_obj); var ieLabel = jQuery(''); ieLabel.append(hpui_text_input); if (hpui_default_text) ieLabel.append(hpui_default_text); ieLabel.append(hpui_button); hpui_file_span.append(ieLabel); } else { hpui_file_span.append(hpui_text_input); if (hpui_default_text) hpui_file_span.append(hpui_default_text); hpui_file_span.append(hpui_button); } // Set screenreader text into the span, and add it to the DOM. if (typeof(hpuiInitialize) == 'function') hpuiInitialize(hpui_file_span); hpui_file_input_self_obj.before(hpui_file_span); setFileScreenreaderText(hpui_file_input_self_obj, hpui_text_input, hpui_button); // If there is an upload button, disable it and wrap all of this - // the span container for the above, the file input, and the upload // button - inside another span container. var hpui_upload = hpui_file_input_self_obj.next(uploadSelector); if (hpui_upload && hpui_upload.length) { // Always initialize to disabled. hpui_upload.attr('disabled', ''); var hpui_parent_span = hpui_file_input_self_obj.parent(spanSelector); if (!hpui_parent_span || !hpui_parent_span.length) { hpui_parent_span = jQuery(''); hpui_file_input_self_obj.wrap(hpui_parent_span); hpui_file_span.detach(); hpui_upload.detach(); hpui_file_span.insertBefore(hpui_file_input_self_obj); hpui_upload.insertAfter(hpui_file_input_self_obj); // To eliminate gap between browse and upload buttons. hpui_file_span.css('float', 'left'); } } } // Register change handler to copy filename value to text input. hpui_file_input_self_obj.off('change.hpui-file'); hpui_file_input_self_obj.on('change.hpui-file', function() { return function() { var fileInput = jQuery(this); var textInput = fileInput.prev(spanSelector).find(textInputSelector); var buttonInput = fileInput.prev(spanSelector).find(buttonSelector); var upload = fileInput.next(uploadSelector); // Backfill the filename into the text input. if (textInput && textInput.length) { var filename = fileInput.val(); // Some browsers prepend path info - strip this for user security. // Paths may be delimited by \ or / chars on different systems. var j = Math.max(filename.lastIndexOf("/"), filename.lastIndexOf("\\")); if (j != -1) { if (j < filename.length - 1) filename = filename.substring(j + 1); else filename = ""; } // Set the text input value equal to the file input value. textInput.trigger('hpui-value', filename); } // Enable or disable the upload button, if any. if (upload) { if (fileInput.val()) upload.removeAttr('disabled'); else upload.attr('disabled', ''); } // Update the screenreader text setFileScreenreaderText(fileInput, textInput, buttonInput); } }()); // Register the disable event on the file element. hpui_file_input_self_obj.off('hpui-disable.hpui-file'); hpui_file_input_self_obj.on('hpui-disable.hpui-file', function() { return function() { var fileInput = jQuery(this); var buttonInput = fileInput.prev(spanSelector).find(buttonSelector); var textInput = fileInput.prev(spanSelector).find(textInputSelector); fileInput.attr('disabled', ''); // disable file input if (buttonInput && buttonInput.length) buttonInput.attr('disabled', ''); // disable button if (textInput && textInput.length) textInput.trigger('hpui-disable'); // disable text input disableLabel(fileInput); // disable label if any // Update the screenreader text setFileScreenreaderText(fileInput, textInput, buttonInput); } }()); // Register the enable event on the file element. hpui_file_input_self_obj.off('hpui-enable.hpui-file'); hpui_file_input_self_obj.on('hpui-enable.hpui-file', function() { return function() { var fileInput = jQuery(this); var buttonInput = fileInput.prev(spanSelector).find(buttonSelector); var textInput = fileInput.prev(spanSelector).find(textInputSelector); fileInput.removeAttr('disabled'); // enable file input if (buttonInput && buttonInput.length) buttonInput.removeAttr('disabled'); // enable button if (textInput && textInput.length) textInput.trigger('hpui-readonly'); // enable text input (readonly) enableLabel(fileInput); // enable label if any // Update the screenreader text setFileScreenreaderText(fileInput, textInput, buttonInput); } }()); // Register the reset event on the file element. hpui_file_input_self_obj.off('hpui-reset.hpui-file'); hpui_file_input_self_obj.on('hpui-reset.hpui-file', function(initState) { return function() { var fileInput = jQuery(this); var textInput = fileInput.prev(spanSelector).find(textInputSelector); var buttonInput = fileInput.prev(spanSelector).find(buttonSelector); // Reset to initial enabled/disabled state - this takes care // of file input, button, text input and label. fileInput.trigger('hpui-' + initState); // Reset to initial value (file elements are always blank initially): // // First clear the file input. Some browsers let us just set // it to blank, others require replacing it with a new one (a clone // of the original, so all attributes and event handlers remain): fileInput.replaceWith(fileInput.val('').clone(true)); // Then reset the text input. if (textInput && textInput.length) textInput.trigger('hpui-reset'); // Update the screenreader text setFileScreenreaderText(fileInput, textInput, buttonInput); } }(currentState)); // Register the clear event on the file element. hpui_file_input_self_obj.off('hpui-clear.hpui-file'); hpui_file_input_self_obj.on('hpui-clear.hpui-file', function() { return function() { var fileInput = jQuery(this); var textInput = fileInput.prev(spanSelector).find(textInputSelector); var buttonInput = fileInput.prev(spanSelector).find(buttonSelector); // Clear the file input. Some browsers let us just set it to // to blank, others require replacing it with a new one (a clone // of the original, so all attributes and event handlers remain): fileInput.replaceWith(fileInput.val('').clone(true)); // Then clear the text input. if (textInput && textInput.length) textInput.trigger('hpui-clear'); // Update the screenreader text setFileScreenreaderText(fileInput, textInput, buttonInput); } }()); // Register the error status event on the file element. hpui_file_input_self_obj.off('hpui-error.hpui-file'); hpui_file_input_self_obj.on('hpui-error.hpui-file', function() { return function() { var fileInput = jQuery(this); var textInput = fileInput.prev(spanSelector).find(textInputSelector); // Just set error status on the text input. if (textInput && textInput.length) textInput.trigger('hpui-error'); } }()); // Register the OK status event on the file element. hpui_file_input_self_obj.off('hpui-ok.hpui-file'); hpui_file_input_self_obj.on('hpui-ok.hpui-file', function() { return function() { var fileInput = jQuery(this); var textInput = fileInput.prev(spanSelector).find(textInputSelector); // Just set OK status on the text input. if (textInput && textInput.length) textInput.trigger('hpui-ok'); } }()); // Note: cannot register hpui-value event handler on file input // due to browser security constraints (browsers do not let you // programatically set a file input value). So hpui-value event // will be ignored by file inputs. } } // Find and process all file text inputs. var hpui_text_input_self = jQuery(textInputSelector, context); if (hpui_text_input_self && hpui_text_input_self.length) { for (var i = 0; i < hpui_text_input_self.length; i++) { var hpui_text_input_self_obj = jQuery(hpui_text_input_self[i]); // Override default keydown event handler (except for tab and enter keys). hpui_text_input_self_obj.off('keydown.hpui-file'); hpui_text_input_self_obj.on('keydown.hpui-file', function(event) { var textInput = jQuery(this); var key = event.keyCode; // number value, not string if (key != 9) { // tab key handled as usual event.preventDefault(); // other keys canceled... textInput.trigger('click'); // and handled like click } }); // Override default click event handler, to open file browser. // This no-ops in IE 10 and lower, which is OK (see comments above // about how we use a fake label tag instead in those browsers). hpui_text_input_self_obj.off('click.hpui-file'); hpui_text_input_self_obj.on('click.hpui-file', function(event) { var textInput = jQuery(this); var fileInput = textInput.parent(spanSelector).next(fileInputSelector); if (fileInput && fileInput.length) { // Cancel default click action and blur immediately. event.stopImmediatePropagation(); event.preventDefault(); textInput.blur(); // Trigger file browser to open. fileInput.trigger('click'); } }); // Remove any focus event handler to prevent keyboard focus. hpui_text_input_self_obj.off('focus'); hpui_text_input_self_obj.on('focus.hpui-file', function(event) { event.stopImmediatePropagation(); event.preventDefault(); }); hpui_text_input_self_obj.off('mousedown'); hpui_text_input_self_obj.on('mousedown.hpui-file', function(event) { event.stopImmediatePropagation(); event.preventDefault(); }); hpui_text_input_self_obj.off('mouseup'); hpui_text_input_self_obj.on('mouseup.hpui-file', function(event) { event.stopImmediatePropagation(); event.preventDefault(); }); } } // Find and process all button inputs. var hpui_file_button_self = jQuery(buttonSelector, context); if (hpui_file_button_self && hpui_file_button_self.length) { for (var i = 0; i < hpui_file_button_self.length; i++) { var hpui_file_button_self_obj = jQuery(hpui_file_button_self[i]); // Register click handler to open file browser. // This no-ops in IE 10 and lower, which is OK (see comments above // about how we use a fake label tag instead in those browsers). hpui_file_button_self_obj.off('click.hpui-file'); hpui_file_button_self_obj.on('click.hpui-file', function() { var buttonInput = jQuery(this); var fileInput = buttonInput.parent(spanSelector).next(fileInputSelector); if (fileInput && fileInput.length) // Trigger file browser to open. fileInput.trigger('click'); }); } } } // Initialize text inputs in the given context. function initTextInputs(baseClass, context) { // Find and process all HPUI text inputs of this current class in this page. var hpui_input_self = jQuery('input[type=text].' + baseClass + ',input[type=password].' + baseClass, context); if (hpui_input_self && hpui_input_self.length) { for (var i = 0; i < hpui_input_self.length; i++) { var hpui_input_self_obj = jQuery(hpui_input_self[i]); var preValue = hpui_input_self_obj.next('.hpui-default-text').html(); var disabled = hpui_input_self_obj.attr('disabled'); var readonly = hpui_input_self_obj.attr('readonly') var error = hpui_input_self_obj.hasClass('hpui-error'); var currentClass = error ? baseClass + ' hpui-error' : baseClass; var currentValue = hpui_input_self_obj.attr('value'); var currentState = readonly ? 'readonly' : 'enable'; currentValue = currentValue ? currentValue : ''; currentState = disabled ? 'disable' : currentState; // Register the focus event on the input element. hpui_input_self_obj.off('focus.hpui-input'); hpui_input_self_obj.on('focus.hpui-input', function(preVal) { return function() { var input = jQuery(this); // Ignore focus on disabled and readonly inputs. if (input.attr('disabled') || input.attr('readonly')) { return; } // On focus, clear current value if filled with default value if (input.attr('value') == preVal) input.attr('value', ''); // On focus, set entered class (but leave error state alone) if (!input.hasClass('hpui-error')) input.addClass('hpui-entered'); } }(preValue)); // Register the blur event on the input element. hpui_input_self_obj.off('blur.hpui-input') hpui_input_self_obj.on('blur.hpui-input', function() { return function() { var input = jQuery(this); // Ignore blur on disabled and readonly inputs. if (input.attr('disabled') || input.attr('readonly')) return; // On blur, reinitialize value and style based on current value. // For datepickers, we do not need to do this as the // datepicker's onSelect and onClose take care of this. if (!input.hasClass('hpui-datepicker') && !input.hasClass('hpui-slim-datepicker')) input.trigger('hpui-value', input.attr('value')); } }()); // Register the custom disable event on the input element. hpui_input_self_obj.off('hpui-disable.hpui-input'); hpui_input_self_obj.on('hpui-disable.hpui-input', function() { return function() { var input = jQuery(this); // Set disabled in the HTML. input.attr('disabled', '').removeAttr('readonly'); // Set disabled style on corresponding label, if any. disableLabel(input); } }()); // Register the custom enable event on the input element. hpui_input_self_obj.off('hpui-enable.hpui-input'); hpui_input_self_obj.on('hpui-enable.hpui-input', function() { return function() { var input = jQuery(this); // Set enabled in the HTML. input.removeAttr('disabled').removeAttr('readonly'); // Set enabled style on corresponding label, if any. enableLabel(input); } }()); // Register the custom readonly event on the input element. hpui_input_self_obj.off('hpui-readonly.hpui-input'); hpui_input_self_obj.on('hpui-readonly.hpui-input', function() { return function() { var input = jQuery(this); // Set readonly in the HTML. input.attr('readonly', '').removeAttr('disabled'); // Set enabled style on corresponding label, if any. enableLabel(input); } }()); // Register the custom reset event on the input element. hpui_input_self_obj.off('hpui-reset.hpui-input'); hpui_input_self_obj.on('hpui-reset.hpui-input', function(initValue, initClass, initState) { return function() { var input = jQuery(this); // Reset the text input style input.removeClass('hpui-entered hpui-error').addClass(initClass); // Reset the text input disabled/readonly/enabled state input.trigger('hpui-' + initState); // Reset the text input value input.trigger('hpui-value', initValue); } }(currentValue, currentClass, currentState)); // Register the custom error status event on the input element. hpui_input_self_obj.off('hpui-error.hpui-input'); hpui_input_self_obj.on('hpui-error.hpui-input', function() { return function() { var input = jQuery(this); // Set error class in every case. input.addClass('hpui-error').removeClass('hpui-entered'); // Reinitialize value and style based on current value. input.trigger('hpui-value', input.attr('value')); } }()); // Register the custom OK status event on the input element. hpui_input_self_obj.off('hpui-ok.hpui-input'); hpui_input_self_obj.on('hpui-ok.hpui-input', function() { return function() { var input = jQuery(this); // Remove error class in every case. input.removeClass('hpui-error').removeClass('hpui-entered'); // Reinitialize value and style based on current value. input.trigger('hpui-value', input.attr('value')); } }()); // Register the custom value event on the input element. hpui_input_self_obj.off('hpui-value.hpui-input'); hpui_input_self_obj.on('hpui-value.hpui-input', {preVal:preValue}, function(event, val) { var input = jQuery(this); // Set the value for the text input. input.attr('value', val); // If the value is blank, override with any default value. if (!input.attr('value') && event.data.preVal) input.attr('value', event.data.preVal); // If there is no error, and the value is not blank and not // defaulted, set the entered class. if (!input.hasClass('hpui-error')) { if (input.attr('value') && (input.attr('value') != event.data.preVal)) input.addClass('hpui-entered'); else input.removeClass('hpui-entered'); } else input.removeClass('hpui-entered'); // If the value is set when in focus, trigger focus event to set // proper styles. if (input.is(':focus')) input.trigger('focus'); }); // Register the custom clear event on the input element. hpui_input_self_obj.off('hpui-clear.hpui-input'); hpui_input_self_obj.on('hpui-clear.hpui-input', function() { return function() { var input = jQuery(this); // Clear value and style - same as setting value to blank. input.trigger('hpui-value', ''); } }()); // Initialize text input state (disabled, readonly, enabled, value // and class) based on current state. hpui_input_self_obj.trigger('hpui-reset'); } } } // Initialize textareas in the given context. function initTextareas(context) { // Find an process all HPUI textareas in this page. var hpui_input_self = jQuery('textarea.hpui-textarea', context); if (hpui_input_self && hpui_input_self.length) { for (var i = 0; i < hpui_input_self.length; i++) { var hpui_input_self_obj = jQuery(hpui_input_self[i]); var preValue = hpui_input_self_obj.next('.hpui-default-text').html(); var error = hpui_input_self_obj.hasClass('hpui-error'); var disabled = hpui_input_self_obj.attr('disabled'); var readonly = hpui_input_self_obj.attr('readonly'); var currentValue = hpui_input_self_obj.val(); var currentClass = error ? 'hpui-textarea hpui-error' : 'hpui-textarea'; var currentState = readonly ? 'readonly' : 'enable'; currentState = disabled ? 'disable' : currentState; // Add modifier classes - at this time, just a font class. hpui_input_self_obj.addClass('hpui-textarea-font'); // Register the focus event on the textarea. hpui_input_self_obj.off('focus.hpui-textarea'); hpui_input_self_obj.on('focus.hpui-textarea', function(preVal) { return function(){ var input = jQuery(this); // Ignore focus on disabled and readonly inputs. if (input.attr('disabled') || input.attr('readonly')) { return; } // On focus, clear current value if filled with default value if (input.val() == preVal) input.val(''); // On focus, set entered class (but leave error state alone) if (!input.hasClass('hpui-error')) input.addClass('hpui-entered'); } }(preValue)); // Register the blur event on the textarea. hpui_input_self_obj.off('blur.hpui-textarea'); hpui_input_self_obj.on('blur.hpui-textarea', function() { return function(){ var input = jQuery(this); // Ignore blur on disabled and readonly inputs. if (input.attr('disabled') || input.attr('readonly')) return; // On blur, reinitialize value and style based on current value. input.trigger('hpui-value', input.val()); } }()); // Register the custom disable event on the textarea. hpui_input_self_obj.off('hpui-disable.hpui-textarea'); hpui_input_self_obj.on('hpui-disable.hpui-textarea', function() { return function() { var input = jQuery(this); // Set disabled in the HTML. input.attr('disabled', '').removeAttr('readonly'); // Disable resize and scroll regardless of class. input.resizable({handles: "se"}); input.resizable('disable'); input.css('overflow', 'hidden'); // Set disabled style on corresponding label, if any. disableLabel(input); } }()); // Register the custom enable event on the textarea. hpui_input_self_obj.off('hpui-enable.hpui-textarea'); hpui_input_self_obj.on('hpui-enable.hpui-textarea', function() { return function() { var input = jQuery(this); var resizable = input.hasClass('hpui-resizable'); // Set enabled in the HTML. input.removeAttr('disabled').removeAttr('readonly'); // Set enabled resize and scroll behaviors per class. input.resizable({handles: "se"}); input.resizable(resizable ? 'enable' : 'disable'); if (resizable) input.css('overflow', 'hidden'); else { input.css('overflow-y', 'auto'); input.css('overflow-x', 'hidden'); } // Set enabled style on corresponding label, if any. enableLabel(input); } }()); // Register the custom readonly event on the textarea. hpui_input_self_obj.off('hpui-readonly.hpui-textarea'); hpui_input_self_obj.on('hpui-readonly.hpui-textarea', function() { return function() { var input = jQuery(this); var resizable = input.hasClass('hpui-resizable'); // Set readonly in the HTML. input.attr('readonly', '').removeAttr('disabled'); // Set readonly resize and scroll behaviors per class. input.resizable({handles: "se"}); input.resizable(resizable ? 'enable' : 'disable'); if (resizable) input.css('overflow', 'hidden'); else { input.css('overflow-y', 'auto'); input.css('overflow-x', 'hidden'); } // Set enabled style on corresponding label, if any. enableLabel(input); } }()); // Register the custom error status event on the textarea. hpui_input_self_obj.off('hpui-error.hpui-textarea'); hpui_input_self_obj.on('hpui-error.hpui-textarea', function() { return function() { var input = jQuery(this); // Set error class in every case. input.addClass('hpui-error').removeClass('hpui-entered'); // Reinitialize value and style based on current value. input.trigger('hpui-value', input.val()); } }()); // Register the custom OK status event on the textarea. hpui_input_self_obj.off('hpui-ok.hpui-textarea'); hpui_input_self_obj.on('hpui-ok.hpui-textarea', function() { return function() { var input = jQuery(this); // Remove error class in every case. input.addClass('hpui-textarea'); input.removeClass('hpui-error').removeClass('hpui-entered'); // Reinitialize value and style based on current value. input.trigger('hpui-value', input.val()); } }()); // Register the custom value event on the textarea. hpui_input_self_obj.off('hpui-value.hpui-textarea'); hpui_input_self_obj.on('hpui-value.hpui-textarea', {preVal:preValue}, function(event, val) { var input = jQuery(this); // Set the value for the textarea. input.val(val); // If the value is blank, override with any default value. if (!input.val() && event.data.preVal) input.val(event.data.preVal); // If the value is not blank and not any default, set the // entered class; otherwise set the base class. But if an error // class, leave this alone. if (!input.hasClass('hpui-error')) { if (input.val() && (input.val() != event.data.preVal)) input.addClass('hpui-entered'); else input.removeClass('hpui-entered'); } else input.removeClass('hpui-entered'); // If the value is set when in focus, trigger focus event to set // proper styles. if (input.is(':focus')) input.trigger('focus'); }); // Register the custom clear event on the textarea. hpui_input_self_obj.off('hpui-clear.hpui-textarea'); hpui_input_self_obj.on('hpui-clear.hpui-textarea', function() { return function() { var input = jQuery(this); // Clear value and style - same as setting value to blank. input.trigger('hpui-value', ''); } }()); // Initialize textarea state (disabled, readonly, enabled) based // on current state. hpui_input_self_obj.trigger('hpui-' + currentState); // Initialize textarea value based on current value. hpui_input_self_obj.trigger('hpui-value', currentValue); // Register the custom reset event on the text field element (this // can only happen after the width and height have been set by // JQuery Resizable, which happened above) var currentWidth = hpui_input_self_obj.width(); var currentHeight = hpui_input_self_obj.height(); hpui_input_self_obj.off('hpui-reset.hpui-textarea'); hpui_input_self_obj.on('hpui-reset.hpui-textarea', function(initValue, initClass, initWidth, initHeight, initState) { return function() { var input = jQuery(this); // Reset the textarea size. input.resizable('destroy'); input.width(initWidth); input.height(initHeight); // Reset the textarea style. input.removeClass('hpui-error hpui-entered').addClass(initClass); // Reset the textarea disabled/readonly/enabled state. input.trigger('hpui-' + initState); // Reset the textarea value. input.trigger('hpui-value', initValue); } }(currentValue, currentClass, currentWidth, currentHeight, currentState)); } } } // Initialize checkboxes in the given context. function initCheckboxes(context) { // Find and process all HPUI checkboxes in this page. var hpui_checkbox_self = jQuery('input[type=checkbox].hpui-checkbox', context); if (hpui_checkbox_self && hpui_checkbox_self.length) { for (var i = 0; i < hpui_checkbox_self.length; i++) { var hpui_checkbox_self_obj = jQuery(hpui_checkbox_self[i]); var error = hpui_checkbox_self_obj.hasClass('hpui-error'); var disabled = hpui_checkbox_self_obj.attr('disabled'); var readonly = hpui_checkbox_self_obj.attr('readonly'); var checked = hpui_checkbox_self_obj.attr('checked'); var currentClass = error ? 'hpui-checkbox hpui-error' : 'hpui-checkbox'; var currentChecked = checked ? 'checked' : ''; var currentState = readonly ? 'readonly' : 'enable'; currentState = disabled ? 'disable' : currentState; // Generate an anchor tag and prepend it to the checkbox input, if // it does not already exist. And make sure the input display is // turned off and screenreader text is set. hpui_checkbox_self_obj.css({display:'none'}); var hpui_checkbox = hpui_checkbox_self_obj.prev('a.hpui-checkbox'); if (!hpui_checkbox || !hpui_checkbox.length) { hpui_checkbox = jQuery(""); // Initialize screenreading text. setCheckboxScreenreaderText(hpui_checkbox_self_obj, hpui_checkbox); // Attach the new checkbox to the DOM. hpui_checkbox_self_obj.before(hpui_checkbox); } // Register the click event on the label, to trigger click on anchor // instead of default action. var labelEl = getLabel(hpui_checkbox_self_obj); if (labelEl) { labelEl.off('click.hpui-checkbox'); labelEl.on('click.hpui-checkbox', {anchor:hpui_checkbox}, function(event) { event.preventDefault(); event.data.anchor.trigger('click'); }); } // Register the click event on the anchor. As a click event, this // propagates to the standard click handler first, and may be // canceled by the standard handler. It delegates to the standard // click handler to toggle the checkbox state, then syncs the CSS // class, screenreader text and anchor state with it. hpui_checkbox.off('click.hpui-checkbox'); hpui_checkbox.on('click.hpui-checkbox', {input:hpui_checkbox_self_obj}, function(event) { var anchor = jQuery(this); var input = event.data.input; // Ignore click on disabled and readonly inputs. if (anchor.attr('disabled') || anchor.attr('readonly')) return; // Trigger the native checkbox click. Note: In JQuery this does not affect the 'checked' // attribute, just the internal state. input.trigger(event); // If the native handling canceled the event, stop. if (event.isDefaultPrevented() || event.isPropagationStopped() || event.isImmediatePropagationStopped()) return; // Now sync CSS class and anchor state with checkbox state. anchor.removeClass('hpui-error'); // Remove error state, if any input.removeClass('hpui-error'); // Remove error state, if any // Because the native checkbox click handler (see above) only affected the internal state, // use .prop method to query state of the checkbox. Then forcibly set the 'checked' // attribute accordingly for all subsequent logic to use. (This is for backward-compatibility // with all the other existing code in this JS file, which expects the .attr('checked') method // to reflect not just the state of the 'checked' attribute but also the internal state of thecheckbox.) if (input.prop('checked')) { anchor.attr('checked', 'checked'); input.attr('checked', 'checked'); } else { anchor.removeAttr('checked'); input.removeAttr('checked'); } // Set screenreading text. setCheckboxScreenreaderText(input, anchor); }); // Register custom event on the input to toggle (or set/unset) the // checked state and then set the class consistent with that. This // does not propagate to the standard click handler, nor use it to // set the checkbox checked state (compare with click handler // above). hpui_checkbox_self_obj.off('hpui-toggle.hpui-checkbox'); hpui_checkbox_self_obj.on('hpui-toggle.hpui-checkbox', {anchor:hpui_checkbox}, function(event, on) { var anchor = event.data.anchor; var input = jQuery(this); if (on == undefined) on = input.attr('checked') ? false : true; // Clear any error class on anchor and checkbox if ((on && !input.attr('checked')) || (!on && input.attr('checked'))) { anchor.removeClass('hpui-error'); input.removeClass('hpui-error'); } // Set checked or unchecked on anchor and checkbox if (on) { anchor.attr('checked', 'checked'); input.attr('checked', 'checked'); } else { anchor.removeAttr('checked'); input.removeAttr('checked'); } // Set screenreading text. setCheckboxScreenreaderText(input, anchor); }); // Register the custom disable event on the input element. hpui_checkbox_self_obj.off('hpui-disable.hpui-checkbox'); hpui_checkbox_self_obj.on('hpui-disable.hpui-checkbox', function(anchor) { return function() { var input = jQuery(this); // Set disabled in the HTML. anchor.attr('disabled', '').removeAttr('readonly'); input.attr('disabled', '').removeAttr('readonly'); // Set disabled style on corresponding label, if any. disableLabel(input); // Set screenreading text. setCheckboxScreenreaderText(input, anchor); } }(hpui_checkbox)); // Register the custom enable event on the input element. hpui_checkbox_self_obj.off('hpui-enable.hpui-checkbox'); hpui_checkbox_self_obj.on('hpui-enable.hpui-checkbox', function(anchor) { return function() { var input = jQuery(this); // Set enabled in the HTML. anchor.removeAttr('disabled').removeAttr('readonly'); input.removeAttr('disabled').removeAttr('readonly'); // Set enabled style on corresponding label, if any. enableLabel(input); // Set screenreading text. setCheckboxScreenreaderText(input, anchor); } }(hpui_checkbox)); // Register the custom readonly event on the input element. hpui_checkbox_self_obj.off('hpui-readonly.hpui-checkbox'); hpui_checkbox_self_obj.on('hpui-readonly.hpui-checkbox', function(anchor) { return function() { var input = jQuery(this); // Set enabled in the HTML. anchor.attr('readonly', '').removeAttr('disabled'); input.attr('readonly', '').removeAttr('disabled'); // Set enabled style on corresponding label, if any. enableLabel(input); // Set screenreading text. setCheckboxScreenreaderText(input, anchor); } }(hpui_checkbox)); // Register the custom error status event on the input element. hpui_checkbox_self_obj.off('hpui-error.hpui-checkbox'); hpui_checkbox_self_obj.on('hpui-error.hpui-checkbox', function(anchor) { return function() { var input = jQuery(this); // Set error class in every case. input.addClass('hpui-error'); anchor.addClass('hpui-error'); } }(hpui_checkbox)); // Register the custom OK status event on the input element. hpui_checkbox_self_obj.off('hpui-ok.hpui-checkbox'); hpui_checkbox_self_obj.on('hpui-ok.hpui-checkbox', function(anchor) { return function() { var input = jQuery(this); // Remove error class in every case. input.removeClass('hpui-error'); anchor.removeClass('hpui-error'); } }(hpui_checkbox)); // Register the custom value event on the input element. hpui_checkbox_self_obj.off('hpui-value.hpui-checkbox'); hpui_checkbox_self_obj.on('hpui-value.hpui-checkbox', function(event, val) { var input = jQuery(this); // Value event with blank value is same as toggle-off; value // event with any non-blank value is same as toggle-on. var on = val; input.trigger('hpui-toggle', on); }); // Register the custom clear event on the input element. hpui_checkbox_self_obj.off('hpui-clear.hpui-checkbox'); hpui_checkbox_self_obj.on('hpui-clear.hpui-checkbox', function() { var input = jQuery(this); // Clear event is same as toggle-off. input.trigger('hpui-toggle', false); }); // Register the custom reset event on the input element. hpui_checkbox_self_obj.off('hpui-reset.hpui-checkbox'); hpui_checkbox_self_obj.on('hpui-reset.hpui-checkbox', function(anchor, initOn, initClass, initState) { return function() { var input = jQuery(this); // Set the checkbox to proper checked/unchecked state input.trigger('hpui-toggle', initOn); // Reset class on checkbox and associated anchor to initial class input.removeClass('hpui-error').addClass(initClass); anchor.removeClass('hpui-error').addClass(initClass); // Reset disabled and/or readonly states to initial state input.trigger('hpui-' + initState); } }(hpui_checkbox, currentChecked, currentClass, currentState)); // Initialize checkbox state (disabled, readonly, enabled, // checked/unchecked and class) based on current values hpui_checkbox_self_obj.trigger('hpui-reset'); } } } // Initialize radio buttons in the given context. function initRadioButtons(context) { // Setup checked/unchecked state across a radio button group function normalizeHPUIradios(input, anchor, group, on) { if (on) { // Uncheck all radio buttons in this group. group.prev('a.hpui-radio').removeAttr('checked'); group.removeAttr('checked'); // Then checkmark this radio button. anchor.attr('checked', 'checked'); input.attr('checked', 'checked'); // Finally set screenreading text across the group. group.each(function() { var input = jQuery(this); var anchor = input.prev('a.hpui-radio'); setRadioScreenreaderText(input, anchor); }); } else { // Uncheck this radio button. No side-effect on the group. anchor.removeAttr('checked'); input.removeAttr('checked'); // Finally set screenreading text. setRadioScreenreaderText(input, anchor); } } // Get radion buttons just in this group function getHPUIradios(all, name) { return all.filter(function(index) { return (jQuery(this).attr('name') == name) ? true : false; }); } // Find and process all HPUI radio buttons in the page. var hpui_radioButton_self = jQuery('input[type=radio].hpui-radio', context); if (hpui_radioButton_self && hpui_radioButton_self.length) { // For each radio button element create an anchor element for the // styling and insert before the radio button, if it does not already // exist. And make sure the input display is off. for (var i = 0; i < hpui_radioButton_self.length; i++) { var hpui_radioButton_self_obj = jQuery(hpui_radioButton_self[i]); var error = hpui_radioButton_self_obj.hasClass('hpui-error'); var currentClass = error ? 'hpui-radio hpui-error' : 'hpui-radio'; var hpui_radioButton = hpui_radioButton_self_obj.prev('a.hpui-radio'); hpui_radioButton_self_obj.css({display:'none'}); if (!hpui_radioButton || !hpui_radioButton.length) { hpui_radioButton = jQuery(""); // Attach the new anchor into the DOM. hpui_radioButton_self_obj.before(hpui_radioButton); } } // For each radio button element find all the related elements and set // them to their normalized initial state across the associated radio // button group. Normalized means: if the page started with 2+ radio // buttons both checked in the same group (an illegal state), the first // one "wins" and the other is unchecked. We can only do this after all // the radios have been initialized with their anchor tags in the loop // above. for(i = 0; i < hpui_radioButton_self.length; i++){ var hpui_radioButton_self_obj = jQuery(hpui_radioButton_self[i]); var hpui_radioButton = hpui_radioButton_self_obj.prev('a.hpui-radio'); var name = hpui_radioButton_self_obj.attr('name'); var checked = hpui_radioButton_self_obj.attr('checked'); var radioButtonGroup = getHPUIradios(hpui_radioButton_self, name); normalizeHPUIradios(hpui_radioButton_self_obj, hpui_radioButton, radioButtonGroup, checked); } // Finally, for each radio button element initialized above, setup its // event handlers based on its normalized initial state. This can only // be done after the above loop. for (var i = 0; i < hpui_radioButton_self.length; i++){ var hpui_radioButton_self_obj = jQuery(hpui_radioButton_self[i]); var hpui_radioButton = hpui_radioButton_self_obj.prev('a.hpui-radio'); var error = hpui_radioButton_self_obj.hasClass('hpui-error'); var name = hpui_radioButton_self_obj.attr('name'); var disabled = hpui_radioButton_self_obj.attr('disabled'); var readonly = hpui_radioButton_self_obj.attr('readonly'); var checked = hpui_radioButton_self_obj.attr('checked'); var radioButtonGroup = getHPUIradios(hpui_radioButton_self, name); var currentClass = error ? 'hpui-radio hpui-error' : 'hpui-radio'; var currentChecked = checked ? 'checked' : ''; var currentState = readonly ? 'readonly' : 'enable'; currentState = disabled ? 'disable' : currentState; // Add click event on the label text. var labelEl = getLabel(hpui_radioButton_self_obj); if (labelEl) { labelEl.off('click.hpui-radio'); labelEl.on('click.hpui-radio', {anchor:hpui_radioButton}, function(event) { event.preventDefault(); event.data.anchor.trigger('click'); }); } // Register the click event on the anchor. As a click event, this // propagates to the standard click handler first, and may be // canceled by the standard handler. It delegates to the standard // click handler to toggle the radio button state, then syncs the // CSS class and anchor state with it. hpui_radioButton.off('click.hpui-radio'); hpui_radioButton.on('click.hpui-radio', {input:hpui_radioButton_self_obj, group:radioButtonGroup}, function(event) { var anchor = jQuery(this); var input = event.data.input; var group = event.data.group; // Do nothing if the radio is disabled or readonly. if (anchor.attr('disabled') || anchor.attr('readonly')) return; // Remember whether to reset the error CSS class - will do that // only if this button is about to change state (ie is not // already checked). var resetError = !input.attr('checked'); // Trigger the native radio button click. Note: In JQuery this does not affect the 'checked' // attribute, just the internal state. input.trigger(event); // If the native handling canceled the event, stop. if (event.isDefaultPrevented() || event.isPropagationStopped() || event.isImmediatePropagationStopped()) return; // Now sync CSS class and anchor state with radio state across // the group. if (resetError) { group.prev('a.hpui-radio').removeClass('hpui-error'); group.removeClass('hpui-error'); } normalizeHPUIradios(input, anchor, group, true); }); // Register the custom toggle event on the input element. hpui_radioButton_self_obj.off('hpui-toggle.hpui-radio'); hpui_radioButton_self_obj.on('hpui-toggle.hpui-radio', {anchor:hpui_radioButton, group:radioButtonGroup}, function(event, on) { var anchor = event.data.anchor; var group = event.data.group; var input = jQuery(this); if (on == undefined) on = input.attr('checked') ? false : true; // Clear any error class, if any, through the whole group, if a // checked-state change is occuring. if ((on && !input.attr('checked')) || (!on && input.attr('checked'))) { group.prev('a.hpui-radio').removeClass('hpui-error'); group.removeClass('hpui-error'); } // Set unchecked or checked throughout the group. normalizeHPUIradios(input, anchor, group, on); }); // Register the custom disable event on the input element. hpui_radioButton_self_obj.off('hpui-disable.hpui-radio'); hpui_radioButton_self_obj.on('hpui-disable.hpui-radio', function(anchor) { return function() { var input = jQuery(this); anchor.attr('disabled', '').removeAttr('readonly'); input.attr('disabled', '').removeAttr('readonly'); disableLabel(input); // Finally set screenreading text. setRadioScreenreaderText(input, anchor); } }(hpui_radioButton)); // Register the custom enable event on the input element. hpui_radioButton_self_obj.off('hpui-enable.hpui-radio'); hpui_radioButton_self_obj.on('hpui-enable.hpui-radio', function(anchor) { return function() { var input = jQuery(this); anchor.removeAttr('disabled').removeAttr('readonly'); input.removeAttr('disabled').removeAttr('readonly'); enableLabel(input); // Finally set screenreading text. setRadioScreenreaderText(input, anchor); } }(hpui_radioButton)); // Register the custom readonly event on the input element. hpui_radioButton_self_obj.off('hpui-readonly.hpui-radio'); hpui_radioButton_self_obj.on('hpui-readonly.hpui-radio', function(anchor) { return function() { var input = jQuery(this); anchor.attr('readonly', '').removeAttr('disabled'); input.attr('readonly', '').removeAttr('disabled'); enableLabel(input); // Finally set screenreading text. setRadioScreenreaderText(input, anchor); } }(hpui_radioButton)); // Register the custom error status event on the input element. hpui_radioButton_self_obj.off('hpui-error.hpui-radio'); hpui_radioButton_self_obj.on('hpui-error.hpui-radio', function(anchor) { return function() { var radio = jQuery(this); // Set error class in every case. radio.addClass('hpui-error'); anchor.addClass('hpui-error'); } }(hpui_radioButton)); // Register the custom OK status event on the input element. hpui_radioButton_self_obj.off('hpui-ok.hpui-radio'); hpui_radioButton_self_obj.on('hpui-ok.hpui-radio', function(anchor) { return function() { var radio = jQuery(this); // Remove error class in every case. radio.removeClass('hpui-error'); anchor.removeClass('hpui-error'); } }(hpui_radioButton)); // Register the custom value event on the input element. hpui_radioButton_self_obj.off('hpui-value.hpui-radio'); hpui_radioButton_self_obj.on('hpui-value.hpui-radio', function(event, val) { var radio = jQuery(this); // Value event with blank value is same as toggle-off; value // event with any non-blank value is same as toggle-on. var on = val; radio.trigger('hpui-toggle', on); }); // Register the custom clear event on the input element. hpui_radioButton_self_obj.off('hpui-clear.hpui-radio'); hpui_radioButton_self_obj.on('hpui-clear.hpui-radio', function() { var radio = jQuery(this); // Clear event is same as toggle-off. radio.trigger('hpui-toggle', false); }); // Register the custom reset event on the input element. hpui_radioButton_self_obj.off('hpui-reset.hpui-radio'); hpui_radioButton_self_obj.on('hpui-reset.hpui-radio', {anchor: hpui_radioButton, group: radioButtonGroup, initOn: currentChecked, initClass: currentClass, initState: currentState}, function(event, resetOne) { if (resetOne) { var input = jQuery(this); var anchor = event.data.anchor; // Reset this button's checked/unchecked to initial state if (event.data.initOn) { input.attr('checked', 'checked'); anchor.attr('checked', 'checked'); } else { input.removeAttr('checked'); anchor.removeAttr('checked'); } // Reset this button's class to initial state input.removeClass('hpui-error').addClass(event.data.initClass); anchor.removeClass('hpui-error').addClass(event.data.initClass); // Reset this button's disabled/readonly to initial state input.trigger('hpui-' + event.data.initState); } else { // Reset all buttons in this radio-button group event.data.group.each(function() { jQuery(this).trigger('hpui-reset', true); }); } }); // Initialize radio button state (disabled, readonly, enabled, // checked/unchecked and class) based on current values hpui_radioButton_self_obj.trigger('hpui-reset', true); } } } // Initialize forms in the given context. function initForms(context) { /* There is a better way to do form reset such that non-HPUI form elements * will get reset too. Comment this out, and see following code. * var allForms = jQuery('form', context); allForms.off("reset.hpui-form"); allForms.on("reset.hpui-form", function(event) { event.preventDefault(); resetForm(this); }); */ // Register our custom form reset handler. var allForms = jQuery('form', context); allForms.off("hpui-form-reset"); allForms.on("hpui-form-reset", function(event) { var form = this; // Do standard form reset first. form.reset(); // Do our custom form reset second. resetForm(form); }); // Overload all form reset buttons so that they do standard form reset // first, then our custom form reset second. var allResetButtons = jQuery('input[type=reset]', context); allResetButtons.off("click.hpui-reset"); allResetButtons.on("click.hpui-reset", function(event) { // First prevent standard reset from triggering afterwards. event.preventDefault(); // Next, trigger our custom reset event on this reset button's form. var form = jQuery(this).closest('form'); form.trigger('hpui-form-reset'); }); } // Enable associated label function enableLabel(el) { var labelEl = getLabel(el); if (labelEl) labelEl.removeClass("hpui-disabled-text"); } // Disable associated label function disableLabel(el) { var labelEl = getLabel(el); if (labelEl) labelEl.addClass("hpui-disabled-text"); } // Get associated label function getLabel(obj) { var label_obj = null; if (obj) { var obj_id = obj.attr("id"); if (obj_id) { label_obj = jQuery("label[for='" + obj_id + "']:not(.hpui-fake)"); } } return label_obj; } // Get ID attribute or generate one if non-existent function generateId(obj) { var obj_id = null; if (obj) { obj_id = obj.attr("id"); if (!obj_id) { obj_id = Math.floor(Math.random()*Math.pow(10,6)); // 6-digit random number obj.attr("id", obj_id); } } return obj_id; } // Set screenreader text for a file input function setFileScreenreaderText(fileInput, textInput, buttonInput) { // First empty out the current screenreader text if any. textInput.prev('span.hpui-screenreader-text').remove(); textInput.prev('span.hpui-screenreader-text').remove(); textInput.prev('span.hpui-screenreader-text').remove(); textInput.prev('label.hpui-label').remove(); // Next copy the label, if any, to screenreader text. var label = getLabel(fileInput); var makeNewLabel = generateId(fileInput); var screenreaderLabelText, screenreaderFileText, screenreaderMessageText; // Set screenreader text equal to the file input label text. if (label) { var labelText = label.text(); if (labelText) { // Generate a span container for a screen-reading duplicate of the label text, and add it to the DOM. screenreaderLabelText = jQuery("" + labelText + ""); textInput.before(screenreaderLabelText); makeNewLabel = makeNewLabel && true; } } // Add screenreader message from message catalog, if any. if ((typeof file_screenreader == 'string') && (typeof file_disabled_screenreader == 'string') && (typeof file_entered_screenreader == 'function') && (typeof file_hint_screenreader == 'function')) { var val = textInput.val(); if (val) { var hint = textInput.next('.hpui-default-text'); if (val != hint.text()) screenreaderFileText = jQuery("" + file_entered_screenreader(val) + ""); else screenreaderFileText = jQuery("" + file_hint_screenreader(val) + ""); textInput.before(screenreaderFileText); } if (fileInput.attr('disabled')) screenreaderMessageText = jQuery("" + file_disabled_screenreader + ""); else screenreaderMessageText = jQuery("" + file_screenreader + ""); textInput.before(screenreaderMessageText); makeNewLabel = makeNewLabel && true; } // Wrap a label tag for the browse button around the screenreader text, if applicable. if (makeNewLabel) { var buttonId = fileInput.attr('id') + "_go"; var screenreaderLabel = jQuery(""); if (screenreaderLabelText) { screenreaderLabelText.detach(); screenreaderLabel.append(screenreaderLabelText); } if (screenreaderFileText) { screenreaderFileText.detach(); screenreaderLabel.append(screenreaderFileText); } if (screenreaderMessageText) { screenreaderMessageText.detach(); screenreaderLabel.append(screenreaderMessageText); } textInput.before(screenreaderLabel); buttonInput.attr('id', buttonId); } } // Set screenreader text into a checkbox function setCheckboxScreenreaderText(input, anchor) { // First empty out the current screenreader text if any. anchor.empty(); // Next copy the label, if any, to screenreader text inside the anchor. var label = getLabel(input); if (label) { var labelText = label.text(); if (labelText) anchor.append("" + labelText + ""); } // Next attach the screenreader text for the current state, from the message catalog. if ((typeof checkbox_on_screenreader == 'string') && (typeof checkbox_off_screenreader == 'string') && (typeof checkbox_on_disabled_screenreader == 'string') && (typeof checkbox_off_disabled_screenreader == 'string') && (typeof checkbox_on_readonly_screenreader == 'string') && (typeof checkbox_off_readonly_screenreader == 'string')) { if (input.attr('disabled')) { if (input.attr('checked')) anchor.append("" + checkbox_on_disabled_screenreader + ""); else anchor.append("" + checkbox_off_disabled_screenreader + ""); // Trigger generic screenreader text generation as for all disabled anchors. anchor.trigger('hpui-disable.hpui-link'); } else if (input.attr('readonly')) { if (input.attr('checked')) anchor.append("" + checkbox_on_readonly_screenreader + ""); else anchor.append("" + checkbox_off_readonly_screenreader + ""); // Trigger generic screenreader text generation as for all non-disabled anchors. anchor.trigger('hpui-enable.hpui-link'); } else { if (input.attr('checked')) anchor.append("" + checkbox_on_screenreader + ""); else anchor.append("" + checkbox_off_screenreader + ""); // Trigger generic screenreader text generation as for all non-disabled anchors. anchor.trigger('hpui-enable.hpui-link'); } } } // Set screenreader text into a radio button function setRadioScreenreaderText(input, anchor) { // First, empty out the current screenreader text if any. anchor.empty(); // Next copy the label, if any, to screenreader text inside the anchor. //check label tag and the label text --- By June var label = getLabel(input); if (label) { var labelText = label.text(); if (labelText) anchor.append("" + labelText + ""); } // Next attach the screenreader text for the current state, from the message catalog. if ((typeof radio_on_screenreader == 'string') && (typeof radio_off_screenreader == 'string') && (typeof radio_on_disabled_screenreader == 'string') && (typeof radio_off_disabled_screenreader == 'string') && (typeof radio_on_readonly_screenreader == 'string') && (typeof radio_off_readonly_screenreader == 'string')) { if (input.attr('disabled')) { if (input.attr('checked')) anchor.append("" + radio_on_disabled_screenreader + ""); else anchor.append("" + radio_off_disabled_screenreader + ""); // Trigger generic screenreader text generation as for all disabled anchors. anchor.trigger('hpui-disable.hpui-link'); } else if (input.attr('readonly')) { if (input.attr('checked')) anchor.append("" + radio_on_readonly_screenreader + ""); else anchor.append("" + radio_off_readonly_screenreader + ""); // Trigger generic screenreader text generation as for all non-disabled anchors. anchor.trigger('hpui-enable.hpui-link'); } else { if (input.attr('checked')) anchor.append("" + radio_on_screenreader + ""); else anchor.append("" + radio_off_screenreader + ""); // Trigger generic screenreader text generation as for all non-disabled anchors. anchor.trigger('hpui-enable.hpui-link'); } } } // Reset HPUI form elements within a given form function resetForm(form) { jQuery( // Normal text inputs 'input[type=text].hpui-input,' + 'input[type=password].hpui-input,' + // Slim text inputs 'input[type=text].hpui-slim-input,' + 'input[type=password].hpui-slim-input,' + // Datepickers - already reset as text inputs // Textareas 'textarea.hpui-textarea,' + // Checkboxes 'input[type=checkbox].hpui-checkbox,' + // Radio buttons 'input[type=radio].hpui-radio,' + // File inputs 'input[type=file].hpui-file,' + 'input[type=file].hpui-slim-file,' + // Dropdowns 'select.hpui-select,' + 'select.hpui-slim-select,' + 'select.hpui-multi-select,' + 'select.hpui-slim-multi-select,' + 'select.hpui-filter-menu,' + 'select.hpui-sort-menu', // Find the above within the form and reset each such element form).each(function() { jQuery(this).trigger('hpui-reset'); }); } /****** end HPE form elements JS (form-elements.js) ******/ /****** begin HPE icons JS (icons.js) ******/ /*** "Public" functions - may be used by feature developers ***/ // Add screenreader messages for the given locale into the icons // within the given context (may be a JQuery Object, a string HTML ID, // or the whole page by default). // Note: expand-collapse icons are covered in expand-collapse.js instead. // Note: shopping-cart icon is covered in shopping-cart.js instead. function hpuiAddIconResources(context) { // Get the message resources. if (typeof(hpuiAddMessageResources) == 'function') { hpuiAddMessageResources(); } // Determine the context (if not given). if (!context || !context.length || (typeof context != 'object') || !(context instanceof jQuery)) { if (context && typeof context == 'string') { context = jQuery('#' + context); } else { context = document; } } // For each preloader icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-small-preloader-icon, div.hpui-small-preloader-icon, span.hpui-small-preloader-icon, ' + 'a.hpui-large-preloader-icon, div.hpui-large-preloader-icon, span.hpui-large-preloader-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_preloader_screenreader == 'string') { icon.html(''+icon_preloader_screenreader+''); } }); // For each print icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-print-icon, div.hpui-print-icon, span.hpui-print-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_print_screenreader == 'string') { icon.html(''+icon_print_screenreader+''); } }); // For each share icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-share-icon, div.hpui-share-icon, span.hpui-share-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_share_screenreader == 'string') { icon.html(''+icon_share_screenreader+''); } }); // For each subscribe icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-subscribe-icon, div.hpui-subscribe-icon, span.hpui-subscribe-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_subscribe_screenreader == 'string') { icon.html(''+icon_subscribe_screenreader+''); } }); // For each standalone "OK" status icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-standalone-ok-icon, div.hpui-standalone-ok-icon, span.hpui-standalone-ok-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_standalone_OK_screenreader == 'string') { icon.html(''+icon_standalone_OK_screenreader+''); } }); // For each standalone "error" status icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-standalone-error-icon, div.hpui-standalone-error-icon, span.hpui-standalone-error-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_standalone_error_screenreader == 'string') { icon.html(''+icon_standalone_error_screenreader+''); } }); // For each info icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-info-icon, div.hpui-info-icon, span.hpui-info-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_info_screenreader == 'string') { icon.html(''+icon_info_screenreader+''); } }); // For each help icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-help-icon, div.hpui-help-icon, span.hpui-help-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_help_screenreader == 'string') { icon.html(''+icon_help_screenreader+''); } }); // For each OK icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-ok-icon, div.hpui-ok-icon, span.hpui-ok-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_OK_screenreader == 'string') { icon.html(''+icon_OK_screenreader+''); } }); // For each unknown icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-unknown-icon, div.hpui-unknown-icon, span.hpui-unknown-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_unknown_screenreader == 'string') { icon.html(''+icon_unknown_screenreader+''); } }); // For each error icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-error-icon, div.hpui-error-icon, span.hpui-error-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_error_screenreader == 'string') { icon.html('' + icon_error_screenreader + ''); } }); // For each warning icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-warn-icon, div.hpui-warn-icon, span.hpui-warn-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_warn_screenreader == 'string') { icon.html('' + icon_warn_screenreader + ''); } }); // For each calendar icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-calendar-icon, div.hpui-calendar-icon, span.hpui-calendar-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_calendar_screenreader == 'string') { icon.html('' + icon_calendar_screenreader + ''); } }); // For each forum icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-forum-icon, div.hpui-forum-icon, span.hpui-forum-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_forum_screenreader == 'string') { icon.html('' + icon_forum_screenreader + ''); } }); // For each service icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-service-icon, div.hpui-service-icon, span.hpui-service-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_service_screenreader == 'string') { icon.html('' + icon_service_screenreader + ''); } }); // For each chat icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-chat-icon, div.hpui-chat-icon, span.hpui-chat-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_chat_screenreader == 'string') { icon.html('' + icon_chat_screenreader + ''); } }); // For each mail icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-mail-icon, div.hpui-mail-icon, span.hpui-mail-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_mail_screenreader == 'string') { icon.html('' + icon_mail_screenreader + ''); } }); // For each contact icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-contact-icon, div.hpui-contact-icon, span.hpui-contact-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_contact_screenreader == 'string') { icon.html('' + icon_contact_screenreader + ''); } }); // For each download icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-download-icon, div.hpui-download-icon, span.hpui-download-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_download_screenreader == 'string') { icon.html('' + icon_download_screenreader + ''); } }); // For each settings icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-settings-icon, div.hpui-settings-icon, span.hpui-settings-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_settings_screenreader == 'string') { icon.html('' + icon_settings_screenreader + ''); } }); // For each refresh icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-refresh-icon, div.hpui-refresh-icon, span.hpui-refresh-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_refresh_screenreader == 'string') { icon.html('' + icon_refresh_screenreader + ''); } }); // For each reports icon set the screenreader message if there is no content exist in it. jQuery('a.hpui-reports-icon, div.hpui-reports-icon, span.hpui-reports-icon', context).each(function() { var icon = jQuery(this); var text = jQuery.trim(icon.text()); var title = jQuery.trim(icon.attr('title')); if (!text && !title && typeof icon_reports_screenreader == 'string') { icon.html('' + icon_reports_screenreader + ''); } }); } /*** "Private" functions not for direct use by feature developers ***/ // Initialize all icons in the given context. // Note: expand-collapse icons are covered in expand-collapse.js instead. // Note: shopping-cart icon is covered in shopping-cart.js instead. function initIcons(context) { var icons = jQuery('a.hpui-calendar-icon, a.hpui-warn-icon, a.hpui-error-icon, a.hpui-error-icon2, ' + 'a.hpui-ok-icon, a.hpui-unknown-icon, a.hpui-help-icon, a.hpui-info-icon, ' + 'a.hpui-standalone-ok-icon, a.hpui-standalone-error-icon, ' + 'a.hpui-print-icon, a.hpui-share-icon, a.hpui-subscribe-icon, ' + 'a.hpui-small-preloader-icon, a.hpui-large-preloader-icon', context).each(function(index) { var icon = jQuery(this); // Insert into the normal tabflow. No need to do this if tab flow or an href // is set. if (!icon.attr('tabindex') && !icon.attr('href')) icon.attr('tabindex', '0'); // Register keypress event handler to trigger click on 'enter', for accessibility. // No need to do this if an href is set. if (!icon.attr('href')) { icon.off('keypress.hpui-icons'); icon.on('keypress.hpui-icons', function(event) { var link = jQuery(this); var keycode = (event.keyCode ? event.keyCode : event.which); if (keycode == '13') { link.trigger('click'); } }); } }); } /****** end HPE icons JS (icons.js) ******/ /****** begin HPE page initialization JS (init.js) ******/ // Note: This file is used for global initialization code only. /*** "Public" functions ***/ // Just one public function here, hpuiInitialize - takes a JQuery object or an // HTML ID string, and initializes that element - otherwise assumes document. function hpuiInitialize(el) { if (!el || !el.length || (typeof el != 'object') || !(el instanceof jQuery)) { if (el && typeof el == 'string') { el = jQuery('#' + el); } else { el = document; } } // Pre-initialization of tables if (typeof(preInitTables) == 'function') preInitTables(el); // Begin main initialization of all elements // Localizations for datepickers only (must execute first) if (typeof(hpuiAddDatepickerResources) == 'function') hpuiAddDatepickerResources(); // Dropdowns if (typeof(initDropdowns) == 'function') initDropdowns(el); if (typeof(initStatelessDropdowns) == 'function') initStatelessDropdowns(el); // Form elements if (typeof(initTextInputs) == 'function') initTextInputs('hpui-input', el); if (typeof(initTextInputs) == 'function') initTextInputs('hpui-slim-input', el); if (typeof(initDatepicker) == 'function') initDatepicker('hpui-datepicker', 'hpui-input', el); // must come after text inputs if (typeof(initDatepicker) == 'function') initDatepicker('hpui-slim-datepicker', 'hpui-slim-input', el); // must come after text inputs if (typeof(initTextareas) == 'function') initTextareas(el); if (typeof(initCheckboxes) == 'function') initCheckboxes(el); if (typeof(initRadioButtons) == 'function') initRadioButtons(el); if (typeof(initFileInputs) == 'function') initFileInputs('hpui-file', 'hpui-input', 'hpui-secondary-button', el); if (typeof(initFileInputs) == 'function') initFileInputs('hpui-slim-file', 'hpui-slim-input', 'hpui-secondary-slim-button', el); if (typeof(initForms) == 'function') initForms(el); // Expand-collapse if (typeof(initExpandCollapse) == 'function') initExpandCollapse(el); // Lists if (typeof(initExpandableListButtons) == 'function') initExpandableListButtons(el); // Icons if (typeof(initIcons) == 'function') initIcons(el); // Links if (typeof(initLinks) == 'function') initLinks(el); // Dividers // Typography // Buttons if (typeof(initButtons) == 'function') initButtons(el); // Navigation if (typeof(initMegaMenus) == 'function') initMegaMenus(el); // Overlays if (typeof(initProgressIndicators) == 'function') initProgressIndicators(el); // Shopping cart if (typeof(initShoppingCart) == 'function') initShoppingCart(el); // Tables if (typeof(initTables) == 'function') initTables(el); // Localizations (must execute after all other main initialization) if (typeof(hpuiAddLocalizedResources) == 'function') hpuiAddLocalizedResources(el); // Post-initialization of tables if (typeof(postInitTables) == 'function') postInitTables(el); } /*** "Private" functions ***/ //Set global variables to defaults for local dev guide (all URL values are paths //relative to content HTML folders) - only do this if they are not already set: if (typeof(HPUI_URL) == 'undefined') var HPUI_URL = ""; if (typeof(HPUI_LOCALE_COOKIE) == 'undefined') var HPUI_LOCALE_COOKIE = ""; if (typeof(HPUI_LOCALE) == 'undefined') var HPUI_LOCALE = ""; //Deprecated (but still supported): if (typeof(HPUI_CSS_URL) == 'undefined') var HPUI_CSS_URL = "../../css"; if (typeof(HPUI_IMG_URL) == 'undefined') var HPUI_IMG_URL = "../../images"; if (typeof(HPUI_JS_URL) == 'undefined') var HPUI_JS_URL = "../../js"; // Function to determine base URL for JS files in the HPUI package. function determineBaseJsUrl(){ var baseUrl = '/hpui/hpe/js/'; if ((typeof(HPUI_URL) == 'string') && HPUI_URL) { baseUrl = (HPUI_URL.lastIndexOf('/') == HPUI_URL.length - 1) ? HPUI_URL : HPUI_URL + '/'; baseUrl += "hpui/hpe/js/"; } else if ((typeof(HPUI_JS_URL) == 'string') && HPUI_JS_URL) { baseUrl = (HPUI_JS_URL.lastIndexOf('/') == HPUI_JS_URL.length - 1) ? HPUI_JS_URL : HPUI_JS_URL + '/'; } return baseUrl; } // Function to determine base URL for CSS files in the HPUI package. function determineBaseCssUrl(){ var baseUrl = '/hpui/hpe/css/'; if ((typeof(HPUI_URL) == 'string') && HPUI_URL) { baseUrl = (HPUI_URL.lastIndexOf('/') == HPUI_URL.length - 1) ? HPUI_URL : HPUI_URL + '/'; baseUrl += "hpui/hpe/css/"; } else if ((typeof(HPUI_CSS_URL) == 'string') && HPUI_CSS_URL) { baseUrl = (HPUI_CSS_URL.lastIndexOf('/') == HPUI_CSS_URL.length - 1) ? HPUI_CSS_URL : HPUI_CSS_URL + '/'; } return baseUrl; } // Function to determine base URL for image files in the HPUI package. function determineBaseImagesUrl(){ var baseUrl = '/hpui/hpe/images/'; if ((typeof(HPUI_URL) == 'string') && HPUI_URL) { baseUrl = (HPUI_URL.lastIndexOf('/') == HPUI_URL.length - 1) ? HPUI_URL : HPUI_URL + '/'; baseUrl += "hpui/hpe/images/"; } else if ((typeof(HPUI_IMG_URL) == 'string') && HPUI_IMG_URL) { baseUrl = (HPUI_IMG_URL.lastIndexOf('/') == HPUI_IMG_URL.length - 1) ? HPUI_IMG_URL : HPUI_IMG_URL + '/'; } return baseUrl; } // Returns the version of Windows Internet Explorer or a -1 // (indicating the use of another browser). function getInternetExplorerVersion() { var rv = -1; // Return value assumes failure. if (navigator.appName == 'Microsoft Internet Explorer') { var ua = navigator.userAgent; var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})"); if (re.exec(ua) != null) rv = parseFloat( RegExp.$1 ); } return rv; } // Now initialize the whole page on document ready: jQuery(document).ready(function() { hpuiInitialize(); }); /****** end HPE page initialization JS (init.js) ******/ /****** begin HPE links JS (links.js) ******/ /*** "Public" functions - may be used by feature developers ***/ // Add screenreader messages for the given locale into the tooltip and help links // within the given context (may be a JQuery Object, a string HTML ID, or the whole // page by default). function hpuiAddLinkResources(context) { // Get the message resources. if (typeof(hpuiAddMessageResources) == 'function') { hpuiAddMessageResources(); } // Determine the context (if not given). if (!context || !context.length || (typeof context != 'object') || !(context instanceof jQuery)) { if (context && typeof context == 'string') { context = jQuery('#' + context); } else { context = document; } } // For each tooltip link set, add the screenreader message and title as needed. jQuery('a.hpui-tooltip-link, a.hpui-standalone-tooltip-link, a.hpui-image-tooltip-link', context).each(function() { var tooltipLink = jQuery(this); var tooltipLinkText = jQuery.trim(tooltipLink.text()); var tooltipLinkTitle = jQuery.trim(tooltipLink.attr('title')); var tooltipLinkScreenreaderText = jQuery.trim(tooltipLink.children("span.hpui-screenreader-text:last").text()); tooltipLinkText = jQuery.trim(tooltipLinkText.replace(tooltipLinkScreenreaderText, '')); if (typeof tooltip_screenreader == 'string') if (tooltipLinkScreenreaderText != tooltip_screenreader) tooltipLink.append(" " + tooltip_screenreader + ""); if (typeof tooltip_title == 'string') // Remember, initial generated/default title is a single-space. // Only set title to message if non-default title not already set, and // no tooltip link text. if (!tooltipLinkText && !tooltipLinkTitle && tooltip_title) tooltipLink.attr('title', tooltip_title); }); // For each contextual help link set, add the screenreader message and title as needed. jQuery('a.hpui-help-link, a.hpui-standalone-help-link', context).each(function() { var helpLink = jQuery(this); var helpLinkText = jQuery.trim(helpLink.text()); var helpLinkTitle = jQuery.trim(helpLink.attr('title')); var helpLinkScreenreaderText = jQuery.trim(helpLink.children("span.hpui-screenreader-text:last").text()); helpLinkText = jQuery.trim(helpLinkText.replace(helpLinkScreenreaderText, '')); if (typeof contextual_help_screenreader == 'string') if (helpLinkScreenreaderText != contextual_help_screenreader) helpLink.append(" " + contextual_help_screenreader + ""); if (typeof contextual_help_title == 'string') // Only set title to message if non-default title not already set, and // no help link text. if (!helpLinkText && !helpLinkTitle) helpLink.attr('title', contextual_help_title); }); // For each callout link set, add the screenreader message and title as needed. jQuery('a.hpui-callout-link, a.hpui-standalone-callout-link', context).each(function() { var calloutLink = jQuery(this); var calloutLinkText = jQuery.trim(calloutLink.text()); var calloutLinkTitle = jQuery.trim(calloutLink.attr('title')); var calloutLinkScreenreaderText = jQuery.trim(calloutLink.children("span.hpui-screenreader-text:last").text()); calloutLinkText = jQuery.trim(calloutLinkText.replace(calloutLinkScreenreaderText, '')); if (typeof callout_screenreader == 'string') if (calloutLinkScreenreaderText != callout_screenreader) calloutLink.append(" " + callout_screenreader + ""); if (typeof callout_title == 'string') // Only set title to message if non-default title not already set, and // no callout link text. if (!calloutLinkText && !calloutLinkTitle) calloutLink.attr('title', callout_title); }); // For each link, update screenreader text as needed. jQuery('a', context).each(function() { var link = jQuery(this); // Update screenreader text based on link status. setLinkScreenreaderText(link); }); } /*** "Private" functions not for direct use by feature developers ***/ function generatingTitle() { var htmlForTitle = jQuery(this).next().html(); return htmlForTitle; } function adjustArrowPosition(el, position, tooltipEl, feedback) { var pl = position.left; var pw = tooltipEl.width(); var pr = pl + pw; var tl = feedback.target.left; var tw = feedback.target.width; var tr = tl + tw; var distance1 = 20; // The fixed distance between the arrow and left edge or right edge of the // tooltip. var arrowWidth = 30; // The width of the arrow image. var distance2 = distance1 + arrowWidth / 2; // Under normal situations, the distance between the tooltip's left edge and // the anchor's left edge // should larger than distance2 so that there will be enough space to keep // the fixed distance between the tooltip's left edge and the arrow image. // i.e.the arrow image is close to the tooltip's left edge . // var distance3 = distance1 + arrowWidth; // Under normal situations, the distance between the tooltip's right edge // and the anchor's right edge // should larger than distance3 so that there will be enough space to keep // the fixed distance between the tooltip's right edge and the arrow image. // i.e. the arrow image is close to the tooltip's right edge. if (pl + distance1 < tl) { // The tooltip's left edge is too far away from the anchor's left edge, // so the arrow image should be moved right toward. if (pr < tr) { // The right of tooltip is smaller than the right of anchor. if (pr - tl > distance2) { // Enough space to keep the fixed distance on the right. el.css('right', distance1 + 'px'); } else { el.css('right', 0 + 'px'); // Display the arrow on very right against the tooltip. } } else { if (pr - tl > distance2 && pr - tr < distance1) { // Enough space to keep the fixed distance on the right. el.css('right', distance1 + 'px'); } else { el.css('left', tw / 2 + tl - pl - arrowWidth / 2 + 'px'); // Display the arrow on the middle of the anchor. } } } else { if (tr - pl > distance2) { el.css('left', distance1 + 'px'); // Enough space to keep the fixed distance on the left. } else { el.css('left', 0 + 'px'); // Display the arrow on the very left against the tooltip. } } } // Set a link into the disabled state. function disableLink(anchor) { // Save-off and remove any href or onclick so nothing will happen when the link is activated. if (anchor.attr('onclick')) { anchor.data('onclick', anchor.attr('onclick')); anchor.removeAttr('onclick'); } if (anchor.attr('href')) { anchor.data('href', anchor.attr('href')); anchor.removeAttr('href'); } // Save any tabbable tabindex, then set tabindex so the link will be not tabbable. if (anchor.attr('tabindex') !== '-1') if (anchor.attr('tabindex') || anchor.attr('tabindex') === '0') anchor.data('tabindex', anchor.attr('tabindex')); anchor.attr('tabindex', '-1'); // Set disabled attr so correct CSS style will be selected. anchor.attr('disabled', ''); // Append 'disabled' screenreading message to the end of the link text. setLinkScreenreaderText(anchor); } // Set a link into the enabled state. function enableLink(anchor) { // Restore any href or onclick so it takes effect when the link is activated. if (anchor.data('onclick')) anchor.attr('onclick', anchor.data('onclick')); if (anchor.data('href')) anchor.attr('href', anchor.data('href')); // Remove any non-tabbable tabindex, then restore any tabindex that had been saved. if (anchor.attr('tabindex') === '-1') anchor.removeAttr('tabindex'); if (anchor.data('tabindex') !== '-1') if (anchor.data('tabindex') || anchor.data('tabindex') === '0') anchor.attr('tabindex', anchor.data('tabindex')); // Remove disabled attr so correct CSS style will be selected. anchor.removeAttr('disabled'); // Remove 'disabled' screenreading message from the end of the link text. setLinkScreenreaderText(anchor); } // Initialize all links in the given context. function initLinks(context) { // Initialization for each image tooltip links in image tag // (must do this before all generic link initialization): var imageTooltipLinks = jQuery('img.hpui-tooltip-link', context).each(function(index) { var tooltipEl = jQuery(this); // If there is no anchor of class="hpui-image-tooltip-link" which is parent of the img, // create the anchor with class="hpui-image-tooltip-link" and enclose the img inside the anchor // and insert the anchor into the DOM where the img was. var anchor = tooltipEl.parent('a'); if (!anchor || !anchor.length) { anchor = jQuery(''); tooltipEl.wrap(anchor); } else { anchor.addClass('hpui-image-tooltip-link'); } tooltipEl.removeClass("hpui-tooltip-link"); }); // Ensure all disabled links are made non-clickable and support event handlers // to set disabled/enabled. var allLinks = jQuery('a', context); allLinks.off('click.hpui-link'); allLinks.on('click.hpui-link', function(event) { var anchor = jQuery(this); // Check disabled attr and do nothing if set. if (anchor.attr('disabled')) { event.stopImmediatePropagation(); event.preventDefault(); } }); allLinks.off('hpui-disable.hpui-link'); allLinks.on('hpui-disable.hpui-link', function(event) { disableLink(jQuery(this)); }); allLinks.off('hpui-enable.hpui-link'); allLinks.on('hpui-enable.hpui-link', function(event) { enableLink(jQuery(this)); }); // Ensure all onclick links are in the tab flow by default and open on // 'enter' key. var onclickLinks = jQuery('a[onclick]', context).each(function(index) { var anchor = jQuery(this); // Insert into the normal tabflow. No need to do this if tab flow or an href // is set. if (!anchor.attr('tabindex') && !anchor.attr('href')) anchor.attr('tabindex', '0'); // Register keypress event handler to trigger click on 'enter', for accessibility. // No need to do this if an href is set. if (!anchor.attr('href')) { anchor.off('keypress.hpui-link'); anchor.on('keypress.hpui-link', function(event) { var link = jQuery(this); var keycode = (event.keyCode ? event.keyCode : event.which); if (keycode == '13') { link.trigger('click'); event.stopImmediatePropagation(); event.preventDefault(); } }); } }); // Initialization for each inline and standalone contextual help link: var helpLinks = jQuery('a.hpui-help-link,a.hpui-standalone-help-link', context).each(function(index) { var helpEl = jQuery(this); if (!jQuery.trim(helpEl.attr('title'))) // Add title to the element otherwise it doesn't work under IE. // Empty title is sufficient; per U/E no need for shopping cart links to have title text anymore. helpEl.attr('title', ''); // Insert the link into normal tabflow by default. if (!helpEl.attr('tabindex') && !helpEl.attr('href')) helpEl.attr('tabindex', '0'); // Register click event handler to open the contextual help layer. helpEl.off('click.hpui-help'); helpEl.on('click.hpui-help', function(event) { var link = jQuery(this); var target = link.attr('data-id'); if (target) { if (typeof(hpuiOpenContextualHelp) == 'function') hpuiOpenContextualHelp(jQuery('#' + target), link, event); } }); // Register keypress event handler to do likewise on 'enter', for accessibility. helpEl.off('keypress.hpui-help'); helpEl.on('keypress.hpui-help', function(event) { var link = jQuery(this); var keycode = (event.keyCode ? event.keyCode : event.which); if (keycode == '13') { link.trigger('click'); event.stopImmediatePropagation(); event.preventDefault(); } }); }); // Initialization for each inline and standalone callout link: var calloutLinks = jQuery('a.hpui-callout-link,a.hpui-standalone-callout-link', context).each(function(index) { var calloutLink = jQuery(this); var calloutEl = jQuery('#' + calloutLink.attr('data-id')); if (!jQuery.trim(calloutLink.attr('title'))) // Add title to the element otherwise it doesn't work under IE. // Empty title is sufficient; per U/E no need for shopping cart links to have title text anymore. calloutLink.attr('title', ''); // Insert the link into normal tabflow by default. if (!calloutLink.attr('tabindex') && !calloutLink.attr('href')) calloutLink.attr('tabindex', '0'); // Register hover event handlers to open/close the callout layer. calloutLink.off('mouseenter.hpui-callout-link'); calloutLink.on('mouseenter.hpui-callout-link', function(event) { if (typeof(hpuiOpenCallout) == 'function') hpuiOpenCallout(calloutEl, calloutLink, event); }); var closeDialog; calloutLink.off('mouseleave.hpui-callout-link'); calloutLink.on('mouseleave.hpui-callout-link', function(event) { closeDialog = setTimeout(function() { calloutEl.dialog("close"); }, 1000); }); calloutEl.off('mouseenter.hpui-callout'); calloutEl.on('mouseenter.hpui-callout', function(event) { clearTimeout(closeDialog); }); calloutEl.off('mouseleave.hpui-callout'); calloutEl.on('mouseleave.hpui-callout', function(event) { // workaround problem in FF where mouseleave event sometimes fires // immediately after mouseenter by delaying closure for 0.2 sec //calloutEl.dialog("close"); closeDialog = setTimeout(function() { calloutEl.dialog("close"); }, 200); }); calloutEl.children().off('focusout.hpui-callout'); calloutEl.children().on('focusout.hpui-callout', function(event) { closeDialog = setTimeout(function() { calloutEl.dialog("close"); }, 1000); }); calloutEl.children().off('focusin.hpui-callout'); calloutEl.children().on('focusin.hpui-callout', function(event) { clearTimeout(closeDialog); }); // Register keypress event handler to do likewise on 'enter', for accessibility. calloutLink.off('keypress.hpui-callout-link'); calloutLink.on('keypress.hpui-callout-link', function(event) { var link = jQuery(this); var keycode = (event.keyCode ? event.keyCode : event.which); if (keycode == '13') { link.trigger('mouseenter'); event.stopImmediatePropagation(); event.preventDefault(); } }); }); // Initialization for each image tooltip links in anchor: var aImageTooltipLinks = jQuery('a.hpui-image-tooltip-link',context).each(function(index) { var tooltipEl = jQuery(this); var tooltipDisabled = tooltipEl.attr('disabled'); var tooltipTitle = jQuery.trim(tooltipEl.attr('title')); var image = tooltipEl.find('img'); var imgAlt = image.attr('alt'); var imgTitle = jQuery.trim(image.attr('title')); var imgSrc = image.attr('src'); // If the anchor has no title: if there is an img title, set the anchor title to the img title. // In any case, remove the title from the img. if (!tooltipTitle && imgTitle) { tooltipEl.attr('title', imgTitle); tooltipTitle = imgTitle; } image.removeAttr('title'); // If blank title and not disabled, then set title to space because otherwise // JQuery UI Tooltip does not work in IE or Firefox. if (!tooltipTitle && !tooltipDisabled) tooltipEl.attr('title', ' '); // Set disable/enable event handlers to keep title up-to-date. tooltipEl.off('hpui-disable.hpui-tooltip-link'); tooltipEl.on('hpui-disable.hpui-tooltip-link', function(event) { var anchor = jQuery(this); if (!jQuery.trim(anchor.attr('title'))) anchor.removeAttr('title'); }); tooltipEl.off('hpui-enable.hpui-tooltip-link'); tooltipEl.on('hpui-enable.hpui-tooltip-link', function(event) { var anchor = jQuery(this); if (!jQuery.trim(anchor.attr('title'))) anchor.attr('title', ' '); }); // If the anchor has no href, set the anchor tabindex attribute to "0". if (!tooltipEl.attr('href')) { if (!tooltipEl.attr('tabindex')) { tooltipEl.attr('tabindex', '0'); } } // Initialize the JQuery UI tooltip construct. tooltipEl.tooltip({ content: generatingTitle, track: true, position: { my: "left-35 bottom-10", at: "center-2 top", collisionPosition:"flip", using: function(position, feedback) { jQuery(this).css(position); if (feedback.vertical == 'bottom') { jQuery(this).children('.hpui-arrow-bottom, .hpui-arrow-top').remove(); adjustArrowPosition(jQuery("
").addClass("hpui-arrow-bottom").appendTo(this), position, jQuery(this), feedback); } else if (feedback.vertical == 'top') { jQuery(this).children('.hpui-arrow-bottom, .hpui-arrow-top').remove(); adjustArrowPosition(jQuery("
").addClass("hpui-arrow-top").appendTo(this), position, jQuery(this), feedback); } } } }) }); // Initialization for each inline tooltip links: var tooltipLinks = jQuery('a.hpui-tooltip-link', context).each(function(index) { var tooltipEl = jQuery(this); var tooltipDisabled = tooltipEl.attr('disabled'); var tooltipTitle = jQuery.trim(tooltipEl.attr('title')); // Insert the link into normal tabflow by default. if (!tooltipEl.attr('tabindex') && !tooltipEl.attr('href')) tooltipEl.attr('tabindex', '0'); // If blank title and not disabled, then set title to space because otherwise // JQuery UI Tooltip does not work in IE or Firefox. if (!tooltipTitle && !tooltipDisabled) tooltipEl.attr('title', ' '); // Set disable/enable event handlers to keep title up-to-date. tooltipEl.off('hpui-disable.hpui-tooltip-link'); tooltipEl.on('hpui-disable.hpui-tooltip-link', function(event) { var anchor = jQuery(this); // Note: hpui-disable.hpui-link event handler will have executed first. if (!jQuery.trim(anchor.attr('title'))) anchor.removeAttr('title'); }); tooltipEl.off('hpui-enable.hpui-tooltip-link'); tooltipEl.on('hpui-enable.hpui-tooltip-link', function(event) { var anchor = jQuery(this); // Note: hpui-disable.hpui-link event handler will have executed first. if (!jQuery.trim(anchor.attr('title'))) anchor.attr('title', ' '); }); // Initialize the tooltip. tooltipEl.tooltip({ content: generatingTitle, position: { my: "left-35 bottom-10", at: "center-2 top", collisionPosition:"flip", using: function(position, feedback) { jQuery(this).css(position); if (feedback.vertical == 'bottom') { adjustArrowPosition(jQuery("
").addClass("hpui-arrow-bottom").appendTo(this), position, jQuery(this), feedback); } else if (feedback.vertical == 'top') { adjustArrowPosition(jQuery("
").addClass("hpui-arrow-top").appendTo(this), position, jQuery(this), feedback); } } } }); }) // Initialization for each standalone tooltip link: var sTooltipLinks = jQuery('a.hpui-standalone-tooltip-link', context).each(function(index) { var tooltipEl = jQuery(this); var tooltipDisabled = tooltipEl.attr('disabled'); var tooltipTitle = jQuery.trim(tooltipEl.attr('title')); // Insert the link into normal tabflow by default. if (!tooltipEl.attr('tabindex') && !tooltipEl.attr('href')) tooltipEl.attr('tabindex', '0'); // If blank title and not disabled, then set title to space because otherwise // JQuery UI Tooltip does not work in IE or Firefox. if (!tooltipTitle && !tooltipDisabled) tooltipEl.attr('title', ' '); // Set disable/enable event handlers to keep title up-to-date. tooltipEl.off('hpui-disable.hpui-tooltip-link'); tooltipEl.on('hpui-disable.hpui-tooltip-link', function(event) { var anchor = jQuery(this); // Note: hpui-disable.hpui-link event handler will have executed first. if (!jQuery.trim(anchor.attr('title'))) anchor.removeAttr('title'); }); tooltipEl.off('hpui-enable.hpui-tooltip-link'); tooltipEl.on('hpui-enable.hpui-tooltip-link', function(event) { var anchor = jQuery(this); // Note: hpui-disable.hpui-link event handler will have executed first. if (!jQuery.trim(anchor.attr('title'))) anchor.attr('title', ' '); }); // Initialize the tooltip. tooltipEl.tooltip({ content : generatingTitle, position : { my : "center1 bottom-10", at: "right-45 top", collisionPosition:'flip', using : function(position, feedback) { jQuery(this).css(position); if (feedback.vertical == 'bottom') { adjustArrowPosition(jQuery("
").addClass("hpui-arrow-bottom").appendTo(this), position, jQuery(this), feedback); } else if (feedback.vertical == 'top') { adjustArrowPosition(jQuery("
").addClass("hpui-arrow-top").appendTo(this), position, jQuery(this), feedback); } } } }); }); // Finally, ensure all disabled links are set disabled. This must come last, after the above // steps have had a chance to initialize the tabindex when needed. var allDisabledLinks = jQuery('a[disabled]', context); allDisabledLinks.each(function() { disableLink(jQuery(this)); }); } // Add the 'disabled' screenreader message to a disabled link, or // remove it from an enabled link. function setLinkScreenreaderText(link) { var disabled = link.attr('disabled'); var linkScreenreaders = link.children("span.hpui-screenreader-text"); if (typeof link_disabled_screenreader != 'string') return; if (disabled) { var already = false; linkScreenreaders.each(function() { var linkScreenreader = jQuery(this); var linkScreenreaderText = linkScreenreader.text(); if (linkScreenreaderText == link_disabled_screenreader) already = true; }); if (!already) link.append("" + link_disabled_screenreader + ""); } else { linkScreenreaders.each(function() { var linkScreenreader = jQuery(this); var linkScreenreaderText = linkScreenreader.text(); if (linkScreenreaderText == link_disabled_screenreader) linkScreenreader.remove(); }); } } /****** end HPE links JS (links.js) ******/ /****** begin HPE lists JS (lists.js) ******/ /*** "Public" functions - may be used by feature developers ***/ /*** "Private" functions not for direct use by feature developers ***/ function addExpandCollapseButton(listItem) { var icon = listItem.children('a.hpui-expand-icon,a.hpui-collapse-icon'); var listContent = listItem.children('div.hpui-content'); if (listContent && listContent.length && (listItem.hasClass('hpui-expanded-section') || listItem.hasClass('hpui-collapsed-section'))) { listItem.css("padding-left", "0px"); if (!icon || !icon.length) { if (listItem.hasClass("hpui-expanded-section")) { listItem.prepend(""); if (typeof(hpuiInitialize) == 'function') hpuiInitialize(listItem); listItem.find("div.hpui-content").first().slideToggle(500); } else { listItem.prepend(""); if (typeof(hpuiInitialize) == 'function') hpuiInitialize(listItem); } } } } function addContentWrapperDiv(content) { var contents = content.children(); if (contents.length == 1) { if ((contents.prop("tagName") == "OL") || (contents.prop("tagName") == "UL")) if (contents.first().hasClass("hpui-expandable-list")) return; if ((contents.prop("tagName") == "DIV")) return; } var original = content.html(); content.empty(); content.append("
" + original + "
"); } function doExpandCollapse(icon) { icon.nextAll("div.hpui-content").first().slideToggle(500); if (icon.hasClass("hpui-expand-icon")) icon.removeClass("hpui-expand-icon").addClass("hpui-collapse-icon"); else icon.removeClass("hpui-collapse-icon").addClass("hpui-expand-icon"); if (typeof(hpuiInitialize) == 'function') hpuiInitialize(icon.parent()); } // Initialize expand/collapse lists in the given context. function initExpandableListButtons(context){ // Add the button icons automatically. Must do this re-entrantly in case // this code reloads (eg from user navigating back). jQuery("ol.hpui-expandable-list li,ul.hpui-expandable-list li", context).each(function() { addExpandCollapseButton(jQuery(this)); }); // Add the content wrapper div automatically. Must do this re-entrantly in // case this code reloads (eg from user navigating back). jQuery("ol.hpui-expandable-list li div.hpui-content," + "ul.hpui-expandable-list li div.hpui-content", context).each(function() { addContentWrapperDiv(jQuery(this)); }); // Register the button click handler. Must do this re-entrantly in case this // code reloads (eg from user navigating back). Also, register keypress // handler for 'enter' key to trigger click handler on the buttons. var buttons = jQuery('ol.hpui-expandable-list li a.hpui-expand-icon,' + 'ol.hpui-expandable-list li a.hpui-collapse-icon,' + 'ul.hpui-expandable-list li a.hpui-expand-icon,' + 'ul.hpui-expandable-list li a.hpui-collapse-icon', context); buttons.off('click.hpui-expandable-list'); buttons.on('click.hpui-expandable-list', function() { doExpandCollapse(jQuery(this)); }); /* buttons.off('keypress.hpui-expandable-list'); buttons.on('keypress.hpui-expandable-list', function(event) { var icon = jQuery(this); var keycode = (event.keyCode ? event.keyCode : event.which); if (keycode == '13') { icon.trigger('click'); } }); */ } /****** end HPE lists JS (lists.js) ******/ /****** begin HPE messages JS (messages.js) ******/ /*** "Public" functions - may be used by feature developers ***/ // This hash maps lowercase locales (format ll eg "fr" or ll-cc, eg "zh-tw") to // Java locale tags (format ll eg "fr" or ll_CC, eg "zh_TW") of provided message // bundles. var HPUI_LOCALES_TO_MESSAGES = { 'zh-hk':'zh_HK', 'zh-tw':'zh_TW', 'cs': 'cs', 'de': 'de', 'el': 'el', 'es': 'es', 'fr': 'fr', 'hu': 'hu', 'it': 'it', 'ja': 'ja', 'ko': 'ko', 'pl': 'pl', 'pt': 'pt', 'ru': 'ru', 'tr': 'tr', 'zh': 'zh' }; // General purpose method for including messages from the message catalog. // Does not do anything with them; just defines them. function hpuiAddMessageResources() { // First determine the locale being requested: either the HPUI_LOCALE or the // value of the HPUI_LOCALE_COOKIE or English by default. From init.js. var requestedLocale = typeof (determineLocale) == 'function' ? determineLocale() : "en"; // From the locale being requested, determine the locale to actually use. var localeToUse = ""; var requestedLanguage = requestedLocale; if (requestedLocale.length > 2) requestedLanguage = requestedLocale.substring(0, 2); if (HPUI_LOCALES_TO_MESSAGES[requestedLocale.toLowerCase()]) // We will use the full locale if it is supported localeToUse = HPUI_LOCALES_TO_MESSAGES[requestedLocale.toLowerCase()]; else if (HPUI_LOCALES_TO_MESSAGES[requestedLanguage.toLowerCase()]) // Else we will use the language if it is supported localeToUse = HPUI_LOCALES_TO_MESSAGES[requestedLanguage.toLowerCase()]; else // Else we will use English if neither full locale nor language are supported localeToUse = "en"; // No need to proceed if locale has already been loaded. if (loadedMessagesForLocale == localeToUse) return; // Instantiate the message properties. Each message property // will be allocated in a variable or function of the same name // when this returns. HPUI_URL and HPUI_JS_URL are alternative // global variables for the root URL to the JS folder. From init.js. var baseUrl = typeof (determineBaseJsUrl) == 'function' ? determineBaseJsUrl() : ""; if (typeof(jQuery.i18n.properties) == 'function') { jQuery.i18n.properties({ name: 'messages', language: localeToUse, // cache: true, // does not work :-( path: baseUrl + 'messages/i18n/' }); } loadedMessagesForLocale = localeToUse; } // Gets the localized messages (eg for screenreader) from the message catalog and // rewrites them into all other widgets in the given context (page by default) // where screenreader text may be required: tabs, links, icons, etc. function hpuiAddLocalizedResources(context) { // Determine the context (if not given). if (!context || !context.length || (typeof context != 'object') || !(context instanceof jQuery)) { if (context && typeof context == 'string') { context = jQuery('#' + context); } else { context = document; } } // Rewrite the localizations into the given context. if (typeof(hpuiAddBasicDatepickerResources) == 'function') hpuiAddBasicDatepickerResources(context); if (typeof(hpuiAddExpandCollapseResources) == 'function') hpuiAddExpandCollapseResources(context); if (typeof(hpuiAddFormResources) == 'function') hpuiAddFormResources(context); if (typeof(hpuiAddLinkResources) == 'function') hpuiAddLinkResources(context); if (typeof(hpuiAddIconResources) == 'function') hpuiAddIconResources(context); // must come after links if (typeof(hpuiAddTabResources) == 'function') hpuiAddTabResources(context); if (typeof(hpuiAddShoppingCartResources) == 'function') hpuiAddShoppingCartResources(context); if (typeof(hpuiAddDropdownResources) == 'function') hpuiAddDropdownResources(context); } /*** "Private" functions not for direct use by feature developers ***/ // Global variable for tracking message resources already loaded on this page. // Needed because JQuery I18n properties plugin 'cache' property does not work. var loadedMessagesForLocale = ""; // Determine locale to use. function determineLocale() { var requestedLocale = ""; if (typeof(HPUI_LOCALE) == 'string') requestedLocale = HPUI_LOCALE; if (!requestedLocale && (typeof(HPUI_LOCALE_COOKIE) == 'string') && (typeof(jQuery.cookie) == 'function') && HPUI_LOCALE_COOKIE) requestedLocale = jQuery.cookie(HPUI_LOCALE_COOKIE); if (!requestedLocale) requestedLocale = "en"; return requestedLocale; } /****** end HPE messages JS (messages.js) ******/ /****** begin HPE navigations JS (navigations.js) ******/ /** * "Public" functions - may be used by feature developers ** */ // Add screenreader messages for the given locale into the tabs within the given // context (may be a JQuery Object, a string HTML ID, or the whole page by // default). function hpuiAddTabResources(context) { // Get the message resources. if (typeof (hpuiAddMessageResources) == 'function') { hpuiAddMessageResources(); } // Determine the context (if not given). if (!context || !context.length || (typeof context != 'object') || !(context instanceof jQuery)) { if (context && typeof context == 'string') { context = jQuery('#' + context); } else { context = document; } } // For each tab set, add the screenreader message if not already set. jQuery('div.hpui-tabs > ul > li > a', context).each( function() { var tabAnchor = jQuery(this); var screenreaderText = tabAnchor.children( "span.hpui-screenreader-text:last").text(); if ((typeof tabs_screenreader == 'string') && (screenreaderText != tabs_screenreader)) tabAnchor.append(" " + tabs_screenreader + ""); }); } // Initialize one tab set, using JQuery UI Tabs plus some enhancements for // URLs in tab links and better sizing of tab width. function hpuiTabs(options) { // Make sure we got table options. if (!options || !options.id) return; var tabsID = options.id; // Select the tab set for the given ID - return immediately unless one and only one is found. var tabDiv = jQuery("div.hpui-tabs#" + tabsID); if (tabDiv && tabDiv.length == 1) { // Remove id option to as it would be unrecognized by JQuery. delete options.id; // Make sure tabs marked disabled have not also been made active. if (jQuery.inArray(options.active, options.disabled) > -1) { delete options.active; } var tabUL = tabDiv.find("ul:first"); tabUL.find("li > a").each(function() { var tabAnchor = jQuery(this); var tabID = getTabID(tabAnchor); // When there is no tab ID on this tab heading, generate one and assign to the heading. if (!tabID) { tabID = Math.floor(Math.random()*Math.pow(10,6)); // Randomly generate a length 6 integer. tabAnchor.attr("href", "#" + tabID); } // When there is no tab content div for this tab heading, generate one after the headings. var tabContentPanel = jQuery("div#" + tabID); if (!tabContentPanel || tabContentPanel.length == 0) { tabUL.after("
"); } }); // Augment the given options with 'beforeActivate' option which makes the tabs linkable to a URL. options.beforeActivate = function(event, ui) { var tabNewHref = ui.newTab.children('a:first').attr('href'); var tabNewRel = ui.newTab.children('a:first').attr('rel'); if (tabNewRel) { location.href = tabNewRel; } else { location.href = tabNewHref; } ui.newTab.focus(); }; // Initialize JQuery UI Tabs with the options. tabDiv.tabs(options); // JQuery UI Tabs uses fixed-width tabs that wrap poorly within a constrained width. So // resize the tabs to fit within one line instead. resizeTabs(tabDiv); } } /** * "Private" functions not for direct use by feature developers ** */ function resizeTabs(tabDiv) { var tabUl = tabDiv.children("ul"); var tabLi = tabUl.children("li"); var tabAnchor = tabLi.children("a"); var tabLiNumber = tabLi.length; var tabLiTextArray = new Array(); //Get font style from tab. var tabLiFontSize = tabAnchor.css("font-size"); var tabLiFontWeight = tabAnchor.css("font-weight"); var tabLiLineHeight = tabAnchor.css("line-height"); var tabLiFloat = tabAnchor.css("float"); var tabAnchorPaddingTop = tabAnchor.css("padding-top"); var tabAnchorPaddingRight = tabAnchor.css("padding-right"); var tabLiSumWidth = 0; //According tab to create a table. var tableID = Math.floor(Math.random()*Math.pow(10,6)); var tableDivId = Math.floor(Math.random()*Math.pow(10,6)); jQuery(window).on("load" , function(){ for(var i = 0; i < tabLiNumber; i++){ var tabLiEveText = tabLi.eq(i).children("a").html(); tabLiTextArray.push(tabLiEveText); var tabLiWidth = tabLi.eq(i).outerWidth(true); tabLiSumWidth += tabLiWidth; } // When the table need wrap line of text, set the table width to 1px to reduce the space between every td, // otherwise set table width for the width of div which is outer of tabs. var tableWidth = 1; if(tabLiSumWidth <= tabDiv.width()){ tableWidth = tabDiv.width(); } tabDiv.append("
"+"
"); jQuery("#"+tableDivId).append("" + "" + "
"); var table = jQuery("#"+tableID); var tableTr = table.find("tr"); for(var i=0; i"+tabLiText+""); } var tableTd = tableTr.find("td"); var tableTdHeight = tableTd.outerHeight(); if( tabUl.width() < tableTr.width()) { tabUl.css("width" , tableTr.width()); } for (var i = 0; i < tabLiNumber; i++) { var tableTdWidth = tableTd.eq(i).outerWidth(); if (tableTdHeight >= 2*(parseInt(tabLiFontSize) + parseInt(tabAnchorPaddingTop))) { tabLi.eq(i).children("a").css("white-space", "pre-wrap"); } tabLi.eq(i).css("width" , tableTdWidth-1); tabLi.eq(i).css("height" , tableTdHeight); } table.css("display", "none"); }); } // Return the tab ID given a tab heading anchor. function getTabID(tabAnchor) { var tabID = tabAnchor.attr("href"); if (tabID) { if (tabID.indexOf("#") == 0) { if (tabID.length > 1) tabID = tabID.substring(1); else tabID = ""; } } else { tabID = ""; } return tabID; } /** **** end HPE navigations JS (navigations.js) ***** */ /****** begin HPE overlays JS (overlays.js) ******/ /*** "Public" functions for use by feature developers ***/ // Positioning function for contextual help overlay when opened. function hpuiOpenContextualHelp(contextualHelpDialog, contextualHelpLink, event) { // Make sure we got passed JQuery objects; return short otherwise. if (!contextualHelpDialog || !contextualHelpDialog.length || (typeof contextualHelpDialog != 'object') || !(contextualHelpDialog instanceof jQuery) || !(contextualHelpDialog.is(':data(dialog)'))) return; if (!contextualHelpLink || !contextualHelpLink.length || (typeof contextualHelpLink != 'object') || !(contextualHelpLink instanceof jQuery)) return; // Calculate and set the contextual help overlay position. var offset = contextualHelpLink.offset(); var dialog_position_x = (offset.left - jQuery(window).scrollLeft()) > jQuery(window).width()/2; var dialog_position_y = (offset.top - jQuery(window).scrollTop()) > jQuery(window).height()/2; if (dialog_position_y) { if (dialog_position_x) { contextualHelpDialog.dialog( "option", "position", { my: "right bottom", at: "right bottom", of: contextualHelpLink, offset: "-50% -90%" } ); } else { contextualHelpDialog.dialog( "option", "position", { my: "left bottom", at: "left bottom", of: contextualHelpLink, offset: "50% -90%" } ); } } else { if (dialog_position_x){ contextualHelpDialog.dialog( "option", "position", { my: "right top", at: "right top", of: contextualHelpLink, offset: "-50% 90%" } ); } else { contextualHelpDialog.dialog( "option", "position", { my: "left top", at: "left top", of: contextualHelpLink, offset: "50% 90%" } ); } } // Show the contextual help overlay. contextualHelpDialog.dialog( "open" ); // Cancel event propagation if we were passed a trigger event for the open. if (event) { event.stopImmediatePropagation(); event.preventDefault(); } } // Positioning function for callout overlay when opened. function hpuiOpenCallout(calloutDialog, calloutLink, event) { // Make sure we got passed JQuery objects; return short otherwise. if (!calloutDialog || !calloutDialog.length || (typeof calloutDialog != 'object') || !(calloutDialog instanceof jQuery) || !(calloutDialog.is(':data(dialog)'))) return; if (!calloutLink || !calloutLink.length || (typeof calloutLink != 'object') || !(calloutLink instanceof jQuery)) return; // Calculate and set the callout overlay position. var offset = calloutLink.offset(); var dialog_position_x = (offset.left - jQuery(window).scrollLeft()) > jQuery(window).width()/2; var dialog_position_y = (offset.top - jQuery(window).scrollTop()) > jQuery(window).height()/2; // Remove the previously appended arrows calloutDialog.children("div.hpui-arrow-bottom, div.hpui-arrow-top, div.hpui-mini-shopping-cart-arrow-bottom, div.hpui-mini-shopping-cart-arrow-top").remove(); if (dialog_position_y) { if (dialog_position_x) { calloutDialog.append("
"); calloutDialog.dialog( "option", "position", { my: "right bottom", at: "right bottom", of: calloutLink, offset: "-25% -145%" } ); } else { calloutDialog.append("
"); calloutDialog.dialog( "option", "position", { my: "left bottom", at: "left bottom", of: calloutLink, offset: "25% -145%" } ); } } else { if (dialog_position_x){ calloutDialog.append("
"); calloutDialog.dialog( "option", "position", { my: "right top", at: "right top", of: calloutLink, offset: "-25% 145%" } ); } else { calloutDialog.append("
"); calloutDialog.dialog( "option", "position", { my: "left top", at: "left top", of: calloutLink, offset: "25% 145%" } ); } } // Show the callout overlay. calloutDialog.dialog( "open" ); // Cancel event propagation if we were passed a trigger event for the open. if (event) { event.stopImmediatePropagation(); event.preventDefault(); } } // Positioning function for alert overlay when opened. function hpuiOpenAlert(alertDialog, container, event) { // Make sure we got passed a JQuery dialog; return short otherwise. if (!alertDialog || !alertDialog.length || (typeof alertDialog != 'object') || !(alertDialog instanceof jQuery) || !(alertDialog.is(':data(dialog)'))) return; // Make sure the container is a DOM element or window; return short otherwise. if (!container || !(container.nodeType || container == window)) return; // Center the alert overlay in the given container and show it. alertDialog.dialog( "option", "position", { my: "center center", at: "center center", of: container } ); alertDialog.dialog( "open" ); // Cancel event propagation if we were passed a trigger event for the open. if (event) { event.stopImmediatePropagation(); event.preventDefault(); } } // Positioning function for dialog overlay when opened. function hpuiOpenDialog(dialogDialog, container, event) { // Make sure we got passed a JQuery dialog; return short otherwise. if (!dialogDialog || !dialogDialog.length || (typeof dialogDialog != 'object') || !(dialogDialog instanceof jQuery) || !(dialogDialog.is(':data(dialog)'))) return; // Make sure the container is a DOM element or window; return short otherwise. if (!container || !(container.nodeType || container == window)) return; // Center the dialog overlay in the given container and show it. dialogDialog.dialog( "option", "position", { my: "center center", at: "center center", of: container } ); dialogDialog.dialog( "open" ); // Cancel event propagation if we were passed a trigger event for the open. if (event) { event.stopImmediatePropagation(); event.preventDefault(); } } // Positioning function for dialog overlay when opened. function hpuiOpenForm(formDialog, container, event) { // Make sure we got passed a JQuery dialog; return short otherwise. if (!formDialog || !formDialog.length || (typeof formDialog != 'object') || !(formDialog instanceof jQuery) || !(formDialog.is(':data(dialog)'))) return; // Make sure the container is a DOM element or window; return short otherwise. if (!container || !(container.nodeType || container == window)) return; formDialog.dialog( "option", "position", { my: "center center", at: "center center", of: container } ); formDialog.dialog( "open" ); // Cancel event propagation if we were passed a trigger event for the open. if (event) { event.stopImmediatePropagation(); event.preventDefault(); } } // Positioning function for progress indicator overlay when opened. function hpuiOpenProgressIndicator(progressDialog, container, event) { // Make sure we got passed a JQuery dialog; return short otherwise. if (!progressDialog || !progressDialog.length || (typeof progressDialog != 'object') || !(progressDialog instanceof jQuery) || !(progressDialog.is(':data(dialog)'))) return; // Make sure the container is a DOM element or window; return short otherwise. if (!container || !(container.nodeType || container == window)) return; progressDialog.dialog( "option", "position", { my: "center center", at: "center center", of: container } ); progressDialog.dialog( "open" ); // HPUI_URL and HPUI_IMG_URL are alternative global variables for the root URL // to the images folder. var baseUrl = typeof (determineBaseImagesUrl) == 'function' ? determineBaseImagesUrl() : ""; // from init.js // Set timeout on the progress indicator image to ensure it starts animating. setTimeout(function() { jQuery("iframe.hpui-progress-indicator").attr("src", baseUrl + 'HPE_animated_large_blue_gray.gif'); }, 300); // Cancel event propagation if we were passed a trigger event for the open. if (event) { event.stopImmediatePropagation(); event.preventDefault(); } } /*** "Private" functions - not for use by feature developers ***/ // Function for closing any open progress indicators when the page loads. function hideAllProgressIndicators() { var indicators = jQuery("div.hpui-progress-indicator,iframe.hpui-progress-indicator"); if (indicators && indicators.length) { for (var i = 0; i < indicators.length; i++) { var indicator = jQuery(indicators[i]); indicator.parent().dialog("close"); } } } // Initialize progress indicators in the given context. function initProgressIndicators(context) { // Convert div to iframe. // HPUI_IMG_URL is a global variable for the root URL to the images folder. var imageUrl = typeof (determineBaseImagesUrl) == 'function' ? determineBaseImagesUrl() : ""; // from init.js jQuery("").replaceAll('div.hpui-progress-indicator', context); // Register event listeners to close any open progress indicators. if (window.attachEvent) { // some browsers support this way: // this event is for loading from server or browser cache window.attachEvent("onload", hideAllProgressIndicators); } else if (window.addEventListener) { // some browsers support this way: // this event is for loading from server window.addEventListener("load", hideAllProgressIndicators, false); // FF // this event is for loading from browser cache window.addEventListener("pageshow", hideAllProgressIndicators, false); // FF } } /****** end HPE overlays JS (overlays.js) ******/ /****** begin HPE shopping cart JS (shopping-cart.js) ******/ /*** "Public" methods - start with prefix "hpui" - for use by feature developers ***/ // Add screenreader messages for the given locale into the shopping cart icons // within the given context (may be a JQuery Object, a string HTML ID, or the whole // page by default). function hpuiAddShoppingCartResources(context) { // Get the message resources. if (typeof(hpuiAddMessageResources) == 'function') { hpuiAddMessageResources(); } // Determine the context (if not given). if (!context || !context.length || (typeof context != 'object') || !(context instanceof jQuery)) { if (context && typeof context == 'string') { context = jQuery('#' + context); } else { context = document; } } // For each shopping cart set, add the screenreader message and title as needed. jQuery('a.hpui-shopping-cart-icon,' + 'span.hpui-shopping-cart-icon,' + 'div.hpui-shopping-cart-icon', context).each(function() { var icon = jQuery(this); setShoppingCartIconScreenreaderText(icon); }); } // Dynamically opens a tooltip without user action. // Stays opened for the specified period and closes automatically. If the user performs // mouse enter action on the content, then the close action will be removed. // Usage - hpuiOpenShoppingCart(jQuery('#NonEmptyMiniShoppingCart .hpui-shopping-cart-icon'),jQuery('.ui-tooltip .hpui-mini-shopping-cart-table'), 3000); function hpuiOpenShoppingCart(shoppingCartLink, shoppingCartContent, period) { // Make sure we got passed JQuery objects; return short otherwise. if (!shoppingCartLink || !shoppingCartLink.length || (typeof shoppingCartLink != 'object') || !(shoppingCartLink instanceof jQuery)) return; if (!shoppingCartContent || !shoppingCartContent.length || (typeof shoppingCartContent != 'object') || !(shoppingCartContent instanceof jQuery)) return; // Make sure the triggering link is not disabled; do nothing if disabled. if (shoppingCartLink.attr('disabled')) return; // Default period to 3 seconds. if (!period || isNaN(period) || (period <= 0)) period = 3000; // Open the tooltip and auto-close at the end of the period. shoppingCartLink.trigger('mouseenter'); var closeTooltip = setTimeout(function() { shoppingCartLink.tooltip('close'); tweakIconTitle(shoppingCartLink); }, period); // Keep the tooltip open if the user mouses-into it until he mouses-out. jQuery("div.ui-tooltip-content").off("mouseenter",shoppingCartContent); jQuery("div.ui-tooltip-content").on("mouseenter",shoppingCartContent,function(){ clearTimeout(closeTooltip); }); jQuery("div.ui-tooltip-content").off("mouseleave",shoppingCartContent); jQuery("div.ui-tooltip-content").on("mouseleave",shoppingCartContent,function(){ shoppingCartLink.tooltip('close'); tweakIconTitle(shoppingCartLink); }); } /*** "Private" functions not for direct use by feature developers ***/ // Return just the counter from the shopping cart icon. // This is the icon text minus any screenreader text, forced // to a non-negative integer. function getIconCounter(icon) { var iconCounter = jQuery.trim(icon.text()); icon.find(".hpui-screenreader-text").each(function() { var screenreaderText = jQuery(this).text(); iconCounter = jQuery.trim(iconCounter.replace(screenreaderText, '')); }); iconCounter = parseInt(iconCounter, 10); if (isNaN(iconCounter) || iconCounter < 0) iconCounter = 0; return iconCounter; } // Set the icon counter in the shopping cart icon. // The counter must be a non-negative integer; if not, zero is assumed. // When the counter is zero, the shopping cart icon is emptied. function setIconCounter(icon, val) { val = parseInt(val, 10); if (isNaN(val) || val < 0) val = 0; if (val > 0) { if (val < 100) icon.html("" + val + ""); else icon.html("" + val + ""); } else { icon.empty(); } } // When icon is enabled, use single-space title instead of no title. // When icon is disabled, use no title instead of single-space title. function tweakIconTitle(icon) { if (!icon.attr('disabled')) { if (!jQuery.trim(icon.attr('title'))) icon.attr('title', ' '); } else { if (!jQuery.trim(icon.attr('title'))) icon.removeAttr('title'); } } // Initialize shopping carts in the given context function initShoppingCart(context) { // Initialize the mini shopping cart tooltip for each shopping cart icon. jQuery('a.hpui-shopping-cart-icon,' + 'span.hpui-shopping-cart-icon,' + 'div.hpui-shopping-cart-icon', context).each(function(index) { var icon = jQuery(this); var iconCounter = getIconCounter(icon); var iconState = icon.attr('disabled') ? 'disable' : 'enable'; // Initialize the appropriate counter span (normal or wide) based on the counter size. // Don't initialize the screenreader text, that will come later. setIconCounter(icon, iconCounter); // Initialize the title attribute. tweakIconTitle(icon); // Insert into the normal tabflow. No need to do this if tab flow or an href // is set. if (!icon.attr('tabindex') && !icon.attr('href')) icon.attr('tabindex', '0'); // Register keypress event handler to trigger click on 'enter', for accessibility. // No need to do this if an href is not set because it happens by default. if (!icon.attr('href')) { icon.off('keypress.hpui-shopping-cart'); icon.on('keypress.hpui-shopping-cart', function(event) { var icon = jQuery(this); var keycode = (event.keyCode ? event.keyCode : event.which); if (keycode == '13') { icon.trigger('click'); } }); } // Initialize the tooltip. icon.tooltip({ content : generatingTitle, tooltipClass: "hpui-mini-shopping-cart-table", position : { my : "right+18 top+8", at: "right bottom", collision: "flip", using : function(position, feedback) { jQuery(this).css(position); if(feedback.vertical == 'bottom'){ jQuery("
").addClass("hpui-mini-shopping-cart-arrow-bottom").appendTo(this); } else if (feedback.vertical == 'top') { jQuery("
").addClass("hpui-mini-shopping-cart-arrow-top").appendTo(this); } } } }); // Keep the tooltip visible if user mouseover the tooltip, otherwise // close the tooltip in 1/2 second. icon.bind("mouseleave", function(event) { event.stopImmediatePropagation(); var fixed = setTimeout(function() { icon.tooltip("close"); tweakIconTitle(icon); }, 500); jQuery(".ui-tooltip").hover( function() { clearTimeout(fixed); }, function() { icon.tooltip("close"); tweakIconTitle(icon); }); }).tooltip(); icon.bind("focus", function() { icon.tooltip("close"); icon.addClass("hpui-shopping-cart-icon-focus"); tweakIconTitle(icon); //jQuery(this).css("background-position", "0px -170px"); }); icon.bind("blur", function() { icon.removeClass("hpui-shopping-cart-icon-focus"); }); // Register the disable event on the shopping cart icon. icon.off('hpui-disable.hpui-shopping-cart'); icon.on('hpui-disable.hpui-shopping-cart', function() { return function() { var icon = jQuery(this); // Disable the shopping cart icon and link. icon.attr('disabled', ''); // Update the screenreader text. setShoppingCartIconScreenreaderText(icon); // Unset single-space title when no title. if (!jQuery.trim(icon.attr('title'))) icon.removeAttr('title'); } }()); // Register the enable event on the shopping cart icon. icon.off('hpui-enable.hpui-shopping-cart'); icon.on('hpui-enable.hpui-shopping-cart', function() { return function() { var icon = jQuery(this); // Enable the shopping cart icon and link. icon.removeAttr('disabled'); // Update the screenreader text. setShoppingCartIconScreenreaderText(icon); // Set single-space title when no title. if (!jQuery.trim(icon.attr('title'))) icon.attr('title', ' '); } }()); // Register the custom value event on the shopping cart icon. icon.off('hpui-value.hpui-shopping-cart'); icon.on('hpui-value.hpui-shopping-cart', function(event, val) { var icon = jQuery(this); // Set the counter value if new value is greater than zero, // and empty the counter value otherwise. setIconCounter(icon, val); // Update the screenreader text. setShoppingCartIconScreenreaderText(icon); }); // Register the custom toggle event on the shopping cart icon. // This increments or decrements the current counter by the integer // amount (positive or negative) given. icon.off('hpui-toggle.hpui-shopping-cart'); icon.on('hpui-toggle.hpui-shopping-cart', function(event, val) { var icon = jQuery(this); // Normalize the value. val = parseInt(val); if (isNaN(val)) val = 0; // Calculate the new counter value. var newVal = getIconCounter(icon) + val; // Set the new counter value. icon.trigger('hpui-value', newVal); }); // Register the custom clear event on the shopping cart icon. icon.off('hpui-clear.hpui-shopping-cart'); icon.on('hpui-clear.hpui-shopping-cart', function() { return function() { var icon = jQuery(this); // Set a value of zero. icon.trigger('hpui-value', 0); } }()); // Register the custom reset event on the shopping cart icon. icon.off('hpui-reset.hpui-shopping-cart'); icon.on('hpui-reset.hpui-shopping-cart', function(initValue, initState) { return function() { var icon = jQuery(this); // Reset the text input disabled/readonly/enabled state icon.trigger('hpui-' + initState); // Reset the counter value icon.trigger('hpui-value', initValue); } }(iconCounter, iconState)); }); } function setShoppingCartIconScreenreaderText(icon) { var iconTitle = jQuery.trim(icon.attr('title')); var iconText = jQuery.trim(icon.text()); var iconCounter = getIconCounter(icon); var iconCounterSpan = icon.children("span.hpui-counter, span.hpui-wide-counter"); var disabled = icon.attr('disabled'); // If there is a counter then attach the messages for the non-empty case as needed. // If no counter, then attach the message for the empty case as needed. if (iconCounter > 0) { if (disabled) { if (typeof non_empty_shoppingcart_disabled_screenreader == 'string') iconCounterSpan.html("" + non_empty_shoppingcart_disabled_screenreader + "" + iconCounter); } else { if (typeof non_empty_shoppingcart_screenreader == 'string') iconCounterSpan.html("" + non_empty_shoppingcart_screenreader + "" + iconCounter); } if (typeof non_empty_shoppingcart_title == 'string') // Remember, initial generated/default title is a single-space. // Only set title to message if title and text not already set. if (!iconTitle && !iconText && non_empty_shoppingcart_title) icon.attr('title', non_empty_shoppingcart_title); } else { if (disabled) { if (typeof empty_shoppingcart_disabled_screenreader == 'string') icon.html("" + empty_shoppingcart_disabled_screenreader + ""); } else { if (typeof empty_shoppingcart_screenreader == 'string') icon.html("" + empty_shoppingcart_screenreader + ""); } if (typeof empty_shoppingcart_title == 'string') // Remember, initial generated/default title is a single-space. // Only set title to message if title and text not already set. if (!iconTitle && !iconText && empty_shoppingcart_title) icon.attr('title', empty_shoppingcart_title); } } /****** end HPE shopping cart JS (shopping-cart.js) ******/ /****** begin HPE tables JS (tables.js) ******/ /*** "Public" table methods - start with prefix "hpui" - for use by feature developers ***/ // This hash maps lowercase locales (format ll eg "fr" or ll-cc, eg "zh-tw") to // Java locale tags (format ll eg "fr" or ll_CC, eg "zh_TW") of provided message // bundles. var HPUI_LOCALES_TO_TABLE_MESSAGES = { 'zh-hk':'zh_HK', 'zh-tw':'zh_TW', 'cs': 'cs', 'de': 'de', 'el': 'el', 'es': 'es', 'fr': 'fr', 'hu': 'hu', 'it': 'it', 'ja': 'ja', 'ko': 'ko', 'pl': 'pl', 'pt': 'pt', 'ru': 'ru', 'tr': 'tr', 'zh': 'zh' }; // Return URL for best-fit localized resource file for the given locale. function hpuiAddTableResources() { // First determine the locale being requested: either the HPUI_LOCALE or the // value of the HPUI_LOCALE_COOKIE or English by default. From init.js. var requestedLocale = typeof (determineLocale) == 'function' ? determineLocale() : "en"; // From the locale being requested, determine the locale to actually use. var localeToUse = ""; var requestedLanguage = requestedLocale; if (requestedLocale.length > 2) requestedLanguage = requestedLocale.substring(0, 2); if (HPUI_LOCALES_TO_TABLE_MESSAGES[requestedLocale.toLowerCase()]) // We will use the full locale if it is supported localeToUse = HPUI_LOCALES_TO_TABLE_MESSAGES[requestedLocale.toLowerCase()]; else if (HPUI_LOCALES_TO_TABLE_MESSAGES[requestedLanguage.toLowerCase()]) // Else we will use the language if it is supported localeToUse = HPUI_LOCALES_TO_TABLE_MESSAGES[requestedLanguage.toLowerCase()]; else // Else we will use English (base) if neither full locale nor language are supported localeToUse = "en"; // Build and return the best-fit datatables JSON file URL for the locale to use. // HPUI_URL and HPUI_JS_URL are alternative global variables for the root URL // to the JS folder. From init.js. var baseUrl = typeof (determineBaseJsUrl) == 'function' ? determineBaseJsUrl() : ""; var url = baseUrl + 'datatables/i18n/datatables' + (localeToUse == 'en' ? '' : '_' + localeToUse) + '.json'; return url; } // Initialize pagination on the given table with the given options. function hpuiPaginateTable(options) { // Make sure we got table options. if (!options || !options.tableID) return; var tableID = options.tableID; var isViewButtonRequired = options.isViewButtonRequired; var pageSize = options.pageSize; var tableElement = jQuery("table.hpui-standard-table#" + tableID + "," + "table.hpui-static-table#" + tableID); // Sanity check - there should be one and only one such table if (tableElement && tableElement.length == 1) { var viewButtonID = "hpui-view-button_" + tableID; var wrapper = tableElement.parent(); var oTable = tableElement.dataTable(); var oSettings = oTable.fnSettings(); var rowsToShow = oSettings.fnRecordsDisplay(); var viewAll = oSettings.oLanguage.oPaginate.sViewAll; var viewLess = oSettings.oLanguage.oPaginate.sViewLess; var paginationInfo = jQuery('.dataTables_info', wrapper); // Sanity check - page size should be a positive number if ((typeof pageSize != "number") || (pageSize < 1)) // Default page size to 25 pageSize = 25; else if (!(oSettings._iDisplayLength == -1 || oSettings._iDisplayLength == pageSize)) { oSettings._iDisplayLength = pageSize; oTable.fnDraw(); } // Insert pagination info into the normal tabflow. if (!paginationInfo.attr('tabindex')) paginationInfo.attr('tabindex', '0'); if (rowsToShow > pageSize) { jQuery('.dataTables_paginate', wrapper).show(); paginationInfo.children('span.hpui-screenreader-text:last').show(); if (isViewButtonRequired) { if (oSettings._iDisplayLength == pageSize) jQuery('.dataTables_paginate', wrapper).append( "" + viewAll + ""); else jQuery('.dataTables_paginate', wrapper).append( "" + viewLess + ""); var viewButton = jQuery("span#" + viewButtonID); viewButton.off('click.hpui-view-button'); viewButton.on('click.hpui-view-button', function() { if (jQuery(this).text() == viewAll) { jQuery(this).text(viewLess); oSettings._iDisplayLength = -1; oTable.fnDraw(); } else { jQuery(this).text(viewAll); oSettings._iDisplayLength = pageSize; oTable.fnDraw(); } }); viewButton.off('keypress.hpui-view-button'); viewButton.on('keypress.hpui-view-button', function(event) { var keycode = (event.keyCode ? event.keyCode : event.which); if(keycode == '13'){ viewButton.trigger('click'); } }); } } else { jQuery('.dataTables_paginate', wrapper).hide(); paginationInfo.children('span.hpui-screenreader-text:last').hide(); } } } // Initialize nested tables inside the given table with the given options. function hpuiNestTable(options){ // Make sure we got table options. if (!options || !options.tableID) return; var tableID = options.tableID; var multiExpand = options.multiExpand; var ajaxPreloader = options.ajaxPreloader; var ajaxProgressIndicator = options.ajaxProgressIndicator; var ajaxError = options.ajaxError; var ajaxDelay = options.ajaxDelay; var ajaxTimeout = options.ajaxTimeout; // Rationalize multiexpand argument if (!multiExpand) multiExpand = false; // Rationalize preloader argument if (!ajaxPreloader) ajaxPreloader = false; else if (typeof ajaxPreloader != 'string') ajaxPreloader = '
'; // Rationalize progress indicator argument if (!ajaxProgressIndicator || !ajaxProgressIndicator.length || typeof ajaxProgressIndicator != 'object' || !(ajaxProgressIndicator instanceof jQuery) || !(ajaxProgressIndicator.is(':data(dialog)'))) ajaxProgressIndicator = false; // Rationalize error argument if (!ajaxError || (typeof ajaxError != "string")) ajaxError = false; // Rationalize delay argument if (!ajaxDelay) ajaxDelay = false; else if ((typeof ajaxDelay != "number") || (ajaxDelay < 1)) ajaxDelay == 500; else ajaxDelay = Math.round(ajaxDelay); // Rationalize timeout argument if (!ajaxTimeout || (typeof ajaxTimeout != "number") || (ajaxTimeout < 1)) ajaxTimeout = 0; else ajaxTimeout = Math.round(ajaxTimeout); // Select the requested table var containerTable = jQuery("table.hpui-standard-table#" + tableID + "," + "table.hpui-static-table#" + tableID); // Sanity check - there should be one and only one such table if (containerTable && containerTable.length == 1) { var containerTable = containerTable.dataTable(); var innerContentDivs = []; var rowCount = 1; var openRows = []; // Setup the expand/collapse icons on the rows that need them. jQuery('td:first-child', containerTable.fnGetNodes()).each(function() { // For each row in the outer table: // var needIcon = false; var firstCell = jQuery(this); var thisRow = firstCell.parent("tr"); var ajaxUrl = firstCell.parent("tr").attr("data-source"); var rowID = tableID + rowCount; thisRow.removeAttr("data-source"); // Ajax case: need icon when an Ajax URL has been defined for this row. if (ajaxUrl) needIcon = true; // Non-Ajax case: need icon when div has been defined for this row. else { var innerContentDiv = jQuery("div#" + rowID); needIcon = innerContentDiv && innerContentDiv.length; // Save div reference for later show/hide. innerContentDivs.push(innerContentDiv); } // Add the icon if needed. Remove it and go to next row if not needed. var icon = firstCell.children('a.hpui-expand-icon,a.hpui-collapse-icon'); if (needIcon) { if (!icon || !icon.length) { icon = jQuery(""); if (typeof(hpuiInitialize) == 'function') hpuiInitialize(icon); firstCell.prepend(icon); if (typeof(hpuiInitialize) == 'function') hpuiInitialize(firstCell); } } else { if (icon && icon.length) icon.remove(); rowCount++; return; } // Register click event on the icon. icon.off('click.hpui-nested-table'); icon.on('click.hpui-nested-table', {ajaxUrl:ajaxUrl}, function (event) { var icon = jQuery(this); var rowObj = icon.parent("td").parent("tr"); var row = rowObj[0]; var i = jQuery.inArray(row, openRows); var ajaxUrl = event.data.ajaxUrl; // Stop the click propagation. event.preventDefault(); event.stopPropagation(); if (i >= 0) { // Handle click when inner content is already open: // // Convert the icon to an expand icon. icon.removeClass("hpui-collapse-icon").addClass("hpui-expand-icon"); if (typeof(hpuiInitialize) == 'function') hpuiInitialize(icon.parent()); // Then close the inner content. containerTable.fnClose(row); // Lastly remove it from the list of open rows. openRows.splice(i, 1); } else { // Handle click when inner content is not already open: // // First close other inner content (unless multi-expand is on). if (openRows.length == 1 && !multiExpand) { var otherIcon = jQuery(openRows[0]).find('a.hpui-collapse-icon'); otherIcon.removeClass("hpui-collapse-icon").addClass("hpui-expand-icon"); if (typeof(hpuiInitialize) == 'function') hpuiInitialize(otherIcon.parent()); containerTable.fnClose(openRows[0]); openRows.splice(openRows[0], 1); } // Then convert the icon to a collapse icon. icon.addClass("hpui-collapse-icon").removeClass("hpui-expand-icon"); if (typeof(hpuiInitialize) == 'function') hpuiInitialize(icon.parent()); // Then add the row to the list of open rows. openRows.push(row); // Then open the inner content - differs for Ajax and non-Ajax cases. if (!ajaxUrl) { // Non-Ajax case: // // Fetch the inner content div from saved references, and // insert into the table. var index = icon.attr('name').replace(tableID, ''); containerTable.fnOpen(row, innerContentDivs[(index - 1)].show(), 'hpui-nested-table-container'); } else { // Ajax case: // // If progress indicator, then open it. if (ajaxProgressIndicator && (typeof(hpuiOpenProgressIndicator) == 'function')) hpuiOpenProgressIndicator(ajaxProgressIndicator, window); // Otherwise if preloader, then open it. else if (ajaxPreloader) { containerTable.fnOpen(row, ajaxPreloader); // Make sure it is initialized. var newRowObj = rowObj.next("tr"); if (typeof (hpuiInitialize) == 'function') hpuiInitialize(newRowObj); } // Make the Ajax call. To slow this down in a demo, so users // can see the progress indicator or preloader for a while, // we support a secret property, ajaxDelay. This is not // public knowledge and we will never use this in // production. var ajaxCall = function() { jQuery.ajax({ url: ajaxUrl, dataType: 'html', timeout: ajaxTimeout, success: function(data) { // Handle success callback from Ajax: // First check whether row is still meant to be open - // if not, abandon the AJAX response. if (icon.hasClass('hpui-collapse-icon')) { // Add the data into the table row (this // automatically replaces a preloader if // any). containerTable.fnOpen(row, data, 'hpui-nested-table-container'); // Initialize the data in the new table // row, by calling hpuiInitialize() on it. var newRowObj = rowObj.next("tr"); if (typeof(hpuiInitialize) == 'function') hpuiInitialize(newRowObj); } // Close the progress indicator if any. if (ajaxProgressIndicator) ajaxProgressIndicator.dialog('close'); }, error: function(data) { // Handle error callback from Ajax: // First check whether row is still meant to be open - // if not, abandon the AJAX response. if (icon.hasClass('hpui-collapse-icon')) { // Add error content, if any, into the table // row (this automatically replaces a // preloader if any). if (ajaxError) { containerTable.fnOpen(row, ajaxError); // Initialize the data in the new table // row, by calling hpuiInitialize() on it. var newRowObj = rowObj.next("tr"); if (typeof(hpuiInitialize) == 'function') hpuiInitialize(newRowObj); } } // Close progress indicator or preloader row // (unless we just inserted an error). if (ajaxProgressIndicator) ajaxProgressIndicator.dialog('close'); else if (!ajaxError) containerTable.fnClose(row); } }); } if (ajaxDelay) { setTimeout (ajaxCall, ajaxDelay); } else ajaxCall(); } } }); // end of click handler rowCount++; return; }); // end of row initializer } } // Initialize inner tables inside the given table. function hpuiInnerTable(id) { // First find all inner tables in the given outer, and set the height of // each one's outer table cell explicitly to its current computed height // (which in turn is the current computed height of that whole outer row). // Since the hpui-inner-table style is height 100%, this will cause each // inner table to occupy the full height of its containing outer row. // // Update: Further testing in IE, FF and Chrome shows that this seems to // be unnecessary, and in the case of Chrome it somehow causes unequal // heights to be set on the outer cells in the last row. So comment // this out. DSJ 2013/9/27 /* jQuery('table.hpui-standard-table#' + id + ',' + 'table.hpui-static-table#' + id).each(function(i) { jQuery(this).find('td.hpui-inner-table,th.hpui-inner-table').each(function(j) { var outerCell = jQuery(this); outerCell.css('height', outerCell.height() + 'px'); }); }); */ // Then find all rows in the given outer, and for each such row, find all // the contained inner table rows and set their heights. Each inner row's // height is set to the maximum current computed height of all like-numbered // rows in all the inner tables of this outer row. This way, the table // row heights of inner tables in the same outer row will all align. // Thanks to Oliver Wu for this algorithm. jQuery('table.hpui-standard-table#' + id + '>tbody>tr,' + 'table.hpui-standard-table#' + id + '>thead>tr,' + 'table.hpui-standard-table#' + id + '>tr,' + 'table.hpui-static-table#' + id + '>tbody>tr,' + 'table.hpui-static-table#' + id + '>thead>tr,' + 'table.hpui-static-table#' + id + '>tr').each(function(i, outerRow) { outerRow = jQuery(outerRow); var nextOuterRow = outerRow.next("tr"); var borderHeight = 1; if (!nextOuterRow || nextOuterRow.length == 0) borderHeight = 0; var innerRowHeights = []; outerRow.find('>td.hpui-inner-table>table,>th.hpui-inner-table>table').each(function(j, innerTable) { innerTable = jQuery(innerTable); innerTable.find('>tbody>tr,>thead>tr,>tr').each(function (k, innerRow) { innerRow = jQuery(innerRow); if (innerRowHeights[k]) innerRowHeights[k] = Math.max(innerRowHeights[k], innerRow.height()); else innerRowHeights[k] = innerRow.height(); }); }); outerRow.find('>td.hpui-inner-table>table,>th.hpui-inner-table>table').each(function(j, innerTable) { innerTable = jQuery(innerTable); innerTable.find('>tbody>tr,>thead>tr,>tr').each(function (k, innerRow) { innerRow = jQuery(innerRow); innerRow.css('height', innerRowHeights[k] + 'px'); }); // calculate any remaining space in the outer row and add to the last row of the inner table // (disregard 1px for outer row bottom border in this calculation) var extra = outerRow.height() - innerTable.height() - borderHeight; if (extra > 0) { innerTable.find('>tbody>tr:last-child,>thead>tr,>tr:last-child').each(function (k, lastInnerRow) { lastInnerRow = jQuery(lastInnerRow); var newHeight = lastInnerRow.height() + extra; lastInnerRow.css('height', newHeight + 'px'); }); } // fix outer row height so if table is proportional and is resized by the user // the above settings will not get thrown out of whack outerRow.css('height', outerRow.height()); }); }); // IE8 hack to remove the unnecessary borders on the inner table. if ((typeof(getInternetExplorerVersion) == 'function') && (getInternetExplorerVersion() === 8)) { jQuery('table.hpui-standard-table#'+id+' td.hpui-inner-table > table > tbody').each(function(event){ jQuery(this).children('tr').children('td').css('border-right','0px'); jQuery(this).children('tr:last-child').children('td').css('border-bottom','0px'); }); } } /* * Function: hpuiGetTableDataAsDisplayed * Purpose: Return an array with the data arrays used for displaying the table * Returns: array node: data array elements * Inputs: tableID * Source: http://datatables.net/forums/discussion/798/export-current-state-of-datatable/p1 */ function hpuiGetTableDataAsDisplayed(tableID) { if (!tableID) return; var tableElement = jQuery("table.hpui-standard-table#" + tableID + "," + "table.hpui-static-table#" + tableID); if (tableElement && tableElement.length == 1) { var oTable = tableElement.dataTable(); var oSettings = oTable.fnSettings(); var aaData = []; for ( var j=0, jLen=oSettings.aiDisplay.length ; j 0) { if (pipeCache) { getPipelinedServerSideTable(sSource, aoData, fnCallback, oSettings, ajaxTimeout, ajaxError, destroyTableOnError, pipeCache, pipeSize); } else { handleServerSideError(ajaxError, destroyTableOnError, oSettings); } } else { getServerSideTable(sSource, aoData, fnCallback, oSettings, ajaxTimeout, ajaxError, destroyTableOnError); } } /*** "Private" functions not for direct use by feature developers ***/ // Pre-Initialize tables in the given context. // This is hack for Large tables in IE9 have random empty TD showing up // For more information visit - https://drupal.org/node/1535714 function preInitTables(context) { if ((typeof(getInternetExplorerVersion) == 'function') && (getInternetExplorerVersion() === 9)) { var tables = jQuery('table.hpui-standard-table,table.hpui-static-table', context); var expr = new RegExp('>[\t\r\n\v\f]*<', 'g'); if (tables && tables.length) for (var i = 0; i < tables.length; i++) jQuery(tables[i]).html(jQuery(tables[i]).html().replace(expr, '><')); } } // Post-initialize tables in the given context. // This does the inner table sizing. Needs to happen after all other // pre-, main and post-init, otherwise some of the table row sizings may be // incorect. function postInitTables(context) { // Finally initialize the inner tables if any. var tables = jQuery('table.hpui-standard-table,table.hpui-static-table', context); if (tables && tables.length) for (var i = 0; i < tables.length; i++) hpuiInnerTable(jQuery(tables[i]).attr('id')); } // Initialize tables in the given context. function initTables(context) { // First, generate table alternating row styles when needed. var tables = jQuery('table.hpui-standard-table.hpui-alternating-rows,' + 'table.hpui-static-table.hpui-alternating-rows', context); if (tables && tables.length) { for (var i = 0; i < tables.length; i++) { var table = jQuery(tables[i]); var bodies = table.children('tbody'); if (bodies && bodies.length) { for (var j = 0; j < bodies.length; j++) { var body = jQuery(bodies[j]); body.children('tr:even').removeClass('hpui-normal-row hpui-alternate-row').addClass('hpui-normal-row'); body.children('tr:odd').removeClass('hpui-normal-row hpui-alternate-row').addClass('hpui-alternate-row'); } } } } // Finally: JQuery Datatables extensions for custom sorting. if (typeof(jQuery.fn.dataTableExt) != 'undefined') { // File Size - see http://www.datatables.net/plug-ins/sorting#file_size jQuery.extend( jQuery.fn.dataTableExt.oSort, { "file-size-pre": function ( a ) { var x = a.substring(0,a.length - 2); var x_unit = (a.substring(a.length - 2, a.length) == "MB" ? 1000 : (a.substring(a.length - 2, a.length) == "GB" ? 1000000 : 1)); return parseInt( x * x_unit, 10 ); }, "file-size-asc": function ( a, b ) { return ((a < b) ? -1 : ((a > b) ? 1 : 0)); }, "file-size-desc": function ( a, b ) { return ((a < b) ? 1 : ((a > b) ? -1 : 0)); } }); // Hidden title numbers - see http://www.datatables.net/plug-ins/sorting#hidden_title_numeric jQuery.extend( jQuery.fn.dataTableExt.oSort, { "title-numeric-pre": function ( a ) { var x = a.match(/title="*(-?[0-9\.]+)/)[1]; return parseFloat( x ); }, "title-numeric-asc": function ( a, b ) { return ((a < b) ? -1 : ((a > b) ? 1 : 0)); }, "title-numeric-desc": function ( a, b ) { return ((a < b) ? 1 : ((a > b) ? -1 : 0)); } } ); // Hidden title strings - see http://www.datatables.net/plug-ins/sorting#hidden_title_string jQuery.extend( jQuery.fn.dataTableExt.oSort, { "title-string-pre": function ( a ) { return a.match(/title="(.*?)"/)[1].toLowerCase(); }, "title-string-asc": function ( a, b ) { return ((a < b) ? -1 : ((a > b) ? 1 : 0)); }, "title-string-desc": function ( a, b ) { return ((a < b) ? 1 : ((a > b) ? -1 : 0)); } } ); // Localized string - wrote this one myself jQuery.extend( jQuery.fn.dataTableExt.oSort, { "i18n-string-asc" : function (s1, s2) { return s1.localeCompare(s2); }, "i18n-string-desc" : function (s1, s2) { return s2.localeCompare(s1); } } ); } // Initialize service summary views (both titles and content): // Set tabindex and map enter key to click event. jQuery('div[onclick].hpui-service-summary-title,' + 'table.hpui-service-summary-content tr[onclick]', context).each(function(index) { var section = jQuery(this); // Insert into the normal tabflow, unless tabflow already specified. if (!section.attr('tabindex')) section.attr('tabindex', '0'); // Register keypress event handler to trigger click on 'enter', for accessibility. section.off('keypress.hpui-tables'); section.on('keypress.hpui-tables', function(event) { var link = jQuery(this); var keycode = (event.keyCode ? event.keyCode : event.which); if (keycode == '13') { link.trigger('click'); } }); }); } // Internal functions used in server side data tables feature function fnSetKey(aoData, sKey, mValue) { for (var i = 0, iLen = aoData.length; i < iLen; i++) { if (aoData[i].name == sKey) { aoData[i].value = mValue; } } } function fnGetKey(aoData, sKey) { for (var i = 0, iLen = aoData.length; i < iLen; i++) { if (aoData[i].name == sKey) { return aoData[i].value; } } return null; } function getServerSideTable(sSource, aoData, fnCallback, oSettings, ajaxTimeout, ajaxError, destroyTableOnError) { jQuery.ajax({ "dataType": 'json', "url": sSource, "data": aoData, "timeout": ajaxTimeout, "success": fnCallback, "error": function() { handleServerSideError(ajaxError, destroyTableOnError, oSettings); }, "complete": function() { if (typeof(hideAllProgressIndicators) == 'function') hideAllProgressIndicators(); } }); } function getPipelinedServerSideTable(sSource, aoData, fnCallback, oSettings, ajaxTimeout, ajaxError, destroyTableOnError, oCache, iPipe) { var bNeedServer = false; var sEcho = fnGetKey(aoData, "sEcho"); var iRequestStart = fnGetKey(aoData, "iDisplayStart"); var iRequestLength = fnGetKey(aoData, "iDisplayLength"); var iRequestEnd = iRequestStart + iRequestLength; oCache.iDisplayStart = iRequestStart; /* If requested page not in cache, remember to make server-side fetch. */ if (!("iCacheLower" in oCache)) oCache.iCacheLower = -1; if (oCache.iCacheLower < 0 || iRequestStart < oCache.iCacheLower || iRequestEnd > oCache.iCacheUpper) { bNeedServer = true; } /* If requested sort or similar criteria not in cache, remember to make server-side fetch. */ if (oCache.lastRequest && !bNeedServer) { for (var i = 0, iLen = aoData.length; i < iLen; i++) { if (aoData[i].name != "iDisplayStart" && aoData[i].name != "iDisplayLength" && aoData[i].name != "sEcho") { if (aoData[i].value != oCache.lastRequest[i].value) { bNeedServer = true; break; } } } } /* Store the request for checking next time around */ oCache.lastRequest = aoData.slice(); /* Make server-side fetch when not in cache. */ if (bNeedServer) { if (iRequestStart < oCache.iCacheLower) { iRequestStart = iRequestStart - (iRequestLength * (iPipe - 1)); if (iRequestStart < 0 || iRequestLength < 0) { iRequestStart = 0; } } oCache.iCacheLower = iRequestStart; oCache.iCacheUpper = iRequestStart + (iRequestLength * iPipe); oCache.iDisplayLength = fnGetKey(aoData, "iDisplayLength"); fnSetKey(aoData, "iDisplayStart", iRequestStart); fnSetKey(aoData, "iDisplayLength", ((iRequestLength < 0) ? iRequestLength : (iRequestLength * iPipe))); jQuery.ajax({ "dataType": 'json', "url": sSource, "data": aoData, "timeout": ajaxTimeout, "success": function(json) { oCache.lastJson = jQuery.extend(true, {}, json); if (oCache.iCacheLower != oCache.iDisplayStart) { json.aaData.splice(0, oCache.iDisplayStart - oCache.iCacheLower); } if (oCache.iDisplayLength >= 0) { json.aaData.splice(oCache.iDisplayLength, json.aaData.length); } fnCallback(json); }, "error": function() { handleServerSideError(ajaxError, destroyTableOnError, oSettings); }, "complete": function() { if (typeof(hideAllProgressIndicators) == 'function') hideAllProgressIndicators(); } }); } /* Fetch from cache when server-side fetch not required. */ else { json = jQuery.extend(true, {}, oCache.lastJson); json.sEcho = sEcho; /* Update the echo for each response */ json.aaData.splice(0, iRequestStart - oCache.iCacheLower); if (iRequestLength >= 0) { json.aaData.splice(iRequestLength, json.aaData.length); } fnCallback(json); return; } } function handleServerSideError(ajaxError, destroyTableOnError, oSettings) { // Hide the progress indicators jQuery.fn.dataTableExt.oApi._fnProcessingDisplay(oSettings, false); if (typeof(hideAllProgressIndicators) == 'function') hideAllProgressIndicators(); // If a custom error message was provided, render it into the table - // otherwise no updates to the table in its current state. if (ajaxError) { if (destroyTableOnError) { jQuery(oSettings.nTableWrapper).html(ajaxError); } else { var nNewRow = document.createElement("tr"); var nNewCell = document.createElement("td"); nNewRow.appendChild( nNewCell ); nNewCell.colSpan = jQuery.fn.dataTableExt.oApi._fnVisbleColumns(oSettings); if (typeof ajaxError === "string") nNewCell.innerHTML = ajaxError; else jQuery(nNewCell).html(ajaxError); jQuery(oSettings.nTBody).html(nNewRow); } } } /****** end HPE tables JS (tables.js) ******/ /****** begin HPE typography JS (typography.js) ******/ /*** "Public" functions - may be used by feature developers ***/ /*** "Private" functions not for direct use by feature developers ***/ /****** end HPE typography JS (typography.js) ******/