javascript reporting-services ssrs-2008 sql-server-2008-r2 reportmanager

El Administrador de informes de SSRS javascript falla en navegadores no IE para menús desplegables



reporting-services ssrs-2008 (2)

Después de algunas horas de pirateo con el archivo ReportingServices.js original, logré corregir el javascript para trabajar en Firefox, Chrome, Opera y Safari, así como en IE.

A pesar de que es un poco grande, he publicado toda la versión de ReportingServices.js editada a continuación para que otros la utilicen si es necesario. He puesto comentarios de "edición de chris" que muestran las líneas anteriores sobre sus ediciones para que pueda (si le importa) seguir lo que he cambiado. También resumí estos cambios en la parte superior del código.

La interfaz web del administrador de informes SSRS es muy útil y sería una pena no usarla solo porque Microsoft no se molestó en probarla en otros navegadores que no sean IE. Esta es la razón por la que siempre prefiero jQuery a través de Javascript simple para evitar este tipo de problemas de compatibilidad de navegador cruzado.

Tuve que publicarlo en 2 partes. Espero que esto ayude a otros!

/* Author: Chris Snowden Modified Date: 21st October 2011 ReportingServices.js file for SQL Server 2008 R2 Reporting Services Updated to fix a bug whereby drop down context menus didn''t work for any other browser than IE. 1) I added functions to find firstChild and lastChild while skipping any whitespace TextNode elements. 2) I updated the Clicked function to get at the table element value in a way that works for firefox. 3) I updated the SplitContextMenuConfigString function to access the table cells by first looping through each row and then the cells. Drop downs now work on Firefox, Chrome, Opera and Safari as well as IE. */ var checkBoxCount; var checkBoxId; var checkBoxHead; // Context menu var _divContextMenu; // The container for the context menu var _selectedIdHiddenField; // The id of the item that opened th context menu var _timeOutLimit = 3000; // How long the context menu stays for after the cursor in no longer over it var _timeOutTimer; // The timout for the context menu var _itemSelected = false; var _mouseOverContext = false; // If the mouse is over the context menu var _contextMenusIds; // The array of the diffrent context menus var _fadeTimeouts; // The array of timouts used for the fade effect var _onLink = false; // If the user is over a name link var _selectedItemId; var _tabFocusedItem = ''''; var _mouseOverItem = ''''; var _unselectedItemStyle; var _currentContextMenuId; // ID of currently displayed context menu var _currentMenuItemId = null; // ID of currently selected context menu item // Search bar var _searchTextBoxID; var _defaultSearchValue; // The value that the box defaults to. // start chris edit // new functions to find firstChild and lastChild but skipping whitespace elements function firstChildNoWS(element) { var child = element.firstChild; while (child != null && child.isElementContentWhitespace) { child = child.nextSibling; } return child; } function lastChildNoWS(element) { var child = element.lastChild; while (child != null && child.isElementContentWhitespace) { child = child.previousSibling; } return child; } // end chris edit function ToggleItem(itemId) { var item = document.getElementById(itemId); if (item.style.display == ''none'') item.style.display = ''inline''; else item.style.display = ''none''; } function ToggleButtonImage(image1ID, image2ID) { var image1 = document.getElementById(image1ID); var image2 = document.getElementById(image2ID); if (image1.style.display == ''none'') { image1.style.display = ''inline-block''; image2.style.display = ''none''; } else { image1.style.display = ''none''; image2.style.display = ''inline-block''; } } function SetFocus(id) { var obj = document.getElementById(id); if (obj != null && !obj.disabled) obj.focus(); } // Validates that an extension has been selected function ValidateDropDownSelection(source, args) { var obj = document.getElementById(source.controltovalidate); if (obj.options[0].selected && !obj.disabled) args.IsValid = false; else args.IsValid = true; } /// selectAll /// selects all the checkBoxes with the given id function selectAll() { var i; var id; var checked = checkBoxHead.checked; for (i = 0; i < checkBoxCount; i++) { id = checkBoxId + i; document.getElementById(id).checked = checked; } } /// onSglCheck /// performs actions when a single checkBox is checked or unchecked /// cb -> the checkBox generating the event /// topId -> id of the "select all" checkBox function onSglCheck() { // uncheck the top checkBox checkBoxHead.checked = false; } /// ToggleButton /// Toggle a buttons enable state function ToggleButton(id, disabled) { if (document.getElementById(id) != null) document.getElementById(id).disabled = disabled; } function ToggleValidator(id, enabled) { document.getElementById(id).enabled = enabled; } function SetCbVars(cbid, count, cbh) { checkBoxCount = count; checkBoxId = cbid; checkBoxHead = cbh; } /// Check to see if any check boxes should disable /// a control /// cbid -> id prefix of the checkBoxes /// cbCount -> total checkBoxes to check /// hidden -> input to look for /// display -> control to disable function CheckCheckBoxes(cbid, hidden, display) { var i; var id; var disable; disable = false; for (i = 0; i < checkBoxCount; i++) { id = cbid + i; if (document.getElementById(id).checked) { id = hidden + id; if (document.getElementById(id) != null) { disable = true; break; } } } ToggleButton(display, disable); } function HiddenCheckClickHandler(hiddenID, promptID, promptStringID) { var hiddenChk = document.getElementById(hiddenID); var promptChk = document.getElementById(promptID); // prompt should be in opposite state of hidden promptChk.checked = !hiddenChk.checked; } function validateSaveRole(source, args) { var i; var id; var c = 0; for (i = 0; i < checkBoxCount; i++) { id = checkBoxId + i; if (document.getElementById(id).checked) c++; } if (0 == c) args.IsValid = false; else args.IsValid = true; } /// Pad an integer less then 10 with a leading zero function PadIntWithZero(val) { var s = val.toString(); if (val < 10 && val >= 0) { if (s.length == 1) s = "0" + s; else if (s.length > 2) s = s.substring(s.length - 2, s.length); } return s; } /// Pad the contents of an input with leading zeros if necesarry function PadInputInteger(id) { document.getElementById(id).value = PadIntWithZero(document.getElementById(id).value); } /// text of confirmation popup when a single item is selected for deletion /// e.g. "Are you sure you want to delete this item" var confirmSingle; /// text of confirmation popup when multiple items are selected for deletion /// e.g. "Are you sure you want to delete these items" var confirmMultiple; function SetDeleteTxt(single, multiple) { confirmSingle = single; confirmMultiple = multiple; } /// doCmDel: DoConfirmDelete /// Given a number of checked items, confirm their deletion /// return true if OK was clicked; false otherwise function doCmDel(checkedCount) { var confirmTxt = confirmSingle; if (checkedCount == 0) return false; if (checkedCount > 1) confirmTxt = confirmMultiple; return confirm(confirmTxt); } /// on non-Netscape browsers, confirm deletion of 0 or more items function confirmDelete() { return doCmDel(getChkCount()); } /// confirm deletion of policies function confirmDeletePlcies(alertString) { var count = getChkCount(); if (count >= checkBoxCount) { alert(alertString); return false; } return doCmDel(count); } /// counts whether 0, 1, or more than 1 checkboxes are checked /// returns 0, 1, or 2 function getChkCount() { var checkedCount = 0; for (i = 0; i < checkBoxCount && checkedCount < 2; i++) { if (document.getElementById(checkBoxId + i).checked) { checkedCount++; } } return checkedCount; } function ToggleButtonBasedOnCheckBox(checkBoxId, toggleId, reverse) { var chkb = document.getElementById(checkBoxId); if (chkb != null) { if (chkb.checked == true) ToggleButton(toggleId, reverse); // enable if reverse == false else ToggleButton(toggleId, !reverse); // disable if reverse == false } } function ToggleButtonBasedOnCheckBoxWithOverride(checkBoxId, toggleId, overrideToDisabled, reverse) { if (overrideToDisabled == true) ToggleButton(toggleId, true); // disable else ToggleButtonBasedOnCheckBox(checkBoxId, toggleId, reverse); } function ToggleButtonBasedOnCheckBoxes(checkBoxId, checkboxId2, toggleId) { var chkb = document.getElementById(checkBoxId); if (chkb != null) { if (chkb.checked == true) ToggleButtonBasedOnCheckBox(checkboxId2, toggleId, false); else ToggleButton(toggleId, true); // disable } } function ToggleButtonBasedOnCheckBoxesWithOverride(checkBoxId, checkboxId2, toggleId, overrideToDisabled) { if (overrideToDisabled == true) ToggleButton(toggleId, true); // disable else ToggleButtonBasedOnCheckBoxes(checkBoxId, checkboxId2, toggleId); } function ToggleValidatorBasedOnCheckBoxWithOverride(checkBoxId, toggleId, overrideToDisabled, reverse) { if (overrideToDisabled == true) ToggleValidator(toggleId, false); else { var chkb = document.getElementById(checkBoxId); if (chkb != null) { ToggleValidator(toggleId, chkb.checked != reverse); } } } function ToggleValidatorBasedOnCheckBoxesWithOverride(checkBoxId, checkBoxId2, toggleId, overrideToDisabled, reverse) { if (overrideToDisabled == true) ToggleValidator(toggleId, false); else { var chkb = document.getElementById(checkBoxId); if (chkb != null) { if (chkb.checked == reverse) ToggleValidator(toggleId, false); else ToggleValidatorBasedOnCheckBoxWithOverride(checkBoxId2, toggleId, overrideToDisabled, reverse); } } } function CheckButton(buttonID, shouldCheck) { document.getElementById(buttonID).checked = shouldCheck; } function EnableMultiButtons(prefix) { // If there are no multibuttons, there is no reason to iterate the // list of checkboxes. if (checkBoxCount == 0 || multiButtonList.length == 0) return; var enableMultiButtons = false; var multipleCheckboxesSelected = false; // If the top level check box is checked, we know the state of all // of the checkboxes var headerCheckBox = document.getElementById(prefix + "ch"); if (headerCheckBox != null && headerCheckBox.checked) { enableMultiButtons = true; multipleCheckboxesSelected = checkBoxCount > 1; } else { // Look at each checkbox. If any one of them is checked, // enable the multi buttons. var foundOneChecked = false; var i; for (i = 0; i < checkBoxCount; i++) { var checkBox = document.getElementById(prefix + ''cb'' + i); if (checkBox.checked) { if (foundOneChecked) { multipleCheckboxesSelected = true; break; } else { enableMultiButtons = true; foundOneChecked = true; } } } } // Enable/disable each of the multi buttons var j; for (j = 0; j < multiButtonList.length; j++) { var button = document.getElementById(multiButtonList[j]); if (button.allowMultiSelect) button.disabled = !enableMultiButtons; else button.disabled = !enableMultiButtons || multipleCheckboxesSelected; } } //function ShadowCopyPassword(suffix) function MarkPasswordFieldChanged(suffix) { if (event.propertyName == "value") { var pwdField = document.getElementById("ui_txtStoredPwd" + suffix); //var shadowField = document.getElementById("ui_shadowPassword" + suffix); var shadowChanged = document.getElementById("ui_shadowPasswordChanged" + suffix); // Don''t shadow copy during initialization if (pwdField.IsInit) { //shadowField.value = pwdField.value; //pwdField.UserEnteredPassword = "true"; shadowChanged.value = "true"; // Update validator state (there is no validator on the data driven subscription page) var validator = document.getElementById("ui_validatorPassword" + suffix) if (validator != null) ValidatorValidate(validator); } } } function InitDataSourcePassword(suffix) { var pwdField = document.getElementById("ui_txtStoredPwd" + suffix); var shadowChanged = document.getElementById("ui_shadowPasswordChanged" + suffix); // var shadowField = document.getElementById("ui_shadowPassword" + suffix); var storedRadioButton = document.getElementById("ui_rdoStored" + suffix); var pwdValidator = document.getElementById("ui_validatorPassword" + suffix); pwdField.IsInit = false; // Initialize the field to the shadow value (for when the user clicks back/forward) // Or to a junk initial value. if (pwdValidator != null && storedRadioButton.checked) { /* if (shadowField.value.length > 0) pwdField.value = shadowField.value; else*/ pwdField.value = "********"; } else shadowChanged.value = "true"; // shadowChanged will be ignored if the page is submitted without storedRadioButton.checked // Now that the initial value is set, track changes to the password field pwdField.IsInit = true; // There is no validator on the data driven subscription page (no stored radio button either) if (pwdValidator != null) ValidatorValidate(pwdValidator); } function SetNeedPassword(suffix) { // Set a flag indicating that we need the password var pwdField = document.getElementById("ui_txtStoredPwd" + suffix); pwdField.NeedPassword = "true"; // Make the validator visible ValidatorValidate(document.getElementById("ui_validatorPassword" + suffix)); } function UpdateValidator(src, validatorID) { if (src.checked) { var validator = document.getElementById(validatorID); ValidatorValidate(validator); } } function ReEnterPasswordValidation(source, arguments) // source = validator { var validatorIdPrefix = "ui_validatorPassword" var suffix = source.id.substr(validatorIdPrefix.length, source.id.length - validatorIdPrefix.length); var storedRadioButton = document.getElementById("ui_rdoStored" + suffix); var pwdField = document.getElementById("ui_txtStoredPwd" + suffix); var shadowChanged = document.getElementById("ui_shadowPasswordChanged" + suffix); var customDataSourceRadioButton = document.getElementById("ui_rdoCustomDataSource" + suffix); var isCustomSelected = true; if (customDataSourceRadioButton != null) isCustomSelected = customDataSourceRadioButton.checked; if (!isCustomSelected || // If the custom (vs shared) data source radio button exists and is not selected, we don''t need the pwd. storedRadioButton.checked == false || // If the data source is not using stored credentials, we don''t need the password pwdField.UserEnteredPassword == "true" || // If the password has changed, we don''t need to get it from the user pwdField.NeedPassword != "true" || // If no credentials have changed, we don''t need the password shadowChanged.value == "true") // If the user has typed a password arguments.IsValid = true; else arguments.IsValid = false; } function ValidateDataSourceSelected(source, arguments) { var validatorIdPrefix = "ui_sharedDSSelectedValidator" var suffix = source.id.substr(validatorIdPrefix.length, source.id.length - validatorIdPrefix.length); var sharedRadioButton = document.getElementById("ui_rdoSharedDataSource" + suffix); var hiddenField = document.getElementById("ui_hiddenSharedDS" + suffix); arguments.IsValid = (sharedRadioButton != null && !sharedRadioButton.checked) || hiddenField.value != "NotSelected"; } /**************************************************************************/ // MultiValueParamClass function MultiValueParamClass(thisID, visibleTextBoxID, floatingEditorID, floatingIFrameID, paramObject, hasValidValues, allowBlank, doPostbackOnHide, postbackScript) { this.m_thisID = thisID; this.m_visibleTextBoxID = visibleTextBoxID; this.m_floatingEditorID = floatingEditorID; this.m_floatingIFrameID = floatingIFrameID; this.m_paramObject = paramObject; this.m_hasValidValues = hasValidValues; this.m_allowBlank = allowBlank; this.m_doPostbackOnHide = doPostbackOnHide; this.m_postbackScript = postbackScript; this.UpdateSummaryString(); } function ToggleVisibility() { var floatingEditor = GetControl(this.m_floatingEditorID); if (floatingEditor.style.display != "inline") this.Show(); else this.Hide(); } MultiValueParamClass.prototype.ToggleVisibility = ToggleVisibility; function Show() { var floatingEditor = GetControl(this.m_floatingEditorID); if (floatingEditor.style.display == "inline") return; // Set the correct size of the floating editor - no more than // 150 pixels high and no less than the width of the text box var visibleTextBox = GetControl(this.m_visibleTextBoxID); if (this.m_hasValidValues) { if (floatingEditor.offsetHeight > 150) floatingEditor.style.height = 150; floatingEditor.style.width = visibleTextBox.offsetWidth; } var newEditorPosition = this.GetNewFloatingEditorPosition(); floatingEditor.style.left = newEditorPosition.Left; floatingEditor.style.top = newEditorPosition.Top; floatingEditor.style.display = "inline"; var floatingIFrame = GetControl(this.m_floatingIFrameID); floatingIFrame.style.left = floatingEditor.style.left; floatingIFrame.style.top = floatingEditor.style.top; floatingIFrame.style.width = floatingEditor.offsetWidth; floatingIFrame.style.height = floatingEditor.offsetHeight; floatingIFrame.style.display = "inline"; // If another multi value is open, close it first if (this.m_paramObject.ActiveMultValue != this && this.m_paramObject.ActiveMultiValue != null) ControlClicked(this.m_paramObject.id); this.m_paramObject.ActiveMultiValue = this; if (floatingEditor.childNodes[0].focus) floatingEditor.childNodes[0].focus(); this.StartPolling(); } MultiValueParamClass.prototype.Show = Show; function Hide() { var floatingEditor = GetControl(this.m_floatingEditorID); var floatingIFrame = GetControl(this.m_floatingIFrameID); // Hide the editor floatingEditor.style.display = "none"; floatingIFrame.style.display = "none"; this.UpdateSummaryString(); if (this.m_doPostbackOnHide) eval(this.m_postbackScript); // Check that the reference is still us in case event ordering // caused another multivalue to click open if (this.m_paramObject.ActiveMultiValue == this) this.m_paramObject.ActiveMultiValue = null; } MultiValueParamClass.prototype.Hide = Hide; function GetNewFloatingEditorPosition() { // Make the editor visible var visibleTextBox = GetControl(this.m_visibleTextBoxID); var textBoxPosition = GetObjectPosition(visibleTextBox); return { Left: textBoxPosition.Left, Top: textBoxPosition.Top + visibleTextBox.offsetHeight }; } MultiValueParamClass.prototype.GetNewFloatingEditorPosition = GetNewFloatingEditorPosition; function UpdateSummaryString() { var summaryString; if (this.m_hasValidValues) summaryString = GetValueStringFromValidValueList(this.m_floatingEditorID); else summaryString = GetValueStringFromTextEditor(this.m_floatingEditorID, false, this.m_allowBlank); var visibleTextBox = GetControl(this.m_visibleTextBoxID); visibleTextBox.value = summaryString; } MultiValueParamClass.prototype.UpdateSummaryString = UpdateSummaryString; function StartPolling() { setTimeout(this.m_thisID + ".PollingCallback();", 100); } MultiValueParamClass.prototype.StartPolling = StartPolling; function PollingCallback() { // If the editor isn''t visible, no more events. var floatingEditor = GetControl(this.m_floatingEditorID); if (floatingEditor.style.display != "inline") return; // If the text box moved, something on the page resized, so close the editor var expectedEditorPos = this.GetNewFloatingEditorPosition(); if (floatingEditor.style.left != expectedEditorPos.Left + "px" || floatingEditor.style.top != expectedEditorPos.Top + "px") { this.Hide(); } else { this.StartPolling(); } } MultiValueParamClass.prototype.PollingCallback = PollingCallback; /*****************************************************************************/ function GetObjectPosition(obj) { var totalTop = 0; var totalLeft = 0; while (obj != document.body) { // Add up the position totalTop += obj.offsetTop; totalLeft += obj.offsetLeft; // Prepare for next iteration obj = obj.offsetParent; } totalTop += obj.offsetTop; totalLeft += obj.offsetLeft; return { Left: totalLeft, Top: totalTop }; } function GetValueStringFromTextEditor(floatingEditorID, asRaw, allowBlank) { var span = GetControl(floatingEditorID); var editor = span.childNodes[0]; var valueString = editor.value; // Remove the blanks if (!allowBlank) { // Break down the text box string to the individual lines var valueArray = valueString.split("/r/n"); var delimiter; if (asRaw) delimiter = "/r/n"; else delimiter = ", "; var finalValue = ""; for (var i = 0; i < valueArray.length; i++) { // If the string is non-blank, add it if (valueArray[i].length > 0) { if (finalValue.length > 0) finalValue += delimiter; finalValue += valueArray[i]; } } return finalValue; } else { if (asRaw) return valueString; else return valueString.replace(//r/n/g, ", "); } } function GetValueStringFromValidValueList(editorID) { var valueString = ""; // Get the table var div = GetControl(editorID); var table = div.childNodes[0]; if (table.nodeName != "TABLE") // Skip whitespace if needed table = div.childNodes[1]; // If there is only one element, it is a real value, not the select all option var startIndex = 0; if (table.rows.length > 1) startIndex = 1; for (var i = startIndex; i < table.rows.length; i++) { // Get the first cell of the row var firstCell = table.rows[i].cells[0]; var span = firstCell.childNodes[0]; var checkBox = span.childNodes[0]; var label = span.childNodes[1]; if (checkBox.checked) { if (valueString.length > 0) valueString += ", "; // chris edit - valueString += label.firstChild.nodeValue; valueString += firstChildNoWS(label).nodeValue; } } return valueString; } function MultiValidValuesSelectAll(src, editorID) { // Get the table var div = GetControl(editorID); var table = div.childNodes[0]; if (table.nodeName != "TABLE") table = div.childNodes[1]; for (var i = 1; i < table.rows.length; i++) { // Get the first cell of the row var firstCell = table.rows[i].cells[0]; var span = firstCell.childNodes[0]; var checkBox = span.childNodes[0]; checkBox.checked = src.checked; } } function ValidateMultiValidValue(editorID, errMsg) { var summaryString = GetValueStringFromValidValueList(editorID); var isValid = summaryString.length > 0; if (!isValid) alert(errMsg) return isValid; } function ValidateMultiEditValue(editorID, errMsg) { // Need to check for a value specified. This code only runs if not allow blank. // GetValueStringFromTextEditor filters out blank strings. So if it was all blank, // the final string will be length 0 var summaryString = GetValueStringFromTextEditor(editorID, true, false) var isValid = false; if (summaryString.length > 0) isValid = true; if (!isValid) alert(errMsg); return isValid; } function GetControl(controlID) { var control = document.getElementById(controlID); if (control == null) alert("Unable to locate control: " + controlID); return control; } function ControlClicked(formID) { var form = GetControl(formID); if (form.ActiveMultiValue != null) form.ActiveMultiValue.Hide(); }

