view src/bbcode/bbcode.js @ 52:9f8ebc757814

add convert urls
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 23 Nov 2022 23:29:16 -0700
parents 78b2d6995244
children cac477dd1f82
line wrap: on
line source

// https://fonts.google.com/icons

function ajax(url,postData,context) {
	let request = new XMLHttpRequest();
	let method = postData ? 'POST' : 'GET';
	request.open( method, url );
	if( postData )
		request.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
	request.onload = function() {
		if( request.status !== 200 ) {
			window.console && console.log( 'ajax failed: ' + request.status );
			if( request.responseText )
				document.write('<pre>'+request.responseText+'</pre>');
			return;
		}
		eval( request.responseText );
	};
	request.send(postData);
}

function upload(input,callback) {
	let file = input.files[0];
	input.value = null;
	let request = new XMLHttpRequest();
	let url = 'https://upload.uploadcare.com/base/';
	request.open( 'POST', url );
	request.onload = function() {
		if( request.status !== 200 ) {
			let err = 'ajax failed: ' + request.status;
			if( request.responseText ) {
				err += '\n' + request.responseText;
				document.write('<pre>'+request.responseText+'</pre>');
			}
			console.log(err);
			ajax( '/error_log.js', 'err='+encodeURIComponent(err) );
			return;
		}
		let response = JSON.parse(request.responseText);
		let filename = file.name;
		let url = 'https://ucarecdn.com/' + response.file + '/' + filename;
		callback(input,url,filename);
	};
	let formData = new FormData();
	formData.append( 'UPLOADCARE_PUB_KEY', 'fe3d30f3088a50941d45' );
	formData.append( 'file', file );
	request.send(formData);
}

