Same as the use of Float-Window API, some of the functions involving ao_module wrapper will require the following library to be imported.
<script type="text/javascript" src="../script/jquery.min.js"></script>
<script type="text/javascript" src="../script/ao_module.js"></script>
Note that jquery must be imported before ao_module.js AND ao_module must be imported with relative path to current script to make sure all the ao_module functions are usable.
ArozOS has a build-in file selector which you can utilize in your WebApp as well as some utilities function to help you build a WebApp easily with file selection functions.
openFileSelector allow user to pick a file from their cloud virtual drives. Once this function is called, the cloud file selector will be shown in a new float window.
There are 4 supported file types which you can use in the type
field
Type Key | Selectable Items |
---|---|
file | Files only |
folder | Folders only |
all | File or folder |
new | Create new file, require options.defaultName to be filled |
Here is an example usage
//Options are optional values
let options = {
defaultName: "newfile.txt", //Default filename used in new operation
fnameOverride: "myfunction", //For those defined with window.myfunction / or script with type="module"
filter: ["mp3","aac","ogg","flac","wav"] //File extension filter
}
//Handler function to process the selected files
function fileSelected(filedata){
for (var i=0; i < filedata.length; i++){
var filename = filedata[i].filename;
var filepath = filedata[i].filepath;
//Do something here with the selected file
}
}
//Call to the open file selector API
ao_module_openFileSelector(fileSelected, "user:/Desktop", "file", true, options);
selectFiles function allow user to pick a file from their local devices. This will create a native file selector that allow the user to pick a file from their computer. The function return a (list of) files.
openPath allows WebApp to launch a new instance of File Manager and load a preset path. If filename was given, the target file will be highlighted in the File Manager.
File passing in ArozOS is done via hash values in URL. The hash value are encoded array of JSON object with filename and filepath properties. The encoding logic is shown in the example below.
let filedata = [{
"filename": "test.jpg",
"filepath": "user:/Desktop/test.jpg"
}];
let fileHash = encodeURIComponent(JSON.stringify(filedata));
//WebApp embedded pages are requested with something like YourApp/embedded.html#{{fileHash_here}}
loadInputFiles return a list of files passed by other modules (mostly File Manager or Application Launcher). The returned value will have the identical structure as a standard ArozOS file passing file data. Here is an example of such structure.
[
{
"filename": "test.jpg",
"filepath": "user:/Desktop/test.jpg"
},
{
"filename": "test2.jpg",
"filepath": "user:/Desktop/test2.jpg"
}
];
If there are no file passing hash found, the function return null
.
File upload in ArozOS is a bit complex as ArozOS is designed to support low end devices with little hardware resources. If possible, please try to avoid handling uploading large files in your WebApp and use the File Manager instead.
uploadFile handle small files upload using xhr requests.
Parameter | Usage | Example / Return Value |
---|---|---|
file | The file object to upload (type File ) |
|
targetPath | The target virtual path for uploading this file | user:/Desktop/ |
callback | Callback function on upload completed | Return the upload target response, usually “ok” |
progressCallback | Callback function on progress change | function displayProgress(completePercentage){console.log(completePercentage + "% uploaded")} |
failedcallback | Callback function on upload failed | Return status code of xhr request |
It is generally not recommend your WebApp to handle any kind of large file upload as this might effect system stability when using with low power hardware. However, if you have specific use case, it is still possible for developers to develop a system that allow files larger than RAM size to be uploaded.
When a large file is required to upload through your WebApp, you can use the websocket upload method. The steps for uploading via websocket works as followings.
You can make a websocket request to /system/file_system/lowmemUpload
and upload chunks of files in sequence. Here is an example code for details implementation.
/*
Low Memory Upload Mode
Assume the file you want to upload is stored in "file" object
*/
var uploadFileChunkSize = 1024 * 512; //512KB per chunk in low memory upload
var largeFileCutoffSize = 8192 * 1024 * 1024; //Any file larger than this size is consider "large file", default to 8GB
var filename = encodeURIComponent(file.name);
var filesize = file.size;
//Open the websocket
let path = "user:/Desktop";
let protocol = "wss://";
if (location.protocol !== 'https:') {
protocol = "ws://";
}
var port = window.location.port;
if (window.location.port == "") {
if (location.protocol !== 'https:') {
port = "80";
} else {
port = "443";
}
}
let uploadDir = "user:/Desktop";
//Fixing Firefox path issues on or above FF48.0
if (isFirefox && file.webkitRelativePath != "") {
//Use the webkitRelativePath instead of the name, this is a folder upload
let pathinfo = file.webkitRelativePath.split("/");
pathinfo.pop();
let subpath = pathinfo.join("/");
uploadDir = uploadDir + subpath;
}
let hugeFileMode = "";
if (file.size > largeFileCutoffSize) {
//Filesize over cutoff line. Use huge file mode
hugeFileMode = "&hugefile=true";
}
let socket = new WebSocket(protocol + window.location.hostname + ":" + port + "/system/file_system/lowmemUpload?filename=" + filename + "&path=" + uploadDir + hugeFileMode);
let currentSendingIndex = 0;
let chunks = Math.ceil(file.size / uploadFileChunkSize, uploadFileChunkSize);
//Define a function for sending a particular chunk
function sendChunk(id, uploadingIconUUID) {
let offsetStart = id * uploadFileChunkSize;
let offsetEnd = id * uploadFileChunkSize + uploadFileChunkSize;
let thisblob = file.slice(offsetStart, offsetEnd);
socket.send(thisblob);
//Update progress to first percentage
let progress = id / (chunks - 1) * 100.0;
if (progress > 100) {
progress = 100;
}
console.log("Uploading " + progress + "%");
}
//Start sending
socket.onopen = function(e) {
//Send the first chunk
sendChunk(0, uploadingIconUUID);
currentSendingIndex++;
};
socket.onmessage = function(event) {
//Append to the send index
var incomingValue = event.data;
if (incomingValue == "next") {
if (currentSendingIndex == chunks + 1) {
//Already finished
socket.send("done");
} else {
//Send next chunk
sendChunk(currentSendingIndex, uploadingIconUUID);
currentSendingIndex++;
}
} else if (incomingValue == "OK") {
//Merge completed
} else {
//Try to parse it as JSON
try {
var resp = JSON.parse(incomingValue.split('\\' + '"').join("\""));
console.log(resp);
if (resp.error !== undefined) {
//This is an error message
console.log("Upload Failed", resp.error);
}
} catch (ex) {
//Something else
console.log(incomingValue);
console.log(ex);
}
}
};
socket.onclose = function(event) {
//Upload completed
alert("upload completed");
};
socket.onerror = function(error) {
console.log(error.message);
//Do something to handle the upload fail
};
ao_module_codec
was used during the ArOZ Online Beta (AOB) era to handle cross frame unicode file passing issues. If you are trying to migrate a module from AOB to ArozOS, please remove all of the usages of these functions.
ao_module_codec.decodeUmFilename(umfilename_here);
ao_module_codec.encodeUMFilename("test.stl");
ao_module_codec.decodeHexFoldername(hexFolderName_here);
ao_module_codec.encodeHexFoldername("test");
From ArozOS v1.0 onward, the core was developed with UTF-8 support. Hence, these functions are no longer required.