diff --git a/module/tutorial/js/index.ui.js b/module/tutorial/js/index.ui.js index 0be3afc326..d30c7cdd28 100644 --- a/module/tutorial/js/index.ui.js +++ b/module/tutorial/js/index.ui.js @@ -1,48 +1,97 @@ let currentGuide = ''; let currentTask = ''; -let currentStep = 0; -const lastTaskStep = {}; +let currentStep = null; let popover = null; function highlightStepTarget(global, $target, step, popoverOptions) { - if(popover) popover.destroy(); + if(popover) + { + const triggerElement = popover.getTriggerElement(); + if(triggerElement) triggerElement.classList.remove('tutorial-hl'); + popover.destroy(); + } popoverOptions = $.extend( { + key : 'tutorialPopover', title : step.title, + strategy : 'fixed', show : true, mask : false, trigger : 'manual', destroyOnHide : true, closeBtn : false, content : step.desc, - contentClass : 'px-4', + contentClass : 'popover-content px-4', className : 'tutorial-popover rounded-md', titleClass : 'popover-title text-lg pl-1', minWidth : 280, + headingClass : 'popover-heading bg-transparent', elementShowClass: 'with-popover-show tutorial-hl', - actions: + footer: { - className: 'py-3 px-4 justify-between mt-2', - items: - [ - {component: 'span', html: `${step.index + 1}/${step.task.steps.length}`}, - {type: 'primary', text: lang.nextStep}, - ] + component: 'toolbar', + props: { + className: 'py-3 px-4 justify-between', + items: + [ + {component: 'span', html: `${step.index + 1}/${step.task.steps.length}`}, + {type: 'primary', text: lang.nextStep, onClick: () => goToNextStep(step)}, + ] + } } }, step.popover, popoverOptions); + if(popoverOptions.title === null) + { + const text = $target.text().trim(); + if(['openApp'].includes(step.type)) popoverOptions.title = lang.clickTipFormat.replace('%s', text); + } popover = new global.zui.Popover($target, popoverOptions); - console.log('> highlightStepTarget', $target, {popover, step}); +} + +function goToNextStep(step) +{ + step = step || currentStep; } function showOpenAppStep(step) { - const indexWindow = $('#iframePage')[0].contentWindow; - const index$ = indexWindow.$; - const $menuMainNav = index$('#menuMainNav'); - let $appNav = $menuMainNav.children(`li[data-app="${step.app}"]`); - console.log('> showOpenAppStep', step, $menuMainNav, $appNav); - if($appNav.length) return highlightStepTarget(indexWindow, $appNav.find('a'), step, {placement: 'right'}); + const indexWindow = $('#iframePage')[0].contentWindow; + const index$ = indexWindow.$; + const $menuNav = index$('#menuNav'); + + if(!$menuNav.data('checkOpenAppStep')) + { + const checkOpenAppStep = (event, info) => + { + if(!currentStep || currentStep.type !== 'openApp') return; + if(event.type === 'shown' && info[0].options.target !== '#menuMoreList') return; + showOpenAppStep(currentStep); + }; + $(indexWindow).on('resize', checkOpenAppStep); + indexWindow.$('#menuMoreBtn').on('shown', checkOpenAppStep); + $menuNav.data('checkOpenAppStep', true); + } + + const $menuMainNav = $menuNav.find('#menuMainNav'); + const $appNav = $menuMainNav.children(`li[data-app="${step.app}"]`); + let $targetNav = $appNav; + if($appNav.hasClass('hidden')) + { + const $menuMoreList = $menuNav.find('#menuMoreList.in'); + if($menuMoreList.length) $targetNav = $menuMoreList.children(`li[data-app="${step.app}"]`); + else $targetNav = $menuNav.find('#menuMoreBtn'); + } + + if(!$targetNav.length) return; + const popoverOptions = {placement: 'right'}; + if($targetNav.is('#menuMoreBtn')) + { + popoverOptions.title = null; + popoverOptions.footer = undefined; + popoverOptions.content = lang.clickAndOpenIt.replace('%s', $targetNav.text().trim()).replace('%s', $appNav.text().trim()); + } + return highlightStepTarget(indexWindow, $targetNav.is('a') ? $targetNav : $targetNav.find('a'), step, popoverOptions); } function toggleActiveTarget(type, name, toggle) @@ -60,6 +109,7 @@ function unactiveTask() { toggleActiveTarget('task', currentTask, false); currentTask = ''; + currentStep = null; } function activeTaskStep(guideName, taskName, stepIndex) @@ -81,8 +131,9 @@ function activeTaskStep(guideName, taskName, stepIndex) step.index = stepIndex; step.isLast = stepIndex === task.steps.length - 1; + currentStep = step; + if(step.type === 'openApp') return showOpenAppStep(step); - console.log('activeTaskStep', guideName, taskName, step); } function activeTask(guideName, taskName, step = 0) @@ -97,7 +148,6 @@ function activeTask(guideName, taskName, step = 0) toggleActiveTarget('task', currentTask, true); } - step = step || lastTaskStep[taskName] || 0; activeTaskStep(guideName, taskName, step); } diff --git a/module/tutorial/lang/de.php b/module/tutorial/lang/de.php index f11c5824eb..58dc08b223 100644 --- a/module/tutorial/lang/de.php +++ b/module/tutorial/lang/de.php @@ -32,6 +32,8 @@ $lang->tutorial->serverErrorTip = 'Fehler!'; $lang->tutorial->ajaxSetError = 'Abgeschlossene Aufgabe muss definiert sein. Wenn Sie die Aufgabe zurücksetzen möchten, setzen Sie den Wert auf Null.'; $lang->tutorial->novice = "Für einen Schnellstart, beginnen Sie mit einer 2 Minuten Anleitung?"; $lang->tutorial->dataNotSave = "In der Anleitung erstellte Daten werden nicht gespeichert!"; +$lang->tutorial->clickTipFormat = "klicken %s"; +$lang->tutorial->clickAndOpenIt = "Click %s to open %s."; $lang->tutorial->tasks = new stdclass(); $lang->tutorial->tasks->createAccount = new stdclass(); diff --git a/module/tutorial/lang/en.php b/module/tutorial/lang/en.php index ef718615f6..a562fc21ba 100644 --- a/module/tutorial/lang/en.php +++ b/module/tutorial/lang/en.php @@ -34,6 +34,8 @@ $lang->tutorial->serverErrorTip = 'Error!'; $lang->tutorial->ajaxSetError = 'Finished task must be defined. If you want to reset the Task, please set its value as null.'; $lang->tutorial->novice = "For a quick start, let's go through a two-minute Tutorial."; $lang->tutorial->dataNotSave = "Data generated in this Tutorial will not be saved!"; +$lang->tutorial->clickTipFormat = "Click %s"; +$lang->tutorial->clickAndOpenIt = "Click %s to open %s."; $lang->tutorial->guideTypes = array(); $lang->tutorial->guideTypes['starter'] = 'Getting Started'; diff --git a/module/tutorial/lang/fr.php b/module/tutorial/lang/fr.php index 0f5f35af0f..75d024ed6e 100644 --- a/module/tutorial/lang/fr.php +++ b/module/tutorial/lang/fr.php @@ -32,6 +32,8 @@ $lang->tutorial->serverErrorTip = 'Error!'; $lang->tutorial->ajaxSetError = 'Finished task must be defined. If you want to reset the Task, please set its value as null.'; $lang->tutorial->novice = "For a quick start, let's go through a two-minute Tutorial."; $lang->tutorial->dataNotSave = "Data generated in this Tutorial will not be saved!"; +$lang->tutorial->clickTipFormat = "cliquez %s"; +$lang->tutorial->clickAndOpenIt = "Click %s to open %s."; $lang->tutorial->tasks = new stdclass(); $lang->tutorial->tasks->createAccount = new stdclass(); diff --git a/module/tutorial/lang/zh-cn.php b/module/tutorial/lang/zh-cn.php index a74e936cf2..f55f33470a 100644 --- a/module/tutorial/lang/zh-cn.php +++ b/module/tutorial/lang/zh-cn.php @@ -34,6 +34,8 @@ $lang->tutorial->serverErrorTip = '发生了一些错误。'; $lang->tutorial->ajaxSetError = '必须指定已完成的任务,如果要重置任务,请设置值为空。'; $lang->tutorial->novice = "你可能初次使用禅道,是否进入新手教程"; $lang->tutorial->dataNotSave = "教程任务中,数据不会保存。"; +$lang->tutorial->clickTipFormat = "点击%s"; +$lang->tutorial->clickAndOpenIt = "点击%s打开%s。"; $lang->tutorial->guideTypes = array(); $lang->tutorial->guideTypes['starter'] = '快速上手'; diff --git a/module/tutorial/ui/index.html.php b/module/tutorial/ui/index.html.php index 329eba0d7b..dfc5fadf14 100644 --- a/module/tutorial/ui/index.html.php +++ b/module/tutorial/ui/index.html.php @@ -149,7 +149,12 @@ $buildTutorialTabPane = function($type) use ($groupedGuides, $lang, $currentType }; jsVar('guides', $guides); -jsVar('lang', array('nextStep' => $lang->tutorial->nextStep)); +jsVar('lang', array +( + 'nextStep' => $lang->tutorial->nextStep, + 'clickTipFormat' => $lang->tutorial->clickTipFormat, + 'clickAndOpenIt' => $lang->tutorial->clickAndOpenIt +)); div ( diff --git a/www/js/zui3/zin.js b/www/js/zui3/zin.js index d04b10f46d..7cc6925569 100644 --- a/www/js/zui3/zin.js +++ b/www/js/zui3/zin.js @@ -41,7 +41,7 @@ let zinbar = null; let historyState = parent.window.history.state; const hasZinBar = DEBUG && window.zin && window.zin.zinTool && !isIndexPage; - const localCacheFirst = config.cache === 'local-first'; + const localCacheFirst = config.clientCache === 'local-first'; function getUrlID(url) {