nm3clol-archived-russellcou.../mirror/www.russellcountyva.us/Scripts/HtmlExtensionSupport.js

728 lines
24 KiB
JavaScript

/// <reference path="jquery-1.3.2-vsdoc.js">
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
});
});
}