Commit ·
afcf829
1
Parent(s): 7475e97
remove: List buttons + indent + all related CSS/JS - Remove bullet list and ordered list buttons from toolbar - Remove formatList() function from format.js - Remove blockquote/ul/ol/li CSS from components.css - Keep clear format button
Browse files- src/css/components.css +0 -21
- src/index.html +0 -10
- src/js/format.js +0 -87
src/css/components.css
CHANGED
|
@@ -519,28 +519,7 @@
|
|
| 519 |
outline: none;
|
| 520 |
}
|
| 521 |
|
| 522 |
-
/* Indent (blockquote) styling inside editor */
|
| 523 |
-
.editor-surface blockquote {
|
| 524 |
-
margin: 0;
|
| 525 |
-
padding-right: 2rem;
|
| 526 |
-
border-right: 3px solid var(--color-primary);
|
| 527 |
-
border-left: none;
|
| 528 |
-
white-space: normal;
|
| 529 |
-
}
|
| 530 |
|
| 531 |
-
/* List styling inside editor */
|
| 532 |
-
.editor-surface ul,
|
| 533 |
-
.editor-surface ol {
|
| 534 |
-
margin: 0.5em 0;
|
| 535 |
-
padding-right: 2rem;
|
| 536 |
-
padding-left: 0;
|
| 537 |
-
white-space: normal;
|
| 538 |
-
}
|
| 539 |
-
|
| 540 |
-
.editor-surface li {
|
| 541 |
-
margin-bottom: 0.25em;
|
| 542 |
-
white-space: normal;
|
| 543 |
-
}
|
| 544 |
|
| 545 |
.editor-surface[data-empty="true"]::before {
|
| 546 |
content: attr(data-placeholder);
|
|
|
|
| 519 |
outline: none;
|
| 520 |
}
|
| 521 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 522 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 523 |
|
| 524 |
.editor-surface[data-empty="true"]::before {
|
| 525 |
content: attr(data-placeholder);
|
src/index.html
CHANGED
|
@@ -586,16 +586,6 @@
|
|
| 586 |
</div>
|
| 587 |
</div>
|
| 588 |
<div class="fmt-divider"></div>
|
| 589 |
-
<!-- Item 9: Lists -->
|
| 590 |
-
<div class="fmt-group">
|
| 591 |
-
<button class="fmt-btn" onclick="formatList('insertUnorderedList')" type="button" title="قائمة نقطية">
|
| 592 |
-
<svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24"><path d="M4 6h2v2H4V6zm4 0h12v2H8V6zM4 11h2v2H4v-2zm4 0h12v2H8v-2zm-4 5h2v2H4v-2zm4 0h12v2H8v-2z"/></svg>
|
| 593 |
-
</button>
|
| 594 |
-
<button class="fmt-btn" onclick="formatList('insertOrderedList')" type="button" title="قائمة مرقمة">
|
| 595 |
-
<svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24"><path d="M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z"/></svg>
|
| 596 |
-
</button>
|
| 597 |
-
</div>
|
| 598 |
-
<div class="fmt-divider"></div>
|
| 599 |
<!-- Clear formatting -->
|
| 600 |
<div class="fmt-group">
|
| 601 |
<button class="fmt-btn" onclick="execFormat('removeFormat')" type="button" title="مسح التنسيق">
|
|
|
|
| 586 |
</div>
|
| 587 |
</div>
|
| 588 |
<div class="fmt-divider"></div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 589 |
<!-- Clear formatting -->
|
| 590 |
<div class="fmt-group">
|
| 591 |
<button class="fmt-btn" onclick="execFormat('removeFormat')" type="button" title="مسح التنسيق">
|
src/js/format.js
CHANGED
|
@@ -38,93 +38,6 @@ function formatAlignRight() { execFormat('justifyRight'); }
|
|
| 38 |
function formatAlignCenter() { execFormat('justifyCenter'); }
|
| 39 |
function formatAlignLeft() { execFormat('justifyLeft'); }
|
| 40 |
|
| 41 |
-
/* ── Lists (manual DOM creation — execCommand doesn't work with pre-wrap) ── */
|
| 42 |
-
function formatList(command) {
|
| 43 |
-
const editor = getEditorElement();
|
| 44 |
-
if (!editor) return;
|
| 45 |
-
|
| 46 |
-
const sel = window.getSelection();
|
| 47 |
-
if (!sel.rangeCount) { editor.focus(); return; }
|
| 48 |
-
|
| 49 |
-
const isOrdered = command === 'insertOrderedList';
|
| 50 |
-
|
| 51 |
-
// Check if we're already inside a list — if so, remove it (toggle off)
|
| 52 |
-
const existingList = sel.anchorNode && sel.anchorNode.closest
|
| 53 |
-
? sel.anchorNode.closest(isOrdered ? 'ol' : 'ul')
|
| 54 |
-
: (sel.anchorNode.parentElement ? sel.anchorNode.parentElement.closest(isOrdered ? 'ol' : 'ul') : null);
|
| 55 |
-
|
| 56 |
-
if (existingList && editor.contains(existingList)) {
|
| 57 |
-
// Unwrap: convert list items back to text lines
|
| 58 |
-
const items = existingList.querySelectorAll('li');
|
| 59 |
-
const fragment = document.createDocumentFragment();
|
| 60 |
-
items.forEach((li, i) => {
|
| 61 |
-
if (i > 0) fragment.appendChild(document.createElement('br'));
|
| 62 |
-
fragment.appendChild(document.createTextNode(li.textContent));
|
| 63 |
-
});
|
| 64 |
-
existingList.replaceWith(fragment);
|
| 65 |
-
editor.normalize();
|
| 66 |
-
editor.focus();
|
| 67 |
-
return;
|
| 68 |
-
}
|
| 69 |
-
|
| 70 |
-
// Get selected text or grab the current line
|
| 71 |
-
const range = sel.getRangeAt(0);
|
| 72 |
-
let text = '';
|
| 73 |
-
|
| 74 |
-
if (!range.collapsed) {
|
| 75 |
-
text = range.toString();
|
| 76 |
-
} else {
|
| 77 |
-
// No selection — use the text content of the current block/node
|
| 78 |
-
const node = sel.anchorNode;
|
| 79 |
-
if (node && node.nodeType === Node.TEXT_NODE) {
|
| 80 |
-
text = node.textContent;
|
| 81 |
-
}
|
| 82 |
-
}
|
| 83 |
-
|
| 84 |
-
if (!text.trim()) {
|
| 85 |
-
// Empty — insert an empty list with one item
|
| 86 |
-
const list = document.createElement(isOrdered ? 'ol' : 'ul');
|
| 87 |
-
const li = document.createElement('li');
|
| 88 |
-
li.innerHTML = '<br>';
|
| 89 |
-
list.appendChild(li);
|
| 90 |
-
range.insertNode(list);
|
| 91 |
-
// Place cursor inside the li
|
| 92 |
-
const newRange = document.createRange();
|
| 93 |
-
newRange.setStart(li, 0);
|
| 94 |
-
newRange.collapse(true);
|
| 95 |
-
sel.removeAllRanges();
|
| 96 |
-
sel.addRange(newRange);
|
| 97 |
-
editor.focus();
|
| 98 |
-
return;
|
| 99 |
-
}
|
| 100 |
-
|
| 101 |
-
// Split text into lines and create list
|
| 102 |
-
const lines = text.split(/\n/).filter(l => l.trim().length > 0);
|
| 103 |
-
const list = document.createElement(isOrdered ? 'ol' : 'ul');
|
| 104 |
-
lines.forEach(line => {
|
| 105 |
-
const li = document.createElement('li');
|
| 106 |
-
li.textContent = line.trim();
|
| 107 |
-
list.appendChild(li);
|
| 108 |
-
});
|
| 109 |
-
|
| 110 |
-
// Replace the selection with the list
|
| 111 |
-
range.deleteContents();
|
| 112 |
-
range.insertNode(list);
|
| 113 |
-
|
| 114 |
-
// Place cursor at end of last li
|
| 115 |
-
const lastLi = list.querySelector('li:last-child');
|
| 116 |
-
if (lastLi) {
|
| 117 |
-
const newRange = document.createRange();
|
| 118 |
-
newRange.selectNodeContents(lastLi);
|
| 119 |
-
newRange.collapse(false);
|
| 120 |
-
sel.removeAllRanges();
|
| 121 |
-
sel.addRange(newRange);
|
| 122 |
-
}
|
| 123 |
-
|
| 124 |
-
editor.normalize();
|
| 125 |
-
editor.focus();
|
| 126 |
-
updateFormatState();
|
| 127 |
-
}
|
| 128 |
|
| 129 |
/* ── Font family ── */
|
| 130 |
function formatFont(fontName) {
|
|
|
|
| 38 |
function formatAlignCenter() { execFormat('justifyCenter'); }
|
| 39 |
function formatAlignLeft() { execFormat('justifyLeft'); }
|
| 40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
/* ── Font family ── */
|
| 43 |
function formatFont(fontName) {
|