commit
aef243e942
@ -0,0 +1,41 @@
|
|||||||
|
import Editor from '../../../src/editor'
|
||||||
|
|
||||||
|
describe('菜单-内容块', () => {
|
||||||
|
const url = 'http://localhost:3000/canvas-editor/'
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit(url)
|
||||||
|
|
||||||
|
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
it('内容块', () => {
|
||||||
|
cy.getEditor().then((editor: Editor) => {
|
||||||
|
editor.listener.saved = function (payload) {
|
||||||
|
const data = payload.data
|
||||||
|
|
||||||
|
expect(data[0].type).to.eq('block')
|
||||||
|
|
||||||
|
expect(data[0].block?.iframeBlock?.src).to.eq(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
editor.command.executeSelectAll()
|
||||||
|
|
||||||
|
editor.command.executeBackspace()
|
||||||
|
|
||||||
|
cy.get('.menu-item__block').click()
|
||||||
|
|
||||||
|
cy.get('.dialog-option__item [name="width"]').type('500')
|
||||||
|
|
||||||
|
cy.get('.dialog-option__item [name="height"]').type('300')
|
||||||
|
|
||||||
|
cy.get('.dialog-option__item [name="value"]').type(url)
|
||||||
|
|
||||||
|
cy.get('.dialog-menu button').eq(1).click()
|
||||||
|
|
||||||
|
cy.get('@canvas').type('{ctrl}s')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
After Width: | Height: | Size: 568 B |
@ -0,0 +1,8 @@
|
|||||||
|
.block-item {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 1px solid rgb(235 236 240);
|
||||||
|
}
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
import { ElementType } from '../../../../dataset/enum/Element'
|
||||||
|
import { IRowElement } from '../../../../interface/Row'
|
||||||
|
import { Draw } from '../../Draw'
|
||||||
|
import { BaseBlock } from './modules/BaseBlock'
|
||||||
|
|
||||||
|
export class BlockParticle {
|
||||||
|
|
||||||
|
private draw: Draw
|
||||||
|
private container: HTMLDivElement
|
||||||
|
private blockContainer: HTMLDivElement
|
||||||
|
private blockMap: Map<string, BaseBlock>
|
||||||
|
|
||||||
|
constructor(draw: Draw) {
|
||||||
|
this.draw = draw
|
||||||
|
this.container = draw.getContainer()
|
||||||
|
this.blockMap = new Map()
|
||||||
|
this.blockContainer = this._createBlockContainer()
|
||||||
|
this.container.append(this.blockContainer)
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createBlockContainer(): HTMLDivElement {
|
||||||
|
const blockContainer = document.createElement('div')
|
||||||
|
blockContainer.classList.add('block-container')
|
||||||
|
return blockContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDraw(): Draw {
|
||||||
|
return this.draw
|
||||||
|
}
|
||||||
|
|
||||||
|
public getBlockContainer(): HTMLDivElement {
|
||||||
|
return this.blockContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(pageNo: number, element: IRowElement, x: number, y: number) {
|
||||||
|
const id = element.id!
|
||||||
|
const cacheBlock = this.blockMap.get(id)
|
||||||
|
if (cacheBlock) {
|
||||||
|
cacheBlock.setClientRects(pageNo, x, y)
|
||||||
|
} else {
|
||||||
|
const newBlock = new BaseBlock(this, element)
|
||||||
|
newBlock.render()
|
||||||
|
newBlock.setClientRects(pageNo, x, y)
|
||||||
|
this.blockMap.set(id, newBlock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public clear() {
|
||||||
|
if (!this.blockMap.size) return
|
||||||
|
const elementList = this.draw.getElementList()
|
||||||
|
const blockElementIds: string[] = []
|
||||||
|
for (let e = 0; e < elementList.length; e++) {
|
||||||
|
const element = elementList[e]
|
||||||
|
if (element.type === ElementType.BLOCK) {
|
||||||
|
blockElementIds.push(element.id!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.blockMap.forEach(block => {
|
||||||
|
const id = block.getBlockElement().id!
|
||||||
|
if (!blockElementIds.includes(id)) {
|
||||||
|
block.remove()
|
||||||
|
this.blockMap.delete(id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
import { BlockType } from '../../../../../dataset/enum/Block'
|
||||||
|
import { IRowElement } from '../../../../../interface/Row'
|
||||||
|
import { Draw } from '../../../Draw'
|
||||||
|
import { BlockParticle } from '../BlockParticle'
|
||||||
|
import { IFrameBlock } from './IFrameBlock'
|
||||||
|
import { VideoBlock } from './VideoBlock'
|
||||||
|
|
||||||
|
export class BaseBlock {
|
||||||
|
|
||||||
|
private draw: Draw
|
||||||
|
private element: IRowElement
|
||||||
|
private block: IFrameBlock | VideoBlock | null
|
||||||
|
private blockContainer: HTMLDivElement
|
||||||
|
private blockItem: HTMLDivElement
|
||||||
|
|
||||||
|
constructor(blockParticle: BlockParticle, element: IRowElement) {
|
||||||
|
this.draw = blockParticle.getDraw()
|
||||||
|
this.blockContainer = blockParticle.getBlockContainer()
|
||||||
|
this.element = element
|
||||||
|
this.block = null
|
||||||
|
this.blockItem = this._createBlockItem()
|
||||||
|
this.blockContainer.append(this.blockItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
public getBlockElement(): IRowElement {
|
||||||
|
return this.element
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createBlockItem(): HTMLDivElement {
|
||||||
|
const blockItem = document.createElement('div')
|
||||||
|
blockItem.classList.add('block-item')
|
||||||
|
return blockItem
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
const block = this.element.block!
|
||||||
|
if (block.type === BlockType.IFRAME) {
|
||||||
|
this.block = new IFrameBlock(this.element)
|
||||||
|
this.block.render(this.blockItem)
|
||||||
|
} else if (block.type === BlockType.VIDEO) {
|
||||||
|
this.block = new VideoBlock(this.element)
|
||||||
|
this.block.render(this.blockItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setClientRects(pageNo: number, x: number, y: number) {
|
||||||
|
const scale = this.draw.getOptions().scale
|
||||||
|
const height = this.draw.getHeight()
|
||||||
|
const pageGap = this.draw.getPageGap()
|
||||||
|
const preY = pageNo * (height + pageGap)
|
||||||
|
// 尺寸
|
||||||
|
this.blockItem.style.width = `${this.element.width! * scale}px`
|
||||||
|
this.blockItem.style.height = `${this.element.height! * scale}px`
|
||||||
|
// 位置
|
||||||
|
this.blockItem.style.left = `${x}px`
|
||||||
|
this.blockItem.style.top = `${preY + y}px`
|
||||||
|
}
|
||||||
|
|
||||||
|
public remove() {
|
||||||
|
this.blockItem.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
import { IRowElement } from '../../../../../interface/Row'
|
||||||
|
|
||||||
|
export class IFrameBlock {
|
||||||
|
|
||||||
|
private static readonly sandbox = [
|
||||||
|
'allow-forms',
|
||||||
|
'allow-scripts',
|
||||||
|
'allow-same-origin',
|
||||||
|
'allow-popups'
|
||||||
|
]
|
||||||
|
private element: IRowElement
|
||||||
|
|
||||||
|
constructor(element: IRowElement) {
|
||||||
|
this.element = element
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(blockItemContainer: HTMLDivElement) {
|
||||||
|
const block = this.element.block!
|
||||||
|
const iframe = document.createElement('iframe')
|
||||||
|
iframe.sandbox.add(...IFrameBlock.sandbox)
|
||||||
|
iframe.style.border = 'none'
|
||||||
|
iframe.style.width = '100%'
|
||||||
|
iframe.style.height = '100%'
|
||||||
|
iframe.src = block.iframeBlock?.src || ''
|
||||||
|
blockItemContainer.append(iframe)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
import { IRowElement } from '../../../../../interface/Row'
|
||||||
|
|
||||||
|
export class VideoBlock {
|
||||||
|
|
||||||
|
private element: IRowElement
|
||||||
|
|
||||||
|
constructor(element: IRowElement) {
|
||||||
|
this.element = element
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(blockItemContainer: HTMLDivElement) {
|
||||||
|
const block = this.element.block!
|
||||||
|
const video = document.createElement('video')
|
||||||
|
video.style.width = '100%'
|
||||||
|
video.style.height = '100%'
|
||||||
|
video.style.objectFit = 'contain'
|
||||||
|
video.src = block.videoBlock?.src || ''
|
||||||
|
video.controls = true
|
||||||
|
video.crossOrigin = 'anonymous'
|
||||||
|
blockItemContainer.append(video)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
export enum BlockType {
|
||||||
|
IFRAME = 'iframe',
|
||||||
|
VIDEO = 'video'
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
import { BlockType } from '../dataset/enum/Block'
|
||||||
|
|
||||||
|
export interface IIFrameBlock {
|
||||||
|
src: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IVideoBlock {
|
||||||
|
src: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IBlock {
|
||||||
|
type: BlockType;
|
||||||
|
iframeBlock?: IIFrameBlock;
|
||||||
|
videoBlock?: IVideoBlock;
|
||||||
|
}
|
||||||
Loading…
Reference in new issue