youssefreda9 commited on
Commit
5d4c0cc
·
1 Parent(s): 993d144

fix: Rewrite list creation with manual DOM manipulation - execCommand('insertUnorderedList/OrderedList') doesn't work with pre-wrap - New approach: manually creates ul/ol + li elements from selected text - Splits text by newlines, creates proper li for each line - Toggle support: click again to remove list - Empty editor: inserts empty list item ready to type - Works regardless of white-space mode

Browse files
Files changed (1) hide show
  1. src/js/format.js +80 -7
src/js/format.js CHANGED
@@ -38,17 +38,90 @@ function formatAlignRight() { execFormat('justifyRight'); }
38
  function formatAlignCenter() { execFormat('justifyCenter'); }
39
  function formatAlignLeft() { execFormat('justifyLeft'); }
40
 
41
- /* ── Lists (need temporary white-space switch for pre-wrap editors) ── */
42
  function formatList(command) {
43
  const editor = getEditorElement();
44
  if (!editor) return;
45
- // pre-wrap blocks list creation, temporarily switch to normal
46
- editor.style.whiteSpace = 'normal';
47
- document.execCommand(command, false, null);
48
- // Restore pre-wrap after browser processes the command
49
- requestAnimationFrame(() => {
50
- editor.style.whiteSpace = '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  editor.focus();
53
  updateFormatState();
54
  }
 
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
  }