toc merged

This commit is contained in:
Galen Wolfe-Pauly 2015-08-05 17:27:00 -07:00
commit 348bc1b0a2
15 changed files with 381 additions and 490 deletions

View File

@ -16,7 +16,6 @@
::
++ json-front
|= a=json ^- json
=< ?~(. [%b |] .) :: XX overloaded nulls
=- (fall `(unit json)`- ~)
%+ biff ((ar some):jo a)
%+ find-in-tree (ot c/(ar some) gn/so ga/(om so) ~):jo

View File

@ -23,6 +23,7 @@ which is normalized and type-checked(request types are `%t` text, `%r` html-deri
- `[%kids query]`, the only recursive value, which executes for all subpaths
XX descent is only currently supported to a single level as a performance optimization
- `[%name %t]`, the node name
- `[%path %t]`, the current path
- `[%snip %r]`, a snippet, extracted via `react-snip-json`
- `[%head %r]`, the first header, extracted via `react-head-json`
- `[%body %r]`, the `react-json` body

View File

@ -229,7 +229,7 @@ li:before {
transition: opacity 1s ease-in-out;
z-index: 4;
}
#nav > div > div {
#nav .links > div {
display: inline-block;
vertical-align: top;
}

View File

@ -156,7 +156,7 @@ li:before
transition opacity 1s ease-in-out
z-index 4
#nav > div > div
#nav .links > div
display inline-block
vertical-align top
@ -391,4 +391,4 @@ div.toc
.error
color rgba(249,23,51,1)
@import 'mobile'
@import 'mobile'

View File

@ -21,35 +21,14 @@ module.exports =
path:path
kids:kids
getPath: (path,query) ->
sendQuery: (path,query) ->
return unless query?
if path.slice(-1) is "/" then path = path.slice(0,-1)
if typeof query is 'string'
query={ # XX unify
body: {
body:'r'
kids:
name:'t'
}
kids: {
kids:
name:'t'
body:'r'
}
snip: {
kids:
name:'t'
snip:'r'
head:'r'
meta:'j'
}
}[query]
TreePersistence.get path,query,(err,res) =>
switch
when query.kids?.snip then @loadSnip path,res.kids
when query.kids?.body then @loadKids path,res.kids
when query.kids?.head then @loadSnip path,res.kids
else @loadPath path,res.body,res.kids
setCurr: (path) ->

View File

