1; 2/** 3 * LearnPress frontend course app. 4 * 5 * @version 3.x.x 6 * @author ThimPress 7 * @package LearnPress/JS/Course 8 */ 9(function ($, LP, _) { 10 11 'use strict'; 12 13 function LP_Storage(key) { 14 var storage = window.localStorage; 15 this.key = key; 16 this.get = function (id) { 17 var val = storage.getItem(this.key) || '', 18 sections = val.split(','); 19 if (id) { 20 id = id + ''; 21 var pos = sections.indexOf(id); 22 if (pos >= 0) { 23 return sections[pos]; 24 } 25 } 26 return sections; 27 } 28 this.set = function (sections) { 29 if (typeof sections !== 'string') { 30 sections = sections.join(','); 31 } 32 storage.setItem(this.key, sections); 33 return sections.split(','); 34 } 35 this.hasSection = function (id) { 36 id = id + ''; 37 var sections = this.get(), 38 at = sections.indexOf(id); 39 40 return at >= 0 ? at : false; 41 } 42 this.add = function (id) { 43 id = id + ''; 44 var sections = this.get(); 45 if (this.hasSection(id)) { 46 return; 47 } 48 sections.push(id); 49 this.set(sections); 50 return sections; 51 } 52 this.remove = function (id) { 53 id = id + ''; 54 var at = this.hasSection(id); 55 if (at !== false) { 56 var sections = this.get(); 57 sections.splice(at, 1); 58 this.set(sections); 59 return sections; 60 } 61 return false; 62 } 63 } 64 65 /** 66 * LP_Course 67 * 68 * @param settings 69 * @constructor 70 */ 71 function LP_Course(settings) { 72 73 var sectionStorage = new LP_Storage('sections'), 74 $body = $('body'), 75 $content = $('.content-item-scrollable'), 76 $curriculum = $('#learn-press-course-curriculum'), 77 $contentItem = $('#learn-press-content-item'), 78 $curriculumScrollable = $curriculum.find('.curriculum-scrollable'), 79 $header = $('#course-item-content-header'), 80 $footer = $('#course-item-content-footer'), 81 $courseItems = $curriculum.find('.course-item'), 82 isShowingHeader = true, 83 fullScreen, contentTop = 0, headerTimer, 84 inPopup = false; 85 86 /** 87 * Toggle answer option check/uncheck 88 */ 89 function toggleAnswerOptions(event) { 90 var $el = $(event.target), 91 $chk; 92 if ($el.is('input.option-check')) { 93 return; 94 } 95 96 $chk = $el.closest('.answer-option').find('input.option-check'); 97 98 if (!$chk.length) { 99 return; 100 } 101 102 if ($chk.is(':disabled')) { 103 return; 104 } 105 if ($chk.is(':checkbox')) { 106 $chk[0].checked = !$chk[0].checked; 107 } else { 108 $chk[0].checked = true; 109 } 110 } 111 112 /** 113 * Show/Hide section content 114 */ 115 function toggleSection() { 116 var id = $(this).closest('.section').data('section-id'); 117 $(this).siblings('.section-content').slideToggle(function () { 118 if ($(this).is(':visible')) { 119 sectionStorage.remove(id); 120 } else { 121 sectionStorage.add(id); 122 } 123 }); 124 } 125 126 /** 127 * Init sections 128 */ 129 function initSections() { 130 var $activeSection = $('.course-item.current').closest('.section'), 131 sections = $('.curriculum-sections').find('.section'), 132 sectionId = $activeSection.data('section-id'), 133 hiddenSections = []; 134 135 if ($activeSection) { 136 hiddenSections = sectionStorage.remove(sectionId); 137 } else { 138 hiddenSections = sectionStorage.get(); 139 } 140 141 for (var i = 0; i < hiddenSections.length; i++) { 142 sections.filter('[data-section-id="' + hiddenSections[i] + '"]').find('.section-content').hide(); 143 } 144 } 145 146 /** 147 * Prepare form before submitting 148 * 149 * @param form 150 */ 151 function prepareForm(form) { 152 var $answerOptions = $('.answer-options'), 153 $form = $(form), 154 data = $answerOptions.serializeJSON(), 155 $hidden = $('<input type="hidden" name="question-data" />').val(JSON.stringify(data)); 156 157 if (($form.attr('method') + '').toLowerCase() !== 'post') { 158 return; 159 } 160 161 $form.find('input[name="question-data"]').remove(); 162 return $form.append($hidden).append($('<div />').append($answerOptions.clone()).hide()); 163 } 164 165 /** 166 * Tab course event 167 * 168 * @param e 169 * @param tab 170 */ 171 function onTabCourseClick(e, tab) { 172 173 if ($(document.body).hasClass('course-item-popup')) { 174 return; 175 } 176 177 var $tab = $(tab), 178 $parent = $tab.closest('.course-nav'); 179 180 if ($parent.siblings().length === 0) { 181 return; 182 } 183 LP.setUrl($tab.attr('href')) 184 } 185 186 /** 187 * Event on press any key into search 188 * 189 * @param e 190 * @returns {boolean} 191 */ 192 function onSearchInputKeypress(e) { 193 194 if (e.type === 'keypress' && e.keyCode === 13) { 195 return false; 196 } 197 198 var s = this.value, 199 r = new RegExp(s, 'ig'); 200 $courseItems.map(function () { 201 var $item = $(this), 202 itemName = $item.find('.item-name').text(); 203 if (itemName.match(r) || !s.length) { 204 $item.show(); 205 } else { 206 $item.hide(); 207 } 208 }); 209 210 $('.section').show().each(function () { 211 if (s.length) { 212 if (!$(this).find('.section-content').children(':visible').length) { 213 $(this).hide(); 214 } else { 215 $(this).show(); 216 } 217 } else { 218 $(this).show(); 219 } 220 }); 221 $(this).closest('.course-item-search').toggleClass('has-keyword', !!this.value.length); 222 } 223 224 function onClearSearchInputClick(e) { 225 var $form = $(this).closest('.course-item-search'); 226 $form.find('input').val('').trigger('keyup') 227 } 228 229 function onClickQM() { 230 $('#qm').css({'z-index': 999999999, position: 'relative'}); 231 $('html, body').css('overflow', 'auto'); 232 } 233 234 function getCurriculumWidth() { 235 return $curriculum.outerWidth(); 236 } 237 238 function maybeShowCurriculum(e) { 239 var offset = $(this).offset(), 240 offsetX = e.pageX - offset.left, 241 curriculumWidth = getCurriculumWidth(); 242 243 if (!fullScreen || (offsetX > 50)) { 244 return; 245 } 246 247 timeoutToClose(); 248 249 if (!isShowingHeader) { 250 $curriculum.stop().animate({ 251 left: 0 252 }); 253 254 $contentItem.stop().animate({ 255 left: curriculumWidth 256 }); 257 258 $footer.stop().animate({ 259 left: curriculumWidth 260 }, function () { 261 $(document, window).trigger('learn-press/toggle-content-item'); 262 }); 263 264 $header.find('.course-item-search').show(); 265 toggleEventShowCurriculum(true); 266 isShowingHeader = true; 267 } 268 } 269 270 function toggleEventShowCurriculum(b) { 271 $(document)[b ? 'off' : 'on']('mousemove.maybe-show-curriculum', 'body', maybeShowCurriculum); 272 } 273 274 function timeoutToClose() { 275 headerTimer && clearTimeout(headerTimer); 276 headerTimer = setTimeout(function () { 277 var curriculumWidth = getCurriculumWidth(); 278 279 if (!fullScreen) { 280 return; 281 } 282 283 $curriculum.stop().animate({ 284 left: -curriculumWidth 285 }); 286 287 $contentItem.stop().animate({ 288 left: 0 289 }); 290 291 $footer.stop().animate({ 292 left: 0 293 }, function () { 294 $(document, window).trigger('learn-press/toggle-content-item'); 295 }); 296 297 $header.find('.course-item-search').hide(); 298 299 isShowingHeader = false; 300 toggleEventShowCurriculum(); 301 }, 3000); 302 } 303 304 function toggleContentItem(e) { 305 e.preventDefault(); 306 var curriculumWidth = getCurriculumWidth(); 307 fullScreen = $body.toggleClass('full-screen-content-item').hasClass('full-screen-content-item'); 308 $curriculum 309 .stop() 310 .animate({ 311 left: fullScreen ? -curriculumWidth : 0 312 }); 313 314 $contentItem 315 .stop() 316 .animate({ 317 left: fullScreen ? 0 : curriculumWidth 318 }); 319 320 $footer.stop().animate({ 321 left: fullScreen ? 0 : curriculumWidth 322 }, function () { 323 $(document, window).trigger('learn-press/toggle-content-item'); 324 }); 325 326 isShowingHeader = !fullScreen;
327 window.localStorage && window.localStorage.setItem('lp-full-screen', fullScreen ? 'yes' : 'no'); 328 329 fullScreen && toggleEventShowCurriculum(); 330 $header.find('.course-title').stop().animate({marginLeft: fullScreen ? -curriculumWidth : 0}) 331 $header.find('.course-item-search').stop().animate({opacity: fullScreen ? 0 : 1}); 332 } 333 334 function initEvents() { 335 // Live events 336 $(document) 337 .on('learn-press/nav-tabs/clicked', onTabCourseClick) 338 .on('keyup keypress', '.course-item-search input', onSearchInputKeypress) 339 .on('click', '.course-item-search button', onClearSearchInputClick) 340 .on('click', '#wp-admin-bar-query-monitor', onClickQM) 341 .on('click', '.answer-options .answer-option', toggleAnswerOptions) 342 .on('click', '.section-header', toggleSection) 343 .on('submit', 'form.lp-form', function () { 344 prepareForm(this); 345 }).on('click', '.toggle-content-item', toggleContentItem); 346 347 $curriculum.hover(function () { 348 headerTimer && clearTimeout(headerTimer); 349 }, function () { 350 if (fullScreen) timeoutToClose(); 351 }) 352 353 } 354 355 function initScrollbar() { 356 $content.addClass('scrollbar-light') 357 .scrollbar({ 358 scrollx: false 359 }); 360 361 $content.parent().css({ 362 position: 'absolute', 363 top: 0, 364 bottom: $('#course-item-content-footer:visible').outerHeight() || 0, 365 width: '100%' 366 }).css('opacity', 1).end().css('opacity', 1); 367 368 369 $curriculumScrollable.addClass('scrollbar-light') 370 .scrollbar({ 371 scrollx: false 372 }); 373 374 $curriculumScrollable.parent().css({ 375 position: 'absolute', 376 top: 0, 377 bottom: 0, 378 width: '100%' 379 }).css('opacity', 1).end().css('opacity', 1); 380 } 381 382 function fitVideo() { 383 var $wrapContent = $('.content-item-summary.content-item-video'); 384 385 if (!$wrapContent.length) { 386 return; 387 } 388 389 var $entryVideo = $wrapContent.find('.entry-video'), 390 $frame = $entryVideo.find('iframe'), 391 width = $frame.attr('width'), 392 height = $frame.attr('height'), 393 ratio = 1, 394 contentHeight, timer; 395 396 function resizeVideo() { 397 var frameWidth = $frame.width(); 398 contentHeight = frameWidth * ratio; 399 $frame.css({ 400 height: contentHeight, 401 marginLeft: ( $entryVideo.width() - frameWidth) / 2 402 }); 403 404 $wrapContent.css({ 405 paddingTop: contentHeight 406 }); 407 } 408 409 if (!$entryVideo.length) { 410 return false; 411 } 412 413 if (width && height) { 414 if (width.indexOf('%') === -1 && height.indexOf('%') === -1) { 415 ratio = height / width; 416 } 417 } 418 419 $(window).on('resize.fit-content-video learn-press/toggle-content-item', function () { 420 timer && clearTimeout(timer); 421 timer = setTimeout(resizeVideo, 250); 422 }).trigger('resize.fit-content-video'); 423 424 $('.content-item-scrollable').scroll(function () { 425 $(this).find('.entry-video').css('padding-top', this.scrollTop); 426 }); 427 } 428 429 /** 430 * Init 431 */ 432 function init() { 433 inPopup = $body.hasClass('course-item-popup'); 434 initSections(); 435 initEvents(); 436 437 438 if (!inPopup) { 439 return; 440 } 441 442 $contentItem.appendTo($body); 443 $curriculum.appendTo($body); 444 445 if ($('#wpadminbar').length) { 446 $body.addClass('wpadminbar'); 447 contentTop = 32; 448 } 449 450 initScrollbar(); 451 fitVideo(); 452 453 fullScreen = window.localStorage && 'yes' === window.localStorage.getItem('lp-full-screen'); 454 if($(window).width()<=768){ 455 fullScreen = true; 456 } 457 if (fullScreen) { 458 var curriculumWidth = getCurriculumWidth(); 459 $body.addClass('full-screen-content-item'); 460 $contentItem.css('left', 0); 461 $curriculum.css('left', -curriculumWidth);
462 $footer.css('left', 0); 463 isShowingHeader = !fullScreen; 464 $header.find('.course-title').css({marginLeft: fullScreen ? -curriculumWidth : 0}) 465 $header.find('.course-item-search').css({opacity: fullScreen ? 0 : 1}); 466 toggleEventShowCurriculum(); 467 } 468 469 setTimeout(function () { 470 var $cs = $body.find('.curriculum-sections').parent(); 471 $cs.scrollTo($cs.find('.course-item.current'), 100); 472 473 if (window.location.hash) { 474 $('.content-item-scrollable:last').scrollTo($(window.location.hash)); 475 } 476 }, 300); 477 478 $body.css('opacity', 1); 479 480 } 481 482 new LP.Alerts(); 483 484 init(); 485 } 486 487 LP.Alerts = function () { 488 this.isShowing = false; 489 var $doc = $(document), 490 self = this, 491 trigger = function (action, args) { 492 var triggered = $doc.triggerHandler(action, args); 493 494 if (triggered !== undefined) { 495 return triggered; 496 } 497 498 return $.isArray(args) ? args[0] : undefined; 499 }, 500 confirmHandle = function (e) { 501 try { 502 var $form = $(this), 503 message = $form.data('confirm'), 504 action = $form.data('action'); 505 506 message = trigger('learn-press/confirm-message', [message, action]); 507 508 if (!message) { 509 return true; 510 } 511 512 jConfirm(message, '', function (confirm) { 513 confirm && $form.off('submit.learn-press-confirm', confirmHandle).submit(); 514 self.isShowing = false; 515 }); 516 517 self.isShowing = true; 518 519 return false; 520 } catch (ex) { 521 console.log(ex) 522 } 523 524 return true; 525 } 526 527 this.watchChange('isShowing', function (prop, oldVal, newVal) { 528 if (newVal) { 529 setTimeout(function () { 530 $.alerts._reposition(); 531 $('#popup_container').addClass('ready') 532 }, 30) 533 534 var $a = $('<a href="" class="close"><i class="fa fa-times"></i></a>') 535 $('#popup_container').append($a); 536 $a.on('click', function () { 537 $.alerts._hide(); 538 return false; 539 }); 540 } 541 $(document.body).toggleClass('confirm', newVal); 542 return newVal; 543 }); 544 545 var $forms = $('form[data-confirm]').on('submit.learn-press-confirm', confirmHandle); 546 } 547 548 549 $(document).ready(function () { 550 $(document).ready(function () { 551 new LP_Course({}); 552 553 $(this).on('submit', 'form[name="course-external-link"]', function () { 554 var redirect = $(this).attr('action'); 555 if (redirect) { 556 window.location.href = redirect; 557 return false; 558 } 559 }) 560 }); 561 }); 562}) 563(jQuery, LP, _);
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.