forked from cory/tildefriends
		
	App import/export from the editor.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4786 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
		| @@ -1029,6 +1029,97 @@ function removeFile() { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| async function appExport() { | ||||
| 	let JsZip = (await import('/static/jszip.min.js')).default; | ||||
| 	let owner = window.location.pathname.split('/')[1].replace('~', ''); | ||||
| 	let name = window.location.pathname.split('/')[2]; | ||||
| 	let zip = new JsZip(); | ||||
| 	zip.file(`${name}.json`, JSON.stringify({ | ||||
| 		type: "tildefriends-app", | ||||
| 		emoji: gApp.emoji || '📦', | ||||
| 	})); | ||||
| 	for (let file of Object.keys(gFiles)) { | ||||
| 		zip.file(`${name}/${file}`, gFiles[file].buffer ?? gFiles[file].doc.doc.toString()); | ||||
| 	} | ||||
| 	let content = await zip.generateAsync({ | ||||
| 		type: 'blob', | ||||
| 		compression: 'DEFLATE', | ||||
| 	}); | ||||
| 	let a = document.createElement('a'); | ||||
| 	a.href = URL.createObjectURL(content); | ||||
| 	a.download = `${owner}_${name}.zip`; | ||||
| 	a.click(); | ||||
| } | ||||
|  | ||||
| async function save_file_to_blob_id(name, file) { | ||||
| 	console.log(`Saving ${name}.`); | ||||
| 	let response = await fetch('/save', { | ||||
| 		method: 'POST', | ||||
| 		headers: { | ||||
| 			'Content-Type': 'application/binary', | ||||
| 		}, | ||||
| 		body: file, | ||||
| 	}); | ||||
| 	if (!response.ok) { | ||||
| 		throw new Error('Saving "' + name + '": ' + response.status + ' ' + response.statusText); | ||||
| 	} | ||||
| 	let blob_id = await response.text(); | ||||
| 	if (blob_id.charAt(0) == '/') { | ||||
| 		blob_id = blob_id.substr(1); | ||||
| 	} | ||||
| 	return blob_id; | ||||
| } | ||||
|  | ||||
| async function appImport() { | ||||
| 	let JsZip = (await import('/static/jszip.min.js')).default; | ||||
| 	let input = document.createElement('input'); | ||||
| 	input.type = 'file'; | ||||
| 	input.click(); | ||||
| 	input.onchange = async function() { | ||||
| 		try { | ||||
| 			for (let file of input.files) { | ||||
| 				if (file.type != 'application/zip') { | ||||
| 					console.log('This does not look like a .zip.'); | ||||
| 					continue; | ||||
| 				} | ||||
| 				let buffer = await file.arrayBuffer(); | ||||
| 				let zip = new JsZip(); | ||||
| 				await zip.loadAsync(buffer); | ||||
| 				let app_object; | ||||
| 				let app_name; | ||||
| 				for (let [name, object] of Object.entries(zip.files)) { | ||||
| 					if (name.endsWith('.json') && name.indexOf('/') == -1) { | ||||
| 						try { | ||||
| 							let parsed = JSON.parse(await object.async('text')); | ||||
| 							if (parsed.type == 'tildefriends-app') { | ||||
| 								app_object = parsed; | ||||
| 								app_name = name.substring(0, name.length - '.json'.length); | ||||
| 								break; | ||||
| 							} | ||||
| 						} catch (e) { | ||||
| 							console.log(e); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				if (app_object) { | ||||
| 					app_object.files = {}; | ||||
| 					for (let [name, object] of Object.entries(zip.files)) { | ||||
| 						if (!name.startsWith(app_name + '/') || name.endsWith('/')) { | ||||
| 							continue; | ||||
| 						} | ||||
| 						app_object.files[name.substring(app_name.length + '/'.length)] = await save_file_to_blob_id(name, await object.async('arrayBuffer')); | ||||
| 					} | ||||
| 					let path = '/' + await save_file_to_blob_id(`${app_name}.json`, JSON.stringify(app_object)) + '/'; | ||||
| 					console.log('Redirecting to:', path); | ||||
| 					window.location.pathname = path; | ||||
| 				} | ||||
| 			} | ||||
| 		} catch (e) { | ||||
| 			alert(e.toString()); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| window.addEventListener("load", function() { | ||||
| 	window.addEventListener("hashchange", hashChange); | ||||
| 	window.addEventListener("focus", focus); | ||||
| @@ -1040,6 +1131,8 @@ window.addEventListener("load", function() { | ||||
| 	document.getElementById('save').addEventListener('click', () => save()); | ||||
| 	document.getElementById('icon').addEventListener('click', () => changeIcon()); | ||||
| 	document.getElementById('delete').addEventListener('click', () => deleteApp()); | ||||
| 	document.getElementById('export').addEventListener('click', () => appExport()); | ||||
| 	document.getElementById('import').addEventListener('click', () => appImport()); | ||||
| 	document.getElementById('trace_button').addEventListener('click', function(event) { | ||||
| 		event.preventDefault(); | ||||
| 		trace(); | ||||
|   | ||||
| @@ -35,6 +35,7 @@ let k_static_files = [ | ||||
| 	{uri: '/', path: 'index.html', type: 'text/html; charset=UTF-8'}, | ||||
| 	{uri: '/client.js', type: 'text/javascript; charset=UTF-8'}, | ||||
| 	{uri: '/favicon.png', type: 'image/png'}, | ||||
| 	{uri: '/jszip.min.js', type: 'text/javascript; charset=UTF-8'}, | ||||
| 	{uri: '/robots.txt', type: 'text/plain; charset=UTF-8'}, | ||||
| 	{uri: '/style.css', type: 'text/css; charset=UTF-8'}, | ||||
| 	{uri: '/tfrpc.js', type: 'text/javascript; charset=UTF-8', headers: {'Access-Control-Allow-Origin': 'null'}}, | ||||
|   | ||||
| @@ -22,6 +22,8 @@ | ||||
| 					<button class="w3-bar-item w3-button w3-blue" id="closeEditor" name="closeEditor" accesskey="c" onmouseover="set_access_key_title(event)" data-tip="Close the editor">Close</button> | ||||
| 					<button class="w3-bar-item w3-button w3-blue" id="save" name="save" accesskey="s" onmouseover="set_access_key_title(event)" data-tip="Save the app under the given path">Save</button> | ||||
| 					<button class="w3-bar-item w3-button w3-blue" id="icon" name="icon" accesskey="i" onmouseover="set_access_key_title(event)" data-tip="Set an icon/emoji for the app">📦</button> | ||||
| 					<button class="w3-bar-item w3-button w3-blue" id="export" name="export" accesskey="e" onmouseover="set_access_key_title(event)" data-tip="Export app to .zip file">Export</button> | ||||
| 					<button class="w3-bar-item w3-button w3-blue" id="import" name="import" accesskey="i" onmouseover="set_access_key_title(event)" data-tip="Import app from .zip file">Import</button> | ||||
| 					<input class="w3-bar-item w3-input w3-border w3-blue" type="text" id="name" name="name" style="flex: 1 1; min-width: 1em"></input> | ||||
| 					<button class="w3-bar-item w3-button w3-blue" id="delete" name="delete" accesskey="d" onmouseover="set_access_key_title(event)" data-tip="Delete the app">Delete</button> | ||||
| 					<button class="w3-bar-item w3-button w3-blue" id="trace_button" accesskey="t" onmouseover="set_access_key_title(event)" data-tip="Open a performance trace for the server">Trace</button> | ||||
|   | ||||
							
								
								
									
										1
									
								
								core/jszip.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								core/jszip.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Reference in New Issue
	
	Block a user