| @@ -41,8 +41,9 @@ | ||
| 41 | 41 | $admin_user = JFactory::getUser(); |
| 42 | 42 | |
| 43 | 43 | $has_vcm = is_file(VCM_SITE_PATH.DIRECTORY_SEPARATOR.'helpers'.DIRECTORY_SEPARATOR.'lib.vikchannelmanager.php'); |
| 44 | 44 | $backlogo = VikBooking::getBackendLogo(); |
| 45 | + $vbo_auth_admin = $admin_user->authorise('core.admin', 'com_vikbooking'); | |
| 45 | 46 | $vbo_auth_global = $admin_user->authorise('core.vbo.global', 'com_vikbooking'); |
| 46 | 47 | $vbo_auth_rateplans = $admin_user->authorise('core.vbo.rateplans', 'com_vikbooking'); |
| 47 | 48 | $vbo_auth_rooms = $admin_user->authorise('core.vbo.rooms', 'com_vikbooking'); |
| 48 | 49 | $vbo_auth_pricing = $admin_user->authorise('core.vbo.pricing', 'com_vikbooking'); |
| @@ -49,8 +50,10 @@ | ||
| 49 | 50 | $vbo_auth_bookings = $admin_user->authorise('core.vbo.bookings', 'com_vikbooking'); |
| 50 | 51 | $vbo_auth_availability = $admin_user->authorise('core.vbo.availability', 'com_vikbooking'); |
| 51 | 52 | $vbo_auth_management = $admin_user->authorise('core.vbo.management', 'com_vikbooking'); |
| 52 | 53 | $vbo_auth_pms = $admin_user->authorise('core.vbo.pms', 'com_vikbooking'); |
| 54 | + $vbo_auth_reports = $admin_user->authorise('core.vbo.pmsreports', 'com_vikbooking'); | |
| 55 | + $vbo_auth_tm = $admin_user->authorise('core.vbo.tm', 'com_vikbooking'); | |
| 53 | 56 | $reviews_dld = 0; |
| 54 | 57 | |
| 55 | 58 | // check for stored quick actions only once |
| 56 | 59 | $admin_menu_actions_checked = $session->get('admin_menu.actions.check', null, 'vikbooking'); |
| @@ -125,9 +128,9 @@ | ||
| 125 | 128 | </li> |
| 126 | 129 | <?php endif; ?> |
| 127 | 130 | <?php if ($vbo_auth_global) : ?> |
| 128 | 131 | <li> |
| 129 | - <div class="<?php echo ($highlight == "11" || $highlight == 'backups' ? "vmenulinkactive" : "vmenulink"); ?>"> | |
| 132 | + <div class="<?php echo ($highlight == "11" || $highlight == 'backups' || $highlight == 'overrides' ? "vmenulinkactive" : "vmenulink"); ?>"> | |
| 130 | 133 | <a href="index.php?option=com_vikbooking&task=config"> |
| 131 | 134 | <?php VikBookingIcons::e('cogs'); ?> |
| 132 | 135 | <span class="vbo-submenu-item"> |
| 133 | 136 | <span class="vbo-submenu-item-txt"><?php echo JText::translate('VBMENUTWELVE'); ?></span> |
| @@ -253,9 +256,9 @@ | ||
| 253 | 256 | <ul class="vbo-submenu-ul" data-menu-scope="pricing"> |
| 254 | 257 | <li> |
| 255 | 258 | <div class="<?php echo ($highlight == "fares" ? "vmenulinkactive" : "vmenulink"); ?>"> |
| 256 | 259 | <a href="index.php?option=com_vikbooking&task=tariffs"> |
| 257 | - <?php VikBookingIcons::e('toolbox'); ?> | |
| 260 | + <?php VikBookingIcons::e('filter-circle-dollar'); ?> | |
| 258 | 261 | <span class="vbo-submenu-item"> |
| 259 | 262 | <span class="vbo-submenu-item-txt"><?php echo JText::translate('VBMENUPRICESTABLE'); ?></span> |
| 260 | 263 | </span> |
| 261 | 264 | </a> |
| @@ -317,10 +320,20 @@ | ||
| 317 | 320 | <span class="vbo-submenu-item"> |
| 318 | 321 | <span class="vbo-submenu-item-txt"><?php echo JText::translate('VBMENUQUICKRES'); ?></span> |
| 319 | 322 | </span> |
| 320 | 323 | </a> |
| 321 | - </div> | |
| 322 | - </li> | |
| 324 | + </div> | |
| 325 | + </li> | |
| 326 | + <li> | |
| 327 | + <div class="<?php echo ($highlight == "managequote" ? "vmenulinkactive" : "vmenulink"); ?>"> | |
| 328 | + <a href="index.php?option=com_vikbooking&view=managequote"> | |
| 329 | + <?php VikBookingIcons::e('file-alt'); ?> | |
| 330 | + <span class="vbo-submenu-item"> | |
| 331 | + <span class="vbo-submenu-item-txt"><?php echo JText::translate('VBO_CREATE_QUOTE'); ?></span> | |
| 332 | + </span> | |
| 333 | + </a> | |
| 334 | + </div> | |
| 335 | + </li> | |
| 323 | 336 | <?php endif; ?> |
| 324 | 337 | <?php if ($vbo_auth_availability) : ?> |
| 325 | 338 | <li> |
| 326 | 339 | <div class="<?php echo ($highlight == "15" ? "vmenulinkactive" : "vmenulink"); ?>"> |
| @@ -344,11 +357,11 @@ | ||
| 344 | 357 | </a> |
| 345 | 358 | </div> |
| 346 | 359 | </li> |
| 347 | 360 | <?php endif; ?> |
| 348 | - <?php if ($has_vcm && ($vbo_auth_availability || $vbo_auth_bookings)) : ?> | |
| 349 | - <li> | |
| 350 | - <div class="vmenulink"> | |
| 361 | + <?php if (($has_vcm || VBOPlatformDetection::isWordPress()) && ($vbo_auth_availability || $vbo_auth_bookings)) : ?> | |
| 362 | + <li class="vbo-menu-vcm-only"> | |
| 363 | + <div class="<?php echo ($highlight == 'vikchannelmanager' ? 'vmenulinkactive' : 'vmenulink'); ?>"> | |
| 351 | 364 | <a href="index.php?option=com_vikchannelmanager" class="vbo-menu-vcmlink"> |
| 352 | 365 | <?php VikBookingIcons::e('cloud'); ?> |
| 353 | 366 | <span class="vbo-submenu-item"> |
| 354 | 367 | <span class="vbo-submenu-item-txt"><?php echo JText::translate('VBMENUCHANNELMANAGER'); ?></span> |
| @@ -418,14 +431,15 @@ | ||
| 418 | 431 | </ul> |
| 419 | 432 | </div> |
| 420 | 433 | </li><?php |
| 421 | 434 | } |
| 422 | - if ($vbo_auth_pms) { | |
| 435 | + if ($vbo_auth_pms || $vbo_auth_reports || $vbo_auth_tm) { | |
| 423 | 436 | ?><li class="vbo-menu-parent-li"> |
| 424 | 437 | <span><?php VikBookingIcons::e('tasks'); ?><a><?php echo JText::translate('VBMENUPMS'); ?> <?php VikBookingIcons::e('chevron-down', 'vbo-submenu-chevron'); ?></a></span> |
| 425 | 438 | <div class="vbo-submenu-wrap"> |
| 426 | - <ul class="vbo-submenu-ul" data-menu-scope="pms"> | |
| 427 | - <li> | |
| 439 | + <ul class="vbo-submenu-ul" data-menu-scope="pms"><?php | |
| 440 | + if ($vbo_auth_pms) { | |
| 441 | + ?><li> | |
| 428 | 442 | <div class="<?php echo ($highlight == "operators" ? "vmenulinkactive" : "vmenulink"); ?>"> |
| 429 | 443 | <a href="index.php?option=com_vikbooking&task=operators"> |
| 430 | 444 | <?php VikBookingIcons::e('user-tie'); ?> |
| 431 | 445 | <span class="vbo-submenu-item"> |
| @@ -442,10 +456,12 @@ | ||
| 442 | 456 | <span class="vbo-submenu-item-txt"><?php echo JText::translate('VBMENUTABLEAUX'); ?></span> |
| 443 | 457 | </span> |
| 444 | 458 | </a> |
| 445 | 459 | </div> |
| 446 | - </li> | |
| 447 | - <li> | |
| 460 | + </li><?php | |
| 461 | + } | |
| 462 | + if ($vbo_auth_admin || $vbo_auth_reports) { | |
| 463 | + ?><li> | |
| 448 | 464 | <div class="<?php echo ($highlight == "pmsreports" ? "vmenulinkactive" : "vmenulink"); ?>"> |
| 449 | 465 | <a href="index.php?option=com_vikbooking&task=pmsreports"> |
| 450 | 466 | <?php VikBookingIcons::e('cash-register'); ?> |
| 451 | 467 | <span class="vbo-submenu-item"> |
| @@ -452,10 +468,12 @@ | ||
| 452 | 468 | <span class="vbo-submenu-item-txt"><?php echo JText::translate('VBMENUPMSREPORTS'); ?></span> |
| 453 | 469 | </span> |
| 454 | 470 | </a> |
| 455 | 471 | </div> |
| 456 | - </li> | |
| 457 | - <li> | |
| 472 | + </li><?php | |
| 473 | + } | |
| 474 | + if ($vbo_auth_pms) { | |
| 475 | + ?><li> | |
| 458 | 476 | <div class="<?php echo ($highlight == "einvoicing" ? "vmenulinkactive" : "vmenulink"); ?>"> |
| 459 | 477 | <a href="index.php?option=com_vikbooking&task=einvoicing"> |
| 460 | 478 | <?php VikBookingIcons::e('laptop-code'); ?> |
| 461 | 479 | <span class="vbo-submenu-item"> |
| @@ -462,10 +480,23 @@ | ||
| 462 | 480 | <span class="vbo-submenu-item-txt"><?php echo JText::translate('VBMENUEINVOICING'); ?></span> |
| 463 | 481 | </span> |
| 464 | 482 | </a> |
| 465 | 483 | </div> |
| 466 | - </li> | |
| 467 | - </ul> | |
| 484 | + </li><?php | |
| 485 | + } | |
| 486 | + if ($vbo_auth_admin || $vbo_auth_tm) { | |
| 487 | + ?><li class="vbo-menu-vcm-only"> | |
| 488 | + <div class="<?php echo ($highlight == "taskmanager" ? "vmenulinkactive" : "vmenulink"); ?>"> | |
| 489 | + <a href="index.php?option=com_vikbooking&view=taskmanager"> | |
| 490 | + <?php VikBookingIcons::e('tasks'); ?> | |
| 491 | + <span class="vbo-submenu-item"> | |
| 492 | + <span class="vbo-submenu-item-txt"><?php echo JText::translate('VBO_TASK_MANAGER'); ?></span> | |
| 493 | + </span> | |
| 494 | + </a> | |
| 495 | + </div> | |
| 496 | + </li><?php | |
| 497 | + } | |
| 498 | + ?></ul> | |
| 468 | 499 | </div> |
| 469 | 500 | </li><?php |
| 470 | 501 | } |
| 471 | 502 | ?> |
| @@ -483,9 +514,9 @@ | ||
| 483 | 514 | <?php VikBookingIcons::e('rocket'); ?> |
| 484 | 515 | <span><?php echo JText::translate('VBOGOTOPROBTN'); ?></span> |
| 485 | 516 | </button> |
| 486 | 517 | <?php |
| 487 | - } else { | |
| 518 | + } elseif ($vbo_auth_global) { | |
| 488 | 519 | ?> |
| 489 | 520 | <button type="button" class="vbo-alreadypro" title="<?php echo addslashes(JText::translate('VBOISPROBTN')); ?>" onclick="document.location.href='admin.php?option=com_vikbooking&view=gotopro';"> |
| 490 | 521 | <?php VikBookingIcons::e('trophy'); ?> |
| 491 | 522 | <span><?php echo JText::translate('VBOISPROBTN'); ?></span> |
| @@ -609,9 +640,9 @@ | ||
| 609 | 640 | } |
| 610 | 641 | } |
| 611 | 642 | } |
| 612 | 643 | |
| 613 | - if ($vbo_auth_management && in_array($highlight, array('18', '11', '8'))) { | |
| 644 | + if ($vbo_auth_management && in_array($highlight, array('18', '11'))) { | |
| 614 | 645 | // VCM Opportunities |
| 615 | 646 | $opp = VikBooking::getVcmOpportunityInstance(); |
| 616 | 647 | if (!is_null($opp)) { |
| 617 | 648 | // download opportunities if it's time to do it |
| @@ -625,12 +656,12 @@ | ||
| 625 | 656 | ); |
| 626 | 657 | $new_opp_count = count($opp->loadOpportunities($opp_filters, null, null)); |
| 627 | 658 | if ($new_opp_count > 0) { |
| 628 | 659 | ?> |
| 629 | - <button type="button" class="vbo-opportunities-btnbadge" data-opportunity-count="<?php echo $new_opp_count; ?>" title="<?php echo htmlspecialchars(JText::translate('VBOGOTOOPPORTUNITIES')); ?>" onclick="document.location.href='<?php echo VBOFactory::getPlatform()->getUri()->admin('index.php?option=com_vikchannelmanager&task=opportunities', false); ?>';"> | |
| 660 | + <!-- <button type="button" class="vbo-opportunities-btnbadge" data-opportunity-count="<?php echo $new_opp_count; ?>" title="<?php echo htmlspecialchars(JText::translate('VBOGOTOOPPORTUNITIES')); ?>" onclick="document.location.href='<?php echo VBOFactory::getPlatform()->getUri()->admin('index.php?option=com_vikchannelmanager&task=opportunities', false); ?>';"> | |
| 630 | 661 | <?php VikBookingIcons::e('crown'); ?> |
| 631 | 662 | <span><?php echo JText::translate('VBOGOTOOPPORTUNITIES'); ?></span> |
| 632 | - </button> | |
| 663 | + </button> --> | |
| 633 | 664 | <?php |
| 634 | 665 | } |
| 635 | 666 | } |
| 636 | 667 | |
| @@ -636,14 +667,16 @@ | ||
| 636 | 667 | |
| 637 | 668 | // Guest Reviews |
| 638 | 669 | $reviews_dld = VikBooking::shouldDownloadReviews(); |
| 639 | 670 | $base_lnk = VBOFactory::getPlatform()->getUri()->admin('index.php?option=com_vikchannelmanager&task=reviews', false); |
| 640 | - ?> | |
| 671 | + if ($highlight == '18') { | |
| 672 | + ?> | |
| 641 | 673 | <button type="button" class="vbo-reviews-btnbadge" data-reviews-count="" title="<?php echo htmlspecialchars(JText::translate('VBOPANELREVIEWS')); ?>" onclick="<?php echo $reviews_dld >= 0 ? "window.open('{$base_lnk}', '_blank'); jQuery(this).removeClass('vbo-reviews-btnbadge-alert').attr('data-reviews-count', '');" : "alert(Joomla.JText._('VBOGUESTREVSVCMREQ'));"; ?>"> |
| 642 | 674 | <?php VikBookingIcons::e('star'); ?> |
| 643 | 675 | <span><?php echo JText::translate('VBOPANELREVIEWS'); ?></span> |
| 644 | 676 | </button> |
| 645 | - <?php | |
| 677 | + <?php | |
| 678 | + } | |
| 646 | 679 | } |
| 647 | 680 | |
| 648 | 681 | /** |
| 649 | 682 | * Admin widgets multitasking side panel. |
| @@ -652,25 +685,59 @@ | ||
| 652 | 685 | */ |
| 653 | 686 | if ($view != 'dashboard') { |
| 654 | 687 | ?> |
| 655 | 688 | <button type="button" class="vbo-multitasking-apps" title="<?php echo htmlspecialchars(JText::translate('VBO_MULTITASK_PANEL'), ENT_QUOTES, 'UTF-8'); ?>"> |
| 656 | - <?php VikBookingIcons::e('th'); ?> | |
| 689 | + <?php VikBookingIcons::e('grip'); ?> | |
| 657 | 690 | </button> |
| 658 | 691 | |
| 659 | 692 | <?php |
| 660 | 693 | // prepare the layout data array |
| 661 | - $layout_data = array( | |
| 694 | + $layout_data = [ | |
| 662 | 695 | 'vbo_page' => (empty($view) ? VikRequest::getString('task', '') : $view), |
| 663 | 696 | 'btn_trigger' => '.vbo-multitasking-apps', |
| 664 | - ); | |
| 665 | - echo JLayoutHelper::render('sidepanel.multitasking', $layout_data, null, [ | |
| 666 | - 'component' => 'com_vikbooking', | |
| 667 | - 'client' => 'administrator', | |
| 668 | - ]); | |
| 697 | + ]; | |
| 698 | + // render the multitasking layout | |
| 699 | + echo JLayoutHelper::render('sidepanel.multitasking', $layout_data); | |
| 669 | 700 | ?> |
| 670 | 701 | <?php |
| 671 | 702 | } |
| 672 | - ?> | |
| 703 | + | |
| 704 | + /** | |
| 705 | + * Notifications Center. | |
| 706 | + * | |
| 707 | + * @since 1.16.8 (J) - 1.6.8 (WP) | |
| 708 | + */ | |
| 709 | + $ncInstance = VBOFactory::getNotificationCenter(); | |
| 710 | + | |
| 711 | + // read "old" notifications | |
| 712 | + $ncInstance->readOldNotifications(); | |
| 713 | + | |
| 714 | + // check if notifications should be downloaded | |
| 715 | + $ncInstance->downloadNotifications(); | |
| 716 | + | |
| 717 | + // count unread notifications | |
| 718 | + $unreadNotifs = $ncInstance->countUnread(); | |
| 719 | + $unreadNotifsRead = $unreadNotifs > 99 ? '99+' : $unreadNotifs; | |
| 720 | + $unreadNotifsRead = !$unreadNotifsRead ? '' : $unreadNotifsRead; | |
| 721 | + ?> | |
| 722 | + <div class="vbo-notifications-center-container"> | |
| 723 | + <button type="button" class="vbo-notifications-center-handler" data-badge-count="<?php echo $unreadNotifs; ?>" data-badge-read="<?php echo $unreadNotifsRead; ?>" title="<?php echo htmlspecialchars(JText::translate('VBO_W_NOTIFSCENTER_TITLE'), ENT_QUOTES, 'UTF-8'); ?>"> | |
| 724 | + <?php VikBookingIcons::e('bell', 'can-shake'); ?> | |
| 725 | + </button> | |
| 726 | + <?php | |
| 727 | + // prepare the layout data array | |
| 728 | + $layout_data = [ | |
| 729 | + 'vbo_page' => (empty($view) ? VikRequest::getString('task', '') : $view), | |
| 730 | + 'btn_trigger' => '.vbo-notifications-center-handler', | |
| 731 | + 'badge_c_attr' => 'data-badge-count', | |
| 732 | + 'badge_r_attr' => 'data-badge-read', | |
| 733 | + 'badge_count' => $unreadNotifs, | |
| 734 | + ]; | |
| 735 | + // render the notificationscenter layout | |
| 736 | + echo JLayoutHelper::render('sidepanel.notificationscenter', $layout_data); | |
| 737 | + ?> | |
| 738 | + </div> | |
| 739 | + | |
| 673 | 740 | </div> |
| 674 | 741 | </div> |
| 675 | 742 | </div> |
| 676 | 743 | |
| @@ -739,10 +806,15 @@ | ||
| 739 | 806 | } catch(e) { |
| 740 | 807 | console.error(e); |
| 741 | 808 | } |
| 742 | 809 | |
| 743 | - // proceed with the navigation | |
| 744 | - window.location.href = jQuery(this).attr('href'); | |
| 810 | + if (e.metaKey) { | |
| 811 | + // open link on new window | |
| 812 | + window.open(jQuery(this).attr('href'), '_blank').focus(); | |
| 813 | + } else { | |
| 814 | + // proceed with the navigation | |
| 815 | + window.location.href = jQuery(this).attr('href'); | |
| 816 | + } | |
| 745 | 817 | |
| 746 | 818 | return true; |
| 747 | 819 | }); |
| 748 | 820 | |
| @@ -747,8 +819,12 @@ | ||
| 747 | 819 | }); |
| 748 | 820 | |
| 749 | 821 | // register event to populate quick actions sub-menu helpers |
| 750 | 822 | document.addEventListener('vbo-adminmenu-quickactions-create', () => { |
| 823 | + // load the action from the "widgets" scope to be used as fallback | |
| 824 | + let menu_widgets_actions = VBOCore.getAdminMenuActions('widgets'); | |
| 825 | + | |
| 826 | + // scan all menu scopes | |
| 751 | 827 | jQuery('.vbo-submenu-ul[data-menu-scope]').each(function() { |
| 752 | 828 | let menu_ul = jQuery(this); |
| 753 | 829 | let scope = menu_ul.attr('data-menu-scope'); |
| 754 | 830 | if (!scope) { |
| @@ -753,35 +829,74 @@ | ||
| 753 | 829 | let scope = menu_ul.attr('data-menu-scope'); |
| 754 | 830 | if (!scope) { |
| 755 | 831 | return; |
| 756 | 832 | } |
| 833 | + | |
| 834 | + let orig_scope = scope; | |
| 757 | 835 | let wrapper = menu_ul.closest('.vbo-submenu-wrap'); |
| 758 | 836 | if (!wrapper || !wrapper.length || wrapper.hasClass('vbo-submenu-wrap-multi') || wrapper.find('.vbo-submenu-helper-ul').length) { |
| 759 | 837 | return; |
| 760 | 838 | } |
| 839 | + | |
| 761 | 840 | let menu_scope_actions = VBOCore.getAdminMenuActions(scope); |
| 762 | 841 | if (!Array.isArray(menu_scope_actions) || !menu_scope_actions.length) { |
| 763 | - return; | |
| 842 | + // check if we can fallback on the "widgets" scope | |
| 843 | + if (Array.isArray(menu_widgets_actions) && menu_widgets_actions.length) { | |
| 844 | + // overwrite scope values | |
| 845 | + scope = 'widgets'; | |
| 846 | + menu_scope_actions = menu_widgets_actions; | |
| 847 | + } else { | |
| 848 | + // do not proceed with this scope | |
| 849 | + return; | |
| 850 | + } | |
| 764 | 851 | } |
| 852 | + | |
| 853 | + // check if menu actions should be merged with the fallback scope | |
| 854 | + if (scope != 'widgets' && menu_scope_actions[0].hasOwnProperty('fallback')) { | |
| 855 | + let before_fill_length = menu_scope_actions.length; | |
| 856 | + menu_scope_actions = VBOCore.fillAdminMenuActions(menu_scope_actions, menu_widgets_actions, scope); | |
| 857 | + let after_fill_length = menu_scope_actions.length; | |
| 858 | + if (before_fill_length && after_fill_length > before_fill_length) { | |
| 859 | + // update scope for the filled entries | |
| 860 | + VBOCore.storageSetItem(VBOCore.getStorageScopeName(scope), menu_scope_actions); | |
| 861 | + } | |
| 862 | + } | |
| 863 | + | |
| 765 | 864 | wrapper.addClass('vbo-submenu-wrap-multi'); |
| 766 | 865 | let quick_actions = jQuery('<ul></ul>').addClass('vbo-submenu-helper-ul'); |
| 767 | 866 | quick_actions.append('<li class="vbo-submenu-helper-lbl-li"><span class="vbo-submenu-helper-lbl-txt">' + Joomla.JText._('VBO_QUICK_ACTIONS') + '</span></li>'); |
| 867 | + | |
| 868 | + // scan all menu actions | |
| 768 | 869 | menu_scope_actions.forEach((action, index) => { |
| 769 | 870 | let is_pinned = action.hasOwnProperty('pinned') && action['pinned']; |
| 770 | 871 | let quick_actions_entry = jQuery('<li></li>').addClass((is_pinned ? 'vbo-submenu-item-helper-pinned' : 'vbo-submenu-item-helper-unpinned')); |
| 771 | 872 | let quick_actions_div = jQuery('<div></div>').addClass('vmenulink'); |
| 772 | 873 | let quick_action_link = jQuery('<a></a>').attr('href', action['href']).addClass('vbo-submenu-item-helper-link'); |
| 874 | + | |
| 773 | 875 | if (action.hasOwnProperty('target') && action['target']) { |
| 774 | 876 | quick_action_link.attr('target', action['target']); |
| 775 | 877 | } |
| 878 | + | |
| 879 | + if (action.hasOwnProperty('widget') && action['widget']) { | |
| 880 | + quick_action_link.on('click', () => { | |
| 881 | + VBOCore.handleDisplayWidgetNotification({widget_id: action['widget']}); | |
| 882 | + }); | |
| 883 | + } | |
| 884 | + | |
| 776 | 885 | if (action.hasOwnProperty('img') && action['img']) { |
| 777 | 886 | let quick_action_img = jQuery('<span></span>').addClass('vbo-submenu-item-helper-avatar'); |
| 778 | 887 | quick_action_img.append('<img src="' + action['img'] + '" />'); |
| 779 | 888 | quick_action_link.append(quick_action_img); |
| 889 | + } else if (action.hasOwnProperty('icon') && action['icon']) { | |
| 890 | + let quick_action_icon = jQuery('<span></span>').addClass('vbo-submenu-item-helper-avatar'); | |
| 891 | + quick_action_icon.append(action['icon']); | |
| 892 | + quick_action_link.append(quick_action_icon); | |
| 780 | 893 | } |
| 894 | + | |
| 781 | 895 | let quick_action_name = jQuery('<span></span>').addClass('vbo-submenu-item-helper-txt').text(action['name']); |
| 782 | 896 | quick_action_link.append(quick_action_name); |
| 783 | 897 | quick_actions_div.append(quick_action_link); |
| 898 | + | |
| 784 | 899 | let quick_action_pin = jQuery('<span></span>').addClass('vbo-submenu-item-helper-setpin').on('click', function() { |
| 785 | 900 | // toggle pinned status and update admin menu action |
| 786 | 901 | if (!action.hasOwnProperty('pinned')) { |
| 787 | 902 | action['pinned'] = !is_pinned; |
| @@ -788,10 +903,20 @@ | ||
| 788 | 903 | } else { |
| 789 | 904 | action['pinned'] = !action['pinned']; |
| 790 | 905 | } |
| 791 | 906 | try { |
| 792 | - // update local storage | |
| 793 | - VBOCore.updateAdminMenuAction(action, scope); | |
| 907 | + // register/unregister pin | |
| 908 | + if (orig_scope != scope && !VBOCore.getAdminMenuActions(orig_scope).length) { | |
| 909 | + // set fallbacked scope | |
| 910 | + action['fallback'] = scope; | |
| 911 | + | |
| 912 | + // register scope on local storage with the fallbacked scope | |
| 913 | + VBOCore.registerAdminMenuAction(action, orig_scope); | |
| 914 | + } else { | |
| 915 | + // update local storage regularly on this scope | |
| 916 | + VBOCore.updateAdminMenuAction(action, scope); | |
| 917 | + } | |
| 918 | + | |
| 794 | 919 | // trigger event |
| 795 | 920 | VBOCore.emitEvent('vbo-adminmenu-quickactions-update'); |
| 796 | 921 | } catch(e) { |
| 797 | 922 | console.error(e); |
| @@ -802,13 +927,16 @@ | ||
| 802 | 927 | } else { |
| 803 | 928 | jQuery(this).closest('li').removeClass('vbo-submenu-item-helper-pinned').addClass('vbo-submenu-item-helper-unpinned'); |
| 804 | 929 | } |
| 805 | 930 | }); |
| 931 | + | |
| 806 | 932 | quick_action_pin.html('<?php VikBookingIcons::e('thumbtack'); ?>'); |
| 807 | 933 | quick_actions_div.append(quick_action_pin); |
| 808 | 934 | quick_actions_entry.append(quick_actions_div); |
| 809 | 935 | quick_actions.append(quick_actions_entry); |
| 810 | 936 | }); |
| 937 | + | |
| 938 | + // append to DOM element | |
| 811 | 939 | wrapper.append(quick_actions); |
| 812 | 940 | }); |
| 813 | 941 | }); |
| 814 | 942 | |
| @@ -847,8 +975,14 @@ | ||
| 847 | 975 | } |
| 848 | 976 | ); |
| 849 | 977 | }, 300)); |
| 850 | 978 | |
| 979 | + // append shortcut to title | |
| 980 | + jQuery('.vbo-multitasking-apps').attr('title', | |
| 981 | + jQuery('.vbo-multitasking-apps').attr('title') + ' ' | |
| 982 | + + (navigator.platform.toUpperCase().indexOf('MAC') === 0 ? '⌘' : '⌃') + '⏎' | |
| 983 | + ); | |
| 984 | + | |
| 851 | 985 | // register shortcuts |
| 852 | 986 | var vbo_menu_last_keydown = null; |
| 853 | 987 | window.addEventListener('keydown', (e) => { |
| 854 | 988 | e = e || window.event; |
| @@ -854,26 +988,38 @@ | ||
| 854 | 988 | e = e || window.event; |
| 855 | 989 | if (!e.key) { |
| 856 | 990 | return; |
| 857 | 991 | } |
| 858 | - if (e.key === 'Enter' && e.metaKey) { | |
| 992 | + | |
| 993 | + let modifier = 'ctrl'; | |
| 994 | + | |
| 995 | + // change the modifier depending on the platform | |
| 996 | + if (navigator.platform.toUpperCase().indexOf('MAC') === 0) { | |
| 997 | + modifier = 'meta'; | |
| 998 | + } | |
| 999 | + | |
| 1000 | + if (e.shortcut([modifier, 13])) { | |
| 859 | 1001 | // toggle multitask panel |
| 860 | 1002 | VBOCore.emitEvent(VBOCore.multitask_shortcut_event); |
| 861 | 1003 | return; |
| 862 | 1004 | } |
| 863 | - if (VBOCore.side_panel_on && e.key === 'f' && e.metaKey) { | |
| 1005 | + | |
| 1006 | + if (VBOCore.side_panel_on && e.shortcut([modifier, 'F'])) { | |
| 864 | 1007 | // focus search admin widget in multitask panel |
| 865 | 1008 | VBOCore.emitEvent(VBOCore.multitask_searchfs_event); |
| 866 | 1009 | e.preventDefault(); |
| 1010 | + | |
| 867 | 1011 | return; |
| 868 | 1012 | } |
| 869 | - if (e.key === 'k' && e.metaKey) { | |
| 1013 | + | |
| 1014 | + if (e.shortcut([modifier, 'K'])) { | |
| 870 | 1015 | // set special key listener for sequences of combos |
| 871 | 1016 | e.preventDefault(); |
| 872 | 1017 | vbo_menu_last_keydown = 'k'; |
| 873 | 1018 | return; |
| 874 | 1019 | } |
| 875 | - if (vbo_menu_last_keydown === 'k' && e.metaKey && ['a', 'd', 'l'].includes(e.key)) { | |
| 1020 | + | |
| 1021 | + if (vbo_menu_last_keydown === 'k' && (e.shortcut([modifier, 'A']) || e.shortcut([modifier, 'D']) || e.shortcut([modifier, 'L']))) { | |
| 876 | 1022 | // trigger event to change color scheme preferences |
| 877 | 1023 | e.preventDefault(); |
| 878 | 1024 | // unset special key |
| 879 | 1025 | vbo_menu_last_keydown = ''; |
| @@ -885,8 +1031,9 @@ | ||
| 885 | 1031 | }; |
| 886 | 1032 | jQuery('.vbo-sidepanel-colorscheme-option[data-scheme="' + color_schemes[e.key] + '"]').trigger('click'); |
| 887 | 1033 | return; |
| 888 | 1034 | } |
| 1035 | + | |
| 889 | 1036 | // always unset last key if this point gets reached |
| 890 | 1037 | vbo_menu_last_keydown = ''; |
| 891 | 1038 | }, true); |
| 892 | 1039 | |
| @@ -941,8 +1088,70 @@ | ||
| 941 | 1088 | } |
| 942 | 1089 | ); |
| 943 | 1090 | }, 300); |
| 944 | 1091 | } |
| 1092 | + | |
| 1093 | + // declare window resize handler for setting the position of sub-menus | |
| 1094 | + const subMenuStylesPositioning = () => { | |
| 1095 | + // get window width | |
| 1096 | + let windowWidth = window.innerWidth; | |
| 1097 | + | |
| 1098 | + // scan all sub-menu entries | |
| 1099 | + document.querySelectorAll('.vbo-submenu-wrap').forEach((submenu) => { | |
| 1100 | + // remove the class to style the sub-menu "to left" | |
| 1101 | + submenu.classList.remove('vbo-submenu-wrap-toleft'); | |
| 1102 | + | |
| 1103 | + // get sub-menu width and offset left position values | |
| 1104 | + let elemWidth = submenu.offsetWidth; | |
| 1105 | + let elemOffLeft = submenu.getBoundingClientRect().left; | |
| 1106 | + | |
| 1107 | + if (elemWidth) { | |
| 1108 | + // sub-menu visibility is hidden, but width has been computed | |
| 1109 | + if ((elemWidth + elemOffLeft) > windowWidth) { | |
| 1110 | + // add "to left" positioning class or the sub-menu would exceed the window | |
| 1111 | + submenu.classList.add('vbo-submenu-wrap-toleft'); | |
| 1112 | + } | |
| 1113 | + } else { | |
| 1114 | + // on small screens, the sub-menu may be hidden, hence with no width | |
| 1115 | + let parentmenu = submenu.closest('.vbo-menu-parent-li'); | |
| 1116 | + | |
| 1117 | + // register listener for mouseover event | |
| 1118 | + parentmenu.addEventListener('mouseover', (e) => { | |
| 1119 | + setTimeout(() => { | |
| 1120 | + let now_submenu = e.target.querySelector('.vbo-submenu-wrap'); | |
| 1121 | + if (!now_submenu) { | |
| 1122 | + return; | |
| 1123 | + } | |
| 1124 | + if ((now_submenu.offsetWidth + now_submenu.getBoundingClientRect().left) > window.innerWidth) { | |
| 1125 | + // add "to left" positioning class or the sub-menu would exceed the window | |
| 1126 | + now_submenu.classList.add('vbo-submenu-wrap-toleft'); | |
| 1127 | + } | |
| 1128 | + }, 0); | |
| 1129 | + }); | |
| 1130 | + | |
| 1131 | + // register listener for touchstart event | |
| 1132 | + parentmenu.addEventListener('touchstart', (e) => { | |
| 1133 | + let limenu = e.target; | |
| 1134 | + if (!limenu.matches('.vbo-menu-parent-li')) { | |
| 1135 | + limenu = limenu.closest('.vbo-menu-parent-li'); | |
| 1136 | + } | |
| 1137 | + // propagate the mouseover event | |
| 1138 | + limenu.dispatchEvent(new Event('mouseover')); | |
| 1139 | + }); | |
| 1140 | + } | |
| 1141 | + }); | |
| 1142 | + }; | |
| 1143 | + | |
| 1144 | + // register listener for window resize event | |
| 1145 | + window.addEventListener('resize', subMenuStylesPositioning); | |
| 1146 | + | |
| 1147 | + // trigger sub-menus styles positioning function on page load | |
| 1148 | + setTimeout(() => { | |
| 1149 | + subMenuStylesPositioning(); | |
| 1150 | + }, 0); | |
| 1151 | + | |
| 1152 | + // populate admin-dock | |
| 1153 | + VBOAdminDock.getInstance(); | |
| 945 | 1154 | }); |
| 946 | 1155 | </script> |
| 947 | 1156 | <?php |
| 948 | 1157 | |
| @@ -970,8 +1179,20 @@ | ||
| 970 | 1179 | }); |
| 971 | 1180 | </script> |
| 972 | 1181 | <?php |
| 973 | 1182 | } |
| 1183 | + | |
| 1184 | + $helpWizardAjaxUrl = VBOFactory::getPlatform()->getUri()->ajax('index.php?option=com_vikbooking'); | |
| 1185 | + JHtml::fetch('script', VBO_ADMIN_URI . 'resources/helpwizard.js', ['version' => VIKBOOKING_SOFTWARE_VERSION]); | |
| 1186 | + JText::script('VBSAVE'); | |
| 1187 | + JText::script('VBDISMISS'); | |
| 1188 | + JFactory::getDocument()->addScriptDeclaration( | |
| 1189 | +<<<JAVASCRIPT | |
| 1190 | +(function(w) { | |
| 1191 | + window.VBO_HELP_WIZARD_AJAX_URL = '{$helpWizardAjaxUrl}'; | |
| 1192 | +})(window); | |
| 1193 | +JAVASCRIPT | |
| 1194 | + ); | |
| 974 | 1195 | } |
| 975 | 1196 | |
| 976 | 1197 | public static function printFooter() |
| 977 | 1198 | { |