This commit is contained in:
C. Guy Yarvin 2015-09-24 16:34:17 -07:00
commit 7488955887
10 changed files with 324 additions and 155 deletions

View File

@ -431,13 +431,14 @@
urb.waspFrom = function(sel,attr){
Array.prototype.map.call(document.querySelectorAll(sel),
function(ele){
if(!ele[attr] || (new URL(ele[attr])).host != document.location.host) return;
if(!ele[attr] || (new URL(ele[attr])).host != document.location.host)
return;
var xhr = new XMLHttpRequest()
xhr.open("HEAD", ele[attr])
xhr.send()
xhr.onload = function(){
var tag = JSON.parse(this.getResponseHeader("etag"))
if(tag) urb.wasp(tag)
var dep = this.getResponseHeader("etag")
if(dep) urb.wasp(JSON.parse(dep.substr(2)))
}})}
if(urb.wasp){urb.waspFrom('script','src'); urb.waspFrom('link','href')}
'''
@ -771,7 +772,7 @@
==
~| q.q.cay
=+ ((hard ,[mit=mite rez=octs]) q.q.cay)
=+ dep=(crip (pojo %s (scot %uv p.sih)))
=+ dep=(crip "W/{(pojo %s (scot %uv p.sih))}")
(give-thou 200 ~[etag/dep content-type/(moon mit)] ~ rez)
==
==

View File

@ -277,7 +277,7 @@ referentially transparent manner.
A `%next` request checks query at the given revision, and it
produces the result of the query the next time it changes, along
with the revsion number when it changes. Thus, a `%next` of a
`%u` is triggered when a file is added or deleted, a `%next of a
`%u` is triggered when a file is added or deleted, a `%next` of a
`%x` is triggered when a file is added, deleted, or changed, and
a `%next` of a `%y` is triggered when a file or any of its
children is added, deleted, or changed.

View File

@ -47,7 +47,7 @@ Links = React.createFactory query {
render: -> div {className:'links'}, @props.children, @_render()
_render: -> div {id:"sibs"}, div {className:"active"}, a {}, @props.curr
CLICK = 'a,h1,h2,h3,h4,h5,h6'
CLICK = 'a' # 'a,h1,h2,h3,h4,h5,h6'
module.exports = query {sein:'t',path:'t',name:'t',next:'t',prev:'t'},recl
displayName: "Anchor"
getInitialState: -> url: window.location.pathname

View File

@ -34,10 +34,10 @@ module.exports = (queries, Child, load=_load)-> recl
filterWith: (have,_queries)->
return _queries unless have?
request = {}
for k of _queries
for k of _queries when k isnt 'kids'
request[k] = _queries[k] unless have[k] isnt undefined
if _queries.kids? and have.kids?
if _.isEmpty have.kids
if _queries.kids?
if not have.kids?
request.kids = _queries.kids
else
request.kids = {}

View File

@ -7,4 +7,5 @@ module.exports =
list: require './ListComponent.coffee'
kids: require './KidsComponent.coffee'
toc: require './TocComponent.coffee'
email: require './EmailComponent.coffee'
lost: recl render: -> (div {}, "<lost(", @props.children, ")>")

View File

@ -0,0 +1,45 @@
reactify = require './Reactify.coffee'
recl = React.createClass
{div,p,button,input} = React.DOM
module.exports = recl
displayName: "email"
getInitialState: -> {submit:false,email:""}
onClick: -> @submit()
onKeyUp: (e) ->
email = @$email.val()
valid = (email.indexOf('@') != -1 &&
email.indexOf('.') != -1 &&
email.length > 7 &&
email.split(".")[1].length > 1 &&
email.split("@")[0].length > 0 &&
email.split("@")[1].length > 4)
@$email.toggleClass 'valid',valid
@$email.removeClass 'error'
if e.keyCode is 13
if valid is true
@submit()
e.stopPropagation()
e.preventDefault()
return false
else
@$email.addClass 'error'
submit: ->
$.post @props.dataPath,{email:@$email.val()},() =>
@setState {submit:true}
componentDidMount: -> @$email = $('input.email')
render: ->
if @state.submit is false
cont = [
(input {key:"field",className:"email",placeholder:"your@email.com",@onKeyUp}, @state.email)
(button {key:"submit",className:"submit",@onClick}, "Submit")
]
else
cont = [(div {className:"submitted"},"Got it. Thanks!")]
(p {className:"email"}, cont)

View File

@ -9,29 +9,26 @@ module.exports = query {body:'r'}, recl
hash:null
displayName: "TableOfContents"
_click: (e) ->
document.location.hash = @urlsafe $(e.target).text()
urlsafe: (str) ->
str.toLowerCase().replace(/\ /g, "-").replace(/[^a-z0-9~_.-]/g,"")
_click: (id)->
-> if id then document.location.hash = id
componentDidMount: ->
@int = setInterval @checkHash,100
@st = $(window).scrollTop()
$(window).on 'scroll',@checkScroll
@$headers = $('#toc h1, #toc h2, #toc h3, #toc h4')
# $(window).on 'scroll',@checkScroll
@$headers = $('#toc').children('h1,h2,h3,h4').filter('[id]')
checkScroll: ->
st = $(window).scrollTop()
if Math.abs(@st-st) > 10
hash = null
@st = st
for k,v of @$headers
for v in @$headers
continue if v.tagName is undefined
$h = $ v
hst = $h.offset().top-$h.outerHeight(true)+10
if hst < st
hash = @urlsafe $h.text()
hash = $h.attr('id')
if hst > st and hash isnt @hash and hash isnt null
@hash = "#"+hash
document.location.hash = hash
@ -40,9 +37,9 @@ module.exports = query {body:'r'}, recl
checkHash: ->
if document.location.hash?.length > 0 and document.location.hash isnt @hash
hash = document.location.hash.slice(1)
for k,v of @$headers
for v in @$headers
$h = $ v
if hash is @urlsafe $h.text()
if hash is $h.attr('id')
@hash = document.location.hash
offset = $h.offset().top - $h.outerHeight(true)
setTimeout -> $(window).scrollTop offset
@ -52,20 +49,23 @@ module.exports = query {body:'r'}, recl
componentWillUnmount: ->
clearInterval @int
collectHeaders: (e) ->
hs = [{gn:"h1", ga:{className:"t"}, c:["Table of contents"]}]
for k,v of e
if not v.gn then continue
if v.gn[0] is 'h' and parseInt(v.gn[1]) isnt NaN
_v = _.clone v
delete _v.ga.id
hs.push v
return hs
collectHeader: ({gn,ga,c})->
if gn and gn[0] is 'h' and parseInt(gn[1]) isnt NaN
ga = _.clone ga
ga.onClick = @_click ga.id
delete ga.id
{gn,ga,c}
parseHeaders: ->
if @props.body.c
for k,v of @props.body.c
for v in @props.body.c
if v.gn is 'div' and v.ga?.id is "toc"
return {gn:"div", ga:{className:"toc",onClick:@_click}, c:@collectHeaders(v.c)}
return {
gn:"div"
ga:{className:"toc"}
c:[
{gn:"h1", ga:{className:"t"}, c:["Table of contents"]}
(_.filter v.c.map @collectHeader)...
]}
render: -> reactify @parseHeaders()
render: -> reactify @parseHeaders()

View File

@ -35,7 +35,8 @@ module.exports = {
};
},{"../dispatcher/Dispatcher.coffee":13,"../persistence/TreePersistence.coffee":19}],2:[function(require,module,exports){
},{"../dispatcher/Dispatcher.coffee":14,"../persistence/TreePersistence.coffee":20}],2:[function(require,module,exports){
var BodyComponent, CLICK, Links, TreeActions, TreeStore, a, clas, div, query, reactify, recl, ref;
clas = require('classnames');
@ -141,7 +142,7 @@ Links = React.createFactory(query({
}
})));
CLICK = 'a,h1,h2,h3,h4,h5,h6';
CLICK = 'a';
module.exports = query({
sein: 't',
@ -288,7 +289,8 @@ module.exports = query({
}));
},{"../actions/TreeActions.coffee":1,"../stores/TreeStore.coffee":20,"./Async.coffee":3,"./BodyComponent.coffee":4,"./Reactify.coffee":10,"classnames":15}],3:[function(require,module,exports){
},{"../actions/TreeActions.coffee":1,"../stores/TreeStore.coffee":21,"./Async.coffee":3,"./BodyComponent.coffee":4,"./Reactify.coffee":11,"classnames":16}],3:[function(require,module,exports){
var TreeActions, TreeStore, _load, code, div, recl, ref, span;
_load = require('./LoadComponent.coffee');
@ -348,12 +350,14 @@ module.exports = function(queries, Child, load) {
}
request = {};
for (k in _queries) {
if (have[k] === void 0) {
request[k] = _queries[k];
if (k !== 'kids') {
if (have[k] === void 0) {
request[k] = _queries[k];
}
}
}
if ((_queries.kids != null) && (have.kids != null)) {
if (_.isEmpty(have.kids)) {
if (_queries.kids != null) {
if (have.kids == null) {
request.kids = _queries.kids;
} else {
request.kids = {};
@ -389,7 +393,8 @@ module.exports = function(queries, Child, load) {
};
},{"../actions/TreeActions.coffee":1,"../stores/TreeStore.coffee":20,"./LoadComponent.coffee":9}],4:[function(require,module,exports){
},{"../actions/TreeActions.coffee":1,"../stores/TreeStore.coffee":21,"./LoadComponent.coffee":10}],4:[function(require,module,exports){
var div, query, reactify, recl;
query = require('./Async.coffee');
@ -414,7 +419,8 @@ module.exports = query({
}));
},{"./Async.coffee":3,"./Reactify.coffee":10}],5:[function(require,module,exports){
},{"./Async.coffee":3,"./Reactify.coffee":11}],5:[function(require,module,exports){
var div, recl, ref, textarea;
recl = React.createClass;
@ -437,6 +443,7 @@ module.exports = recl({
});
},{}],6:[function(require,module,exports){
var div, recl;
@ -450,6 +457,7 @@ module.exports = {
list: require('./ListComponent.coffee'),
kids: require('./KidsComponent.coffee'),
toc: require('./TocComponent.coffee'),
email: require('./EmailComponent.coffee'),
lost: recl({
render: function() {
return div({}, "<lost(", this.props.children, ")>");
@ -458,7 +466,89 @@ module.exports = {
};
},{"./CodeMirror.coffee":5,"./KidsComponent.coffee":7,"./ListComponent.coffee":8,"./SearchComponent.coffee":11,"./TocComponent.coffee":12}],7:[function(require,module,exports){
},{"./CodeMirror.coffee":5,"./EmailComponent.coffee":7,"./KidsComponent.coffee":8,"./ListComponent.coffee":9,"./SearchComponent.coffee":12,"./TocComponent.coffee":13}],7:[function(require,module,exports){
var button, div, input, p, reactify, recl, ref;
reactify = require('./Reactify.coffee');
recl = React.createClass;
ref = React.DOM, div = ref.div, p = ref.p, button = ref.button, input = ref.input;
module.exports = recl({
displayName: "email",
getInitialState: function() {
return {
submit: false,
email: ""
};
},
onClick: function() {
return this.submit();
},
onKeyUp: function(e) {
var email, valid;
email = this.$email.val();
valid = email.indexOf('@') !== -1 && email.indexOf('.') !== -1 && email.length > 7 && email.split(".")[1].length > 1 && email.split("@")[0].length > 0 && email.split("@")[1].length > 4;
this.$email.toggleClass('valid', valid);
this.$email.removeClass('error');
if (e.keyCode === 13) {
if (valid === true) {
this.submit();
e.stopPropagation();
e.preventDefault();
return false;
} else {
return this.$email.addClass('error');
}
}
},
submit: function() {
return $.post(this.props.dataPath, {
email: this.$email.val()
}, (function(_this) {
return function() {
return _this.setState({
submit: true
});
};
})(this));
},
componentDidMount: function() {
return this.$email = $('input.email');
},
render: function() {
var cont;
if (this.state.submit === false) {
cont = [
input({
key: "field",
className: "email",
placeholder: "your@email.com",
onKeyUp: this.onKeyUp
}, this.state.email), button({
key: "submit",
className: "submit",
onClick: this.onClick
}, "Submit")
];
} else {
cont = [
div({
className: "submitted"
}, "Got it. Thanks!")
];
}
return p({
className: "email"
}, cont);
}
});
},{"./Reactify.coffee":11}],8:[function(require,module,exports){
var a, div, hr, li, query, reactify, recl, ref, ul;
reactify = require('./Reactify.coffee');
@ -497,7 +587,8 @@ module.exports = query({
}));
},{"./Async.coffee":3,"./Reactify.coffee":10}],8:[function(require,module,exports){
},{"./Async.coffee":3,"./Reactify.coffee":11}],9:[function(require,module,exports){
var a, clas, div, h1, li, query, reactify, recl, ref, ul;
clas = require('classnames');
@ -592,7 +683,8 @@ module.exports = query({
}));
},{"./Async.coffee":3,"./Reactify.coffee":10,"classnames":15}],9:[function(require,module,exports){
},{"./Async.coffee":3,"./Reactify.coffee":11,"classnames":16}],10:[function(require,module,exports){
var div, input, recl, ref, textarea;
recl = React.createClass;
@ -632,7 +724,8 @@ module.exports = recl({
});
},{}],10:[function(require,module,exports){
},{}],11:[function(require,module,exports){
var Virtual, div, load, reactify, recl, ref, rele, span, walk;
recl = React.createClass;
@ -699,7 +792,8 @@ module.exports = _.extend(reactify, {
});
},{"./LoadComponent.coffee":9}],11:[function(require,module,exports){
},{"./LoadComponent.coffee":10}],12:[function(require,module,exports){
var a, div, input, query, reactify, recl, ref,
slice = [].slice;
@ -837,8 +931,10 @@ module.exports = query({
}));
},{"./Async.coffee":3,"./Reactify.coffee":10}],12:[function(require,module,exports){
var div, query, reactify, recl;
},{"./Async.coffee":3,"./Reactify.coffee":11}],13:[function(require,module,exports){
var div, query, reactify, recl,
slice = [].slice;
query = require('./Async.coffee');
@ -853,35 +949,35 @@ module.exports = query({
}, recl({
hash: null,
displayName: "TableOfContents",
_click: function(e) {
return document.location.hash = this.urlsafe($(e.target).text());
},
urlsafe: function(str) {
return str.toLowerCase().replace(/\ /g, "-").replace(/[^a-z0-9~_.-]/g, "");
_click: function(id) {
return function() {
if (id) {
return document.location.hash = id;
}
};
},
componentDidMount: function() {
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');
return this.$headers = $('#toc').children('h1,h2,h3,h4').filter('[id]');
},
checkScroll: function() {
var $h, hash, hst, k, ref, results, st, v;
var $h, hash, hst, i, len, ref, results, st, v;
st = $(window).scrollTop();
if (Math.abs(this.st - st) > 10) {
hash = null;
this.st = st;
ref = this.$headers;
results = [];
for (k in ref) {
v = ref[k];
for (i = 0, len = ref.length; i < len; i++) {
v = ref[i];
if (v.tagName === void 0) {
continue;
}
$h = $(v);
hst = $h.offset().top - $h.outerHeight(true) + 10;
if (hst < st) {
hash = this.urlsafe($h.text());
hash = $h.attr('id');
}
if (hst > st && hash !== this.hash && hash !== null) {
this.hash = "#" + hash;
@ -895,15 +991,15 @@ module.exports = query({
}
},
checkHash: function() {
var $h, hash, k, offset, ref, ref1, results, v;
var $h, hash, i, len, 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);
ref1 = this.$headers;
results = [];
for (k in ref1) {
v = ref1[k];
for (i = 0, len = ref1.length; i < len; i++) {
v = ref1[i];
$h = $(v);
if (hash === this.urlsafe($h.text())) {
if (hash === $h.attr('id')) {
this.hash = document.location.hash;
offset = $h.offset().top - $h.outerHeight(true);
setTimeout(function() {
@ -920,44 +1016,39 @@ module.exports = query({
componentWillUnmount: function() {
return clearInterval(this.int);
},
collectHeaders: function(e) {
var _v, hs, k, v;
hs = [
{
gn: "h1",
ga: {
className: "t"
},
c: ["Table of contents"]
}
];
for (k in e) {
v = e[k];
if (!v.gn) {
continue;
}
if (v.gn[0] === 'h' && parseInt(v.gn[1]) !== NaN) {
_v = _.clone(v);
delete _v.ga.id;
hs.push(v);
}
collectHeader: function(arg) {
var c, ga, gn;
gn = arg.gn, ga = arg.ga, c = arg.c;
if (gn && gn[0] === 'h' && parseInt(gn[1]) !== NaN) {
ga = _.clone(ga);
ga.onClick = this._click(ga.id);
delete ga.id;
return {
gn: gn,
ga: ga,
c: c
};
}
return hs;
},
parseHeaders: function() {
var k, ref, ref1, v;
var i, len, ref, ref1, v;
if (this.props.body.c) {
ref = this.props.body.c;
for (k in ref) {
v = ref[k];
for (i = 0, len = ref.length; i < len; i++) {
v = ref[i];
if (v.gn === 'div' && ((ref1 = v.ga) != null ? ref1.id : void 0) === "toc") {
return {
gn: "div",
ga: {
className: "toc",
onClick: this._click
className: "toc"
},
c: this.collectHeaders(v.c)
c: [{
gn: "h1",
ga: {
className: "t"
},
c: ["Table of contents"]
}].concat(slice.call(_.filter(v.c.map(this.collectHeader))))
};
}
}
@ -969,7 +1060,8 @@ module.exports = query({
}));
},{"./Async.coffee":3,"./Reactify.coffee":10}],13:[function(require,module,exports){
},{"./Async.coffee":3,"./Reactify.coffee":11}],14:[function(require,module,exports){
var Dispatcher;
Dispatcher = require('flux').Dispatcher;
@ -990,7 +1082,8 @@ module.exports = _.extend(new Dispatcher(), {
});
},{"flux":16}],14:[function(require,module,exports){
},{"flux":17}],15:[function(require,module,exports){
var rend;
rend = React.render;
@ -1136,7 +1229,8 @@ $(function() {
});
},{"./actions/TreeActions.coffee":1,"./components/AnchorComponent.coffee":2,"./components/BodyComponent.coffee":4,"./components/Components.coffee":6,"./persistence/TreePersistence.coffee":19}],15:[function(require,module,exports){
},{"./actions/TreeActions.coffee":1,"./components/AnchorComponent.coffee":2,"./components/BodyComponent.coffee":4,"./components/Components.coffee":6,"./persistence/TreePersistence.coffee":20}],16:[function(require,module,exports){
/*!
Copyright (c) 2015 Jed Watson.
Licensed under the MIT License (MIT), see
@ -1144,50 +1238,50 @@ $(function() {
*/
(function () {
'use strict';
'use strict';
function classNames () {
function classNames () {
var classes = '';
var classes = '';
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (!arg) continue;
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (!arg) continue;
var argType = typeof arg;
var argType = typeof arg;
if ('string' === argType || 'number' === argType) {
classes += ' ' + arg;
if ('string' === argType || 'number' === argType) {
classes += ' ' + arg;
} else if (Array.isArray(arg)) {
classes += ' ' + classNames.apply(null, arg);
} else if (Array.isArray(arg)) {
classes += ' ' + classNames.apply(null, arg);
} else if ('object' === argType) {
for (var key in arg) {
if (arg.hasOwnProperty(key) && arg[key]) {
classes += ' ' + key;
}
}
}
}
} else if ('object' === argType) {
for (var key in arg) {
if (arg.hasOwnProperty(key) && arg[key]) {
classes += ' ' + key;
}
}
}
}
return classes.substr(1);
}
return classes.substr(1);
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = classNames;
} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd){
// AMD. Register as an anonymous module.
define(function () {
return classNames;
});
} else {
window.classNames = classNames;
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = classNames;
} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd){
// AMD. Register as an anonymous module.
define(function () {
return classNames;
});
} else {
window.classNames = classNames;
}
}());
},{}],16:[function(require,module,exports){
},{}],17:[function(require,module,exports){
/**
* Copyright (c) 2014-2015, Facebook, Inc.
* All rights reserved.
@ -1199,7 +1293,7 @@ $(function() {
module.exports.Dispatcher = require('./lib/Dispatcher')
},{"./lib/Dispatcher":17}],17:[function(require,module,exports){
},{"./lib/Dispatcher":18}],18:[function(require,module,exports){
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
@ -1451,7 +1545,7 @@ var _prefix = 'ID_';
module.exports = Dispatcher;
},{"./invariant":18}],18:[function(require,module,exports){
},{"./invariant":19}],19:[function(require,module,exports){
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
@ -1506,7 +1600,11 @@ var invariant = function(condition, format, a, b, c, d, e, f) {
module.exports = invariant;
},{}],19:[function(require,module,exports){
},{}],20:[function(require,module,exports){
var dedup;
dedup = {};
module.exports = {
get: function(path, query, cb) {
var url;
@ -1514,6 +1612,10 @@ module.exports = {
query = "no-query";
}
url = (window.tree.basepath(path)) + ".json?q=" + (this.encode(query));
if (dedup[url]) {
return;
}
dedup[url] = true;
return $.get(url, {}, function(data) {
if (cb) {
return cb(null, data);
@ -1523,7 +1625,7 @@ module.exports = {
encode: function(obj) {
var _encode, delim;
delim = function(n) {
return ('_'.repeat(n)) || '.';
return Array(n + 1).join('_') || '.';
};
_encode = function(obj) {
var _dep, dep, k, res, sub, v;
@ -1556,7 +1658,8 @@ module.exports = {
};
},{}],20:[function(require,module,exports){
},{}],21:[function(require,module,exports){
var EventEmitter, MessageDispatcher, QUERIES, TreeStore, _curr, _data, _tree, clog;
EventEmitter = require('events').EventEmitter;
@ -1596,23 +1699,32 @@ TreeStore = _.extend(EventEmitter.prototype, {
return this.fulfillAt(this.getTree(path.split('/')), path, query);
},
fulfillAt: function(tree, path, query) {
var data, k, ref, sub, t;
var data, have, k, sub, t;
data = this.fulfillLocal(path, query);
for (k in query) {
t = query[k];
if (!QUERIES[k]) {
continue;
have = _data[path];
if (have != null) {
for (k in query) {
t = query[k];
if (!QUERIES[k]) {
continue;
}
if (t !== QUERIES[k]) {
throw TypeError("Wrong query type: " + k + ", '" + t + "'");
}
data[k] = have[k];
}
if (t !== QUERIES[k]) {
throw TypeError("Wrong query type: " + k + ", '" + t + "'");
}
data[k] = (ref = _data[path]) != null ? ref[k] : void 0;
}
if (query.kids) {
data.kids = {};
for (k in tree) {
sub = tree[k];
data.kids[k] = this.fulfillAt(sub, path + "/" + k, query.kids);
if (query.kids) {
if (have.EMPTY) {
data.kids = {};
} else {
for (k in tree) {
sub = tree[k];
if (data.kids == null) {
data.kids = {};
}
data.kids[k] = this.fulfillAt(sub, path + "/" + k, query.kids);
}
}
}
}
if (!_.isEmpty(data)) {
@ -1665,6 +1777,7 @@ TreeStore = _.extend(EventEmitter.prototype, {
this.loadValues(tree[k], path + "/" + k, v);
}
if (data.kids && _.isEmpty(data.kids)) {
old.EMPTY = true;
old.body = {
gn: 'div',
c: [
@ -1791,7 +1904,8 @@ TreeStore.dispatchToken = MessageDispatcher.register(function(payload) {
module.exports = TreeStore;
},{"../dispatcher/Dispatcher.coffee":13,"events":21}],21:[function(require,module,exports){
},{"../dispatcher/Dispatcher.coffee":14,"events":22}],22:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@ -2094,4 +2208,4 @@ function isUndefined(arg) {
return arg === void 0;
}
},{}]},{},[14]);
},{}]},{},[15]);

View File

@ -1,6 +1,9 @@
dedup = {} # XX wrong layer
module.exports =
get: (path,query="no-query",cb) ->
url = "#{window.tree.basepath(path)}.json?q=#{@encode query}"
return if dedup[url]
dedup[url] = true
$.get url, {}, (data) -> if cb then cb null,data
encode: (obj)->
delim = (n)-> Array(n+1).join('_') || '.'

View File

@ -21,13 +21,17 @@ TreeStore = _.extend EventEmitter.prototype, {
fulfill: (path,query) -> @fulfillAt (@getTree path.split '/'),path,query
fulfillAt: (tree,path,query)->
data = @fulfillLocal path, query
for k,t of query when QUERIES[k]
if t isnt QUERIES[k] then throw TypeError "Wrong query type: #{k}, '#{t}'"
data[k] = _data[path]?[k]
if query.kids
data.kids = {}
for k,sub of tree
data.kids[k] = @fulfillAt sub, path+"/"+k, query.kids
have = _data[path]
if have?
for k,t of query when QUERIES[k]
if t isnt QUERIES[k] then throw TypeError "Wrong query type: #{k}, '#{t}'"
data[k] = have[k]
if query.kids
if have.EMPTY
data.kids = {}
else for k,sub of tree
data.kids ?= {}
data.kids[k] = @fulfillAt sub, path+"/"+k, query.kids
data unless _.isEmpty data
fulfillLocal: (path, query)->
@ -54,6 +58,7 @@ TreeStore = _.extend EventEmitter.prototype, {
@loadValues tree[k], path+"/"+k, v
if data.kids && _.isEmpty data.kids
old.EMPTY = true
old.body =
gn: 'div'
c: [ {gn:'h1', ga:{className:'error'}, c:['Error: Empty path']}