Storage MVC using dependency injection
Storage Data Model
Based on back end storage model at
storage.types.ts
interface IFile {
Name: string;
id?: string;
Extension?: string;
FileSizeBytes?: Number;
IsTextFile?: boolean;
fullPath?: string;
ModifiedDate?: Date;
Contents?: string;
metadata?: Object;
}
interface IFolder {
Name: string;
id?: string;
FileCount?: Number;
ModifiedDate?: Date;
fullPath?: string;
}
interface IStorage {
Parent?: IFolder | string;
Home?: IFolder;
File?: IFile;
Files: IFile[];
Folders: IFolder[];
}
<file-browser>
Description
Web view component based on https://github.com/ServiceStack/ServiceStack.Examples/tree/master/src/RestFiles/RestFiles
Converted to Web Component in Typescript
Seperation of Concerns
https://en.wikipedia.org/wiki/Separation_of_concerns
Communication to backend separated out for dependency injection and frontend controller based on backend model created
interface ISnapshot {
bytesTransferred: number;
totalBytes: number;
}
interface IStorageController {
provider?: string;
folder: IFolder;
Delete(file: IFile, callback: (msg: string) => void);
ListAll(folder: IFolder, callback: (data: IStorage) => void);
MkDir(file: IFolder, callback: (msg: string) => void);
Upload(file: IFile, data: File, callback: (snapshot: ISnapshot) => void);
}
Google Drive and Firebase storage controller implementations
firebase implementation
firebase.storage.controller.ts
google drive impementation
gdrive.storage.controller.ts
Features
jQuery Shadow DOM
var self = this;
$('#fileupload', shadowRoot).fileupload({
dataType: 'json',
replaceFileInput: false,
add: function (e, data) {
data.context = $('<button/>').text('Upload')
.appendTo($('#files', shadowRoot))
.click(function () {
data.context = $('<p/>').text('Uploading...').replaceAll($(this));
data.submit();
});
$.each(data.files, function (index, file) {
var node = $('<p/>').append($('<span/>').text(file.name).data(data));
node.appendTo(data.context);
});
data.url = self.Base + self.href + "?format=json";
console.log(data.url);
},
done: function (e, data) {
data.context.text('Upload finished.');
self.refresh();
},
progressall: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('#progress .bar', shadowRoot).css(
'width',
progress + '%'
);
}
});
Google Signin
import '@google-web-components/google-signin';
googlesignin.addEventListener("google-signin-aware-success", e => {
document.cookie = "id_token=" + e.detail.id_token;
});
<google-signin brand="google" client-id="1054047045356-j8pgqgls9vdef3rl09hapoicumbte0bo.apps.googleusercontent.com">
</google-signin>
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[0.1.2] - 2020-03-19
Coverted
Web Component including necessary modification to jQuery
[0.1.9] 2020-03-24
Selected Row
$("table tr", self.shadowRoot).click(function () {
$(this).addClass('selected').siblings().removeClass('selected');
var value = $(this).find('td:first').children('a').attr("href").replace('#!files','');
let event = new CustomEvent('selected-changed',{detail:value});
self.dispatchEvent(event);
});
#ls TABLE TR.selected {
outline: thin solid black;
}
storage
<filestorage-provider folder='video' accept='text/*,audio/*,video/*,image/*' inputs='input,textarea'>
<div id='custommetadata'>
<div class="item">
<label for='strd'>Start At</label>
<input id='strd' type="date" name='startdate'></label>
</div>
<div class="item">
<label for='expd'>Expire At</label>
<input id='expd' type="date" name='expiredate'>
</div>
<div class="item">
<label for='com'>Comments</label>
<textarea id='com' name="comments" rows="3" cols="50" placeholder="Add comment"></textarea>
</div>
</div>
</filestorage-provider>
clone metadata inputs child node for each upload item
const metadata_template = this.querySelector('#custommetadata');
//metadata template from index.html
const metadata_node = null;
if (metadata_template) metadata_node = metadata_template.cloneNode(true);
else if (this.children[0]) metadata_node = this.children[0].cloneNode(true);
if (metadata_node) file_list_item_container.appendChild(metadata_node);
//
//28 April 2020
if (Object.keys(metadata).length > 0) {
uploadTask = storageRef.child('users/' + user + '/' + this.folder + '/' + file.name).put(file, metadata);
}
//29 April 2020 Create Directory
$('.mkdir .btn', this.shadowRoot).click(() => {
var dir = $('#dirname', this.shadowRoot);
if (!dir.val()) {
alert('Enter the name of the folder first');
dir.focus();
return;
}
var file = new File([dir.val().toString()], 'folder.info', {
type: 'text/plain',
});
var user = firebase.auth().currentUser.uid;
if (!user) return;
var storageRef = firebase.storage().ref();
var self = this;
var uploadTask = storageRef.child('users/' + user + '/' + this.folder + '/' + dir.val() + '/' + file.name).put(file).then(function (snapshot) {
console.log('Uploaded a blob or file!');
// todo refresh file list
self.dispatchEvent(new Event('onchange'));
});
});