Skip to content

Commit

Permalink
various ways to upload documents from the browser
Browse files Browse the repository at this point in the history
  • Loading branch information
fergiemcdowall committed Sep 20, 2024
1 parent c26beca commit 8886dad
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 83 deletions.
152 changes: 69 additions & 83 deletions www_root/utils/uploader/index.html
Original file line number Diff line number Diff line change
@@ -1,108 +1,94 @@
<html>
<head>
<title>Uploader</title>
<style>
textarea:invalid {
border: 3px solid red;
background: pink;
}

textarea:valid {
border: 2px solid lime;
}

#loading {
align-items: center; /* Vertically centers the image */
background-color: rgba(0, 0, 0, 0.3);
display: none;
height: 100%; /* Full viewport height */
justify-content: center; /* Horizontally centers the image */
left: 0;
position: fixed;
top: 0;
width: 100%; /* Full viewport width */
z-index: 9999;
}

#loading-img {
max-width: 400px; /* Optional: Ensures the image is responsive */
}

</style>
<script type="text/javascript" src="uploader.js"></script>
<link rel="stylesheet" href="styles.css">
</head>
<body>

<div id="loading">
<img id="loading-img" src="loading.webp" alt="loading...">
</div>

<label for="server-root">Server root:</label><br>
<input id="server-root" />
<p />
<td>
<details>
<summary>Click here to upload by manually inputting documents</summary>
<p>
<label for="json">Documents:</label>
<br>
<textarea id="json"
name="json"
oninput="validateInput()"
placeholder="Paste or type in an array of objects in json format"
rows=1
style="width:100%;"
type="text"></textarea>
</td>
<p />
<button onclick="PUT()" id="put">PUT</button>
</body>
<script>
</p>

const el = id => document.getElementById(id)
<p>
<button onclick="PUTFromTextArea()" id="put">/PUT</button>
</p>
</details>

const input = () => JSON.stringify(JSON.parse(el('json').value), null, 2)
<details>
<summary>Click here to upload from a file</summary>
<p>
<input type="file" id="file-upload">
</p>

// resize textarea to its contents
const resizeTextarea = () => el('json').setAttribute(
'rows', el('json')
.value.split(/\r|\r\n|\n/).length
)

const PUT = () => {
el('loading').style['display'] = 'flex'
fetch(new Request(el('server-root').value + "/API/PUT", {
body: input(),
headers: {
"Access-Control-Allow-Origin":"*"
},
method: "POST"
})).then(res => res.json()).then(json => {
console.log(json)
el('loading').style['display'] = 'none'
el('json').value = ''
resizeTextarea()
}).catch(console.error)
}
<p>
<button onclick="PUTFromFile()" id="put">/PUT</button>
</p>
</details>

const validateInput = () => {
// set invalid, not submittable as default
el('put').disabled = true
el('json').setCustomValidity('')

validation: try {
if (el('json').value == '') break validation // valid, but not submittable
el('json').value = input()
el('put').disabled = false // if no error thrown, json is valid
}
catch (e) {
el('json').setCustomValidity(e.toString()) // JSON is invalid
}
finally {
resizeTextarea()
}
}
<details>
<summary>Click here to upload via the openapi GUI</summary>
<p>
<a href="http://localhost:3030/openapi/#operations-WRITE-post_PUT">
Openapi docs
</a>
</p>
</details>

window.onload = () => {
validateInput()
el('server-root').value = window.location.protocol + '//' + window.location.host
}
<details>
<summary>Click here for cURL</summary>
<p>
(Assuming that you are running norch on http://localhost:3030).
</p>

</script>
<p>
Send data in curl command itself:

<pre>
curl -X 'POST' \
'http://localhost:3030/API/PUT?caseSensitive=true&nGrams=%7B%0A%20%20%22lengths%22%3A%20%5B%0A%20%20%20%201%0A%20%20%5D%2C%0A%20%20%22join%22%3A%20%22%20%22%2C%0A%20%20%22fields%22%3A%20%5B%5D%0A%7D&replace=%7B%0A%20%20%22fields%22%3A%20%5B%5D%2C%0A%20%20%22values%22%3A%20%7B%7D%0A%7D&tokenSplitRegex=%2F%5B%5Cp%7BL%7D%5Cd%5D%2B%2Fgu' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '[
{
"_id": "string"
}
]'
</pre>
</p>