@ -1,5 +1,7 @@
clas = require 'classnames'
BodyComponent = React.createFactory require './BodyComponent.coffee'
reactify = React.createFactory require './Reactify.coffee'
query = require './Async.coffee'
TreeStore = require '../stores/TreeStore.coffee'
TreeActions = require '../actions/TreeActions.coffee'
@ -7,88 +9,61 @@ TreeActions = require '../actions/TreeActions.coffee'
recl = React.createClass
{div,a} = React.DOM
module.exports = recl
Links = React.createFactory query {
path:'t'
kids:
name:'t'
head:'r'
meta:'j'
}, (recl
# {curr:'t',prev:'t,next:'t',onClick:'f'}
displayName: "Links"
render: -> div {className:'links'}, @props.children, @_render()
_render: ->
keys = _(@props.kids).keys().sort()
style = {marginTop: -24 * (keys.indexOf @props.curr) + "px"}
div {id:"sibs",style}, keys.map (key) =>
href = window.tree.basepath @props.path+"/"+key
data = @props.kids[key]
head = data.meta.title if data.meta
head ?= @toText data.head
head ||= key
className = clas active: key is @props.curr
(div {className,key}, (a {href,onClick:@props.onClick}, head))
toText: (elem)-> switch
# manx: {fork: ["string", {gn:"string" ga:{dict:"string"} c:{list:"manx"}}]}
when !elem? then ""
when typeof elem == "string" then elem
when elem.gn? then (elem.c ? []).map(@toText).join ""
else throw "Bad react-json #{JSON.stringify elem}"
), recl
displayName: "Links_loading"
render: -> div {className:'links'}, @props.children, @_render()
_render: -> div {id:"sibs"}, div {className:"active"}, a {}, @props.curr
module.exports = query {sein:'t',path:'t',name:'t',next:'t',prev:'t'},recl
displayName: "Anchor"
stateFromStore: ->
{
path:TreeStore.getCurr()
pare:TreeStore.getPare()
sibs:TreeStore.getSiblings()
snip:TreeStore.getSnip()
next:TreeStore.getNext()
prev:TreeStore.getPrev()
cont:TreeStore.getCont()
url:window.location.pathname
}
getInitialState: -> url: window.location.pathname
onClick: -> @toggleFocus()
onMouseOver: -> @toggleFocus true
onMouseOut: -> @toggleFocus false
onTouchStart: -> @ts = Number Date.now()
onTouchEnd: -> dt = @ts - Number Date.now()
toggleFocus: (state) ->
$(@getDOMNode()).toggleClass 'focus',state
_click: -> @toggleFocus()
_mouseOver: -> @toggleFocus true
_mouseOut: -> @toggleFocus false
_touchStart: ->
@ts = Number Date.now()
_touchEnd: ->
dt = @ts - Number Date.now()
setPath: (href,hist) ->
href_parts = href.split("#")
next = href_parts[0]
if next.substr(-1) is "/" then next = next.slice(0,-1)
href_parts[0] = next
if hist isnt false
history.pushState {}, "", window.tree.basepath href_parts.join ""
if next isnt @state.path
React.unmountComponentAtNode $('#cont')[0]
TreeActions.setCurr next
React.render (BodyComponent {}, ""),$('#cont')[0]
goTo: (path) ->
@toggleFocus false
$("html,body").animate {scrollTop:0}
@setPath path
checkURL: ->
if @state.url isnt window.location.pathname
@setPath (window.tree.fragpath window.location.pathname),false
setTitle: ->
title = $('#cont h1').first().text()
if title.length is 0
path = @state.path.split("/")
title = path[path.length-1]
document.title = "#{title} - #{@state.path}"
checkUp: ->
up = @state.pare ? "/"
if up.slice(-1) is "/" then up = up.slice 0,-1
unless @state.cont[up]? then TreeActions.getPath up, "body"
unless TreeStore.gotSnip(up) then TreeActions.getPath up, "snip"
componentDidUpdate: ->
@setTitle()
@checkUp()
toggleFocus: (state) -> $(@getDOMNode()).toggleClass 'focus',state
componentDidUpdate: -> @setTitle()
componentWillUnmount: -> clearInterval @interval; $('body').off 'click', 'a'
componentDidMount: ->
TreeStore.addChangeListener @_onChangeStore
@setTitle()
@checkUp()
@interval = setInterval @checkURL,100
$('body').on 'keyup', (e) =>
switch e.keyCode
when 37 then @goTo @state.prev # left
when 39 then @goTo @state.next # right
when 37 then @goTo @props.prev # left
when 39 then @goTo @props.next # right
$('body').on 'click', 'a', (e) =>
href = $(e.target).closest('a').attr('href')
@ -97,60 +72,50 @@ module.exports = recl
e.stopPropagation()
@goTo window.tree.fragpath href
componentWillUnmount: ->
clearInterval @interval
$('body').off 'click', 'a'
setTitle: ->
title = $('#cont h1').first().text() || @props.name
document.title = "#{title} - #{@props.path}"
getInitialState: -> @stateFromStore()
setPath: (href,hist) ->
href_parts = href.split("#")
next = href_parts[0]
if next.substr(-1) is "/" then next = next.slice(0,-1)
href_parts[0] = next
if hist isnt false
history.pushState {}, "", window.tree.basepath href_parts.join ""
if next isnt @props.path
React.unmountComponentAtNode $('#cont')[0]
TreeActions.setCurr next
React.render (BodyComponent {}, ""),$('#cont')[0]
_onChangeStore: -> @setState @stateFromStore()
goTo: (path) ->
@toggleFocus false
$("html,body").animate {scrollTop:0}
@setPath path
checkURL: ->
if @state.url isnt window.location.pathname
@setPath (window.tree.fragpath window.location.pathname),false
@setState url: window.location.pathname
renderArrow: (name, path) ->
href = window.tree.basepath path
(a {href,key:"arow-#{name}",className:"arow-#{name}"},"")
toText: (elem)-> $(React.renderToStaticMarkup reactify manx: elem).text()
renderParts: -> [
if @state.pare then _.filter [
div {id:"up",key:"up"}, @renderArrow "up", @state.pare
if @state.prev or @state.next
div {id:"sides",key:"sides"}, _.filter [
if @state.prev then @renderArrow "prev", @state.prev
if @state.next then @renderArrow "next", @state.next
] ]
if _.keys(@state.sibs).length > 0
[up..., curr] = @state.path.split "/"
up = up.join "/"
ci=0
k=0
_sibs = _(@state.sibs).keys().sort().map (i) =>
if curr is i
className = "active"
ci = k
className ?= ""
k++
path = up+"/"+i
href = window.tree.basepath path
snip = @state.snip[path]
head = snip?.meta?.title
head ?= @toText snip?.head if snip?.head
head ||= i
(div {className,key:i}, (a {href,onClick:@_click}, head))
style = {marginTop:"#{-24*ci}px"}
div {key:"sibs",id:"sibs",style}, _sibs
]
render: ->
obj =
onMouseOver:@_mouseOver
onMouseOut:@_mouseOut
onClick:@_click
onTouchStart:@_touchStart
onTouchEnd:@_touchEnd
obj = {@onMouseOver,@onMouseOut,@onClick,@onTouchStart,@onTouchEnd}
if _.keys(window).indexOf("ontouchstart") isnt -1
delete obj.onMouseOver
delete obj.onMouseOut
div obj, _.filter @renderParts()
div obj, Links {
@onClick
curr:@props.name
dataPath:@props.sein
}, if @props.sein then _.filter [
div {id:"up",key:"up"}, @renderArrow "up", @props.sein
if @props.prev or @props.next then _.filter [
div {id:"sides",key:"sides"},
if @props.prev then @renderArrow "prev", @props.prev
if @props.next then @renderArrow "next", @props.next
] ]

View File

