feat:add separator
This commit is contained in:
+22
@@ -122,6 +122,28 @@
|
||||
</div>
|
||||
<div class="menu-item__separator">
|
||||
<i></i>
|
||||
<div class="options">
|
||||
<ul>
|
||||
<li data-separator='0,0'>
|
||||
<i></i>
|
||||
</li>
|
||||
<li data-separator="1,1">
|
||||
<i></i>
|
||||
</li>
|
||||
<li data-separator="3,1">
|
||||
<i></i>
|
||||
</li>
|
||||
<li data-separator="4,4">
|
||||
<i></i>
|
||||
</li>
|
||||
<li data-separator="7,3,3,3">
|
||||
<i></i>
|
||||
</li>
|
||||
<li data-separator="6,2,2,2,2,2">
|
||||
<i></i>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="menu-divider"></div>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg width="126" height="20" xmlns="http://www.w3.org/2000/svg"><path d="M4 10h5v1H4zm7 0h2v1h-2zm4 0h2v1h-2zm4 0h5v1h-5zm7 0h2v1h-2zm4 0h2v1h-2zm4 0h5v1h-5zm7 0h2v1h-2zm4 0h2v1h-2zm4 0h5v1h-5zm7 0h2v1h-2zm4 0h2v1h-2zm4 0h5v1h-5zm7 0h2v1h-2zm4 0h2v1h-2zm4 0h5v1h-5zm7 0h2v1h-2zm4 0h2v1h-2zm4 0h5v1h-5zm7 0h2v1h-2zm4 0h2v1h-2zm4 0h5v1h-5zm7 0h2v1h-2zm4 0h2v1h-2z" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 390 B |
@@ -0,0 +1 @@
|
||||
<svg width="126" height="20" xmlns="http://www.w3.org/2000/svg"><path d="M4 10h6v1H4zm9 0h3v1h-3zm6 0h6v1h-6zm9 0h3v1h-3zm6 0h6v1h-6zm9 0h3v1h-3zm6 0h6v1h-6zm9 0h3v1h-3zm6 0h6v1h-6zm9 0h3v1h-3zm6 0h6v1h-6zm9 0h3v1h-3zm6 0h6v1h-6zm9 0h3v1h-3zm6 0h6v1h-6zm9 0h3v1h-3z" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 294 B |
@@ -0,0 +1 @@
|
||||
<svg width="126" height="20" xmlns="http://www.w3.org/2000/svg"><path d="M5 10h4v1H5zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4zm8 0h4v1h-4z" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 282 B |
@@ -0,0 +1 @@
|
||||
<svg width="126" height="20" xmlns="http://www.w3.org/2000/svg"><path d="M4 10h4v1H4zm5 0h4v1H9zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h4v1h-4zm5 0h3v1h-3z" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 389 B |
@@ -0,0 +1 @@
|
||||
<svg width="126" height="20" xmlns="http://www.w3.org/2000/svg"><path d="M4 10h1v1H4zm12 0h1v1h-1zM6 10h1v1H6zm12 0h1v1h-1zM8 10h1v1H8zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm2 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm2 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm2 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm2 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1zm12 0h1v1h-1zm-10 0h1v1h-1z" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 885 B |
@@ -0,0 +1 @@
|
||||
<svg width="126" height="20" xmlns="http://www.w3.org/2000/svg"><path d="M4 10h118v1H4z" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 116 B |
@@ -235,8 +235,8 @@ export class Command {
|
||||
return Command.image(payload)
|
||||
}
|
||||
|
||||
public executeSeparator() {
|
||||
return Command.separator()
|
||||
public executeSeparator(payload: number[]) {
|
||||
return Command.separator(payload)
|
||||
}
|
||||
|
||||
public executeSearch(payload: string | null) {
|
||||
|
||||
@@ -890,18 +890,32 @@ export class CommandAdapt {
|
||||
this.draw.render({ curIndex })
|
||||
}
|
||||
|
||||
public separator() {
|
||||
public separator(payload: number[]) {
|
||||
const { startIndex, endIndex } = this.range.getRange()
|
||||
if (!~startIndex && !~endIndex) return
|
||||
const elementList = this.draw.getElementList()
|
||||
// 光标后是否存在分割线
|
||||
if (elementList[endIndex]?.type === ElementType.SEPARATOR) return
|
||||
const element: IElement = {
|
||||
value: '\n',
|
||||
type: ElementType.SEPARATOR
|
||||
let curIndex = -1
|
||||
// 光标存在分割线,则判断为修改线段逻辑
|
||||
const endElement = elementList[endIndex + 1]
|
||||
if (endElement && endElement.type === ElementType.SEPARATOR) {
|
||||
if (endElement.dashArray && endElement.dashArray.join() === payload.join()) return
|
||||
curIndex = endIndex
|
||||
endElement.dashArray = payload
|
||||
} else {
|
||||
const newElement: IElement = {
|
||||
value: '\n',
|
||||
type: ElementType.SEPARATOR,
|
||||
dashArray: payload
|
||||
}
|
||||
// 从行头增加分割线
|
||||
if (startIndex !== 0 && elementList[startIndex].value === ZERO) {
|
||||
elementList.splice(startIndex, 1, newElement)
|
||||
curIndex = startIndex - 1
|
||||
} else {
|
||||
elementList.splice(startIndex + 1, 0, newElement)
|
||||
curIndex = startIndex
|
||||
}
|
||||
}
|
||||
const curIndex = startIndex + 1
|
||||
elementList.splice(curIndex, 0, element)
|
||||
this.range.setRange(curIndex, curIndex)
|
||||
this.draw.render({ curIndex })
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ export class Draw {
|
||||
this.pageNumber = new PageNumber(this)
|
||||
this.header = new Header(this)
|
||||
this.hyperlinkParticle = new HyperlinkParticle(this)
|
||||
this.separatorParticle = new SeparatorParticle(this)
|
||||
this.separatorParticle = new SeparatorParticle()
|
||||
this.superscriptParticle = new SuperscriptParticle()
|
||||
this.subscriptParticle = new SubscriptParticle()
|
||||
|
||||
@@ -447,6 +447,7 @@ export class Draw {
|
||||
metrics.boundingBoxDescent = elementHeight
|
||||
metrics.boundingBoxAscent = 0
|
||||
} else if (element.type === ElementType.SEPARATOR) {
|
||||
element.width = innerWidth
|
||||
metrics.width = innerWidth
|
||||
metrics.height = this.options.defaultSize
|
||||
metrics.boundingBoxAscent = -rowMargin
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
import { IRowElement } from "../../../interface/Row"
|
||||
import { Draw } from "../Draw"
|
||||
|
||||
export class SeparatorParticle {
|
||||
|
||||
private draw: Draw
|
||||
|
||||
constructor(draw: Draw) {
|
||||
this.draw = draw
|
||||
}
|
||||
|
||||
public render(ctx: CanvasRenderingContext2D, element: IRowElement, x: number, y: number) {
|
||||
const innerWidth = this.draw.getInnerWidth()
|
||||
ctx.save()
|
||||
if (element.color) {
|
||||
ctx.strokeStyle = element.color
|
||||
}
|
||||
ctx.translate(0.5, 0.5)
|
||||
if (element.dashArray && element.dashArray.length) {
|
||||
ctx.setLineDash(element.dashArray)
|
||||
}
|
||||
ctx.translate(0, 0.5) // 从1处渲染,避免线宽度等于3
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(x, y)
|
||||
ctx.lineTo(x + innerWidth, y)
|
||||
ctx.lineTo(x + element.width!, y)
|
||||
ctx.stroke()
|
||||
ctx.restore()
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ export class RangeManager {
|
||||
const highlight = curElement.highlight || null
|
||||
const rowFlex = curElement.rowFlex || null
|
||||
const rowMargin = curElement.rowMargin || this.options.defaultRowMargin
|
||||
const dashArray = curElement.dashArray || []
|
||||
// 菜单
|
||||
const painter = !!this.draw.getPainterStyle()
|
||||
const undo = this.historyManager.isCanUndo()
|
||||
@@ -95,7 +96,8 @@ export class RangeManager {
|
||||
color,
|
||||
highlight,
|
||||
rowFlex,
|
||||
rowMargin
|
||||
rowMargin,
|
||||
dashArray
|
||||
})
|
||||
}
|
||||
|
||||
@@ -119,7 +121,8 @@ export class RangeManager {
|
||||
color: null,
|
||||
highlight: null,
|
||||
rowFlex: null,
|
||||
rowMargin
|
||||
rowMargin,
|
||||
dashArray: []
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,16 @@ export interface ISuperscriptSubscript {
|
||||
actualSize?: number;
|
||||
}
|
||||
|
||||
export type IElement = IElementBasic & IElementStyle & ITable & IHyperlinkElement & ISuperscriptSubscript
|
||||
export interface ISeparator {
|
||||
dashArray?: number[];
|
||||
}
|
||||
|
||||
export type IElement = IElementBasic
|
||||
& IElementStyle
|
||||
& ITable
|
||||
& IHyperlinkElement
|
||||
& ISuperscriptSubscript
|
||||
& ISeparator
|
||||
|
||||
export interface IElementMetrics {
|
||||
width: number;
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface IRangeStyle {
|
||||
highlight: string | null;
|
||||
rowFlex: RowFlex | null;
|
||||
rowMargin: number;
|
||||
dashArray: number[];
|
||||
}
|
||||
|
||||
export type IRangeStyleChange = (payload: IRangeStyle) => void
|
||||
|
||||
+28
-4
@@ -465,9 +465,22 @@ window.onload = function () {
|
||||
})
|
||||
}
|
||||
const separatorDom = document.querySelector<HTMLDivElement>('.menu-item__separator')!
|
||||
const separatorOptionDom = separatorDom.querySelector<HTMLDivElement>('.options')!
|
||||
separatorDom.onclick = function () {
|
||||
console.log('separator')
|
||||
instance.command.executeSeparator()
|
||||
separatorOptionDom.classList.toggle('visible')
|
||||
}
|
||||
separatorOptionDom.onmousedown = function (evt) {
|
||||
let payload: number[] = []
|
||||
const li = evt.target as HTMLLIElement
|
||||
const separatorDash = li.dataset.separator?.split(',').map(Number)
|
||||
if (separatorDash) {
|
||||
const isSingleLine = separatorDash.every(d => d === 0)
|
||||
if (!isSingleLine) {
|
||||
payload = separatorDash
|
||||
}
|
||||
}
|
||||
instance.command.executeSeparator(payload)
|
||||
}
|
||||
const collspanDom = document.querySelector<HTMLDivElement>('.menu-item__search__collapse')
|
||||
const searchInputDom = document.querySelector<HTMLInputElement>('.menu-item__search__collapse__search input')
|
||||
@@ -510,11 +523,22 @@ window.onload = function () {
|
||||
// 控件类型
|
||||
payload.type === ElementType.SUBSCRIPT ? subscriptDom.classList.add('active') : subscriptDom.classList.remove('active')
|
||||
payload.type === ElementType.SUPERSCRIPT ? superscriptDom.classList.add('active') : superscriptDom.classList.remove('active')
|
||||
payload.type === ElementType.SEPARATOR ? separatorDom.classList.add('active') : separatorDom.classList.remove('active')
|
||||
separatorOptionDom.querySelectorAll('li').forEach(li => li.classList.remove('active'))
|
||||
if (payload.type === ElementType.SEPARATOR) {
|
||||
const separator = payload.dashArray.join(',') || '0,0'
|
||||
const curSeparatorDom = separatorOptionDom.querySelector<HTMLLIElement>(`[data-separator='${separator}']`)!
|
||||
if (curSeparatorDom) {
|
||||
curSeparatorDom.classList.add('active')
|
||||
}
|
||||
}
|
||||
// 富文本
|
||||
const curFontDom = fontOptionDom.querySelector<HTMLLIElement>(`[data-family=${payload.font}]`)!
|
||||
fontSelectDom.innerText = curFontDom.innerText
|
||||
fontOptionDom.querySelectorAll<HTMLLIElement>('li').forEach(li => li.classList.remove('active'))
|
||||
curFontDom.classList.add('active')
|
||||
const curFontDom = fontOptionDom.querySelector<HTMLLIElement>(`[data-family=${payload.font}]`)
|
||||
if (curFontDom) {
|
||||
fontSelectDom.innerText = curFontDom.innerText
|
||||
curFontDom.classList.add('active')
|
||||
}
|
||||
payload.bold ? boldDom.classList.add('active') : boldDom.classList.remove('active')
|
||||
payload.italic ? italicDom.classList.add('active') : italicDom.classList.remove('active')
|
||||
payload.underline ? underlineDom.classList.add('active') : underlineDom.classList.remove('active')
|
||||
|
||||
+41
-1
@@ -369,10 +369,50 @@ ul {
|
||||
background-image: url('./assets/images/hyperlink.svg');
|
||||
}
|
||||
|
||||
.menu-item__separator i {
|
||||
.menu-item__separator {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.menu-item__separator>i {
|
||||
background-image: url('./assets/images/separator.svg');
|
||||
}
|
||||
|
||||
.menu-item .menu-item__separator .options {
|
||||
width: 128px;
|
||||
}
|
||||
|
||||
.menu-item .menu-item__separator li {
|
||||
padding: 1px 5px;
|
||||
}
|
||||
|
||||
.menu-item__separator li i {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.menu-item__separator li[data-separator="0,0"] {
|
||||
background-image: url('./assets/images/line-single.svg');
|
||||
}
|
||||
|
||||
.menu-item__separator li[data-separator="1,1"] {
|
||||
background-image: url('./assets/images/line-dot.svg');
|
||||
}
|
||||
|
||||
.menu-item__separator li[data-separator="3,1"] {
|
||||
background-image: url('./assets/images/line-dash-small-gap.svg');
|
||||
}
|
||||
|
||||
.menu-item__separator li[data-separator="4,4"] {
|
||||
background-image: url('./assets/images/line-dash-large-gap.svg');
|
||||
}
|
||||
|
||||
.menu-item__separator li[data-separator="7,3,3,3"] {
|
||||
background-image: url('./assets/images/line-dash-dot.svg');
|
||||
}
|
||||
|
||||
.menu-item__separator li[data-separator="6,2,2,2,2,2"] {
|
||||
background-image: url('./assets/images/line-dash-dot-dot.svg');
|
||||
}
|
||||
|
||||
.menu-item__search {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user