/// var needRegisterH5Exts = true; var isAlreadyInitialized = false; // Only register the placeholder attachment code once, regardless of include count. // File shouldn't be included more than once, but it could happen. if (needRegisterH5Exts) { $(document).ready(function () { // Register placeholder shims, if needed. if (needPlaceHoldersShim() && !isAlreadyInitialized) { isAlreadyInitialized = true; // Not all INPUTs/TEXTAREAs are automatically hooked into this, // since we have older implementations of placeholders and // overridding them would cause wierd behavior. Plus, it // would not make sense to hook to image/checkbox/radio/etc. // The attribute cp5ph (CivicPlus HTML5 PlaceHolder) is automatically placed on inputs // with placeholders through the CPHtml5TextInput() HTML extension. registerPlaceHoldersShim($('input[cp5ph]')); registerPlaceHoldersShim($('textarea[cp5ph]')); } }); needRegisterH5Exts = false; } // Registers placeholders on fields inside a specific context. function registerPlaceHoldersShimOnContainer($container) { registerPlaceHoldersShim($('input[cp5ph]', $container)); registerPlaceHoldersShim($('textarea[cp5ph]', $container)); } // Unregisters placeholders on fields inside a specific context. function unregisterPlaceHoldersShimOnContainer($container) { unregisterPlaceHolderShim($('input[cp5ph]', $container)); unregisterPlaceHolderShim($('textarea[cp5ph]', $container)); } // Determines if placeholder shim is necessary. function needPlaceHoldersShim() { var tmpElem = document.createElement('input'); return !('placeholder' in tmpElem); } // Added due to a bug with IE 10's IE 7 document standards mode. The elem.getAttribute('placeholder') // always returns NULL if IE 10 in IE 7 document standards mode, but elem.attributes['placeholder'] // works. function getPlaceholder(elem) { var placeholder = elem.getAttribute('placeholder') if (placeholder == null) { placeholder = elem.attributes['placeholder']; if (placeholder == null) return ''; else return placeholder.value; } return placeholder; } // Unregisters placeholder shim hooks. Destroys event hooks and spawned placeholder element. function unregisterPlaceHolderShim($elemsToHack) { // Get hooks. var hookData = $elemsToHack.data('cp5ph_hooks'); if (hookData) { // Destroy all the hooks present. var attachedMSIE = hookData.ie == null ? [] : hookData.ie; var attachedSTD = hookData.std == null ? [] : hookData.std; var attachedJQR = hookData.jqr == null ? [] : hookData.jqr; var spawnedPHs = hookData.spawns == null ? [] : hookData.spawns; // Remove MSIE style events. for (var i = 0, len = attachedMSIE.length; i < len; i++) { if (attachedMSIE[i].element) attachedMSIE[i].element.detachEvent(attachedMSIE[i].event, attachedMSIE[i].method); } // Remove DOM standard (STD) events. for (var i = 0, len = attachedSTD.length; i < len; i++) { if (attachedSTD[i].element) attachedSTD[i].element.removeEventListener(attachedSTD[i].event, attachedSTD[i].method, false); } // Remove jQuery bindings. for (var i = 0, len = attachedJQR.length; i < len; i++) { if (attachedJQR[i].instance) attachedJQR[i].instance.unbind(attachedJQR[i].event, attachedJQR[i].method); } // Destroy placeholder spawned elements. for (var i = 0, len = spawnedPHs.length; i < len; i++) { if (spawnedPHs[i]) { spawnedPHs[i].innerHTML = ""; spawnedPHs[i].style.display = "none"; if (spawnedPHs[i].parentNode) spawnedPHs[i].parentNode.removeChild(spawnedPHs[i]); } } // Destroy hook data now that hooks have been cleaned. $elemsToHack.removeData('cp5ph_hooks'); } } // Registers placeholder shims for jQuery element group specified. // The shim is by no means perfect (won't catch things like attribute selectors causing changes). function registerPlaceHoldersShim($elemsToHack) { // Track standard, MSIE, and jQuery event assignments so they can be cancelled/destroyed. // Also track any spawned placeholder elements since they too need to be cleaned up. var attachedMSIE = []; var attachedSTD = []; var attachedJQR = []; var spawnedPHs = []; // Hooks programmatic changes to the value property for browsers without // placeholder support. jQuery did not seem to have a way to do this. var hookProgrammaticValueChange = function(elem, callback) { // Note: Browsers are buggy at this time with DOMControlValueChanged. // Handle Firefox Prior to 4 (which has built-in placeholder support). if (elem.__defineSetter__) { var oldSetter = elem.__lookupSetter__('value'); if (oldSetter) { elem.__defineSetter__('value', function(v) { oldSetter.call(elem, v); callback(); }); } } // Handle IE, even up to IE 9. if (elem.attachEvent) { attachedMSIE.push({ element: elem, event: 'onpropertychange', method: callback }); elem.attachEvent('onpropertychange', callback); } }; var displayAttrMatch = new RegExp('^(class|value|className|placeholder|id|style|style\\..*)$'); // Hooks display changes for an element (placeholder may need to update itself). var hookDisplayUpdates = function(elem, callback) { if (elem.addEventListener) { var domAttrModifiedHook = function(event) { // Prevents an infinite loop due to bubbling. event.stopPropagation(); // Another necessary escape hatch. if (event.target.className == '_ph_shim') return; if (displayAttrMatch.test(event.attrName)) callback(event.attrName); }; attachedSTD.push({ element: elem, event: 'DOMAttrModified', method: domAttrModifiedHook }); elem.addEventListener('DOMAttrModified', domAttrModifiedHook, false); } else if (elem.attachEvent) { var propertyChangeHook = function(event) { if (displayAttrMatch.test(event.propertyName)) callback(event.propertyName); }; attachedMSIE.push({ element: elem, event: 'onpropertychange', method: propertyChangeHook }); elem.attachEvent('onpropertychange', propertyChangeHook); } }; // Hooks display changes for an element or its parents. var hookDisplayUpdatesAndParents = function(elem, callback) { var node = elem; while (node && node != document.body) { hookDisplayUpdates(node, callback); node = node.parentNode; } }; // Debouncer used to prevent the same placeholder updates from ocuring over and over again within a short time (30 ms). var debouncer = []; var isBouncy = function(element) { var now = function() { return new Date().getTime(); }; var getIndexOf = function(elem) { for (var i = 0; i < debouncer.length; i++) { if (debouncer[i].object === element) { return i; } } return -1; }; var index = getIndexOf(element); if (index === -1) { var obj = { object: element, recentlyOccured: true }; debouncer.push(obj); setTimeout(function () { obj.recentlyOccured = false; } ,30); return false; } else if (debouncer[index].recentlyOccured) { return true; } else { debouncer[index].recentlyOccured = true; setTimeout(function () { debouncer[index].recentlyOccured = false; } , 30); return false; } }; // Updates position/style of pseudo-element that acts as placeholder message. // Called when necessary to ensure placeholder looks right (e.g. styles changed). var updatePlaceHolderMessageElement = function (phElem, elem) { var $elem = $(elem); if (isBouncy(elem)) { return; } // TODO: Does $elem.is() not work if the element is not in the document? if (elem.parentNode != null && !elem._focus && $elem.is(':visible')) phElem.style.display = (elem.value == '' || elem.value == null ? 'block' : 'none'); else { phElem.style.display = 'none'; return; } // Determine where placeholder element should go. var shouldParent = $elem.offsetParent().get(0); // Placeholder element cannot go inside table rows, use cell instead. if (shouldParent.tagName == 'TR') { shouldParent = elem; while (shouldParent.tagName != 'TD') shouldParent = shouldParent.parentNode; } var phChanged = (phElem.getAttribute('_ph_val') != getPlaceholder(elem)); if ((shouldParent != phElem.parentNode) || phChanged) { // Remove from old parent (or existing, if phChanged). // Necessary for phChanged since element may be inside a table, // and trying to set innerHTML in a table with IE causes trouble. phElem.parentNode.removeChild(phElem); // If placeholder changed, update innerHTML. if (phChanged) phElem.innerHTML = getPlaceholder(elem); // Ensure pseudo-placeholder is placed in same offsetParent // that element resides within (positioning), and add it to // the end (resolves some possible z-index issues). shouldParent.appendChild(phElem); } phElem.style.width = elem.clientWidth + 'px'; phElem.style.height = elem.clientHeight + 'px'; phElem.style.verticalAlign = elem.style.verticalAlign; phElem.style.lineHeight = elem.style.lineHeight; phElem.style.textAlign = elem.style.textAlign; phElem.style.fontSize = elem.style.fontSize; phElem.style.fontFamily = elem.style.fontFamily; var compStyle = (window.getComputedStyle ? window.getComputedStyle(elem, null) : elem.currentStyle); var elemPaddingLeft = parseInt(compStyle.paddingLeft.replace(/px$/g, ''), 10); var elemPaddingTop = parseInt(compStyle.paddingTop.replace(/px$/g, ''), 10); var pos = $elem.position(); phElem.style.top = (pos.top + elem.clientTop + elemPaddingTop - 2) + 'px'; phElem.style.left = (pos.left + elem.clientLeft + elemPaddingLeft) + 'px'; } // Creates pseudo-element that acts as placeholder message. var createPlaceHolderMessageElement = function(elem) { // Create pseudo-placeholder that will appear over the top of the control. var phElem = document.createElement('div'); // Attach to element for reference. elem._ph_shim = phElem; // Ensure pseudo-placeholder is placed in same offsetParent // that element resides within (positioning), and add it to // the end (resolves some possible z-index issues). var phValue = getPlaceholder(elem); phElem.innerHTML = (phValue == null ? '' : phValue); phElem.setAttribute('_ph_val', 'phValue'); phElem.setAttribute('id', 'ph_' + elem.id); phElem.setAttribute('name', 'ph_' + elem.id); var shouldParent = $(elem).offsetParent().get(0); shouldParent.appendChild(phElem); // Configure the pseudo-placeholder. phElem.className = '_ph_shim'; phElem.style.position = 'absolute'; phElem.style.color = '#aaa'; // Placeholder Text Color. phElem.style.backgroundColor = 'transparent'; phElem.style.cssFloat = 'none'; // Update appearance. updatePlaceHolderMessageElement(phElem, elem); // Set up events for pseudo-placeholder and element. var $phElem = $(phElem); var mouseDownHook = function(event) { phElem.style.display = 'none'; // Mouse down is passed to the input control // the placeholder is shown on top of. $(elem).trigger('mousedown', event); // Hack: IE needs setTimeout to actually do this properly for TEXTAREA. setTimeout(function() { try { elem.focus() } catch(err) { //When the text box is readonly then the above focus code would throw error //so that error is only handled only for Center, if u happen to get this error please do ur implemntation below //NOTE: here we have checked only for /formcenter and so if there is any other place which uses readonly textbox and trys to focus also will get the same alert - This is known bug //for DEtails talk to Akila or Robin - AK //**Please note the use of lowercase here** var url = (location.href).toLowerCase(); if (url.indexOf("/admin/formcenter") > -1) { alert('You have selected the field input. Please select the field label or instructions.'); } } }, 15); }; $phElem.mousedown(mouseDownHook); attachedJQR.push({ instance: $phElem, event: 'mousedown', method: mouseDownHook }); return phElem; }; // Registers a shim placeholder for an element (private helper method). var registerPlaceHolder = function (elem) { // Create jQuery wrapper. var $elem = $(elem); // Create placeholder. var phElem = createPlaceHolderMessageElement(elem); // Track creation. spawnedPHs.push(phElem); var focusHook = function () { // Older firefox does not support document.activeElement. elem._focus = true; phElem.style.display = 'none'; }; var blurHook = function () { // Older firefox does not support document.activeElement. elem._focus = false; if ((elem.value == '' || elem.value == null) && $(elem).is(':visible')) phElem.style.display = 'block'; }; $elem.focus(focusHook); $elem.blur(blurHook); attachedJQR.push({ instance: $elem, event: 'focus', method: focusHook }); attachedJQR.push({ instance: $elem, event: 'blur', method: blurHook }); // Ensure placeholder state is updated when the value // is changed programmatically. hookProgrammaticValueChange(elem, function () { if (elem._focus) phElem.style.display = 'none'; else { if ((elem.value == '' || elem.value == null) && $(elem).is(':visible')) phElem.style.display = 'block'; else phElem.style.display = 'none'; } }); // Ensure placeholder UI updates correctly when display changes are made. hookDisplayUpdatesAndParents(elem, function () { updatePlaceHolderMessageElement(phElem, elem); }); }; // Attach shim to each wrapped element passed to the method. $elemsToHack.each(function () { registerPlaceHolder(this); }); // Keep track of hooks so they can be destroyed. $elemsToHack.data('cp5ph_hooks', { ie: attachedMSIE, std: attachedSTD, jqr: attachedJQR, spawns: spawnedPHs }); } // Unregisters placeholder shim hooks. Destroys event hooks and spawned placeholder element. function unregisterPlaceHoldersShimForEach($elemsToHack) { // Get hooks. $elemsToHack.each(function () { var hookData = $(this).data('cp5ph_hooks'); if (hookData) { // Destroy all the hooks present. var attachedMSIE = hookData.ie == null ? [] : hookData.ie; var attachedSTD = hookData.std == null ? [] : hookData.std; var attachedJQR = hookData.jqr == null ? [] : hookData.jqr; var spawnedPHs = hookData.spawns == null ? [] : hookData.spawns; // Remove MSIE style events. for (var i = 0, len = attachedMSIE.length; i < len; i++) { if (attachedMSIE[i].element) attachedMSIE[i].element.detachEvent(attachedMSIE[i].event, attachedMSIE[i].method); } // Remove DOM standard (STD) events. for (var i = 0, len = attachedSTD.length; i < len; i++) { if (attachedSTD[i].element) attachedSTD[i].element.removeEventListener(attachedSTD[i].event, attachedSTD[i].method, false); } // Remove jQuery bindings. for (var i = 0, len = attachedJQR.length; i < len; i++) { if (attachedJQR[i].instance) attachedJQR[i].instance.unbind(attachedJQR[i].event, attachedJQR[i].method); } // Destroy placeholder spawned elements. for (var i = 0, len = spawnedPHs.length; i < len; i++) { if (spawnedPHs[i]) { spawnedPHs[i].innerHTML = ""; spawnedPHs[i].style.display = "none"; if (spawnedPHs[i].parentNode) spawnedPHs[i].parentNode.removeChild(spawnedPHs[i]); } } // Destroy hook data now that hooks have been cleaned. $(this).removeData('cp5ph_hooks'); } }); } // Registers placeholder shims for jQuery element group specified. // The shim is by no means perfect (won't catch things like attribute selectors causing changes). function registerPlaceHoldersShimForEach($elemsToHack) { // Track standard, MSIE, and jQuery event assignments so they can be cancelled/destroyed. // Also track any spawned placeholder elements since they too need to be cleaned up. var attachedMSIE = []; var attachedSTD = []; var attachedJQR = []; var spawnedPHs = []; // Hooks programmatic changes to the value property for browsers without // placeholder support. jQuery did not seem to have a way to do this. var hookProgrammaticValueChange = function (elem, callback) { // Note: Browsers are buggy at this time with DOMControlValueChanged. // Handle Firefox Prior to 4 (which has built-in placeholder support). if (elem.__defineSetter__) { var oldSetter = elem.__lookupSetter__('value'); if (oldSetter) { elem.__defineSetter__('value', function (v) { oldSetter.call(elem, v); callback(); }); } } // Handle IE, even up to IE 9. if (elem.attachEvent) { attachedMSIE.push({ element: elem, event: 'onpropertychange', method: callback }); elem.attachEvent('onpropertychange', callback); } }; var displayAttrMatch = new RegExp('^(class|value|className|placeholder|id|style|style\\..*)$'); // Hooks display changes for an element (placeholder may need to update itself). var hookDisplayUpdates = function (elem, callback) { if (elem.addEventListener) { var domAttrModifiedHook = function (event) { // Prevents an infinite loop due to bubbling. event.stopPropagation(); // Another necessary escape hatch. if (event.target.className == '_ph_shim') return; if (displayAttrMatch.test(event.attrName)) callback(event.attrName); }; attachedSTD.push({ element: elem, event: 'DOMAttrModified', method: domAttrModifiedHook }); elem.addEventListener('DOMAttrModified', domAttrModifiedHook, false); } else if (elem.attachEvent) { var propertyChangeHook = function (event) { if (displayAttrMatch.test(event.propertyName)) callback(event.propertyName); }; attachedMSIE.push({ element: elem, event: 'onpropertychange', method: propertyChangeHook }); elem.attachEvent('onpropertychange', propertyChangeHook); } }; // Hooks display changes for an element or its parents. var hookDisplayUpdatesAndParents = function (elem, callback) { var node = elem; while (node && node != document.body) { hookDisplayUpdates(node, callback); node = node.parentNode; } }; // Updates position/style of pseudo-element that acts as placeholder message. // Called when necessary to ensure placeholder looks right (e.g. styles changed). var updatePlaceHolderMessageElement = function (phElem, elem) { var $elem = $(elem); // TODO: Does $elem.is() not work if the element is not in the document? if (elem.parentNode != null && !elem._focus && $elem.is(':visible')) phElem.style.display = (elem.value == '' || elem.value == null ? 'block' : 'none'); else { phElem.style.display = 'none'; return; } // Determine where placeholder element should go. var shouldParent = $elem.offsetParent().get(0); // Placeholder element cannot go inside table rows, use cell instead. if (shouldParent.tagName == 'TR') { shouldParent = elem; while (shouldParent.tagName != 'TD') shouldParent = shouldParent.parentNode; } var phChanged = (phElem.getAttribute('_ph_val') != getPlaceholder(elem)); if ((shouldParent != phElem.parentNode) || phChanged) { // Remove from old parent (or existing, if phChanged). // Necessary for phChanged since element may be inside a table, // and trying to set innerHTML in a table with IE causes trouble. phElem.parentNode.removeChild(phElem); // If placeholder changed, update innerHTML. if (phChanged) phElem.innerHTML = getPlaceholder(elem); // Ensure pseudo-placeholder is placed in same offsetParent // that element resides within (positioning), and add it to // the end (resolves some possible z-index issues). shouldParent.appendChild(phElem); } phElem.style.width = elem.clientWidth + 'px'; phElem.style.height = elem.clientHeight + 'px'; phElem.style.verticalAlign = elem.style.verticalAlign; phElem.style.lineHeight = elem.style.lineHeight; phElem.style.textAlign = elem.style.textAlign; phElem.style.fontSize = elem.style.fontSize; phElem.style.fontFamily = elem.style.fontFamily; var compStyle = (window.getComputedStyle ? window.getComputedStyle(elem, null) : elem.currentStyle); var elemPaddingLeft = parseInt(compStyle.paddingLeft.replace(/px$/g, ''), 10); var elemPaddingTop = parseInt(compStyle.paddingTop.replace(/px$/g, ''), 10); var pos = $elem.position(); phElem.style.top = (pos.top + elem.clientTop + elemPaddingTop - 2) + 'px'; phElem.style.left = (pos.left + elem.clientLeft + elemPaddingLeft) + 'px'; } // Creates pseudo-element that acts as placeholder message. var createPlaceHolderMessageElement = function (elem) { // Create pseudo-placeholder that will appear over the top of the control. var phElem = document.createElement('div'); // Attach to element for reference. elem._ph_shim = phElem; // Ensure pseudo-placeholder is placed in same offsetParent // that element resides within (positioning), and add it to // the end (resolves some possible z-index issues). var phValue = getPlaceholder(elem); phElem.innerHTML = (phValue == null ? '' : phValue); phElem.setAttribute('_ph_val', 'phValue'); phElem.setAttribute('id', 'ph_' + elem.id); phElem.setAttribute('name', 'ph_' + elem.id); var shouldParent = $(elem).offsetParent().get(0); shouldParent.appendChild(phElem); // Configure the pseudo-placeholder. phElem.className = '_ph_shim'; phElem.style.position = 'absolute'; phElem.style.color = '#aaa'; // Placeholder Text Color. phElem.style.backgroundColor = 'transparent'; phElem.style.cssFloat = 'none'; // Update appearance. updatePlaceHolderMessageElement(phElem, elem); // Set up events for pseudo-placeholder and element. var $phElem = $(phElem); var mouseDownHook = function (event) { phElem.style.display = 'none'; // Mouse down is passed to the input control // the placeholder is shown on top of. $(elem).trigger('mousedown', event); // Hack: IE needs setTimeout to actually do this properly for TEXTAREA. setTimeout(function () { try { elem.focus() } catch (err) { //When the text box is readonly then the above focus code would throw error //so that error is only handled only for Center, if u happen to get this error please do ur implemntation below //NOTE: here we have checked only for /formcenter and so if there is any other place which uses readonly textbox and trys to focus also will get the same alert - This is known bug //for DEtails talk to Akila or Robin - AK //**Please note the use of lowercase here** var url = (location.href).toLowerCase(); if (url.indexOf("/admin/formcenter") > -1) { alert('You have selected the field input. Please select the field label or instructions.'); } } }, 15); }; $phElem.mousedown(mouseDownHook); attachedJQR.push({ instance: $phElem, event: 'mousedown', method: mouseDownHook }); return phElem; } // Registers a shim placeholder for an element (private helper method). var registerPlaceHolder = function (elem) { // Create jQuery wrapper. var $elem = $(elem); // Create placeholder. var phElem = createPlaceHolderMessageElement(elem); // Track creation. spawnedPHs.push(phElem); var focusHook = function () { // Older firefox does not support document.activeElement. elem._focus = true; phElem.style.display = 'none'; }; var blurHook = function () { // Older firefox does not support document.activeElement. elem._focus = false; if ((elem.value == '' || elem.value == null) && $(elem).is(':visible')) phElem.style.display = 'block'; }; $elem.focus(focusHook); $elem.blur(blurHook); attachedJQR.push({ instance: $elem, event: 'focus', method: focusHook }); attachedJQR.push({ instance: $elem, event: 'blur', method: blurHook }); // Ensure placeholder state is updated when the value // is changed programmatically. hookProgrammaticValueChange(elem, function () { if (elem._focus) phElem.style.display = 'none'; else { if ((elem.value == '' || elem.value == null) && $(elem).is(':visible')) phElem.style.display = 'block'; else phElem.style.display = 'none'; } }); // Ensure placeholder UI updates correctly when display changes are made. hookDisplayUpdatesAndParents(elem, function () { updatePlaceHolderMessageElement(phElem, elem); }); }; // Attach shim to each wrapped element passed to the method. $elemsToHack.each(function () { registerPlaceHolder(this); }); // Keep track of hooks so they can be destroyed. $elemsToHack.each(function() { $(this).data('cp5ph_hooks', { ie: attachedMSIE, std: attachedSTD, jqr: attachedJQR, spawns: spawnedPHs }); }); }