ng-devui
Version:
DevUI components based on Angular
1 lines • 104 kB
Source Map (JSON)
{"version":3,"file":"ng-devui-user-guide.mjs","sources":["../../devui/user-guide/utils/calculate-panel-position.ts","../../devui/user-guide/utils/help-functions.ts","../../devui/user-guide/user-guide-core.service.ts","../../devui/user-guide/user-guide-ui.component.ts","../../devui/user-guide/user-guide-ui.component.html","../../devui/user-guide/user-guide.component.ts","../../devui/user-guide/user-guide.component.html","../../devui/user-guide/user-guide.service.ts","../../devui/user-guide/user-guide.module.ts","../../devui/user-guide/ng-devui-user-guide.ts"],"sourcesContent":["import { IStepElementDetail } from '../user-guide.types';\n\nconst ARROW_WIDTH = 8;\nconst PANEL_TO_ELEMENT = 10;\n\nexport class PanelPostion {\n top: number;\n left: number;\n arrowTopBias: number;\n arrowLeftBias: number;\n\n availablePosition: string;\n alignDirection: string;\n step: IStepElementDetail;\n document: Document;\n\n constructor(document) {\n this.document = document;\n }\n\n calculateAvailablePosition(curStepRect, panelRect) {\n if (this.step.position !== undefined) {\n this.availablePosition = this.step.position.split('-')[0];\n } else {\n if (curStepRect.bottom + panelRect.height + PANEL_TO_ELEMENT <= this.document.documentElement.clientHeight) {\n this.availablePosition = 'bottom';\n } else if (curStepRect.top - panelRect.height - PANEL_TO_ELEMENT > 0) {\n this.availablePosition = 'top';\n } else if (curStepRect.right + panelRect.width + PANEL_TO_ELEMENT <= this.document.documentElement.clientWidth) {\n this.availablePosition = 'right';\n } else if (curStepRect.left - panelRect.width - PANEL_TO_ELEMENT > 0) {\n this.availablePosition = 'left';\n }\n }\n }\n\n calculateTopAndLeft(curStepRect, panelRect) {\n if (this.availablePosition === 'bottom') {\n this.top = curStepRect.bottom + PANEL_TO_ELEMENT;\n this.arrowTopBias = ARROW_WIDTH / 2;\n } else if (this.availablePosition === 'top') {\n this.arrowTopBias = panelRect.height - ARROW_WIDTH / 2;\n this.top = curStepRect.top - panelRect.height - PANEL_TO_ELEMENT;\n } else if (this.availablePosition === 'right') {\n this.left = curStepRect.right + PANEL_TO_ELEMENT;\n this.arrowLeftBias = -ARROW_WIDTH / 2;\n } else if (curStepRect.left - panelRect.width - PANEL_TO_ELEMENT > 0) {\n this.left = curStepRect.left - panelRect.width - PANEL_TO_ELEMENT;\n this.arrowLeftBias = panelRect.width - ARROW_WIDTH / 2;\n }\n }\n\n calculateAlignDirection(curStepRect, panelRect) {\n if (this.step.position !== undefined) {\n this.alignDirection = this.step.position.split('-')[1] || 'middle';\n } else {\n if (this.availablePosition === 'bottom' || this.availablePosition === 'top') {\n this.calculateTopBottomAlign(curStepRect, panelRect);\n } else if (this.availablePosition === 'left' || this.availablePosition === 'right') {\n this.calculateLeftRightAlign(curStepRect, panelRect);\n }\n }\n }\n\n calculateTopBottomAlign(curStepRect, panelRect) {\n if (curStepRect.left + panelRect.width < this.document.documentElement.clientWidth) {\n this.alignDirection = 'left';\n } else if (curStepRect.right - panelRect.width > 0) {\n this.alignDirection = 'right';\n }\n if (\n panelRect.width < curStepRect.width ||\n (curStepRect.left + curStepRect.width / 2 - panelRect.width / 2 > 0 &&\n curStepRect.left + curStepRect.width / 2 + panelRect.width / 2 < this.document.documentElement.clientWidth)\n ) {\n this.alignDirection = 'middle';\n }\n }\n\n calculateLeftRightAlign(curStepRect, panelRect) {\n if (\n panelRect.height < curStepRect.height ||\n (curStepRect.top + curStepRect.height / 2 - panelRect.height / 2 > 0 &&\n curStepRect.top + curStepRect.height / 2 + panelRect.height / 2 < this.document.documentElement.clientHeight)\n ) {\n this.alignDirection = 'middle';\n } else if (curStepRect.top + panelRect.height < this.document.documentElement.clientWidth) {\n this.alignDirection = 'top';\n } else if (curStepRect.bottom - panelRect.height > 0) {\n this.alignDirection = 'bottom';\n }\n }\n\n calculateBias(curStepRect, panelRect) {\n if (this.availablePosition === 'bottom' || this.availablePosition === 'top') {\n this.calculateTopBottomBias(curStepRect, panelRect);\n } else if (this.availablePosition === 'left' || this.availablePosition === 'right') {\n this.calculateLeftRightBias(curStepRect, panelRect);\n }\n }\n\n calculateTopBottomBias(curStepRect, panelRect) {\n if (this.alignDirection === 'middle') {\n this.left = curStepRect.left + curStepRect.width / 2 - panelRect.width / 2;\n this.arrowLeftBias = panelRect.width / 2 - ARROW_WIDTH / 2;\n } else if (this.alignDirection === 'left') {\n this.left = curStepRect.left;\n this.arrowLeftBias = PANEL_TO_ELEMENT + ARROW_WIDTH;\n } else if (this.alignDirection === 'right') {\n this.left = curStepRect.right - panelRect.width;\n this.arrowLeftBias = panelRect.width - PANEL_TO_ELEMENT - ARROW_WIDTH;\n }\n }\n\n calculateLeftRightBias(curStepRect, panelRect) {\n if (this.alignDirection === 'middle') {\n this.top = curStepRect.top + curStepRect.height / 2 - panelRect.height / 2;\n this.arrowTopBias = panelRect.height / 2;\n } else if (this.alignDirection === 'top') {\n this.top = curStepRect.top;\n this.arrowTopBias = PANEL_TO_ELEMENT + ARROW_WIDTH;\n } else if (this.alignDirection === 'bottom') {\n this.top = curStepRect.bottom - panelRect.height;\n this.arrowTopBias = panelRect.height - PANEL_TO_ELEMENT - ARROW_WIDTH;\n }\n }\n\n getRealClientRect(step) {\n const stepRect = step.element?.getBoundingClientRect();\n const realRect = {\n top: stepRect?.top - (step?.highlightOffset ? step.highlightOffset[0] : 0),\n right: stepRect?.right + (step?.highlightOffset ? step.highlightOffset[1] : 0),\n left: stepRect?.left - (step?.highlightOffset ? step.highlightOffset[3] : 0),\n bottom: stepRect?.bottom + (step?.highlightOffset ? step.highlightOffset[2] : 0),\n width: stepRect?.width + (step?.highlightOffset ? step.highlightOffset[3] + step.highlightOffset[1] : 0),\n height: stepRect?.height + (step?.highlightOffset ? step.highlightOffset[0] + step.highlightOffset[2] : 0),\n };\n return realRect;\n }\n\n calculatePosition(step) {\n const panel = this.document.querySelector('.user-guide-panel') as HTMLElement;\n const panelRect = panel.getBoundingClientRect();\n this.step = step;\n\n const curStepRect = this.getRealClientRect(step);\n\n this.calculateAvailablePosition(curStepRect, panelRect);\n this.calculateTopAndLeft(curStepRect, panelRect);\n this.calculateAlignDirection(curStepRect, panelRect);\n this.calculateBias(curStepRect, panelRect);\n\n const panelArrow = this.document.querySelector('.devui-user-guide-panel-arrow') as HTMLElement;\n if (panelArrow) {\n panelArrow.style.top = `${this.arrowTopBias}px`;\n panelArrow.style.left = `${this.arrowLeftBias}px`;\n }\n\n panel.style.cssText = `\n top: ${this.top}px;\n left: ${this.left}px;\n `;\n }\n}\n","export function disableClick(e) {\n e.preventDefault();\n e.stopPropagation();\n}\n\nexport function documentRealHeight(document) {\n return Math.max(\n document.body.scrollHeight,\n document.documentElement.scrollHeight,\n document.body.offsetHeight,\n document.documentElement.offsetHeight,\n document.body.clientHeight,\n document.documentElement.clientHeight\n );\n}\n","import { DOCUMENT } from '@angular/common';\nimport { Inject, Injectable, OnDestroy, Renderer2, RendererFactory2 } from '@angular/core';\nimport { BehaviorSubject, fromEvent, fromEventPattern, Observable, Subject } from 'rxjs';\nimport { debounceTime, takeUntil } from 'rxjs/operators';\nimport { PanelPostion } from './utils/calculate-panel-position';\nimport { disableClick, documentRealHeight } from './utils/help-functions';\n\n@Injectable()\nexport class UserGuideCoreService implements OnDestroy {\n private steps = []; // 用户输入的指引步骤\n private stepsDetails = []; // 经过处理加入细节的指引步骤\n private currentStep;\n private prevStep;\n private nextStep;\n private isStart = false;\n private _destory = new Subject<void>();\n private onExit;\n private interactableEvent = {\n eventType: null,\n element: null,\n eventFunction: null,\n };\n\n private _showOverlayState = {\n showMaskLayer: false,\n showNormalOverlay: false,\n showTopOverlay: false,\n showBottomOverlay: false,\n showLeftOverlay: false,\n showRightOverlay: false,\n showBorder: false,\n };\n\n private currentType; // 当前指引步骤的展现形式\n private currentDirection;\n\n public onResize: Observable<Event>;\n public onScroll;\n\n curContent = new BehaviorSubject('start');\n curSubContent = new BehaviorSubject('');\n curStep = new BehaviorSubject(-1);\n canNext = new BehaviorSubject(true);\n canPrev = new BehaviorSubject(true);\n canFinish = new BehaviorSubject(false);\n isFinished = new BehaviorSubject(false);\n showButtons = new BehaviorSubject(true);\n showOverlayState = new BehaviorSubject(this._showOverlayState);\n showOperateZone = new BehaviorSubject(false);\n showPrevButton = new BehaviorSubject(true);\n curStepType = new BehaviorSubject('normal');\n document: Document;\n panelPostion;\n\n constructor(private rendererFactory2: RendererFactory2, @Inject(DOCUMENT) private doc: any) {\n const renderer = this.rendererFactory2.createRenderer(null, null);\n this.document = this.doc;\n this.panelPostion = new PanelPostion(this.document);\n\n this.createOnResizeObservable(renderer);\n this.onScroll = fromEvent(window, 'scroll')\n .pipe(takeUntil(this._destory), debounceTime(100))\n .subscribe(() => {\n if (this.isStart && this.stepsDetails[this.currentStep].type !== 'display') {\n this.updateCurrentStepElement();\n this.setStepShow(this.currentType, this.currentStep);\n }\n });\n\n this.onResize.subscribe((e: Event) => {\n if (this.isStart && this.stepsDetails[this.currentStep].type !== 'display') {\n this.updateCurrentStepElement();\n this.setStepShow(this.currentType, this.currentStep);\n }\n });\n\n this.curStep.subscribe((index) => {\n if (index !== -1) {\n this.canChange(index).then((canChange) => {\n if (canChange) {\n this.changeStep();\n }\n });\n }\n });\n }\n\n ngOnDestroy() {\n this._destory.next();\n this._destory.complete();\n\n if (this.curContent) {\n this.curContent.unsubscribe();\n }\n if (this.curSubContent) {\n this.curSubContent.unsubscribe();\n }\n if (this.curStep) {\n this.curStep.unsubscribe();\n }\n if (this.canNext) {\n this.canNext.unsubscribe();\n }\n if (this.canPrev) {\n this.canPrev.unsubscribe();\n }\n if (this.canFinish) {\n this.canFinish.unsubscribe();\n }\n if (this.isFinished) {\n this.isFinished.unsubscribe();\n }\n if (this.showButtons) {\n this.showButtons.unsubscribe();\n }\n if (this.showOverlayState) {\n this.showOverlayState.unsubscribe();\n }\n if (this.showOperateZone) {\n this.showOperateZone.unsubscribe();\n }\n if (this.curStepType) {\n this.curStepType.unsubscribe();\n }\n\n if (this.showPrevButton) {\n this.showPrevButton.unsubscribe();\n }\n }\n\n start() {\n if (this.steps.length === 0) {\n return;\n }\n\n this.generateStepsDetails();\n this.setInitialState();\n }\n\n private generateStepsDetails() {\n this.steps.forEach((item) => {\n if (item.element === undefined) {\n this.stepsDetails.push({\n title: item.title,\n content: item.content,\n type: 'display',\n beforeChange: item?.beforeChange,\n showPrevButton: item?.showPrevButton === undefined ? true : item.showPrevButton,\n });\n } else {\n const rect = (this.document.getElementById(item.element) || this.document.querySelector(item.element))?.getBoundingClientRect();\n this.stepsDetails.push({\n element: this.document.getElementById(item.element) || this.document.querySelector(item.element),\n title: item.title,\n content: item.content,\n position: item.position,\n highlightOffset: item?.highlightOffset,\n top: rect?.top,\n left: rect?.left,\n width: rect?.width,\n height: rect?.height,\n type: item.type === undefined ? 'normal' : item.type,\n eventType: item?.eventType,\n inputData: item?.inputData,\n waitingTime: item?.waitingTime,\n beforeChange: item?.beforeChange,\n showPrevButton: item?.showPrevButton === undefined ? true : item.showPrevButton,\n });\n }\n });\n }\n\n private setInitialState() {\n this.isStart = true;\n\n // 初始状态,令currentStep为-1\n this.currentStep = -1;\n this.prevStep = -2;\n this.nextStep = 0;\n }\n\n setSteps(steps) {\n this.steps = steps;\n }\n\n setExitFunction(exit) {\n this.onExit = exit;\n }\n\n updateNextStepElement() {\n for (let i = this.nextStep; i < this.steps.length; i++) {\n if (this.stepsDetails[i].type !== 'display') {\n this.stepsDetails[i].element =\n this.document.getElementById(this.steps[i].element) || this.document.querySelector(this.steps[i].element);\n\n const rect = this.stepsDetails[i]?.element?.getBoundingClientRect();\n this.stepsDetails[i].top = rect?.top;\n this.stepsDetails[i].left = rect?.left;\n this.stepsDetails[i].width = rect?.width;\n this.stepsDetails[i].height = rect?.height;\n }\n }\n }\n\n updateCurrentStepElement() {\n const cur = this.currentStep;\n this.stepsDetails[cur].element =\n this.document.getElementById(this.steps[cur].element) || this.document.querySelector(this.steps[cur].element);\n if (this.stepsDetails[cur].element) {\n const rect = this.stepsDetails[cur].element.getBoundingClientRect();\n const hasHighlightOffset = this.stepsDetails[cur].highlightOffset;\n const scrollTop = this.document.documentElement.scrollTop;\n this.stepsDetails[cur].top = rect?.top - (hasHighlightOffset ? this.stepsDetails[cur].highlightOffset[0] : 0) + scrollTop;\n this.stepsDetails[cur].left = rect?.left - (hasHighlightOffset ? this.stepsDetails[cur].highlightOffset[3] : 0);\n this.stepsDetails[cur].width =\n rect?.width + (hasHighlightOffset ? this.stepsDetails[cur].highlightOffset[3] + this.stepsDetails[cur].highlightOffset[1] : 0);\n this.stepsDetails[cur].height =\n rect?.height + (hasHighlightOffset ? this.stepsDetails[cur].highlightOffset[0] + this.stepsDetails[cur].highlightOffset[2] : 0);\n }\n }\n\n private canChange(index: number) {\n let changeResult = Promise.resolve(true);\n if (this.stepsDetails[index]?.beforeChange !== undefined) {\n const result: any = this.stepsDetails[index].beforeChange();\n if (typeof result !== 'undefined') {\n if (result.then) {\n changeResult = result;\n } else if (result.subscribe) {\n changeResult = (result as Observable<boolean>).toPromise();\n } else {\n changeResult = Promise.resolve(result);\n }\n }\n }\n return changeResult;\n }\n\n next() {\n this.changeStepState('forward');\n }\n\n prev() {\n this.changeStepState('backward');\n }\n\n exit() {\n if (this.currentStep === this.steps.length - 1) {\n this.isFinished.next(true);\n this.canFinish.next(false);\n }\n\n\n try {\n localStorage.setItem('devui-user-guide-last-step', this.currentStep);\n } catch (error) {\n console.error(error);\n }\n\n\n if (this.interactableEvent.eventType !== null) {\n this.interactableEvent.element.forEach((item, index) => {\n item.removeEventListener(this.interactableEvent.eventType[index], this.interactableEvent.eventFunction[index]);\n });\n }\n\n this.clearInteractableEvent();\n if (this.onExit) {\n this.onExit();\n }\n\n this.currentType = undefined;\n this.steps = [];\n this.stepsDetails = [];\n this.isStart = false;\n this.onExit = undefined;\n }\n\n goStep(index: number) {\n if (index > this.currentStep) {\n this.changeStepState('forward', Math.abs(this.currentStep - index));\n } else if (index < this.currentStep) {\n this.changeStepState('backward', Math.abs(this.currentStep - index));\n }\n }\n\n onBeforeChange(index: number) {\n this.clearInteractableEvent();\n\n this.registerInteractableEvent(index);\n }\n\n getCurrentStep() {\n return this.currentStep;\n }\n\n getCurrentDirection() {\n return this.currentDirection;\n }\n\n getStepLength() {\n return this.steps.length;\n }\n\n private registerInteractableEvent(index: number) {\n if (this.stepsDetails[index].eventType === 'clickable') {\n this.registerClickEvent(index);\n } else if (this.stepsDetails[index].eventType === 'inputable') {\n this.registerInputEvent(index);\n } else if (this.stepsDetails[index].eventType === 'exit') {\n this.registerExitEvent(index);\n }\n }\n\n private clearInteractableEvent() {\n if (this.interactableEvent.eventType !== null) {\n this.interactableEvent.eventType = null;\n this.interactableEvent.element = null;\n this.interactableEvent.eventFunction = null;\n\n this.showButtons.next(true);\n this.showOperateZone.next(false);\n this.canPrev.next(false);\n }\n }\n\n private registerClickEvent(index: number) {\n const clickElement = this.stepsDetails[index].element;\n\n this.interactableEvent.eventType = ['click'];\n this.interactableEvent.element = [clickElement];\n this.interactableEvent.eventFunction = [this.clickEventHandle.bind(this)];\n\n this.showButtons.next(false);\n\n clickElement.addEventListener('click', this.interactableEvent.eventFunction[0], { once: true });\n }\n\n private clickEventHandle() {\n const waitingTime = this.stepsDetails[this.currentStep].waitingTime || 300;\n this.document.body.addEventListener('click', disableClick, true);\n setTimeout(() => {\n this.updateNextStepElement();\n this.next();\n }, waitingTime);\n setTimeout(() => {\n this.document.body.removeEventListener('click', disableClick, true);\n }, 1000);\n }\n\n private registerInputEvent(index: number) {\n this.showOperateZone.next(true);\n\n setTimeout(() => {\n const inputElement = this.document.querySelector('.operate-zone') as HTMLElement;\n\n this.interactableEvent.eventType = ['input', 'click'];\n this.interactableEvent.element = [this.stepsDetails[this.currentStep].element, inputElement];\n this.interactableEvent.eventFunction = [this.inputEventHandle.bind(this), this.inputOperateZoneHandle.bind(this)];\n\n this.showButtons.next(false);\n\n this.stepsDetails[this.currentStep].element.addEventListener('input', this.interactableEvent.eventFunction[0], { once: true });\n inputElement.addEventListener('click', this.interactableEvent.eventFunction[1], { once: true });\n });\n }\n\n private inputEventHandle() {\n const operateZone = this.document.querySelector('.operate-zone') as HTMLElement;\n operateZone.innerHTML = '<p><i class=\"icon icon-right-o\" style=\"color: rgb(61, 204, 166); padding-right: 4px;\"></i>Good!</p>';\n this.showButtons.next(true);\n }\n\n private inputOperateZoneHandle() {\n this.stepsDetails[this.currentStep].element.value = this.stepsDetails[this.currentStep].inputData;\n const operateZone = this.document.querySelector('.operate-zone') as HTMLElement;\n operateZone.innerHTML = '<p><i class=\"icon icon-right-o\" style=\"color: rgb(61, 204, 166); padding-right: 4px;\"></i>Good!</p>';\n this.showButtons.next(true);\n }\n\n private registerExitEvent(index: number) {\n const clickElement = this.stepsDetails[index].element;\n\n this.interactableEvent.eventType = ['click'];\n this.interactableEvent.element = [clickElement];\n this.interactableEvent.eventFunction = [this.ExitEventHandle.bind(this)];\n\n this.showButtons.next(false);\n\n clickElement.addEventListener('click', this.interactableEvent.eventFunction[0], { once: true });\n }\n\n private ExitEventHandle() {\n this.generateOverlay('display');\n this.currentType = 'display';\n const panel = this.document.querySelector('.user-guide-panel') as HTMLElement;\n panel.style.cssText = `\n top: 50%;\n left:50%;\n transform: translate(-50%, -50%);\n `;\n\n const closeButton = this.document.querySelector('.user-guide-panel-close') as HTMLElement;\n closeButton.style.display = 'none';\n\n const carouselDots = this.document.querySelector('.devui-carousel-dots') as HTMLElement;\n if (carouselDots) {\n carouselDots.style.display = 'none';\n }\n\n const operateZone = this.document.querySelector('.user-guide-panel-multiple-body') as HTMLElement;\n operateZone.style.maxWidth = 'unset';\n operateZone.innerHTML = `<div style=\"text-align: center;\">\n <i class=\"icon icon-right-o\" style=\"color: rgb(61, 204, 166); font-size: 36px;\"></i>\n <p style=\"margin-top: 4px; font-size: 16px;\">Congratulations!</p></div>`;\n setTimeout(() => {\n this.exit();\n }, 2000);\n }\n\n private ChooseProperOverlay() {\n if (this.stepsDetails[this.currentStep].type !== this.currentType) {\n this.generateOverlay(this.stepsDetails[this.currentStep].type);\n this.currentType = this.stepsDetails[this.currentStep].type;\n }\n }\n\n private generateOverlay(type: string) {\n switch (type) {\n case 'normal':\n this.generateNormalOverlay();\n break;\n\n case 'interactable':\n this.generateInteractableOverlay();\n break;\n\n case 'display':\n this.generateDisplayOverlay();\n break;\n\n case 'tip':\n this.generateTipOverlay();\n break;\n\n default:\n break;\n }\n }\n\n private setStepShow(type: string, index: number) {\n this.curStepType.next(type);\n switch (type) {\n case 'normal':\n this.setNormalStepShow(index);\n break;\n\n case 'interactable':\n this.setInteractableStepShow(index);\n break;\n\n case 'display':\n this.setDisplayStepShow(index);\n break;\n\n case 'tip':\n this.setTipStepShow(index);\n break;\n\n default:\n break;\n }\n }\n\n private changeStepState(direction: string, times = 1) {\n this.currentDirection = direction;\n for (let i = 0; i < times; i++) {\n if (direction === 'forward' && this.nextStep < this.steps.length) {\n this.prevStep = this.currentStep;\n this.currentStep++;\n this.nextStep = this.currentStep + 1;\n } else if (direction === 'backward' && this.prevStep >= 0) {\n this.nextStep = this.currentStep;\n this.currentStep--;\n this.prevStep = this.currentStep - 1;\n }\n }\n\n this.curStep.next(this.currentStep);\n\n this.canNext.next(false);\n this.canPrev.next(false);\n }\n\n private changeStep() {\n if (this.currentStep >= 0 && this.currentStep < this.steps.length) {\n this.onBeforeChange(this.currentStep);\n this.ChooseProperOverlay();\n this.updateCurrentStepElement();\n this.setStepShow(this.currentType, this.currentStep);\n }\n\n if (this.nextStep === this.steps.length) {\n this.canNext.next(false);\n this.canFinish.next(true);\n } else {\n this.canNext.next(true);\n this.canFinish.next(false);\n }\n\n if (this.prevStep === -1) {\n this.canPrev.next(false);\n } else {\n this.canPrev.next(true);\n }\n }\n\n private generateNormalOverlay() {\n this._showOverlayState = {\n showMaskLayer: false,\n showNormalOverlay: true,\n showTopOverlay: true,\n showBottomOverlay: true,\n showLeftOverlay: true,\n showRightOverlay: true,\n showBorder: false,\n };\n\n this.showOverlayState.next(this._showOverlayState);\n }\n\n private setNormalStepShow(index: number) {\n this.setInteractableStepShow(index);\n }\n\n private generateInteractableOverlay() {\n this._showOverlayState = {\n showMaskLayer: false,\n showNormalOverlay: false,\n showTopOverlay: true,\n showBottomOverlay: true,\n showLeftOverlay: true,\n showRightOverlay: true,\n showBorder: true,\n };\n\n this.showOverlayState.next(this._showOverlayState);\n }\n\n private setInteractableStepShow(index: number) {\n const topOverlay = this.document.querySelector('.user-guide-top-overlay') as HTMLElement;\n topOverlay.style.cssText = `\n height: ${this.stepsDetails[index].top}px;\n `;\n\n const bottomOverlay = this.document.querySelector('.user-guide-bottom-overlay') as HTMLElement;\n bottomOverlay.style.cssText = `\n top: ${this.stepsDetails[index].top + this.stepsDetails[index].height}px;\n height: ${documentRealHeight(this.document) - (this.stepsDetails[index].top + this.stepsDetails[index].height)}px;\n `;\n\n const leftOverlay = this.document.querySelector('.user-guide-left-overlay') as HTMLElement;\n leftOverlay.style.cssText = `\n top: ${this.stepsDetails[index].top}px;\n width: ${this.stepsDetails[index].left}px;\n height: ${this.stepsDetails[index].height}px;\n `;\n\n const rightOverlay = this.document.querySelector('.user-guide-right-overlay') as HTMLElement;\n rightOverlay.style.cssText = `\n top: ${this.stepsDetails[index].top}px;\n left: ${this.stepsDetails[index].left + this.stepsDetails[index].width}px;\n width: ${this.document.documentElement.clientWidth - (this.stepsDetails[index].left + this.stepsDetails[index].width)}px;\n height: ${this.stepsDetails[index].height}px;\n `;\n\n const activeShadow = this.document.querySelector('.user-guide-active-shadow') as HTMLElement;\n activeShadow.style.cssText = `\n top: ${this.stepsDetails[index].top}px;\n left: ${this.stepsDetails[index].left}px;\n width: ${this.stepsDetails[index].width}px;\n height: ${this.stepsDetails[index].height}px;\n `;\n setTimeout(() => {\n this.panelPostion.calculatePosition(this.stepsDetails[this.currentStep]);\n }, 0);\n\n this.curContent.next(this.stepsDetails[index].title);\n this.curSubContent.next(this.stepsDetails[index].content);\n this.showPrevButton.next(this.stepsDetails[index].showPrevButton);\n }\n\n private generateDisplayOverlay() {\n this._showOverlayState = {\n showMaskLayer: true,\n showNormalOverlay: false,\n showTopOverlay: false,\n showBottomOverlay: false,\n showLeftOverlay: false,\n showRightOverlay: false,\n showBorder: false,\n };\n\n this.showOverlayState.next(this._showOverlayState);\n }\n\n private setDisplayStepShow(index: number) {\n const panel = this.document.querySelector('.user-guide-panel') as HTMLElement;\n panel.style.cssText = `\n top: 50%;\n left:50%;\n transform: translate(-50%, -50%);\n `;\n this.curContent.next(this.stepsDetails[index].title);\n this.curSubContent.next(this.stepsDetails[index].content);\n this.showPrevButton.next(this.stepsDetails[index].showPrevButton);\n }\n\n private generateTipOverlay() {\n this._showOverlayState = {\n showMaskLayer: false,\n showNormalOverlay: false,\n showTopOverlay: false,\n showBottomOverlay: false,\n showLeftOverlay: false,\n showRightOverlay: false,\n showBorder: false,\n };\n\n this.showOverlayState.next(this._showOverlayState);\n }\n\n private setTipStepShow(index: number) {\n this.setInteractableStepShow(index);\n }\n\n private createOnResizeObservable(renderer: Renderer2) {\n let removeResizeEventListener: () => void;\n const createResizeEventListener = (handler: (e: Event) => boolean | void) => {\n removeResizeEventListener = renderer.listen('window', 'resize', handler);\n };\n\n this.onResize = fromEventPattern<Event>(createResizeEventListener, () => removeResizeEventListener()).pipe(takeUntil(this._destory));\n }\n}\n","import { Component, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core';\nimport { IButtonStyle } from 'ng-devui/button';\nimport { I18nInterface, I18nService } from 'ng-devui/i18n';\nimport { Subscription } from 'rxjs';\nimport { UserGuideCoreService } from './user-guide-core.service';\nimport { IUserGuideExtraConfig } from './user-guide.types';\n\n@Component({\n selector: 'd-user-guide-ui',\n templateUrl: './user-guide-ui.component.html',\n styleUrls: ['./user-guide-ui.component.scss']\n})\nexport class UserGuideUIComponent implements OnInit, OnDestroy {\n i18nCommonText: I18nInterface['userGuide'];\n i18nSubscription: Subscription;\n @Input() showDots = false;\n @Input() maxContentWidth = 320;\n @Input() isCover = true;\n @Input() extraConfig: IUserGuideExtraConfig;\n stepsLength: number;\n currentStep: number;\n curStepType: string;\n title: string;\n content: string | TemplateRef<any>;\n canNext: boolean;\n canPrev: boolean;\n canFinish: boolean;\n\n showMaskLayer = false;\n\n showNormalOverlay = false;\n\n showTopOverlay = false;\n showBottomOverlay = false;\n showLeftOverlay = false;\n showRightOverlay = false;\n\n showBorder = false;\n\n showButtons = true;\n showOperateZone = false;\n\n showPrevButton = true;\n\n items = [];\n get contentTemplate(): TemplateRef<any> {\n return this.content as TemplateRef<any>;\n }\n\n get nextButtonType(): IButtonStyle {\n return (this.extraConfig?.nextButtonType || 'primary') as IButtonStyle;\n }\n constructor(private userGuideCoreService: UserGuideCoreService, private i18n: I18nService) { }\n\n ngOnInit() {\n this.userGuideCoreService.curContent.subscribe(item => {this.title = item;});\n this.userGuideCoreService.curSubContent.subscribe(item => {this.content = item;});\n this.userGuideCoreService.canNext.subscribe(item => {this.canNext = item;});\n this.userGuideCoreService.canPrev.subscribe(item => {this.canPrev = item;});\n this.userGuideCoreService.canFinish.subscribe(item => {this.canFinish = item;});\n this.userGuideCoreService.curStep.subscribe(item => {this.currentStep = item;});\n this.userGuideCoreService.curStepType.subscribe(item => {this.curStepType = item;});\n this.userGuideCoreService.showButtons.subscribe(item => {this.showButtons = item;});\n this.userGuideCoreService.showOperateZone.subscribe(item => {this.showOperateZone = item;});\n this.userGuideCoreService.showOverlayState.subscribe(item => {\n this.showMaskLayer = item.showMaskLayer;\n\n this.showNormalOverlay = item.showNormalOverlay;\n\n this.showTopOverlay = item.showTopOverlay;\n this.showBottomOverlay = item.showBottomOverlay;\n this.showLeftOverlay = item.showLeftOverlay;\n this.showRightOverlay = item.showRightOverlay;\n\n this.showBorder = item.showBorder;\n });\n this.userGuideCoreService.showPrevButton.subscribe(item => {this.showPrevButton = item;});\n\n this.stepsLength = this.userGuideCoreService.getStepLength();\n\n for (let i = 0; i < this.stepsLength; i++) {\n this.items.push(i);\n }\n this.i18nCommonText = this.i18n.getI18nText().userGuide;\n this.i18nSubscription = this.i18n.langChange().subscribe((data) => {\n this.i18nCommonText = data.userGuide;\n });\n }\n\n next() {\n this.userGuideCoreService.next();\n }\n\n prev() {\n this.userGuideCoreService.prev();\n }\n\n exit() {\n this.userGuideCoreService.exit();\n this.close();\n }\n\n close() {\n\n }\n\n switchStep(index) {\n this.userGuideCoreService.goStep(index);\n }\n\n disableClick(event) {\n event.preventDefault();\n event.stopPropagation();\n }\n\n isTemplateContent() {\n return this.content instanceof TemplateRef;\n }\n\n ngOnDestroy() {\n if (this.i18nSubscription) {\n this.i18nSubscription.unsubscribe();\n }\n }\n}\n","<div [class.show-overlay]=\"showMaskLayer && isCover\" class=\"user-guide-mask-layer\"></div>\n<div [class.show-overlay]=\"showNormalOverlay && isCover\" class=\"user-guide-normal-overlay\"></div>\n\n<div [class.show-overlay]=\"showTopOverlay && isCover\" class=\"user-guide-top-overlay\" (click)=\"disableClick($event)\"></div>\n<div [class.show-overlay]=\"showBottomOverlay && isCover\" class=\"user-guide-bottom-overlay\" (click)=\"disableClick($event)\"></div>\n<div [class.show-overlay]=\"showLeftOverlay && isCover\" class=\"user-guide-left-overlay\" (click)=\"disableClick($event)\"></div>\n<div [class.show-overlay]=\"showRightOverlay && isCover\" class=\"user-guide-right-overlay\" (click)=\"disableClick($event)\"></div>\n\n<div [class.show-overlay]=\"showBorder && isCover\" class=\"user-guide-active-shadow\" (click)=\"disableClick($event)\"></div>\n\n<div class=\"user-guide-panel\">\n <div\n *ngIf=\"!isCover && (stepsLength !== 1 || curStepType !== 'tip') && curStepType !== 'display'\"\n class=\"devui-user-guide-panel-arrow\"\n [style.background-color]=\"extraConfig?.panelBackground\"\n ></div>\n <div\n *ngIf=\"stepsLength !== 1 || curStepType !== 'tip'\"\n id=\"devui-user-guide\"\n class=\"user-guide-panel-multiple\"\n [style.background]=\"extraConfig?.panelBackground\"\n >\n <div class=\"user-guide-panel-multiple-header\">\n <d-icon class=\"user-guide-panel-close\" [icon]=\"closeTemplate\" [operable]=\"true\" (click)=\"exit()\"> </d-icon>\n </div>\n <div class=\"user-guide-panel-multiple-body\" [style.maxWidth.px]=\"maxContentWidth\">\n <div *ngIf=\"title\" class=\"user-guide-panel-title\" [style.color]=\"extraConfig?.infoColor\">\n <div class=\"user-guide-panel-title-index\">\n <svg\n width=\"24px\"\n height=\"24px\"\n viewBox=\"0 0 24 24\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n >\n <defs>\n <linearGradient x1=\"39.5307261%\" y1=\"4.02342885%\" x2=\"62.2425974%\" y2=\"95.9765712%\" id=\"star-linearGradient-1\">\n <stop stop-color=\"#FFDC42\" offset=\"0%\"></stop>\n <stop stop-color=\"#FAA631\" offset=\"100%\"></stop>\n </linearGradient>\n <linearGradient x1=\"50.4447351%\" y1=\"9.89598169%\" x2=\"50.4447351%\" y2=\"100%\" id=\"star-linearGradient-2\">\n <stop stop-color=\"#FFFDF5\" offset=\"0%\"></stop>\n <stop stop-color=\"#FFE46C\" offset=\"45.8568177%\"></stop>\n <stop stop-color=\"#FFE46C\" offset=\"77.1796784%\"></stop>\n <stop stop-color=\"#FFB84C\" offset=\"100%\"></stop>\n </linearGradient>\n <linearGradient x1=\"50%\" y1=\"0%\" x2=\"50%\" y2=\"100%\" id=\"star-linearGradient-3\">\n <stop stop-color=\"#FDD461\" offset=\"0%\"></stop>\n <stop stop-color=\"#FAA932\" offset=\"100%\"></stop>\n </linearGradient>\n <linearGradient x1=\"49.9999995%\" y1=\"100%\" x2=\"49.9999995%\" y2=\"6.6099008%\" id=\"star-linearGradient-4\">\n <stop stop-color=\"#FFCB7E\" offset=\"0%\"></stop>\n <stop stop-color=\"#FFA60C\" offset=\"31.1380841%\"></stop>\n <stop stop-color=\"#FFDA65\" offset=\"64.2551587%\"></stop>\n <stop stop-color=\"#F8E7B3\" offset=\"100%\"></stop>\n </linearGradient>\n </defs>\n <g id=\"页面-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <g id=\"星星\">\n <rect id=\"矩形\" opacity=\"0.848224019\" x=\"0\" y=\"0\" width=\"24\" height=\"24\" rx=\"1.5\"></rect>\n <g id=\"编组-30\" transform=\"translate(1.500000, 0.750000)\">\n <path\n d=\"M10.2849545,0.00312821355 C9.01530446,0.0801671154 7.93648512,1.57985131 6.82414587,4.47008186 L6.68705842,4.83270968 L6.25577388,4.89811591 L5.72946472,4.9840674 L5.22697862,5.07265412 L4.74822094,5.16405115 L4.29309704,5.25843358 C1.78084521,5.80205672 0.4023952,6.4979103 0.0802523031,7.48936419 L0.0527435764,7.58351023 C-0.223764928,8.64745912 0.589252054,9.94431065 2.43691735,11.6231017 L2.79546598,11.9423873 L3.1781838,12.2708429 L3.66780035,12.6765484 L3.53907311,13.3293274 L3.44799898,13.829093 L3.36780146,14.3082434 C3.34289719,14.4645382 3.3198289,14.6174178 3.29861979,14.7669031 L3.24059321,15.2051965 C2.95237883,17.5600309 3.17664519,18.9963886 4.01764407,19.60741 L4.09594063,19.6608172 C4.99328277,20.2344195 6.41801766,19.867408 8.49419949,18.6398756 L8.87889319,18.4072233 C8.94421443,18.3668735 9.01014077,18.325738 9.07667568,18.2838189 L9.4832155,18.0229203 L9.90452651,17.7433245 L10.3925423,17.409 L10.6636031,17.592728 L11.0861157,17.8731527 L11.4939736,18.1359757 L11.8873453,18.3811025 C11.9517094,18.420477 12.015477,18.4591102 12.0786514,18.4970002 L12.4506094,18.7154052 C12.6330581,18.8201324 12.8102323,18.9181349 12.9822267,19.0093594 L13.3193373,19.1827553 C14.9155955,19.9770028 16.0337342,20.1345728 16.7593115,19.60741 L16.8322112,19.5509531 C17.4404328,19.0494252 17.6883676,18.0458603 17.6249485,16.4915 L17.603775,16.1078533 L17.5707959,15.7029063 C17.5449079,15.4258082 17.5112498,15.1344101 17.4700218,14.8285121 L17.4025276,14.3587654 C17.3903407,14.2786535 17.377687,14.1976291 17.3645695,14.1156891 L17.2803251,13.613037 L17.1851018,13.0882608 L17.1057681,12.6812903 L17.1896115,12.6144018 C17.3293157,12.5014059 17.4650241,12.3899369 17.5967223,12.2799601 L17.9797719,11.9544721 L18.3386732,11.6377301 C20.2460636,9.91931968 21.0537817,8.58833879 20.6967032,7.48936419 L20.663964,7.39795277 C20.3400348,6.57159251 19.3245511,5.9514404 17.5893825,5.46113493 L17.1761707,5.35025772 C17.0341664,5.31404381 16.8878908,5.27856346 16.7373311,5.24378192 L16.2727869,5.14149897 C16.1136462,5.10808029 15.9502086,5.07532566 15.7824614,5.04320033 L15.2662775,4.94867745 L14.7241587,4.85772181 L14.5451229,4.82932258 L14.4696753,4.66957886 C12.9812146,1.55985477 11.7071674,-7.32747196e-14 10.3884778,-7.32747196e-14 L10.2849545,0.00312821355 Z\"\n id=\"路径\"\n fill=\"url(#star-linearGradient-1)\"\n fill-rule=\"nonzero\"\n ></path>\n <path\n d=\"M10.3884778,1.35483871 C10.698933,1.35483871 11.1473381,1.73828119 11.6929355,2.50673715 L11.8684127,2.76220752 C11.8981815,2.80691957 11.9282076,2.85269859 11.9584852,2.89954482 L12.1431199,3.1934305 L12.333503,3.51294013 L12.5293494,3.85808471 L12.7303739,4.22887523 L12.9362911,4.62532267 L13.1468159,5.04743805 C13.1822715,5.11993022 13.2179072,5.19349234 13.2537171,5.26812464 L13.4706185,5.72876252 L13.6241243,6.06080357 L13.9859608,6.11455876 C14.1641422,6.14102976 14.3380531,6.16803704 14.5076775,6.19553742 L15.0036752,6.27947467 L15.4738587,6.36611146 C15.5500662,6.38076149 15.625194,6.3955132 15.6992403,6.41036121 L16.1305234,6.50056152 C16.2002355,6.51577309 16.2688621,6.53107015 16.3364011,6.54644731 L16.7285692,6.63962823 L17.0945412,6.73447239 C17.2121552,6.76633553 17.3253874,6.7984327 17.4342217,6.83072071 L17.7475153,6.92811413 C18.7477431,7.25437947 19.3065985,7.59541179 19.4081751,7.90803238 C19.4934424,8.17045841 19.2883637,8.62751564 18.7797589,9.24774919 L18.5989641,9.46049412 C18.4389036,9.64274596 18.2553099,9.83731888 18.0479004,10.0435387 L17.7875595,10.2965499 L17.5042469,10.5604832 C17.4551078,10.6053678 17.4050071,10.6506968 17.3539424,10.6964647 L17.0359691,10.9762958 L16.6947531,11.2664018 L16.3301858,11.5665238 C16.2674726,11.6173645 16.203782,11.6686116 16.1391116,11.72026 L15.6136198,12.1349914 L15.697482,12.5445924 C16.08423,14.433552 16.2763848,15.9111437 16.2763848,16.9661037 C16.2763848,17.8761079 16.1311295,18.3891382 15.9629573,18.5113225 C15.8300053,18.6079177 15.5616817,18.601431 15.1681121,18.486175 L14.9776083,18.425236 L14.7695393,18.3487262 C14.6611504,18.3065578 14.5462574,18.2585039 14.424985,18.2044944 L14.1739709,18.0885141 L13.9061659,17.956528 L13.6217912,17.8084121 L13.321068,17.644042 L13.0042177,17.4632934 L12.4991875,17.1611893 L12.142987,16.938951 L11.7714335,16.6998995 L11.3847483,16.4439104 L10.9831526,16.1708594 L10.3859552,15.7553852 L9.99736535,16.0311488 C9.81569992,16.1600681 9.63812068,16.2841165 9.46464912,16.4032906 L8.95657891,16.7461861 C7.88255303,17.4574274 6.98298347,17.9625763 6.26376755,18.2606573 C5.46502915,18.5916966 4.97946103,18.6315382 4.81399828,18.5113225 C4.62937748,18.3771876 4.47932656,17.8617864 4.47932656,16.9506689 C4.47932656,16.269409 4.56255815,15.4131874 4.72973741,14.3851273 L4.82925578,13.8073442 C4.88318197,13.5099505 4.94336188,13.1998176 5.00981004,12.877009 L5.16574773,12.1400686 L4.83794663,11.8788974 C4.50171066,11.6110058 4.18930468,11.3532121 3.90081117,11.1057047 L3.48601555,10.7421818 C2.82461448,10.1492467 2.31292405,9.62119004 1.952233,9.16095683 C1.46234724,8.53587427 1.30403179,8.10730838 1.36878049,7.90803238 C1.43601883,7.70109403 1.89806718,7.38372936 2.79109438,7.07213055 C3.75858961,6.73454804 5.14367806,6.43046355 6.93848028,6.16463381 L7.68453956,6.05800922 L7.82258087,5.6732626 C7.9090951,5.43213148 7.9950492,5.20119982 8.08026573,4.98044224 L8.24966276,4.55248498 C8.36186839,4.27621374 8.47255245,4.01799966 8.5812943,3.77778255 L8.74289786,3.43094709 L8.90127264,3.11106196 C8.92738184,3.05999112 8.95334337,3.01004133 8.97915065,2.96121166 L9.13209074,2.68166738 C9.63537056,1.79460735 10.0716926,1.35483871 10.3884778,1.35483871 Z\"\n id=\"路径\"\n fill=\"url(#star-linearGradient-2)\"\n ></path>\n <path\n d=\"M18,0.5625 C17.0680195,0.5625 16.3125,1.31801948 16.3125,2.25 C16.3125,3.18198052 17.0680195,3.9375 18,3.9375 C18.9319805,3.9375 19.6875,3.18198052 19.6875,2.25 C19.6875,1.31801948 18.9319805,0.5625 18,0.5625 Z\"\n id=\"路径\"\n fill=\"url(#star-linearGradient-3)\"\n fill-rule=\"nonzero\"\n ></path>\n <path\n d=\"M18,0.9375 C18.7248737,0.9375 19.3125,1.52512627 19.3125,2.25 C19.3125,2.97487373 18.7248737,3.5625 18,3.5625 C17.2751263,3.5625 16.6875,2.97487373 16.6875,2.25 C16.6875,1.52512627 17.2751263,0.9375 18,0.9375 Z\"\n id=\"路径\"\n fill=\"url(#star-linearGradient-4)\"\n fill-rule=\"nonzero\"\n ></path>\n <path\n d=\"M10.5,19.3125 C9.56801948,19.3125 8.8125,20.0680195 8.8125,21 C8.8125,21.9319805 9.56801948,22.6875 10.5,22.6875 C11.4319805,22.6875 12.1875,21.9319805 12.1875,21 C12.1875,20.0680195 11.4319805,19.3125 10.5,19.3125 Z\"\n id=\"路径\"\n fill=\"url(#star-linearGradient-3)\"\n fill-rule=\"nonzero\"\n ></path>\n <path\n d=\"M10.5,19.6875 C11.2248737,19.6875 11.8125,20.2751263 11.8125,21 C11.8125,21.7248737 11.2248737,22.3125 10.5,22.3125 C9.77512627,22.3125 9.1875,21.7248737 9.1875,21 C9.1875,20.2751263 9.77512627,19.6875 10.5,19.6875 Z\"\n id=\"路径\"\n fill=\"url(#star-linearGradient-4)\"\n fill-rule=\"nonzero\"\n ></path>\n <path\n d=\"M3,0.5625 C2.06801948,0.5625 1.3125,1.31801948 1.3125,2.25 C1.3125,3.18198052 2.06801948,3.9375 3,3.9375 C3.93198052,3.9375 4.6875,3.18198052 4.6875,2.25 C4.6875,1.31801948 3.93198052,0.5625 3,0.5625 Z\"\n id=\"路径\"\n fill=\"url(#star-linearGradient-3)\"\n fill-rule=\"nonzero\"\n ></path>\n <path\n d=\"M3,0.9375 C3.72487373,0.9375 4.3125,1.52512627 4.3125,2.25 C4.3125,2.97487373 3.72487373,3.5625 3,3.5625 C2.27512627,3.5625 1.6875,2.97487373 1.6875,2.25 C1.6875,1.52512627 2.27512627,0.9375 3,0.9375 Z\"\n id=\"路径\"\n fill=\"url(#star-linearGradient-4)\"\n fill-rule=\"nonzero\"\n ></path>\n </g>\n </g>\n </g>\n </svg>\n </div>\n {{ title }}\n </div>\n <div *ngIf=\"content\" class=\"user-guide-panel-content\" [style.color]=\"extraConfig?.infoColor\">\n <div *ngIf=\"!isTemplateContent()\" [innerHTML]=\"content | safe : 'html'\"></div>\n <ng-container *ngIf=\"isTemplateContent()\">\n <ng-container *ngTemplateOutlet=\"contentTemplate\"></ng-container>\n </ng-container>\n </div>\n <div *ngIf=\"showOperateZone\" class=\"operate-zone\">\n <p><i class=\"icon icon-info-o\" style=\"color: rgb(81, 112, 255); padding-right: 4px\"></i>{{ i18nCommonText.autoFill }}</p>\n </div>\n </div>\n <div class=\"user-guide-panel-multiple-footer\" [class.user-guide-panel-multiple-footer-only-dot]=\"!showButtons\">\n <div class=\"user-guide-panel-multiple-footer-left\">\n <ul class=\"devui-carousel-dots\" *ngIf=\"stepsLength > 1 && showDots\">\n <li\n class=\"dot-item\"\n [ngClass]=\"{ active: currentStep === index }\"\n [style.background]=\"currentStep === index ? extraConfig?.operationColor : extraConfig?.dotColor\"\n *ngFor=\"let item of items; let index = index\"\n (click)=\"switchStep(index)\"\n ></li>\n </ul>\n </div>\n <div *ngIf=\"showButtons\" class=\"user-guide-panel-multiple-footer-right\">\n <d-button bsStyle=\"common\" [disabled]=\"!canPrev\" *ngIf=\"showPrevButton\" (btnClick)=\"prev()\">{{ i18nCommonText.prev }}</d-button>\n <d-button *ngIf=\"!canFinish\" [disabled]=\"!canNext\" [bsStyle]=\"nextButtonType\" (btnClick)=\"next()\">{{\n i18nCommonText.next\n }}</d-button>\n <d-button\n *ngIf=\"currentStep === stepsLength - 1 && canFinish\"\n [bsStyle]=\"nextButtonType\"\n [disabled]=\"!canFinish\"\n (btnClick)=\"exit()\"\n >{{ i18nCommonText.finish }}</d-button\n >\n </div>\n </div>\n </div>\n\n <div *ngIf=\"stepsLength === 1 && curStepType === 'tip'\">\n <div *ngIf=\"curStepType === 'tip'\" class=\"devui-user-guide-panel-arrow\"></div>\n <div [class.user-guide-panel-tip]=\"curStepType === 'tip'\" [class.user-guide-panel-single]=\"curStepType !== 'tip'\">\n {{ title }}\n <div *ngIf=\"content\" class=\"user-guide-panel-content\" [innerHTML]=\"content | safe : 'html'\"></div>\n <button type=\"button\" class=\"close\" aria-label=\"Close\" (click)=\"exit()\">\n <svg class=\"svg-icon-close\" xmlns=\"http://www.w3.org/2000/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 12 12\" version=\"1.1\">\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <g transform=\"translate(-2.000000, -2.000000)\" fill-rule=\"nonzero\">\n <polygon\n points=\"8 6.58578644 12.2426407 2.34314575 13.6568542 3.75735931 9.41421356 8 13.6568542 12.2426407 12.2426407 13.6568542 8 9.41421356 3.75735931 13.6568542 2.34314575 12.2426407 6.58578644 8 2.34314575 3.75735931 3.75735931 2.34314575\"\n />\n </g>\n </g>\n </svg>\n </button>\n </div>\n </div>\n</div>\n<ng-template #closeTemplate>\n <svg\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n >\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <path\n d=\"M14.6887175,1.25368865 C15.0770801,1.64205125 15.0121881,2.34244569 14.544513,2.81012074 L9.383,7.971 L14.544513,13.1322854 C14.9787827,13.5665551 15.0657548,14.2014859 14.7650189,14.6009195 L14.6887175,14.6887175 C14.3003549,15.0770801 13.5999604,15.0121881 13.1322854,14.544513 L13.1322854,14.544513 L7.971,9.383 L2.81012075,14.544513 C2.3424457,15.0121881 1.64205125,15.0770801 1.25368865,14.6887175 C0.865326051,14.3003549 0.930218063,13.5999605 1.39789313,13.1322854 L6.558,7.971 L1.39789311,2.81012074 C0.963623424,2.37585105 0.876651354,1.74092026 1.17738727,1.34148668 L1.25368865,1.25368865 C1.64205125,0.865326051 2.34244569,0.930218063 2.81012074,1.39789311 L2.81012074,1.39789311 L7.971,6.558 L13.1322854,1.39789311 C13.5999605,0.930218063 14.3003549,0.865326051 14.6887175,1.25368865 Z\"\n id=\"形状结合\"\n fill=\"#8A8E99\"\n fill-rule=\"nonzero\"\n ></path>\n </g>\n </svg>\n</ng-template>\n","import {\n AfterViewInit, Component,\n ComponentFactoryResolver,\n ComponentRef,\n Input,\n OnDestroy,\n OnInit\n} from '@angular/core';\nimport { I18nInterface, I18nService } from 'ng-devui/i18n';\nimport { OverlayContainerRef } from 'ng-devui/overlay-container';\nimport { Subscription } from 'rxjs';\nimport { UserGuideCoreService } from './user-guide-core.service';\nimport { UserGuideUIComponent } from './user-guide-ui.component';\n\n@Component({\n selector: 'd-user-guide',\n templateUrl: './user-guide.component.html',\n styleUrls: ['./user-guide.component.scss']\n})\nexport class UserGuideComponent implements OnInit, AfterViewInit, OnDestr