@ -1,4 +1,4 @@
load = React.createFactory require './LoadComponent.coffee'
_load = require './LoadComponent.coffee'
TreeStore = require '../stores/TreeStore.coffee'
TreeActions = require '../actions/TreeActions.coffee'
@ -6,25 +6,36 @@ TreeActions = require '../actions/TreeActions.coffee'
recl = React.createClass
{div,span,code} = React.DOM
module.exports = (queries, Child)-> recl
module.exports = (queries, Child, load=_load)-> recl
displayName: "Async"
stateFromStore: ->
path= @props.dataPath ? TreeStore.getCurr()
{path,got: TreeStore.fulfill path, queries}
getInitialState: -> @stateFromStore()
_onChangeStore: ->
@setState @stateFromStore()
getPath: -> @props.dataPath ? TreeStore.getCurr()
stateFromStore: -> got: TreeStore.fulfill @getPath(), queries
componentDidMount: ->
TreeStore.addChangeListener @_onChangeStore
@checkPath()
componentWillUnmount: ->
TreeStore.removeChangeListener @_onChangeStore
componentDidUpdate: (_props,_state) -> @checkPath()
componentDidUpdate: (_props,_state) ->
if _props isnt @props
@setState @stateFromStore()
@checkPath()
checkPath: -> TreeActions.sendQuery @getPath(), @filterQueries()
filterQueries: -> @filterWith @state.got, queries
filterWith: (have,_queries)->
return _queries unless have?
request = {}
for k of _queries
request[k] = _queries[k] unless have[k]?
request[k] = _queries[k] unless have[k] isnt undefined
if _queries.kids? and have.kids?
if _.isEmpty have.kids
request.kids = _queries.kids
@ -35,16 +46,10 @@ module.exports = (queries, Child)-> recl
if _.isEmpty request.kids
delete request.kids
request unless _.isEmpty request
checkPath: -> TreeActions.getPath @state.path, @filterQueries()
getInitialState: -> @stateFromStore()
_onChangeStore: ->
@setState @stateFromStore()
render: -> div {},
#span {}, JSON.stringify @filterQueries()
if @filterQueries()?
(div {className:"loading"}, (load {}, ""))
React.createElement load, @props
else React.createElement Child,
(_.merge @props, @state.got),
@props.children
(_.merge {}, @props, @state.got),
@props.children

View File

@ -4,7 +4,7 @@ query = require './Async.coffee'
recl = React.createClass
{div,a,ul,li,hr} = React.DOM
module.exports = query {kids: body:'r'},recl
module.exports = query {kids: body:'r'}, recl
displayName: "Kids"
render: -> div {className:"kids"},
for v in _.keys(@props.kids).sort()

View File

