From 9d4675770bdb78da3ebba5c6842dfcb60ebd6dff Mon Sep 17 00:00:00 2001 From: Arinerron Date: Fri, 7 Sep 2018 22:47:56 -0700 Subject: [PATCH] Set a maximum character limit --- .../www/ui/common/onionr-timeline-post.html | 4 +- onionr/static-data/www/ui/compile.py | 14 ++--- onionr/static-data/www/ui/dist/index.html | 10 +++- onionr/static-data/www/ui/dist/js/main.js | 28 ++++++--- onionr/static-data/www/ui/dist/js/timeline.js | 57 +++++++++++++++++-- onionr/static-data/www/ui/lang.json | 4 ++ onionr/static-data/www/ui/src/index.html | 12 +++- onionr/static-data/www/ui/src/js/main.js | 24 ++++++-- onionr/static-data/www/ui/src/js/timeline.js | 57 +++++++++++++++++-- 9 files changed, 178 insertions(+), 32 deletions(-) diff --git a/onionr/static-data/www/ui/common/onionr-timeline-post.html b/onionr/static-data/www/ui/common/onionr-timeline-post.html index 68440a01..05259139 100644 --- a/onionr/static-data/www/ui/common/onionr-timeline-post.html +++ b/onionr/static-data/www/ui/common/onionr-timeline-post.html @@ -22,8 +22,8 @@
- <$= LANG.POST_LIKE $> - <$= LANG.POST_REPLY $> + <$= LANG.POST_LIKE $> + <$= LANG.POST_REPLY $>
diff --git a/onionr/static-data/www/ui/compile.py b/onionr/static-data/www/ui/compile.py index 2667b210..e991af08 100755 --- a/onionr/static-data/www/ui/compile.py +++ b/onionr/static-data/www/ui/compile.py @@ -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) diff --git a/onionr/static-data/www/ui/dist/index.html b/onionr/static-data/www/ui/dist/index.html index ba0c31d4..756f8107 100644 --- a/onionr/static-data/www/ui/dist/index.html +++ b/onionr/static-data/www/ui/dist/index.html @@ -59,6 +59,12 @@
+
+
+

Timeline

+
+
+
@@ -74,7 +80,9 @@
- + + +
diff --git a/onionr/static-data/www/ui/dist/js/main.js b/onionr/static-data/www/ui/dist/js/main.js index 71c80266..561dafb2 100644 --- a/onionr/static-data/www/ui/dist/js/main.js +++ b/onionr/static-data/www/ui/dist/js/main.js @@ -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 {
\ \
\ - like\ - reply\ + like\ + reply\
\ \ \ @@ -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', '
', 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(); } } } diff --git a/onionr/static-data/www/ui/dist/js/timeline.js b/onionr/static-data/www/ui/dist/js/timeline.js index 73e46559..e77b3b47 100644 --- a/onionr/static-data/www/ui/dist/js/timeline.js +++ b/onionr/static-data/www/ui/dist/js/timeline.js @@ -10,11 +10,16 @@ Block.getBlocks({'type' : 'onionr-post', 'signed' : true, 'reverse' : true}, fun var blockContent = JSON.parse(block.getContent()); - post.setContent(blockContent['content']); - post.setPostDate(block.getDate()); - post.setUser(user); + // just ignore anything shorter than 280 characters + if(String(blockContent['content']).length <= 280) { + post.setContent(blockContent['content']); + post.setPostDate(block.getDate()); + post.setUser(user); - document.getElementById('onionr-timeline-posts').innerHTML += post.getHTML(); + 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(); diff --git a/onionr/static-data/www/ui/lang.json b/onionr/static-data/www/ui/lang.json index 872a68cf..06e02194 100644 --- a/onionr/static-data/www/ui/lang.json +++ b/onionr/static-data/www/ui/lang.json @@ -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" }, diff --git a/onionr/static-data/www/ui/src/index.html b/onionr/static-data/www/ui/src/index.html index 99463d27..d64a35d0 100644 --- a/onionr/static-data/www/ui/src/index.html +++ b/onionr/static-data/www/ui/src/index.html @@ -29,6 +29,12 @@
+
+
+

<$= LANG.TIMELINE $>

+
+
+
@@ -40,11 +46,13 @@ - + + +
diff --git a/onionr/static-data/www/ui/src/js/main.js b/onionr/static-data/www/ui/src/js/main.js index ca2c5214..808809ba 100644 --- a/onionr/static-data/www/ui/src/js/main.js +++ b/onionr/static-data/www/ui/src/js/main.js @@ -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', '
', 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(); } } } diff --git a/onionr/static-data/www/ui/src/js/timeline.js b/onionr/static-data/www/ui/src/js/timeline.js index c411f41c..0aea4f28 100644 --- a/onionr/static-data/www/ui/src/js/timeline.js +++ b/onionr/static-data/www/ui/src/js/timeline.js @@ -10,11 +10,16 @@ Block.getBlocks({'type' : 'onionr-post', 'signed' : true, 'reverse' : true}, fun var blockContent = JSON.parse(block.getContent()); - post.setContent(blockContent['content']); - post.setPostDate(block.getDate()); - post.setUser(user); + // just ignore anything shorter than 280 characters + if(String(blockContent['content']).length <= 280) { + post.setContent(blockContent['content']); + post.setPostDate(block.getDate()); + post.setUser(user); - document.getElementById('onionr-timeline-posts').innerHTML += post.getHTML(); + 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();