He estado depurando el archivo ReportingServices.js usando Firefox y Firebug. Descubrí que el motivo por el que el Administrador de informes SSRS (SQL Server Reporting Services) (interfaz web para informes) no funciona en Firefox (v7.0.1) es que usa javascript .lastChild para buscar elementos. Desafortunadamente, Firefox también retoma los espacios en blanco como elementos TextNode que hace que la selección de elementos no funcione como se esperaba.

Esto funciona en IE y es de esperar que alguien sepa una solución para esto. Edité el javascript para solucionar un error, pero luego llegué a otro más complicado, probablemente un campo de minas para intentar arreglarlo manualmente. Con suerte, hay alguna actualización o parche disponible.

Se está ejecutando la edición estándar de SQL Server 2008 R2 en un servidor de Windows 2008 R2 Datacenter.

Disculpas si sientes que este no es el foro para esa pregunta. En ese caso, sugiera dónde más debo hacer la pregunta si no es apropiado. Es similar a un problema de javascript pero probablemente con una solución de actualización de software.

Actualizado:

Después de unas horas de corregir los errores de compatibilidad del navegador en el archivo ReportingServices.js logré que funcionara en Firefox, Chrome, Opera y Safari, así como en IE. Lamento que mi respuesta a continuación sea en 2 partes; Publiqué el código completo de ReportingServices.js actualizado para la solución.


