/* * Name: * rss_toggle.js * * Description: * Defines functions for the RSS Toggle box. * * Libraries: * event_handler.js * html_element_search.js * * Pre-conditions: * None * * Post-conditions: * Defines the following functions: * - shortenString Shorten a string if necessary, optionally adding an ellipsis. * - createToggleElements Create UI toggler elements for toggling individual RSS feeds. * * Log: * Randall Betta 08/24/2006 * - Creation * Randall Betta 11/06/2006 * - Fixed a bug in the createToggleElements function involving the back button under IE. * */ /* * Name: * shortenString * * Description: * Truncates a string, optionally suffixing an ellipsis ("..."). * * Preconditions: * This function takes the following arguments: * - strText : REQUIRED The string to potentially truncate. * - strLength : REQUIRED The number of characters of the returned string. * - ellipsis : REQUIRED If true and strLength > 3, suffix an ellipsis ("..."). Removes three extra chars from the string. * * Postconditions: * The truncated string is returned, optionally with an ellipsis. The ellipsis is only added * if truncation was necessary. * * Log: * Randall Betta 08/28/2006 * - Creation * */ function shortenString(strText, strLength, ellipsis) { var currentLength; currentLength = strText.length; if (currentLength > strLength) { // If: the string needs shortening. if (ellipsis && strLength > 3) { // If: an ellipsis is desired and the new length will be > 3 chars. strLength -= 3; strText = strText.substring(0, strLength) + '...'; } else { // Else: an ellipsis is not desired, or the string is less than 3 characters. strText = strText.substring(0, strLength); } // End else: an ellipsis is not desired, or the string is less than 3 characters. } // End if: The string needs shortening. return strText; } // End function: shortenString. /* * Name: * createToggleElements * * Description: * Dynamically creates a reference to an HTML DOM element that contains controls to hide or show * the individual RSS feeds in any External RSS boxes on the page. * * Pre-conditions: * masterElt REQUIRED A reference to the div tag to put the individual RSS feed togglers into. * stylePrefix REQUIRED The prefix to prepend to CSS class names, if any. * maxLabelChars REQUIRED The maximum number of characters per feed toggling label. Zero = unlimited. * * Post-conditions: * Returns a reference to the new HTML element hierarchy that contains controls for RSS feed visibility. * * Log: * Randall Betta 08/24/2006 * - Creation * Randall Betta 11/06/2006 * - Fixed a bug where Internet Explorer would mangle the HTML if the back button was * used, due to a missing float-clearing element. Bad IE! No biscuit for you! * */ function createToggleElements(masterElt, stylePrefix, maxLabelChars) { var idRegex; var elts; var eltCount; var eltIndex; var currentElt; var feedData; var externalRssId; var idParts; var eltArray; var divIndex; var toggleTab; var toggleTabName; var newNode; var funcCode; var funcCodeIter; var eltsToCheck; var checkboxElt; // CSS demands a float-clearing element both before and after the toggler tabs; otherwise, the tabs // do not exist in the same layout flow. This manifests as a peculiar rendering error on Internet // explorer 6 when the back button is used. Create the initial float-clearing element here: newNode = document.createElement('div'); newNode.style.height = '1px'; newNode.style.overflow = 'hidden'; newNode.style.clear = 'both'; newNode.appendChild(document.createTextNode(' ')); masterElt.appendChild(newNode); // Initialize the array of HTML checkbox elements that need to be checked. eltsToCheck = new Array(); // The HTML property of every toggleable div has the following parts, delimited by hyphens: // 1: "RssToggleDiv" // 2: URL-encoded RSS feed name, with all percent signs replaced with underscores. // 3: stnBoxId -- may have an underscore if it is in a boxgroup. // 4: externalRssId // 5: zero-indexed incrementing count of headlines in the current feed. // 6: one-index incrementing count of visiblity-toggleable elements in this headline. idRegex = 'RssToggleDiv[-]([^-])*[-]([0-9_])+[-]([0-9])+[-]([0-9])+[-]([0-9])+'; // Obtain all divs on all accessible (i)frames and this page. This is case-sensitive. elts = getRelatedElements('table', idRegex, true, true); // // Create a two-dimensional array: the first dimension will be the unique externalRssId values // of the feeds on the page. The second array will be the elements that need to be toggled when // the RSS feeds with that externalRssId are toggled visible or invisible. // // Initialize the two-dimensional array of externalRssId to hidable div mappings. feedData = new Array(); // Iterate through the elements that will require visibility toggling. eltCount = elts.length; for (eltIndex = 0; eltIndex < eltCount; eltIndex++) { // For: iterate through elements requiring hiding. try { // Store the current element in this iteration. currentElt = elts[eltIndex]; // Break the element's HTML ID property into its hyphen-delimited pieces. idParts = currentElt.id.split('-'); // The externalRssId is stored in element number 3 (it's zero-indexed). externalRssId = idParts[3]; // Create a first-dimensional index for this externalRssId if one doesn't exist in the data array. feedData[externalRssId] = (feedData[externalRssId]) ? feedData[externalRssId] : new Array(); // Insert this HTML element into the next element of the array's second dimension. eltArray = feedData[externalRssId]; eltArray[eltArray.length] = currentElt; } catch (exc) { // Silently fail if a domain-security restriction prevents accessing the current element. continue; } } // End for: iterate throughy elements requiring hiding. // Iterate through the array of ExternalRssId values, creating a visibility toggler for each feed. for (externalRssId in feedData) { // For: iterate through externalRssIds in feedData. // This method of array iteration will enumerate properties, so skip any that are found. if (!(('' + externalRssId).match(/^[0-9]+$/))) { // If: externalRssId is not a positive integer. // This element of the array is actually a property of the Array object. Skip it. continue; } // End if: externalRssId is not a positive integer. // Store the HTML elements associated with this feed (they are the array's second dimension). // Note that this lign reinitializes the previously-declared elts array. elts = feedData[externalRssId]; // Store the name of this RSS feed, grabbing it from the first visibility-toggleable element's ID. idParts = elts[0].id.split('-'); // The name is URL encoded in the second hyphen-delimited part of the ID, with percent signs // replaced with underscores and guaranteed to have no plus signs. toggleTabName = ('' + idParts[1]).replace(/[_]/, '%'); toggleTabName = unescape(toggleTabName); // // Begin constructing a new toggle control for this individual RSS feed. // // Create the surrounding div for the toggle tab. toggleTab = document.createElement('div'); toggleTab.className = stylePrefix + 'Tab'; // Create the checkbox for toggling visibility of this feed. newNode = document.createElement('input'); newNode.setAttribute('type', 'checkbox'); // Dynamically create the code inside the following anonymous function, allowing it // to show or hide the visibility of all elements that require visibility toggling // for this RSS feed. eltCount = elts.length; funcCode = 'var elt;\r\n'; funcCode += 'var docsArray;\r\n'; funcCode += 'var frameIndex;\r\n'; funcCode += 'var docIndex;\r\n'; funcCode += 'var thisDoc;\r\n'; funcCode += 'var framesArray;\r\n\r\n'; funcCode += '// Obtain all documents in the window (frame) hierarchy.\r\n'; funcCode += 'docsArray = new Array();\r\n'; funcCode += 'try {\r\n'; funcCode += '\tframesArray = getAllFrames(window);\r\n'; funcCode += '\tfor (frameIndex = 0; frameIndex < framesArray.length; frameIndex++) {\r\n'; funcCode += '\t\ttry {\r\n'; funcCode += '\t\t\tdocsArray[frameIndex] = framesArray[frameIndex].document;\r\n'; funcCode += '\t\t} catch (exc) {;}\r\n'; funcCode += '\t}\r\n'; funcCode += '}\r\n'; funcCode += 'catch (exc) {};\r\n'; for (eltIndex = 0; eltIndex < eltCount; eltIndex++) { // For: iterate through all toggleable HTML elements. funcCodeIter = ''; try { funcCodeIter += '// Try to find each toggleable element in all the available documents.\r\n'; funcCodeIter += 'for (docIndex = 0; docIndex < docsArray.length; docIndex++) {\r\n'; funcCodeIter += '\ttry {\r\n'; funcCodeIter += '\t\tthisDoc = docsArray[docIndex];\r\n'; funcCodeIter += "\t\telt = thisDoc.getElementById('" + elts[eltIndex].id + "');\r\n"; funcCodeIter += "\t\telt.style.display = (elt.style.display == 'none') ? 'block' : 'none';\r\n"; funcCodeIter += '\t}\r\n'; funcCodeIter += '\tcatch (exc) { ; /* Silently fail on an error.*/ }\r\n'; funcCodeIter += '}\r\n'; funcCode += funcCodeIter; } catch (exc) { // Do not append the code for this element if this element cannot be accessed (i.e. if // the attempt to access the id property fails due to a domain security restriction). continue; } } // End for: iterate through all toggleable HTML elements. funcCode += "return;"; // Register a handler function for the click event that will show or hide the appropriate HTML elements. registerEvent(newNode, 'click', new Function('', funcCode)); // Append this RSS feed's toggle-controlling checkbox to its containing div. toggleTab.appendChild(newNode); // Record this checkbox element as requiring checking. eltsToCheck[eltsToCheck.length] = newNode; // Append the name of this RSS feed to the containing div. toggleTab.appendChild(document.createTextNode(' ' + shortenString(toggleTabName, maxLabelChars, true))); // Append this completed RSS feed toggler to the master containing HTML element. masterElt.appendChild(toggleTab); } // End for: iterate through externalRssIds in feedData. // Check all elements requiring it. This is done here to appease Internet Explorer, which is finicky // about this property. for (eltIndex = 0; eltIndex < eltsToCheck.length; eltIndex++) { // For: elements requiring checking. checkboxElt = eltsToCheck[eltIndex]; checkboxElt.checked = true; } // End for: elements requiring checking. // CSS demands a float-clearing element both before and after the toggler tabs; otherwise, the tabs // do not exist in the same layout flow. This manifests as a peculiar rendering error on Internet // explorer 6 when the back button is used. Create the final float-clearing element here: newNode = document.createElement('div'); newNode.style.height = '1px'; newNode.style.overflow = 'hidden'; newNode.style.clear = 'both'; newNode.appendChild(document.createTextNode(' ')); masterElt.appendChild(newNode); } // End function: createToggleElements