<p>

Send file data from curl command:

<pre>
curl -X 'POST' \
'http://localhost:3030/API/PUT?caseSensitive=true&nGrams=%7B%0A%20%20%22lengths%22%3A%20%5B%0A%20%20%20%201%0A%20%20%5D%2C%0A%20%20%22join%22%3A%20%22%20%22%2C%0A%20%20%22fields%22%3A%20%5B%5D%0A%7D&replace=%7B%0A%20%20%22fields%22%3A%20%5B%5D%2C%0A%20%20%22values%22%3A%20%7B%7D%0A%7D&tokenSplitRegex=%2F%5B%5Cp%7BL%7D%5Cd%5D%2B%2Fgu' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
--data '@myFile.json'
</pre>
</p>


</details>



<pre id="server-response" />

</body>
</html>
39 changes: 39 additions & 0 deletions www_root/utils/uploader/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
textarea:invalid {
border: 3px solid red;
background: pink;
}

textarea:valid {
border: 2px solid lime;
}

#loading {
align-items: center; /* Vertically centers the image */
background-color: rgba(0, 0, 0, 0.3);
display: none;
height: 100%; /* Full viewport height */
justify-content: center; /* Horizontally centers the image */
left: 0;
position: fixed;
top: 0;
width: 100%; /* Full viewport width */
z-index: 9999;
}

#loading-img {
max-width: 400px; /* Optional: Ensures the image is responsive */
}

#server-response-details {
display: none;
}

label {
display: block;
}

summary {
cursor: pointer;
}

summary:hover { text-decoration: underline; }
97 changes: 97 additions & 0 deletions www_root/utils/uploader/uploader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// make it easier to grab elements
const el = id => document.getElementById(id)

// grab value of documents from textarea
const textareaInput = () =>
JSON.stringify(JSON.parse(el('json').value), null, 2)

// resize textarea to its contents
const resizeTextarea = () =>
el('json').setAttribute('rows', el('json').value.split(/\r|\r\n|\n/).length)

// log server responses to web page
const printResponse = response => {
el('server-response').innerHTML =
'\n\n' +
new Date().toISOString() +
' ->\n\n' +
JSON.stringify(response, null, 2) +
el('server-response').innerHTML
}

const loading = toggle =>
toggle
? (el('loading').style.display = 'flex')
: (el('loading').style.display = 'none')

// upload to server from textarea
const PUTFromTextArea = () => {
loading(true)
PUT(textareaInput())
}

// upload to server from file
PUTFromFile = () => {
loading(true)
const reader = new FileReader()
const [file] = el('file-upload').files
if (file) reader.readAsText(file)
reader.addEventListener('load', () => PUT(reader.result))
}

// upload to server
const PUT = json =>
fetch(
new Request('/API/PUT', {
body: json,
headers: {
'Access-Control-Allow-Origin': '*'
},
method: 'POST'
})
)
.then(res => res.json())
.then(reponse => {
console.log(reponse)
loading(false)
printResponse(reponse)
resizeTextarea()
})
.catch(console.error)

// pretty input validation
const validateInput = () => {
// set invalid, not submittable as default
el('put').disabled = true
el('json').setCustomValidity('')
validation: try {
if (el('json').value == '') break validation // valid, but not submittable
el('json').value = textareaInput()
el('put').disabled = false // if no error thrown, json is valid
} catch (e) {
el('json').setCustomValidity(e.toString()) // JSON is invalid
} finally {
resizeTextarea()
}
}

// only open one <details> element at a time
const setDetails = () => {
const details = document.querySelectorAll('details')
details.forEach(targetDetail => {
targetDetail.addEventListener('click', () => {
// Close all details that are not targetDetail
details.forEach(detail => {
if (detail !== targetDetail) {
detail.removeAttribute('open')
}
})
})
})
}

// if browser initialises wit content in textarea- validate!
window.onload = () => {
validateInput()
setDetails()
}

0 comments on commit 8886dad

Please sign in to comment.