富文本编辑基本可以使用了

This commit is contained in:
枫谷剑仙 2022-12-14 00:50:51 +08:00
parent 6b5e044ce7
commit 3a1c60495e
12 changed files with 246 additions and 52 deletions

View File

@ -3,6 +3,7 @@
addition_display: "追加の表示",
title_blank: "入力タイトル",
detail_blank: "入力詳細",
request_input: tp`${'info'}を入力してください`,
sort_name:{
sort_none: "いいえ",
sort_id: "カード ID",

View File

@ -3,6 +3,7 @@
addition_display: "추가 표시입니다",
title_blank: "입력 제목",
detail_blank: "입력 내용",
request_input: tp`${'info'}를 입력하십시오`,
sort_name:{
sort_none: "없음",
sort_id: "카드 ID",

View File

@ -2,6 +2,7 @@
webpage_title: `龍族拼圖${teamsCount}人隊伍圖製作`,
title_blank: "輸入隊伍標題",
detail_blank: "輸入説明",
request_input: tp`請輸入${'info'}`,
sort_name:{
sort_none: "無",
sort_id: "怪物ID",

View File

@ -2,6 +2,7 @@
webpage_title: `智龙迷城${teamsCount}人队伍图制作`,
title_blank: "输入队伍标题",
detail_blank: "输入说明",
request_input: tp`请输入${'info'}`,
sort_name:{
sort_none: "无",
sort_id: "怪物ID",

View File

@ -73,12 +73,12 @@ var formation = new Formation(teamsCount,5);
<option>110</option>
<option>120</option>
</datalist>
<input type="checkbox" name="change-swap-to-copy" id="change-swap-to-copy"><label class="config-checkbox-lbl change-swap-to-copy-lbl" for="change-swap-to-copy"></label>
</div>
<div>
<input type="checkbox" class="config-checkbox-ipt" name="show-mon-id" id="show-mon-id"><label class="config-checkbox-lbl show-mon-id-lbl" for="show-mon-id"><div class="config-checkbox-lbl-cicle"></div></label>
<input type="checkbox" class="config-checkbox-ipt" name="show-mon-skill-cd" id="show-mon-skill-cd"><label class="config-checkbox-lbl show-mon-skill-cd-lbl" for="show-mon-skill-cd"><div class="config-checkbox-lbl-cicle"></div></label>
<input type="checkbox" class="config-checkbox-ipt" name="show-mon-awoken" id="show-mon-awoken"><label class="config-checkbox-lbl show-mon-awoken-lbl" for="show-mon-awoken"><div class="config-checkbox-lbl-cicle"></div></label>
<input type="checkbox" name="change-swap-to-copy" id="change-swap-to-copy"><label class="config-checkbox-lbl change-swap-to-copy-lbl" for="change-swap-to-copy"></label>
</div>
<div class="status"><span class="icon"></span><span class="text"></span></div>
<div>
@ -88,7 +88,7 @@ var formation = new Formation(teamsCount,5);
</div>
</div>
<div class="formation-box">
<div class="title-box edit"><input type="text" class="title" placeholder="输入队伍标题" /><h1 class="title-display"></h1></div>
<div class="title-box"><input type="text" class="title-code" placeholder="输入队伍标题" /><h1 class="title-display rich-text" contenteditable="true"></h1></div>
<div class="dungeon-enchance"></div>
<div class="formation-total-info">
<div class="tIf-total-skill-boost">
@ -756,13 +756,23 @@ var formation = new Formation(teamsCount,5);
<li class="awoken-count display-none"><span class="awoken-icon" data-awoken-icon="55"></span><span class="count"></span></li><!--防封条-->
</ul>
</div>
<div class="detail-box edit"><textarea class="detail" placeholder="输入说明"></textarea><div class="detail-display"></div></div>
<div class="detail-box"><textarea class="detail-code" placeholder="输入说明"></textarea><div class="detail-display rich-text" contenteditable="true"></div></div>
<div class="dialog dialog-hp-detail display-none">
<div class="dialog-title"></div>
<div class="dialog-content"></div>
<div class="dialog-control"><button class="dialog-close brown-button"></button></div>
</div>
</div>
<div id="rich-text-tools">
<button id="set-font-color"></button><input id="color-chooser" type="color" />
<button id="insert-card-avatar"></button>
<button id="insert-awoken-icon"></button>
<button id="insert-latent-icon"></button>
<button id="insert-type-icon"></button>
<button id="insert-orb-icon"></button>
<input type="checkbox" class="config-checkbox-ipt" id="siwtch-code-mode"><label class="config-checkbox-lbl" for="siwtch-code-mode"><div class="config-checkbox-lbl-cicle"></div></label>
</div>
<div class="edit-box display-none">
<div class="edit-box-title"><!--修改怪物--></div>
<div class="search-box display-none">

View File

@ -17,6 +17,7 @@ let localTranslating = {
addition_display: "💬",
title_blank: "Input Formation Title",
detail_blank: "Input Detail",
request_input: tp`Please Input ${'info'}`,
sort_name:{
sort_none: "Nope",
sort_id: "Cards Id",

View File

@ -862,7 +862,7 @@ function searchCollab(event) {
function createIndexedIcon(type, index) {
if (type == 'card') {//卡片头像
const avatar = cardN(index);
avatar.monDom.contentEditable = false;
avatar.contentEditable = false;
avatar.monDom.setAttribute("onclick", "cardNClick.call(this);return false;")
return avatar;
}

198
script.js
View File

@ -1629,6 +1629,11 @@ function initialize() {
editBox = document.body.querySelector(".edit-box");
editBox.editMon = editMember;
formationBox.refreshDocumentTitle = function() {
let titleStr = txtTitleDisplay.textContent.trim();
document.title = titleStr.length > 0 ? `${titleStr.trim()} - ${localTranslating.webpage_title}` : localTranslating.webpage_title;
}
if (isGuideMod) {
console.info('现在是 怪物图鉴 模式');
document.body.classList.add('guide-mod');
@ -2168,15 +2173,56 @@ function initialize() {
const txtTitleDisplay = titleBox.querySelector(".title-display");
const txtDetailDisplay = detailBox.querySelector(".detail-display");
//const richTextTools = document.getElementById("rich-text-tools");
const richTextTools = document.getElementById("rich-text-tools");
const siwtchCodeMode = document.getElementById("siwtch-code-mode");
const setFontColor = document.getElementById("set-font-color");
const colorChooser = document.getElementById("color-chooser");
const insertCardAvatar = document.getElementById("insert-card-avatar");
const insertTypeIcon = document.getElementById("insert-type-icon");
const insertAwokenIcon = document.getElementById("insert-awoken-icon");
const insertLatentIcon = document.getElementById("insert-latent-icon");
const insertTypeIcon = document.getElementById("insert-type-icon");
const insertOrbIcon = document.getElementById("insert-orb-icon");
const insertAwokenIconList = insertAwokenIcon.list = document.createElement("ul");
insertAwokenIconList.className = "awoken-ul " + className_displayNone;
const insertLatentIconList = insertLatentIcon.list = document.createElement("ul");
insertLatentIconList.className = "m-latent-allowable-ul " + className_displayNone;
const insertTypeIconList = insertTypeIcon.list = document.createElement("ul");
insertTypeIconList.className = "types-ul " + className_displayNone;
const insertOrbList = insertOrbIcon.list = document.createElement("ul");
insertOrbList.className = "orb-ul " + className_displayNone;
for (let id of official_awoken_sorting) {
const li = document.createElement("li");
const icon = li.appendChild(createIndexedIcon('awoken', id));
icon.onclick = insertIconToText;
insertAwokenIconList.appendChild(li);
}
for (let id of new Set(pdcLatentMap.map(obj=>obj.pdf))) {
const li = document.createElement("li");
const icon = li.appendChild(createIndexedIcon('latent', id));
icon.onclick = insertIconToText;
insertLatentIconList.appendChild(li);
}
for (let obj of typekiller_for_type) {
const li = document.createElement("li");
const icon = li.appendChild(createIndexedIcon('type', obj.type));
icon.onclick = insertIconToText;
insertTypeIconList.appendChild(li);
}
for (let i=0;i<10;i++) {
const li = document.createElement("li");
const icon = li.appendChild(createIndexedIcon('orb', i));
icon.onclick = insertIconToText;
insertOrbList.appendChild(li);
}
richTextTools.append(
insertTypeIconList,
insertAwokenIconList,
insertLatentIconList,
insertOrbList
);
//切换代码模式
siwtchCodeMode.onclick = function(){
if (this.checked) txtDetail.style.height = txtDetailDisplay.scrollHeight + "px";
@ -2185,11 +2231,15 @@ function initialize() {
siwtchCodeMode.checked = false;
//设置文字颜色
function setSelectionFontColor(color) {
//如果并没有任何选择区,则返回
if (docSelection.rangeCount < 1) return;
const range = docSelection.getRangeAt(0);
//如果并没有选中文字,则返回
if (range.startOffset === range.endOffset) return;
let target;
if (target = (txtTitleDisplay.contains(range.commonAncestorContainer) && txtTitleDisplay)
|| (txtDetailDisplay.contains(range.commonAncestorContainer) && txtDetailDisplay)) {
|| (txtDetailDisplay.contains(range.commonAncestorContainer) && txtDetailDisplay))
{
const docObj = range.extractContents(); //移动了Range 中的内容从文档树到DocumentFragment文档片段对象)。
let dom
if (color === "#000000") {
@ -2203,11 +2253,13 @@ function initialize() {
target.onblur();
} else if (color !== "#000000" &&
(target = (txtTitle.contains(range.commonAncestorContainer) && txtTitle)
|| (txtDetail.contains(range.commonAncestorContainer) && txtDetail))) {
let str = target.value.substring(target.selectionStart, target.selectionEnd)
.replace(/\^(\w+?)\^([^\^]+?)\^p/igm, "$2");
let colorStr = `^${color.substring(1)}^${str}^p`;
target.setRangeText(colorStr);
|| (txtDetail.contains(range.commonAncestorContainer) && txtDetail)))
{
let str = target.value.substring(target.selectionStart, target.selectionEnd)
.replace(/\^(\w+?)\^([^\^]+?)\^p/igm, "$2");
let colorStr = `^${color.substring(1)}^${str}^p`;
target.setRangeText(colorStr);
target.onchange();
}
}
setFontColor.onclick = function(){
@ -2215,60 +2267,153 @@ function initialize() {
}
colorChooser.onchange = function(){
setFontColor.style.color = this.value;
setSelectionFontColor(this.value);
}
setFontColor.style.color = colorChooser.value;
//添加图标
//添加头像图标
insertCardAvatar.onclick = function(){
let id = prompt("请输入角色 ID");
id = parseInt(id,10);
if (id) {
const range = docSelection.getRangeAt(0);
if (docSelection.rangeCount < 1) return;
const range = docSelection.getRangeAt(0);
//优先获取选中部分的数字
let id = parseInt(range.toString().trim(), 10);
if (!Number.isInteger(id)) {
id = prompt(localTranslating.request_input({info: localTranslating.sort_name.sort_id}).textContent);
id = parseInt(id,10);
}
if (Number.isInteger(id)) {
let target;
if (target = (txtTitleDisplay.contains(range.commonAncestorContainer) && txtTitleDisplay)
|| (txtDetailDisplay.contains(range.commonAncestorContainer) && txtDetailDisplay)) {
|| (txtDetailDisplay.contains(range.commonAncestorContainer) && txtDetailDisplay))
{
let dom = createIndexedIcon('card', id);
range.deleteContents();
range.insertNode(dom);
target.onblur();
} else if (target = (txtTitle.contains(range.commonAncestorContainer) && txtTitle)
|| (txtDetail.contains(range.commonAncestorContainer) && txtDetail)) {
|| (txtDetail.contains(range.commonAncestorContainer) && txtDetail))
{
let str = `%{m${id}}`;
target.setRangeText(str);
target.onchange();
}
}
}
//添加其他序号图标
function insertIconToText() {
if (docSelection.rangeCount < 1) return;
let type, stype, id;
if(this.classList.contains("awoken-icon")) { //觉醒
type = 'awoken';
stype = 'a';
id = this.getAttribute("data-awoken-icon");
}
else if(this.classList.contains("type-icon")) { //类型
type = 'type';
stype = 't';
id = this.getAttribute("data-type-icon");
}
else if(this.classList.contains("orb")) { //宝珠
type = 'orb';
stype = 'o';
id = this.getAttribute("data-orb-icon");
}
else if(this.classList.contains("latent-icon")) { //潜觉
type = 'latent';
stype = 'l';
id = this.getAttribute("data-latent-icon");
}
const range = docSelection.getRangeAt(0);
let target;
console.log(range);
if (target = (txtTitleDisplay.contains(range.commonAncestorContainer) && txtTitleDisplay)
|| (txtDetailDisplay.contains(range.commonAncestorContainer) && txtDetailDisplay))
{
let dom = createIndexedIcon(type, id);
range.insertNode(dom);
console.log(target);
target.onblur();
} else if (target = (txtTitle.contains(range.commonAncestorContainer) && txtTitle)
|| (txtDetail.contains(range.commonAncestorContainer) && txtDetail))
{
let str = `%{${stype}${id}}`;
target.setRangeText(str);
target.onchange();
}
}
function showInsertIconList() {
//如果自身的列表已经打开了,则隐藏
if (!this.list.classList.contains(className_displayNone)) {
this.list.classList.add(className_displayNone);
return;
}
//否则隐藏其他的列表
[
insertAwokenIcon.list,
insertLatentIcon.list,
insertTypeIcon.list,
insertOrbIcon.list,
].forEach(ul=>ul.classList.toggle(className_displayNone, ul != this.list));
}
insertAwokenIcon.onclick = showInsertIconList;
insertLatentIcon.onclick = showInsertIconList;
insertTypeIcon.onclick = showInsertIconList;
insertOrbIcon.onclick = showInsertIconList;
function richTextToCode(parentElement){
let code = [];
for (let node of parentElement.childNodes) {
if (node.nodeName == "#text"){
code.push(node.nodeValue);
continue;
}
else if(node.classList.contains("detail-mon")) { //卡片头像
let type, id;
if(node.classList.contains("detail-mon")) { //卡片头像
const mon = node.querySelector(".monster");
code.push(`%{m${mon.getAttribute("data-cardid")}}`);
if (!mon) continue;
type = 'm';
id = mon.getAttribute("data-cardid");
}
else if(node.classList.contains("awoken-icon")) { //觉醒
code.push(`%{a${node.getAttribute("data-awoken-icon")}}`);
type = 'a';
id = node.getAttribute("data-awoken-icon");
}
else if(node.classList.contains("type-icon")) { //类型
code.push(`%{a${node.getAttribute("data-type-icon")}}`);
type = 't';
id = node.getAttribute("data-type-icon");
}
else if(node.classList.contains("orb")) { //宝珠
code.push(`%{a${node.getAttribute("data-orb-icon")}}`);
type = 'o';
id = node.getAttribute("data-orb-icon");
}
else if(node.classList.contains("latent")) { //潜觉
code.push(`%{a${node.getAttribute("data-latent-icon")}}`);
else if(node.classList.contains("latent-icon")) { //潜觉
type = 'l';
id = node.getAttribute("data-latent-icon");
}
code.push(`%{${type}${id}}`);
}
return code.join('');
}
txtTitleDisplay.onblur = function(){
txtTitle.value = richTextToCode(this);
formation.title = txtTitle.value = richTextToCode(this);
formationBox.refreshDocumentTitle();
creatNewUrl();
}
txtDetailDisplay.onblur = function(){
txtDetail.value = richTextToCode(this);
formation.detail = txtDetail.value = richTextToCode(this);
creatNewUrl();
}
txtTitle.onchange = function() {
formation.title = this.value;
txtTitleDisplay.innerHTML = '';
txtTitleDisplay.append(descriptionToHTML(this.value));
formationBox.refreshDocumentTitle();
creatNewUrl();
};
txtDetail.onchange = function() {
formation.detail = this.value;
txtDetailDisplay.innerHTML = '';
txtDetailDisplay.append(descriptionToHTML(this.value));
creatNewUrl();
};
// txtTitle.onchange = function() {
// formation.title = this.value;
@ -4748,8 +4893,7 @@ function refreshAll(formationData) {
const txtDetailDisplay = detailBox.querySelector(".detail-display");
txtTitleDisplay.innerHTML = '';
txtTitleDisplay.append(descriptionToHTML(txtTitle.value));
let titleStr = txtTitleDisplay.textContent.trim();
document.title = titleStr.length > 0 ? `${titleStr.trim()} - ${localTranslating.webpage_title}` : localTranslating.webpage_title;
formationBox.refreshDocumentTitle();
txtDetailDisplay.innerHTML = '';
txtDetailDisplay.append(descriptionToHTML(txtDetail.value));

View File

@ -599,21 +599,22 @@ var formation = new Formation(teamsCount,6);
</li>
</ul>
<div class="detail-box"><textarea class="detail-code" placeholder="输入说明"></textarea><div class="detail-display rich-text" contenteditable="true"></div></div>
<div id="rich-text-tools">
<button id="set-font-color"></button><input id="color-chooser" type="color" />
<button id="insert-card-avatar"></button>
<button id="insert-type-icon"></button>
<button id="insert-awoken-icon"></button>
<button id="insert-latent-icon"></button>
<button id="insert-orb-icon"></button>
<input type="checkbox" class="config-checkbox-ipt" id="siwtch-code-mode"><label class="config-checkbox-lbl" for="siwtch-code-mode"><div class="config-checkbox-lbl-cicle"></div></label>
</div>
<div class="dialog dialog-hp-detail display-none">
<div class="dialog-title"></div>
<div class="dialog-content"></div>
<div class="dialog-control"><button class="dialog-close brown-button"></button></div>
</div>
</div>
<div id="rich-text-tools">
<button id="set-font-color"></button><input id="color-chooser" type="color" />
<button id="insert-card-avatar"></button>
<button id="insert-awoken-icon"></button>
<button id="insert-latent-icon"></button>
<button id="insert-type-icon"></button>
<button id="insert-orb-icon"></button>
<input type="checkbox" class="config-checkbox-ipt" id="siwtch-code-mode"><label class="config-checkbox-lbl" for="siwtch-code-mode"><div class="config-checkbox-lbl-cicle"></div></label>
</div>
<div class="edit-box display-none">
<div class="edit-box-title"><!--修改怪物--></div>
<div class="search-box display-none">

View File

@ -1261,7 +1261,7 @@
){ /*占两格*/
grid-column: span 2;
}
.m-latent-allowable-ul .latent-icon:where(
.edit-box .m-latent-allowable-ul .latent-icon:where(
[data-latent-icon='39'],
[data-latent-icon='40'],
[data-latent-icon='41'],

View File

@ -86,8 +86,8 @@ details>summary {
bottom: 0;
margin-top: 10px;
backdrop-filter: blur(3px);
padding: 3px;
border-radius: 3px;
padding: 5px;
user-select: none; /*让内容不可选中*/
}
#rich-text-tools button
{
@ -97,8 +97,8 @@ details>summary {
}
#rich-text-tools button::before {
font-family: var(--icon-font-family);
vertical-align: middle;
}
/*添加卡片头像*/
:where(
#insert-card-avatar,
#insert-type-icon,
@ -173,7 +173,24 @@ label[for="siwtch-code-mode"]::after {
transform: scale(calc(25 / 36));
margin: calc(-36px * (1 - (25 / 36)) / 2);
}
#rich-text-tools>ul icon {
cursor: pointer;
}
#rich-text-tools>ul {
margin-top: 10px;
display: grid;
grid-template-columns: repeat(auto-fill, 32px);
grid-auto-rows: 32px;
grid-gap: 4px;
}
#rich-text-tools>.orb-ul{
grid-template-columns: repeat(auto-fill, 36px);
grid-auto-rows: 36px;
}
.rich-text icon{
vertical-align: middle;
}
.title-code,
.title-display
{
@ -1423,22 +1440,22 @@ icon.inflicts::after
top: 20px;
}
.detail-box .detail-mon{
.rich-text .detail-mon{
width: 50px;
height: 50px;
}
.detail-box .detail-mon .monster{
.rich-text .detail-mon .monster{
transform: scale(0.5);
margin: calc(-100px * (1 - 0.5) / 2);
}
.detail-box .detail-mon .monster .id{
.rich-text .detail-mon .monster .id{
font-weight: bold;
font-size: 23px;
}
.detail-box .detail-mon .monster .id::before {
.rich-text .detail-mon .monster .id::before {
font-size: 15px;
}
.detail-box .latent-icon {
.rich-text .latent-icon {
width: 32px;
height: 32px;
display: inline-block;
@ -2890,6 +2907,13 @@ icon.inflicts::after
{
transform: rotate(90deg);
}
.orb-ul
{
display: grid;
grid-template-columns: repeat(auto-fill, 36px);
grid-auto-rows: 36px;
grid-gap: 5px;
}
.orb-icon
{
width: 20px;

View File

@ -67,13 +67,13 @@ var formation = new Formation(teamsCount,6);
<option>110</option>
<option>120</option>
</datalist>
<input type="checkbox" name="change-swap-to-copy" id="change-swap-to-copy"><label class="config-checkbox-lbl change-swap-to-copy-lbl" for="change-swap-to-copy"></label>
</div>
<div>
<input type="checkbox" class="config-checkbox-ipt" name="show-mon-id" id="show-mon-id"><label class="config-checkbox-lbl show-mon-id-lbl" for="show-mon-id"><div class="config-checkbox-lbl-cicle"></div></label>
<input type="checkbox" class="config-checkbox-ipt" name="show-mon-skill-cd" id="show-mon-skill-cd"><label class="config-checkbox-lbl show-mon-skill-cd-lbl" for="show-mon-skill-cd"><div class="config-checkbox-lbl-cicle"></div></label>
<input type="checkbox" class="config-checkbox-ipt" name="show-awoken-count" id="show-awoken-count" checked><label class="config-checkbox-lbl show-awoken-count-lbl" for="show-awoken-count"><div class="config-checkbox-lbl-cicle"></div></label>
<input type="checkbox" class="config-checkbox-ipt" name="show-mon-awoken" id="show-mon-awoken"><label class="config-checkbox-lbl show-mon-awoken-lbl" for="show-mon-awoken"><div class="config-checkbox-lbl-cicle"></div></label>
<input type="checkbox" name="change-swap-to-copy" id="change-swap-to-copy"><label class="config-checkbox-lbl change-swap-to-copy-lbl" for="change-swap-to-copy"></label>
</div>
<div class="status"><span class="icon"></span><span class="text"></span></div>
<div>
@ -83,7 +83,7 @@ var formation = new Formation(teamsCount,6);
</div>
</div>
<div class="formation-box">
<div class="title-box edit"><input type="text" class="title" placeholder="输入队伍标题" /><h1 class="title-display"></h1></div>
<div class="title-box"><input type="text" class="title-code" placeholder="输入队伍标题" /><h1 class="title-display rich-text" contenteditable="true"></h1></div>
<div class="dungeon-enchance"></div>
<ul class="teams">
<li class="team-bigbox team-1 show-team-name-right">
@ -1650,13 +1650,23 @@ var formation = new Formation(teamsCount,6);
</div>
</li>
</ul>
<div class="detail-box edit"><textarea class="detail" placeholder="输入说明"></textarea><div class="detail-display"></div></div>
<div class="detail-box"><textarea class="detail-code" placeholder="输入说明"></textarea><div class="detail-display rich-text" contenteditable="true"></div></div>
<div class="dialog dialog-hp-detail display-none">
<div class="dialog-title"></div>
<div class="dialog-content"></div>
<div class="dialog-control"><button class="dialog-close brown-button"></button></div>
</div>
</div>
<div id="rich-text-tools">
<button id="set-font-color"></button><input id="color-chooser" type="color" />
<button id="insert-card-avatar"></button>
<button id="insert-awoken-icon"></button>
<button id="insert-latent-icon"></button>
<button id="insert-type-icon"></button>
<button id="insert-orb-icon"></button>
<input type="checkbox" class="config-checkbox-ipt" id="siwtch-code-mode"><label class="config-checkbox-lbl" for="siwtch-code-mode"><div class="config-checkbox-lbl-cicle"></div></label>
</div>
<div class="edit-box display-none">
<div class="edit-box-title"><!--修改怪物--></div>
<div class="search-box display-none">