diff --git a/README.md b/README.md index 2ae1488..767cb13 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# zine -DIY E-Zine and Operating System +# Zine OS +DIY E-Zine and Operating System Interfaces ----------- +========== FS Interface ------------ @@ -24,14 +24,14 @@ Delete a file at a path, returns a promise that is fulfilled when the delete suc Returns a promise list: (directoryPath) -> - + FileEntry Interface ------------------- +------------------- - path: - size: - type: + path: + size: + type: FolderEntry Interface --------------------- diff --git a/TODO.md b/TODO.md index cfda0b3..7573cd5 100644 --- a/TODO.md +++ b/TODO.md @@ -23,7 +23,7 @@ System Features [ ] Drag 'n' Drop -[ ] Cloud Briefcase +[X] Cloud Briefcase Applications ------------ @@ -55,6 +55,6 @@ Network Social [ ] Sharing -[ ] Remote Files +[ ] Remote Files (Network Neighborhood) -[ ] Personal Homepage +[X] Personal Homepage diff --git a/apps/achievement-status.coffee b/apps/achievement-status.coffee new file mode 100644 index 0000000..b8bd0fd --- /dev/null +++ b/apps/achievement-status.coffee @@ -0,0 +1,15 @@ +module.exports = -> + {Achievement, UI} = system + {Window} = UI + + cheevoElement = Achievement.progressView() + cheevoElement.style.width = "100%" + cheevoElement.style.padding = "1em" + + Achievement.unlock "Check yo' self" + + windowView = Window + title: "Cheevos" + content: cheevoElement + width: 640 + height: 480 diff --git a/apps/audio-bro.coffee b/apps/audio-bro.coffee index ae3e9f8..1fb6679 100644 --- a/apps/audio-bro.coffee +++ b/apps/audio-bro.coffee @@ -5,7 +5,7 @@ Model = require "model" module.exports = -> # Global system - {ContextMenu, MenuBar, Modal, Progress, Util:{parseMenu}, Window} = system.UI + {ContextMenu, MenuBar, Modal, Observable, Progress, Util:{parseMenu}, Window} = system.UI {Achievement} = system Achievement.unlock "Pump up the jam" @@ -14,8 +14,11 @@ module.exports = -> audio.controls = true audio.autoplay = true + filePath = Observable() + handlers = Model().include(FileIO).extend loadFile: (blob) -> + filePath blob.path audio.src = URL.createObjectURL blob exit: -> @@ -31,11 +34,16 @@ module.exports = -> handlers: handlers windowView = Window - title: "Audio Bro" + title: -> + if path = filePath() + "Audio Bro - #{path}" + else + "Audio Bro" content: audio menuBar: menuBar.element width: 308 height: 80 + iconEmoji: "🎶" windowView.loadFile = handlers.loadFile diff --git a/apps/chateau.coffee b/apps/chateau.coffee index 1fc1887..6f9ebfc 100644 --- a/apps/chateau.coffee +++ b/apps/chateau.coffee @@ -8,6 +8,7 @@ module.exports = -> width: 960 height: 540 title: "Chateau" + iconEmoji: "🍷" app.on "event", (name) -> switch name diff --git a/apps/contrasaurus.coffee b/apps/contrasaurus.coffee index f740bed..acc9a2f 100644 --- a/apps/contrasaurus.coffee +++ b/apps/contrasaurus.coffee @@ -1,9 +1,7 @@ -IFrameApp = require "../lib/iframe-app" - module.exports = -> - {Achievement} = system + {Achievement, iframeApp} = system - app = IFrameApp + app = iframeApp src: "https://contrasaur.us/" width: 960 height: 540 diff --git a/apps/dungeon-of-sadness.coffee b/apps/dungeon-of-sadness.coffee index 99123ff..ddaf317 100644 --- a/apps/dungeon-of-sadness.coffee +++ b/apps/dungeon-of-sadness.coffee @@ -1,18 +1,12 @@ -Model = require "model" - module.exports = -> - {ContextMenu, MenuBar, Modal, Observable, Progress, Table, Util:{parseMenu}, Window} = system.UI - - frame = document.createElement "iframe" - frame.src = "https://danielx.net/ld33/" + {Achievement, iframeApp} = system - system.Achievement.unlock "The dungeon is in our heart" - - windowView = Window + app = iframeApp title: "Dungeon of Sadness" - content: frame - menuBar: null + src: "https://danielx.net/ld33/" width: 648 height: 507 - return windowView + Achievement.unlock "The dungeon is in our heart" + + return app diff --git a/apps/explorer.coffee b/apps/explorer.coffee index 07b8136..1b8b9e3 100644 --- a/apps/explorer.coffee +++ b/apps/explorer.coffee @@ -1,8 +1,6 @@ # Explorer File Browser # # Explore the file system like adventureres of old! -# TODO: Drag and drop folders between folders -# TODO: Drop files onto folders # TODO: Drop files onto applications # TODO: Select multiple # TOOD: Keyboard Input @@ -13,21 +11,40 @@ FolderTemplate = require "../templates/folder" {emptyElement} = require "../util" +extractPath = (element) -> + while element + path = element.getAttribute("path") + return path if path + element = element.parentElement + module.exports = Explorer = (options={}) -> {ContextMenu, MenuBar, Modal, Progress, Util:{parseMenu}, Window} = system.UI {path} = options path ?= '/' explorer = document.createElement "explorer" + explorer.setAttribute("path", path) Drop explorer, (e) -> return if e.defaultPrevented + targetPath = extractPath(e.target) or path + folderTarget = targetPath.match(/\/$/) + fileSelectionData = e.dataTransfer.getData("zineos/file-selection") if fileSelectionData data = JSON.parse fileSelectionData - system.moveFileSelection(data, path) + + if folderTarget + system.moveFileSelection(data, targetPath) + else + # Attempt to open file in app + selectedFile = data.files[0] + console.log "Open in app #{targetPath} <- #{selectedFile}" + system.readFile(selectedFile.path) + .then (file) -> + system.execPathWithFile(targetPath, file) e.preventDefault() return @@ -36,9 +53,13 @@ module.exports = Explorer = (options={}) -> if files.length e.preventDefault() - files.forEach (file) -> - newPath = path + file.name - system.writeFile(newPath, file, true) + if folderTarget + files.forEach (file) -> + newPath = targetPath + file.name + system.writeFile(newPath, file, true) + else + file = files[0] + system.execPathWithFile(targetPath, file) explorerContextMenu = ContextMenu items: parseMenu """ @@ -150,10 +171,24 @@ module.exports = Explorer = (options={}) -> handlers: open: -> addWindow(folder.path) - delete: -> # TODO: Delete all files under folder + delete: -> + system.readTree(folder.path) + .then (results) -> + Promise.all results.map (result) -> + system.deleteFile(result.path) rename: -> - ;# TODO: Rename all files under folder (!) - # May want to think about inodes or something that makes this simpler + Modal.prompt "Name", folder.path + .then (newName) -> + return unless newName + + # Ensure trailing slash + newName = newName.replace(/\/*$/, "/") + + system.readTree(folder.path) + .then (files) -> + Promise.all files.map (file) -> + newPath = file.path.replace(folder.path, newName) + system.moveFile(file.path, newPath) properties: -> # TODO contextMenu.display @@ -169,22 +204,25 @@ module.exports = Explorer = (options={}) -> addedFolders = {} files.forEach (file) -> - if file.relativePath.match /\// # folder - folderPath = file.relativePath.replace /\/.*$/, "" + if file.relativePath.match /\/$/ # folder + folderPath = file.relativePath addedFolders[folderPath] = true return - file.dblclick = -> - system.open file + Object.assign file, + displayName: file.relativePath - file.contextmenu = (e) -> - contextMenuFor(file, e) + dblclick: -> + system.open file - file.dragstart = (e) -> - # Note: Blobs don't make it through the stringify - e.dataTransfer.setData "zineos/file-selection", JSON.stringify - sourcePath: path - files: [ file ] + contextmenu: (e) -> + contextMenuFor(file, e) + + dragstart: (e) -> + # Note: Blobs don't make it through the stringify + e.dataTransfer.setData "zineos/file-selection", JSON.stringify + sourcePath: path + files: [ file ] fileElement = FileTemplate file if file.type.match /^image\// @@ -199,15 +237,18 @@ module.exports = Explorer = (options={}) -> Object.keys(addedFolders).reverse().forEach (folderName) -> folder = - path: "#{path}#{folderName}/" + path: "#{path}#{folderName}" relativePath: folderName + displayName: folderName.replace(/\/$/, "") contextmenu: (e) -> contextMenuForFolder(folder, e) dblclick: -> # Open folder in new window addWindow(folder.path) dragstart: (e) -> - console.log e, folder + e.dataTransfer.setData "zineos/file-selection", JSON.stringify + sourcePath: folder.path.slice(0, folder.path.length - folder.relativePath.length) + files: [ folder ] folderElement = FolderTemplate folder explorer.insertBefore(folderElement, explorer.firstChild) @@ -220,9 +261,7 @@ module.exports = Explorer = (options={}) -> system.fs.on "update", (path) -> update() addWindow = (path) -> - element = document.createElement "container" - - element.appendChild Explorer + element = Explorer path: path windowView = Window @@ -231,6 +270,7 @@ module.exports = Explorer = (options={}) -> menuBar: null width: 640 height: 480 + iconEmoji: "📂" document.body.appendChild windowView.element diff --git a/apps/my-briefcase.coffee b/apps/my-briefcase.coffee index 1281005..a9a62b4 100644 --- a/apps/my-briefcase.coffee +++ b/apps/my-briefcase.coffee @@ -6,7 +6,7 @@ This depends on having the AWS library available: This is where you can put the files that you want to access from the cloud. -They'll live in the whims-fs bucket under the path to your aws user id. +They'll live in the whimsy-fs bucket under the path to your aws user id. The subdomain -> s3 proxy will have a map from simple names to the crazy ids. @@ -48,8 +48,11 @@ module.exports = -> system.Achievement.unlock "Oh no, my files!" LoginTemplate = system.compileTemplate """ - a#LoginWithAmazon(@click) - img(border="0" alt="Login with Amazon" src="https://images-na.ssl-images-amazon.com/images/G/01/lwa/btnLWA_gold_156x32.png" width="156" height="32") + span(style="text-align: center; padding: 0 2em;") + h1 My Briefcase + p= @description + a#LoginWithAmazon(@click) + img(border="0" alt="Login with Amazon" src="https://images-na.ssl-images-amazon.com/images/G/01/lwa/btnLWA_gold_156x32.png" width="156" height="32") """ LoadedTemplate = system.compileTemplate """ @@ -119,6 +122,13 @@ module.exports = -> console.warn e, e.message content LoginTemplate + description: -> + """ + Maintain access to your files across different machines. Publish + effortlessly to the internet. Your briefcase holds all of your hopes + and dreams in a magical cloud that is available anywhere there is an + internet connection. 💼 + """ click: -> options = { scope : 'profile' } amazon.Login.authorize options, (resp) -> @@ -141,10 +151,11 @@ module.exports = -> .then receivedCredentials windowView = Window - title: "💼 My Briefcase 💼" + title: "My Briefcase" width: 640 height: 480 content: content + iconEmoji: "💼" return windowView diff --git a/apps/pixel.coffee b/apps/pixel.coffee index afdebbe..120a2ed 100644 --- a/apps/pixel.coffee +++ b/apps/pixel.coffee @@ -1,35 +1,16 @@ -Model = require "model" -Postmaster = require "postmaster" +IFrameApp = require "../lib/iframe-app" FileIO = require "../os/file-io" +Model = require "model" module.exports = -> - {ContextMenu, MenuBar, Modal, Observable, Progress, Table, Util:{parseMenu}, Window} = system.UI - - frame = document.createElement "iframe" - frame.src = "https://danielx.net/pixel-editor/" - - # TODO: Gross hack to keep track of waiting for child window to load - # May want to move it into the postmaster library - resolveLoaded = null - loadedPromise = new Promise (resolve) -> - resolveLoaded = resolve - - postmaster = Postmaster() - postmaster.remoteTarget = -> frame.contentWindow - Object.assign postmaster, - childLoaded: -> - console.log "child loaded" - resolveLoaded() - save: -> - handlers.save() + {MenuBar, Modal, Observable, Util:{parseMenu}} = system.UI handlers = Model().include(FileIO).extend loadFile: (blob) -> - loadedPromise.then -> - postmaster.invokeRemote "loadFile", blob + app.send "loadFile", blob newFile: -> saveData: -> - postmaster.invokeRemote "getBlob" + app.send "getBlob" menuBar = MenuBar items: parseMenu """ @@ -47,15 +28,17 @@ module.exports = -> """ handlers: handlers - windowView = Window + app = IFrameApp title: Observable "Pixie Paint" - content: frame - menuBar: menuBar.element + src: "https://danielx.net/pixel-editor/" + menuBar: menuBar + handlers: handlers width: 640 height: 480 - windowView.loadFile = handlers.loadFile + app.handlers = handlers + app.loadFile = handlers.loadFile system.Achievement.unlock "Pixel perfect" - return windowView + return app diff --git a/apps/story-reader.coffee b/apps/story-reader.coffee new file mode 100644 index 0000000..f7cbe2e --- /dev/null +++ b/apps/story-reader.coffee @@ -0,0 +1,16 @@ +module.exports = (opts) -> + {title, width, height, text} = opts + width ?= 380 + height ?= 480 + + div = document.createElement "div" + div.textContent = text + div.style.padding = "1em" + div.style.whiteSpace = "pre-wrap" + div.style.textAlign = "justify" + + system.UI.Window + title: title + content: div + width: width + height: height diff --git a/apps/text-editor.coffee b/apps/text-editor.coffee index bccec4c..6892a23 100644 --- a/apps/text-editor.coffee +++ b/apps/text-editor.coffee @@ -3,11 +3,7 @@ FileIO = require "../os/file-io" ace.require("ace/ext/language_tools") -extraModes = - jadelet: "jade" - -mode = (mode) -> - extraModes[mode] or mode +{extensionFor} = require "../util" module.exports = -> {ContextMenu, MenuBar, Modal, Observable, Progress, Table, Util:{parseMenu}, Window} = system.UI @@ -39,12 +35,6 @@ module.exports = -> global.aceEditor = aceEditor - extensionFor = (path) -> - result = path.match /\.([^.]+)$/ - - if result - result[1] - modes = cson: "coffeescript" jadelet: "jade" @@ -52,14 +42,8 @@ module.exports = -> md: "markdown" styl: "stylus" - mimes = - html: "text/html" - js: "application/javascript" - json: "application/json" - md: "text/markdown" - mimeTypeFor = (path) -> - type = mimes[extensionFor(path)] or "text/plain" + type = system.mimeTypeFor(path) "#{type}; charset=utf-8" diff --git a/extensions.coffee b/extensions.coffee index 962c941..2523543 100644 --- a/extensions.coffee +++ b/extensions.coffee @@ -1,3 +1,9 @@ +# Pretend Hamlet Runtime is a real package +PACKAGE.dependencies["_lib_hamlet-runtime"] = + entryPoint: "main" + distribution: + main: PACKAGE.distribution["lib/hamlet-runtime"] + # Add some utility readers to the Blob API Blob::readAsText = -> file = this diff --git a/issues/2016-12.coffee b/issues/2016-12.coffee index a9497b9..a2abea0 100644 --- a/issues/2016-12.coffee +++ b/issues/2016-12.coffee @@ -44,7 +44,7 @@ module.exports = -> area: issueTag .then (data) -> ajax - url: "https://whimsy-space.gomix.me/comments" + url: "https://whimsy-space.glitch.me/comments" data: JSON.stringify(data) headers: "Content-Type": "application/json" @@ -53,7 +53,7 @@ module.exports = -> handlers.viewComments() viewComments: -> - ajax.getJSON "https://whimsy-space.gomix.me/comments/#{issueTag}" + ajax.getJSON "https://whimsy-space.glitch.me/comments/#{issueTag}" .then (data) -> data = data.reverse() diff --git a/issues/2017-03.coffee b/issues/2017-03.coffee index 00a7bc1..0bcf701 100644 --- a/issues/2017-03.coffee +++ b/issues/2017-03.coffee @@ -48,7 +48,7 @@ module.exports = -> contrasaurus: -> visit "csaur" - document.body.appendChild Contrasaurus(system).element + document.body.appendChild Contrasaurus().element achievementStatus: -> visit "cheevo" diff --git a/issues/2017-04.coffee b/issues/2017-04.coffee new file mode 100644 index 0000000..64abd37 --- /dev/null +++ b/issues/2017-04.coffee @@ -0,0 +1,174 @@ +Model = require "model" +Chateau = require "../apps/chateau" +Contrasaurus = require "../apps/contrasaurus" +PixiePaint = require "../apps/pixel" +Spreadsheet = require "../apps/spreadsheet" +TextEditor = require "../apps/text-editor" +MyBriefcase = require "../apps/my-briefcase" + +Social = require "../social/social" + +{parentElementOfType, emptyElement} = require "../util" + +writeIfNotPresent = (destination, sourceURL) -> + system.readFile destination + .then (file) -> + throw new Error "File not found" unless file + return file + .catch -> + ajax + url: sourceURL + responseType: "blob" + .then (blob) -> + system.writeFile destination, blob + +module.exports = -> + {ContextMenu, MenuBar, Modal, Progress, Util:{parseMenu}, Window} = system.UI + {Achievement, ajax} = system + + visitedAreas = + bikes: false + izzy: false + residue: false + chateau: false + cheevo: false + briefcase: false + podcast: false + + visit = (area) -> + visitedAreas[area] = true + + visitedAll = Object.keys(visitedAreas).every (key) -> + visitedAreas[key] + + if visitedAll + Achievement.unlock "Cover-2-cover 4: Fast & Furious" + + system.writeFile "issue-4/izzy.txt", new Blob [require "../stories/izzy"], type: "text/plain" + system.writeFile "issue-4/residue.txt", new Blob [require "../stories/residue"], type: "text/plain" + + downloadBikes = -> + ["and-yet-they-rode-bikes.md", "infog.png", "lanes.png", "totally-a.html"].forEach (path) -> + filePath = "issue-4/bikes/#{path}" + + writeIfNotPresent filePath, "https://fs.whimsy.space/us-east-1:90fe8dfb-e9d2-45c7-a347-cf840a3e757f/public/bikes/#{path}" + + downloadBikes() + + writeIfNotPresent "issue-4/Funkytown.mp3", "https://fs.whimsy.space/us-east-1:90fe8dfb-e9d2-45c7-a347-cf840a3e757f/public/music/Funkytown.mp3" + .then -> + system.openPath "issue-4/Funkytown.mp3" + + writeIfNotPresent "issue-4/zinecast1.mp3", "https://fs.whimsy.space/us-east-1:90fe8dfb-e9d2-45c7-a347-cf840a3e757f/public/podcasts/zinecast1.mp3" + + system.Achievement.unlock "Issue 4" + + handlers = Model().include(Social).extend + area: -> + "2017-04" + + zinecast1: -> + visit "podcast" + system.readFile "issue-4/zinecast1.mp3" + .then system.open + + bikes: -> + visit "bikes" + system.readFile "issue-4/bikes/and-yet-they-rode-bikes.md" + .then system.open + + chateau: -> + visit "chateau" + app = Chateau(system) + document.body.appendChild app.element + + achievementStatus: -> + visit "cheevo" + cheevoElement = system.Achievement.progressView() + cheevoElement.style.width = "100%" + cheevoElement.style.padding = "1em" + + system.Achievement.unlock "Check yo' self" + + windowView = Window + title: "Cheevos" + content: cheevoElement + width: 640 + height: 480 + + document.body.appendChild windowView.element + + myBriefcase: -> + visit "briefcase" + app = MyBriefcase() + document.body.appendChild app.element + + izzy: -> + Achievement.unlock "Izzy" + visit "izzy" + storyWindow = StoryWindow("Izzy", require("../stories/izzy")) + + document.body.appendChild storyWindow.element + + residue: -> + Achievement.unlock "Residue" + visit "residue" + + storyWindow = StoryWindow("Residue", require("../stories/residue")) + + document.body.appendChild storyWindow.element + + funkytown8bitRemix: -> + system.readFile "issue-4/Funkytown.mp3" + .then system.open + + menuBar = MenuBar + items: parseMenu """ + [A]pps + [C]hateau + My [B]riefcase + [M]usic + [F]unkytown (8-bit Remix) + [Z]inecast 1 + [S]tories + [B]ikes + [I]zzy + [R]esidue + #{Social.menuText} + [H]elp + [A]chievement Status + """ + handlers: handlers + + content = document.createElement "content" + content.style = "width: 100%; height: 100%" + + img = document.createElement "img" + img.src = "https://fs.whimsy.space/us-east-1:90fe8dfb-e9d2-45c7-a347-cf840a3e757f/public/images/708e9398a4b4bea08d7c61ff7a0f863f.gif" + img.style = "width: 100%; height: 100%" + + windowView = Window + title: "ZineOS Volume 1 | Issue 4 | DISCO TECH | April 2017" + content: img + menuBar: menuBar.element + width: 480 + height: 600 + x: 64 + y: 64 + + windowView.element.querySelector('viewport').style.overflow = "initial" + + document.body.appendChild windowView.element + +StoryWindow = (title, text) -> + div = document.createElement "div" + div.textContent = text + div.style.padding = "1em" + div.style.whiteSpace = "pre-wrap" + div.style.textAlign = "justify" + + system.UI.Window + title: title + content: div + width: 380 + height: 480 diff --git a/issues/2017-05.coffee b/issues/2017-05.coffee new file mode 100644 index 0000000..519dc2f --- /dev/null +++ b/issues/2017-05.coffee @@ -0,0 +1,99 @@ +Model = require "model" + +AchievementStatus = require "../apps/achievement-status" +Chateau = require "../apps/chateau" +Contrasaurus = require "../apps/contrasaurus" +PixiePaint = require "../apps/pixel" +Spreadsheet = require "../apps/spreadsheet" +TextEditor = require "../apps/text-editor" +MyBriefcase = require "../apps/my-briefcase" + +StoryReader = require "../apps/story-reader" + +Social = require "../social/social" + +module.exports = -> + {ContextMenu, MenuBar, Modal, Progress, Util:{parseMenu}, Window} = system.UI + {Achievement, ajax} = system + + ggPath = "issue-5/gleep-glorp.m4a" + + system.readFile ggPath + .then (file) -> + throw new Error "File not found" unless file + .catch -> + ajax + url: "https://fs.whimsy.space/us-east-1:90fe8dfb-e9d2-45c7-a347-cf840a3e757f/public/hao/gleep-glorp.m4a" + responseType: "blob" + .then (blob) -> + system.writeFile ggPath, blob + + handlers = Model().include(Social).extend + area: -> + "2017-05" + + achievementStatus: -> + system.launchApp AchievementStatus + + chateau: -> + system.launchApp Chateau + + crescent: -> + app = StoryReader + text: require "../stories/crescent" + title: "Crescent" + + document.body.appendChild app.element + + gleepGlorp: -> + system.openPath ggPath + + marigold: -> + app = StoryReader + text: require "../stories/marigold" + title: "Marigold" + + document.body.appendChild app.element + + myBriefcase: -> + system.launchApp MyBriefcase + + pixiePaint: -> + system.launchApp PixiePaint + + textEditor: -> + system.launchApp TextEditor + + menuBar = MenuBar + items: parseMenu """ + [A]pps + [C]hateau + My [B]riefcase + [P]ixie Paint + [T]ext Editor + [C]ontent + [C]rescent + [G]leep Glorp + [M]arigold + #{Social.menuText} + [H]elp + [A]chievement Status + """ + handlers: handlers + + img = document.createElement "img" + img.src = "https://i.imgur.com/hKOGoex.jpg" + img.style = "width: 100%; height: 100%" + + windowView = Window + title: "ZineOS Volume 1 | Issue 5 | A May Zine | May 2017" + content: img + menuBar: menuBar.element + width: 640 + height: 360 + x: 64 + y: 64 + + windowView.element.querySelector('viewport').style.overflow = "initial" + + document.body.appendChild windowView.element diff --git a/lib/app-drop.coffee b/lib/app-drop.coffee new file mode 100644 index 0000000..500c1cd --- /dev/null +++ b/lib/app-drop.coffee @@ -0,0 +1,35 @@ +Drop = require "./drop" + +# General drop handling for apps +module.exports = (app) -> + {element} = app + + Drop element, (e) -> + {handlers} = app + + fileSelectionData = e.dataTransfer.getData("zineos/file-selection") + + if fileSelectionData + data = JSON.parse(fileSelectionData) + e.preventDefault() + file = data.files[0] + + # TODO: Handle multi-files + path = data.files[0].path + + system.readFile path + .then handlers.loadFile + .then -> + handlers.currentPath path + + return + + files = e.dataTransfer.files + + if files.length + e.preventDefault() + + file = files[0] + handlers.loadFile file + .then -> + handlers.currentPath null diff --git a/lib/dexie-fs.coffee b/lib/dexie-fs.coffee index aeb80b4..1ad5ec4 100644 --- a/lib/dexie-fs.coffee +++ b/lib/dexie-fs.coffee @@ -1,6 +1,11 @@ Bindable = require "bindable" Model = require "model" +FolderEntry = (path, prefix) -> + folder: true + path: prefix + path + relativePath: path + # FS Wrapper to Dexie database module.exports = (db) -> Files = db.files @@ -38,12 +43,23 @@ module.exports = (db) -> Files.delete(path) .then notify "delete", path - # TODO: Collapse folders - # .replace(/\/.*$/, "/") + # List files and folders in a directory list: (dir) -> Files.where("path").startsWith(dir).toArray() .then (files) -> - files.forEach (file) -> + folderPaths = {} + + files = files.filter (file) -> file.relativePath = file.path.replace(dir, "") - return files + if file.relativePath.match /\// # folder + folderPath = file.relativePath.replace /\/.*$/, "/" + folderPaths[folderPath] = true + return + else + return file + + folders = Object.keys(folderPaths).map (folderPath) -> + FolderEntry folderPath, dir + + return folders.concat(files) diff --git a/lib/hamlet.js b/lib/hamlet.js index b18539c..9445320 100644 --- a/lib/hamlet.js +++ b/lib/hamlet.js @@ -2448,4 +2448,4 @@ module.exports={ } },{}]},{},[1])(1) -}); \ No newline at end of file +}); diff --git a/lib/iframe-app.coffee b/lib/iframe-app.coffee index 9f9e1fb..52847de 100644 --- a/lib/iframe-app.coffee +++ b/lib/iframe-app.coffee @@ -3,9 +3,9 @@ Postmaster = require "postmaster" FileIO = require "../os/file-io" module.exports = (opts={}) -> - {ContextMenu, MenuBar, Modal, Observable, Progress, Table, Util:{parseMenu}, Window} = system.UI + {Window} = system.UI - {height, menuBar, src, title, width, sandbox, pkg} = opts + {height, menuBar, src, handlers, title, width, sandbox, pkg, packageOptions, iconEmoji} = opts frame = document.createElement "iframe" @@ -15,18 +15,10 @@ module.exports = (opts={}) -> if src frame.src = src else if pkg - frame.src = URL.createObjectURL new Blob [""" - - - - - -