mirror of
https://github.com/osnr/TabFS.git
synced 2024-05-13 19:16:34 +02:00
embed-files: draw the tab dir files on all pages
This commit is contained in:
parent
1dd5136415
commit
08d2b5d1d4
|
@ -166,6 +166,52 @@ const routeWithContents = (function() {
|
||||||
return routeWithContents;
|
return routeWithContents;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// Returns a 'writable directory' object; its routeForRoot and
|
||||||
|
// routeForFilename properties can be wired up as routes to create a
|
||||||
|
// generally writable folder.
|
||||||
|
function createWritableDirectory() {
|
||||||
|
const dir = {}; // Map<Path, {content: String, x, y}>
|
||||||
|
return {
|
||||||
|
directory: dir,
|
||||||
|
routeForRoot: {
|
||||||
|
usage: 'ls $0',
|
||||||
|
async readdir({path}) {
|
||||||
|
// filter out keys not from this path prefix,
|
||||||
|
// get just last component of keys (filename)
|
||||||
|
return { entries: [".", "..",
|
||||||
|
...Object.keys(dir)
|
||||||
|
.filter(key => key.startsWith(path))
|
||||||
|
.map(key => key.substr(key.lastIndexOf("/") + 1))] };
|
||||||
|
},
|
||||||
|
getattr() {
|
||||||
|
return {
|
||||||
|
st_mode: unix.S_IFDIR | 0777, // writable so you can create/rm evals
|
||||||
|
st_nlink: 3,
|
||||||
|
st_size: 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
routeForFilename: {
|
||||||
|
usage: ['echo "2 + 2" > $0',
|
||||||
|
'cat $0.result'],
|
||||||
|
|
||||||
|
async mknod({path, mode}) {
|
||||||
|
dir[path] = '';
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
async unlink({path}) {
|
||||||
|
delete dir[path];
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
|
||||||
|
...routeWithContents(
|
||||||
|
async ({path}) => dir[path],
|
||||||
|
async ({path}, buf) => { dir[path] = buf; }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function routeDirectoryForChildren(path) {
|
function routeDirectoryForChildren(path) {
|
||||||
function depth(p) { return p === '/' ? 0 : (p.match(/\//g) || []).length; }
|
function depth(p) { return p === '/' ? 0 : (p.match(/\//g) || []).length; }
|
||||||
|
|
||||||
|
@ -234,6 +280,8 @@ Routes["/tabs/by-id"] = {
|
||||||
|
|
||||||
const tabIdDirectory = createWritableDirectory();
|
const tabIdDirectory = createWritableDirectory();
|
||||||
Routes["/tabs/by-id/#TAB_ID"] = routeDefer(() => {
|
Routes["/tabs/by-id/#TAB_ID"] = routeDefer(() => {
|
||||||
|
// we deferred construction of this route so that we have all the
|
||||||
|
// children to enumerate by now.
|
||||||
const childrenRoute = routeDirectoryForChildren("/tabs/by-id/#TAB_ID");
|
const childrenRoute = routeDirectoryForChildren("/tabs/by-id/#TAB_ID");
|
||||||
return {
|
return {
|
||||||
...tabIdDirectory.routeForRoot, // so getattr is inherited
|
...tabIdDirectory.routeForRoot, // so getattr is inherited
|
||||||
|
@ -250,17 +298,7 @@ Routes["/tabs/by-id/#TAB_ID"] = routeDefer(() => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
Routes["/tabs/by-id/#TAB_ID/:FILENAME"] = {
|
Routes["/tabs/by-id/#TAB_ID/:FILENAME"] = tabIdDirectory.routeForFilename;
|
||||||
...tabIdDirectory.routeForFilename,
|
|
||||||
async mknod(req) {
|
|
||||||
const ret = tabIdDirectory.routeForFilename.mknod(req);
|
|
||||||
// TODO: put icon on page
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// TODO: can I trigger 1. nav to Finder and 2. nav to Terminal from toolbar click?
|
|
||||||
// TODO: how can i let them drag files in?
|
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
const routeForTab = (readHandler, writeHandler) => routeWithContents(async ({tabId}) => {
|
const routeForTab = (readHandler, writeHandler) => routeWithContents(async ({tabId}) => {
|
||||||
|
@ -305,49 +343,6 @@ Routes["/tabs/by-id/#TAB_ID/:FILENAME"] = {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
function createWritableDirectory() {
|
|
||||||
const dir = {};
|
|
||||||
return {
|
|
||||||
directory: dir,
|
|
||||||
routeForRoot: {
|
|
||||||
usage: 'ls $0',
|
|
||||||
async readdir({path}) {
|
|
||||||
// get just last component of keys (filename)
|
|
||||||
return { entries: [".", "..",
|
|
||||||
...Object.keys(dir).map(
|
|
||||||
key => key.substr(key.lastIndexOf("/") + 1)
|
|
||||||
)] };
|
|
||||||
},
|
|
||||||
getattr() {
|
|
||||||
return {
|
|
||||||
st_mode: unix.S_IFDIR | 0777, // writable so you can create/rm evals
|
|
||||||
st_nlink: 3,
|
|
||||||
st_size: 0,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
routeForFilename: {
|
|
||||||
usage: ['echo "2 + 2" > $0',
|
|
||||||
'cat $0.result'],
|
|
||||||
|
|
||||||
async mknod({path, mode}) {
|
|
||||||
dir[path] = '';
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
async unlink({path}) {
|
|
||||||
delete dir[path];
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
|
|
||||||
...routeWithContents(
|
|
||||||
async ({path}) => dir[path],
|
|
||||||
async ({path}, buf) => { dir[path] = buf; }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
const evals = createWritableDirectory();
|
const evals = createWritableDirectory();
|
||||||
Routes["/tabs/by-id/#TAB_ID/evals"] = evals.routeForRoot;
|
Routes["/tabs/by-id/#TAB_ID/evals"] = evals.routeForRoot;
|
||||||
|
|
|
@ -1,6 +1,27 @@
|
||||||
// Content script that injects a file manager into tabs.
|
if (chrome.extension.getBackgroundPage) {
|
||||||
|
// When running in background script:
|
||||||
|
// 'Server' that manages the files for all tabs.
|
||||||
|
|
||||||
document.body.insertAdjacentHTML('beforeend', `
|
// TODO: can I trigger 1. nav to Finder and 2. nav to Terminal from toolbar click?
|
||||||
|
// accept requests from the page
|
||||||
|
|
||||||
|
browser.runtime.onMessage.addListener(async (request, sender) => {
|
||||||
|
const {entries} = await Routes["/tabs/by-id/#TAB_ID"].readdir({path: `/tabs/by-id/${sender.tab.id}`});
|
||||||
|
return entries;
|
||||||
|
});
|
||||||
|
|
||||||
|
// send the file list to the page
|
||||||
|
|
||||||
|
// receive events from the page of
|
||||||
|
// they dragged a new file in,
|
||||||
|
// or they moved a file,
|
||||||
|
// or they double-clicked a file
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// When running in page:
|
||||||
|
// Content script that injects a file manager into the page.
|
||||||
|
|
||||||
|
document.body.insertAdjacentHTML('beforeend', `
|
||||||
<style>
|
<style>
|
||||||
.--tabfs-file-container .--tabfs-file {
|
.--tabfs-file-container .--tabfs-file {
|
||||||
/* fixed makes sense if it's a property of the tab; */
|
/* fixed makes sense if it's a property of the tab; */
|
||||||
|
@ -17,84 +38,90 @@ document.body.insertAdjacentHTML('beforeend', `
|
||||||
<div class="--tabfs-file-container">
|
<div class="--tabfs-file-container">
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
const container = document.getElementsByClassName('--tabfs-file-container')[0];
|
const container = document.getElementsByClassName('--tabfs-file-container')[0];
|
||||||
|
|
||||||
const icons = {};
|
const icons = {};
|
||||||
|
|
||||||
let frontierX = 0, frontierY = 0;
|
let frontierX = 0, frontierY = 0;
|
||||||
function addFile(name, x, y, file) {
|
const addFile = function(name, x, y, file) {
|
||||||
if (!x) {
|
// TODO: report into the extension
|
||||||
x = frontierX; frontierX += 64;
|
|
||||||
y = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
container.insertAdjacentHTML('beforeend', `
|
if (!x) {
|
||||||
|
x = frontierX; frontierX += 64;
|
||||||
|
y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
container.insertAdjacentHTML('beforeend', `
|
||||||
<div class="--tabfs-file">${name}</div>
|
<div class="--tabfs-file">${name}</div>
|
||||||
`);
|
`);
|
||||||
const icon = container.lastElementChild;
|
const icon = container.lastElementChild;
|
||||||
icon.style.left = `${x}px`; icon.style.top = `${y}px`;
|
icon.style.left = `${x}px`; icon.style.top = `${y}px`;
|
||||||
|
|
||||||
// from https://htmldom.dev/make-a-draggable-element/:
|
// from https://htmldom.dev/make-a-draggable-element/:
|
||||||
|
|
||||||
// The current position of mouse
|
// The current position of mouse
|
||||||
let mouseX = 0;
|
let mouseX = 0;
|
||||||
let mouseY = 0;
|
let mouseY = 0;
|
||||||
|
|
||||||
// Handle the mousedown event
|
// Handle the mousedown event
|
||||||
// that's triggered when user drags the element
|
// that's triggered when user drags the element
|
||||||
const mouseDownHandler = function(e) {
|
const mouseDownHandler = function(e) {
|
||||||
// Get the current mouse position
|
// Get the current mouse position
|
||||||
mouseX = e.clientX;
|
mouseX = e.clientX;
|
||||||
mouseY = e.clientY;
|
mouseY = e.clientY;
|
||||||
|
|
||||||
// Attach the listeners to `document`
|
// Attach the listeners to `document`
|
||||||
document.addEventListener('mousemove', mouseMoveHandler);
|
document.addEventListener('mousemove', mouseMoveHandler);
|
||||||
document.addEventListener('mouseup', mouseUpHandler);
|
document.addEventListener('mouseup', mouseUpHandler);
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
const mouseMoveHandler = function(e) {
|
||||||
|
// How far the mouse has been moved
|
||||||
|
const dx = e.clientX - mouseX;
|
||||||
|
const dy = e.clientY - mouseY;
|
||||||
|
|
||||||
|
// Set the position of element
|
||||||
|
icon.style.top = `${icon.offsetTop + dy}px`;
|
||||||
|
icon.style.left = `${icon.offsetLeft + dx}px`;
|
||||||
|
|
||||||
|
// Reassign the position of mouse
|
||||||
|
mouseX = e.clientX;
|
||||||
|
mouseY = e.clientY;
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
const mouseUpHandler = function() {
|
||||||
|
// Remove the handlers of `mousemove` and `mouseup`
|
||||||
|
document.removeEventListener('mousemove', mouseMoveHandler);
|
||||||
|
document.removeEventListener('mouseup', mouseUpHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
icon.addEventListener('mousedown', mouseDownHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ask for what the files are
|
||||||
|
chrome.runtime.sendMessage({hello: 'hello'}, function(response) {
|
||||||
|
response.forEach(name => addFile(name));
|
||||||
|
});
|
||||||
|
|
||||||
|
document.body.addEventListener('dragenter', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
};
|
});
|
||||||
|
document.body.addEventListener('dragover', function(e) {
|
||||||
const mouseMoveHandler = function(e) {
|
|
||||||
// How far the mouse has been moved
|
|
||||||
const dx = e.clientX - mouseX;
|
|
||||||
const dy = e.clientY - mouseY;
|
|
||||||
|
|
||||||
// Set the position of element
|
|
||||||
icon.style.top = `${icon.offsetTop + dy}px`;
|
|
||||||
icon.style.left = `${icon.offsetLeft + dx}px`;
|
|
||||||
|
|
||||||
// Reassign the position of mouse
|
|
||||||
mouseX = e.clientX;
|
|
||||||
mouseY = e.clientY;
|
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
};
|
});
|
||||||
|
document.body.addEventListener('dragleave', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
const mouseUpHandler = function() {
|
document.body.addEventListener('drop', function(e) {
|
||||||
// Remove the handlers of `mousemove` and `mouseup`
|
// bubble thing
|
||||||
document.removeEventListener('mousemove', mouseMoveHandler);
|
e.preventDefault(); // stops browser nav to that file
|
||||||
document.removeEventListener('mouseup', mouseUpHandler);
|
for (let file of [...e.dataTransfer.files]) {
|
||||||
};
|
addFile(file.name, e.clientX, e.clientY, file);
|
||||||
|
}
|
||||||
icon.addEventListener('mousedown', mouseDownHandler);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
['a.js', 'b.html', 'c.js'].forEach(name => addFile(name));
|
|
||||||
|
|
||||||
document.body.addEventListener('dragenter', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
});
|
|
||||||
document.body.addEventListener('dragover', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
});
|
|
||||||
document.body.addEventListener('dragleave', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
document.body.addEventListener('drop', function(e) {
|
|
||||||
// bubble thing
|
|
||||||
e.preventDefault(); // stops browser nav to that file
|
|
||||||
for (let file of [...e.dataTransfer.files]) {
|
|
||||||
addFile(file.name, e.clientX, e.clientY, file);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
|
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
|
||||||
|
|
||||||
"background": {
|
"background": {
|
||||||
"scripts": ["vendor/browser-polyfill.js", "background.js"],
|
"scripts": ["vendor/browser-polyfill.js", "background.js", "embed-files.js"],
|
||||||
"persistent": true
|
"persistent": true
|
||||||
},
|
},
|
||||||
"content_scripts": [{
|
"content_scripts": [{
|
||||||
|
|
Loading…
Reference in a new issue