function bbcodeCreate(div,options) {
	if( typeof(div) === 'string' ) {
		div = document.querySelector(div);
		if(!div) throw 'selector not found';
	}
	options = options || {};
	let content = options.content || '';
	let save = options.save;
	let cancel = options.cancel;
	let html = `\
		<div bbcode_editor>
			<textarea name=bbcode>${content}</textarea>
			<div preview from_bbcode></div>
			<div buttons>
				<button type=button bold title="Bold"><img src="/bbcode/icons/format_bold.svg"></button>
				<button type=button italic title="Italic"><img src="/bbcode/icons/format_italic.svg"></button>
				<button type=button underline title="Underline"><img src="/bbcode/icons/format_underlined.svg"></button>
				<button type=button strikethrough title="Strikethrough"><img src="/bbcode/icons/format_strikethrough.svg"></button>
				<button type=button sub title="Subscript"><img src="/bbcode/icons/subscript.svg"></button>
				<button type=button sup title="Superscript"><img src="/bbcode/icons/superscript.svg"></button>
				<button type=button ul title="Bullet list"><img src="/bbcode/icons/format_list_bulleted.svg"></button>
				<button type=button ol title="Numbered list"><img src="/bbcode/icons/format_list_numbered.svg"></button>
				<button type=button code_block title="Code block"><img src="/bbcode/icons/code_blocks.svg"></button>
				<button type=button code_inline title="Inline code"><img src="/bbcode/icons/code.svg"></button>
				<button type=button convert_urls checked title="Convert URLs"><img src="/bbcode/icons/media_link.svg"></button>
				<input type=hidden name=convert_urls value=true>
				<button type=button more checked title="More..."><img src="/bbcode/icons/more_horiz.svg"></button>
				<input type=file>
				<button type=button upload title="Upload File"><img src="/bbcode/icons/file_upload.svg"></button>
				<button type=button preview title="Preview"><img src="/bbcode/icons/preview.svg"></button>
`	;
	if(save) {
		html += `\
				<button type=button save title="Send message"><img src="/bbcode/icons/send.svg"></button>
`		;
	}
	if(cancel) {
		html += `\
				<button type=button cancel title="Cancel"><img src="/bbcode/icons/cancel.svg"></button>
`		;
	}
	html += `\
			</div>
		</div>
`	;
	div.innerHTML = html;

	let enabledInPreview = [];
	let convertUrls = true;

	if(save) {
		let button = div.querySelector('button[save]');
		button.onclick = function(event) {
			event.convertUrls = convertUrls;
			save(event);
		};
		enabledInPreview.push(button);
	}
	if(cancel) {
		let button = div.querySelector('button[cancel]');
		button.onclick = cancel;
		enabledInPreview.push(button);
	}

	let textarea = div.querySelector('textarea');
	function fixTextarea() {
		let height = textarea.scrollHeight;
		if( height > textarea.clientHeight ) {
			textarea.style.height = (height+2) + "px";
		}
	};
	textarea.oninput = fixTextarea;
	fixTextarea();

	function toggle(button) {
		let checked = button.getAttribute('checked') !== null;
		checked = !checked;  // toggle
		if( checked ) {
			button.setAttribute('checked','');
		} else {
			button.removeAttribute('checked');
		}
		return checked;
	}

	let moreButton = div.querySelector('button[more]');
	function more() {
		let checked = toggle(moreButton);
		let buttons = moreButton.parentNode.querySelectorAll('button');
		if( checked ) {
			for( let b of buttons ) {
				if( b === moreButton )
					break;
				b.removeAttribute('hidden');
			}
		} else {
			for( let b of buttons ) {
				if( b === moreButton )
					break;
				b.setAttribute('hidden','');
			}
		}
	};
	moreButton.onclick = more;
	more();
	enabledInPreview.push(moreButton);

	let divPreview = div.querySelector('div[preview]');
	function contextPreview(bbcode,html) {
		textarea.value = bbcode;
		divPreview.innerHTML = html;
	}
	let previewButton = div.querySelector('button[preview]');
	function preview() {
		let checked = toggle(previewButton);
		let buttons = previewButton.parentNode.querySelectorAll('button');
		if( checked ) {
			for( let b of buttons ) {
				if( !enabledInPreview.includes(b) )
					b.disabled = true;
			}
			textarea.style.display = 'none';
			divPreview.style.display = 'block';
			let url = '/bbcode/preview.js?text=' + encodeURIComponent(textarea.value) + '&convert_urls=' + convertUrls;
			ajax( url, null, {preview: contextPreview} );
		} else {
			for( let b of buttons ) {
					b.disabled = false;
			}
			textarea.style.display = 'initial';
			divPreview.style.display = 'none';
			textarea.focus();
		}
	}
	previewButton.onclick = preview;
	enabledInPreview.push(previewButton);

	let convertUrlsButton = div.querySelector('button[convert_urls]');
	let convertUrlsInput = div.querySelector('input[name="convert_urls"]');
	function toggleConvertUrls() {
		convertUrls = toggle(convertUrlsButton);
		convertUrlsInput.value = convertUrls;
	}
	convertUrlsButton.onclick = toggleConvertUrls;

	function add(tag,openTag,closeTag) {
		let button = div.querySelector('button['+tag+']');
		button.onclick = function() {
			let start = textarea.selectionStart;
			let end = textarea.selectionEnd;
			textarea.setRangeText(closeTag,end,end);
			textarea.setRangeText(openTag,start,start);
			let len = openTag.length;
			textarea.setSelectionRange(start+len,end+len);
			fixTextarea();
			textarea.focus();
		};
	}
	add('bold','[b]','[/b]');
	add('italic','[i]','[/i]');
	add('underline','[u]','[/u]');
	add('strikethrough','[s]','[/s]');
	add('sub','[sub]','[/sub]');
	add('sup','[sup]','[/sup]');
	add('ul','[list]\n[item]','[/item]\n[/list]');
	add('ol','[list=1]\n[item]','[/item]\n[/list]');
	add('code_block','[code]','[/code]');
	add('code_inline','[code=inline]','[/code]');

	let fileInput = div.querySelector('input[type="file"]');
	div.querySelector('button[upload]').onclick = function(){ fileInput.click(); };
	function uploaded(input,url,filename) {
		textarea.setRangeText(url,textarea.selectionStart,textarea.selectionEnd,'select');
		textarea.focus();
	}
	fileInput.onchange = function() { upload(fileInput,uploaded); };
}