1// ********************************************************************************* 2// THE NEW CODE FOR SOME HELPER FUNCTIONS FOR F1000RESEARCH 3// 4// TO USE THE HELPERS IN A PAGE ADD THE FOLLOWING SCRIPT LINK 5// <script src="/js/app/research.helpers.js" type="text/javascript"></script> 6// 7// YOU CAN THEN CALL THE HELPERS INITIALIZE FUNCTION WITH THE OPTIONS REQUIRED, IF ANY 8// OPTIONS AVAILABLE WHEN INITIALIZING ARE... (backToTop, debug) 9// $(document).ready(function() { 10// R.helpers.initialize({ "backToTop": true, "debug": true }); 11// // R.helpers.initialize(); <!-- INITIALIZING WITH NO OPTIONS --> 12// }); 13// 14// OR YOU CAN CALL THE PUBLIC FUNCTIONS INDIVIDUALLY 15// $(document).ready(function() { 16// R.helpers.addBackToTop(); 17// R.helpers.showModalWindow({ 18// "modal-title": "Title For Modal", 19// "modal-content": "<span class='test'>CONTENT</span>", 20// "modal-footer": "FOOTER", 21// "add-close-button": true 22// }); 23// R.helpers.setPageColour("#f7f6f5"); 24// R.helpers.checkForDuplicateID(); 25// }); 26// ********************************************************************************* 27 28 29/* 30============================================================================== 31SOME NOTES FOR JAMES 32-------------------- 3301) Need to add an error handling function/option etc. 34 displayError: function(container, message) { 35 if (this.inDevelopmentMode) { console.log("running displayError(" + container + ", " + message + ") function"); } 36 message = message || "An unknown error has occurred."; 37 container.html(message); 38 container.fadeIn(400); 39 setTimeout(function() { 40 container.effect("drop", "easeInCubic", 1000); 41 }, 5000); 42 }, 43============================================================================== 44*/ 45 46/* jslint plusplus: true */ 47/* global $, window, document, console, R */ 48$(document).ready(function () { 49 /* jslint validthis: true */ 50 "use strict"; 51 52 R.helpers = new ResearchHelpers(); 53 54 function ResearchHelpers() { 55 var publicProperties = { 56 description: "The F1000Research Helpers JS", 57 inDevelopmentMode: window.location.hostname === "XXX.f1000.com" ? true : false, 58 // localServerHostCode: function() { 59 // THIS IS JUST AN EXAMPLE OF ASSIGNING A VARIABLE WITH A FUNCTION ETC. 60 // for (var i=0,hn="hall.f1000.com",hc="";i<hn.length;i++) { hc+=hn.charCodeAt(i); } 61 // return hc; 62 //}, 63 64 initialize: initialize, 65 addBackToTop: addBackToTop, 66 setPageColour: setPageColour, 67 platformToolbar: platformToolbar, 68 stickyFooter: stickyFooter, 69 stickyNavigation: stickyNavigation, 70 bindFormFieldHandlers: bindFormFieldHandlers, 71 bindAllFormFields: bindAllFormFields, 72 addTextSearcher: addTextSearcher, 73 addSectionNumbersToTitles: addSectionNumbersToTitles, 74 showModalWindow: showModalWindow, 75 closeModalWindow: closeModalWindow, 76 checkForDuplicateID: checkForDuplicateID, 77 debounce: debounce, 78 hasExtension: hasExtension, 79 initialScrollDownToElement:initialScrollDownToElement 80 }; 81 82 function initialize(options) { 83 options = options || ""; 84 if (options["debug"] === true) { this.inDevelopmentMode = true; } 85 if (this.inDevelopmentMode) { console.log("running initialize() function"); } 86 87 var option = "", 88 optionValue = ""; 89 90 // SET ITEMS FOR ALL PAGES 91 createHelperStyles(); 92 93 appendBackgroundMaskMarkup(); 94 appendModalWindowMarkup(); 95 appendMoreInfoPopupMarkup(); 96 //appendPageFaderMarkup(); 97 98 if (!options["bindAllFormFields"]) { 99 bindFormFieldHandlers(); 100 bindFormCheckboxHandlers(); 101 bindFormToggleHandlers(); 102 bindFormToggleRadioHandlers(); 103 } 104 bindModalWindowHandlers(); 105 bindMoreInfoWindowHandlers(); 106 bindAccordionListHandlers(); 107 bindMoreLessHandlers(); 108 //bindPageFaderHandlers(); 109 110 // LOOP THROUGH OPTION PARAMETER AND SET FUNCTIONS AS REQUIRED 111 if (options) { 112 for (option in options) { 113 optionValue = options[option]; 114 switch (option) { 115 case "backToTop" : 116 this.addBackToTop(); 117 break; 118 case "setPageColour" : 119 this.setPageColour(optionValue === "" ? "" : optionValue); 120 break; 121 case "platformToolbar" : 122 this.platformToolbar(optionValue); 123 break; 124 case "stickyFooter" : 125 this.stickyFooter(optionValue); 126 break; 127 case "stickyNavigation" : 128 this.stickyNavigation(optionValue); 129 break; 130 case "bindAllFormFields" : 131 this.bindAllFormFields(); 132 break; 133 case "addTextSearcher" : 134 this.addTextSearcher(optionValue); 135 break; 136 case "addSectionNumbersToTitles" : 137 this.addSectionNumbersToTitles(); 138 break; 139 case "debug" : 140 this.checkForDuplicateID(); 141 break; 142 case "initialScrollDownToElement" : 143 this.initialScrollDownToElement(); 144 break; 145 } 146 } 147 } 148 } 149 150 function initialScrollDownToElement() { 151 var splitArr = window.location.href.split('#') 152 var selectorFromUrl = splitArr[1] ||'prp' 153 // var newUrl = splitArr[0] 154 if ($("#" + selectorFromUrl).size()) { 155 scrollToElement("#" + selectorFromUrl, 600, -140); 156 // history.pushState({}, null, newUrl); 157 } 158 } 159 // ================================================================================ 160 // THIS FUNCTION CREATES THE 'BACK TO TOP' ICON MARKUP AND HANDLERS 161 function addBackToTop() { 162 if (R.helpers.inDevelopmentMode) { console.log("running addBackToTop() function"); } 163 var that = this, 164 reqdHTML = "<div id=\"back-to-top-wrapper\" class=\"back-to-top-wrapper\" style=\"display: none;\">" + 165 "<div id=\"back-to-top-arrow\" class=\"up-arrow bigger back-to-top-arrow\"></div></div>"; 166 if ($("#back-to-top-wrapper").size() === 0) { $("body").append(reqdHTML); } 167 bindBackToTopHandlers({ "display-position": 150, "display-time": 400, "scroll-time": 1500 }); 168 169 function bindBackToTopHandlers(settings) { 170 if (R.helpers.inDevelopmentMode) { console.log("running bindBackToTopHandlers(" + settings + ") function"); } 171 var displayPosition = settings["display-position"] || 150, 172 displayTime = settings["display-time"] || 400, 173 scrollTime = settings["scroll-time"] || 1500; 174 175 if (R.helpers.inDevelopmentMode) { console.log("Current scrollTop() = " + $(this).scrollTop()); } 176 if (R.helpers.inDevelopmentMode) { console.log("displayPosition = " + displayPosition); } 177 178 $(window).scroll(function () { 179 if ($(this).scrollTop() > displayPosition) { 180 if ($(".sticky").filter(":visible").size() > 0) { $("#back-to-top-wrapper").css({ "bottom": $(".sticky").height() + 10 }); } 181 if ($(".cookie-warning").filter(":visible").size() > 0) { $("#back-to-top-wrapper").css({ "bottom": $(".cookie-warning").height() + 10 }); } 182 $(".back-to-top-wrapper").fadeIn(displayTime); 183 } else { 184 $(".back-to-top-wrapper").fadeOut(displayTime); 185 } 186 }); 187 188 $(".back-to-top-wrapper").on("click", function() { 189 $("body,html").animate({ scrollTop: 0 }, { duration: scrollTime, easing: "easeInOutCubic" }); 190 }); 191 } 192 } 193 // END OF THE BACK TO TOP FUNCTION 194 // ================================================================================ 195 196 197 // ================================================================================ 198 // THIS FUNCTION SETS THE BACKGROUND COLOUR OF THE PAGE 199 function setPageColour(theColour) { 200 theColour = theColour || "#f7f6f5"; 201 if (R.helpers.inDevelopmentMode) { console.log("running setPageColour() function"); } 202 $("body, .content-wrapper").css({ "background-color": theColour }); 203 } 204 // END OF THE SET PAGE COLOUR FUNCTION 205 // ================================================================================ 206 207 208 // ================================================================================ 209 // THIS FUNCTION HANDLES THE DISPLAY OF THE PLATFORM TOOLBAR 210 function platformToolbar(website) { 211 var Toolbar = (function() { 212 var $toolbar = $('.f1r-platform-toolbar'),
213 $info = $toolbar.find(".information-text"), 214 hideToolbar = $toolbar.hasClass("is-hidden"); 215 var updateWrapperMargin = R.helpers.debounce(function() { 216 var toolbarHeight = $toolbar.height(); 217 //previewAssetWrapper.css('margin-top', toolbarHeight-20); 218 }, 250); 219 var updatePreviewBox = R.helpers.debounce(function () { 220 var windowWidth = $(window).width(), 221 scrollTop = $(window).scrollTop(), 222 platform = $(".f1r-platform-toolbar select").size() ? $(".f1r-platform-toolbar select option:selected").text() : $.trim($(".f1r-platform-toolbar .form-field .h2-title").text()); 223 platform = platform.split(" "); 224 platform = platform[0].toLowerCase(); 225 if (platform === "") { platform = website.toLowerCase(); } 226 if (scrollTop > 56 && windowWidth <= 810) { 227 $toolbar.css({ 228 width: "100%", 229 "margin": "0 0 0 -20px", 230 "padding-left": "20px", 231 top: 56, 232 position: "fixed", 233 "z-index": 99 234 }).addClass(platform); 235 if (hideToolbar) { $toolbar.removeClass("is-hidden"); } 236 $info.addClass("white"); 237 } else if (scrollTop > 120) { 238 $toolbar.css({ 239 width: "100%", 240 "margin": "0 0 0 -20px", 241 "padding-left": "20px", 242 top: 0, 243 position: "fixed", 244 "z-index": 99 245 }).addClass(platform); 246 if (hideToolbar) { $toolbar.removeClass("is-hidden"); } 247 $info.addClass("white"); 248 } else { 249 $toolbar.removeClass(platform).attr("style", ""); 250 if (hideToolbar) { $toolbar.addClass("is-hidden"); } 251 $info.removeClass("white"); 252 } 253 }, 5); 254 return { 255 updateWrapperMargin: updateWrapperMargin, 256 updatePreviewBox: updatePreviewBox 257 }; 258 259 }()); 260 $(window).on("resize", Toolbar.updateWrapperMargin); 261 $(window).on("scroll", Toolbar.updatePreviewBox); 262 Toolbar.updatePreviewBox(); 263 Toolbar.updateWrapperMargin(); 264 } 265 // END OF THE PLATFORM TOOLBAR FUNCTION 266 // ================================================================================ 267 268 269 // ================================================================================ 270 // THIS FUNCTION FORCES THE FOOTER TO DISPLAY ON THE PAGE BOTTOM (WHEN NOT ENOUGH CONTENT) 271 function stickyFooter(page) { 272 if (R.helpers.inDevelopmentMode) { console.log("running stickyFooter() function"); } 273 page = page || "default"; 274 var theWindowHeight = $(window).height(), 275 theBodyHeight = $("body").outerHeight(true), 276 footerID = "footer-wrapper", 277 theFooterHeight = 0, 278 headerID = "header-wrapper", 279 headHeight = 0, 280 titleID = "", 281 titleHeight = 0, 282 contentHeight = 0, 283 nonBodyHeight = 0, 284 isChannels = page === "channels" ? true : false; 285 if (isChannels) { 286 headerID = "channel-header-bar"; 287 titleID = "channel-view-header"; 288 titleHeight = $(".channel-view-header").outerHeight(true); 289 } 290 theFooterHeight = $("." + footerID).outerHeight(true); 291 headHeight = $("." + headerID).outerHeight(true); 292 if (theBodyHeight < getTheWindowHeight()) { 293 //$("." + footerID).css({ "position": "fixed", "width": "100%", "top": theWindowHeight - theFooterHeight + "px" }); 294 //$("." + footerID).css({ "bottom": 0, "position": "absolute", "width": "100%" });
295 if (isChannels) { 296 nonBodyHeight = headHeight + titleHeight + theFooterHeight; 297 contentHeight = theWindowHeight - (nonBodyHeight + 35); 298 $(".channel-view-list").css({ "min-height": contentHeight + "px" }); 299 } 300 } else { 301 if (isChannels) { $("#page-spacer-container").css({ "height": "40px", "display": "block" }); } 302 } 303 // Return the height of the current window 304 function getTheWindowHeight() { 305 var theHeight = 0; 306 if (typeof window.innerHeight === "number") { 307 theHeight = window.innerHeight; 308 } else { 309 if (document.documentElement && document.documentElement.clientHeight) { 310 theHeight = document.documentElement.clientHeight; 311 } else { 312 if (document.body && document.body.clientHeight) { 313 theHeight = document.body.clientHeight; 314 } 315 } 316 } 317 return theHeight; 318 } 319 } 320 // END OF THE STICKY FOOTER FUNCTION 321 // ================================================================================ 322 323 324 // ================================================================================ 325 // THIS FUNCTION STICKS THE LEFT 'NAVIGATION' MENU WHEN THE PAGE IS SCROLLED 326 function stickyNavigation() { 327 var fullBar = $('.js-sticky-nav'), 328 pageContent = $(".page-content"), 329 stickyHeader = $(".js-sticky-header__content"), 330 stickyHeaderHeight = stickyHeader.outerHeight(true), 331 navWidth = fullBar.outerWidth(true), 332 navHeight = fullBar.outerHeight(true), 333 windowHeight = $(window).height(), 334 topPadding = 25, 335 stickyContainer = $('.row.research-layout._mdl-layout'),
336 stickyTop = pageContent.offset().top + topPadding, 337 stickyBottom = stickyTop + pageContent.outerHeight(true) - navHeight, 338 isGateCollPage = location.pathname.match(/(gateways|collections)/) ? true : false, 339 myExpandingSectionEvent = new CustomEvent('sectionExpanded'); 340 stickyContainer.css({ position: 'relative' }); 341 //console.log('top, bottom', stickyTop, stickyBottom); 342 343 $('.mdl-expandingsection, .read-more-trigger').on('click', function(e) { 344 pageContent.trigger(myExpandingSectionEvent); 345 }); 346 347 $(".read-more-trigger").on("click", function (e) { 348 setTimeout(function(){ pageContent.trigger(myExpandingSectionEvent); }, 50); 349 }); 350 351 $(window) 352 .on("scroll", reposition) 353 .on("resize sectionExpanded", function (e) { 354 navWidth = fullBar.outerWidth(true); 355 reposition(); 356 }); 357 358 function reposition(e) { 359 var m = $(window).scrollTop(); 360 stickyHeaderHeight = isGateCollPage ? stickyHeader.outerHeight(true) : 0;
361 stickyTop = pageContent.offset().top + topPadding - stickyHeaderHeight; 362 stickyBottom = stickyTop + pageContent.outerHeight(true) - navHeight; 363 // RESEARCH-8609: When the nav bar is longer then the content, trying to make it 'sticky' causes issues with scrolling 364 // In those circumstances there's no need to make the menu to be 'sticky' 365 if((m > stickyBottom) && (navHeight <= pageContent.outerHeight(true))) { 366 fullBar.css({ position: "absolute", top: "", bottom: "0", width: navWidth + "px", "padding-top": topPadding + "px" }); 367 pageContent.css({ "margin-left": navWidth + "px" }); 368 } else if ((m > stickyTop) && (navHeight <= pageContent.outerHeight(true))) { 369 fullBar.css({ position: "fixed", top: stickyHeaderHeight, width: navWidth + "px", "padding-top": 0 }); 370 pageContent.css({ "margin-left": navWidth + "px" }); 371 } else { 372 fullBar.css({ position: "", top: "", width: "", "padding-top": topPadding + "px" }); 373 pageContent.css({ "margin-left": 0 }); 374 } 375 } 376 } 377 // END OF THE STICKY NAVIGATION FUNCTION 378 // ================================================================================ 379 380 381 // ================================================================================ 382 // THIS FUNCTION BINDS THE ITEMS REQUIRED FOR A STANDARD FORM PAGE (INPUT FIELDS, CHECKBOX ETC.) 383 function bindAllFormFields() { 384 var that = this; 385 if (R.helpers.inDevelopmentMode) { console.log("running bindAllFormFields() function"); } 386 bindFormFieldHandlers(); 387 bindFormCheckboxHandlers(); 388 bindFormToggleHandlers(); 389 bindFormToggleRadioHandlers(); 390 } 391 // END OF THE BIND ALL FORM FIELDS FUNCTION 392 // ================================================================================ 393 394 395 // ================================================================================ 396 // THIS FUNCTION CREATES THE SIMPLE HTML/CSS3 TEXT SEARCHER 397 // Mandatory options are "text-field-ID" (The ID ref of the text field where the search is entered) 398 // Optional options are "error-field-ID" (The ID ref of the error item to display when nothing selected) 399 function addTextSearcher(searchOptions) { 400 if (R.helpers.inDevelopmentMode) { console.log("running addTextSearcher() function"); } 401 var searchField = searchOptions["text-field-ID"] || "search-box", 402 errorField = searchOptions["error-field-ID"] ? $("#" + searchOptions["error-field-ID"]) : "", 403 numberOfSearchableItems = $(".f1r-searchable").size(); 404 if ($("#" + searchField).size() > 0) { 405 if ($("#f1r_search_style").size() < 1) { $("body").append("<style id='f1r_search_style'></style>"); } 406 var searchStyle = document.getElementById("f1r_search_style"); 407 document.getElementById(searchField).addEventListener("input", function() { 408 if (!this.value) { 409 searchStyle.innerHTML = ""; 410 if (errorField) { errorField.hide(); } 411 } else { 412 searchStyle.innerHTML = ".f1r-searchable:not([data-index*=\"" + this.value.toLowerCase() + "\"]) { display: none !important; }"; 413 if ($(".f1r-searchable:not([data-index*=\"" + this.value.toLowerCase() + "\"])").size() >= numberOfSearchableItems && errorField) { 414 errorField.fadeIn(200); 415 } else { 416 errorField.hide(); 417 } 418 } 419 }); 420 } 421 } 422 // END OF THE ADD TEXT SEARCHER FUNCTION 423 // ================================================================================ 424 425 426 // ================================================================================ 427 // THIS FUNCTION ADDS THE RELEVANT SECTION NUMBERS TO THE SECTION TITLE 428 function addSectionNumbersToTitles() { 429 if (R.helpers.inDevelopmentMode) { console.log("running addSectionNumbersToTitles() function"); } 430 431 $(".numbered-list-links").each(function(i, list) { 432 $(list).find("li a").each(function(j, item) { 433 var sectionID = $(item).attr("href") || "", 434 sectionNo = j + 1; 435 if (sectionID !== "" && sectionID !== "undefined") { 436 $(sectionID).html(sectionNo + ". " + $(sectionID).html()); 437 } 438 }); 439 }); 440 } 441 // END OF THE SECTION NUMBER UPDATE FUNCTION 442 // ================================================================================ 443 444 445 // ================================================================================ 446 // THIS FUNCTION OPENS THE MODAL WINDOW WITH THE SPECIFIED OPTIONS 447 function showModalWindow(options) { 448 if (R.helpers.inDevelopmentMode) { console.log("running showModalWindow(" + options + ") function"); } 449 var modalWindow = $("#rhelper-modal-window"),
450 modalWindowBackgroundMask = $("#rhelper-background-mask"), 451 modalAltClass = options["modal-class"] || "", 452 modalTitle = options["modal-title"] || "", 453 modalContent = options["modal-content"] || "", 454 modalFooter = options["modal-footer"] || "", 455 modalCloseButton = options["add-close-button"] || false; 456 if (R.helpers.inDevelopmentMode) { console.log(options, modalTitle, modalContent, modalFooter); } 457 if (modalWindow.size() > 0) { 458 if (modalCloseButton) { 459 modalFooter = modalFooter + "<button id='rhelper-modal-close-button' class='rhelper-modal-close-button'>Close</button>"; 460 } 461 if(modalAltClass) modalWindow.addClass(modalAltClass); 462 modalWindow.find(".rhelper-modal-title").html(modalTitle); 463 modalWindow.find(".rhelper-modal-content").html(modalContent); 464 modalWindow.find(".rhelper-modal-footer").html(modalFooter); 465 } 466 modalWindow.fadeIn(400); 467 modalWindowBackgroundMask.fadeIn(200); 468 } 469 // END OF THE MODAL WINDOW FUNCTIONS 470 // ================================================================================ 471 472 473 // ================================================================================ 474 // THIS FUNCTION CREATES THE MARKUP FOR THE POPUP WINDOWS BACKGROUND MASK 475 function appendBackgroundMaskMarkup() { 476 if (R.helpers.inDevelopmentMode) { console.log("running appendBackgroundMaskMarkup() function"); } 477 var maskID = "rhelper-background-mask", 478 messageID = "rhelper-background-message", 479 tickerID = "rhelper-bg-ticker", 480 maskHTML = "<div id='" + maskID + "' name='" + maskID + "' class='" + maskID + "'>" + 481 "<div id='" + messageID + "' name='" + messageID + 482 "' class='" + messageID + "'></div>" + 483 "</div>" + 484 "<div id='" + tickerID + "' name='" + tickerID + 485 "' class='" + tickerID + "'></div>"; 486 if ($("#" + maskID).size() === 0) { $("body").append(maskHTML); } 487 } 488 // END OF THE BACKGROUND MASK FUNCTION 489 // ================================================================================ 490 491 492 // ================================================================================ 493 // THIS FUNCTION CREATES THE MARKUP FOR THE POPUP WINDOWS 494 function appendModalWindowMarkup() { 495 if (R.helpers.inDevelopmentMode) { console.log("running appendModalWindowMarkup() function"); } 496 var modalID = "rhelper-modal-window", 497 modalHTML = "<div id=\"" + modalID + "\" name=\"" + modalID + "\" class=\"" + modalID + "\">" + 498 "<div class=\"rhelper-modal-close-icon\"></div>" + 499 "<div class=\"rhelper-modal-title\"></div>" + 500 "<div class=\"rhelper-modal-content\"></div>" + 501 "<div class=\"rhelper-modal-footer\"><button class=\"rhelper-modal-close-button\">Close</button></div>" + 502 "</div>"; 503 if ($("#" + modalID).size() === 0) { $("body").append(modalHTML); } 504 } 505 // END OF THE POPUPS MARKUP FUNCTION 506 // ================================================================================ 507 508 509 // ================================================================================ 510 // THIS FUNCTION CREATES THE MARKUP FOR THE MORE INFO ICONS 511 function appendMoreInfoPopupMarkup() { 512 if (R.helpers.inDevelopmentMode) { console.log("running appendMoreInfoPopupMarkup() function"); } 513 var popupID = "rhelper-more-info-popup", 514 popupHTML = '<div id="' + popupID + '" name="' + popupID + '" class="' + popupID + '">' + 515 '<div class="rhelper-more-info research-layout">' + 516 '<div class="more-info-content"></div>' + 517 '</div>' + 518 '<div class="more-info-pointer"></div>' + 519 '</div>'; 520 if ($("#" + popupID).size() === 0) { $("body").append(popupHTML); } 521 } 522 // END OF THE MORE INFO POPUP MARKUP 523 // ================================================================================ 524 525 526 // ================================================================================ 527 // THIS FUNCTION CREATES THE MARKUP FOR THE POPUP WINDOWS 528 function appendPageFaderMarkup() { 529 if (R.helpers.inDevelopmentMode) { console.log("running appendPageFaderMarkup() function"); } 530 var modalID = "rhelper-page-fader", 531 modalHTML = "<div id=\"" + modalID + "\" name=\"" + modalID + "\" class=\"" + modalID + "\">" + 532 "</div>"; 533 if ($("#" + modalID).size() === 0) { $("body").append(modalHTML); } 534 } 535 // END OF THE POPUPS MARKUP FUNCTION 536 // ================================================================================ 537 538 539 // ================================================================================ 540 // THIS FUNCTION BINDS THE HANDLERS FOR INPUT FIELDS (ADDS CLASS ON ACTIVE ETC.) 541 function bindFormFieldHandlers() { 542 if (R.helpers.inDevelopmentMode) { console.log("running bindFormFieldHandlers() function"); } 543 $("body").on("focus", "input:not('#header-search-input'), textarea", function() { 544 if (!$(this).parent().hasClass("selected-option") && !$(this).closest("form.sticky-email__form")) { 545 $(this).removeClass("form-field-error form-checkbox-error"); 546 $(this).addClass("form-field-active"); 547 } 548 }).on("blur", "input, textarea", function() { 549 $(this).removeClass("form-field-active"); 550 }); 551 $(".new-select-standard-wrapper input").on("focus", function() {
552 $(this).closest(".new-select-standard-wrapper").removeClass("form-field-error"); 553 }); 554 $("body").on("focus", "input.form-field-error, textarea.form-field-error", function() { 555 $(this).removeClass('form-field-error'); 556 }); 557 } 558 // END OF THE BIND INPUT FIELDS FUNCTION 559 // ================================================================================ 560 561 562 // ================================================================================ 563 // THIS FUNCTION BINDS THE HANDLERS FOR THE MODAL WINDOWS 564 function bindModalWindowHandlers() { 565 if (R.helpers.inDevelopmentMode) { console.log("running bindModalWindowHandlers() function"); } 566 $(".rhelper-modal-close-button, .rhelper-modal-close-icon").on("click", function() { 567 closeModalWindow(); 568 }); 569 $("body").on("click", "#rhelper-modal-close-button", function(e) { 570 e.preventDefault(); 571 closeModalWindow(); 572 }); 573 $("#rhelper-background-mask").click(function(e) { 574 e.preventDefault(); 575 if ($("#rhelper-modal-window").has(e.target).length === 0) { 576 closeModalWindow(); 577 } 578 }); 579 } 580 581 function closeModalWindow(callback) { 582 if (R.helpers.inDevelopmentMode) { console.log("running closeModalWindow() function"); } 583 $("#rhelper-modal-window").fadeOut(200); 584 $("#rhelper-background-mask").fadeOut(400); 585 586 if(callback) setTimeout(callback, 600); 587 } 588 // END OF THE MODAL WINDOW HANDLER BINDING FUNCTION 589 // ================================================================================ 590 591 592 // ================================================================================ 593 // THIS FUNCTION BINDS THE HANDLERS FOR THE MORE INFO POPUPS 594 // -------------------------------------------------------------------------------- 595 // Expected markup for the more-info popup to work 596 // 597 // <span class="icon-more-info"> <!-- You can always add new classes etc. --> 598 // <div class="is-hidden more-info"> <!-- This DIV should contain the text for the popup --> 599 // MORE INFO TEXT GOES HERE 600 // </div> 601 // </span> 602 // -------------------------------------------------------------------------------- 603 // If you need a bigger 'popup containter' add class 'more-info-big' to the main <span> 604 // -------------------------------------------------------------------------------- 605 function bindMoreInfoWindowHandlers() { 606 if (R.helpers.inDevelopmentMode) { console.log("running bindMoreInfoWindowHandlers() function"); } 607 $("body").on("click", ".icon-more-info", function(e) { 608 var textForPopup = $(this).find(".more-info").html(), 609 infoPopupWrapper = $("#rhelper-more-info-popup"), 610 popupText = infoPopupWrapper.find(".more-info-content"), 611 popupPointer = infoPopupWrapper.find(".more-info-pointer"), 612 popupBigger = $(this).hasClass("more-info-big") ? true : false, 613 pointerMargin = 90, 614 $parentContainer = $("#highlight-area"), 615 parentLeft = parseInt(($parentContainer.position().left + 5), 10), 616 parentRight = parseInt(parentLeft + ($parentContainer.width() - 10), 10), 617 leftPosition = popupBigger ? $(this).offset().left - 487 : $(this).offset().left - 87, 618 rightPosition = popupBigger ? $(this).offset().left + 600 : $(this).offset().left + 200, 619 topPosition = $(this).offset().top - 2; // The "- 2" adds a margin of 2 between icon & pointer 620 if (popupBigger) { 621 infoPopupWrapper.find(".rhelper-more-info").css({ "width": "560px" }); 622 } else { 623 infoPopupWrapper.find(".rhelper-more-info").css({ "width": "160px" }); 624 } 625 // Check if the popup stays in the boundaries of the parent container 626 if (rightPosition > parentRight) { 627 leftPosition = popupBigger ? parentRight - 575 : parentRight - 175; 628 pointerMargin = (e.pageX - (leftPosition + 10)); 629 } else if (leftPosition < parentLeft) { 630 leftPosition = parentLeft + 20; 631 pointerMargin = (e.pageX - (leftPosition + 10)); 632 } 633 // Populate the popup text 634 popupText.html(textForPopup); 635 // Set the pointer position 636 popupPointer.css({ "margin-left": pointerMargin + "px" }); 637 // Add some margin when on mobile in the browse view 638 if ($("#the-responsive-header").is(":visible") && $(".subject-browse .wellcome.article-listing").size()) { 639 $("#rhelper-more-info-popup .rhelper-more-info").css({ "margin-left": "10px" }); 640 } 641 // Annoying hack so we can get the height of the hidden item 642 infoPopupWrapper.css({ "visibility": "hidden", "display": "block"}); 643 topPosition = topPosition - infoPopupWrapper.height(); 644 infoPopupWrapper.css({ "top": topPosition + "px", "left"
644: leftPosition + "px", "visibility": "", "display": "none" }); 645 //infoPopupWrapper.fadeIn(100); 646 infoPopupWrapper.show(); 647 }); 648 $(document).on("mouseup", function(e) { 649 var helpContainer = $(".rhelper-more-info-popup"); 650 if (!helpContainer.is(e.target) && helpContainer.has(e.target).length === 0) { 651 //helpContainer.fadeOut(200); 652 helpContainer.hide(); 653 } 654 }); 655 } 656 // END OF THE MORE INFO POPUP BINDING FUNCTION 657 // ================================================================================ 658 659 660 // ================================================================================ 661 // THIS FUNCTION BINDS THE HANDLER FOR CHECKBOX GROUPS (CLASS IS .form-checkbox-group) 662 // -------------------------------------------------------------------------------- 663 // Expected markup for the checkboxes to work 664 // 665 // <div class="form-input-wrapper full-width form-checkbox-group" data-checkbox-group="SOME_NAME"> 666 // Checkbox markup (likely to be MDL) 667 // </div> 668 // -------------------------------------------------------------------------------- 669 function bindFormCheckboxHandlers() { 670 if (R.helpers.inDevelopmentMode) { console.log("running bindFormCheckboxHandlers() function"); } 671 672 $("body").on("change", ".mdl-checkbox__input", function(e) { 673 if (!this.checked) return; 674 675 const thisCheckboxGroup = this.closest('.form-checkbox-group') 676 if (!thisCheckboxGroup) return; 677 678 const checkboxGroupName = thisCheckboxGroup.dataset.checkboxGroup, 679 allCheckboxGroup = document.querySelectorAll(`[data-checkbox-group="${checkboxGroupName}"]`); 680 681 for (const checkboxGroup of allCheckboxGroup) { 682 if (checkboxGroup !== thisCheckboxGroup) { 683 F1000.MdlHelper.prototype.checkboxUncheck(checkboxGroup.querySelector('input')); 684 } 685 } 686 }); 687 } 688 // END OF THE BIND CHECKBOX GROUPS FUNCTION 689 // ================================================================================ 690 691 692 // ================================================================================ 693 // BIND THE HANDLERS FOR THE YES/NO TOGGLE BUTTON (CLASS IS .form-toggle-button) 694 // -------------------------------------------------------------------------------- 695 // Expected markup for the toggle to work 696 // 697 // <div class="form-toggle-button" data-associated-container="has_priority_area"> 698 // <input type="radio" class="is-hidden yes-button" value="true" /> 699 // <input type="radio" class="is-hidden no-button" value="false" /> 700 // </div> 701 // 702 // Notes: The 'data-associated-container' attribute allows you to specify the ID of 703 // an item to show/hide when the toggle button is pressed. This is optional. 704 // The radio buttons are also optional (if you just need the toggle) 705 // -------------------------------------------------------------------------------- 706 function bindFormToggleHandlers() { 707 if (R.helpers.inDevelopmentMode) { console.log("running bindFormToggleHandlers() function"); } 708 $(".form-toggle-button").on("change", function() { 709 const assocContainerID = $(this).attr("data-associated-container"); 710 if (assocContainerID) { 711 $(`#${assocContainerID}`).slideToggle(250); 712 } 713 }); 714 } 715 716 717 //similar to above but working on radio buttons 718 function bindFormToggleRadioHandlers(){ 719 $(".js-show-form-section, .js-hide-form-section").on("click", function() { 720 var sectionID = $(this).attr("data-associated-container"), 721 section = $("#" + sectionID), 722 toggleSection = ($(this).hasClass("js-show-form-section") && !section.is(":visible")) || ($(this).hasClass("js-hide-form-section") && section.is(":visible")) ? true : false; 723 if (toggleSection) { section.slideToggle(600); } 724 }); 725 726 727 } 728 729 730 // END OF THE BIND YES/NO TOGGLE HANDLERS FUNCTION 731 // ================================================================================ 732 733 734 // ================================================================================ 735 // THIS FUNCTION BINDS THE HANDLERS FOR THE 'ACCORDION' LISTS 736 // -------------------------------------------------------------------------------- 737 // Expected markup for an accordion list (Requires parent class of .research-layout) 738 // 739 // NOTE: The optional data-accordion-type attribute is to specify how the exp
739anding 740 // and collapsing of the list items works, as follows: 741 // accordion This will close any existing open sections when expanding an item 742 // multiple This is the default. Allows multiple sections to be open. You can 743 // just omit adding the data-accordion-type attribute all together. 744 // 745 // <div class="accordion-list" [OPTIONAL: data-accordion-type="accordion || multiple"]> 746 // <div class="section-box"> 747 // <ul class="section-detail"> 748 // <li class="heading5 section-item"> 749 // <span class="open-row"><a href="#" class="title-link"> -TITLE HERE- </a></span> 750 // <span class="open-section f1r-icon icon-20_plus_big" title="Open"></span> 751 // <span class="close-section f1r-icon icon-12_minus_big" title="Close"></span> 752 // <div class="section-content heading10 padding-bottom"> -CONTENT TEXT HERE- </div> 753 // </li> 754 // </ul> 755 // </div> 756 // </div> 757 // -------------------------------------------------------------------------------- 758 function bindAccordionListHandlers() { 759 if (R.helpers.inDevelopmentMode) { console.log("running bindAccordionListHandlers() function"); } 760 $(".accordion-list").on("click", ".section-detail .accordion-control", function(e) { 761 e.preventDefault(); 762 var openSections = $(".content-shown"), 763 $listItem = $(this).closest("li"), 764 accordionList = $(this).closest(".accordion-list").attr("data-accordion-type") === "accordion" ? true : false, 765 options = { 766 "action": "hide", 767 "content": $listItem.find(".section-content"), 768 "plus": $listItem.find(".open-section"), 769 "minus": $listItem.find(".close-section"), 770 "fadeDuration": 200, 771 "slideDuration": 400 772 }, 773 accordionController = { 774 update: function(options) { 775 var action = options["action"] || "show", 776 content = options["content"] || "", 777 plus = options["plus"] || "", 778 minus = options["minus"] || "", 779 fadeDuration = options["fadeDuration"] || 200, 780 slideDuration = options["slideDuration"] || (fadeDuration * 2), 781 effect = options["effect"] || "easeOutCirc"; 782 content.slideToggle(slideDuration, effect); 783 if (action === "show") { 784 this.switchIcon(plus, minus, fadeDuration); 785 } else { 786 this.switchIcon(minus, plus, fadeDuration); 787 } 788 }, 789 switchIcon: function(itemToHide, itemToShow, fadeDuration) { 790 itemToHide.fadeOut(fadeDuration, function() { itemToShow.fadeIn(fadeDuration); }); 791 } 792 }; 793 if ($listItem.hasClass("content-shown")) { 794 $listItem.removeClass("content-shown"); 795 accordionController.update(options); 796 } else { 797 if (accordionList && openSections.size() > 0) { 798 openSections.each(function (index, element) { 799 $(this).removeClass("content-shown"); 800 accordionController.update({ 801 "action": "hide", 802 "content": $(this).find(".section-content"), 803 "plus": $(this).find(".open-section"), 804 "minus": $(this).find(".close-section"), 805 "fadeDuration": 100, 806 "slideDuration": 200, 807 "effect": "swing" 808 }); 809 }); 810 } 811 $listItem.addClass("content-shown"); 812 options["action"] = "show"; 813 accordionController.update(options); 814 } 815 }); 816 } 817 // END OF THE ACCORDION LIST HANDLERS 818 // ================================================================================ 819 820 821 // ================================================================================ 822 // THIS FUNCTION BINDS THE HANDLERS FOR THE MORE/LESS SECTION EXPAND 823 // -------------------------------------------------------------------------------- 824 // Expected markup for the more/less to work 825 // 826 // <div class="example-detail"> 827 // <div class="collapsed-section [CAN INCLUDE OTHER CLASSES HERE]">
828 // == The text for the collapsed section goes here == 829 // <a href="#" title="More" class="more-less-link more [MORE CLASSES HERE]"> 830 // Show More <span class="f1r-icon icon-27_sub_marker link-arrow-tiny orange"></span> 831 // </a> 832 // </div> 833 // <div class="expanded-section [CAN INCLUDE OTHER CLASSES HERE]"> 834 // == The text for the expanded section goes here == 835 // <a href="#" title="Less" class="more-less-link less [MORE CLASSES HERE]"> 836 // Show Less <span class="f1r-icon icon-77_sub_marker_up link-arrow-tiny orange"></span> 837 // </a> 838 // </div> 839 // </div> 840 // -------------------------------------------------------------------------------- 841 function bindMoreLessHandlers() { 842 if (R.helpers.inDevelopmentMode) { } 843 $(".more-less-link").on("click", function(e) { 844 e.preventDefault(); 845 var theContainer = $(this).closest(".example-detail"), 846 fullSection = theContainer.find(".expanded-section"), 847 partSection = theContainer.find(".collapsed-section"), 848 myExpandingSectionEvent = new CustomEvent('sectionExpanded'), 849 pageContent = $(".page-content"); 850 if ($(this).hasClass("more") || $(this).hasClass("more-text")) { 851 partSection.hide(1, function() { 852 fullSection.fadeIn(200, resizeStickyNav); 853 }); 854 } else { 855 fullSection.hide(1, function(pageContent) { 856 partSection.fadeIn(200, resizeStickyNav); 857 }); 858 } 859 860 function resizeStickyNav() { 861 pageContent.trigger(myExpandingSectionEvent); 862 } 863 }); 864 } 865 // END OF THE BIND MORE/LESS SECTION EXPAND FUNCTION 866 // ================================================================================ 867 868 869 // ================================================================================ 870 // THIS FUNCTION BINDS THE HANDLERS FOR THE PAGE FADE EFFECT WHEN CHANGING URLS 871 function bindPageFaderHandlers() { 872 if (R.helpers.inDevelopmentMode) { console.log("running bindPageFaderHandlers() function"); } 873 $(".fade-link, .fade-link-med, .fade-link-slow").on("click", function(e) { 874 e.preventDefault(); 875 var theURL = $(this).attr("href"), 876 fadeTime = 100; 877 if ($(this).hasClass("fade-link-med")) { 878 fadeTime = 500; 879 } else if ($(this).hasClass("fade-link-slow")) { 880 fadeTime = 2000; 881 } 882 //theURL = theURL + "?speed=" + fadeTime; 883 $(".rhelper-page-fader").fadeTo(fadeTime, 1, function() { 884 window.location.replace(theURL); 885 }); 886 }); 887 $(".rhelper-page-fader").fadeTo(100, 0, function() { $(this).hide(); }); 888 } 889 // END OF THE PAGE FADER HANDLERS 890 // ================================================================================ 891 892 893 // ================================================================================ 894 // THIS FUNCTION CHECKS THE PAGE FOR ITEMS WITH A DUPLICATE ID REF 895 function checkForDuplicateID() { 896 if (R.helpers.inDevelopmentMode) { console.log("running checkForDuplicateID() function"); } 897 $("[id]").each(function() { 898 var ids = $("[id='" + this.id + "']"); 899 if (ids.length > 1 && ids[0] == this) { 900 console.warn("Multiple IDs on item #" + this.id); 901 } 902 }); 903 } 904 // END OF THE CHECK FOR DUPLICATE ID'S 905 // ================================================================================ 906 907 908 // ================================================================================ 909 // THIS FUNCTION CREATES THE STYLES REQUIRED FOR THE HELPER FUNCTIONS 910 function createHelperStyles() { 911 if (R.helpers.inDevelopmentMode) { console.log("running createHelperStyles() function"); } 912 var helperStyles = $("<style type=\"text/css\">").appendTo("head"), 913 bgmaskCSS = ".rhelper-background-mask { " + 914 "position: fixed; top: 0; left: 0; display: none; z-index: 1000; " + 915 "width: 100%; height: 100%; background-color: #000; " + 916 "-ms-filter: \"progid:DXImageTransform.Microsoft.Alpha(Opacity=40)\"; " + 917 "filter: alpha(opacity=40); -moz-opacity: 0.4; opacity: 0.4; " + 918 "}", 919 bgMessageCSS = ".rhelper-background-message { " + 920 "font: normal normal normal 30px/30px 'ProximaBold', Arial, sans-serif; " + 921 "width: 500px; margin: 0 auto; padding-top: 20%; color: white; letter-spacing: 0.05em; " + 922 "text-align: center; position: relative; z-index: 1001;" + 923 "}", 924 bgTickerCSS = ".rhelper-bg-ticker { " + 925 "display: none; position: fixed; z-index: 1001; " + 926 "top: 50%; left: 50%; margin: -10px 0 0 -8px;" + 927 "width: 16px; height: 11px; " + 928 "background: transparent url(\"/img/ticker.gif\") no-repeat center center;" + 929 "}", 930 modalWindowCSS = ".rhelper-modal-window { " + 931 "display: none; position: absolute; z-index: 1001; " + 932 "font: normal normal normal 14px/18px Verdana,Arial,sans-serif; " + 933 "background-color: #e2e2e2; width: 400px; height: 300px; " + 934 "left: 50%; top: 50%; margin-left: -220px; margin-top: -150px; " + 935 "text-align: left; padding: 20px; " + 936 "border: 1px solid #ccc; border-radius: 6px; " + 937 "-moz-box-shadow: 0 6px 25px #808080; " + 938 "-webkit-box-shadow: 0 6px 25px #808080; " + 939 "box-shadow: 0 6px 25px #808080; " + 940 "}", 941 modalCloseIconCSS = ".rhelper-modal-close-icon { " + 942 "background: url(\"/img/ui/close-icon.png\") no-repeat scroll 0 0 transparent; " + 943 "position: absolute; height: 20px;
943 width: 20px; right: -10px; top: -10px; " + 944 "}" + 945 ".rhelper-modal-close-icon:hover { cursor: pointer; }", 946 modalTitleCSS = ".rhelper-modal-title { font-weight: bold; font-size: 20px; line-height: 24px; }", 947 modalContentCSS = ".rhelper-modal-content { height: 200px; padding: 10px 0; }", 948 modalCloseCSS = ".rhelper-modal-close-button { " + 949 "text-transform: uppercase; padding: 4px 8px; " + 950 "border: 1px solid #e96527; border-radius: 4px; " + 951 "background-color: #fff; " + 952 "}", 953 modalOverCloseCSS = ".rhelper-modal-close-button:hover { " + 954 "color: #e96527; " + 955 "-moz-box-shadow: 0 2px 6px #808080; " + 956 "-webkit-box-shadow: 0 2px 6px #808080; " + 957 "box-shadow: 0 2px 6px #808080; " + 958 "}", 959 moreInfoPopupCSS = ".rhelper-more-info-popup { display: none; position: absolute; }", 960 moreInfoCSS = ".rhelper-more-info-popup .rhelper-more-info { " + 961 "background-color: white; border: 1px solid #ccc;" + 962 "-moz-border-radius: 6px; -webkit-border-radius: 6px; border-radius: 6px;" + 963 "-moz-box-shadow: 0 0 10px 2px #c3c3c3;" + 964 "-webkit-box-shadow: 0 0 10px 2px #c3c3c3;" + 965 "box-shadow: 0 2px 10px 2px #c3c3c3;" + 966 "padding: 20px; width: 160px;" + 967 "position: relative;" + 968 "z-index: 9;" + 969 "}", 970 moreInfoPointerCSS = ".rhelper-more-info-popup .more-info-pointer {" + 971 "background: transparent url(/img/new_submission/more_info_pointer.png) no-repeat center center;" + 972 "width: 20px; height: 10px; margin: -1px 0 0 90px;" + 973 "position: relative; z-index: 10;" + 974 "}", 975 pageFaderCSS = ".rhelper-page-fader {" + 976 "position: fixed; top: 115px; left: 0; bottom: 0; width: 100%;" + 977 "background-color: white; z-index: 1000;" + 978 "}"; 979 helperStyles.append(bgmaskCSS); 980 helperStyles.append(bgMessageCSS); 981 helperStyles.append(bgTickerCSS); 982 helperStyles.append(modalWindowCSS); 983 helperStyles.append(modalCloseIconCSS); 984 helperStyles.append(modalCloseCSS); 985 helperStyles.append(modalOverCloseCSS); 986 helperStyles.append(modalTitleCSS); 987 helperStyles.append(modalContentCSS); 988 helperStyles.append(moreInfoPopupCSS); 989 helperStyles.append(moreInfoCSS); 990 helperStyles.append(moreInfoPointerCSS); 991 helperStyles.append(pageFaderCSS); 992 } 993 // END OF THE STYLES CREATION FUNCTION 994 // ================================================================================ 995 996 // Returns a function, that, as long as it continues to be invoked, will not 997 // be triggered. The function will be called after it stops being called for 998 // N milliseconds. If `immediate` is passed, trigger the function on the 999 // leading edge, instead of the trailing. 1000 function debounce(func, wait, immediate) { 1001 var timeout; 1002 return function() { 1003 var context = this, args = arguments; 1004 var later = function() { 1005 timeout = null;
1006 if (!immediate) func.apply(context, args); 1007 }; 1008 var callNow = immediate && !timeout; 1009 clearTimeout(timeout); 1010 timeout = setTimeout(later, wait); 1011 if (callNow) func.apply(context, args); 1012 }; 1013 }; 1014 1015 //check file extension 1016 function hasExtension(fileName, exts) { 1017 return (new RegExp('(' + exts.join('|').replace(/\./g, '\\.') + ')$')).test(fileName); 1018 } 1019 1020 return publicProperties; 1021 } 1022 1023});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.