Parte 2 de ReportingServices.js actualizado de mi respuesta:

// --- Context Menu --- // This function is called in the onload event of the body. // It hooks the context menus up to the Javascript code. // divContextMenuId, is the id of the div that contains the context menus // selectedIdHiddenFieldId, is the id of the field used to post back the name of the item clicked // contextMenusIds, is an array of the ids of the context menus // searchTextBox ID, is the id of the search box // defaultSearchValue. the value the search box has by default function InitContextMenu(divContextMenuId, selectedIdHiddenFieldId, contextMenusIds, searchTextBoxID, defaultSearchValue ) { ResetSearchBar( searchTextBoxID, defaultSearchValue ); _divContextMenu = document.getElementById(divContextMenuId); _selectedIdHiddenField = document.getElementById(selectedIdHiddenFieldId); _contextMenusIds = contextMenusIds; _divContextMenu.onmouseover = function() { _mouseOverContext = true; }; _divContextMenu.onmouseout = function() { if (_mouseOverContext == true) { _mouseOverContext = false; if (_timeOutTimer == null) { _timeOutTimer = setTimeout(TimeOutAction, _timeOutLimit); } } }; document.body.onmousedown = ContextMouseDown; AddKeyDownListener(); } // This handler stops bubling when arrow keys Up or Down pressed to prevent scrolling window function KeyDownHandler(e) { // Cancel window scrolling only when menu is opened if(_currentContextMenuId == null) { return true; } if(!e) { e = window.event; } var key = e.keyCode; if(key == 38 || key == 40) { return false; } else { return true; } } function AddKeyDownListener() { if(document.addEventListener) { document.addEventListener(''keydown'', KeyDownHandler, false); } else { document.onkeydown = KeyDownHandler; } } // This function starts the context menu timeout process function TimeOutAction() { if (_mouseOverContext == false) { UnSelectedMenuItem() } _timeOutTimer = null; } // This function is called when a name tag is clicked, it displays the contextmenu for a given item. function Clicked(event, contextMenuId) { if (!_onLink) { ClearTimeouts(); SelectContextMenuFromColletion(contextMenuId); _itemSelected = true; // **Cross browser compatibility code** // Some browsers will not pass the event so we need to get it from the window instead. if (event == null) event = window.event; var selectedElement = event.target != null ? event.target : event.srcElement; var outerTableElement = GetOuterElementOfType(selectedElement, ''table''); var elementPosition = GetElementPosition(outerTableElement); _selectedItemId = outerTableElement.id; // chris edit - _selectedIdHiddenField.value = outerTableElement.value; _selectedIdHiddenField.value = outerTableElement.attributes["value"].value; outerTableElement.className = "msrs-SelectedItem"; ResetContextMenu(); var contextMenuHeight = _divContextMenu.offsetHeight; var contextMenuWidth = _divContextMenu.offsetWidth; var boxHeight = outerTableElement.offsetHeight; var boxWidth = outerTableElement.offsetWidth; var boxXcoordinate = elementPosition.left; var boxYcooridnate = elementPosition.top; var pageWidth = 0, pageHeight = 0; // **Cross browser compatibility code** if (typeof (window.innerWidth) == ''number'') { //Non-IE pageWidth = window.innerWidth; pageHeight = window.innerHeight; } else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) { //IE 6+ in ''standards compliant mode'' pageWidth = document.documentElement.clientWidth; pageHeight = document.documentElement.clientHeight; } else if (document.body && (document.body.clientWidth || document.body.clientHeight)) { //IE 4 compatible pageWidth = document.body.clientWidth; pageHeight = document.body.clientHeight; } // **Cross browser compatibility code** var iebody = (document.compatMode && document.compatMode != "BackCompat") ? document.documentElement : document.body var pageXOffSet = document.all ? iebody.scrollLeft : pageXOffset var pageYOffSet = document.all ? iebody.scrollTop : pageYOffset _divContextMenu.style.left = SetContextMenuHorizonatalPosition(pageWidth, pageXOffSet, boxXcoordinate, contextMenuWidth, boxWidth) + ''px''; _divContextMenu.style.top = SetContextMenuVerticalPosition(pageHeight, pageYOffSet, boxYcooridnate, contextMenuHeight, boxHeight) + ''px''; ChangeOpacityForElement(100, _divContextMenu.id); // chris edit - document.getElementById(_currentContextMenuId).firstChild.focus(); firstChildNoWS(document.getElementById(_currentContextMenuId)).focus(); } } // *********************************** // Context menu keyboard navigation // *********************************** // Opens context menu via keyboard. Context menu // is opened by selecting an item and pressing // Alt + Down. function OpenMenuKeyPress(e, contextMenuId) { // Alt key was pressed if (e.altKey) { var keyCode; if (window.event) keyCode = e.keyCode; else keyCode = e.which; // Down key was pressed if (keyCode == 40) { // Open context menu. Clicked(event, contextMenuId); // Highlight the first selectable item // in the context menu. HighlightContextMenuItem(true); } } } // Performs keyboard navigation within // opened context menu. function NavigateMenuKeyPress(e) { var keyCode; if (window.event) keyCode = e.keyCode; else keyCode = e.which; // Down key moves down to the next context menu item if (keyCode == 40) { HighlightContextMenuItem(true); } // Up key moves up to the previous context menu item else if (keyCode == 38) { HighlightContextMenuItem(false); } // Escape key closes context menu else if (keyCode == 27) { // Close context menu UnSelectedMenuItem(); // Make sure focus is given to the catalog item // in the folder view. document.getElementById(_selectedItemId).focus(); } } // Highlights context menu item. // Parameter: highlightNext // - If true, highlights menu item below current menu item. // If current menu item is the last item, wraps around and // highlights first menu item. // - If false, highlights menu item above current menu item. // If current menu item is the first item, wraps around and // highlights last menu item. function HighlightContextMenuItem(highlightNext) { var contextMenu = document.getElementById(_currentContextMenuId); // chris edit - var table = contextMenu.lastChild; var table = lastChildNoWS(contextMenu); var currentMenuItemIndex = -1; if (_currentMenuItemId != null) currentMenuItemIndex = document.getElementById(_currentMenuItemId).parentNode.rowIndex; var index = currentMenuItemIndex; while (true) { if (highlightNext) { index++; // If the index is out of range, // reset it to the beginning if (index < 0 || index >= table.cells.length) index = 0; } else { index--; // If the index is out of range, // reset it to the end if (index < 0 || index >= table.cells.length) index = table.cells.length - 1; } // Each context menu item has an associated // group ID. Make sure the table cell has a valid // group ID, otherwise it is not a menu item (e.g. // an underline separator). if (table.cells[index].group >= 0) { FocusContextMenuItem(table.cells[index].id, ''msrs-MenuUIItemTableHover'', ''msrs-MenuUIItemTableCell''); break; } // If we reach the orignal index, that means we looped // through all table cells and did not find a valid context // menu item. In that case, stop searching. if (index == currentMenuItemIndex) break; } } // *** End keyboard navigation *** // This function resets the context menus shape and size. function ResetContextMenu() { _divContextMenu.style.height = ''auto''; _divContextMenu.style.width = ''auto''; _divContextMenu.style.overflowY = ''visible''; _divContextMenu.style.overflowX = ''visible''; _divContextMenu.style.overflow = ''visible''; _divContextMenu.style.display = ''block''; } // This function sets the horizontal position of the context menu. // It also sets is the context menu has vertical scroll bars. function SetContextMenuHorizonatalPosition(pageWidth, pageXOffSet, boxXcoordinate, contextMenuWidth, boxWidth) { var menuXCoordinate = boxXcoordinate + boxWidth - contextMenuWidth; var spaceRightBox = (pageWidth + pageXOffSet) - menuXCoordinate; var spaceLeftBox = menuXCoordinate - pageXOffSet; var returnValue; if ((contextMenuWidth < spaceRightBox) && (pageXOffSet < menuXCoordinate)) { returnValue = menuXCoordinate; } else if ((contextMenuWidth < spaceRightBox)) { returnValue = pageXOffSet; } else if (contextMenuWidth < spaceLeftBox) { returnValue = menuXCoordinate - (contextMenuWidth - (pageWidth + pageXOffSet - menuXCoordinate)); } else { _divContextMenu.style.overflowX = "scroll"; if (spaceLeftBox < spaceRightBox) { _divContextMenu.style.width = spaceRightBox; returnValue = pageXOffSet; } else { _divContextMenu.style.width = spaceLeftBox; returnValue = menuXCoordinate - (spaceLeftBox - (pageWidth + pageXOffSet - menuXCoordinate)); } } return returnValue; } // This function sets the vertical position of the context menu. // It also sets is the context menu has horizontal scroll bars. function SetContextMenuVerticalPosition(pageHeight, pageYOffSet, boxYcooridnate, contextMenuHeight, boxHeight) { var spaceBelowBox = (pageHeight + pageYOffSet) - (boxYcooridnate + boxHeight); var spaceAboveBox = boxYcooridnate - pageYOffSet; var returnValue; if (contextMenuHeight < spaceBelowBox) { returnValue = (boxYcooridnate + boxHeight); } else if (contextMenuHeight < spaceAboveBox) { returnValue = (boxYcooridnate - contextMenuHeight); } else if (spaceBelowBox > spaceAboveBox) { _divContextMenu.style.height = spaceBelowBox; _divContextMenu.style.overflowY = "scroll"; returnValue = (boxYcooridnate + boxHeight); } else { _divContextMenu.style.height = spaceAboveBox; _divContextMenu.style.overflowY = "scroll"; returnValue = (boxYcooridnate - spaceAboveBox); } return returnValue; } // This function displays a context menu given its id and then hides the others function SelectContextMenuFromColletion(contextMenuConfigString) { var contextMenuId = SplitContextMenuConfigString(contextMenuConfigString); for (i = 0; i < _contextMenusIds.length; i++) { var cm = document.getElementById(_contextMenusIds[i]); if (cm.id == contextMenuId) { cm.style.visibility = ''visible''; cm.style.display = ''block''; _currentContextMenuId = contextMenuId; } else { cm.style.visibility = ''hidden''; cm.style.display = ''none''; } } } function SplitContextMenuConfigString(contextMenuConfigString) { var contextMenuEnd = contextMenuConfigString.indexOf(":"); var contextMenuId = contextMenuConfigString; var contextMenuHiddenItems; if (contextMenuEnd != -1) { contextMenuId = contextMenuConfigString.substr(0, contextMenuEnd); } var cm = document.getElementById(contextMenuId); // chris edit - var table = cm.firstChild; var table = firstChildNoWS(cm); var groupItemCount = []; // The items in each group var groupUnderlineId = []; // The Id''s of the underlines. // Enable all menu items counting the number of groups, // number of items in the groups and underlines for the groups as we go. // start chris edit /* for (i = 0; i < table.cells.length; i++) { table.cells[i].style.visibility = ''visible''; table.cells[i].style.display = ''block'' if ((groupItemCount.length - 1) < table.cells[i].group) { groupItemCount.push(1); groupUnderlineId.push(table.cells[i].underline); } else { groupItemCount[table.cells[i].group]++; } AlterVisibilityOfAssociatedUnderline(table.cells[i], true) }*/ if (table != null && table.rows != null) { for (r = 0; r < table.rows.length; r++) { for (i = 0; i < table.rows[r].cells.length; i++) { table.rows[r].cells[i].style.visibility = ''visible''; table.rows[r].cells[i].style.display = ''block'' if ((groupItemCount.length - 1) < table.rows[r].cells[i].group) { groupItemCount.push(1); groupUnderlineId.push(table.rows[r].cells[i].underline); } else { groupItemCount[table.rows[r].cells[i].group]++; } AlterVisibilityOfAssociatedUnderline(table.rows[r].cells[i], true) } } } // end chris edit // If hidden items are listed, remove them from the context menu if (contextMenuEnd != -1) { contextMenuHiddenItems = contextMenuConfigString.substr((contextMenuEnd + 1), (contextMenuConfigString.length - 1)).split("-"); var groupsToHide = groupItemCount; // Hide the hidden items for (i = 0; i < contextMenuHiddenItems.length; i++) { var item = document.getElementById(contextMenuHiddenItems[i]); item.style.visibility = ''hidden''; item.style.display = ''none'' groupsToHide[item.group]--; } var allHidden = true; // Work back through the groups hiding the underlines as required. for (i = (groupsToHide.length - 1); i > -1; i--) { if (groupsToHide[i] == 0) { AlterVisibilityOfAssociatedUnderline(groupUnderlineId[i], false); } else if (allHidden && i == (groupsToHide.length - 1)) { allHidden = false; } // If all the items have been hidden so far hide the last underline too. else if (allHidden) { allHidden = false; AlterVisibilityOfAssociatedUnderline(groupUnderlineId[i], false); } } } return contextMenuId; } function AlterVisibilityOfAssociatedUnderline(underLineId, visibility) { if (underLineId != null && underLineId != "") { var underlineElement = document.getElementById(underLineId); if (underlineElement != null) { if (visibility) { underlineElement.style.visibility = ''visible''; underlineElement.style.display = ''block'' } else { underlineElement.style.visibility = ''hidden''; underlineElement.style.display = ''none'' } } } } function ClearTimeouts() { if (_fadeTimeouts != null) { for (i = 0; i < _fadeTimeouts.length; i++) { clearTimeout(_fadeTimeouts[i]); } } _fadeTimeouts = []; } // This function chnages an elements opacity given its id. function FadeOutElement(id, opacStart, opacEnd, millisec) { ClearTimeouts(); //speed for each frame var speed = Math.round(millisec / 100); var timer = 0; for (i = opacStart; i >= opacEnd; i--) { _fadeTimeouts.push(setTimeout("ChangeOpacityForElement(" + i + ",''" + id + "'')", (timer * speed))); timer++; } } // This function changes the opacity of an elemnent given it''s id. // Works across browsers for different browsers function ChangeOpacityForElement(opacity, id) { var object = document.getElementById(id).style; if (opacity != 0) { // **Cross browser compatibility code** object.opacity = (opacity / 100); object.MozOpacity = (opacity / 100); object.KhtmlOpacity = (opacity / 100); object.filter = "alpha(opacity=" + opacity + ")"; } else { object.display = ''none''; } } // This function is the click for the body of the document function ContextMouseDown() { if (_mouseOverContext) { return; } else { HideMenu() } } // This function fades out the context menu and then unselects the associated name control function UnSelectedMenuItem() { if (_itemSelected) { FadeOutElement(_divContextMenu.id, 100, 0, 300); UnselectCurrentMenuItem(); } } // Hides context menu without fading effect function HideMenu() { if (_itemSelected) { ChangeOpacityForElement(0, _divContextMenu.id); UnselectCurrentMenuItem(); } } function UnselectCurrentMenuItem() { _itemSelected = false; _currentContextMenuId = null; SwapStyle(_currentMenuItemId, ''msrs-MenuUIItemTableCell''); _currentMenuItemId = null; ChangeReportItemStyle(_selectedItemId, "msrs-UnSelectedItem"); } // This function walks back up the DOM tree until it finds the first occurrence // of a given element. It then returns this element function GetOuterElementOfType(element, type) { while (element.tagName.toLowerCase() != type) { element = element.parentNode; } return element; } // This function gets the corrdinates of the top left corner of a given element function GetElementPosition(element) { element = GetOuterElementOfType(element, ''table''); var left, top; left = top = 0; if (element.offsetParent) { do { left += element.offsetLeft; top += element.offsetTop; } while (element = element.offsetParent); } return { left: left, top: top }; } function FocusContextMenuItem(menuItemId, focusStyle, blurStyle) { SwapStyle(_currentMenuItemId, blurStyle); SwapStyle(menuItemId, focusStyle); // chrid edit - document.getElementById(menuItemId).firstChild.focus(); firstChildNoWS(document.getElementById(menuItemId)).focus(); _currentMenuItemId = menuItemId; } // This function swaps the style using the id of a given element function SwapStyle(id, style) { if (document.getElementById) { var selectedElement = document.getElementById(id); if (selectedElement != null) { selectedElement.className = style; } } } // This function changes the style using the id of a given element // and should only be called for catalog items in the tile or details view function ChangeReportItemStyle(id, style) { if (!_itemSelected) { if (document.getElementById) { var selectedElement = document.getElementById(id); selectedElement.className = style; // Change the style on the end cell by drilling into the table. if (selectedElement.tagName.toLowerCase() == "table") { // chris edit - var tbody = selectedElement.lastChild; var tbody = lastChildNoWS(selectedElement); if (tbody != null) { // chris edit - var tr = tbody.lastChild; var tr = lastChildNoWS(tbody); if (tr != null) { // chris edit - tr.lastChild.className = style + ''End''; trLastChild = lastChildNoWS(tr); if (trLastChild != null) { trLastChild.className = style + ''End''; } } } } } } } function ChangeReportItemStyleOnFocus(id, currentStyle, unselectedStyle) { _unselectedItemStyle = unselectedStyle; _tabFocusedItem = id; // We should unselect selected by mouse over item if there is one if(_mouseOverItem != '''') { ChangeReportItemStyle(_mouseOverItem, _unselectedItemStyle); _mouseOverItem = ''''; } ChangeReportItemStyle(id, currentStyle); } function ChangeReportItemStyleOnBlur(id, style) { ChangeReportItemStyle(id, style); _tabFocusedItem = ''''; } function ChangeReportItemStyleOnMouseOver(id, currentStyle, unselectedStyle) { _unselectedItemStyle = unselectedStyle; _mouseOverItem = id; // We should unselect tabbed item if there is one if(_tabFocusedItem != '''') { ChangeReportItemStyle(_tabFocusedItem, _unselectedItemStyle); _tabFocusedItem = ''''; } ChangeReportItemStyle(id, currentStyle); } function ChangeReportItemStyleOnMouseOut(id, style) { ChangeReportItemStyle(id, style); _mouseOverItem = ''''; } // This function is used to set the style of the search bar on the onclick event. function SearchBarClicked(id, defaultText, style) { var selectedElement = document.getElementById(id); if (selectedElement.value == defaultText) { selectedElement.value = ""; selectedElement.className = style; } } // This function is used to set the style of the search bar on the onblur event. function SearchBarBlured(id, defaultText, style) { var selectedElement = document.getElementById(id); if (selectedElement.value == "") { selectedElement.value = defaultText; selectedElement.className = style; } } function ResetSearchBar(searchTextBoxID,defaultSearchValue) { var selectedElement = document.getElementById(searchTextBoxID); if (selectedElement != null) { if (selectedElement.value == defaultSearchValue) { selectedElement.className = ''msrs-searchDefaultFont''; } else { selectedElement.className = ''msrs-searchBarNoBorder''; } } } function OnLink() { _onLink = true; } function OffLink() { _onLink = false; } function ShouldDelete(confirmMessage) { if (_selectedIdHiddenField.value != null || _selectedIdHiddenField.value != "") { var message = confirmMessage.replace("{0}", _selectedIdHiddenField.value); var result = confirm(message); if (result == true) { return true; } else { return false; } } else { return false; } } function UpdateValidationButtonState(promptCredsRdoBtnId, typesDropDownId, forbiddenTypesConfigString, validateButtonId) { var dropdown = document.getElementById(typesDropDownId); if(dropdown == null) { return; } var selectedValue = dropdown.options[dropdown.selectedIndex].value; var forbiddenTypes = forbiddenTypesConfigString.split(":"); var chosenForbiddenType = false; for (i = 0; i < forbiddenTypes.length; i++) { if(forbiddenTypes[i] == selectedValue) { chosenForbiddenType = true; } } var isDisabled = chosenForbiddenType || IsRadioButtonChecked(promptCredsRdoBtnId); ChangeDisabledButtonState(validateButtonId, isDisabled); } function ChangeDisabledButtonState(buttonId, isDisabled) { var button = document.getElementById(buttonId); if(button != null) { button.disabled = isDisabled; } } function IsRadioButtonChecked(radioButtonId) { var rbtn = document.getElementById(radioButtonId); if(rbtn != null && rbtn.checked) { return true; } return false; }