comparison src/bbcode/bbcode.js @ 60:8b5b1bce7d6b

bcode menus
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 30 Nov 2022 23:50:52 -0700
parents cac477dd1f82
children
comparison
equal deleted inserted replaced
59:02d8876dc41d 60:8b5b1bce7d6b
50 if( typeof(div) === 'string' ) { 50 if( typeof(div) === 'string' ) {
51 div = document.querySelector(div); 51 div = document.querySelector(div);
52 if(!div) throw 'selector not found'; 52 if(!div) throw 'selector not found';
53 } 53 }
54 options = options || {}; 54 options = options || {};
55 options.buttons = options.buttons || {};
55 let content = options.content || ''; 56 let content = options.content || '';
56 let save = options.save;
57 let cancel = options.cancel;
58 let html = `\ 57 let html = `\
59 <div bbcode_editor> 58 <div bbcode_editor>
60 <textarea name=bbcode>${content}</textarea> 59 <div buttons=top>
61 <div preview from_bbcode></div>
62 <div buttons>
63 <button type=button bold title="Bold"><img src="/bbcode/icons/format_bold.svg"></button> 60 <button type=button bold title="Bold"><img src="/bbcode/icons/format_bold.svg"></button>
64 <button type=button italic title="Italic"><img src="/bbcode/icons/format_italic.svg"></button> 61 <button type=button italic title="Italic"><img src="/bbcode/icons/format_italic.svg"></button>
65 <button type=button underline title="Underline"><img src="/bbcode/icons/format_underlined.svg"></button> 62 <button type=button underline title="Underline"><img src="/bbcode/icons/format_underlined.svg"></button>
66 <button type=button strikethrough title="Strikethrough"><img src="/bbcode/icons/format_strikethrough.svg"></button> 63 <button type=button strikethrough title="Strikethrough"><img src="/bbcode/icons/format_strikethrough.svg"></button>
67 <button type=button sub title="Subscript"><img src="/bbcode/icons/subscript.svg"></button> 64 <button type=button sub title="Subscript"><img src="/bbcode/icons/subscript.svg"></button>
68 <button type=button sup title="Superscript"><img src="/bbcode/icons/superscript.svg"></button> 65 <button type=button sup title="Superscript"><img src="/bbcode/icons/superscript.svg"></button>
69 <button type=button ul title="Bullet list"><img src="/bbcode/icons/format_list_bulleted.svg"></button> 66 <button type=button ul title="Bullet list"><img src="/bbcode/icons/format_list_bulleted.svg"></button>
70 <button type=button ol title="Numbered list"><img src="/bbcode/icons/format_list_numbered.svg"></button> 67 <button type=button ol title="Numbered list"><img src="/bbcode/icons/format_list_numbered.svg"></button>
71 <button type=button code_block title="Code block"><img src="/bbcode/icons/code_blocks.svg"></button> 68 <button type=button code_block title="Code block"><img src="/bbcode/icons/code_blocks.svg"></button>
72 <button type=button code_inline title="Inline code"><img src="/bbcode/icons/code.svg"></button> 69 <button type=button code_inline title="Inline code"><img src="/bbcode/icons/code.svg"></button>
73 <button type=button convert_urls checked title="Convert URLs"><img src="/bbcode/icons/media_link.svg"></button> 70 <button type=button convert_urls><input type=checkbox name=convert_urls checked> Convert URLs</button>
74 <input type=hidden name=convert_urls value=true> 71 </div>
75 <button type=button more checked title="More..."><img src="/bbcode/icons/more_horiz.svg"></button> 72 <textarea name=bbcode>${content}</textarea>
73 <div preview from_bbcode></div>
74 <div buttons=bottom>
75 <button type=button more><input type=checkbox> BBCode menu</button>
76 <input type=file> 76 <input type=file>
77 <button type=button upload title="Upload File"><img src="/bbcode/icons/file_upload.svg"></button> 77 <button type=button upload>Upload file</button>
78 <button type=button preview title="Preview"><img src="/bbcode/icons/preview.svg"></button> 78 <button type=button preview><input type=checkbox> Preview</button>
79 ` ; 79 ` ;
80 if(save) { 80 for( let key of Object.keys(options.buttons) ) {
81 html += `\ 81 html += `\
82 <button type=button save title="Send message"><img src="/bbcode/icons/send.svg"></button> 82 <button type=button key="${key}">${key}</button>
83 ` ;
84 }
85 if(cancel) {
86 html += `\
87 <button type=button cancel title="Cancel"><img src="/bbcode/icons/cancel.svg"></button>
88 ` ; 83 ` ;
89 } 84 }
90 html += `\ 85 html += `\
91 </div> 86 </div>
92 </div> 87 </div>
94 div.innerHTML = html; 89 div.innerHTML = html;
95 90
96 let enabledInPreview = []; 91 let enabledInPreview = [];
97 let convertUrls = true; 92 let convertUrls = true;
98 93
99 if(save) { 94 for( let entry of Object.entries(options.buttons) ) {
100 let button = div.querySelector('button[save]'); 95 console.log(entry);
96 let button = div.querySelector('button[key="'+entry[0]+'"]');
97 let fn = entry[1];
101 button.onclick = function(event) { 98 button.onclick = function(event) {
102 event.convertUrls = convertUrls; 99 event.convertUrls = convertUrls;
103 save(event); 100 fn(event);
104 }; 101 };
105 enabledInPreview.push(button);
106 }
107 if(cancel) {
108 let button = div.querySelector('button[cancel]');
109 button.onclick = cancel;
110 enabledInPreview.push(button); 102 enabledInPreview.push(button);
111 } 103 }
112 104
113 let textarea = div.querySelector('textarea'); 105 let textarea = div.querySelector('textarea');
114 function fixTextarea() { 106 function fixTextarea() {
118 } 110 }
119 }; 111 };
120 textarea.oninput = fixTextarea; 112 textarea.oninput = fixTextarea;
121 fixTextarea(); 113 fixTextarea();
122 114
123 function toggle(button) { 115 function checkboxButtonClick(event) {
124 let checked = button.getAttribute('checked') !== null; 116 event.target.querySelector('input').click();
125 checked = !checked; // toggle 117 };
126 if( checked ) { 118
127 button.setAttribute('checked',''); 119 let topButtons = div.querySelector('[buttons="top"]');
120 topButtons.style.display = 'none';
121 let moreButton = div.querySelector('button[more]');
122 moreButton.onclick = checkboxButtonClick;
123 let moreCheckbox = moreButton.querySelector('input');
124 moreCheckbox.onclick = function() {
125 if( moreCheckbox.checked ) {
126 topButtons.style.display = 'flex';
128 } else { 127 } else {
129 button.removeAttribute('checked'); 128 topButtons.style.display = 'none';
130 } 129 }
131 return checked; 130 event.stopPropagation();
132 } 131 };
133
134 let moreButton = div.querySelector('button[more]');
135 function more() {
136 let checked = toggle(moreButton);
137 let buttons = moreButton.parentNode.querySelectorAll('button');
138 if( checked ) {
139 for( let b of buttons ) {
140 if( b === moreButton )
141 break;
142 b.removeAttribute('hidden');
143 }
144 } else {
145 for( let b of buttons ) {
146 if( b === moreButton )
147 break;
148 b.setAttribute('hidden','');
149 }
150 }
151 };
152 moreButton.onclick = more;
153 more();
154 enabledInPreview.push(moreButton);
155 132
156 let divPreview = div.querySelector('div[preview]'); 133 let divPreview = div.querySelector('div[preview]');
157 function contextPreview(bbcode,html) { 134 function contextPreview(bbcode,html) {
158 textarea.value = bbcode; 135 textarea.value = bbcode;
159 divPreview.innerHTML = html; 136 divPreview.innerHTML = html;
160 } 137 }
161 let previewButton = div.querySelector('button[preview]'); 138 let previewButton = div.querySelector('button[preview]');
162 function preview() { 139 previewButton.onclick = checkboxButtonClick;
163 let checked = toggle(previewButton); 140 let previewCheckbox = previewButton.querySelector('input');
141 previewCheckbox.onclick = function() {
164 let buttons = previewButton.parentNode.querySelectorAll('button'); 142 let buttons = previewButton.parentNode.querySelectorAll('button');
165 if( checked ) { 143 if( previewCheckbox.checked ) {
166 for( let b of buttons ) { 144 for( let b of buttons ) {
167 if( !enabledInPreview.includes(b) ) 145 if( !enabledInPreview.includes(b) )
168 b.disabled = true; 146 b.disabled = true;
169 } 147 }
170 textarea.style.display = 'none'; 148 textarea.style.display = 'none';
171 divPreview.style.display = 'block'; 149 divPreview.style.display = 'block';
150 topButtons.style.display = 'none';
172 let postData = 'text=' + encodeURIComponent(textarea.value) + '&convert_urls=' + convertUrls; 151 let postData = 'text=' + encodeURIComponent(textarea.value) + '&convert_urls=' + convertUrls;
173 ajax( '/bbcode/preview.js', postData, {preview: contextPreview} ); 152 ajax( '/bbcode/preview.js', postData, {preview: contextPreview} );
174 } else { 153 } else {
175 for( let b of buttons ) { 154 for( let b of buttons ) {
176 b.disabled = false; 155 b.disabled = false;
177 } 156 }
178 textarea.style.display = 'initial'; 157 textarea.style.display = 'initial';
179 divPreview.style.display = 'none'; 158 divPreview.style.display = 'none';
159 if( moreCheckbox.checked )
160 topButtons.style.display = 'flex';
180 textarea.focus(); 161 textarea.focus();
181 } 162 }
182 } 163 event.stopPropagation();
183 previewButton.onclick = preview; 164 }
184 enabledInPreview.push(previewButton); 165 enabledInPreview.push(previewButton);
185 166
186 let convertUrlsButton = div.querySelector('button[convert_urls]'); 167 let convertUrlsButton = div.querySelector('button[convert_urls]');
187 let convertUrlsInput = div.querySelector('input[name="convert_urls"]'); 168 convertUrlsButton.onclick = checkboxButtonClick;
188 function toggleConvertUrls() { 169 let convertUrlsCheckbox = convertUrlsButton.querySelector('input');
189 convertUrls = toggle(convertUrlsButton); 170 convertUrlsCheckbox.onclick = function(event) {
190 convertUrlsInput.value = convertUrls; 171 convertUrls = convertUrlsCheckbox.checked;
191 } 172 event.stopPropagation();
192 convertUrlsButton.onclick = toggleConvertUrls; 173 };
193 174
194 function add(tag,openTag,closeTag) { 175 function add(tag,openTag,closeTag) {
195 let button = div.querySelector('button['+tag+']'); 176 let button = div.querySelector('button['+tag+']');
196 button.onclick = function() { 177 button.onclick = function() {
197 let start = textarea.selectionStart; 178 let start = textarea.selectionStart;