diff --git a/ape/hood.hoon b/ape/hood.hoon index a4d98398e..ce80d2271 100644 --- a/ape/hood.hoon +++ b/ape/hood.hoon @@ -128,6 +128,7 @@ ++ poke-kiln-unsync (wrap poke-unsync):from-kiln ++ poke-write-paste (wrap poke-paste):from-write ++ poke-write-tree (wrap poke-tree):from-write +++ poke-write-wipe (wrap poke-wipe):from-write ++ poke-will (wrap poke-will):from-helm ++ quit-drum-phat (wrap quit-phat):from-drum ++ reap-drum-phat (wrap reap-phat):from-drum diff --git a/lib/write.hoon b/lib/write.hoon index 05f24d9c1..83013eed7 100644 --- a/lib/write.hoon +++ b/lib/write.hoon @@ -32,9 +32,17 @@ :: pax/(cu deft (su fel:stab)) :: dat/(of json/some mime/(pe / (cu taco so)) ~) :: XX mite :: == +++ poke-wipe + |= sup=spur ^+ abet :: XX determine extension, beak + =+ ext=%md + ?~ (file (tope beak-now [ext sup])) + ~|(not-found/[ext `path`(flop sup)] !!) + =- abet:(emit %info write/~ our -) + (fray (tope beak-now [ext sup])) +:: ++ poke-tree - |= [sup=spur mim=mime] ^+ abet - (poke--data [`%md (flop sup)] %mime mim) :: XX determine extension + |= [sup=spur mim=mime] ^+ abet :: XX determine extension, beak + (poke--data [`%md (flop sup)] %mime mim) :: ++ poke-paste |= [typ=?(%hoon %md %txt) txt=@t] ^+ abet diff --git a/mar/write/paste.hoon b/mar/write/paste.hoon new file mode 100644 index 000000000..10117692b --- /dev/null +++ b/mar/write/paste.hoon @@ -0,0 +1,12 @@ +:: +:::: /hoon/core/save/mar + :: +!: +|_ [typ=?(%hoon %md %txt) txt=@t] +++ grab + |% + ++ noun ,[?(%hoon %md %txt) @t] + ++ json + (corl need =>(jo (ot typ/(ci (soft ?(%hoon %md %txt)) so) txt/so ~))) + -- +-- diff --git a/mar/write/tree.hoon b/mar/write/tree.hoon new file mode 100644 index 000000000..b47fa0925 --- /dev/null +++ b/mar/write/tree.hoon @@ -0,0 +1,13 @@ +:: +:::: /hoon/core/save/mar + :: +!: +|_ [sup=spur mim=mime] +++ grab + |% + ++ noun ,[spur mime] + ++ json + %+ corl need :: XX {pax, mite, octs} + =>(jo (ot sup/(su fel:stab) mime/(cu |=(a=@t [/ (taco a)]) so) ~)) + -- +-- diff --git a/mar/write/wipe.hoon b/mar/write/wipe.hoon new file mode 100644 index 000000000..3106ac9f8 --- /dev/null +++ b/mar/write/wipe.hoon @@ -0,0 +1,11 @@ +:: +:::: /hoon/core/save/mar + :: +!: +|_ spur +++ grab + |% + ++ noun spur + ++ json (corl need (su:jo fel:stab)) + -- +-- diff --git a/pub/tree/src/js/actions/TreeActions.coffee b/pub/tree/src/js/actions/TreeActions.coffee index f4373aeba..8a452f61c 100644 --- a/pub/tree/src/js/actions/TreeActions.coffee +++ b/pub/tree/src/js/actions/TreeActions.coffee @@ -21,3 +21,8 @@ module.exports = TreePersistence.put spur, mime, (err,res)-> if err? then throw err if cb? then cb res + + deleteFile: (spur, cb) -> + TreePersistence.del spur, (err,res)-> + if err? then throw err + if cb? then cb res diff --git a/pub/tree/src/js/components/BodyComponent.coffee b/pub/tree/src/js/components/BodyComponent.coffee index df1ab88da..4d212f152 100644 --- a/pub/tree/src/js/components/BodyComponent.coffee +++ b/pub/tree/src/js/components/BodyComponent.coffee @@ -1,5 +1,6 @@ clas = require 'classnames' +load = require './LoadComponent.coffee' query = require './Async.coffee' reactify = require './Reactify.coffee' codemirror = require './CodeMirror.coffee' @@ -81,11 +82,20 @@ Add = recl else input {type:"text",onKeyDown:(e)=> if 13 is e.keyCode - neu = @getDOMNode().value - newPath = @props.path+"/"+neu + {value} = @getDOMNode() + escp = value.toLowerCase().replace(/[^a-z0-9._~-]+/g, '-') + newPath = @props.path+"/"+escp + newSpur = "/"+escp+@props.spur history.pushState {}, "", window.tree.basepath newPath + "#edit" - TreeActions.saveFile "/"+neu+@props.spur, '', -> - # TreeActions.setCurr newPath + # TreeActions.setCurr newPath # XX indirect through Anchor poll + urb.onupdate = -> # disable autoreload + TreeActions.saveFile newSpur, '# '+value, -> + TreeActions.loadPath newPath, { + spur:newSpur + meta:{} + mime:{mite:"text/x-markdown",octs:'# '+value} + body:{gn:"div",ga:{},c:[{gn:"h1",ga:{},c:[value]}]} + } @setState edit:false } @@ -103,10 +113,14 @@ module.exports = query { @hash = document.location.hash document.location.hash = "#edit" # XX generic state<->hash binding @setState edit:true + urb.onupdate = -> # disable autoreload unsetEdit: -> document.location.hash = @hash ? "" - @setState edit:false document.location.reload() # XX sigh + # @setState edit:false + doDelete: -> + TreeActions.deleteFile @props.spur, => @unsetEdit() + @setState edit:"gone" render: -> className = clas (@props.meta.layout?.split ',') @@ -114,17 +128,20 @@ module.exports = query { extra = (name,props={})=> if @props.meta[name]? then rele extras[name], props - unless @state.edit - body = reactify @props.body - editButton = button {onClick: => @setEdit()}, "Edit" - - else - body = rele Edit, {} - - onClick = => - txt = $(@getDOMNode()).find('.CodeMirror')[0].CodeMirror.getValue() # XX refs - TreeActions.saveFile @props.spur, txt, => @unsetEdit() - editButton = button {onClick}, "Done" + switch @state.edit + when false + body = reactify @props.body + editButton = button {onClick: => @setEdit()}, "Edit" + when "pending", "gone" + body = div {}, rele load, {} + editButton = button {onClick: => @setEdit()}, "Edit" + when true + body = rele Edit, {} + onClick = => + txt = $(@getDOMNode()).find('.CodeMirror')[0].CodeMirror.getValue() # XX refs + TreeActions.saveFile @props.spur, txt, => @unsetEdit() + @setState edit:"pending" + editButton = button {onClick}, "Done" (div { id:'body', @@ -134,6 +151,7 @@ module.exports = query { extra 'spam' extra 'logo', color: @props.meta.logo if own then editButton + if own then button {onClick: => @doDelete()}, "Delete" body extra 'next', {dataPath:@props.sein,curr:@props.name} if own then rele Add,{spur:@props.spur, path:@props.path} diff --git a/pub/tree/src/js/main.js b/pub/tree/src/js/main.js index fb4d8c239..79294ac05 100644 --- a/pub/tree/src/js/main.js +++ b/pub/tree/src/js/main.js @@ -44,6 +44,16 @@ module.exports = { return cb(res); } }); + }, + deleteFile: function(spur, cb) { + return TreePersistence.del(spur, function(err, res) { + if (err != null) { + throw err; + } + if (cb != null) { + return cb(res); + } + }); } }; @@ -443,10 +453,12 @@ module.exports = function(queries, Child, load) { },{"../actions/TreeActions.coffee":1,"../stores/TreeStore.coffee":21,"./LoadComponent.coffee":10}],4:[function(require,module,exports){ -var Add, Edit, TreeActions, a, button, clas, codemirror, div, extras, img, input, p, pre, query, reactify, recl, ref, rele; +var Add, Edit, TreeActions, a, button, clas, codemirror, div, extras, img, input, load, p, pre, query, reactify, recl, ref, rele; clas = require('classnames'); +load = require('./LoadComponent.coffee'); + query = require('./Async.coffee'); reactify = require('./Reactify.coffee'); @@ -583,12 +595,34 @@ Add = recl({ type: "text", onKeyDown: (function(_this) { return function(e) { - var neu, newPath; + var escp, newPath, newSpur, value; if (13 === e.keyCode) { - neu = _this.getDOMNode().value; - newPath = _this.props.path + "/" + neu; + value = _this.getDOMNode().value; + escp = value.toLowerCase().replace(/[^a-z0-9._~-]+/g, '-'); + newPath = _this.props.path + "/" + escp; + newSpur = "/" + escp + _this.props.spur; history.pushState({}, "", window.tree.basepath(newPath + "#edit")); - TreeActions.saveFile("/" + neu + _this.props.spur, '', function() {}); + urb.onupdate = function() {}; + TreeActions.saveFile(newSpur, '# ' + value, function() {}); + TreeActions.loadPath(newPath, { + spur: newSpur, + meta: {}, + mime: { + mite: "text/x-markdown", + octs: '# ' + value + }, + body: { + gn: "div", + ga: {}, + c: [ + { + gn: "h1", + ga: {}, + c: [value] + } + ] + } + }); return _this.setState({ edit: false }); @@ -617,18 +651,26 @@ module.exports = query({ setEdit: function() { this.hash = document.location.hash; document.location.hash = "#edit"; - return this.setState({ + this.setState({ edit: true }); + return urb.onupdate = function() {}; }, unsetEdit: function() { var ref1; document.location.hash = (ref1 = this.hash) != null ? ref1 : ""; - this.setState({ - edit: false - }); return document.location.reload(); }, + doDelete: function() { + TreeActions.deleteFile(this.props.spur, (function(_this) { + return function() { + return _this.unsetEdit(); + }; + })(this)); + return this.setState({ + edit: "gone" + }); + }, render: function() { var body, className, editButton, extra, onClick, own, ref1; className = clas((ref1 = this.props.meta.layout) != null ? ref1.split(',') : void 0); @@ -643,29 +685,45 @@ module.exports = query({ } }; })(this); - if (!this.state.edit) { - body = reactify(this.props.body); - editButton = button({ - onClick: (function(_this) { + switch (this.state.edit) { + case false: + body = reactify(this.props.body); + editButton = button({ + onClick: (function(_this) { + return function() { + return _this.setEdit(); + }; + })(this) + }, "Edit"); + break; + case "pending": + case "gone": + body = div({}, rele(load, {})); + editButton = button({ + onClick: (function(_this) { + return function() { + return _this.setEdit(); + }; + })(this) + }, "Edit"); + break; + case true: + body = rele(Edit, {}); + onClick = (function(_this) { return function() { - return _this.setEdit(); + var txt; + txt = $(_this.getDOMNode()).find('.CodeMirror')[0].CodeMirror.getValue(); + TreeActions.saveFile(_this.props.spur, txt, function() { + return _this.unsetEdit(); + }); + return _this.setState({ + edit: "pending" + }); }; - })(this) - }, "Edit"); - } else { - body = rele(Edit, {}); - onClick = (function(_this) { - return function() { - var txt; - txt = $(_this.getDOMNode()).find('.CodeMirror')[0].CodeMirror.getValue(); - return TreeActions.saveFile(_this.props.spur, txt, function() { - return _this.unsetEdit(); - }); - }; - })(this); - editButton = button({ - onClick: onClick - }, "Done"); + })(this); + editButton = button({ + onClick: onClick + }, "Done"); } return div({ id: 'body', @@ -673,7 +731,13 @@ module.exports = query({ className: className }, extra('spam'), extra('logo', { color: this.props.meta.logo - }), own ? editButton : void 0, body, extra('next', { + }), own ? editButton : void 0, own ? button({ + onClick: (function(_this) { + return function() { + return _this.doDelete(); + }; + })(this) + }, "Delete") : void 0, body, extra('next', { dataPath: this.props.sein, curr: this.props.name }), own ? rele(Add, { @@ -685,7 +749,7 @@ module.exports = query({ -},{"../actions/TreeActions.coffee":1,"./Async.coffee":3,"./CodeMirror.coffee":5,"./Reactify.coffee":11,"classnames":16}],5:[function(require,module,exports){ +},{"../actions/TreeActions.coffee":1,"./Async.coffee":3,"./CodeMirror.coffee":5,"./LoadComponent.coffee":10,"./Reactify.coffee":11,"classnames":16}],5:[function(require,module,exports){ var div, recl, ref, textarea; recl = React.createClass; @@ -2001,14 +2065,20 @@ dedup = {}; if (urb.send) { urb.appl = 'hood'; - urb.send.mark = 'write-tree'; } module.exports = { + del: function(sup, cb) { + return urb.send(sup, { + mark: 'write-wipe' + }, cb); + }, put: function(sup, mime, cb) { return urb.send({ sup: sup, mime: mime + }, { + mark: 'write-tree' }, cb); }, get: function(path, query, cb) { diff --git a/pub/tree/src/js/persistence/TreePersistence.coffee b/pub/tree/src/js/persistence/TreePersistence.coffee index aa61a1269..a0821e9e4 100644 --- a/pub/tree/src/js/persistence/TreePersistence.coffee +++ b/pub/tree/src/js/persistence/TreePersistence.coffee @@ -1,10 +1,10 @@ dedup = {} # XX wrong layer if urb.send urb.appl = 'hood' - urb.send.mark = 'write-tree' module.exports = - put: (sup,mime,cb)-> urb.send {sup,mime},cb + del: (sup,cb)-> urb.send sup,{mark:'write-wipe'}, cb + put: (sup,mime,cb)-> urb.send {sup,mime},{mark:'write-tree'}, cb get: (path,query="no-query",cb) -> url = "#{window.tree.basepath(path)}.json?q=#{@encode query}" diff --git a/tree/hymn.hook b/tree/hymn.hook index 4a5d38e09..dfe7f9ccb 100644 --- a/tree/hymn.hook +++ b/tree/hymn.hook @@ -38,7 +38,8 @@ [;script(type "text/javascript", src "/~/as/own/~/at/home/lib/urb.js");]~ == ;body - ;+ =+ inject=(jobe kids/kids-json body/body.dat ~) + ;+ =+ mime=(jobe mite/[%s (moon p.mime.dat)] octs/[%s q.q.mime.dat] ~) :: XX factor out + =+ inject=(jobe kids/kids-json body/body.dat ?.(aut ~ [mime/mime]~)) ;script(type "text/javascript"): window.tree = {(pojo inject)} ;div#nav; ;div#cont;