mirror of
https://github.com/urbit/shrub.git
synced 2024-11-28 05:22:27 +03:00
Merge pull request #2244 from urbit/m/link-fe-path
link fe: use base64url
This commit is contained in:
commit
6f65a65d85
@ -32309,7 +32309,6 @@
|
|||||||
global$2[key$1] = "esm";
|
global$2[key$1] = "esm";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//# sourceMappingURL=react-router.js.map
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The public API for a <Router> that uses HTML5 history.
|
* The public API for a <Router> that uses HTML5 history.
|
||||||
@ -32609,7 +32608,6 @@
|
|||||||
style: propTypes.object
|
style: propTypes.object
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//# sourceMappingURL=react-router-dom.js.map
|
|
||||||
|
|
||||||
var classnames = createCommonjsModule(function (module) {
|
var classnames = createCommonjsModule(function (module) {
|
||||||
/*!
|
/*!
|
||||||
@ -49765,6 +49763,61 @@
|
|||||||
return str.slice(0,-1);
|
return str.slice(0,-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// encodes string into base64url,
|
||||||
|
// by encoding into base64 and replacing non-url-safe characters.
|
||||||
|
//
|
||||||
|
function base64urlEncode(string) {
|
||||||
|
return window.btoa(string)
|
||||||
|
.split('+').join('-')
|
||||||
|
.split('/').join('_');
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode base64url. inverse of base64urlEncode above.
|
||||||
|
//
|
||||||
|
function base64urlDecode(string) {
|
||||||
|
return window.atob(
|
||||||
|
string.split('_').join('/')
|
||||||
|
.split('-').join('+')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode the string into @ta-safe format, using logic from +wood.
|
||||||
|
// for example, 'some Chars!' becomes '~.some.~43.hars~21.'
|
||||||
|
//
|
||||||
|
function stringToTa(string) {
|
||||||
|
let out = '';
|
||||||
|
for (let i = 0; i < string.length; i++) {
|
||||||
|
const char = string[i];
|
||||||
|
let add = '';
|
||||||
|
switch (char) {
|
||||||
|
case ' ':
|
||||||
|
add = '.';
|
||||||
|
break;
|
||||||
|
case '.':
|
||||||
|
add = '~.';
|
||||||
|
break;
|
||||||
|
case '~':
|
||||||
|
add = '~~';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
const charCode = string.charCodeAt(i);
|
||||||
|
if (
|
||||||
|
(charCode >= 97 && charCode <= 122) || // a-z
|
||||||
|
(charCode >= 48 && charCode <= 57) || // 0-9
|
||||||
|
char === '-'
|
||||||
|
) {
|
||||||
|
add = char;
|
||||||
|
} else {
|
||||||
|
//TODO behavior for unicode doesn't match +wood's,
|
||||||
|
// but we can probably get away with that for now.
|
||||||
|
add = '~' + charCode.toString(16) + '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out = out + add;
|
||||||
|
}
|
||||||
|
return '~.' + out;
|
||||||
|
}
|
||||||
|
|
||||||
function uxToHex(ux) {
|
function uxToHex(ux) {
|
||||||
let value = ux.substr(2).replace('.', '').padStart(6, '0');
|
let value = ux.substr(2).replace('.', '').padStart(6, '0');
|
||||||
return value;
|
return value;
|
||||||
@ -54806,7 +54859,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
getCommentsPage(path, url, page) {
|
getCommentsPage(path, url, page) {
|
||||||
const strictUrl = this.encodeUrl(url);
|
const strictUrl = stringToTa(url);
|
||||||
const endpoint = '/json/' + page + '/discussions/' + strictUrl + path;
|
const endpoint = '/json/' + page + '/discussions/' + strictUrl + path;
|
||||||
this.bindLinkView(endpoint,
|
this.bindLinkView(endpoint,
|
||||||
(res) => {
|
(res) => {
|
||||||
@ -54833,8 +54886,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSubmission(path, url, callback) {
|
getSubmission(path, url, callback) {
|
||||||
console.log('api: get submission', path, url);
|
const strictUrl = stringToTa(url);
|
||||||
const strictUrl = this.encodeUrl(url);
|
|
||||||
const endpoint = '/json/0/submission/' + strictUrl + path;
|
const endpoint = '/json/0/submission/' + strictUrl + path;
|
||||||
this.bindLinkView(endpoint,
|
this.bindLinkView(endpoint,
|
||||||
(res) => {
|
(res) => {
|
||||||
@ -54879,42 +54931,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO into lib?
|
|
||||||
// encode the url into @ta-safe format, using logic from +wood
|
|
||||||
encodeUrl(url) {
|
|
||||||
let strictUrl = '';
|
|
||||||
for (let i = 0; i < url.length; i++) {
|
|
||||||
const char = url[i];
|
|
||||||
let add = '';
|
|
||||||
switch (char) {
|
|
||||||
case ' ':
|
|
||||||
add = '.';
|
|
||||||
break;
|
|
||||||
case '.':
|
|
||||||
add = '~.';
|
|
||||||
break;
|
|
||||||
case '~':
|
|
||||||
add = '~~';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
const charCode = url.charCodeAt(i);
|
|
||||||
if (
|
|
||||||
(charCode >= 97 && charCode <= 122) || // a-z
|
|
||||||
(charCode >= 48 && charCode <= 57) || // 0-9
|
|
||||||
char === '-'
|
|
||||||
) {
|
|
||||||
add = char;
|
|
||||||
} else {
|
|
||||||
//TODO behavior for unicode doesn't match +wood's,
|
|
||||||
// but we can probably get away with that for now.
|
|
||||||
add = '~' + charCode.toString(16) + '.';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
strictUrl = strictUrl + add;
|
|
||||||
}
|
|
||||||
return '~.' + strictUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let api$1 = new UrbitApi();
|
let api$1 = new UrbitApi();
|
||||||
@ -55150,14 +55166,14 @@
|
|||||||
react.createElement('div', { className: "dib f8 pl6", __self: this, __source: {fileName: _jsxFileName$3, lineNumber: 28}}
|
react.createElement('div', { className: "dib f8 pl6", __self: this, __source: {fileName: _jsxFileName$3, lineNumber: 28}}
|
||||||
, react.createElement(Link, {
|
, react.createElement(Link, {
|
||||||
className: "no-underline " + memColor,
|
className: "no-underline " + memColor,
|
||||||
to: `/~link/` + popout + `members` + props.path, __self: this, __source: {fileName: _jsxFileName$3, lineNumber: 29}}, "Members"
|
to: `/~link/` + popout + `members` + props.groupPath, __self: this, __source: {fileName: _jsxFileName$3, lineNumber: 29}}, "Members"
|
||||||
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
react.createElement('div', { className: "dib", style: { width: 0 }, __self: this, __source: {fileName: _jsxFileName$3, lineNumber: 36}})
|
react.createElement('div', { className: "dib", style: { width: 0 }, __self: this, __source: {fileName: _jsxFileName$3, lineNumber: 36}})
|
||||||
)
|
)
|
||||||
, react.createElement('a', { href: `/~link/popout` + props.path, target: "_blank",
|
, react.createElement('a', { href: `/~link/popout` + props.groupPath, target: "_blank",
|
||||||
className: "dib fr" , __self: this, __source: {fileName: _jsxFileName$3, lineNumber: 38}}
|
className: "dib fr" , __self: this, __source: {fileName: _jsxFileName$3, lineNumber: 38}}
|
||||||
, react.createElement('img', {
|
, react.createElement('img', {
|
||||||
className: `flex-shrink-0 pr4 dn invert-d ` + hidePopoutIcon,
|
className: `flex-shrink-0 pr4 dn invert-d ` + hidePopoutIcon,
|
||||||
@ -59132,34 +59148,34 @@
|
|||||||
hostname = hostname[4];
|
hostname = hostname[4];
|
||||||
}
|
}
|
||||||
|
|
||||||
let encodedUrl = window.btoa(props.url);
|
let encodedUrl = base64urlEncode(props.url);
|
||||||
|
|
||||||
let comments = props.comments + " comment" + ((props.comments === 1) ? "" : "s");
|
let comments = props.comments + " comment" + ((props.comments === 1) ? "" : "s");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
react.createElement('div', { className: "w-100 pv3 flex" , __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 53}}
|
react.createElement('div', { className: "w-100 pv3 flex" , __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 54}}
|
||||||
, react.createElement(Sigil, {
|
, react.createElement(Sigil, {
|
||||||
ship: "~" + props.ship,
|
ship: "~" + props.ship,
|
||||||
size: 36,
|
size: 36,
|
||||||
color: "#" + props.color, __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 54}}
|
color: "#" + props.color, __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 55}}
|
||||||
)
|
)
|
||||||
, react.createElement('div', { className: "flex flex-column ml2" , __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 59}}
|
, react.createElement('div', { className: "flex flex-column ml2" , __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 60}}
|
||||||
, react.createElement('a', { href: props.url,
|
, react.createElement('a', { href: props.url,
|
||||||
className: "w-100 flex" ,
|
className: "w-100 flex" ,
|
||||||
target: "_blank", __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 60}}
|
target: "_blank", __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 61}}
|
||||||
, react.createElement('p', { className: "f8 truncate" , __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 63}}, props.title
|
, react.createElement('p', { className: "f8 truncate" , __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 64}}, props.title
|
||||||
, react.createElement('span', { className: "gray2 dib truncate-m mw4-m v-btm ml2" , __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 64}}, hostname, " ↗" )
|
, react.createElement('span', { className: "gray2 dib truncate-m mw4-m v-btm ml2" , __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 65}}, hostname, " ↗" )
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
, react.createElement('div', { className: "w-100 pt1" , __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 67}}
|
, react.createElement('div', { className: "w-100 pt1" , __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 68}}
|
||||||
, react.createElement('span', { className: "f9 pr2 v-mid " + mono, __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 68}}, (props.nickname)
|
, react.createElement('span', { className: "f9 pr2 v-mid " + mono, __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 69}}, (props.nickname)
|
||||||
? props.nickname
|
? props.nickname
|
||||||
: "~" + props.ship)
|
: "~" + props.ship)
|
||||||
, react.createElement('span', { className: "f9 inter gray2 pr3 v-mid" , __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 71}}, this.state.timeSinceLinkPost)
|
, react.createElement('span', { className: "f9 inter gray2 pr3 v-mid" , __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 72}}, this.state.timeSinceLinkPost)
|
||||||
, react.createElement(Link$1, { to:
|
, react.createElement(Link$1, { to:
|
||||||
"/~link" + props.popout + "/" + props.channel + "/" + props.page + "/" + props.linkIndex + "/" + encodedUrl,
|
"/~link" + props.popout + props.groupPath + "/" + props.page + "/" + props.linkIndex + "/" + encodedUrl,
|
||||||
className: "v-top", __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 72}}
|
className: "v-top", __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 73}}
|
||||||
, react.createElement('span', { className: "f9 inter gray2" , __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 75}}
|
, react.createElement('span', { className: "f9 inter gray2" , __self: this, __source: {fileName: _jsxFileName$6, lineNumber: 76}}
|
||||||
, comments
|
, comments
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -59301,12 +59317,12 @@
|
|||||||
return (
|
return (
|
||||||
react.createElement('div', { className: "w-100 inter relative pv6" , __self: this, __source: {fileName: _jsxFileName$8, lineNumber: 20}}
|
react.createElement('div', { className: "w-100 inter relative pv6" , __self: this, __source: {fileName: _jsxFileName$8, lineNumber: 20}}
|
||||||
, react.createElement('div', { className: prevDisplay + " inter f8", __self: this, __source: {fileName: _jsxFileName$8, lineNumber: 21}}
|
, react.createElement('div', { className: prevDisplay + " inter f8", __self: this, __source: {fileName: _jsxFileName$8, lineNumber: 21}}
|
||||||
, react.createElement(Link$1, { to: "/~link" + props.popout + props.path + prevPage, __self: this, __source: {fileName: _jsxFileName$8, lineNumber: 22}}, "<- Previous Page"
|
, react.createElement(Link$1, { to: "/~link" + props.popout + props.groupPath + prevPage, __self: this, __source: {fileName: _jsxFileName$8, lineNumber: 22}}, "<- Previous Page"
|
||||||
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
, react.createElement('div', { className: nextDisplay + " inter f8", __self: this, __source: {fileName: _jsxFileName$8, lineNumber: 26}}
|
, react.createElement('div', { className: nextDisplay + " inter f8", __self: this, __source: {fileName: _jsxFileName$8, lineNumber: 26}}
|
||||||
, react.createElement(Link$1, { to: "/~link" + props.popout + props.path + nextPage, __self: this, __source: {fileName: _jsxFileName$8, lineNumber: 27}}, "Next Page ->"
|
, react.createElement(Link$1, { to: "/~link" + props.popout + props.groupPath + nextPage, __self: this, __source: {fileName: _jsxFileName$8, lineNumber: 27}}, "Next Page ->"
|
||||||
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -59329,14 +59345,13 @@
|
|||||||
(!this.props.links[linkPage] ||
|
(!this.props.links[linkPage] ||
|
||||||
this.props.links.local[linkPage])
|
this.props.links.local[linkPage])
|
||||||
) {
|
) {
|
||||||
api.getPage(this.props.path, this.props.page);
|
api.getPage(this.props.groupPath, this.props.page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let props = this.props;
|
let props = this.props;
|
||||||
let popout = (props.popout) ? "/popout" : "";
|
let popout = (props.popout) ? "/popout" : "";
|
||||||
let channel = props.path.substr(1);
|
|
||||||
let linkPage = props.page;
|
let linkPage = props.page;
|
||||||
|
|
||||||
let links = !!props.links[linkPage]
|
let links = !!props.links[linkPage]
|
||||||
@ -59391,58 +59406,58 @@
|
|||||||
ship: ship,
|
ship: ship,
|
||||||
color: color,
|
color: color,
|
||||||
comments: commentCount,
|
comments: commentCount,
|
||||||
channel: channel,
|
groupPath: props.groupPath,
|
||||||
popout: popout, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 76}}
|
popout: popout, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 75}}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
react.createElement('div', {
|
react.createElement('div', {
|
||||||
className: "h-100 w-100 overflow-hidden flex flex-column" , __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 94}}
|
className: "h-100 w-100 overflow-hidden flex flex-column" , __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 93}}
|
||||||
, react.createElement('div', {
|
, react.createElement('div', {
|
||||||
className: "w-100 dn-m dn-l dn-xl inter pt4 pb6 pl3 f8" ,
|
className: "w-100 dn-m dn-l dn-xl inter pt4 pb6 pl3 f8" ,
|
||||||
style: { height: "1rem" }, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 96}}
|
style: { height: "1rem" }, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 95}}
|
||||||
, react.createElement(Link$1, { to: "/~link/", __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 99}}, "⟵ All Channels")
|
, react.createElement(Link$1, { to: "/~link/", __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 98}}, "⟵ All Channels")
|
||||||
)
|
)
|
||||||
, react.createElement('div', {
|
, react.createElement('div', {
|
||||||
className: `pl3 pt2 flex relative overflow-x-scroll
|
className: `pl3 pt2 flex relative overflow-x-scroll
|
||||||
overflow-x-auto-l overflow-x-auto-xl flex-shrink-0
|
overflow-x-auto-l overflow-x-auto-xl flex-shrink-0
|
||||||
bb bn-m bn-l bn-xl b--gray4`,
|
bb bn-m bn-l bn-xl b--gray4`,
|
||||||
style: { height: 48 }, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 101}}
|
style: { height: 48 }, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 100}}
|
||||||
, react.createElement(SidebarSwitcher, {
|
, react.createElement(SidebarSwitcher, {
|
||||||
sidebarShown: props.sidebarShown,
|
sidebarShown: props.sidebarShown,
|
||||||
popout: props.popout, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 106}})
|
popout: props.popout, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 105}})
|
||||||
, react.createElement(Link$1, { to: `/~link` + popout + props.path, className: "pt2", __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 109}}
|
, react.createElement(Link$1, { to: `/~link` + popout + props.groupPath, className: "pt2", __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 108}}
|
||||||
, react.createElement('h2', {
|
, react.createElement('h2', {
|
||||||
className: `dib f8 fw4 v-top ` +
|
className: `dib f8 fw4 v-top ` +
|
||||||
(props.path.includes("/~/")
|
(props.groupPath.includes("/~/")
|
||||||
? ""
|
? ""
|
||||||
: "mono"), __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 110}}
|
: "mono"), __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 109}}
|
||||||
, (props.path.includes("/~/"))
|
, (props.groupPath.includes("/~/"))
|
||||||
? "Private"
|
? "Private"
|
||||||
: channel
|
: props.groupPath.substr(1)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
, react.createElement(LinksTabBar, {
|
, react.createElement(LinksTabBar, {
|
||||||
...props,
|
...props,
|
||||||
popout: popout,
|
popout: popout,
|
||||||
path: props.path + "/" + props.page, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 120}})
|
groupPath: props.groupPath + "/" + props.page, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 119}})
|
||||||
)
|
)
|
||||||
, react.createElement('div', { className: "w-100 mt2 flex justify-center overflow-y-scroll ph4 pb4" , __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 125}}
|
, react.createElement('div', { className: "w-100 mt2 flex justify-center overflow-y-scroll ph4 pb4" , __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 124}}
|
||||||
, react.createElement('div', { className: "w-100 mw7" , __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 126}}
|
, react.createElement('div', { className: "w-100 mw7" , __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 125}}
|
||||||
, react.createElement('div', { className: "flex", __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 127}}
|
, react.createElement('div', { className: "flex", __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 126}}
|
||||||
, react.createElement(LinkSubmit, { path: props.path, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 128}})
|
, react.createElement(LinkSubmit, { groupPath: props.groupPath, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 127}})
|
||||||
)
|
)
|
||||||
, react.createElement('div', { className: "pb4", __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 130}}
|
, react.createElement('div', { className: "pb4", __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 129}}
|
||||||
, LinkList
|
, LinkList
|
||||||
, react.createElement(Pagination, {
|
, react.createElement(Pagination, {
|
||||||
...props,
|
...props,
|
||||||
key: props.path + props.page,
|
key: props.groupPath + props.page,
|
||||||
popout: popout,
|
popout: popout,
|
||||||
path: props.path,
|
groupPath: props.groupPath,
|
||||||
currentPage: currentPage,
|
currentPage: currentPage,
|
||||||
totalPages: totalPages, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 132}}
|
totalPages: totalPages, __self: this, __source: {fileName: _jsxFileName$9, lineNumber: 131}}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -59521,31 +59536,31 @@
|
|||||||
? "dib"
|
? "dib"
|
||||||
: "dn";
|
: "dn";
|
||||||
|
|
||||||
let encodedUrl = window.btoa(props.url);
|
let encodedUrl = base64urlEncode(props.url);
|
||||||
let popout = (props.popout) ? "/popout" : "";
|
let popout = (props.popout) ? "/popout" : "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
react.createElement('div', { className: "w-100 relative pt4 pb6" , __self: this, __source: {fileName: _jsxFileName$b, lineNumber: 23}}
|
react.createElement('div', { className: "w-100 relative pt4 pb6" , __self: this, __source: {fileName: _jsxFileName$b, lineNumber: 24}}
|
||||||
, react.createElement(Link$1, {
|
, react.createElement(Link$1, {
|
||||||
className: "pb6 absolute inter f8 left-0 " + prevDisplay,
|
className: "pb6 absolute inter f8 left-0 " + prevDisplay,
|
||||||
to: "/~link"
|
to: "/~link"
|
||||||
+ popout
|
+ popout
|
||||||
+ props.path
|
+ props.groupPath
|
||||||
+ "/" + props.linkPage
|
+ "/" + props.linkPage
|
||||||
+ "/" + props.linkIndex
|
+ "/" + props.linkIndex
|
||||||
+ "/" + encodedUrl
|
+ "/" + encodedUrl
|
||||||
+ "/comments" + prevPage, __self: this, __source: {fileName: _jsxFileName$b, lineNumber: 24}}, "<- Previous Page"
|
+ "/comments" + prevPage, __self: this, __source: {fileName: _jsxFileName$b, lineNumber: 25}}, "<- Previous Page"
|
||||||
|
|
||||||
)
|
)
|
||||||
, react.createElement(Link$1, {
|
, react.createElement(Link$1, {
|
||||||
className: "pb6 absolute inter f8 right-0 " + nextDisplay,
|
className: "pb6 absolute inter f8 right-0 " + nextDisplay,
|
||||||
to: "/~link"
|
to: "/~link"
|
||||||
+ popout
|
+ popout
|
||||||
+ props.path
|
+ props.groupPath
|
||||||
+ "/" + props.linkPage
|
+ "/" + props.linkPage
|
||||||
+ "/" + props.linkIndex
|
+ "/" + props.linkIndex
|
||||||
+ "/" + encodedUrl
|
+ "/" + encodedUrl
|
||||||
+ "/comments" + nextPage, __self: this, __source: {fileName: _jsxFileName$b, lineNumber: 35}}, "Next Page ->"
|
+ "/comments" + nextPage, __self: this, __source: {fileName: _jsxFileName$b, lineNumber: 36}}, "Next Page ->"
|
||||||
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -59568,7 +59583,7 @@
|
|||||||
) {
|
) {
|
||||||
this.setState({requested: this.props.commentPage});
|
this.setState({requested: this.props.commentPage});
|
||||||
api$1.getCommentsPage(
|
api$1.getCommentsPage(
|
||||||
this.props.path,
|
this.props.groupPath,
|
||||||
this.props.url,
|
this.props.url,
|
||||||
this.props.commentPage);
|
this.props.commentPage);
|
||||||
}
|
}
|
||||||
@ -59627,8 +59642,8 @@
|
|||||||
react.createElement('div', {__self: this, __source: {fileName: _jsxFileName$c, lineNumber: 78}}
|
react.createElement('div', {__self: this, __source: {fileName: _jsxFileName$c, lineNumber: 78}}
|
||||||
, commentsList
|
, commentsList
|
||||||
, react.createElement(CommentsPagination, {
|
, react.createElement(CommentsPagination, {
|
||||||
key: props.path + props.commentPage,
|
key: props.groupPath + props.commentPage,
|
||||||
path: props.path,
|
groupPath: props.groupPath,
|
||||||
popout: props.popout,
|
popout: props.popout,
|
||||||
linkPage: props.linkPage,
|
linkPage: props.linkPage,
|
||||||
linkIndex: props.linkIndex,
|
linkIndex: props.linkIndex,
|
||||||
@ -59664,7 +59679,7 @@
|
|||||||
// if we have no preloaded data, and we aren't expecting it, get it
|
// if we have no preloaded data, and we aren't expecting it, get it
|
||||||
if (!this.state.data.title) {
|
if (!this.state.data.title) {
|
||||||
api$1.getSubmission(
|
api$1.getSubmission(
|
||||||
this.props.path, this.props.url, this.updateData.bind(this)
|
this.props.groupPath, this.props.url, this.updateData.bind(this)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59697,7 +59712,7 @@
|
|||||||
let url = this.props.url || "";
|
let url = this.props.url || "";
|
||||||
|
|
||||||
let request = api$1.postComment(
|
let request = api$1.postComment(
|
||||||
this.props.path,
|
this.props.groupPath,
|
||||||
url,
|
url,
|
||||||
this.state.comment
|
this.state.comment
|
||||||
);
|
);
|
||||||
@ -59714,7 +59729,6 @@
|
|||||||
render() {
|
render() {
|
||||||
let props = this.props;
|
let props = this.props;
|
||||||
let popout = (props.popout) ? "/popout" : "";
|
let popout = (props.popout) ? "/popout" : "";
|
||||||
let routePath = props.path + "/" + props.page + "/" + props.linkIndex + "/" + window.btoa(props.url);
|
|
||||||
|
|
||||||
const data = this.state.data || props.data;
|
const data = this.state.data || props.data;
|
||||||
let ship = data.ship || "zod";
|
let ship = data.ship || "zod";
|
||||||
@ -59761,13 +59775,13 @@
|
|||||||
popout: props.popout, __self: this, __source: {fileName: _jsxFileName$d, lineNumber: 126}})
|
popout: props.popout, __self: this, __source: {fileName: _jsxFileName$d, lineNumber: 126}})
|
||||||
, react.createElement(Link$1, {
|
, react.createElement(Link$1, {
|
||||||
className: "dib f8 fw4 v-top pt2 gray2" ,
|
className: "dib f8 fw4 v-top pt2 gray2" ,
|
||||||
to: "/~link" + popout + props.path + "/" + props.page, __self: this, __source: {fileName: _jsxFileName$d, lineNumber: 129}}
|
to: "/~link" + popout + props.groupPath + "/" + props.page, __self: this, __source: {fileName: _jsxFileName$d, lineNumber: 129}}
|
||||||
, "<- Collection index"
|
, "<- Collection index"
|
||||||
)
|
)
|
||||||
, react.createElement(LinksTabBar, {
|
, react.createElement(LinksTabBar, {
|
||||||
...props,
|
...props,
|
||||||
popout: popout,
|
popout: popout,
|
||||||
path: routePath, __self: this, __source: {fileName: _jsxFileName$d, lineNumber: 134}})
|
groupPath: props.groupPath, __self: this, __source: {fileName: _jsxFileName$d, lineNumber: 134}})
|
||||||
)
|
)
|
||||||
, react.createElement('div', { className: "w-100 mt2 flex justify-center overflow-y-scroll ph4 pb4" , __self: this, __source: {fileName: _jsxFileName$d, lineNumber: 139}}
|
, react.createElement('div', { className: "w-100 mt2 flex justify-center overflow-y-scroll ph4 pb4" , __self: this, __source: {fileName: _jsxFileName$d, lineNumber: 139}}
|
||||||
, react.createElement('div', { className: "w-100 mw7" , __self: this, __source: {fileName: _jsxFileName$d, lineNumber: 140}}
|
, react.createElement('div', { className: "w-100 mw7" , __self: this, __source: {fileName: _jsxFileName$d, lineNumber: 140}}
|
||||||
@ -59793,7 +59807,7 @@
|
|||||||
, react.createElement('span', { className: "f9 inter gray2 pr3 v-mid" , __self: this, __source: {fileName: _jsxFileName$d, lineNumber: 160}}
|
, react.createElement('span', { className: "f9 inter gray2 pr3 v-mid" , __self: this, __source: {fileName: _jsxFileName$d, lineNumber: 160}}
|
||||||
, this.state.timeSinceLinkPost
|
, this.state.timeSinceLinkPost
|
||||||
)
|
)
|
||||||
, react.createElement(Link$1, { to: "/~link" + props.path + "/" + props.page + "/" + props.linkIndex + "/" + window.btoa(props.url), className: "v-top", __self: this, __source: {fileName: _jsxFileName$d, lineNumber: 163}}
|
, react.createElement(Link$1, { to: "/~link" + props.path + "/" + props.page + "/" + props.linkIndex + "/" + base64urlEncode(props.url), className: "v-top", __self: this, __source: {fileName: _jsxFileName$d, lineNumber: 163}}
|
||||||
, react.createElement('span', { className: "f9 inter gray2" , __self: this, __source: {fileName: _jsxFileName$d, lineNumber: 164}}
|
, react.createElement('span', { className: "f9 inter gray2" , __self: this, __source: {fileName: _jsxFileName$d, lineNumber: 164}}
|
||||||
, comments
|
, comments
|
||||||
)
|
)
|
||||||
@ -59824,8 +59838,8 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
, react.createElement(Comments, {
|
, react.createElement(Comments, {
|
||||||
path: props.path,
|
groupPath: props.groupPath,
|
||||||
key: props.path + props.commentPage,
|
key: props.groupPath + props.commentPage,
|
||||||
comments: props.comments,
|
comments: props.comments,
|
||||||
commentPage: props.commentPage,
|
commentPage: props.commentPage,
|
||||||
members: props.members,
|
members: props.members,
|
||||||
@ -59867,7 +59881,7 @@
|
|||||||
let comments = !!state.comments ? state.comments : {};
|
let comments = !!state.comments ? state.comments : {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
react.createElement(BrowserRouter, {__self: this, __source: {fileName: _jsxFileName$e, lineNumber: 38}}
|
react.createElement(BrowserRouter, {__self: this, __source: {fileName: _jsxFileName$e, lineNumber: 39}}
|
||||||
, react.createElement(Route, { exact: true, path: "/~link",
|
, react.createElement(Route, { exact: true, path: "/~link",
|
||||||
render: (props) => {
|
render: (props) => {
|
||||||
return (
|
return (
|
||||||
@ -59876,17 +59890,17 @@
|
|||||||
paths: paths,
|
paths: paths,
|
||||||
rightPanelHide: true,
|
rightPanelHide: true,
|
||||||
sidebarShown: true,
|
sidebarShown: true,
|
||||||
links: links, __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 42}}
|
links: links, __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 43}}
|
||||||
, react.createElement('div', { className: "h-100 w-100 overflow-x-hidden flex flex-column bg-white bg-gray0-d dn db-ns" , __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 48}}
|
, react.createElement('div', { className: "h-100 w-100 overflow-x-hidden flex flex-column bg-white bg-gray0-d dn db-ns" , __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 49}}
|
||||||
, react.createElement('div', { className: "pl3 pr3 pt2 dt pb3 w-100 h-100" , __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 49}}
|
, react.createElement('div', { className: "pl3 pr3 pt2 dt pb3 w-100 h-100" , __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 50}}
|
||||||
, react.createElement('p', { className: "f8 pt3 gray2 w-100 h-100 dtc v-mid tc" , __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 50}}, "Collections are shared across groups. To create a new collection, "
|
, react.createElement('p', { className: "f8 pt3 gray2 w-100 h-100 dtc v-mid tc" , __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 51}}, "Collections are shared across groups. To create a new collection, "
|
||||||
, react.createElement('a', { className: "black white-d" , href: "/~contacts", __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 51}}, "create a group" ), "."
|
, react.createElement('a', { className: "black white-d" , href: "/~contacts", __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 52}}, "create a group" ), "."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}, __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 39}} )
|
}, __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 40}} )
|
||||||
, react.createElement(Route, { exact: true, path: "/~link/(popout)?/:ship/:channel/:page?",
|
, react.createElement(Route, { exact: true, path: "/~link/(popout)?/:ship/:channel/:page?",
|
||||||
render: (props) => {
|
render: (props) => {
|
||||||
// groups/contacts and link channels are the same thing in ver 1
|
// groups/contacts and link channels are the same thing in ver 1
|
||||||
@ -59916,20 +59930,20 @@
|
|||||||
sidebarShown: state.sidebarShown,
|
sidebarShown: state.sidebarShown,
|
||||||
sidebarHideMobile: true,
|
sidebarHideMobile: true,
|
||||||
popout: popout,
|
popout: popout,
|
||||||
links: links, __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 79}}
|
links: links, __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 80}}
|
||||||
, react.createElement(Links, {
|
, react.createElement(Links, {
|
||||||
...props,
|
...props,
|
||||||
members: groupMembers,
|
members: groupMembers,
|
||||||
links: channelLinks,
|
links: channelLinks,
|
||||||
comments: channelComments,
|
comments: channelComments,
|
||||||
page: page,
|
page: page,
|
||||||
path: groupPath,
|
groupPath: groupPath,
|
||||||
popout: popout,
|
popout: popout,
|
||||||
sidebarShown: state.sidebarShown, __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 88}}
|
sidebarShown: state.sidebarShown, __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 89}}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}, __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 58}}
|
}, __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 59}}
|
||||||
)
|
)
|
||||||
, react.createElement(Route, { exact: true, path: "/~link/(popout)?/:ship/:channel/:page/:index/:encodedUrl/(comments)?/:commentpage?",
|
, react.createElement(Route, { exact: true, path: "/~link/(popout)?/:ship/:channel/:page/:index/:encodedUrl/(comments)?/:commentpage?",
|
||||||
render: (props) => {
|
render: (props) => {
|
||||||
@ -59942,7 +59956,7 @@
|
|||||||
|
|
||||||
let index = props.match.params.index || 0;
|
let index = props.match.params.index || 0;
|
||||||
let page = props.match.params.page || 0;
|
let page = props.match.params.page || 0;
|
||||||
let url = window.atob(props.match.params.encodedUrl);
|
let url = base64urlDecode(props.match.params.encodedUrl);
|
||||||
|
|
||||||
let data = !!links[groupPath]
|
let data = !!links[groupPath]
|
||||||
? !!links[groupPath][page]
|
? !!links[groupPath][page]
|
||||||
@ -59964,23 +59978,23 @@
|
|||||||
sidebarShown: state.sidebarShown,
|
sidebarShown: state.sidebarShown,
|
||||||
sidebarHideMobile: true,
|
sidebarHideMobile: true,
|
||||||
popout: popout,
|
popout: popout,
|
||||||
links: links, __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 127}}
|
links: links, __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 128}}
|
||||||
, react.createElement(LinkDetail, {
|
, react.createElement(LinkDetail, {
|
||||||
...props,
|
...props,
|
||||||
page: page,
|
page: page,
|
||||||
url: url,
|
url: url,
|
||||||
linkIndex: index,
|
linkIndex: index,
|
||||||
members: groupMembers,
|
members: groupMembers,
|
||||||
path: groupPath,
|
groupPath: groupPath,
|
||||||
popout: popout,
|
popout: popout,
|
||||||
sidebarShown: state.sidebarShown,
|
sidebarShown: state.sidebarShown,
|
||||||
data: data,
|
data: data,
|
||||||
comments: coms,
|
comments: coms,
|
||||||
commentPage: commentPage, __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 136}}
|
commentPage: commentPage, __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 137}}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}, __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 102}}
|
}, __self: this, __source: {fileName: _jsxFileName$e, lineNumber: 103}}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { uuid } from '/lib/util';
|
import { uuid, stringToTa } from '/lib/util';
|
||||||
import { store } from '/store';
|
import { store } from '/store';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ class UrbitApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getCommentsPage(path, url, page) {
|
getCommentsPage(path, url, page) {
|
||||||
const strictUrl = this.encodeUrl(url);
|
const strictUrl = stringToTa(url);
|
||||||
const endpoint = '/json/' + page + '/discussions/' + strictUrl + path;
|
const endpoint = '/json/' + page + '/discussions/' + strictUrl + path;
|
||||||
this.bindLinkView(endpoint,
|
this.bindLinkView(endpoint,
|
||||||
(res) => {
|
(res) => {
|
||||||
@ -129,7 +129,7 @@ class UrbitApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSubmission(path, url, callback) {
|
getSubmission(path, url, callback) {
|
||||||
const strictUrl = this.encodeUrl(url);
|
const strictUrl = stringToTa(url);
|
||||||
const endpoint = '/json/0/submission/' + strictUrl + path;
|
const endpoint = '/json/0/submission/' + strictUrl + path;
|
||||||
this.bindLinkView(endpoint,
|
this.bindLinkView(endpoint,
|
||||||
(res) => {
|
(res) => {
|
||||||
@ -174,42 +174,6 @@ class UrbitApi {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO into lib?
|
|
||||||
// encode the url into @ta-safe format, using logic from +wood
|
|
||||||
encodeUrl(url) {
|
|
||||||
let strictUrl = '';
|
|
||||||
for (let i = 0; i < url.length; i++) {
|
|
||||||
const char = url[i];
|
|
||||||
let add = '';
|
|
||||||
switch (char) {
|
|
||||||
case ' ':
|
|
||||||
add = '.';
|
|
||||||
break;
|
|
||||||
case '.':
|
|
||||||
add = '~.';
|
|
||||||
break;
|
|
||||||
case '~':
|
|
||||||
add = '~~';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
const charCode = url.charCodeAt(i);
|
|
||||||
if (
|
|
||||||
(charCode >= 97 && charCode <= 122) || // a-z
|
|
||||||
(charCode >= 48 && charCode <= 57) || // 0-9
|
|
||||||
char === '-'
|
|
||||||
) {
|
|
||||||
add = char;
|
|
||||||
} else {
|
|
||||||
//TODO behavior for unicode doesn't match +wood's,
|
|
||||||
// but we can probably get away with that for now.
|
|
||||||
add = '~' + charCode.toString(16) + '.';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
strictUrl = strictUrl + add;
|
|
||||||
}
|
|
||||||
return '~.' + strictUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export let api = new UrbitApi();
|
export let api = new UrbitApi();
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Route, Link } from 'react-router-dom';
|
import { Route, Link } from 'react-router-dom';
|
||||||
|
import { base64urlEncode } from '../../lib/util';
|
||||||
|
|
||||||
export class CommentsPagination extends Component {
|
export class CommentsPagination extends Component {
|
||||||
render() {
|
render() {
|
||||||
@ -16,7 +17,7 @@ export class CommentsPagination extends Component {
|
|||||||
? "dib"
|
? "dib"
|
||||||
: "dn";
|
: "dn";
|
||||||
|
|
||||||
let encodedUrl = window.btoa(props.url);
|
let encodedUrl = base64urlEncode(props.url);
|
||||||
let popout = (props.popout) ? "/popout" : "";
|
let popout = (props.popout) ? "/popout" : "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -25,7 +26,7 @@ export class CommentsPagination extends Component {
|
|||||||
className={"pb6 absolute inter f8 left-0 " + prevDisplay}
|
className={"pb6 absolute inter f8 left-0 " + prevDisplay}
|
||||||
to={"/~link"
|
to={"/~link"
|
||||||
+ popout
|
+ popout
|
||||||
+ props.path
|
+ props.groupPath
|
||||||
+ "/" + props.linkPage
|
+ "/" + props.linkPage
|
||||||
+ "/" + props.linkIndex
|
+ "/" + props.linkIndex
|
||||||
+ "/" + encodedUrl
|
+ "/" + encodedUrl
|
||||||
@ -36,7 +37,7 @@ export class CommentsPagination extends Component {
|
|||||||
className={"pb6 absolute inter f8 right-0 " + nextDisplay}
|
className={"pb6 absolute inter f8 right-0 " + nextDisplay}
|
||||||
to={"/~link"
|
to={"/~link"
|
||||||
+ popout
|
+ popout
|
||||||
+ props.path
|
+ props.groupPath
|
||||||
+ "/" + props.linkPage
|
+ "/" + props.linkPage
|
||||||
+ "/" + props.linkIndex
|
+ "/" + props.linkIndex
|
||||||
+ "/" + encodedUrl
|
+ "/" + encodedUrl
|
||||||
|
@ -19,7 +19,7 @@ export class Comments extends Component {
|
|||||||
) {
|
) {
|
||||||
this.setState({requested: this.props.commentPage});
|
this.setState({requested: this.props.commentPage});
|
||||||
api.getCommentsPage(
|
api.getCommentsPage(
|
||||||
this.props.path,
|
this.props.groupPath,
|
||||||
this.props.url,
|
this.props.url,
|
||||||
this.props.commentPage);
|
this.props.commentPage);
|
||||||
}
|
}
|
||||||
@ -78,8 +78,8 @@ export class Comments extends Component {
|
|||||||
<div>
|
<div>
|
||||||
{commentsList}
|
{commentsList}
|
||||||
<CommentsPagination
|
<CommentsPagination
|
||||||
key={props.path + props.commentPage}
|
key={props.groupPath + props.commentPage}
|
||||||
path={props.path}
|
groupPath={props.groupPath}
|
||||||
popout={props.popout}
|
popout={props.popout}
|
||||||
linkPage={props.linkPage}
|
linkPage={props.linkPage}
|
||||||
linkIndex={props.linkIndex}
|
linkIndex={props.linkIndex}
|
||||||
|
@ -3,6 +3,7 @@ import moment from 'moment';
|
|||||||
|
|
||||||
import { Sigil } from '/components/lib/icons/sigil';
|
import { Sigil } from '/components/lib/icons/sigil';
|
||||||
import { Route, Link } from 'react-router-dom';
|
import { Route, Link } from 'react-router-dom';
|
||||||
|
import { base64urlEncode } from '../../lib/util';
|
||||||
|
|
||||||
export class LinkItem extends Component {
|
export class LinkItem extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -45,7 +46,7 @@ export class LinkItem extends Component {
|
|||||||
hostname = hostname[4];
|
hostname = hostname[4];
|
||||||
}
|
}
|
||||||
|
|
||||||
let encodedUrl = window.btoa(props.url);
|
let encodedUrl = base64urlEncode(props.url);
|
||||||
|
|
||||||
let comments = props.comments + " comment" + ((props.comments === 1) ? "" : "s");
|
let comments = props.comments + " comment" + ((props.comments === 1) ? "" : "s");
|
||||||
|
|
||||||
@ -70,7 +71,7 @@ export class LinkItem extends Component {
|
|||||||
: "~" + props.ship}</span>
|
: "~" + props.ship}</span>
|
||||||
<span className="f9 inter gray2 pr3 v-mid">{this.state.timeSinceLinkPost}</span>
|
<span className="f9 inter gray2 pr3 v-mid">{this.state.timeSinceLinkPost}</span>
|
||||||
<Link to=
|
<Link to=
|
||||||
{"/~link" + props.popout + "/" + props.channel + "/" + props.page + "/" + props.linkIndex + "/" + encodedUrl}
|
{"/~link" + props.popout + props.groupPath + "/" + props.page + "/" + props.linkIndex + "/" + encodedUrl}
|
||||||
className="v-top">
|
className="v-top">
|
||||||
<span className="f9 inter gray2">
|
<span className="f9 inter gray2">
|
||||||
{comments}
|
{comments}
|
||||||
|
@ -28,14 +28,14 @@ export class LinksTabBar extends Component {
|
|||||||
<div className={"dib f8 pl6"}>
|
<div className={"dib f8 pl6"}>
|
||||||
<Link
|
<Link
|
||||||
className={"no-underline " + memColor}
|
className={"no-underline " + memColor}
|
||||||
to={`/~link/` + popout + `members` + props.path}>
|
to={`/~link/` + popout + `members` + props.groupPath}>
|
||||||
Members
|
Members
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="dib" style={{ width: 0 }}></div>
|
<div className="dib" style={{ width: 0 }}></div>
|
||||||
)}
|
)}
|
||||||
<a href={`/~link/popout` + props.path} target="_blank"
|
<a href={`/~link/popout` + props.groupPath} target="_blank"
|
||||||
className="dib fr">
|
className="dib fr">
|
||||||
<img
|
<img
|
||||||
className={`flex-shrink-0 pr4 dn invert-d ` + hidePopoutIcon}
|
className={`flex-shrink-0 pr4 dn invert-d ` + hidePopoutIcon}
|
||||||
|
@ -19,12 +19,12 @@ export class Pagination extends Component {
|
|||||||
return (
|
return (
|
||||||
<div className="w-100 inter relative pv6">
|
<div className="w-100 inter relative pv6">
|
||||||
<div className={prevDisplay + " inter f8"}>
|
<div className={prevDisplay + " inter f8"}>
|
||||||
<Link to={"/~link" + props.popout + props.path + prevPage}>
|
<Link to={"/~link" + props.popout + props.groupPath + prevPage}>
|
||||||
<- Previous Page
|
<- Previous Page
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className={nextDisplay + " inter f8"}>
|
<div className={nextDisplay + " inter f8"}>
|
||||||
<Link to={"/~link" + props.popout + props.path + nextPage}>
|
<Link to={"/~link" + props.popout + props.groupPath + nextPage}>
|
||||||
Next Page ->
|
Next Page ->
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,6 +7,7 @@ import { Sigil } from '/components/lib/icons/sigil';
|
|||||||
import { Comments } from './lib/comments';
|
import { Comments } from './lib/comments';
|
||||||
import { uxToHex } from '../lib/util';
|
import { uxToHex } from '../lib/util';
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
import { base64urlEncode } from '../lib/util';
|
||||||
|
|
||||||
export class LinkDetail extends Component {
|
export class LinkDetail extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -31,7 +32,7 @@ export class LinkDetail extends Component {
|
|||||||
// if we have no preloaded data, and we aren't expecting it, get it
|
// if we have no preloaded data, and we aren't expecting it, get it
|
||||||
if (!this.state.data.title) {
|
if (!this.state.data.title) {
|
||||||
api.getSubmission(
|
api.getSubmission(
|
||||||
this.props.path, this.props.url, this.updateData.bind(this)
|
this.props.groupPath, this.props.url, this.updateData.bind(this)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ export class LinkDetail extends Component {
|
|||||||
let url = this.props.url || "";
|
let url = this.props.url || "";
|
||||||
|
|
||||||
let request = api.postComment(
|
let request = api.postComment(
|
||||||
this.props.path,
|
this.props.groupPath,
|
||||||
url,
|
url,
|
||||||
this.state.comment
|
this.state.comment
|
||||||
);
|
);
|
||||||
@ -81,7 +82,6 @@ export class LinkDetail extends Component {
|
|||||||
render() {
|
render() {
|
||||||
let props = this.props;
|
let props = this.props;
|
||||||
let popout = (props.popout) ? "/popout" : "";
|
let popout = (props.popout) ? "/popout" : "";
|
||||||
let routePath = props.path + "/" + props.page + "/" + props.linkIndex + "/" + window.btoa(props.url);
|
|
||||||
|
|
||||||
const data = this.state.data || props.data;
|
const data = this.state.data || props.data;
|
||||||
let ship = data.ship || "zod";
|
let ship = data.ship || "zod";
|
||||||
@ -128,13 +128,13 @@ export class LinkDetail extends Component {
|
|||||||
popout={props.popout}/>
|
popout={props.popout}/>
|
||||||
<Link
|
<Link
|
||||||
className="dib f8 fw4 v-top pt2 gray2"
|
className="dib f8 fw4 v-top pt2 gray2"
|
||||||
to={"/~link" + popout + props.path + "/" + props.page}>
|
to={"/~link" + popout + props.groupPath + "/" + props.page}>
|
||||||
{"<- Collection index"}
|
{"<- Collection index"}
|
||||||
</Link>
|
</Link>
|
||||||
<LinksTabBar
|
<LinksTabBar
|
||||||
{...props}
|
{...props}
|
||||||
popout={popout}
|
popout={popout}
|
||||||
path={routePath}/>
|
groupPath={props.groupPath}/>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-100 mt2 flex justify-center overflow-y-scroll ph4 pb4">
|
<div className="w-100 mt2 flex justify-center overflow-y-scroll ph4 pb4">
|
||||||
<div className="w-100 mw7">
|
<div className="w-100 mw7">
|
||||||
@ -160,7 +160,7 @@ export class LinkDetail extends Component {
|
|||||||
<span className="f9 inter gray2 pr3 v-mid">
|
<span className="f9 inter gray2 pr3 v-mid">
|
||||||
{this.state.timeSinceLinkPost}
|
{this.state.timeSinceLinkPost}
|
||||||
</span>
|
</span>
|
||||||
<Link to={"/~link" + props.path + "/" + props.page + "/" + props.linkIndex + "/" + window.btoa(props.url)} className="v-top">
|
<Link to={"/~link" + props.path + "/" + props.page + "/" + props.linkIndex + "/" + base64urlEncode(props.url)} className="v-top">
|
||||||
<span className="f9 inter gray2">
|
<span className="f9 inter gray2">
|
||||||
{comments}
|
{comments}
|
||||||
</span>
|
</span>
|
||||||
@ -191,8 +191,8 @@ export class LinkDetail extends Component {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<Comments
|
<Comments
|
||||||
path={props.path}
|
groupPath={props.groupPath}
|
||||||
key={props.path + props.commentPage}
|
key={props.groupPath + props.commentPage}
|
||||||
comments={props.comments}
|
comments={props.comments}
|
||||||
commentPage={props.commentPage}
|
commentPage={props.commentPage}
|
||||||
members={props.members}
|
members={props.members}
|
||||||
|
@ -22,14 +22,13 @@ export class Links extends Component {
|
|||||||
(!this.props.links[linkPage] ||
|
(!this.props.links[linkPage] ||
|
||||||
this.props.links.local[linkPage])
|
this.props.links.local[linkPage])
|
||||||
) {
|
) {
|
||||||
api.getPage(this.props.path, this.props.page);
|
api.getPage(this.props.groupPath, this.props.page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let props = this.props;
|
let props = this.props;
|
||||||
let popout = (props.popout) ? "/popout" : "";
|
let popout = (props.popout) ? "/popout" : "";
|
||||||
let channel = props.path.substr(1);
|
|
||||||
let linkPage = props.page;
|
let linkPage = props.page;
|
||||||
|
|
||||||
let links = !!props.links[linkPage]
|
let links = !!props.links[linkPage]
|
||||||
@ -84,7 +83,7 @@ export class Links extends Component {
|
|||||||
ship={ship}
|
ship={ship}
|
||||||
color={color}
|
color={color}
|
||||||
comments={commentCount}
|
comments={commentCount}
|
||||||
channel={channel}
|
groupPath={props.groupPath}
|
||||||
popout={popout}
|
popout={popout}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@ -106,34 +105,34 @@ export class Links extends Component {
|
|||||||
<SidebarSwitcher
|
<SidebarSwitcher
|
||||||
sidebarShown={props.sidebarShown}
|
sidebarShown={props.sidebarShown}
|
||||||
popout={props.popout}/>
|
popout={props.popout}/>
|
||||||
<Link to={`/~link` + popout + props.path} className="pt2">
|
<Link to={`/~link` + popout + props.groupPath} className="pt2">
|
||||||
<h2
|
<h2
|
||||||
className={`dib f8 fw4 v-top ` +
|
className={`dib f8 fw4 v-top ` +
|
||||||
(props.path.includes("/~/")
|
(props.groupPath.includes("/~/")
|
||||||
? ""
|
? ""
|
||||||
: "mono")}>
|
: "mono")}>
|
||||||
{(props.path.includes("/~/"))
|
{(props.groupPath.includes("/~/"))
|
||||||
? "Private"
|
? "Private"
|
||||||
: channel}
|
: props.groupPath.substr(1)}
|
||||||
</h2>
|
</h2>
|
||||||
</Link>
|
</Link>
|
||||||
<LinksTabBar
|
<LinksTabBar
|
||||||
{...props}
|
{...props}
|
||||||
popout={popout}
|
popout={popout}
|
||||||
path={props.path + "/" + props.page}/>
|
groupPath={props.groupPath + "/" + props.page}/>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-100 mt2 flex justify-center overflow-y-scroll ph4 pb4">
|
<div className="w-100 mt2 flex justify-center overflow-y-scroll ph4 pb4">
|
||||||
<div className="w-100 mw7">
|
<div className="w-100 mw7">
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<LinkSubmit path={props.path}/>
|
<LinkSubmit groupPath={props.groupPath}/>
|
||||||
</div>
|
</div>
|
||||||
<div className="pb4">
|
<div className="pb4">
|
||||||
{LinkList}
|
{LinkList}
|
||||||
<Pagination
|
<Pagination
|
||||||
{...props}
|
{...props}
|
||||||
key={props.path + props.page}
|
key={props.groupPath + props.page}
|
||||||
popout={popout}
|
popout={popout}
|
||||||
path={props.path}
|
groupPath={props.groupPath}
|
||||||
currentPage={currentPage}
|
currentPage={currentPage}
|
||||||
totalPages={totalPages}
|
totalPages={totalPages}
|
||||||
/>
|
/>
|
||||||
|
@ -9,6 +9,7 @@ import { store } from '/store';
|
|||||||
import { Skeleton } from '/components/skeleton';
|
import { Skeleton } from '/components/skeleton';
|
||||||
import { Links } from '/components/links-list';
|
import { Links } from '/components/links-list';
|
||||||
import { LinkDetail } from '/components/link';
|
import { LinkDetail } from '/components/link';
|
||||||
|
import { base64urlDecode } from '../lib/util';
|
||||||
|
|
||||||
|
|
||||||
export class Root extends Component {
|
export class Root extends Component {
|
||||||
@ -91,7 +92,7 @@ export class Root extends Component {
|
|||||||
links={channelLinks}
|
links={channelLinks}
|
||||||
comments={channelComments}
|
comments={channelComments}
|
||||||
page={page}
|
page={page}
|
||||||
path={groupPath}
|
groupPath={groupPath}
|
||||||
popout={popout}
|
popout={popout}
|
||||||
sidebarShown={state.sidebarShown}
|
sidebarShown={state.sidebarShown}
|
||||||
/>
|
/>
|
||||||
@ -110,7 +111,7 @@ export class Root extends Component {
|
|||||||
|
|
||||||
let index = props.match.params.index || 0;
|
let index = props.match.params.index || 0;
|
||||||
let page = props.match.params.page || 0;
|
let page = props.match.params.page || 0;
|
||||||
let url = window.atob(props.match.params.encodedUrl);
|
let url = base64urlDecode(props.match.params.encodedUrl);
|
||||||
|
|
||||||
let data = !!links[groupPath]
|
let data = !!links[groupPath]
|
||||||
? !!links[groupPath][page]
|
? !!links[groupPath][page]
|
||||||
@ -139,7 +140,7 @@ export class Root extends Component {
|
|||||||
url={url}
|
url={url}
|
||||||
linkIndex={index}
|
linkIndex={index}
|
||||||
members={groupMembers}
|
members={groupMembers}
|
||||||
path={groupPath}
|
groupPath={groupPath}
|
||||||
popout={popout}
|
popout={popout}
|
||||||
sidebarShown={state.sidebarShown}
|
sidebarShown={state.sidebarShown}
|
||||||
data={data}
|
data={data}
|
||||||
|
@ -14,11 +14,66 @@ export function uuid() {
|
|||||||
return str.slice(0,-1);
|
return str.slice(0,-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// encodes string into base64url,
|
||||||
|
// by encoding into base64 and replacing non-url-safe characters.
|
||||||
|
//
|
||||||
|
export function base64urlEncode(string) {
|
||||||
|
return window.btoa(string)
|
||||||
|
.split('+').join('-')
|
||||||
|
.split('/').join('_');
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode base64url. inverse of base64urlEncode above.
|
||||||
|
//
|
||||||
|
export function base64urlDecode(string) {
|
||||||
|
return window.atob(
|
||||||
|
string.split('_').join('/')
|
||||||
|
.split('-').join('+')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function isPatTa(str) {
|
export function isPatTa(str) {
|
||||||
const r = /^[a-z,0-9,\-,\.,_,~]+$/.exec(str)
|
const r = /^[a-z,0-9,\-,\.,_,~]+$/.exec(str)
|
||||||
return !!r;
|
return !!r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// encode the string into @ta-safe format, using logic from +wood.
|
||||||
|
// for example, 'some Chars!' becomes '~.some.~43.hars~21.'
|
||||||
|
//
|
||||||
|
export function stringToTa(string) {
|
||||||
|
let out = '';
|
||||||
|
for (let i = 0; i < string.length; i++) {
|
||||||
|
const char = string[i];
|
||||||
|
let add = '';
|
||||||
|
switch (char) {
|
||||||
|
case ' ':
|
||||||
|
add = '.';
|
||||||
|
break;
|
||||||
|
case '.':
|
||||||
|
add = '~.';
|
||||||
|
break;
|
||||||
|
case '~':
|
||||||
|
add = '~~';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
const charCode = string.charCodeAt(i);
|
||||||
|
if (
|
||||||
|
(charCode >= 97 && charCode <= 122) || // a-z
|
||||||
|
(charCode >= 48 && charCode <= 57) || // 0-9
|
||||||
|
char === '-'
|
||||||
|
) {
|
||||||
|
add = char;
|
||||||
|
} else {
|
||||||
|
//TODO behavior for unicode doesn't match +wood's,
|
||||||
|
// but we can probably get away with that for now.
|
||||||
|
add = '~' + charCode.toString(16) + '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out = out + add;
|
||||||
|
}
|
||||||
|
return '~.' + out;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Goes from:
|
Goes from:
|
||||||
~2018.7.17..23.15.09..5be5 // urbit @da
|
~2018.7.17..23.15.09..5be5 // urbit @da
|
||||||
|
Loading…
Reference in New Issue
Block a user