滑动选中
This commit is contained in:
@@ -1208,10 +1208,16 @@ export default {
|
||||
hasChange: false,
|
||||
hasInit: false,
|
||||
selectedIds: [],
|
||||
isMouseSelecting: false,
|
||||
_selectionSyncToCheckboxesTimer: null,
|
||||
_onDocumentSelectionChange: null,
|
||||
_onDocumentMouseUp: null,
|
||||
_onManuscriptMouseDown: null,
|
||||
|
||||
displayList: [],
|
||||
currentTypeText: '',
|
||||
tinymceId: this.id || 'vue-tinymce-' + +new Date()
|
||||
|
||||
};
|
||||
},
|
||||
// this.$nextTick(() => window.tinymce.get(this.tinymceId).setContent(newVal));
|
||||
@@ -1274,51 +1280,60 @@ export default {
|
||||
});
|
||||
this.$refs.scrollDiv.addEventListener('scroll', this.divOnScroll, { passive: true });
|
||||
|
||||
document.addEventListener('selectionchange', () => {
|
||||
if(this.isPreview)return;
|
||||
const selection = window.getSelection();
|
||||
if (selection.rangeCount === 0) return;
|
||||
// document.addEventListener('selectionchange', () => {
|
||||
// if(this.isPreview)return;
|
||||
// const selection = window.getSelection();
|
||||
// if (selection.rangeCount === 0) return;
|
||||
|
||||
const range = selection.getRangeAt(0);
|
||||
// 依然保留 trim() 后的文本判断,用来决定是否显示气泡
|
||||
const plainText = selection.toString().trim();
|
||||
// const range = selection.getRangeAt(0);
|
||||
// // 依然保留 trim() 后的文本判断,用来决定是否显示气泡
|
||||
// const plainText = selection.toString().trim();
|
||||
|
||||
if (plainText !== '' && selection.rangeCount > 0) {
|
||||
// --- 1. 获取包含标签的 HTML 内容 ---
|
||||
const fragment = range.cloneContents();
|
||||
const tempDiv = document.createElement('div');
|
||||
tempDiv.appendChild(fragment);
|
||||
// 关键点:这个 label 变量现在包含了完整的 HTML 结构(如 <myfigure>)
|
||||
const htmlLabel = tempDiv.innerHTML;
|
||||
const allPMainElements = this.getInvolvedPMain(range);
|
||||
const allIds = [...new Set(allPMainElements.map((el) => el.getAttribute('data-id')))];
|
||||
if (allIds.length > 0) {
|
||||
this.updateBubblePosition(range);
|
||||
const rootItem = this.wordList.find((item) => item.am_id == allIds[0]);
|
||||
// if (plainText !== '' && selection.rangeCount > 0) {
|
||||
// // --- 1. 获取包含标签的 HTML 内容 ---
|
||||
// const fragment = range.cloneContents();
|
||||
// const tempDiv = document.createElement('div');
|
||||
// tempDiv.appendChild(fragment);
|
||||
// // 关键点:这个 label 变量现在包含了完整的 HTML 结构(如 <myfigure>)
|
||||
// const htmlLabel = tempDiv.innerHTML;
|
||||
// const allPMainElements = this.getInvolvedPMain(range);
|
||||
// const allIds = [...new Set(allPMainElements.map((el) => el.getAttribute('data-id')))];
|
||||
// if (allIds.length > 0) {
|
||||
// this.updateBubblePosition(range);
|
||||
// const rootItem = this.wordList.find((item) => item.am_id == allIds[0]);
|
||||
|
||||
this.currentSelection = {
|
||||
// 将 label 设置为包含标签的 HTML 字符串
|
||||
label: htmlLabel,
|
||||
mainId: allIds[0],
|
||||
index: this.wordList.indexOf(rootItem),
|
||||
// this.currentSelection = {
|
||||
// // 将 label 设置为包含标签的 HTML 字符串
|
||||
// label: htmlLabel,
|
||||
// mainId: allIds[0],
|
||||
// index: this.wordList.indexOf(rootItem),
|
||||
|
||||
content: rootItem ? rootItem.content : ''
|
||||
};
|
||||
// content: rootItem ? rootItem.content : ''
|
||||
// };
|
||||
|
||||
this.currentId = allIds[0];
|
||||
this.currentData = rootItem;
|
||||
// this.currentId = allIds[0];
|
||||
// this.currentData = rootItem;
|
||||
// }
|
||||
// } else {
|
||||
// this.currentTag = '';
|
||||
// this.currentTagData = {};
|
||||
// this.currentSelection = {
|
||||
// label: '',
|
||||
// mainId: '',
|
||||
// index: 0,
|
||||
// content: {}
|
||||
// };
|
||||
// }
|
||||
// });
|
||||
this._onDocumentSelectionChange = this.handleDocumentSelectionChange.bind(this);
|
||||
this._onDocumentMouseUp = this.handleDocumentMouseUp.bind(this);
|
||||
this._onManuscriptMouseDown = this.handleManuscriptMouseDown.bind(this);
|
||||
document.addEventListener('selectionchange', this._onDocumentSelectionChange);
|
||||
document.addEventListener('mouseup', this._onDocumentMouseUp);
|
||||
if (this.$refs.scroll) {
|
||||
this.$refs.scroll.addEventListener('mousedown', this._onManuscriptMouseDown);
|
||||
}
|
||||
} else {
|
||||
this.currentTag = '';
|
||||
this.currentTagData = {};
|
||||
this.currentSelection = {
|
||||
label: '',
|
||||
mainId: '',
|
||||
index: 0,
|
||||
content: {}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
activated() {
|
||||
// 主动触发 MathJax 渲染
|
||||
@@ -1378,6 +1393,115 @@ export default {
|
||||
|
||||
return rangePs;
|
||||
},
|
||||
handleManuscriptMouseDown(event) {
|
||||
if (this.isPreview) return;
|
||||
const root = this.$refs && this.$refs.scroll;
|
||||
if (!root) return;
|
||||
if (root.contains(event.target)) {
|
||||
this.isMouseSelecting = true;
|
||||
}
|
||||
},
|
||||
handleDocumentMouseUp() {
|
||||
this.isMouseSelecting = false;
|
||||
},
|
||||
handleDocumentSelectionChange() {
|
||||
if (this.isPreview) return;
|
||||
const selection = window.getSelection();
|
||||
if (!selection || selection.rangeCount === 0) return;
|
||||
|
||||
const range = selection.getRangeAt(0);
|
||||
const plainText = selection.toString().trim();
|
||||
|
||||
if (plainText !== '' && selection.rangeCount > 0) {
|
||||
const fragment = range.cloneContents();
|
||||
const tempDiv = document.createElement('div');
|
||||
tempDiv.appendChild(fragment);
|
||||
const htmlLabel = tempDiv.innerHTML;
|
||||
const allPMainElements = this.getInvolvedPMain(range);
|
||||
const allIds = [...new Set(allPMainElements.map((el) => el.getAttribute('data-id')))];
|
||||
if (allIds.length > 0) {
|
||||
this.updateBubblePosition(range);
|
||||
const rootItem = this.wordList.find((item) => item.am_id == allIds[0]);
|
||||
|
||||
this.currentSelection = {
|
||||
label: htmlLabel,
|
||||
mainId: allIds[0],
|
||||
index: this.wordList.indexOf(rootItem),
|
||||
content: rootItem ? rootItem.content : ''
|
||||
};
|
||||
|
||||
this.currentId = allIds[0];
|
||||
this.currentData = rootItem;
|
||||
}
|
||||
} else {
|
||||
this.currentTag = '';
|
||||
this.currentTagData = {};
|
||||
this.currentSelection = {
|
||||
label: '',
|
||||
mainId: '',
|
||||
index: 0,
|
||||
content: {}
|
||||
};
|
||||
}
|
||||
this.scheduleSyncSelectedIdsFromRange();
|
||||
},
|
||||
scheduleSyncSelectedIdsFromRange() {
|
||||
if (this._selectionSyncToCheckboxesTimer) {
|
||||
clearTimeout(this._selectionSyncToCheckboxesTimer);
|
||||
}
|
||||
this._selectionSyncToCheckboxesTimer = setTimeout(() => {
|
||||
this.syncSelectedIdsFromRangeInternal();
|
||||
}, 80);
|
||||
},
|
||||
syncSelectedIdsFromRangeInternal() {
|
||||
if (this.isPreview || this.isInternalAction) return;
|
||||
const scrollRoot = this.$refs && this.$refs.scroll;
|
||||
if (!scrollRoot) return;
|
||||
|
||||
const selection = window.getSelection();
|
||||
if (!selection || selection.rangeCount === 0 || selection.isCollapsed) return;
|
||||
const range = selection.getRangeAt(0);
|
||||
const common = range.commonAncestorContainer;
|
||||
const commonElement = common && common.nodeType === 1 ? common : common && common.parentElement;
|
||||
if (!commonElement || !scrollRoot.contains(commonElement)) return;
|
||||
|
||||
const nodes = Array.from(scrollRoot.querySelectorAll('.drop-target[main-id]'));
|
||||
const touchedMainIds = [];
|
||||
nodes.forEach((node) => {
|
||||
const id = node.getAttribute('main-id');
|
||||
if (!id || id === 'References') return;
|
||||
try {
|
||||
if (range.intersectsNode(node)) {
|
||||
touchedMainIds.push(id);
|
||||
}
|
||||
} catch (e) {}
|
||||
});
|
||||
if (!touchedMainIds.length) return;
|
||||
|
||||
const indexMap = {};
|
||||
this.wordList.forEach((item, idx) => {
|
||||
if (item && item.am_id != null) {
|
||||
indexMap[String(item.am_id)] = idx;
|
||||
}
|
||||
});
|
||||
const indices = [...new Set(touchedMainIds.map((id) => indexMap[String(id)]).filter((v) => Number.isInteger(v)))];
|
||||
if (!indices.length) return;
|
||||
const lo = Math.min(...indices);
|
||||
const hi = Math.max(...indices);
|
||||
const rangeIds = this.wordList
|
||||
.slice(lo, hi + 1)
|
||||
.map((item) => (item && item.am_id != null ? item.am_id : null))
|
||||
.filter((id) => id != null);
|
||||
if (!rangeIds.length) return;
|
||||
|
||||
const existingSet = new Set(this.selectedIds || []);
|
||||
rangeIds.forEach((id) => existingSet.add(id));
|
||||
const ordered = this.wordList
|
||||
.map((item) => (item && item.am_id != null ? item.am_id : null))
|
||||
.filter((id) => id != null && existingSet.has(id));
|
||||
this.selectedIds = ordered;
|
||||
this.$forceUpdate();
|
||||
},
|
||||
|
||||
handleUnbindLink(type) {
|
||||
const rootItem = this.wordList.find((item) => item.am_id == this.currentTagData.main_id);
|
||||
|
||||
Reference in New Issue
Block a user