//=============================================================================================================== // System : Sandcastle Help File Builder // File : branding.js // Author : Eric Woodruff (Eric@EWoodruff.us) // Updated : 10/08/2015 // Note : Copyright 2014-2015, Eric Woodruff, All rights reserved // Portions Copyright 2010-2014 Microsoft, All rights reserved // // This file contains the methods necessary to implement the language filtering, collapsible section, and // copy to clipboard options. // // This code is published under the Microsoft Public License (Ms-PL). A copy of the license should be // distributed with the code and can be found at the project website: https://GitHub.com/EWSoftware/SHFB. This // notice, the author's name, and all copyright notices must remain intact in all applications, documentation, // and source files. // // Date Who Comments // ============================================================================================================== // 05/04/2014 EFW Created the code based on the MS Help Viewer script //=============================================================================================================== // The IDs of all code snippet sets on the same page are stored so that we can keep them in synch when a tab is // selected. var allTabSetIds = new Array(); // The IDs of language-specific text (LST) spans are used as dictionary keys so that we can get access to the // spans and update them when the user changes to a different language tab. The values of the dictionary // objects are pipe separated language-specific attributes (lang1=value|lang2=value|lang3=value). The language // ID can be specific (cs, vb, cpp, etc.) or may be a neutral entry (nu) which specifies text common to multiple // languages. If a language is not present and there is no neutral entry, the span is hidden for all languages // to which it does not apply. var allLSTSetIds = new Object(); // Help 1 persistence support. This code must appear inline. var isHelp1; var curLoc = document.location + "."; if(curLoc.indexOf("mk:@MSITStore") == 0) { isHelp1 = true; curLoc = "ms-its:" + curLoc.substring(14, curLoc.length - 1); document.location.replace(curLoc); } else if(curLoc.indexOf("ms-its:") == 0) isHelp1 = true; else isHelp1 = false; // The OnLoad method function OnLoad(defaultLanguage) { var defLang; if(typeof (defaultLanguage) == "undefined" || defaultLanguage == null || defaultLanguage == "") defLang = "vb"; else defLang = defaultLanguage; // In MS Help Viewer, the transform the topic is ran through can move the footer. Move it back where it // belongs if necessary. try { var footer = document.getElementById("pageFooter") if(footer) { var footerParent = document.body; if(footer.parentElement != footerParent) { footer.parentElement.removeChild(footer); footerParent.appendChild(footer); } } } catch(e) { } var language = GetCookie("CodeSnippetContainerLanguage", defLang); // If LST exists on the page, set the LST to show the user selected programming language UpdateLST(language); // If code snippet groups exist, set the current language for them if(allTabSetIds.length > 0) { var i = 0; while(i < allTabSetIds.length) { var tabCount = 1; // The tab count may vary so find the last one in this set while(document.getElementById(allTabSetIds[i] + "_tab" + tabCount) != null) tabCount++; tabCount--; // If not grouped, skip it if(tabCount > 1) SetCurrentLanguage(allTabSetIds[i], language, tabCount); i++; } } InitializeToc(); } // This is just a place holder. The website script implements this function to initialize it's in-page TOC pane function InitializeToc() { } // This function executes in the OnLoad event and ChangeTab action on code snippets. The function parameter // is the user chosen programming language. This function iterates through the "allLSTSetIds" dictionary object // to update the node value of the LST span tag per the user's chosen programming language. function UpdateLST(language) { for(var lstMember in allLSTSetIds) { var devLangSpan = document.getElementById(lstMember); if(devLangSpan != null) { // There may be a carriage return before the LST span in the content so the replace function below // is used to trim the whitespace at the end of the previous node of the current LST node. if(devLangSpan.previousSibling != null && devLangSpan.previousSibling.nodeValue != null) devLangSpan.previousSibling.nodeValue = devLangSpan.previousSibling.nodeValue.replace(/\s+$/, ""); var langs = allLSTSetIds[lstMember].split("|"); var k = 0; var keyValue; while(k < langs.length) { keyValue = langs[k].split("="); if(keyValue[0] == language) { devLangSpan.innerHTML = keyValue[1]; // Help 1 and MS Help Viewer workaround. Add a space if the following text element starts // with a space to prevent things running together. if(devLangSpan.parentNode != null && devLangSpan.parentNode.nextSibling != null) { if (devLangSpan.parentNode.nextSibling.nodeValue != null && !devLangSpan.parentNode.nextSibling.nodeValue.substring(0, 1).match(/[.,);:!/?]/)) { devLangSpan.innerHTML = keyValue[1] + " "; } } break; } k++; } // If not found, default to the neutral language. If there is no neutral language entry, clear the // content to hide it. if(k >= langs.length) { if(language != "nu") { k = 0; while(k < langs.length) { keyValue = langs[k].split("="); if(keyValue[0] == "nu") { devLangSpan.innerHTML = keyValue[1]; // Help 1 and MS Help Viewer workaround. Add a space if the following text element // starts with a space to prevent things running together. if(devLangSpan.parentNode != null && devLangSpan.parentNode.nextSibling != null) { if(devLangSpan.parentNode.nextSibling.nodeValue != null && !devLangSpan.parentNode.nextSibling.nodeValue.substring(0, 1).match(/[.,);:!/?]/)) { devLangSpan.innerHTML = keyValue[1] + " "; } } break; } k++; } } if(k >= langs.length) devLangSpan.innerHTML = ""; } } } } // Get the specified cookie. If not found, return the specified default value. function GetCookie(cookieName, defaultValue) { if(isHelp1) { try { var globals = Help1Globals; var value = globals.Load(cookieName); if(value == null) value = defaultValue; return value; } catch(e) { return defaultValue; } } var cookie = document.cookie.split("; "); for(var i = 0; i < cookie.length; i++) { var crumb = cookie[i].split("="); if(cookieName == crumb[0]) return unescape(crumb[1]) } return defaultValue; } // Set the specified cookie to the specified value function SetCookie(name, value) { if(isHelp1) { try { var globals = Help1Globals; globals.Save(name, value); } catch(e) { } return; } var today = new Date(); today.setTime(today.getTime()); // Set the expiration time to be 60 days from now (in milliseconds) var expires_date = new Date(today.getTime() + (60 * 1000 * 60 * 60 * 24)); document.cookie = name + "=" + escape(value) + ";expires=" + expires_date.toGMTString() + ";path=/"; } // Add a language-specific text ID function AddLanguageSpecificTextSet(lstId) { var keyValue = lstId.split("?") allLSTSetIds[keyValue[0]] = keyValue[1]; } var clipboardHandler; // Add a language tab set ID function AddLanguageTabSet(tabSetId) { allTabSetIds.push(tabSetId); // Create the clipboard handler on first use if(clipboardHandler == null && typeof (Clipboard) == "function") { clipboardHandler = new Clipboard('.copyCodeSnippet', { text: function (trigger) { // Get the code to copy to the clipboard from the active tab of the given tab set var i = 1, tabSetId = trigger.id; var pos = tabSetId.indexOf('_'); if(pos == -1) return ""; tabSetId = tabSetId.substring(0, pos); do { contentId = tabSetId + "_code_Div" + i; tabTemp = document.getElementById(contentId); if(tabTemp != null && tabTemp.style.display != "none") break; i++; } while(tabTemp != null); if(tabTemp == null) return ""; return document.getElementById(contentId).innerText; } }); } } // Switch the active tab for all of other code snippets function ChangeTab(tabSetId, language, snippetIdx, snippetCount) { SetCookie("CodeSnippetContainerLanguage", language); SetActiveTab(tabSetId, snippetIdx, snippetCount); // If LST exists on the page, set the LST to show the user selected programming language UpdateLST(language); var i = 0; while(i < allTabSetIds.length) { // We just care about other snippets if(allTabSetIds[i] != tabSetId) { // Other tab sets may not have the same number of tabs var tabCount = 1; while(document.getElementById(allTabSetIds[i] + "_tab" + tabCount) != null) tabCount++; tabCount--; // If not grouped, skip it if(tabCount > 1) SetCurrentLanguage(allTabSetIds[i], language, tabCount); } i++; } } // Sets the current language in the specified tab set function SetCurrentLanguage(tabSetId, language, tabCount) { var tabIndex = 1; while(tabIndex <= tabCount) { var tabTemp = document.getElementById(tabSetId + "_tab" + tabIndex); if(tabTemp != null && tabTemp.innerHTML.indexOf("'" + language + "'") != -1) break; tabIndex++; } if(tabIndex > tabCount) { // Select the first non-disabled tab tabIndex = 1; if(document.getElementById(tabSetId + "_tab1").className == "codeSnippetContainerTabPhantom") { tabIndex++; while(tabIndex <= tabCount) { var tab = document.getElementById(tabSetId + "_tab" + tabIndex); if(tab.className != "codeSnippetContainerTabPhantom") { tab.className = "codeSnippetContainerTabActive"; document.getElementById(tabSetId + "_code_Div" + j).style.display = "block"; break; } tabIndex++; } } } SetActiveTab(tabSetId, tabIndex, tabCount); } // Set the active tab within a tab set function SetActiveTab(tabSetId, tabIndex, tabCount) { var i = 1; while(i <= tabCount) { var tabTemp = document.getElementById(tabSetId + "_tab" + i); if (tabTemp != null) { if(tabTemp.className == "codeSnippetContainerTabActive") tabTemp.className = "codeSnippetContainerTab"; else if(tabTemp.className == "codeSnippetContainerTabPhantom") tabTemp.style.display = "none"; var codeTemp = document.getElementById(tabSetId + "_code_Div" + i); if(codeTemp.style.display != "none") codeTemp.style.display = "none"; } i++; } // Phantom tabs are shown or hidden as needed if(document.getElementById(tabSetId + "_tab" + tabIndex).className != "codeSnippetContainerTabPhantom") document.getElementById(tabSetId + "_tab" + tabIndex).className = "codeSnippetContainerTabActive"; else document.getElementById(tabSetId + "_tab" + tabIndex).style.display = "block"; document.getElementById(tabSetId + "_code_Div" + tabIndex).style.display = "block"; } // Copy the code from the active tab of the given tab set to the clipboard function CopyToClipboard(tabSetId) { var tabTemp, contentId; var i = 1; if(typeof (Clipboard) == "function") return; do { contentId = tabSetId + "_code_Div" + i; tabTemp = document.getElementById(contentId); if(tabTemp != null && tabTemp.style.display != "none") break; i++; } while(tabTemp != null); if(tabTemp == null) return; if(window.clipboardData) { try { window.clipboardData.setData("Text", document.getElementById(contentId).innerText); } catch(e) { alert("Permission denied. Enable copying to the clipboard."); } } else if(window.netscape) { try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var clip = Components.classes["@mozilla.org/widget/clipboard;1"].createInstance( Components.interfaces.nsIClipboard); if(!clip) return; var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance( Components.interfaces.nsITransferable); if(!trans) return; trans.addDataFlavor("text/unicode"); var str = new Object(); var len = new Object(); var str = Components.classes["@mozilla.org/supports-string;1"].createInstance( Components.interfaces.nsISupportsString); var copytext = document.getElementById(contentId).textContent; str.data = copytext; trans.setTransferData("text/unicode", str, copytext.length * 2); var clipid = Components.interfaces.nsIClipboard; clip.setData(trans, null, clipid.kGlobalClipboard); } catch(e) { alert("Permission denied. Enter \"about:config\" in the address bar and double-click the \"signed.applets.codebase_principal_support\" setting to enable copying to the clipboard."); } } } // Expand or collapse a section function SectionExpandCollapse(togglePrefix) { var image = document.getElementById(togglePrefix + "Toggle"); var section = document.getElementById(togglePrefix + "Section"); if(image != null && section != null) if(section.style.display == "") { image.src = image.src.replace("SectionExpanded.png", "SectionCollapsed.png"); section.style.display = "none"; } else { image.src = image.src.replace("SectionCollapsed.png", "SectionExpanded.png"); section.style.display = ""; } } // Expand or collapse a section when it has the focus and Enter is hit function SectionExpandCollapse_CheckKey(togglePrefix, eventArgs) { if(eventArgs.keyCode == 13) SectionExpandCollapse(togglePrefix); } // Help 1 persistence object. This requires a hidden input element on the page with a class of "userDataStyle" // defined in the style sheet that implements the user data binary behavior: // var Help1Globals = { UserDataCache: function() { var userData = document.getElementById("userDataCache"); return userData; }, Load: function(key) { var userData = this.UserDataCache(); userData.load("userDataSettings"); var value = userData.getAttribute(key); return value; }, Save: function(key, value) { var userData = this.UserDataCache(); userData.setAttribute(key, value); userData.save("userDataSettings"); } };