@ -28,7 +28,7 @@ module.exports = query {
path = @props.path+"/"+item
elem = @props.kids[item]
href = window.tree.basepath path
li {className:@props.dataType ? ""},
li {key:item,className:@props.dataType ? ""},
a {href,className:(clas preview: @props.dataPreview?)},
if not @props.dataPreview? then (h1 {},item)
else if @props.dataType is 'post'
@ -41,4 +41,4 @@ module.exports = query {
gn: 'div'
c: [head, (elem.snip.c.slice 0,2)...]
else if @props.titlesOnly? then reactify elem.head
else [(reactify elem.head), (reactify elem.snip)]
else div {}, (reactify elem.head), (reactify elem.snip)

View File

@ -1,7 +1,7 @@
recl = React.createClass
{div,input,textarea} = React.DOM
module.exports = recl
module.exports = recl
displayName: "Load"
getInitialState: -> {anim: 0}
@ -14,5 +14,5 @@ module.exports = recl
if anim > 3 then anim = 0
@setState {anim:anim}
render: ->
(div {className:"spin state-#{@state.anim}"}, "")
render: -> (div {className:"loading"},
(div {className:"spin state-#{@state.anim}"}, ""))

View File

@ -17,12 +17,12 @@ components =
module.exports = recl
displayName: "Virtual"
render: -> @walk @props.manx
walk: (obj,key) -> switch
walk: (elem,key) -> switch
# manx: {fork: ["string", {gn:"string" ga:{dict:"string"} c:{list:"manx"}}]}
when !obj? then (span {className:"loading"}, (load {}, ""))
when typeof obj == "string" then obj
when obj.gn?
React.createElement components[obj.gn] ? obj.gn,
$.extend {key}, obj.ga
obj.c.map @walk
else throw "Bad react-json #{JSON.stringify obj}"
when !elem? then (load {}, "")
when typeof elem == "string" then elem
when elem.gn?
React.createElement components[elem.gn] ? elem.gn,
$.extend {key}, elem.ga
elem.c?.map @walk
else throw "Bad react-json #{JSON.stringify elem}"

View File

@ -1,13 +1,7 @@
clas = require 'classnames'
TreeStore = require '../stores/TreeStore.coffee'
TreeActions = require '../actions/TreeActions.coffee'
load = React.createFactory require './LoadComponent.coffee'
reactify = (manx)-> React.createElement window.tree.reactify, {manx}
recl = React.createClass
[div,a,ul,li,] = [React.DOM.div,React.DOM.a,React.DOM.ul,React.DOM.li,React.DOM.h1]
{div} = React.DOM
module.exports = recl
hash:null
@ -20,12 +14,15 @@ module.exports = recl
_onChangeStore: ->
@setState @stateFromStore()
_onChangeStore: -> @setState tocs: @compute()
_click: (e) ->
document.location.hash = @urlsafe $(e.target).text()
urlsafe: (str) -> str.toLowerCase().replace(/\ /g, "-")
componentDidMount: ->
urlsafe: (str) ->
str.toLowerCase().replace(/\ /g, "-").replace(/[^a-z0-9~_.-]/g,"")
componentDidMount: ->
TreeStore.addChangeListener @_onChangeStore
@int = setInterval @checkHash,100
@st = $(window).scrollTop()
$(window).on 'scroll',@checkScroll
@ -63,7 +60,7 @@ module.exports = recl
TreeStore.removeChangeListener @_onChangeStore
clearInterval @int
getInitialState: -> @stateFromStore()
getInitialState: -> tocs: @compute()
gotPath: -> TreeStore.gotSnip(@state.path)
@ -81,4 +78,4 @@ module.exports = recl
if v.gn is 'div' and v.ga?.id is "toc"
return {gn:"div", ga:{className:"toc",onClick:@_click}, c:@collectHeaders(v.c)}
render: -> reactify @parseHeaders()
render: -> reactify @parseHeaders()

View File

@ -28,45 +28,21 @@ module.exports = {
kids: kids
});
},
getPath: function(path, query) {
sendQuery: function(path, query) {
if (query == null) {
return;
}
if (path.slice(-1) === "/") {
path = path.slice(0, -1);
}
if (typeof query === 'string') {
query = {
body: {
body: 'r',
kids: {
name: 't'
}
},
kids: {
kids: {
name: 't',
body: 'r'
}
},
snip: {
kids: {
name: 't',
snip: 'r',
head: 'r',
meta: 'j'
}
}
}[query];
}
return TreePersistence.get(path, query, (function(_this) {
return function(err, res) {
var ref, ref1;
switch (false) {
case !((ref = query.kids) != null ? ref.snip : void 0):
return _this.loadSnip(path, res.kids);
case !((ref1 = query.kids) != null ? ref1.body : void 0):
case !((ref = query.kids) != null ? ref.body : void 0):
return _this.loadKids(path, res.kids);
case !((ref1 = query.kids) != null ? ref1.head : void 0):
return _this.loadSnip(path, res.kids);
default:
return _this.loadPath(path, res.body, res.kids);
}
@ -84,12 +60,13 @@ module.exports = {
},{"../dispatcher/Dispatcher.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/dispatcher/Dispatcher.coffee","../persistence/TreePersistence.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/persistence/TreePersistence.coffee"}],"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/components/AnchorComponent.coffee":[function(require,module,exports){
var BodyComponent, TreeActions, TreeStore, a, div, reactify, recl, ref,
slice = [].slice;
var BodyComponent, Links, TreeActions, TreeStore, a, clas, div, query, recl, ref;
clas = require('classnames');
BodyComponent = React.createFactory(require('./BodyComponent.coffee'));
reactify = React.createFactory(require('./Reactify.coffee'));
query = require('./Async.coffee');
TreeStore = require('../stores/TreeStore.coffee');
@ -99,106 +76,132 @@ recl = React.createClass;
ref = React.DOM, div = ref.div, a = ref.a;
module.exports = recl({
Links = React.createFactory(query({
path: 't',
kids: {
name: 't',
head: 'r',
meta: 'j'
}
}, recl({
displayName: "Links",
render: function() {
return div({
className: 'links'
}, this.props.children, this._render());
},
_render: function() {
var keys, style;
keys = _(this.props.kids).keys().sort();
style = {
marginTop: -24 * (keys.indexOf(this.props.curr)) + "px"
};
return div({
id: "sibs",
style: style
}, keys.map((function(_this) {
return function(key) {
var className, data, head, href;
href = window.tree.basepath(_this.props.path + "/" + key);
data = _this.props.kids[key];
if (data.meta) {
head = data.meta.title;
}
if (head == null) {
head = _this.toText(data.head);
}
head || (head = key);
className = clas({
active: key === _this.props.curr
});
return div({
className: className,
key: key
}, a({
href: href,
onClick: _this.props.onClick
}, head));
};
})(this)));
},
toText: function(elem) {
var ref1;
switch (false) {
case !(elem == null):
return "";
case typeof elem !== "string":
return elem;
case elem.gn == null:
return ((ref1 = elem.c) != null ? ref1 : []).map(this.toText).join("");
default:
throw "Bad react-json " + (JSON.stringify(elem));
}
}
}), recl({
displayName: "Links_loading",
render: function() {
return div({
className: 'links'
}, this.props.children, this._render());
},
_render: function() {
return div({
id: "sibs"
}, div({
className: "active"
}, a({}, this.props.curr)));
}
})));
module.exports = query({
sein: 't',
path: 't',
name: 't',
next: 't',
prev: 't'
}, recl({
displayName: "Anchor",
stateFromStore: function() {
getInitialState: function() {
return {
path: TreeStore.getCurr(),
pare: TreeStore.getPare(),
sibs: TreeStore.getSiblings(),
snip: TreeStore.getSnip(),
next: TreeStore.getNext(),
prev: TreeStore.getPrev(),
cont: TreeStore.getCont(),
url: window.location.pathname
};
},
onClick: function() {
return this.toggleFocus();
},
onMouseOver: function() {
return this.toggleFocus(true);
},
onMouseOut: function() {
return this.toggleFocus(false);
},
onTouchStart: function() {
return this.ts = Number(Date.now());
},
onTouchEnd: function() {
var dt;
return dt = this.ts - Number(Date.now());
},
toggleFocus: function(state) {
return $(this.getDOMNode()).toggleClass('focus', state);
},
_click: function() {
return this.toggleFocus();
},
_mouseOver: function() {
return this.toggleFocus(true);
},
_mouseOut: function() {
return this.toggleFocus(false);
},
_touchStart: function() {
return this.ts = Number(Date.now());
},
_touchEnd: function() {
var dt;
return dt = this.ts - Number(Date.now());
},
setPath: function(href, hist) {
var href_parts, next;
href_parts = href.split("#");
next = href_parts[0];
if (next.substr(-1) === "/") {
next = next.slice(0, -1);
}
href_parts[0] = next;
if (hist !== false) {
history.pushState({}, "", window.tree.basepath(href_parts.join("")));
}
if (next !== this.state.path) {
React.unmountComponentAtNode($('#cont')[0]);
TreeActions.setCurr(next);
return React.render(BodyComponent({}, ""), $('#cont')[0]);
}
},
goTo: function(path) {
this.toggleFocus(false);
$("html,body").animate({
scrollTop: 0
});
return this.setPath(path);
},
checkURL: function() {
if (this.state.url !== window.location.pathname) {
return this.setPath(window.tree.fragpath(window.location.pathname), false);
}
},
setTitle: function() {
var path, title;
title = $('#cont h1').first().text();
if (title.length === 0) {
path = this.state.path.split("/");
title = path[path.length - 1];
}
return document.title = title + " - " + this.state.path;
},
checkUp: function() {
var ref1, up;
up = (ref1 = this.state.pare) != null ? ref1 : "/";
if (up.slice(-1) === "/") {
up = up.slice(0, -1);
}
if (this.state.cont[up] == null) {
TreeActions.getPath(up, "body");
}
if (!TreeStore.gotSnip(up)) {
return TreeActions.getPath(up, "snip");
}
},
componentDidUpdate: function() {
this.setTitle();
return this.checkUp();
return this.setTitle();
},
componentWillUnmount: function() {
clearInterval(this.interval);
return $('body').off('click', 'a');
},
componentDidMount: function() {
TreeStore.addChangeListener(this._onChangeStore);
this.setTitle();
this.checkUp();
this.interval = setInterval(this.checkURL, 100);
$('body').on('keyup', (function(_this) {
return function(e) {
switch (e.keyCode) {
case 37:
return _this.goTo(_this.state.prev);
return _this.goTo(_this.props.prev);
case 39:
return _this.goTo(_this.state.next);
return _this.goTo(_this.props.next);
}
};
})(this));
@ -214,15 +217,42 @@ module.exports = recl({
};
})(this));
},
componentWillUnmount: function() {
clearInterval(this.interval);
return $('body').off('click', 'a');
setTitle: function() {
var title;
title = $('#cont h1').first().text() || this.props.name;
return document.title = title + " - " + this.props.path;
},
getInitialState: function() {
return this.stateFromStore();
setPath: function(href, hist) {
var href_parts, next;
href_parts = href.split("#");
next = href_parts[0];
if (next.substr(-1) === "/") {
next = next.slice(0, -1);
}
href_parts[0] = next;
if (hist !== false) {
history.pushState({}, "", window.tree.basepath(href_parts.join("")));
}
if (next !== this.props.path) {
React.unmountComponentAtNode($('#cont')[0]);
TreeActions.setCurr(next);
return React.render(BodyComponent({}, ""), $('#cont')[0]);
}
},
_onChangeStore: function() {
return this.setState(this.stateFromStore());
goTo: function(path) {
this.toggleFocus(false);
$("html,body").animate({
scrollTop: 0
});
return this.setPath(path);
},
checkURL: function() {
if (this.state.url !== window.location.pathname) {
this.setPath(window.tree.fragpath(window.location.pathname), false);
return this.setState({
url: window.location.pathname
});
}
},
renderArrow: function(name, path) {
var href;
@ -233,83 +263,43 @@ module.exports = recl({
className: "arow-" + name
}, "");
},
toText: function(elem) {
return $(React.renderToStaticMarkup(reactify({
manx: elem
}))).text();
},
renderParts: function() {
var _sibs, ci, curr, j, k, ref1, style, up;
return [
this.state.pare ? _.filter([
div({
id: "up",
key: "up"
}, this.renderArrow("up", this.state.pare)), this.state.prev || this.state.next ? div({
id: "sides",
key: "sides"
}, _.filter([this.state.prev ? this.renderArrow("prev", this.state.prev) : void 0, this.state.next ? this.renderArrow("next", this.state.next) : void 0])) : void 0
]) : void 0, _.keys(this.state.sibs).length > 0 ? ((ref1 = this.state.path.split("/"), up = 2 <= ref1.length ? slice.call(ref1, 0, j = ref1.length - 1) : (j = 0, []), curr = ref1[j++], ref1), up = up.join("/"), ci = 0, k = 0, _sibs = _(this.state.sibs).keys().sort().map((function(_this) {
return function(i) {
var className, head, href, path, ref2, snip;
if (curr === i) {
className = "active";
ci = k;
}
if (className == null) {
className = "";
}
k++;
path = up + "/" + i;
href = window.tree.basepath(path);
snip = _this.state.snip[path];
head = snip != null ? (ref2 = snip.meta) != null ? ref2.title : void 0 : void 0;
if (snip != null ? snip.head : void 0) {
if (head == null) {
head = _this.toText(snip != null ? snip.head : void 0);
}
}
head || (head = i);
return div({
className: className,
key: i
}, a({
href: href,
onClick: _this._click
}, head));
};
})(this)), style = {
marginTop: (-24 * ci) + "px"
}, div({
key: "sibs",
id: "sibs",
style: style
}, _sibs)) : void 0
];
},
render: function() {
var obj;
obj = {
onMouseOver: this._mouseOver,
onMouseOut: this._mouseOut,
onClick: this._click,
onTouchStart: this._touchStart,
onTouchEnd: this._touchEnd
onMouseOver: this.onMouseOver,
onMouseOut: this.onMouseOut,
onClick: this.onClick,
onTouchStart: this.onTouchStart,
onTouchEnd: this.onTouchEnd
};
if (_.keys(window).indexOf("ontouchstart") !== -1) {
delete obj.onMouseOver;
delete obj.onMouseOut;
}
return div(obj, _.filter(this.renderParts()));
return div(obj, Links({
onClick: this.onClick,
curr: this.props.name,
dataPath: this.props.sein
}, this.props.sein ? _.filter([
div({
id: "up",
key: "up"
}, this.renderArrow("up", this.props.sein)), this.props.prev || this.props.next ? _.filter([
div({
id: "sides",
key: "sides"
}, this.props.prev ? this.renderArrow("prev", this.props.prev) : void 0, this.props.next ? this.renderArrow("next", this.props.next) : void 0)
]) : void 0
]) : void 0));
}
});
}));
},{"../actions/TreeActions.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/actions/TreeActions.coffee","../stores/TreeStore.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/stores/TreeStore.coffee","./BodyComponent.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/components/BodyComponent.coffee","./Reactify.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/components/Reactify.coffee"}],"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/components/Async.coffee":[function(require,module,exports){
var TreeActions, TreeStore, code, div, load, recl, ref, span;
},{"../actions/TreeActions.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/actions/TreeActions.coffee","../stores/TreeStore.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/stores/TreeStore.coffee","./Async.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/components/Async.coffee","./BodyComponent.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/components/BodyComponent.coffee","classnames":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/node_modules/classnames/index.js"}],"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/components/Async.coffee":[function(require,module,exports){
var TreeActions, TreeStore, _load, code, div, recl, ref, span;
load = React.createFactory(require('./LoadComponent.coffee'));
_load = require('./LoadComponent.coffee');
TreeStore = require('../stores/TreeStore.coffee');
@ -319,15 +309,25 @@ recl = React.createClass;
ref = React.DOM, div = ref.div, span = ref.span, code = ref.code;
module.exports = function(queries, Child) {
module.exports = function(queries, Child, load) {
if (load == null) {
load = _load;
}
return recl({
displayName: "Async",
getInitialState: function() {
return this.stateFromStore();
},
_onChangeStore: function() {
return this.setState(this.stateFromStore());
},
getPath: function() {
var ref1;
return (ref1 = this.props.dataPath) != null ? ref1 : TreeStore.getCurr();
},
stateFromStore: function() {
var path, ref1;
path = (ref1 = this.props.dataPath) != null ? ref1 : TreeStore.getCurr();
return {
path: path,
got: TreeStore.fulfill(path, queries)
got: TreeStore.fulfill(this.getPath(), queries)
};
},
componentDidMount: function() {
@ -338,8 +338,14 @@ module.exports = function(queries, Child) {
return TreeStore.removeChangeListener(this._onChangeStore);
},
componentDidUpdate: function(_props, _state) {
if (_props !== this.props) {
this.setState(this.stateFromStore());
}
return this.checkPath();
},
checkPath: function() {
return TreeActions.sendQuery(this.getPath(), this.filterQueries());
},
filterQueries: function() {
return this.filterWith(this.state.got, queries);
},
@ -350,7 +356,7 @@ module.exports = function(queries, Child) {
}
request = {};
for (k in _queries) {
if (have[k] == null) {
if (have[k] === void 0) {
request[k] = _queries[k];
}
}
@ -373,19 +379,8 @@ module.exports = function(queries, Child) {
return request;
}
},
checkPath: function() {
return TreeActions.getPath(this.state.path, this.filterQueries());
},
getInitialState: function() {
return this.stateFromStore();
},
_onChangeStore: function() {
return this.setState(this.stateFromStore());
},
render: function() {
return div({}, this.filterQueries() != null ? div({
className: "loading"
}, load({}, "")) : React.createElement(Child, _.merge(this.props, this.state.got), this.props.children));
return div({}, this.filterQueries() != null ? React.createElement(load, this.props) : React.createElement(Child, _.merge({}, this.props, this.state.got), this.props.children));
}
});
};
@ -539,6 +534,7 @@ module.exports = query({
elem = this.props.kids[item];
href = window.tree.basepath(path);
results.push(li({
key: item,
className: (ref1 = this.props.dataType) != null ? ref1 : ""
}, a({
href: href,
@ -551,7 +547,7 @@ module.exports = query({
} : elem.head, reactify({
gn: 'div',
c: [head].concat(slice.call(elem.snip.c.slice(0, 2)))
})) : this.props.titlesOnly != null ? reactify(elem.head) : [reactify(elem.head), reactify(elem.snip)])));
})) : this.props.titlesOnly != null ? reactify(elem.head) : div({}, reactify(elem.head), reactify(elem.snip)))));
}
return results;
}
@ -591,8 +587,10 @@ module.exports = recl({
},
render: function() {
return div({
className: "loading"
}, div({
className: "spin state-" + this.state.anim
}, "");
}, ""));
}
});
@ -634,21 +632,19 @@ module.exports = recl({
render: function() {
return this.walk(this.props.manx);
},
walk: function(obj, key) {
var ref1;
walk: function(elem, key) {
var ref1, ref2;
switch (false) {
case !(obj == null):
return span({
className: "loading"
}, load({}, ""));
case typeof obj !== "string":
return obj;
case obj.gn == null:
return React.createElement((ref1 = components[obj.gn]) != null ? ref1 : obj.gn, $.extend({
case !(elem == null):
return load({}, "");
case typeof elem !== "string":
return elem;
case elem.gn == null:
return React.createElement((ref1 = components[elem.gn]) != null ? ref1 : elem.gn, $.extend({
key: key
}, obj.ga), obj.c.map(this.walk));
}, elem.ga), (ref2 = elem.c) != null ? ref2.map(this.walk) : void 0);
default:
throw "Bad react-json " + (JSON.stringify(obj));
throw "Bad react-json " + (JSON.stringify(elem));
}
}
});
@ -656,25 +652,13 @@ module.exports = recl({
},{"./CodeMirror.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/components/CodeMirror.coffee","./KidsComponent.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/components/KidsComponent.coffee","./ListComponent.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/components/ListComponent.coffee","./LoadComponent.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/components/LoadComponent.coffee","./TocComponent.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/components/TocComponent.coffee"}],"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/components/TocComponent.coffee":[function(require,module,exports){
var TreeActions, TreeStore, a, clas, div, li, load, reactify, recl, ref, ul;
clas = require('classnames');
var TreeStore, div, recl;
TreeStore = require('../stores/TreeStore.coffee');
TreeActions = require('../actions/TreeActions.coffee');
load = React.createFactory(require('./LoadComponent.coffee'));
reactify = function(manx) {
return React.createElement(window.tree.reactify, {
manx: manx
});
};
recl = React.createClass;
ref = [React.DOM.div, React.DOM.a, React.DOM.ul, React.DOM.li, React.DOM.h1], div = ref[0], a = ref[1], ul = ref[2], li = ref[3];
div = React.DOM.div;
module.exports = recl({
hash: null,
@ -687,28 +671,34 @@ module.exports = recl({
_onChangeStore: function() {
return this.setState(this.stateFromStore());
},
_onChangeStore: function() {
return this.setState({
tocs: this.compute()
});
},
_click: function(e) {
return document.location.hash = this.urlsafe($(e.target).text());
},
urlsafe: function(str) {
return str.toLowerCase().replace(/\ /g, "-");
return str.toLowerCase().replace(/\ /g, "-").replace(/[^a-z0-9~_.-]/g, "");
},
componentDidMount: function() {
TreeStore.addChangeListener(this._onChangeStore);
this.int = setInterval(this.checkHash, 100);
this.st = $(window).scrollTop();
$(window).on('scroll', this.checkScroll);
return this.$headers = $('#toc h1, #toc h2, #toc h3, #toc h4');
},
checkScroll: function() {
var $h, hash, hst, k, ref1, results, st, v;
var $h, hash, hst, k, ref, results, st, v;
st = $(window).scrollTop();
if (Math.abs(this.st - st) > 10) {
hash = null;
this.st = st;
ref1 = this.$headers;
ref = this.$headers;
results = [];
for (k in ref1) {
v = ref1[k];
for (k in ref) {
v = ref[k];
if (v.tagName === void 0) {
continue;
}
@ -729,13 +719,13 @@ module.exports = recl({
}
},
checkHash: function() {
var $h, hash, k, offset, ref1, ref2, results, v;
if (((ref1 = document.location.hash) != null ? ref1.length : void 0) > 0 && document.location.hash !== this.hash) {
var $h, hash, k, offset, ref, ref1, results, v;
if (((ref = document.location.hash) != null ? ref.length : void 0) > 0 && document.location.hash !== this.hash) {
hash = document.location.hash.slice(1);
ref2 = this.$headers;
ref1 = this.$headers;
results = [];
for (k in ref2) {
v = ref2[k];
for (k in ref1) {
v = ref1[k];
$h = $(v);
if (hash === this.urlsafe($h.text())) {
this.hash = document.location.hash;
@ -756,7 +746,9 @@ module.exports = recl({
return clearInterval(this.int);
},
getInitialState: function() {
return this.stateFromStore();
return {
tocs: this.compute()
};
},
gotPath: function() {
return TreeStore.gotSnip(this.state.path);
@ -784,12 +776,12 @@ module.exports = recl({
return hs;
},
parseHeaders: function() {
var k, ref1, ref2, v;
var k, ref, ref1, v;
if (this.state.body.c) {
ref1 = this.state.body.c;
for (k in ref1) {
v = ref1[k];
if (v.gn === 'div' && ((ref2 = v.ga) != null ? ref2.id : void 0) === "toc") {
ref = this.state.body.c;
for (k in ref) {
v = ref[k];
if (v.gn === 'div' && ((ref1 = v.ga) != null ? ref1.id : void 0) === "toc") {
return {
gn: "div",
ga: {
@ -809,7 +801,7 @@ module.exports = recl({
},{"../actions/TreeActions.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/actions/TreeActions.coffee","../stores/TreeStore.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/stores/TreeStore.coffee","./LoadComponent.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/components/LoadComponent.coffee","classnames":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/node_modules/classnames/index.js"}],"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/dispatcher/Dispatcher.coffee":[function(require,module,exports){
},{"../stores/TreeStore.coffee":"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/stores/TreeStore.coffee"}],"/Users/galen/src/urbit-dev/urb/zod/pub/tree/src/js/dispatcher/Dispatcher.coffee":[function(require,module,exports){
var Dispatcher;
Dispatcher = require('flux').Dispatcher;
@ -1406,7 +1398,7 @@ EventEmitter = require('events').EventEmitter;
MessageDispatcher = require('../dispatcher/Dispatcher.coffee');
clog = console.log;
clog = console.log.bind(console);
_tree = {};
@ -1431,39 +1423,6 @@ TreeStore = _.extend(EventEmitter.prototype, {
pathToArr: function(_path) {
return _path.split("/");
},
filterQuery: function(query) {
return this.filterWith(this.fulfill(_curr, query), query);
},
filterWith: function(have, query) {
var _query, k, kid, ref;
if (have == null) {
return query;
}
_query = {};
for (k in query) {
if (have[k] == null) {
_query[k] = query[k];
}
}
if ((query.kids != null) && (have.kids != null)) {
if (_.isEmpty(have.kids)) {
_query.kids = query.kids;
} else {
_query.kids = {};
ref = have.kids;
for (k in ref) {
kid = ref[k];
_.merge(_query.kids, this.filterWith(kid, query.kids));
}
if (_.isEmpty(_query.kids)) {
delete _query.kids;
}
}
}
if (!_.isEmpty(_query)) {
return _query;
}
},
fulfill: function(path, query) {
var data, i, k, len, ref, ref1, ref2, ref3;
data = this.fulfillLocal(path, query);

View File

@ -1,7 +1,7 @@
EventEmitter = require('events').EventEmitter
MessageDispatcher = require '../dispatcher/Dispatcher.coffee'
clog = console.log
clog = console.log.bind(console)
_tree = {}
_cont = {}
@ -16,23 +16,6 @@ TreeStore = _.extend EventEmitter.prototype, {
emitChange: -> @emit 'change'
pathToArr: (_path) -> _path.split "/"
filterQuery: (query)-> @filterWith (@fulfill _curr, query), query
filterWith: (have,query)->
return query unless have?
_query = {}
for k of query
_query[k] = query[k] unless have[k]?
if query.kids? and have.kids?
if _.isEmpty have.kids
_query.kids = query.kids
else
_query.kids = {}
for k,kid of have.kids
_.merge _query.kids, @filterWith kid, query.kids
if _.isEmpty _query.kids
delete _query.kids
_query unless _.isEmpty _query
fulfill: (path,query)->
data = @fulfillLocal path, query
@ -96,6 +79,7 @@ TreeStore = _.extend EventEmitter.prototype, {
{gn:'div', c:[
{gn:'pre', c:[@getCurr()]}
{gn:'span', c:['is either empty or does not exist.']}
# {gn:'list'} XX handle empty snip
] }]
_got_snip[path] = true

View File

@ -20,6 +20,7 @@
++ query
$% [%kids p=(list query)]
[%name %t]
[%path %t]
[%snip %r]
[%head %r]
[%body %r]
@ -49,6 +50,7 @@
:- -.a
?- -.a
%name (from-type +.a ?^(s.bem i.s.bem q.bem))
%path (from-type +.a (crip (spud (flop s.bem))))
%head (from-type +.a head.dat)
%snip (from-type +.a snip.dat)
%meta (from-type +.a meta.dat)