1/* global mejs:false */ 2/** 3 * open content in overlay 4 * @module overlay 5 * @param {jQuery} $ Instance of jQuery 6 * @return {Object} List of overlay methods 7 */ 8XA.component.overlay = function ($) { 9 /** 10 * This object stores all public api methods 11 * @type {Object.<Methods>} 12 * @memberOf module:overlay 13 * */ 14 var api = {}, 15 href = window.location.href, 16 host = location.host, 17 label, 18 overlayPlaceholder = false, 19 marginTop = 100, 20 focusableElementsString = 'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"], [contenteditable]', 21 firstTabStop, 22 lastTabStop, 23 overlayClickSource; 24 /** 25 * isPreviewMode check if page in preview mode 26 * @memberOf module:overlay 27 * @private 28 * @returns {Boolean} is page in a preview mode 29 */ 30 function isPreviewMode() { 31 if (href.indexOf("sc_mode=preview") > -1) { 32 return true; 33 } 34 var $hdPageMode = $('#hdPageMode'); 35 36 return $hdPageMode.length > 0 && $hdPageMode.attr('value') == 'preview'; 37 } 38 39 40 /** 41 * isOverlayPage check if "#wrapper" element has class "overlay-page" 42 * @memberOf module:overlay 43 * @private 44 * @returns {Boolean} is #wrapper an overlay page 45 */ 46 function isOverlayPage() { 47 return $('#wrapper').hasClass('overlay-page'); 48 } 49 /** 50 * hasOverlayContent check if "overlay-source" 51 * element present on a page 52 * @memberOf module:overlay 53 * @private 54 * @returns {Boolean} is overlay-source present on a page 55 */ 56 function hasOverlayContent() { 57 return $(".overlay-source").length; 58 } 59 /** 60 * hasSpinnerContent check if "overlay-source" 61 * element present on a page 62 * @memberOf module:spinner 63 * @private 64 * @returns {Boolean} is spinner-source present on a page 65 */ 66 function hasSpinnerContent() { 67 return $(".spinner-wrapper").length; 68 } 69 /** 70 * resizeOverlay resize overlay 71 * @memberOf module:overlay 72 * @param {jQuery<Object>} inner ".overlay-inner" 73 * @param {jQuery<Object>} content (".component-content"), 74 * @param {Object} options contains size of overlay 75 * @param {number} [options.width] width of overlay 76 * @param {number} [options.height] height of overlay 77 * @param {string} [options.percent] units of width and height 78 * @alias module:overlay.resizeOverlay 79 */ 80 api.resizeOverlay = function (inner, content, options) { 81 var unit = "px"; 82 var css = { 83 "width": "", 84 "height": "" 85 }; 86 var wh = $(window).height(); 87 88 if (options.percent) { 89 unit = "%"; 90 inner.addClass("overlay-percent"); 91 } else { 92 inner.removeClass("overlay-percent"); 93 } 94 95 if (options.width) { 96 css["width"] = options.width + unit; 97 } 98 if (options.height) { 99 css["height"] = options.height + unit; 100 } 101 102 css["max-height"] = (wh - marginTop - 0.1 * wh) + "px"; 103 104 content.css(css); 105 } 106 /** 107 * getUrlVariables get variables provided in overlay url 108 * @memberOf module:overlay 109 * @param {String} url url of overlay content 110 * @private 111 * @returns {Object} list of get parameters 112 */ 113 function getUrlVariables(url) { 114 var q = url.split('?')[1], 115 vars = [], 116 hash; 117 118 if (q != undefined) { 119 q = q.split('&'); 120 for (var i = 0; i < q.length; i++) { 121 hash = q[i].split('='); 122 vars.push(hash[1]); 123 vars[hash[0]] = hash[1]; 124 } 125 } 126 127 return vars; 128 } 129 /** 130 * getSize check if overlay has width or height in url 131 * and set up this values 132 * @memberOf module:overlay 133 * @param {String} vars variables from url of overlay content 134 * @private 135 * @returns {Object} sizes of overlay 136 */ 137 function getSize(vars) { 138 var obj = {}; 139 140 if (vars["width"] !== null) {
141 obj["width"] = vars["width"]; 142 } 143 144 if (vars["height"] !== null) { 145 obj["height"] = vars["height"]; 146 } 147 148 return obj; 149 } 150 /** 151 * checkInternal checks if overlay content is internal resource 152 * @memberOf module:overlay 153 * @param {String} url url of overlay content 154 * @private 155 * @returns {Boolean} true - content is internal| false - content is external 156 */ 157 function checkInternal(url) { 158 if (url.indexOf(host) > -1) { 159 return true; 160 } 161 return false; 162 } 163 /** 164 * checkImage checks if overlay content is an image 165 * @memberOf module:overlay 166 * @param {String} url url of overlay content 167 * @private 168 * @returns {Boolean} true - content is an image| false - content not an a image 169 */ 170 function checkImage(url) { 171 var ext = url.split("?")[0].split('.').pop(); 172 if ($.inArray(ext, ['gif', 'png', 'jpg', 'jpeg']) > -1) { 173 return true; 174 } 175 176 return false; 177 } 178 179 /** 180 * loadOverlay creates overlay content and show it 181 * @memberOf module:overlay 182 * @param {String} url url of overlay 183 * @param {jQuery<DOMElement>} overlay overlay DOMElement 184 * @private 185 */ 186 function loadOverlay(url, overlay) { 187 var content = overlay.find(".overlay-inner"), 188 overlayContent = overlay.find(".component-content"), 189 vars = getUrlVariables(url), 190 internalLink = checkInternal(url), 191 overlaySize = getSize(vars), 192 suffix; 193 overlayContent.addClass('overlayFullWidth'); 194 content.removeAttr('style'); 195 if (internalLink) { 196 if (checkImage(url)) { 197 content.empty().append($("<img>", { src: url })); 198 content.css(overlaySize); 199 overlayContent.removeClass('overlayFullWidth'); 200 showOverlay(overlay); 201 } else if (url.indexOf("overlaytype=iframe") > -1) { 202 content.empty().append($("<iframe>", { src: url, style: "width: 100%; height: 100%" })); 203 content.css(overlaySize); 204 showOverlay(overlay); 205 } else { 206 if (isPreviewMode()) { 207 suffix = "cf_overlay=1"; 208 url = url.replace("sitecore/shell/"); 209 url += (url.indexOf("?") == -1 ? "?" : "&") + suffix; 210 } 211 212 $.get(url, function (data) { 213 var overlayData = $(data).before().first(); 214 215 api.resizeOverlay(content, overlayContent, { 216 width: overlayData.attr("data-width"), 217 height: overlayData.data("height"), 218 percent: overlayData.data("percent") 219 }); 220 221 content.empty().append(data); 222 XA.init(); 223 showOverlay(overlay); 224 hideSpinner(); 225 }); 226 } 227 } else { 228 if (checkImage(url)) { 229 content.empty().append($("<img>", { src: url })); 230 } else { 231 content.empty().append($("<iframe >", { src: url, style: "width: 100%; height: 100%" })); 232 } 233 content.css(overlaySize); 234 showOverlay(overlay); 235 } 236 237 } 238 /** 239 * preShowOverlay sets opacity to 1 and shows overlay 240 * @memberOf module:overlay 241 * @param {jQuery<DOMElement>} overlay overlay DOMElement 242 * @private 243 */ 244 function preShowOverlay(overlay) { 245 // overlay.css({ 246 // "opacity": 1 247 // }).show(); 248 showSpinner(); 249 } 250 /** 251 * showOverlay makes overlay visible 252 * @memberOf module:overlay 253 * @param {jQuery<DOMElement>} overlay overlay DOMElement 254 * @private 255 * @returns {jQuery<DOMElement>} overlay overlay DOMElement 256 */ 257 function showOverlay(overlay) { 258 var close, content; 259 overlay.show().animate({ 260 opacity: 1 261 }); 262 263 // hides wrapper data from screen readers 264 $("#wrapper").addClass("aria-hidden"); 265 266 overlayClickSource = document.activeElement; 267 268 close = overlay.find(".overlay-close"); 269 setTimeout(function () { close.focus(); }, 0); 270 271 content = overlay.find(".overlay-inner"); 272 content.blur(function (args) { 273 args.preventDefault(); 274 args.stopPropagation(); 275 setTimeout(function () { close.focus() }, 0); 276 }); 277 278 // Finds all focusable children 279 var focusableElements = content.find(focusableElementsString); 280 281 // Converts NodeList to Array 282 focusableElements = Array.prototype.slice.call(focusableElements);
283 firstTabStop = focusableElements[0]; 284 lastTabStop = focusableElements[focusableElements.length - 1]; 285 286 // Focus first 287 firstTabStop.focus(); 288 return overlay; 289 } 290 /** 291 * showSpinner makes spinner visible 292 * @memberOf module:overlay 293 * @param {jQuery<DOMElement>} spinner overlay DOMElement 294 * @private 295 * @returns {jQuery<DOMElement>} spinner overlay DOMElement 296 */ 297 function showSpinner() { 298 $(".spinner-wrapper").show(); 299 } 300 /** 301 * hideOverlay hide overlay 302 * @memberOf module:overlay 303 * @private 304 */ 305 function hideOverlay(overlay) { 306 $("#wrapper").removeClass("aria-hidden"); 307 var content = overlay.find(".overlay-inner"); 308 309 overlay.animate({ opacity: 0 }, 310 function () { 311 overlay.hide(); 312 content.empty(); 313 314 if (mejs) { 315 for (var p in mejs.players) { 316 if ($("#" + mejs.players[p].id).parents(".overlay").length == 1) { 317 $("#" + mejs.players[p].id + ' video').attr('src', ''); 318 mejs.players[p].remove(); 319 mejs.players.splice(p, 1); 320 } 321 } 322 } 323 } 324 ); 325 326 overlay.removeClass('sticky'); 327 //console.debug('DEBUG: Removed "sticky" from deconstructed overlay: ', !overlay.hasClass('sticky'), overlay) 328 329 return overlay; 330 } 331 /** 332 * hideOverlay hide spinner 333 * @memberOf module:spinner 334 * @private 335 */ 336 function hideSpinner() { 337 $(".spinner-wrapper").hide(); 338 } 339 /** 340 * createOverlay creates a markup for overlay and appends it to body 341 * @memberOf module:overlay 342 * @private 343 */ 344 function createOverlay() { 345 var overlay = "<div class='overlay-wrapper'>" + 346 "<div class='overlay component'>" + 347 "<div class='component-content' role='dialog'>" + 348 "<div class='overlay-inner'></div>" + 349 "<div class='overlay-close' role='button' aria-label='Close dialog'></div>" + 350 "</div>" + 351 "</div>" + 352 "</div>"; 353 354 $("body").append(overlay); 355 } 356 /** 357 * createSpinner creates a markup for spinner and appends it to body 358 * @memberOf module:spinner 359 * @private 360 */ 361 function createSpinner() { 362 var spinner = "<div class='spinner-wrapper' style='display: none;'> "+ 363 "<span class='spinner'></span>" + 364 "</div>"; 365 366 $(".overlay-wrapper").append(spinner); 367 } 368 /** 369 * initInstance method prevent event propagation and call 370 * ["preShowOverlay"]{@link module:overlay.preShowOverlay} and 371 * ["loadOverlay"]{@link module:overlay.loadOverlay} methods 372 * @memberOf module:overlay 373 * @method 374 * @param {jQuery} component Root DOM element of archive component wrapped by jQuery 375 * @param {jQuery<DOMElement>} overlay overlay DOMElement 376 * @param {jQuery<DOMElement>} overlayContent overlay content DOMElement 377 * @alias module:overlay.initInstance 378 */ 379 api.initInstance = function (component, overlay, overlayContent) { 380 component.on("click", 381 function (event) { 382 event.preventDefault(); 383 event.stopPropagation(); 384 preShowOverlay(overlay, overlayContent); 385 386 //console.debug('DEBUG: Initializing an overlay instance', overlay, 'for component', component) 387 var isSticky = component.hasClass('overlay-sticky'); 388 //console.debug('DEBUG: Component ', component, ' is marked as sticky?: ', isSticky) 389 if (isSticky){ 390 //console.debug('DEBUG: Adding class "sticky" to overlay: ', overlay) 391 overlay.addClass('sticky'); 392 } 393 394 var uri = this.href; 395 loadOverlay(uri, overlay); 396 397 var href = this.href.split('/'); 398 for (var i = 0; i <= href.length; i++) { 399 label = href.pop();
400 if (label.length == 0) { 401 continue; 402 } 403 break; 404 } 405 }); 406 } 407 /** 408 * init method makes preparation for overlay content, binds events 409 * for proper work of overlay and 410 * calls in a loop for each instance of overlay 411 * [".initInstance"]{@link module:Accordion.initInstance} method. 412 * @memberOf module:overlay 413 * @alias module:overlay.init 414 */ 415 api.init = function () { 416 var overlayContent, 417 overlaySource, 418 overlaySticky, 419 overlayInner, 420 overlayCloseLink, 421 closeAction, 422 page, 423 overlay, 424 content; 425 426 if (!overlayPlaceholder && hasOverlayContent()) { 427 createOverlay(); 428 } 429 430 if(hasSpinnerContent() == 0) { 431 createSpinner(); 432 } 433 434 if (isOverlayPage()) { 435 436 page = $(".overlay-page"); 437 overlayContent = page.children(".component-content"); 438 overlay = $("#spnOverlay"); 439 content = overlayContent.children(".overlay-inner"); 440 441 api.resizeOverlay(content, overlayContent, { 442 width: overlayContent.data("width"), 443 height: overlayContent.data("height"), 444 percent: overlayContent.data("percent") 445 }); 446 overlayContent.on("click", function (event) { 447 event.stopPropagation(); 448 }); 449 page.on("click", function () { 450 if (isPreviewMode()) { 451 location.href = location.href.replace("sc_mode=preview", "sc_mode=edit"); 452 } 453 }); 454 } 455 overlay = $(".overlay-wrapper > .overlay"); 456 overlayContent = overlay.find(".component-content"); 457 overlaySource = $(".overlay-source a:not(.initialized), a.overlay-source:not(.initialized)"); 458 overlayInner = $(".overlay-inner"); 459 overlayCloseLink = overlay.find(".overlay-close"); 460 461 isSticky = function isSticky(el) { 462 var $el = $(el), $overlay; 463 464 if ($el.hasClass('overlay') && $el.parent().hasClass('overlay-wrapper')){ 465 $overlay = $el; 466 } else { 467 $overlay = $(el).closest('.overlay-wrapper > .overlay'); 468 } 469 470 return overlay.hasClass('sticky'); 471 } 472 473 closeAction = function () { 474 //console.debug('DEBUG: closeAction() called'); 475 hideOverlay(overlay); 476 overlayInner.off("blur"); 477 setTimeout(function () { 478 if (overlayClickSource != null) { 479 overlayClickSource.focus(); 480 } 481 }, 0); 482 }; 483 484 if (!overlayPlaceholder) { 485 overlayContent.on("click", function (event) { 486 //console.debug('DEBUG: overlayContent was clicked, stopPropagation()'); 487 event.stopPropagation(); 488 }); 489 490 overlay.on("click", function () { 491 //console.debug('DEBUG: overlay got clicked', $(this)); 492 if (!overlay.hasClass('sticky')){ 493 //console.debug('DEBUG: overlay is not sticky, decided to close'); 494 closeAction(); 495 } 496 }); 497 498 overlayCloseLink.on("click", function (args) { 499 //console.debug('DEBUG: overlayCloseLink was clicked'); 500 args.preventDefault(); 501 closeAction(); 502 }); 503 504 $("body").keydown(function (e) { 505 //console.debug('DEBUG: keydown event on body; keyCode: ', e.keyCode); 506 // Check for TAB key press 507 if (e.keyCode === 9) { 508 // SHIFT + TAB 509 if (e.shiftKey) { 510 if (document.activeElement === firstTabStop) { 511 e.preventDefault(); 512 lastTabStop.focus(); 513 } 514 515 // TAB 516 } else if (document.activeElement === lastTabStop) { 517 e.preventDefault(); 518 // firstTabStop.attr('tabindex', 0); 519 firstTabStop.focus(); 520 } 521 } 522 523 // ESCAPE 524 if (e.keyCode === 27) { 525 //console.debug('DEBUG: keydown event caused by ESC'); 526 e.stopPropagation(); 527 if (!overlay.hasClass('sticky')){ 528 //console.debug('DEBUG: overlay is not sticky, decided to close'); 529 closeAction(); 530 } 531 } 532 }); 533 534 $(window).on("resize", function () { 535 var height = $(window).height(); 536 height = height - marginTop - 0.1 * height; 537 overlayContent.css("max-height", height + "px"); 538 }); 539 540 overlayPlaceholder = true; 541 } 542 543 544 overlaySource.each(function () { 545 api.initInstance($(this), overlay, overlayContent); 546 $(this).addClass("initialized"); 547 }); 548 549 550 }; 551 552 return api; 553 554}(jQuery); 555 556XA.register("overlay", XA.component.overlay); 557 558 559[].forEach.call(document.querySelectorAll('.search-results.overlay-source'), function (e) { 560 XA.dom.observeDOM(e, function () { XA.component.overlay.init(); }); 561});
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.