Set a maximum character limit
parent
7ec869a36f
commit
9d4675770b
|
@ -22,8 +22,8 @@
|
|||
</div>
|
||||
|
||||
<div class="onionr-post-controls pt-2">
|
||||
<a href="#!" onclick="toggleLike('$post-id')" class="glyphicon glyphicon-heart mr-2"><$= LANG.POST_LIKE $></a>
|
||||
<a href="#!" onclick="reply('$post-id')" class="glyphicon glyphicon-comment mr-2"><$= LANG.POST_REPLY $></a>
|
||||
<a href="#!" onclick="toggleLike('$post-hash')" class="glyphicon glyphicon-heart mr-2"><$= LANG.POST_LIKE $></a>
|
||||
<a href="#!" onclick="reply('$post-hash')" class="glyphicon glyphicon-comment mr-2"><$= LANG.POST_REPLY $></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -41,16 +41,16 @@ LANG = type('LANG', (), langmap)
|
|||
|
||||
# templating
|
||||
class Template:
|
||||
def jsTemplate(template):
|
||||
def jsTemplate(template, filename = ''):
|
||||
with open('common/%s.html' % template, 'r') as file:
|
||||
return Template.parseTags(file.read().replace('\\', '\\\\').replace('\'', '\\\'').replace('\n', "\\\n"))
|
||||
return Template.parseTags(file.read().replace('\\', '\\\\').replace('\'', '\\\'').replace('\n', "\\\n"), filename)
|
||||
|
||||
def htmlTemplate(template):
|
||||
def htmlTemplate(template, filename = ''):
|
||||
with open('common/%s.html' % template, 'r') as file:
|
||||
return Template.parseTags(file.read())
|
||||
return Template.parseTags(file.read(), filename)
|
||||
|
||||
# tag parser
|
||||
def parseTags(contents):
|
||||
def parseTags(contents, filename = ''):
|
||||
# <$ logic $>
|
||||
for match in re.findall(r'(<\$(?!=)(.*?)\$>)', contents):
|
||||
try:
|
||||
|
@ -66,7 +66,7 @@ class Template:
|
|||
try:
|
||||
out = eval(match[1].strip())
|
||||
contents = contents.replace(match[0], '' if out is None else str(out))
|
||||
except NameError as e:
|
||||
except (NameError, AttributeError) as e:
|
||||
name = match[1].strip()
|
||||
print('Warning: %s does not exist, treating as an str' % name)
|
||||
contents = contents.replace(match[0], name)
|
||||
|
@ -118,7 +118,7 @@ def iterate(directory):
|
|||
|
||||
# do python tags
|
||||
if settings['python_tags']:
|
||||
contents = Template.parseTags(contents)
|
||||
contents = Template.parseTags(contents, filename)
|
||||
|
||||
# write file
|
||||
file.write(contents)
|
||||
|
|
|
@ -59,6 +59,12 @@
|
|||
|
||||
<div class="col-sm-12 col-lg-6">
|
||||
<div class="row" id="onionr-timeline-post-creator">
|
||||
<div class="col-12">
|
||||
<div class="onionr-timeline">
|
||||
<h2>Timeline</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- POST -->
|
||||
<div class="col-12">
|
||||
<div class="onionr-post-creator">
|
||||
|
@ -74,7 +80,9 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<textarea class="onionr-post-creator-content" id="onionr-post-creator-content"></textarea>
|
||||
<textarea class="onionr-post-creator-content" id="onionr-post-creator-content" oninput="postCreatorChange()"></textarea>
|
||||
|
||||
<div class="onionr-post-creator-content-message" id="onionr-post-creator-content-message"></div>
|
||||
|
||||
<input type="button" onclick="makePost()" title="Create post" value="Create post" id="onionr-post-creator-create" class="onionr-post-creator-create" />
|
||||
</div>
|
||||
|
|
|
@ -115,10 +115,10 @@ function timeSince(date, size) {
|
|||
}
|
||||
|
||||
/* replace all instances of string */
|
||||
String.prototype.replaceAll = function(search, replacement) {
|
||||
String.prototype.replaceAll = function(search, replacement, limit) {
|
||||
// taken from https://stackoverflow.com/a/17606289/3678023
|
||||
var target = this;
|
||||
return target.split(search).join(replacement);
|
||||
return target.split(search, limit).join(replacement);
|
||||
};
|
||||
|
||||
/* useful functions to sanitize data */
|
||||
|
@ -287,8 +287,8 @@ class Post {
|
|||
</div>\
|
||||
\
|
||||
<div class="onionr-post-controls pt-2">\
|
||||
<a href="#!" onclick="toggleLike(\'$post-id\')" class="glyphicon glyphicon-heart mr-2">like</a>\
|
||||
<a href="#!" onclick="reply(\'$post-id\')" class="glyphicon glyphicon-comment mr-2">reply</a>\
|
||||
<a href="#!" onclick="toggleLike(\'$post-hash\')" class="glyphicon glyphicon-heart mr-2">like</a>\
|
||||
<a href="#!" onclick="reply(\'$post-hash\')" class="glyphicon glyphicon-comment mr-2">reply</a>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
|
@ -308,7 +308,8 @@ class Post {
|
|||
|
||||
postTemplate = postTemplate.replaceAll('$user-id', Sanitize.html(this.getUser().getID()));
|
||||
postTemplate = postTemplate.replaceAll('$user-image', "data:image/jpeg;base64," + Sanitize.html(this.getUser().getIcon()));
|
||||
postTemplate = postTemplate.replaceAll('$content', Sanitize.html(this.getContent()));
|
||||
postTemplate = postTemplate.replaceAll('$content', Sanitize.html(this.getContent()).replaceAll('\n', '<br />', 16)); // Maximum of 16 lines
|
||||
postTemplate = postTemplate.replaceAll('$post-hash', this.getHash());
|
||||
postTemplate = postTemplate.replaceAll('$date-relative', timeSince(this.getPostDate(), device) + (device === 'desktop' ? ' ago' : ''));
|
||||
postTemplate = postTemplate.replaceAll('$date', this.getPostDate().toLocaleString());
|
||||
|
||||
|
@ -342,6 +343,14 @@ class Post {
|
|||
return this.date;
|
||||
}
|
||||
|
||||
setHash(hash) {
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
getHash() {
|
||||
return this.hash;
|
||||
}
|
||||
|
||||
save(callback) {
|
||||
var args = {'type' : 'onionr-post', 'sign' : true, 'content' : JSON.stringify({'content' : this.getContent()})};
|
||||
|
||||
|
@ -354,8 +363,11 @@ class Post {
|
|||
if(callback !== undefined) {
|
||||
// async
|
||||
|
||||
var thisObject = this;
|
||||
|
||||
http.addEventListener('load', function() {
|
||||
callback(Block.parseBlockArray(JSON.parse(http.responseText)['hash']));
|
||||
thisObject.setHash(Block.parseBlockArray(JSON.parse(http.responseText)['hash']));
|
||||
callback(thisObject.getHash());
|
||||
}, false);
|
||||
|
||||
http.open('GET', url, true);
|
||||
|
@ -367,7 +379,9 @@ class Post {
|
|||
http.open('GET', url, false);
|
||||
http.send(null);
|
||||
|
||||
return Block.parseBlockArray(JSON.parse(http.responseText)['hash']);
|
||||
this.setHash(Block.parseBlockArray(JSON.parse(http.responseText)['hash']));
|
||||
|
||||
return this.getHash();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,16 @@ Block.getBlocks({'type' : 'onionr-post', 'signed' : true, 'reverse' : true}, fun
|
|||
|
||||
var blockContent = JSON.parse(block.getContent());
|
||||
|
||||
// just ignore anything shorter than 280 characters
|
||||
if(String(blockContent['content']).length <= 280) {
|
||||
post.setContent(blockContent['content']);
|
||||
post.setPostDate(block.getDate());
|
||||
post.setUser(user);
|
||||
|
||||
post.setHash(block.getHash());
|
||||
|
||||
document.getElementById('onionr-timeline-posts').innerHTML += post.getHTML();
|
||||
}
|
||||
|
||||
finished = true;
|
||||
});
|
||||
|
@ -27,6 +32,47 @@ Block.getBlocks({'type' : 'onionr-post', 'signed' : true, 'reverse' : true}, fun
|
|||
}
|
||||
});
|
||||
|
||||
function postCreatorChange() {
|
||||
var content = document.getElementById('onionr-post-creator-content').value;
|
||||
var message = '';
|
||||
|
||||
var disable = true;
|
||||
|
||||
if(content.length !== 0) {
|
||||
if(content.length - content.replaceAll('\n', '').length > 16) {
|
||||
// 16 max newlines
|
||||
message = 'Please use less than 16 newlines';
|
||||
} else if(content.length <= 280) {
|
||||
// 280 max characters
|
||||
message = '%s characters remaining'.replaceAll('%s', (280 - content.length));
|
||||
disable = false;
|
||||
} else {
|
||||
message = '%s characters over maximum'.replaceAll('%s', (content.length - 280));
|
||||
}
|
||||
}
|
||||
|
||||
var element = document.getElementById('onionr-post-creator-content-message');
|
||||
var button = document.getElementById("onionr-post-creator-create");
|
||||
|
||||
if(message === '')
|
||||
element.style.display = 'none';
|
||||
else {
|
||||
element.style.display = 'block';
|
||||
|
||||
element.innerHTML = message;
|
||||
|
||||
if(disable)
|
||||
element.style.color = 'red';
|
||||
else
|
||||
element.style.color = 'gray';
|
||||
}
|
||||
|
||||
if(disable)
|
||||
button.disabled = true;
|
||||
else
|
||||
button.disabled = false;
|
||||
}
|
||||
|
||||
function viewProfile(id, name) {
|
||||
id = decodeURIComponent(id);
|
||||
document.getElementById("onionr-profile-username").innerHTML = Sanitize.html(decodeURIComponent(name));
|
||||
|
@ -129,3 +175,6 @@ viewCurrentProfile = function() {
|
|||
|
||||
document.getElementById("onionr-post-creator-user-id").onclick = viewCurrentProfile;
|
||||
document.getElementById("onionr-post-creator-user-name").onclick = viewCurrentProfile;
|
||||
|
||||
// on some browsers it saves the user input on reload. So, it should also recheck the input.
|
||||
postCreatorChange();
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
"POST_CREATOR_PLACEHOLDER" : "Enter a message here...",
|
||||
"POST_CREATOR_CREATE" : "Create post",
|
||||
|
||||
"POST_CREATOR_MESSAGE_MAXIMUM_NEWLINES" : "Please use less than 16 newlines",
|
||||
"POST_CREATOR_MESSAGE_REMAINING" : "%s characters remaining",
|
||||
"POST_CREATOR_MESSAGE_OVER" : "%s characters over maximum",
|
||||
|
||||
"PROFILE_EDIT_SAVE" : "Save",
|
||||
"PROFILE_EDIT_CANCEL" : "Cancel"
|
||||
},
|
||||
|
|
|
@ -29,6 +29,12 @@
|
|||
|
||||
<div class="col-sm-12 col-lg-6">
|
||||
<div class="row" id="onionr-timeline-post-creator">
|
||||
<div class="col-12">
|
||||
<div class="onionr-timeline">
|
||||
<h2><$= LANG.TIMELINE $></h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- POST -->
|
||||
<div class="col-12">
|
||||
<div class="onionr-post-creator">
|
||||
|
@ -40,11 +46,13 @@
|
|||
<div class="row">
|
||||
<div class="col col-auto">
|
||||
<a class="onionr-post-creator-user-name" id="onionr-post-creator-user-name" href="#!" onclick="viewProfile('$user-id-url', '$user-name-url')"></a>
|
||||
<a class="onionr-post-creator-user-id" id="onionr-post-creator-user-id" href="#!" onclick="viewProfile('$user-id-url', '$user-name-url')" data-placement="top" data-toggle="tooltip" title="$user-id">you</a>
|
||||
<a class="onionr-post-creator-user-id" id="onionr-post-creator-user-id" href="#!" onclick="viewProfile('$user-id-url', '$user-name-url')" data-placement="top" data-toggle="tooltip" title="$user-id"><$= LANG.POST_CREATOR_YOU $></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<textarea class="onionr-post-creator-content" id="onionr-post-creator-content"></textarea>
|
||||
<textarea class="onionr-post-creator-content" id="onionr-post-creator-content" oninput="postCreatorChange()"></textarea>
|
||||
|
||||
<div class="onionr-post-creator-content-message" id="onionr-post-creator-content-message"></div>
|
||||
|
||||
<input type="button" onclick="makePost()" title="<$= LANG.POST_CREATOR_CREATE $>" value="<$= LANG.POST_CREATOR_CREATE $>" id="onionr-post-creator-create" class="onionr-post-creator-create" />
|
||||
</div>
|
||||
|
|
|
@ -115,10 +115,10 @@ function timeSince(date, size) {
|
|||
}
|
||||
|
||||
/* replace all instances of string */
|
||||
String.prototype.replaceAll = function(search, replacement) {
|
||||
String.prototype.replaceAll = function(search, replacement, limit) {
|
||||
// taken from https://stackoverflow.com/a/17606289/3678023
|
||||
var target = this;
|
||||
return target.split(search).join(replacement);
|
||||
return target.split(search, limit).join(replacement);
|
||||
};
|
||||
|
||||
/* useful functions to sanitize data */
|
||||
|
@ -276,7 +276,8 @@ class Post {
|
|||
|
||||
postTemplate = postTemplate.replaceAll('$user-id', Sanitize.html(this.getUser().getID()));
|
||||
postTemplate = postTemplate.replaceAll('$user-image', "data:image/jpeg;base64," + Sanitize.html(this.getUser().getIcon()));
|
||||
postTemplate = postTemplate.replaceAll('$content', Sanitize.html(this.getContent()));
|
||||
postTemplate = postTemplate.replaceAll('$content', Sanitize.html(this.getContent()).replaceAll('\n', '<br />', 16)); // Maximum of 16 lines
|
||||
postTemplate = postTemplate.replaceAll('$post-hash', this.getHash());
|
||||
postTemplate = postTemplate.replaceAll('$date-relative', timeSince(this.getPostDate(), device) + (device === 'desktop' ? ' ago' : ''));
|
||||
postTemplate = postTemplate.replaceAll('$date', this.getPostDate().toLocaleString());
|
||||
|
||||
|
@ -310,6 +311,14 @@ class Post {
|
|||
return this.date;
|
||||
}
|
||||
|
||||
setHash(hash) {
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
getHash() {
|
||||
return this.hash;
|
||||
}
|
||||
|
||||
save(callback) {
|
||||
var args = {'type' : 'onionr-post', 'sign' : true, 'content' : JSON.stringify({'content' : this.getContent()})};
|
||||
|
||||
|
@ -322,8 +331,11 @@ class Post {
|
|||
if(callback !== undefined) {
|
||||
// async
|
||||
|
||||
var thisObject = this;
|
||||
|
||||
http.addEventListener('load', function() {
|
||||
callback(Block.parseBlockArray(JSON.parse(http.responseText)['hash']));
|
||||
thisObject.setHash(Block.parseBlockArray(JSON.parse(http.responseText)['hash']));
|
||||
callback(thisObject.getHash());
|
||||
}, false);
|
||||
|
||||
http.open('GET', url, true);
|
||||
|
@ -335,7 +347,9 @@ class Post {
|
|||
http.open('GET', url, false);
|
||||
http.send(null);
|
||||
|
||||
return Block.parseBlockArray(JSON.parse(http.responseText)['hash']);
|
||||
this.setHash(Block.parseBlockArray(JSON.parse(http.responseText)['hash']));
|
||||
|
||||
return this.getHash();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,16 @@ Block.getBlocks({'type' : 'onionr-post', 'signed' : true, 'reverse' : true}, fun
|
|||
|
||||
var blockContent = JSON.parse(block.getContent());
|
||||
|
||||
// just ignore anything shorter than 280 characters
|
||||
if(String(blockContent['content']).length <= 280) {
|
||||
post.setContent(blockContent['content']);
|
||||
post.setPostDate(block.getDate());
|
||||
post.setUser(user);
|
||||
|
||||
post.setHash(block.getHash());
|
||||
|
||||
document.getElementById('onionr-timeline-posts').innerHTML += post.getHTML();
|
||||
}
|
||||
|
||||
finished = true;
|
||||
});
|
||||
|
@ -27,6 +32,47 @@ Block.getBlocks({'type' : 'onionr-post', 'signed' : true, 'reverse' : true}, fun
|
|||
}
|
||||
});
|
||||
|
||||
function postCreatorChange() {
|
||||
var content = document.getElementById('onionr-post-creator-content').value;
|
||||
var message = '';
|
||||
|
||||
var disable = true;
|
||||
|
||||
if(content.length !== 0) {
|
||||
if(content.length - content.replaceAll('\n', '').length > 16) {
|
||||
// 16 max newlines
|
||||
message = '<$= LANG.POST_CREATOR_MESSAGE_MAXIMUM_NEWLINES $>';
|
||||
} else if(content.length <= 280) {
|
||||
// 280 max characters
|
||||
message = '<$= LANG.POST_CREATOR_MESSAGE_REMAINING $>'.replaceAll('%s', (280 - content.length));
|
||||
disable = false;
|
||||
} else {
|
||||
message = '<$= LANG.POST_CREATOR_MESSAGE_OVER $>'.replaceAll('%s', (content.length - 280));
|
||||
}
|
||||
}
|
||||
|
||||
var element = document.getElementById('onionr-post-creator-content-message');
|
||||
var button = document.getElementById("onionr-post-creator-create");
|
||||
|
||||
if(message === '')
|
||||
element.style.display = 'none';
|
||||
else {
|
||||
element.style.display = 'block';
|
||||
|
||||
element.innerHTML = message;
|
||||
|
||||
if(disable)
|
||||
element.style.color = 'red';
|
||||
else
|
||||
element.style.color = 'gray';
|
||||
}
|
||||
|
||||
if(disable)
|
||||
button.disabled = true;
|
||||
else
|
||||
button.disabled = false;
|
||||
}
|
||||
|
||||
function viewProfile(id, name) {
|
||||
id = decodeURIComponent(id);
|
||||
document.getElementById("onionr-profile-username").innerHTML = Sanitize.html(decodeURIComponent(name));
|
||||
|
@ -129,3 +175,6 @@ viewCurrentProfile = function() {
|
|||
|
||||
document.getElementById("onionr-post-creator-user-id").onclick = viewCurrentProfile;
|
||||
document.getElementById("onionr-post-creator-user-name").onclick = viewCurrentProfile;
|
||||
|
||||
// on some browsers it saves the user input on reload. So, it should also recheck the input.
|
||||
postCreatorChange();
|
||||
|
|
Loading…
Reference in New Issue