mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-22 12:01:23 +01:00
Cloud support / Dropbox OAuth reference client (#659)
* bioms shouldn't be masked or the style selection box is useless * fix: misleading comment * Fix: calculating absolute flux from precipitation normal-value. * Fix: River automatic rerender on regeneration. * Dropbox OAuth implementation and Cloud framework * add some space * removing unnecessary logs, defer script load Created by: Mészáros Gergely <monk@geotronic.hu>
This commit is contained in:
parent
e55588f313
commit
948a7ed3a1
5 changed files with 196 additions and 65 deletions
33
index.html
33
index.html
|
|
@ -2967,8 +2967,8 @@
|
|||
|
||||
<div data-tip="Burg mean annual temperature and real-world city for comparison">
|
||||
<div class="label">Temperature:</div>
|
||||
<span id="burgTemperature"></span>, like in
|
||||
<span id="burgTemperatureLike"></span>
|
||||
<span id="burgTemperature"></span>, like in
|
||||
<span id="burgTemperatureLikeIn"></span>
|
||||
</div>
|
||||
|
||||
<div data-tip="Burg height above mean sea level">
|
||||
|
|
@ -4575,26 +4575,29 @@
|
|||
<button onclick="quickSave()" data-tip="Save the project to browser storage (quick save). It can be unreliable. Shortcut: F6">browser</button>
|
||||
</div>
|
||||
<p style="font-style: italic">Maps are saved in <i>.map</i> format, that can be loaded back via 'Load' in menu. Please keep noted that we do not keep any data on our side. There is no way to restore the progress if .map file is lost. Please keep old .map files on your machine or cloud storage as backups.</p>
|
||||
<p style="font-style: italic">Saving to Dropbox may not be allowed for big files. In this case open <a href="https://www.dropbox.com/home/FMG" target="_blank">Dropbox</a>, download the .map file and upload it manually.</p>
|
||||
|
||||
<div style="margin-top: .3em" data-tip="Select .map file on dropbox and share a sharable link">
|
||||
<strong>Create sharable link</strong>
|
||||
<button onclick="createSharableDropboxLink()">select file</button>
|
||||
<div id="sharableLinkContainer" style="display: none">
|
||||
<a id="sharableLink" target="_blank"></a>
|
||||
<i data-tip="Copy link to the clipboard" onclick="copyLinkToClickboard()" class="icon-clone pointer"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="loadMapData" style="display: none" class="dialog">
|
||||
<div style="margin-bottom: .3em">Load map from</div>
|
||||
<div>
|
||||
<button onclick="mapToLoad.click()" data-tip="Load .map file from local disk">local disk</button>
|
||||
<button onclick="loadFromDropbox()" data-tip="Load .map file from your Dropbox">Dropbox</button>
|
||||
<button onclick="loadURL()" data-tip="Load .map file from URL (server should allow CORS)">URL</button>
|
||||
<button onclick="quickLoad()" data-tip="Load map from browser storage (if saved before)">storage</button>
|
||||
</div>
|
||||
<div id="loadFromDropbox">
|
||||
<p>From your Dropbox account:</p>
|
||||
<select style="margin-bottom:.3em">
|
||||
</select>
|
||||
<button onclick="loadFromDropbox()" data-tip="Load .map file from your Dropbox">Open</button>
|
||||
<button onclick="createSharableDropboxLink()" data-tip="Select .map file on dropbox and share a sharable link">Create link</button>
|
||||
|
||||
<div style="margin-top: .3em">
|
||||
<div id="sharableLinkContainer" style="display: none">
|
||||
<a id="sharableLink" target="_blank"></a>
|
||||
<i data-tip="Copy link to the clipboard" onclick="copyLinkToClickboard()" class="icon-clone pointer"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="saveTilesScreen" style="display: none" class="dialog">
|
||||
|
|
@ -4612,7 +4615,7 @@
|
|||
<div data-tip="Image scale relative to image size (e.g. 5x)" style="margin-bottom: .3em">
|
||||
<div class="label">Scale:</div>
|
||||
<input id="tileScaleInput" data-stored="tileScale" type="range" min=1 max=4 value=1 style="width: 11em">
|
||||
<input id="tileScaleOutput" data-stored="tileScale" type="number" min=1 value=1
|
||||
<input id="tileScaleOutput" data-stored="tileScale" type="number" min=1 value=1
|
||||
>
|
||||
</div>
|
||||
<div data-tip="Calculated size of image if combined" style="margin-bottom: .3em">
|
||||
|
|
@ -10895,6 +10898,7 @@
|
|||
<script defer src="modules/ui/style.js"></script>
|
||||
<script defer src="modules/save.js"></script>
|
||||
<script defer src="modules/load.js"></script>
|
||||
<script defer src="modules/cloud.js"></script>
|
||||
<script defer src="main.js"></script>
|
||||
<script defer src="modules/relief-icons.js"></script>
|
||||
<script defer src="modules/ui/tools.js"></script>
|
||||
|
|
@ -10936,7 +10940,6 @@
|
|||
<script defer src="libs/jquery.ui.touch-punch.min.js"></script>
|
||||
<script defer src="libs/pell.min.js"></script>
|
||||
<script defer src="libs/jszip.min.js"></script>
|
||||
<script defer src="libs/dropins.min.js" id="dropboxjs" data-app-key="pdr9ae64ip0qno4"></script>
|
||||
</body>
|
||||
>>>>>>> f557701e (dropbox - import changes from alpha)
|
||||
</html>
|
||||
|
|
|
|||
141
modules/cloud.js
Normal file
141
modules/cloud.js
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
"use strict";
|
||||
|
||||
/*
|
||||
Cloud provider implementations (Dropbox only as now)
|
||||
|
||||
provider Interface:
|
||||
|
||||
name: name of the provider
|
||||
async auth(): authenticate and get access tokens from provider
|
||||
async save(filename): save map file to provider as filename
|
||||
async load(filename): load filename from provider
|
||||
async list(): list available filenames at provider
|
||||
async getLink(filePath): get shareable link for file
|
||||
restore(): restore access tokens from storage if possible
|
||||
|
||||
*/
|
||||
|
||||
window.Cloud = (function () {
|
||||
|
||||
// helpers to use in providers for token handling
|
||||
const lSKey = x => `auth-${x}`
|
||||
const setToken = (prov, key) => localStorage.setItem(lSKey(prov), key)
|
||||
const getToken = prov => localStorage.getItem(lSKey(prov))
|
||||
|
||||
/**********************************************************/
|
||||
/* Dropbox provider */
|
||||
/**********************************************************/
|
||||
|
||||
const DBP = {
|
||||
name: 'dropbox',
|
||||
clientId: 'sp7tzwm27u2w5ns',
|
||||
authWindow: undefined,
|
||||
token: null, // Access token
|
||||
api: null,
|
||||
|
||||
restore() {
|
||||
this.token = getToken(this.name)
|
||||
if (this.token) this.connect(this.token)
|
||||
},
|
||||
|
||||
async call(name, param) {
|
||||
try {
|
||||
return await this.api[name](param)
|
||||
} catch (e) {
|
||||
if (e.name !== "DropboxResponseError") throw(e)
|
||||
// retry with auth
|
||||
await this.auth()
|
||||
return await this.api[name](param)
|
||||
}
|
||||
},
|
||||
|
||||
connect(token) {
|
||||
const clientId = this.clientId
|
||||
const auth = new Dropbox.DropboxAuth({ clientId })
|
||||
auth.setAccessToken(token)
|
||||
this.api = new Dropbox.Dropbox({ auth })
|
||||
},
|
||||
|
||||
async save(fileName, contents) {
|
||||
if (!this.api) await this.auth()
|
||||
const resp = this.call('filesUpload', { path: '/' + fileName, contents })
|
||||
console.log("Dropbox response:", resp)
|
||||
return true
|
||||
},
|
||||
|
||||
async load(path) {
|
||||
if (!this.api) await this.auth()
|
||||
const resp = await this.call('filesDownload', { path })
|
||||
const blob = resp.result.fileBlob
|
||||
if (!blob) throw(new Error('Invalid response from dropbox.'))
|
||||
return blob
|
||||
},
|
||||
|
||||
async list() {
|
||||
if (!this.api) return null
|
||||
const resp = await this.call('filesListFolder', { path: '' })
|
||||
return resp.result.entries.map(e => ({ name: e.name, path: e.path_lower }))
|
||||
},
|
||||
|
||||
auth() {
|
||||
const url = window.location.origin + window.location.pathname + 'dropbox.html'
|
||||
this.authWindow = window.open(url, 'auth', 'width=640,height=480')
|
||||
// child window expected to call
|
||||
// window.opener.Cloud.providers.dropbox.setDropBoxToken (see below)
|
||||
return new Promise((resolve, reject) => {
|
||||
const watchDog = () => {
|
||||
this.authWindow.close()
|
||||
reject(new Error("Timeout. No auth for dropbox."))
|
||||
}
|
||||
setTimeout(watchDog, 120*1000)
|
||||
window.addEventListener('dropboxauth', e => {
|
||||
clearTimeout(watchDog)
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// Callback function for auth window.
|
||||
setDropBoxToken(token) {
|
||||
console.log('Access token got:', token)
|
||||
setToken(this.name, token)
|
||||
this.connect(token)
|
||||
this.authWindow.close()
|
||||
window.dispatchEvent(new Event('dropboxauth'))
|
||||
},
|
||||
|
||||
async getLink(path) {
|
||||
if (!this.api) await this.auth()
|
||||
let resp
|
||||
|
||||
// already exists?
|
||||
resp = await this.call('sharingListSharedLinks', { path })
|
||||
if (resp.result.links.length)
|
||||
return resp.result.links[0].url
|
||||
|
||||
// create new
|
||||
resp = await this.call('sharingCreateSharedLinkWithSettings', {
|
||||
path,
|
||||
settings: {
|
||||
require_password: false,
|
||||
audience: 'public',
|
||||
access: 'viewer',
|
||||
requested_visibility: 'public',
|
||||
allow_download: true,
|
||||
}
|
||||
})
|
||||
console.log("dropbox link object:", resp.result)
|
||||
return resp.result.url
|
||||
},
|
||||
}
|
||||
|
||||
// register providers here:
|
||||
const providers = {
|
||||
dropbox: DBP,
|
||||
}
|
||||
|
||||
// restore all providers at startup
|
||||
for (const p of Object.values(providers)) p.restore()
|
||||
|
||||
return { providers }
|
||||
})()
|
||||
|
|
@ -12,16 +12,34 @@ function quickLoad() {
|
|||
});
|
||||
}
|
||||
|
||||
function loadFromDropbox() {
|
||||
const options = {
|
||||
success: function (files) {
|
||||
const url = files[0].link;
|
||||
loadMapFromURL(url);
|
||||
},
|
||||
linkType: "direct",
|
||||
extensions: [".map"]
|
||||
};
|
||||
Dropbox.choose(options);
|
||||
async function loadFromDropbox(fileName) {
|
||||
const map = document.querySelector("#loadFromDropbox select").value;
|
||||
console.log('loading dropbox map', map);
|
||||
const blob = await Cloud.providers.dropbox.load(map);
|
||||
uploadMap(blob);
|
||||
}
|
||||
|
||||
async function createSharableDropboxLink() {
|
||||
const mapFile = document.querySelector("#loadFromDropbox select").value;
|
||||
const sharableLink = document.getElementById("sharableLink");
|
||||
const sharableLinkContainer = document.getElementById("sharableLinkContainer");
|
||||
let url
|
||||
try {
|
||||
url = await Cloud.providers.dropbox.getLink(mapFile);
|
||||
} catch {
|
||||
tip("Dropbox API error. Can not create link.", true, "error", 2000);
|
||||
return
|
||||
}
|
||||
|
||||
const fmg = window.location.href.split("?")[0];
|
||||
const reallink= `${fmg}?maplink=${url}`;
|
||||
// voodoo magic required by the yellow god of CORS
|
||||
const link = reallink.replace('www.dropbox.com/s/', 'dl.dropboxusercontent.com/1/view/')
|
||||
const shortLink = link.slice(0, 50) + "...";
|
||||
|
||||
sharableLinkContainer.style.display = "block";
|
||||
sharableLink.innerText = shortLink;
|
||||
sharableLink.setAttribute("href", link);
|
||||
}
|
||||
|
||||
function loadMapPrompt(blob) {
|
||||
|
|
|
|||
|
|
@ -441,42 +441,19 @@ function dowloadMap() {
|
|||
window.URL.revokeObjectURL(URL);
|
||||
}
|
||||
|
||||
function saveToDropbox() {
|
||||
async function saveToDropbox() {
|
||||
const sharableLinkContainer = document.getElementById("sharableLinkContainer");
|
||||
if (customization) return tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error");
|
||||
closeDialogs("#alert");
|
||||
|
||||
const mapData = getMapData();
|
||||
const URL = "data:text/plain; base64," + btoa(encodeURIComponent(mapData));
|
||||
const filename = getFileName() + ".map";
|
||||
const options = {
|
||||
success: () => tip("Map is saved to your Dropbox", true, "success", 8000),
|
||||
error: function (errorMessage) {
|
||||
tip("Cannot save .map to your Dropbox", true, "error", 8000);
|
||||
console.error(errorMessage);
|
||||
}
|
||||
};
|
||||
Dropbox.save(URL, filename, options);
|
||||
}
|
||||
|
||||
function createSharableDropboxLink() {
|
||||
const sharableLink = document.getElementById("sharableLink");
|
||||
const sharableLinkContainer = document.getElementById("sharableLinkContainer");
|
||||
|
||||
const options = {
|
||||
success: function (files) {
|
||||
const url = files[0].link;
|
||||
const fmg = window.location.href.split("?")[0];
|
||||
const link = `${fmg}/?maplink=${url}`;
|
||||
const shortLink = link.slice(0, 50) + "...";
|
||||
|
||||
sharableLinkContainer.style.display = "block";
|
||||
sharableLink.innerText = shortLink;
|
||||
sharableLink.setAttribute("href", link);
|
||||
},
|
||||
linkType: "direct",
|
||||
extensions: [".map"]
|
||||
};
|
||||
Dropbox.choose(options);
|
||||
try {
|
||||
await Cloud.providers.dropbox.save(filename, mapData);
|
||||
tip("Map is saved to your Dropbox", true, "success", 8000);
|
||||
} catch (msg) {
|
||||
console.error(msg);
|
||||
tip("Cannot save .map to your Dropbox", true, "error", 8000);
|
||||
}
|
||||
}
|
||||
|
||||
function saveGeoJSON_Cells() {
|
||||
|
|
|
|||
|
|
@ -702,11 +702,7 @@ function showSavePane() {
|
|||
$("#saveMapData").dialog({
|
||||
title: "Save map",
|
||||
resizable: false,
|
||||
<<<<<<< HEAD
|
||||
width: "25em",
|
||||
=======
|
||||
width: "27em",
|
||||
>>>>>>> f557701e (dropbox - import changes from alpha)
|
||||
position: {my: "center", at: "center", of: "svg"},
|
||||
buttons: {
|
||||
Close: function () {
|
||||
|
|
@ -747,11 +743,7 @@ async function showLoadPane() {
|
|||
$("#loadMapData").dialog({
|
||||
title: "Load map",
|
||||
resizable: false,
|
||||
<<<<<<< HEAD
|
||||
width: "24em",
|
||||
=======
|
||||
width: "22em",
|
||||
>>>>>>> f557701e (dropbox - import changes from alpha)
|
||||
position: {my: "center", at: "center", of: "svg"},
|
||||
buttons: {
|
||||
Close: function () {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue