work on contact manager, removed old twitter-like ui for now
This commit is contained in:
parent
4827ef6def
commit
3fc623b8ee
29 changed files with 38 additions and 3562 deletions
|
@ -21,7 +21,8 @@ import sqlite3, os, sys, time, math, base64, tarfile, nacl, logger, json, netcon
|
|||
from onionrblockapi import Block
|
||||
|
||||
import onionrutils, onionrcrypto, onionrproofs, onionrevents as events, onionrexceptions
|
||||
import onionrblacklist, onionrusers
|
||||
import onionrblacklist
|
||||
from onionrusers import onionrusers
|
||||
import dbcreator, onionrstorage, serializeddata
|
||||
from etc import onionrvalues
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ MIN_PY_VERSION = 6
|
|||
if sys.version_info[0] == 2 or sys.version_info[1] < MIN_PY_VERSION:
|
||||
print('Error, Onionr requires Python 3.%s+' % (MIN_PY_VERSION,))
|
||||
sys.exit(1)
|
||||
import os, base64, random, getpass, shutil, subprocess, requests, time, platform, datetime, re, json, getpass, sqlite3
|
||||
import os, base64, random, getpass, shutil, time, platform, datetime, re, json, getpass, sqlite3
|
||||
import webbrowser, uuid, signal
|
||||
from threading import Thread
|
||||
import api, core, config, logger, onionrplugins as plugins, onionrevents as events
|
||||
|
@ -33,7 +33,8 @@ import onionrutils
|
|||
import netcontroller, onionrstorage
|
||||
from netcontroller import NetController
|
||||
from onionrblockapi import Block
|
||||
import onionrproofs, onionrexceptions, onionrusers, communicator
|
||||
import onionrproofs, onionrexceptions, communicator
|
||||
from onionrusers import onionrusers
|
||||
|
||||
try:
|
||||
from urllib3.contrib.socks import SOCKSProxyManager
|
||||
|
|
|
@ -18,8 +18,9 @@
|
|||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
'''
|
||||
|
||||
import core as onionrcore, logger, config, onionrexceptions, nacl.exceptions, onionrusers
|
||||
import core as onionrcore, logger, config, onionrexceptions, nacl.exceptions
|
||||
import json, os, sys, datetime, base64, onionrstorage
|
||||
from onionrusers import onionrusers
|
||||
|
||||
class Block:
|
||||
blockCacheOrder = list() # NEVER write your own code that writes to this!
|
||||
|
|
30
onionr/onionrusers/contactmanager.py
Normal file
30
onionr/onionrusers/contactmanager.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
'''
|
||||
Onionr - P2P Anonymous Storage Network
|
||||
|
||||
Sets more abstract information related to a peer. Can be thought of as traditional 'contact' system
|
||||
'''
|
||||
'''
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
'''
|
||||
|
||||
import onionrusers
|
||||
|
||||
class ContactManager(onionrusers.OnionrUser):
|
||||
def set_info(self, key, value):
|
||||
return
|
||||
def add_contact(self):
|
||||
return
|
||||
def delete_contact(self):
|
||||
return
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
# Onionr UI
|
||||
|
||||
## About
|
||||
|
||||
The default GUI for Onionr
|
||||
|
||||
## Setup
|
||||
|
||||
To compile the application, simply execute the following:
|
||||
|
||||
```
|
||||
python3 compile.py
|
||||
```
|
||||
|
||||
If you are wanting to compile Onionr UI for another language, execute the following, replacing `[lang]` with the target language (supported languages include `eng` for English, `spa` para español, and `zho`为中国人):
|
||||
|
||||
```
|
||||
python3 compile.py [lang]
|
||||
```
|
||||
|
||||
## FAQ
|
||||
### Why "compile" anyway?
|
||||
This web application is compiled for a few reasons:
|
||||
1. To make it easier to update; this way, we do not have to update the header in every file if we want to change something about it.
|
||||
2. To make the application smaller in size; there is less duplicated code when the code like the header and footer can be stored in an individual file rather than every file.
|
||||
3. For multi-language support; with the Python "tags" feature, we can reference strings by variable name, and based on a language file, they can be dynamically inserted into the page on compilation.
|
||||
4. For compile-time customizations.
|
||||
|
||||
### What exactly happens when you compile?
|
||||
Upon compilation, files from the `src/` directory will be copied to `dist/` directory, header and footers will be injected in the proper places, and Python "tags" will be interpreted.
|
||||
|
||||
|
||||
### How do Python "tags" work?
|
||||
There are two types of Python "tags":
|
||||
1. Logic tags (`<$ logic $>`): These tags allow you to perform logic at compile time. Example: `<$ import datetime; lastUpdate = datetime.datetime.now() $>`: This gets the current time while compiling, then stores it in `lastUpdate`.
|
||||
2. Data tags (`<$= data $>`): These tags take whatever the return value of the statement in the tags is, and write it directly to the page. Example: `<$= 'This application was compiled at %s.' % lastUpdate $>`: This will write the message in the string in the tags to the page.
|
||||
|
||||
**Note:** Logic tags take a higher priority and will always be interpreted first.
|
||||
|
||||
### How does the language feature work?
|
||||
When you use a data tag to write a string to the page (e.g. `<$= LANG.HELLO_WORLD $>`), the language feature simply takes dictionary of the language that is currently being used from the language map file (`lang.json`), then searches for the key (being the variable name after the characters `LANG.` in the data tag, like `HELLO_WORLD` from the example before). It then writes that string to the page. Language variables are always prefixed with `LANG.` and should always be uppercase (as they are a constant).
|
||||
|
||||
### I changed a few things in the application and tried to view the updates in my browser, but nothing changed!
|
||||
You most likely forgot to compile. Try running `python3 compile.py` and check again. If you are still having issues, [open up an issue](https://gitlab.com/beardog/Onionr/issues/new?issue[title]=Onionr UI not updating after compiling).
|
File diff suppressed because one or more lines are too long
|
@ -1,19 +0,0 @@
|
|||
<!-- Modal -->
|
||||
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="modal-title" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="modal-title"><$= LANG.MODAL_TITLE $></h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" id="modal-content"><$= LANG.MODAL_MESSAGE $></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
|
||||
<script src="js/main.js"></script>
|
|
@ -1,30 +0,0 @@
|
|||
<title><$= LANG.ONIONR_TITLE $></title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous" />
|
||||
<link rel="stylesheet" type="text/css" href="css/main.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/themes/dark.css" />
|
||||
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
|
||||
<a class="navbar-brand" href="#">Onionr</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="index.html"><$= LANG.TIMELINE $></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="notifications.html"><$= LANG.NOTIFICATIONS $></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="messages.html"><$= LANG.MESSAGES $></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
|
@ -1,31 +0,0 @@
|
|||
<!-- POST REPLIES -->
|
||||
<div class="onionr-post-creator">
|
||||
<div class="row">
|
||||
<div class="onionr-reply-creator container">
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<img class="onionr-post-creator-user-icon" id="onionr-reply-creator-user-icon">
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<div class="row">
|
||||
<div class="col col-auto">
|
||||
<a class="onionr-post-creator-user-name" id="onionr-reply-creator-user-name" href="#!" onclick="viewProfile('$user-id-url', '$user-name-url')"></a>
|
||||
<a class="onionr-post-creator-user-id" id="onionr-reply-creator-user-id" href="#!" onclick="viewProfile('$user-id-url', '$user-name-url')" data-placement="top" data-toggle="tooltip" title="$user-id"><$= LANG.REPLY_CREATOR_YOU $></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<textarea class="onionr-post-creator-content" id="onionr-reply-creator-content" oninput="replyCreatorChange()"></textarea>
|
||||
|
||||
<div class="onionr-post-creator-content-message" id="onionr-reply-creator-content-message"></div>
|
||||
|
||||
<input type="button" onclick="makeReply()" title="<$= LANG.REPLY_CREATOR_CREATE $>" value="<$= LANG.REPLY_CREATOR_CREATE $>" id="onionr-reply-creator-create" class="onionr-post-creator-create" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div id="onionr-replies"></div>
|
||||
</div>
|
||||
<!-- END POST REPLIES -->
|
|
@ -1,32 +0,0 @@
|
|||
<!-- POST -->
|
||||
<div class="col-12">
|
||||
<div class="onionr-post" id="onionr-post-$post-hash" onclick="focusPost('$post-hash', 'user-id-url', 'user-name-url', '')">
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
<img class="onionr-post-user-icon" src="$user-image">
|
||||
</div>
|
||||
<div class="col-10">
|
||||
<div class="row">
|
||||
<div class="col col-auto">
|
||||
<a class="onionr-post-user-name" id="onionr-post-user-name" href="#!" onclick="viewProfile('$user-id-url', '$user-name-url')">$user-name</a>
|
||||
<a class="onionr-post-user-id" id="onionr-post-user-id" href="#!" onclick="viewProfile('$user-id-url', '$user-name-url')" data-placement="top" data-toggle="tooltip" title="$user-id">$user-id-truncated</a>
|
||||
</div>
|
||||
|
||||
<div class="col col-auto text-right ml-auto pl-0">
|
||||
<div class="onionr-post-date text-right" data-placement="top" data-toggle="tooltip" title="$date">$date-relative</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="onionr-post-content">
|
||||
$content
|
||||
</div>
|
||||
|
||||
<div class="onionr-post-controls pt-2">
|
||||
<a href="#!" onclick="toggleLike('$post-hash')" class="glyphicon glyphicon-heart mr-2">$liked</a>
|
||||
<a href="#!" onclick="reply('$post-hash')" class="glyphicon glyphicon-comment mr-2"><$= LANG.POST_REPLY $></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END POST -->
|
|
@ -1,30 +0,0 @@
|
|||
<!-- POST FOCUS REPLIES -->
|
||||
<div class="col-12">
|
||||
<div class="row">
|
||||
<div class="onionr-post-focus-reply-creator">
|
||||
<div class="row">
|
||||
<div class="col-1"></div>
|
||||
<div class="col-2">
|
||||
<img class="onionr-post-creator-user-icon" id="onionr-post-focus-reply-creator-user-icon">
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<div class="row">
|
||||
<div class="col col-auto">
|
||||
<a class="onionr-post-creator-user-name" id="onionr-post-focus-reply-creator-user-name" href="#!" onclick="viewProfile('$user-id-url', '$user-name-url')"></a>
|
||||
<a class="onionr-post-creator-user-id" id="onionr-post-focus-reply-creator-user-id" href="#!" onclick="viewProfile('$user-id-url', '$user-name-url')" data-placement="top" data-toggle="tooltip" title="$user-id"><$= LANG.REPLY_CREATOR_YOU $></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<textarea class="onionr-post-creator-content" id="onionr-post-focus-reply-creator-content" oninput="focusReplyCreatorChange()"></textarea>
|
||||
|
||||
<div class="onionr-post-creator-content-message" id="onionr-post-focus-reply-creator-content-message"></div>
|
||||
|
||||
<input type="button" onclick="makeFocusReply()" title="<$= LANG.REPLY_CREATOR_CREATE $>" value="<$= LANG.REPLY_CREATOR_CREATE $>" id="onionr-post-focus-reply-creator-create" class="onionr-post-creator-create" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="onionr-post-focus-replies"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END POST FOCUS REPLIES -->
|
|
@ -1,31 +0,0 @@
|
|||
<!-- POST -->
|
||||
<div class="col-12">
|
||||
<div class="onionr-post" id="onionr-post-$post-hash" onclick="focusPost('$post-hash', 'user-id-url', 'user-name-url', '')">
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<img class="onionr-post-user-icon" src="$user-image">
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<div class="row">
|
||||
<div class="col col-auto">
|
||||
<a class="onionr-post-user-name" id="onionr-post-user-name" href="#!" onclick="viewProfile('$user-id-url', '$user-name-url')">$user-name</a>
|
||||
</div>
|
||||
|
||||
<div class="col col-auto text-right ml-auto pl-0">
|
||||
<div class="onionr-post-date text-right" data-placement="top" data-toggle="tooltip" title="$date">$date-relative-truncated</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="onionr-post-content">
|
||||
$content
|
||||
</div>
|
||||
|
||||
<div class="onionr-post-controls pt-2">
|
||||
<a href="#!" onclick="toggleLike('$post-hash')" class="glyphicon glyphicon-heart mr-2">$liked</a>
|
||||
<a href="#!" onclick="reply('$post-hash')" class="glyphicon glyphicon-comment mr-2"><$= LANG.POST_REPLY $></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END POST -->
|
|
@ -1,130 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import shutil, os, re, json, traceback
|
||||
|
||||
# get user's config
|
||||
settings = {}
|
||||
with open('config.json', 'r') as file:
|
||||
settings = json.loads(file.read())
|
||||
|
||||
# "hardcoded" config, not for user to mess with
|
||||
HEADER_FILE = 'common/header.html'
|
||||
FOOTER_FILE = 'common/footer.html'
|
||||
SRC_DIR = 'src/'
|
||||
DST_DIR = 'dist/'
|
||||
HEADER_STRING = '<header />'
|
||||
FOOTER_STRING = '<footer />'
|
||||
|
||||
# remove dst folder
|
||||
shutil.rmtree(DST_DIR, ignore_errors=True)
|
||||
|
||||
# taken from https://stackoverflow.com/questions/1868714/how-do-i-copy-an-entire-directory-of-files-into-an-existing-directory-using-pyth
|
||||
def copytree(src, dst, symlinks=False, ignore=None):
|
||||
for item in os.listdir(src):
|
||||
s = os.path.join(src, item)
|
||||
d = os.path.join(dst, item)
|
||||
if os.path.isdir(s):
|
||||
shutil.copytree(s, d, symlinks, ignore)
|
||||
else:
|
||||
shutil.copy2(s, d)
|
||||
|
||||
# copy src to dst
|
||||
copytree(SRC_DIR, DST_DIR, False)
|
||||
|
||||
# load in lang map
|
||||
langmap = {}
|
||||
|
||||
with open('lang.json', 'r') as file:
|
||||
langmap = json.loads(file.read())[settings['language']]
|
||||
|
||||
LANG = type('LANG', (), langmap)
|
||||
|
||||
# templating
|
||||
class Template:
|
||||
def jsTemplate(template, filename = ''):
|
||||
with open('common/%s.html' % template, 'r') as file:
|
||||
return Template.parseTags(file.read().replace('\\', '\\\\').replace('\'', '\\\'').replace('\n', "\\\n"), filename)
|
||||
|
||||
def htmlTemplate(template, filename = ''):
|
||||
with open('common/%s.html' % template, 'r') as file:
|
||||
return Template.parseTags(file.read(), filename)
|
||||
|
||||
# tag parser
|
||||
def parseTags(contents, filename = ''):
|
||||
# <$ logic $>
|
||||
for match in re.findall(r'(<\$(?!=)(.*?)\$>)', contents):
|
||||
try:
|
||||
out = exec(match[1].strip())
|
||||
contents = contents.replace(match[0], '' if out is None else str(out))
|
||||
except Exception as e:
|
||||
print('Error: Failed to execute python tag (%s): %s\n' % (filename, match[1]))
|
||||
traceback.print_exc()
|
||||
print('\nIgnoring this error, continuing to compile...\n')
|
||||
|
||||
# <$= data $>
|
||||
for match in re.findall(r'(<\$=(.*?)\$>)', contents):
|
||||
try:
|
||||
out = eval(match[1].strip())
|
||||
contents = contents.replace(match[0], '' if out is None else str(out))
|
||||
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)
|
||||
except Exception as e:
|
||||
print('Error: Failed to execute python tag (%s): %s\n' % (filename, match[1]))
|
||||
traceback.print_exc()
|
||||
print('\nIgnoring this error, continuing to compile...\n')
|
||||
|
||||
return contents
|
||||
|
||||
def jsTemplate(contents):
|
||||
return Template.jsTemplate(contents)
|
||||
|
||||
def htmlTemplate(contents):
|
||||
return Template.htmlTemplate(contents)
|
||||
|
||||
# get header file
|
||||
with open(HEADER_FILE, 'r') as file:
|
||||
HEADER_FILE = file.read()
|
||||
if settings['python_tags']:
|
||||
HEADER_FILE = Template.parseTags(HEADER_FILE)
|
||||
|
||||
# get footer file
|
||||
with open(FOOTER_FILE, 'r') as file:
|
||||
FOOTER_FILE = file.read()
|
||||
if settings['python_tags']:
|
||||
FOOTER_FILE = Template.parseTags(FOOTER_FILE)
|
||||
|
||||
# iterate dst, replace files
|
||||
def iterate(directory):
|
||||
for filename in os.listdir(directory):
|
||||
if filename.split('.')[-1].lower() in ['htm', 'html', 'css', 'js']:
|
||||
try:
|
||||
path = os.path.join(directory, filename)
|
||||
if os.path.isdir(path):
|
||||
iterate(path)
|
||||
else:
|
||||
contents = ''
|
||||
with open(path, 'r') as file:
|
||||
# get file contents
|
||||
contents = file.read()
|
||||
|
||||
os.remove(path)
|
||||
|
||||
with open(path, 'w') as file:
|
||||
# set the header & footer
|
||||
contents = contents.replace(HEADER_STRING, HEADER_FILE)
|
||||
contents = contents.replace(FOOTER_STRING, FOOTER_FILE)
|
||||
|
||||
# do python tags
|
||||
if settings['python_tags']:
|
||||
contents = Template.parseTags(contents, filename)
|
||||
|
||||
# write file
|
||||
file.write(contents)
|
||||
except Exception as e:
|
||||
print('Error: Failed to parse file: %s\n' % filename)
|
||||
traceback.print_exc()
|
||||
print('\nIgnoring this error, continuing to compile...\n')
|
||||
|
||||
iterate(DST_DIR)
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"language" : "eng",
|
||||
"python_tags" : true
|
||||
}
|
122
onionr/static-data/www/ui/dist/css/main.css
vendored
122
onionr/static-data/www/ui/dist/css/main.css
vendored
|
@ -1,122 +0,0 @@
|
|||
/* general formatting */
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.container-small {
|
||||
width: 300px;
|
||||
}
|
||||
.container-large {
|
||||
width: 970px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.container-small {
|
||||
width: 500px;
|
||||
}
|
||||
.container-large {
|
||||
width: 1170px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
.container-small {
|
||||
width: 700px;
|
||||
}
|
||||
.container-large {
|
||||
width: 1500px;
|
||||
}
|
||||
}
|
||||
|
||||
.container-small, .container-large {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* navbar */
|
||||
|
||||
body {
|
||||
margin-top: 5rem;
|
||||
}
|
||||
|
||||
/* timeline */
|
||||
|
||||
.onionr-post-focus-separator {
|
||||
width: 100%;
|
||||
|
||||
padding: 1rem;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.onionr-post {
|
||||
padding: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.onionr-post-user-name {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.onionr-post-user-id:before { content: "("; }
|
||||
.onionr-post-user-id:after { content: ")"; }
|
||||
|
||||
.onionr-post-content {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.onionr-post-user-icon {
|
||||
border-radius: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.onionr-post-creator {
|
||||
padding: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.onionr-post-creator-user-name {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.onionr-post-creator-user-id:before { content: "("; }
|
||||
.onionr-post-creator-user-id:after { content: ")"; }
|
||||
|
||||
.onionr-post-creator-content {
|
||||
word-wrap: break-word;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.onionr-post-creator-user-icon {
|
||||
border-radius: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.onionr-post-creator-create {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.h-divider {
|
||||
margin: 5px 15px;
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* profile */
|
||||
|
||||
.onionr-profile-user-icon {
|
||||
border-radius: 100%;
|
||||
width: 100%;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.onionr-profile-username {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.onionr-profile-save {
|
||||
width: 100%;
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
body {
|
||||
background-color: #96928f;
|
||||
color: #25383C;
|
||||
}
|
||||
|
||||
/* timeline */
|
||||
|
||||
.onionr-post-focus-separator {
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
border: 1px solid black;
|
||||
border-radius: 1rem;
|
||||
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
.onionr-post {
|
||||
border: 1px solid black;
|
||||
border-radius: 1rem;
|
||||
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
.onionr-post-user-name {
|
||||
color: green;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.onionr-post-user-id {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.onionr-post-date {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.onionr-post-content {
|
||||
font-family: sans-serif, serif;
|
||||
border-top: 1px solid black;
|
||||
font-size: 15pt;
|
||||
}
|
||||
|
||||
.onionr-post-creator {
|
||||
border: 1px solid black;
|
||||
border-radius: 1rem;
|
||||
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
.onionr-post-creator-user-name {
|
||||
color: green;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.onionr-post-creator-user-id {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.onionr-post-creator-date {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.onionr-post-creator-content {
|
||||
font-family: sans-serif, serif;
|
||||
border-top: 1px solid black;
|
||||
font-size: 15pt;
|
||||
background-color: lightgray;
|
||||
color: black;
|
||||
border-width: 0px;
|
||||
}
|
||||
|
||||
.h-divider {
|
||||
border-top:1px solid gray;
|
||||
}
|
BIN
onionr/static-data/www/ui/dist/img/default.png
vendored
BIN
onionr/static-data/www/ui/dist/img/default.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 6.6 KiB |
215
onionr/static-data/www/ui/dist/index.html
vendored
215
onionr/static-data/www/ui/dist/index.html
vendored
|
@ -1,215 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Onionr UI</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous" />
|
||||
<link rel="stylesheet" type="text/css" href="css/main.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/themes/dark.css" />
|
||||
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
|
||||
<a class="navbar-brand" href="#">Onionr</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="index.html">Timeline</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="notifications.html">Notifications</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="messages.html">Messages</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12 col-lg-3">
|
||||
<div class="onionr-profile">
|
||||
<div class="row">
|
||||
<div class="col-4 col-lg-12">
|
||||
<img id="onionr-profile-user-icon" class="onionr-profile-user-icon" src="">
|
||||
</div>
|
||||
<div class="col-8 col-lg-12">
|
||||
<h2 maxlength="25" id="onionr-profile-username" class="onionr-profile-username text-left text-lg-center text-sm-left" data-placement="top" data-toggle="tooltip" title="unknown" data-editable></h2>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<p maxlength="128" id="onionr-profile-description" class="onionr-profile-description" data-editable></p>
|
||||
</div>
|
||||
|
||||
<div class="col-12 onionr-profile-edit" id="onionr-profile-edit" style="display: none">
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-lg-12">
|
||||
<input type="button" onclick="updateUser()" class="onionr-profile-save text-center" id="onionr-profile-save" value="Save" />
|
||||
</div>
|
||||
<div class="col-sm-6 col-lg-12">
|
||||
<input type="button" onclick="cancelUpdate()" class="onionr-profile-save text-center" id="onionr-profile-cancel" value="Cancel" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="h-divider pb-3 d-block d-lg-none"></div>
|
||||
|
||||
<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 CREATOR -->
|
||||
<div class="col-12">
|
||||
<div class="onionr-post-creator">
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
<img class="onionr-post-creator-user-icon" id="onionr-post-creator-user-icon">
|
||||
</div>
|
||||
<div class="col-10">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END POST CREATOR -->
|
||||
</div>
|
||||
|
||||
<div class="row" id="onionr-timeline-posts">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-none d-lg-block col-lg-3">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="onionr-replies">
|
||||
<h2 id="onionr-replies-title"></h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="onionr-reply-creator-panel">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- POST FOCUS DIALOG -->
|
||||
<div class="modal fade" id="onionr-post-focus" tabindex="-1" role="dialog" aria-labelledby="modal-title" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="row p-3">
|
||||
<div class="col-2">
|
||||
<img src="" id="onionr-post-focus-user-icon" class="onionr-post-user-icon">
|
||||
</div>
|
||||
<div class="col-10">
|
||||
<div class="row">
|
||||
<div class="col col-auto">
|
||||
<a class="onionr-post-user-name" id="onionr-post-focus-user-name" href="#!" onclick="viewProfile('$user-id-url', '$user-name-url'); jQuery('#onionr-post-focus').modal('hide');">$user-name</a>
|
||||
<a class="onionr-post-user-id" id="onionr-post-focus-user-id" href="#!" onclick="viewProfile('$user-id-url', '$user-name-url'); jQuery('#onionr-post-focus').modal('hide');" data-placement="top" data-toggle="tooltip" title="$user-id">$user-id-truncated</a>
|
||||
</div>
|
||||
|
||||
<div class="col col-auto text-right ml-auto pl-0">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="onionr-post-content" id="onionr-post-focus-content">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="col-12 onionr-post-focus-separator" />
|
||||
|
||||
<!-- POST FOCUS REPLIES -->
|
||||
<div class="col-12">
|
||||
<div class="row">
|
||||
<div class="onionr-post-focus-reply-creator">
|
||||
<div class="row">
|
||||
<div class="col-1"></div>
|
||||
<div class="col-2">
|
||||
<img class="onionr-post-creator-user-icon" id="onionr-post-focus-reply-creator-user-icon">
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<div class="row">
|
||||
<div class="col col-auto">
|
||||
<a class="onionr-post-creator-user-name" id="onionr-post-focus-reply-creator-user-name" href="#!" onclick="viewProfile('$user-id-url', '$user-name-url')"></a>
|
||||
<a class="onionr-post-creator-user-id" id="onionr-post-focus-reply-creator-user-id" href="#!" onclick="viewProfile('$user-id-url', '$user-name-url')" data-placement="top" data-toggle="tooltip" title="$user-id">you</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<textarea class="onionr-post-creator-content" id="onionr-post-focus-reply-creator-content" oninput="focusReplyCreatorChange()"></textarea>
|
||||
|
||||
<div class="onionr-post-creator-content-message" id="onionr-post-focus-reply-creator-content-message"></div>
|
||||
|
||||
<input type="button" onclick="makeFocusReply()" title="Reply" value="Reply" id="onionr-post-focus-reply-creator-create" class="onionr-post-creator-create" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="onionr-post-focus-replies"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END POST FOCUS REPLIES -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END POST FOCUS DIALOG -->
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="modal-title" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="modal-title">Loading...</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" id="modal-content">Onionr has begun performing a CPU-intensive operation. If this operation does not complete in the next 10 seconds, try reloading the page.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
|
||||
<script src="js/main.js"></script>
|
||||
|
||||
<script src="js/timeline.js"></script>
|
||||
</body>
|
||||
</html>
|
753
onionr/static-data/www/ui/dist/js/main.js
vendored
753
onionr/static-data/www/ui/dist/js/main.js
vendored
File diff suppressed because one or more lines are too long
491
onionr/static-data/www/ui/dist/js/timeline.js
vendored
491
onionr/static-data/www/ui/dist/js/timeline.js
vendored
|
@ -1,491 +0,0 @@
|
|||
/* just for testing rn */
|
||||
Block.getBlocks({'type' : 'onionr-post', 'signed' : true, 'reverse' : true}, function(data) {
|
||||
for(var i = 0; i < data.length; i++) {
|
||||
try {
|
||||
var block = data[i];
|
||||
|
||||
var finished = false;
|
||||
User.getUser(new String(block.getHeader('signer', 'unknown')), function(user) {
|
||||
var post = new Post();
|
||||
|
||||
var blockContent = JSON.parse(block.getContent());
|
||||
|
||||
// just ignore anything shorter than 280 characters
|
||||
if(String(blockContent['content']).length <= 280 && block.getParent() === null) {
|
||||
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;
|
||||
});
|
||||
|
||||
while(!finished);
|
||||
} catch(e) {
|
||||
console.log('Troublemaker block: ' + data[i].getHash());
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function toggleLike(hash) {
|
||||
var post = getPostMap(hash);
|
||||
if(post === null || !getPostMap()[hash]['liked']) {
|
||||
console.log('Liking ' + hash + '...');
|
||||
|
||||
if(post === null)
|
||||
getPostMap()[hash] = {};
|
||||
|
||||
getPostMap()[hash]['liked'] = true;
|
||||
|
||||
set('postmap', JSON.stringify(getPostMap()));
|
||||
|
||||
var block = new Block();
|
||||
|
||||
block.setType('onionr-post-like');
|
||||
block.setContent(JSON.stringify({'hash' : hash}));
|
||||
block.save(true, function(hash) {});
|
||||
} else {
|
||||
console.log('Unliking ' + hash + '...');
|
||||
}
|
||||
}
|
||||
|
||||
function postCreatorChange() {
|
||||
var content = document.getElementById('onionr-post-creator-content').value;
|
||||
var message = '';
|
||||
|
||||
var maxlength = 280;
|
||||
|
||||
var disable = true;
|
||||
var warn = false;
|
||||
|
||||
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 <= maxlength) {
|
||||
// 280 max characters
|
||||
message = '%s characters remaining'.replaceAll('%s', (280 - content.length));
|
||||
disable = false;
|
||||
|
||||
if(maxlength - content.length < maxlength / 4) {
|
||||
warn = true;
|
||||
}
|
||||
} else {
|
||||
message = '%s characters over maximum'.replaceAll('%s', (content.length - maxlength));
|
||||
}
|
||||
}
|
||||
|
||||
var element = document.getElementById('onionr-post-creator-content-message');
|
||||
var button = document.getElementById("onionr-post-creator-create");
|
||||
|
||||
if(message === '')
|
||||
element.style.visibility = 'hidden';
|
||||
else {
|
||||
element.style.visibility = 'visible';
|
||||
|
||||
element.innerHTML = message;
|
||||
|
||||
if(disable)
|
||||
element.style.color = 'red';
|
||||
else if(warn)
|
||||
element.style.color = '#FF8C00';
|
||||
else
|
||||
element.style.color = 'gray';
|
||||
}
|
||||
|
||||
if(disable)
|
||||
button.disabled = true;
|
||||
else
|
||||
button.disabled = false;
|
||||
}
|
||||
|
||||
function replyCreatorChange() {
|
||||
var content = document.getElementById('onionr-reply-creator-content').value;
|
||||
var message = '';
|
||||
|
||||
var maxlength = 280;
|
||||
|
||||
var disable = true;
|
||||
var warn = false;
|
||||
|
||||
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 <= maxlength) {
|
||||
// 280 max characters
|
||||
message = '%s characters remaining'.replaceAll('%s', (280 - content.length));
|
||||
disable = false;
|
||||
|
||||
if(maxlength - content.length < maxlength / 4) {
|
||||
warn = true;
|
||||
}
|
||||
} else {
|
||||
message = '%s characters over maximum'.replaceAll('%s', (content.length - maxlength));
|
||||
}
|
||||
}
|
||||
|
||||
var element = document.getElementById('onionr-reply-creator-content-message');
|
||||
var button = document.getElementById("onionr-reply-creator-create");
|
||||
|
||||
if(message === '')
|
||||
element.style.visibility = 'hidden';
|
||||
else {
|
||||
element.style.visibility = 'visible';
|
||||
|
||||
element.innerHTML = message;
|
||||
|
||||
if(disable)
|
||||
element.style.color = 'red';
|
||||
else if(warn)
|
||||
element.style.color = '#FF8C00';
|
||||
else
|
||||
element.style.color = 'gray';
|
||||
}
|
||||
|
||||
if(disable)
|
||||
button.disabled = true;
|
||||
else
|
||||
button.disabled = false;
|
||||
}
|
||||
|
||||
function focusReplyCreatorChange() {
|
||||
var content = document.getElementById('onionr-post-focus-reply-creator-content').value;
|
||||
var message = '';
|
||||
|
||||
var maxlength = 280;
|
||||
|
||||
var disable = true;
|
||||
var warn = false;
|
||||
|
||||
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 <= maxlength) {
|
||||
// 280 max characters
|
||||
message = '%s characters remaining'.replaceAll('%s', (280 - content.length));
|
||||
disable = false;
|
||||
|
||||
if(maxlength - content.length < maxlength / 4) {
|
||||
warn = true;
|
||||
}
|
||||
} else {
|
||||
message = '%s characters over maximum'.replaceAll('%s', (content.length - maxlength));
|
||||
}
|
||||
}
|
||||
|
||||
var element = document.getElementById('onionr-post-focus-reply-creator-content-message');
|
||||
var button = document.getElementById("onionr-post-focus-reply-creator-create");
|
||||
|
||||
if(message === '')
|
||||
element.style.visibility = 'hidden';
|
||||
else {
|
||||
element.style.visibility = 'visible';
|
||||
|
||||
element.innerHTML = message;
|
||||
|
||||
if(disable)
|
||||
element.style.color = 'red';
|
||||
else if(warn)
|
||||
element.style.color = '#FF8C00';
|
||||
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));
|
||||
|
||||
User.getUser(id, function(data) {
|
||||
if(data !== null) {
|
||||
document.getElementById("onionr-profile-user-icon").src = "data:image/jpeg;base64," + Sanitize.html(data.getIcon());
|
||||
document.getElementById("onionr-profile-user-icon").b64 = Sanitize.html(data.getIcon());
|
||||
document.getElementById("onionr-profile-username").innerHTML = Sanitize.html(Sanitize.username(data.getName()));
|
||||
document.getElementById("onionr-profile-username").title = Sanitize.html(data.getID());
|
||||
document.getElementById("onionr-profile-description").innerHTML = Sanitize.html(Sanitize.description(data.getDescription()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateUser() {
|
||||
toggleSaveButton(false);
|
||||
|
||||
// jQuery('#modal').modal('show');
|
||||
|
||||
var name = jQuery('#onionr-profile-username').text();
|
||||
var id = document.getElementById("onionr-profile-username").title;
|
||||
var icon = document.getElementById("onionr-profile-user-icon").b64;
|
||||
var description = jQuery("#onionr-profile-description").text();
|
||||
|
||||
var user = new User();
|
||||
|
||||
user.setName(name);
|
||||
user.setID(id);
|
||||
user.setIcon(icon);
|
||||
user.setDescription(Sanitize.description(description));
|
||||
|
||||
user.remember();
|
||||
user.save(function() {
|
||||
setCurrentUser(user);
|
||||
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
function cancelUpdate() {
|
||||
toggleSaveButton(false);
|
||||
|
||||
var name = jQuery('#onionr-profile-username').text();
|
||||
var id = document.getElementById("onionr-profile-username").title;
|
||||
|
||||
viewProfile(id, name);
|
||||
}
|
||||
|
||||
function toggleSaveButton(show) {
|
||||
document.getElementById("onionr-profile-edit").style.display = (show ? 'block' : 'none');
|
||||
}
|
||||
|
||||
function makePost() {
|
||||
var content = document.getElementById("onionr-post-creator-content").value;
|
||||
|
||||
if(content.trim() !== '') {
|
||||
var post = new Post();
|
||||
|
||||
post.setUser(getCurrentUser());
|
||||
post.setContent(content);
|
||||
post.setPostDate(new Date());
|
||||
|
||||
post.save(function(data) {}); // async, but no function
|
||||
|
||||
document.getElementById('onionr-timeline-posts').innerHTML = post.getHTML() + document.getElementById('onionr-timeline-posts').innerHTML;
|
||||
|
||||
document.getElementById("onionr-post-creator-content").value = "";
|
||||
document.getElementById("onionr-post-creator-content").focus();
|
||||
postCreatorChange();
|
||||
} else {
|
||||
console.log('Not making empty post.');
|
||||
}
|
||||
}
|
||||
|
||||
function getReplies(id, callback) {
|
||||
Block.getBlocks({'type' : 'onionr-post', 'parent' : id, 'signed' : true, 'reverse' : true}, callback);
|
||||
}
|
||||
|
||||
function focusPost(id) {
|
||||
viewReplies(id);
|
||||
}
|
||||
|
||||
function viewRepliesMobile(id) {
|
||||
var post = document.getElementById('onionr-post-' + id);
|
||||
|
||||
var user_name = '';
|
||||
var user_id = '';
|
||||
var user_id_trunc = '';
|
||||
var user_icon = '';
|
||||
var post_content = '';
|
||||
|
||||
if(post !== null && post !== undefined) {
|
||||
// if the post is in the timeline, get the data from it
|
||||
user_name = post.getElementsByClassName('onionr-post-user-name')[0].innerHTML;
|
||||
user_id = post.getElementsByClassName('onionr-post-user-id')[0].title;
|
||||
user_id_trunc = post.getElementsByClassName('onionr-post-user-id')[0].innerHTML;
|
||||
user_icon = post.getElementsByClassName('onionr-post-user-icon')[0].src;
|
||||
post_content = post.getElementsByClassName('onionr-post-content')[0].innerHTML;
|
||||
} else {
|
||||
// otherwise, fetch the data
|
||||
}
|
||||
|
||||
document.getElementById('onionr-post-focus-user-icon').src = user_icon;
|
||||
document.getElementById('onionr-post-focus-user-name').innerHTML = user_name;
|
||||
document.getElementById('onionr-post-focus-user-id').innerHTML = user_id_trunc;
|
||||
document.getElementById('onionr-post-focus-user-id').title = user_id;
|
||||
document.getElementById('onionr-post-focus-content').innerHTML = post_content;
|
||||
|
||||
document.getElementById('onionr-post-focus-reply-creator-user-name').innerHTML = Sanitize.html(Sanitize.username(getCurrentUser().getName()));
|
||||
document.getElementById('onionr-post-focus-reply-creator-user-icon').src = "data:image/jpeg;base64," + Sanitize.html(getCurrentUser().getIcon());
|
||||
document.getElementById('onionr-post-focus-reply-creator-content').value = '';
|
||||
document.getElementById('onionr-post-focus-reply-creator-content-message').value = '';
|
||||
|
||||
jQuery('#onionr-post-focus').modal('show');
|
||||
}
|
||||
|
||||
function viewReplies(id) {
|
||||
document.getElementById('onionr-replies-title').innerHTML = 'Replies';
|
||||
document.getElementById('onionr-reply-creator-panel').originalPost = id;
|
||||
document.getElementById('onionr-reply-creator-panel').innerHTML = '<!-- POST REPLIES -->\
|
||||
<div class="onionr-post-creator">\
|
||||
<div class="row">\
|
||||
<div class="onionr-reply-creator container">\
|
||||
<div class="row">\
|
||||
<div class="col-3">\
|
||||
<img class="onionr-post-creator-user-icon" id="onionr-reply-creator-user-icon">\
|
||||
</div>\
|
||||
<div class="col-9">\
|
||||
<div class="row">\
|
||||
<div class="col col-auto">\
|
||||
<a class="onionr-post-creator-user-name" id="onionr-reply-creator-user-name" href="#!" onclick="viewProfile(\'$user-id-url\', \'$user-name-url\')"></a>\
|
||||
<a class="onionr-post-creator-user-id" id="onionr-reply-creator-user-id" href="#!" onclick="viewProfile(\'$user-id-url\', \'$user-name-url\')" data-placement="top" data-toggle="tooltip" title="$user-id">you</a>\
|
||||
</div>\
|
||||
</div>\
|
||||
\
|
||||
<textarea class="onionr-post-creator-content" id="onionr-reply-creator-content" oninput="replyCreatorChange()"></textarea>\
|
||||
\
|
||||
<div class="onionr-post-creator-content-message" id="onionr-reply-creator-content-message"></div>\
|
||||
\
|
||||
<input type="button" onclick="makeReply()" title="Reply" value="Reply" id="onionr-reply-creator-create" class="onionr-post-creator-create" />\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
\
|
||||
<div class="row">\
|
||||
<div id="onionr-replies"></div>\
|
||||
</div>\
|
||||
<!-- END POST REPLIES -->\
|
||||
';
|
||||
|
||||
document.getElementById('onionr-reply-creator-content').innerHTML = '';
|
||||
document.getElementById("onionr-reply-creator-content").placeholder = "Enter a message here...";
|
||||
document.getElementById('onionr-reply-creator-user-name').innerHTML = Sanitize.html(Sanitize.username(getCurrentUser().getName()));
|
||||
document.getElementById('onionr-reply-creator-user-icon').src = "data:image/jpeg;base64," + Sanitize.html(getCurrentUser().getIcon());
|
||||
|
||||
document.getElementById('onionr-replies').innerHTML = '';
|
||||
getReplies(id, function(data) {
|
||||
var replies = document.getElementById('onionr-replies');
|
||||
|
||||
replies.innerHTML = '';
|
||||
|
||||
for(var i = 0; i < data.length; i++) {
|
||||
try {
|
||||
var block = data[i];
|
||||
|
||||
var finished = false;
|
||||
User.getUser(new String(block.getHeader('signer', 'unknown')), function(user) {
|
||||
var post = new Post();
|
||||
|
||||
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());
|
||||
|
||||
replies.innerHTML += post.getHTML('reply');
|
||||
}
|
||||
|
||||
finished = true;
|
||||
});
|
||||
|
||||
while(!finished);
|
||||
} catch(e) {
|
||||
console.log('Troublemaker block: ' + data[i].getHash());
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function makeReply() {
|
||||
var content = document.getElementById("onionr-reply-creator-content").value;
|
||||
|
||||
if(content.trim() !== '') {
|
||||
var post = new Post();
|
||||
|
||||
var originalPost = document.getElementById('onionr-reply-creator-panel').originalPost;
|
||||
|
||||
console.log('Original post hash: ' + originalPost);
|
||||
|
||||
post.setUser(getCurrentUser());
|
||||
post.setParent(originalPost);
|
||||
post.setContent(content);
|
||||
post.setPostDate(new Date());
|
||||
|
||||
post.save(function(data) {}); // async, but no function
|
||||
|
||||
document.getElementById('onionr-replies').innerHTML = post.getHTML('reply') + document.getElementById('onionr-replies').innerHTML;
|
||||
|
||||
document.getElementById("onionr-reply-creator-content").value = "";
|
||||
document.getElementById("onionr-reply-creator-content").focus();
|
||||
replyCreatorChange();
|
||||
} else {
|
||||
console.log('Not making empty reply.');
|
||||
}
|
||||
}
|
||||
|
||||
jQuery('body').on('click', '[data-editable]', function() {
|
||||
var el = jQuery(this);
|
||||
var txt = el.text();
|
||||
var maxlength = el.attr("maxlength");
|
||||
|
||||
var input = jQuery('<input/>').val(txt);
|
||||
input.attr('maxlength', maxlength);
|
||||
el.replaceWith(input);
|
||||
|
||||
var save = function() {
|
||||
var newTxt = input.val();
|
||||
|
||||
if(el.attr('id') === 'onionr-profile-username')
|
||||
newTxt = Sanitize.username(newTxt);
|
||||
if(el.attr('id') === 'onionr-profile-description')
|
||||
newTxt = Sanitize.description(newTxt);
|
||||
|
||||
var p = el.text(newTxt);
|
||||
|
||||
input.replaceWith(p);
|
||||
|
||||
if(newTxt !== txt)
|
||||
toggleSaveButton(true);
|
||||
};
|
||||
|
||||
var saveEnter = function(event) {
|
||||
console.log(event);
|
||||
console.log(event.keyCode);
|
||||
if (event.keyCode === 13)
|
||||
save();
|
||||
};
|
||||
|
||||
input.one('blur', save).bind('keyup', saveEnter).focus();
|
||||
});
|
||||
//viewProfile('$user-id-url', '$user-name-url')
|
||||
// jQuery('#onionr-post-user-id').on('click', function(e) { alert(3);});
|
||||
//jQuery('#onionr-post *').on('click', function(e) { e.stopPropagation(); });
|
||||
// jQuery('#onionr-post').click(function(e) { alert(1); });
|
||||
|
||||
currentUser = getCurrentUser();
|
||||
if(currentUser !== undefined && currentUser !== null) {
|
||||
document.getElementById("onionr-post-creator-user-name").innerHTML = Sanitize.html(currentUser.getName());
|
||||
document.getElementById("onionr-post-creator-user-id").innerHTML = "you";
|
||||
document.getElementById("onionr-post-creator-user-icon").src = "data:image/jpeg;base64," + Sanitize.html(currentUser.getIcon());
|
||||
document.getElementById("onionr-post-creator-user-id").title = currentUser.getID();
|
||||
|
||||
document.getElementById("onionr-post-creator-content").placeholder = "Enter a message here...";
|
||||
document.getElementById("onionr-post-focus-reply-creator-content").placeholder = "Enter a message here...";
|
||||
|
||||
document.getElementById("onionr-post-focus-reply-creator-user-id").innerHTML = "you";
|
||||
}
|
||||
|
||||
viewCurrentProfile = function() {
|
||||
viewProfile(encodeURIComponent(currentUser.getID()), encodeURIComponent(currentUser.getName()));
|
||||
}
|
||||
|
||||
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();
|
|
@ -1,65 +0,0 @@
|
|||
{
|
||||
"eng" : {
|
||||
"ONIONR_TITLE" : "Onionr UI",
|
||||
|
||||
"TIMELINE" : "Timeline",
|
||||
"NOTIFICATIONS" : "Notifications",
|
||||
"MESSAGES" : "Messages",
|
||||
|
||||
"LATEST" : "Latest...",
|
||||
"TRENDING" : "Trending",
|
||||
"REPLIES" : "Replies",
|
||||
|
||||
"MODAL_TITLE" : "Loading...",
|
||||
"MODAL_MESSAGE" : "Onionr has begun performing a CPU-intensive operation. If this operation does not complete in the next 10 seconds, try reloading the page.",
|
||||
|
||||
"POST_LIKE" : "like",
|
||||
"POST_UNLIKE" : "unlike",
|
||||
"POST_REPLY" : "reply",
|
||||
|
||||
"POST_CREATOR_YOU" : "you",
|
||||
"POST_CREATOR_PLACEHOLDER" : "Enter a message here...",
|
||||
"POST_CREATOR_CREATE" : "Create post",
|
||||
|
||||
"REPLY_CREATOR_YOU" : "you",
|
||||
"REPLY_CREATOR_PLACEHOLDER" : "Enter reply here...",
|
||||
"REPLY_CREATOR_CREATE" : "Reply",
|
||||
|
||||
"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",
|
||||
|
||||
"REPLY_CREATOR_MESSAGE_MAXIMUM_NEWLINES" : "Please use less than 16 newlines",
|
||||
"REPLY_CREATOR_MESSAGE_REMAINING" : "%s characters remaining",
|
||||
"REPLY_CREATOR_MESSAGE_OVER" : "%s characters over maximum",
|
||||
|
||||
"PROFILE_EDIT_SAVE" : "Save",
|
||||
"PROFILE_EDIT_CANCEL" : "Cancel"
|
||||
},
|
||||
|
||||
"spa" : {
|
||||
"ONIONR_TITLE" : "Onionr UI",
|
||||
|
||||
"TIMELINE" : "Linea de Tiempo",
|
||||
"NOTIFICATIONS" : "Notificaciones",
|
||||
"MESSAGES" : "Mensaje",
|
||||
|
||||
"TRENDING" : "Trending",
|
||||
|
||||
"POST_LIKE" : "me gusta",
|
||||
"POST_REPLY" : "comentario"
|
||||
},
|
||||
|
||||
"zho" : {
|
||||
"ONIONR_TITLE" : "洋葱 用户界面",
|
||||
|
||||
"TIMELINE" : "时间线",
|
||||
"NOTIFICATIONS" : "通知",
|
||||
"MESSAGES" : "消息",
|
||||
|
||||
"TRENDING" : "趋势",
|
||||
|
||||
"POST_LIKE" : "喜欢",
|
||||
"POST_REPLY" : "回复"
|
||||
}
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
/* general formatting */
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.container-small {
|
||||
width: 300px;
|
||||
}
|
||||
.container-large {
|
||||
width: 970px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.container-small {
|
||||
width: 500px;
|
||||
}
|
||||
.container-large {
|
||||
width: 1170px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
.container-small {
|
||||
width: 700px;
|
||||
}
|
||||
.container-large {
|
||||
width: 1500px;
|
||||
}
|
||||
}
|
||||
|
||||
.container-small, .container-large {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* navbar */
|
||||
|
||||
body {
|
||||
margin-top: 5rem;
|
||||
}
|
||||
|
||||
/* timeline */
|
||||
|
||||
.onionr-post-focus-separator {
|
||||
width: 100%;
|
||||
|
||||
padding: 1rem;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.onionr-post {
|
||||
padding: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.onionr-post-user-name {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.onionr-post-user-id:before { content: "("; }
|
||||
.onionr-post-user-id:after { content: ")"; }
|
||||
|
||||
.onionr-post-content {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.onionr-post-user-icon {
|
||||
border-radius: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.onionr-post-creator {
|
||||
padding: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.onionr-post-creator-user-name {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.onionr-post-creator-user-id:before { content: "("; }
|
||||
.onionr-post-creator-user-id:after { content: ")"; }
|
||||
|
||||
.onionr-post-creator-content {
|
||||
word-wrap: break-word;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.onionr-post-creator-user-icon {
|
||||
border-radius: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.onionr-post-creator-create {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.h-divider {
|
||||
margin: 5px 15px;
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* profile */
|
||||
|
||||
.onionr-profile-user-icon {
|
||||
border-radius: 100%;
|
||||
width: 100%;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.onionr-profile-username {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.onionr-profile-save {
|
||||
width: 100%;
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
body {
|
||||
background-color: #96928f;
|
||||
color: #25383C;
|
||||
}
|
||||
|
||||
/* timeline */
|
||||
|
||||
.onionr-post-focus-separator {
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
border: 1px solid black;
|
||||
border-radius: 1rem;
|
||||
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
.onionr-post {
|
||||
border: 1px solid black;
|
||||
border-radius: 1rem;
|
||||
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
.onionr-post-user-name {
|
||||
color: green;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.onionr-post-user-id {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.onionr-post-date {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.onionr-post-content {
|
||||
font-family: sans-serif, serif;
|
||||
border-top: 1px solid black;
|
||||
font-size: 15pt;
|
||||
}
|
||||
|
||||
.onionr-post-creator {
|
||||
border: 1px solid black;
|
||||
border-radius: 1rem;
|
||||
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
.onionr-post-creator-user-name {
|
||||
color: green;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.onionr-post-creator-user-id {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.onionr-post-creator-date {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.onionr-post-creator-content {
|
||||
font-family: sans-serif, serif;
|
||||
border-top: 1px solid black;
|
||||
font-size: 15pt;
|
||||
background-color: lightgray;
|
||||
color: black;
|
||||
border-width: 0px;
|
||||
}
|
||||
|
||||
.h-divider {
|
||||
border-top:1px solid gray;
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 6.6 KiB |
|
@ -1,136 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<header />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12 col-lg-3">
|
||||
<div class="onionr-profile">
|
||||
<div class="row">
|
||||
<div class="col-4 col-lg-12">
|
||||
<img id="onionr-profile-user-icon" class="onionr-profile-user-icon" src="">
|
||||
</div>
|
||||
<div class="col-8 col-lg-12">
|
||||
<h2 maxlength="25" id="onionr-profile-username" class="onionr-profile-username text-left text-lg-center text-sm-left" data-placement="top" data-toggle="tooltip" title="unknown" data-editable></h2>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<p maxlength="128" id="onionr-profile-description" class="onionr-profile-description" data-editable></p>
|
||||
</div>
|
||||
|
||||
<div class="col-12 onionr-profile-edit" id="onionr-profile-edit" style="display: none">
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-lg-12">
|
||||
<input type="button" onclick="updateUser()" class="onionr-profile-save text-center" id="onionr-profile-save" value="<$= LANG.PROFILE_EDIT_SAVE $>" />
|
||||
</div>
|
||||
<div class="col-sm-6 col-lg-12">
|
||||
<input type="button" onclick="cancelUpdate()" class="onionr-profile-save text-center" id="onionr-profile-cancel" value="<$= LANG.PROFILE_EDIT_CANCEL $>" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="h-divider pb-3 d-block d-lg-none"></div>
|
||||
|
||||
<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 CREATOR -->
|
||||
<div class="col-12">
|
||||
<div class="onionr-post-creator">
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
<img class="onionr-post-creator-user-icon" id="onionr-post-creator-user-icon">
|
||||
</div>
|
||||
<div class="col-10">
|
||||
<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"><$= LANG.POST_CREATOR_YOU $></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END POST CREATOR -->
|
||||
</div>
|
||||
|
||||
<div class="row" id="onionr-timeline-posts">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-none d-lg-block col-lg-3">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="onionr-replies">
|
||||
<h2 id="onionr-replies-title"></h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="onionr-reply-creator-panel">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- POST FOCUS DIALOG -->
|
||||
<div class="modal fade" id="onionr-post-focus" tabindex="-1" role="dialog" aria-labelledby="modal-title" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="row p-3">
|
||||
<div class="col-2">
|
||||
<img src="" id="onionr-post-focus-user-icon" class="onionr-post-user-icon">
|
||||
</div>
|
||||
<div class="col-10">
|
||||
<div class="row">
|
||||
<div class="col col-auto">
|
||||
<a class="onionr-post-user-name" id="onionr-post-focus-user-name" href="#!" onclick="viewProfile('$user-id-url', '$user-name-url'); jQuery('#onionr-post-focus').modal('hide');">$user-name</a>
|
||||
<a class="onionr-post-user-id" id="onionr-post-focus-user-id" href="#!" onclick="viewProfile('$user-id-url', '$user-name-url'); jQuery('#onionr-post-focus').modal('hide');" data-placement="top" data-toggle="tooltip" title="$user-id">$user-id-truncated</a>
|
||||
</div>
|
||||
|
||||
<div class="col col-auto text-right ml-auto pl-0">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="onionr-post-content" id="onionr-post-focus-content">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="col-12 onionr-post-focus-separator" />
|
||||
|
||||
<$= htmlTemplate('onionr-timeline-reply-creator') $>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END POST FOCUS DIALOG -->
|
||||
|
||||
<footer />
|
||||
<script src="js/timeline.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,689 +0,0 @@
|
|||
|
||||
/* handy localstorage functions for quick usage */
|
||||
|
||||
function set(key, val) {
|
||||
return localStorage.setItem(key, val);
|
||||
}
|
||||
|
||||
function get(key, df) { // df is default
|
||||
value = localStorage.getItem(key);
|
||||
if(value == null)
|
||||
value = df;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function remove(key) {
|
||||
return localStorage.removeItem(key);
|
||||
}
|
||||
|
||||
function getParameter(name) {
|
||||
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
|
||||
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
|
||||
}
|
||||
|
||||
/* usermap localStorage stuff */
|
||||
|
||||
var usermap = JSON.parse(get('usermap', '{}'));
|
||||
var postmap = JSON.parse(get('postmap', '{}'))
|
||||
|
||||
function getUserMap() {
|
||||
return usermap;
|
||||
}
|
||||
|
||||
function getPostMap(hash) {
|
||||
if(hash !== undefined) {
|
||||
if(hash in postmap)
|
||||
return postmap[hash];
|
||||
return null;
|
||||
}
|
||||
|
||||
return postmap;
|
||||
}
|
||||
|
||||
function deserializeUser(id) {
|
||||
if(!(id in getUserMap()))
|
||||
return null;
|
||||
|
||||
var serialized = getUserMap()[id]
|
||||
var user = new User();
|
||||
|
||||
user.setName(serialized['name']);
|
||||
user.setID(serialized['id']);
|
||||
user.setIcon(serialized['icon']);
|
||||
user.setDescription(serialized['description']);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
function getCurrentUser() {
|
||||
var user = get('currentUser', null);
|
||||
|
||||
if(user === null)
|
||||
return null;
|
||||
|
||||
return User.getUser(user, function() {});
|
||||
}
|
||||
|
||||
function setCurrentUser(user) {
|
||||
set('currentUser', user.getID());
|
||||
}
|
||||
|
||||
/* returns a relative date format, e.g. "5 minutes" */
|
||||
function timeSince(date, size) {
|
||||
// taken from https://stackoverflow.com/a/3177838/3678023
|
||||
|
||||
var seconds = Math.floor((new Date() - date) / 1000);
|
||||
var interval = Math.floor(seconds / 31536000);
|
||||
|
||||
if (size === null)
|
||||
size = 'desktop';
|
||||
|
||||
var dates = {
|
||||
'mobile' : {
|
||||
'yr' : 'yrs',
|
||||
'mo' : 'mo',
|
||||
'd' : 'd',
|
||||
'hr' : 'h',
|
||||
'min' : 'm',
|
||||
'secs' : 's',
|
||||
'sec' : 's',
|
||||
},
|
||||
|
||||
'desktop' : {
|
||||
'yr' : ' years',
|
||||
'mo' : ' months',
|
||||
'd' : ' days',
|
||||
'hr' : ' hours',
|
||||
'min' : ' minutes',
|
||||
'secs' : ' seconds',
|
||||
'sec' : ' second',
|
||||
},
|
||||
};
|
||||
|
||||
if (interval > 1)
|
||||
return interval + dates[size]['yr'];
|
||||
interval = Math.floor(seconds / 2592000);
|
||||
|
||||
if (interval > 1)
|
||||
return interval + dates[size]['mo'];
|
||||
interval = Math.floor(seconds / 86400);
|
||||
|
||||
if (interval > 1)
|
||||
return interval + dates[size]['d'];
|
||||
interval = Math.floor(seconds / 3600);
|
||||
|
||||
if (interval > 1)
|
||||
return interval + dates[size]['hr'];
|
||||
interval = Math.floor(seconds / 60);
|
||||
|
||||
if (interval > 1)
|
||||
return interval + dates[size]['min'];
|
||||
|
||||
if(Math.floor(seconds) !== 1)
|
||||
return Math.floor(seconds) + dates[size]['secs'];
|
||||
|
||||
return '1' + dates[size]['sec'];
|
||||
}
|
||||
|
||||
/* replace all instances of string */
|
||||
String.prototype.replaceAll = function(search, replacement, limit) {
|
||||
// taken from https://stackoverflow.com/a/17606289/3678023
|
||||
var target = this;
|
||||
return target.split(search, limit).join(replacement);
|
||||
};
|
||||
|
||||
/* useful functions to sanitize data */
|
||||
class Sanitize {
|
||||
/* sanitizes HTML in a string */
|
||||
static html(html) {
|
||||
return String(html).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||
}
|
||||
|
||||
/* URL encodes a string */
|
||||
static url(url) {
|
||||
return encodeURIComponent(url);
|
||||
}
|
||||
|
||||
/* usernames */
|
||||
static username(username) {
|
||||
return String(username).replace(/[\W_]+/g, " ").substring(0, 25);
|
||||
}
|
||||
|
||||
/* profile descriptions */
|
||||
static description(description) {
|
||||
return String(description).substring(0, 128);
|
||||
}
|
||||
}
|
||||
|
||||
/* config stuff */
|
||||
function getWebPassword() {
|
||||
return get("web-password", null);
|
||||
}
|
||||
|
||||
function setWebPassword(password) {
|
||||
return set("web-password", password);
|
||||
}
|
||||
|
||||
function getTimingToken() {
|
||||
return get("timing-token", null);
|
||||
}
|
||||
|
||||
function setTimingToken(token) {
|
||||
return set("timing-token", token);
|
||||
}
|
||||
|
||||
/* user class */
|
||||
class User {
|
||||
constructor() {
|
||||
this.name = 'Unknown';
|
||||
this.id = 'unknown';
|
||||
this.image = 'img/default.png';
|
||||
}
|
||||
|
||||
setName(name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
setID(id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
getID() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
setIcon(image) {
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
getIcon() {
|
||||
return this.image;
|
||||
}
|
||||
|
||||
setDescription(description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
serialize() {
|
||||
return {
|
||||
'name' : this.getName(),
|
||||
'id' : this.getID(),
|
||||
'icon' : this.getIcon(),
|
||||
'description' : this.getDescription()
|
||||
};
|
||||
}
|
||||
|
||||
/* save in usermap */
|
||||
remember() {
|
||||
usermap[this.getID()] = this.serialize();
|
||||
set('usermap', JSON.stringify(usermap));
|
||||
}
|
||||
|
||||
/* save as a block */
|
||||
save(callback) {
|
||||
var block = new Block();
|
||||
|
||||
block.setType('onionr-user');
|
||||
block.setContent(JSON.stringify(this.serialize()));
|
||||
|
||||
return block.save(true, callback);
|
||||
}
|
||||
|
||||
static getUser(id, callback) {
|
||||
// console.log(callback);
|
||||
var user = deserializeUser(id);
|
||||
if(user === null) {
|
||||
Block.getBlocks({'type' : 'onionr-user-info', 'signed' : true, 'reverse' : true}, function(data) {
|
||||
if(data.length !== 0) {
|
||||
try {
|
||||
user = new User();
|
||||
|
||||
var userInfo = JSON.parse(data[0].getContent());
|
||||
|
||||
if(userInfo['id'] === id) {
|
||||
user.setName(userInfo['name']);
|
||||
user.setIcon(userInfo['icon']);
|
||||
user.setDescription(userInfo['description']);
|
||||
user.setID(id);
|
||||
|
||||
user.remember();
|
||||
// console.log(callback);
|
||||
callback(user);
|
||||
return user;
|
||||
}
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
|
||||
callback(null);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
callback(null);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// console.log(callback);
|
||||
callback(user);
|
||||
return user;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* post class */
|
||||
class Post {
|
||||
/* returns the html content of a post */
|
||||
getHTML(type) {
|
||||
var replyTemplate = '<$= jsTemplate('onionr-timeline-reply') $>';
|
||||
var postTemplate = '<$= jsTemplate('onionr-timeline-post') $>';
|
||||
|
||||
var template = '';
|
||||
|
||||
if(type !== undefined && type !== null && type == 'reply')
|
||||
template = replyTemplate;
|
||||
else
|
||||
template = postTemplate;
|
||||
|
||||
var device = (jQuery(document).width() < 768 ? 'mobile' : 'desktop');
|
||||
|
||||
template = template.replaceAll('$user-name-url', Sanitize.html(Sanitize.url(this.getUser().getName())));
|
||||
template = template.replaceAll('$user-name', Sanitize.html(this.getUser().getName()));
|
||||
template = template.replaceAll('$user-id-url', Sanitize.html(Sanitize.url(this.getUser().getID())));
|
||||
|
||||
template = template.replaceAll('$user-id-truncated', Sanitize.html(this.getUser().getID().substring(0, 12) + '...'));
|
||||
// template = template.replaceAll('$user-id-truncated', Sanitize.html(this.getUser().getID().split('-').slice(0, 4).join('-')));
|
||||
|
||||
template = template.replaceAll('$user-id', Sanitize.html(this.getUser().getID()));
|
||||
template = template.replaceAll('$user-image', "data:image/jpeg;base64," + Sanitize.html(this.getUser().getIcon()));
|
||||
template = template.replaceAll('$content', Sanitize.html(this.getContent()).replaceAll('\n', '<br />', 16)); // Maximum of 16 lines
|
||||
template = template.replaceAll('$post-hash', this.getHash());
|
||||
template = template.replaceAll('$date-relative-truncated', timeSince(this.getPostDate(), 'mobile'));
|
||||
template = template.replaceAll('$date-relative', timeSince(this.getPostDate(), device) + (device === 'desktop' ? ' ago' : ''));
|
||||
template = template.replaceAll('$date', this.getPostDate().toLocaleString());
|
||||
|
||||
if(this.getHash() in getPostMap() && getPostMap()[this.getHash()]['liked']) {
|
||||
template = template.replaceAll('$liked', '<$= LANG.POST_UNLIKE $>');
|
||||
} else {
|
||||
template = template.replaceAll('$liked', '<$= LANG.POST_LIKE $>');
|
||||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
setUser(user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
getUser() {
|
||||
return this.user;
|
||||
}
|
||||
|
||||
setContent(content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
getContent() {
|
||||
return this.content;
|
||||
}
|
||||
|
||||
setParent(parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
getParent() {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
setPostDate(date) { // unix timestamp input
|
||||
if(date instanceof Date)
|
||||
this.date = date;
|
||||
else
|
||||
this.date = new Date(date * 1000);
|
||||
}
|
||||
|
||||
getPostDate() {
|
||||
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()})};
|
||||
|
||||
if(this.getParent() !== undefined && this.getParent() !== null)
|
||||
args['parent'] = (this.getParent() instanceof Post ? this.getParent().getHash() : (this.getParent() instanceof Block ? this.getParent().getHash() : this.getParent()));
|
||||
|
||||
var url = '/client/?action=insertBlock&data=' + Sanitize.url(JSON.stringify(args)) + '&token=' + Sanitize.url(getWebPassword()) + '&timingToken=' + Sanitize.url(getTimingToken());
|
||||
|
||||
console.log(url);
|
||||
|
||||
var http = new XMLHttpRequest();
|
||||
|
||||
if(callback !== undefined) {
|
||||
// async
|
||||
|
||||
var thisObject = this;
|
||||
|
||||
http.addEventListener('load', function() {
|
||||
thisObject.setHash(Block.parseBlockArray(JSON.parse(http.responseText)['hash']));
|
||||
callback(thisObject.getHash());
|
||||
}, false);
|
||||
|
||||
http.open('GET', url, true);
|
||||
http.timeout = 5000;
|
||||
http.send(null);
|
||||
} else {
|
||||
// sync
|
||||
|
||||
http.open('GET', url, false);
|
||||
http.send(null);
|
||||
|
||||
this.setHash(Block.parseBlockArray(JSON.parse(http.responseText)['hash']));
|
||||
|
||||
return this.getHash();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* block class */
|
||||
class Block {
|
||||
constructor(type, content) {
|
||||
this.type = type;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
// returns the block hash, if any
|
||||
getHash() {
|
||||
return this.hash;
|
||||
}
|
||||
|
||||
// returns the block type
|
||||
getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
// returns the block header
|
||||
getHeader(key, df) { // df is default
|
||||
if(key !== undefined) {
|
||||
if(this.getHeader().hasOwnProperty(key))
|
||||
return this.getHeader()[key];
|
||||
else
|
||||
return (df === undefined ? null : df);
|
||||
} else
|
||||
return this.header;
|
||||
}
|
||||
|
||||
// returns the block metadata
|
||||
getMetadata(key, df) { // df is default
|
||||
if(key !== undefined) {
|
||||
if(this.getMetadata().hasOwnProperty(key))
|
||||
return this.getMetadata()[key];
|
||||
else
|
||||
return (df === undefined ? null : df);
|
||||
} else
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
// returns the block content
|
||||
getContent() {
|
||||
return this.content;
|
||||
}
|
||||
|
||||
// returns the parent block's hash (not Block object, for performance)
|
||||
getParent() {
|
||||
// console.log(this.parent);
|
||||
|
||||
// TODO: Create a function to fetch the block contents and parse it from the server; right now it is only possible to search for types of blocks (see Block.getBlocks), so it is impossible to return a Block object here
|
||||
|
||||
// if(!(this.parent instanceof Block) && this.parent !== undefined && this.parent !== null)
|
||||
// this.parent = Block.openBlock(this.parent); // convert hash to Block object
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
// returns the date that the block was received
|
||||
getDate() {
|
||||
return this.date;
|
||||
}
|
||||
|
||||
// returns a boolean that indicates whether or not the block is valid
|
||||
isValid() {
|
||||
return this.valid;
|
||||
}
|
||||
|
||||
// returns a boolean thati ndicates whether or not the block is signed
|
||||
isSigned() {
|
||||
return this.signed;
|
||||
}
|
||||
|
||||
// returns the block signature
|
||||
getSignature() {
|
||||
return this.signature;
|
||||
}
|
||||
|
||||
// returns the block type
|
||||
setType(type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
// sets block metadata by key
|
||||
setMetadata(key, val) {
|
||||
this.metadata[key] = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
// sets block content
|
||||
setContent(content) {
|
||||
this.content = content;
|
||||
return this;
|
||||
}
|
||||
|
||||
// sets the block parent by hash or Block object
|
||||
setParent(parent) {
|
||||
this.parent = parent;
|
||||
return this;
|
||||
}
|
||||
|
||||
// indicates if the Block exists or not
|
||||
exists() {
|
||||
return !(this.hash === null || this.hash === undefined);
|
||||
}
|
||||
|
||||
// saves the block, returns the hash
|
||||
save(sign, callback) {
|
||||
var type = this.getType();
|
||||
var content = this.getContent();
|
||||
var parent = this.getParent();
|
||||
|
||||
if(content !== undefined && content !== null && type !== '') {
|
||||
var args = {'content' : content};
|
||||
|
||||
if(type !== undefined && type !== null && type !== '')
|
||||
args['type'] = type;
|
||||
if(parent !== undefined && parent !== null && parent.getHash() !== undefined && parent.getHash() !== null && parent.getHash() !== '')
|
||||
args['parent'] = parent.getHash();
|
||||
if(sign !== undefined && sign !== null)
|
||||
args['sign'] = String(sign) !== 'false'
|
||||
|
||||
|
||||
var url = '/client/?action=insertBlock&data=' + Sanitize.url(JSON.stringify(args)) + '&token=' + Sanitize.url(getWebPassword()) + '&timingToken=' + Sanitize.url(getTimingToken());
|
||||
|
||||
console.log(url);
|
||||
|
||||
var http = new XMLHttpRequest();
|
||||
|
||||
if(callback !== undefined) {
|
||||
// async
|
||||
|
||||
http.addEventListener('load', function() {
|
||||
callback(Block.parseBlockArray(JSON.parse(http.responseText)['hash']));
|
||||
}, false);
|
||||
|
||||
http.open('GET', url, true);
|
||||
http.timeout = 5000;
|
||||
http.send(null);
|
||||
} else {
|
||||
// sync
|
||||
|
||||
http.open('GET', url, false);
|
||||
http.send(null);
|
||||
|
||||
return Block.parseBlockArray(JSON.parse(http.responseText)['hash']);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static functions */
|
||||
|
||||
// recreates a block by hash
|
||||
static openBlock(hash) {
|
||||
return Block.parseBlock(hash);
|
||||
}
|
||||
|
||||
// converts an associative array to a Block
|
||||
static parseBlock(val) {
|
||||
var block = new Block();
|
||||
|
||||
block.type = val['type'];
|
||||
block.content = val['content'];
|
||||
block.header = val['header'];
|
||||
block.metadata = val['metadata'];
|
||||
block.date = new Date(val['date'] * 1000);
|
||||
block.hash = val['hash'];
|
||||
block.signature = val['signature'];
|
||||
block.signed = val['signed'];
|
||||
block.valid = val['valid'];
|
||||
block.parent = val['parent'];
|
||||
|
||||
if(block.getParent() !== null) {
|
||||
// if the block data is already in the associative array
|
||||
|
||||
/*
|
||||
if (blocks.hasOwnProperty(block.getParent()))
|
||||
block.setParent(Block.parseAssociativeArray({blocks[block.getParent()]})[0]);
|
||||
*/
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
// converts an array of associative arrays to an array of Blocks
|
||||
static parseBlockArray(blocks) {
|
||||
var outputBlocks = [];
|
||||
|
||||
for(var key in blocks) {
|
||||
if(blocks.hasOwnProperty(key)) {
|
||||
var val = blocks[key];
|
||||
|
||||
var block = Block.parseBlock(val);
|
||||
|
||||
outputBlocks.push(block);
|
||||
}
|
||||
}
|
||||
|
||||
return outputBlocks;
|
||||
}
|
||||
|
||||
static getBlocks(args, callback) { // callback is optional
|
||||
args = args || {}
|
||||
|
||||
var url = '/client/?action=searchBlocks&data=' + Sanitize.url(JSON.stringify(args)) + '&token=' + Sanitize.url(getWebPassword()) + '&timingToken=' + Sanitize.url(getTimingToken());
|
||||
|
||||
console.log(url);
|
||||
|
||||
var http = new XMLHttpRequest();
|
||||
|
||||
if(callback !== undefined) {
|
||||
// async
|
||||
|
||||
http.addEventListener('load', function() {
|
||||
callback(Block.parseBlockArray(JSON.parse(http.responseText)['blocks']));
|
||||
}, false);
|
||||
|
||||
http.open('GET', url, true);
|
||||
http.timeout = 5000;
|
||||
http.send(null);
|
||||
} else {
|
||||
// sync
|
||||
|
||||
http.open('GET', url, false);
|
||||
http.send(null);
|
||||
|
||||
return Block.parseBlockArray(JSON.parse(http.responseText)['blocks']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* temporary code */
|
||||
|
||||
var tt = getParameter("timingToken");
|
||||
if(tt !== null && tt !== undefined) {
|
||||
setTimingToken(tt);
|
||||
}
|
||||
|
||||
if(getWebPassword() === null) {
|
||||
var password = "";
|
||||
while(password.length != 64) {
|
||||
password = prompt("Please enter the web password (run `./RUN-LINUX.sh --details`)");
|
||||
}
|
||||
|
||||
setWebPassword(password);
|
||||
}
|
||||
|
||||
if(getCurrentUser() === null) {
|
||||
jQuery('#modal').modal('show');
|
||||
|
||||
var url = '/client/?action=info&token=' + Sanitize.url(getWebPassword()) + '&timingToken=' + Sanitize.url(getTimingToken());
|
||||
|
||||
console.log(url);
|
||||
|
||||
var http = new XMLHttpRequest();
|
||||
|
||||
// sync
|
||||
|
||||
http.addEventListener('load', function() {
|
||||
var id = JSON.parse(http.responseText)['pubkey'];
|
||||
|
||||
User.getUser(id, function(data) {
|
||||
if(data === null || data === undefined) {
|
||||
var user = new User();
|
||||
|
||||
user.setName('New User');
|
||||
user.setID(id);
|
||||
user.setIcon('<$= Template.jsTemplate("default-icon") $>');
|
||||
user.setDescription('A new OnionrUI user');
|
||||
|
||||
user.remember();
|
||||
user.save();
|
||||
|
||||
setCurrentUser(user);
|
||||
} else {
|
||||
setCurrentUser(data);
|
||||
}
|
||||
|
||||
window.location.reload();
|
||||
});
|
||||
}, false);
|
||||
|
||||
http.open('GET', url, true);
|
||||
http.send(null);
|
||||
}
|
||||
|
||||
currentUser = getCurrentUser();
|
|
@ -1,460 +0,0 @@
|
|||
/* just for testing rn */
|
||||
Block.getBlocks({'type' : 'onionr-post', 'signed' : true, 'reverse' : true}, function(data) {
|
||||
for(var i = 0; i < data.length; i++) {
|
||||
try {
|
||||
var block = data[i];
|
||||
|
||||
var finished = false;
|
||||
User.getUser(new String(block.getHeader('signer', 'unknown')), function(user) {
|
||||
var post = new Post();
|
||||
|
||||
var blockContent = JSON.parse(block.getContent());
|
||||
|
||||
// just ignore anything shorter than 280 characters
|
||||
if(String(blockContent['content']).length <= 280 && block.getParent() === null) {
|
||||
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;
|
||||
});
|
||||
|
||||
while(!finished);
|
||||
} catch(e) {
|
||||
console.log('Troublemaker block: ' + data[i].getHash());
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function toggleLike(hash) {
|
||||
var post = getPostMap(hash);
|
||||
if(post === null || !getPostMap()[hash]['liked']) {
|
||||
console.log('Liking ' + hash + '...');
|
||||
|
||||
if(post === null)
|
||||
getPostMap()[hash] = {};
|
||||
|
||||
getPostMap()[hash]['liked'] = true;
|
||||
|
||||
set('postmap', JSON.stringify(getPostMap()));
|
||||
|
||||
var block = new Block();
|
||||
|
||||
block.setType('onionr-post-like');
|
||||
block.setContent(JSON.stringify({'hash' : hash}));
|
||||
block.save(true, function(hash) {});
|
||||
} else {
|
||||
console.log('Unliking ' + hash + '...');
|
||||
}
|
||||
}
|
||||
|
||||
function postCreatorChange() {
|
||||
var content = document.getElementById('onionr-post-creator-content').value;
|
||||
var message = '';
|
||||
|
||||
var maxlength = 280;
|
||||
|
||||
var disable = true;
|
||||
var warn = false;
|
||||
|
||||
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 <= maxlength) {
|
||||
// 280 max characters
|
||||
message = '<$= LANG.POST_CREATOR_MESSAGE_REMAINING $>'.replaceAll('%s', (280 - content.length));
|
||||
disable = false;
|
||||
|
||||
if(maxlength - content.length < maxlength / 4) {
|
||||
warn = true;
|
||||
}
|
||||
} else {
|
||||
message = '<$= LANG.POST_CREATOR_MESSAGE_OVER $>'.replaceAll('%s', (content.length - maxlength));
|
||||
}
|
||||
}
|
||||
|
||||
var element = document.getElementById('onionr-post-creator-content-message');
|
||||
var button = document.getElementById("onionr-post-creator-create");
|
||||
|
||||
if(message === '')
|
||||
element.style.visibility = 'hidden';
|
||||
else {
|
||||
element.style.visibility = 'visible';
|
||||
|
||||
element.innerHTML = message;
|
||||
|
||||
if(disable)
|
||||
element.style.color = 'red';
|
||||
else if(warn)
|
||||
element.style.color = '#FF8C00';
|
||||
else
|
||||
element.style.color = 'gray';
|
||||
}
|
||||
|
||||
if(disable)
|
||||
button.disabled = true;
|
||||
else
|
||||
button.disabled = false;
|
||||
}
|
||||
|
||||
function replyCreatorChange() {
|
||||
var content = document.getElementById('onionr-reply-creator-content').value;
|
||||
var message = '';
|
||||
|
||||
var maxlength = 280;
|
||||
|
||||
var disable = true;
|
||||
var warn = false;
|
||||
|
||||
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 <= maxlength) {
|
||||
// 280 max characters
|
||||
message = '<$= LANG.POST_CREATOR_MESSAGE_REMAINING $>'.replaceAll('%s', (280 - content.length));
|
||||
disable = false;
|
||||
|
||||
if(maxlength - content.length < maxlength / 4) {
|
||||
warn = true;
|
||||
}
|
||||
} else {
|
||||
message = '<$= LANG.POST_CREATOR_MESSAGE_OVER $>'.replaceAll('%s', (content.length - maxlength));
|
||||
}
|
||||
}
|
||||
|
||||
var element = document.getElementById('onionr-reply-creator-content-message');
|
||||
var button = document.getElementById("onionr-reply-creator-create");
|
||||
|
||||
if(message === '')
|
||||
element.style.visibility = 'hidden';
|
||||
else {
|
||||
element.style.visibility = 'visible';
|
||||
|
||||
element.innerHTML = message;
|
||||
|
||||
if(disable)
|
||||
element.style.color = 'red';
|
||||
else if(warn)
|
||||
element.style.color = '#FF8C00';
|
||||
else
|
||||
element.style.color = 'gray';
|
||||
}
|
||||
|
||||
if(disable)
|
||||
button.disabled = true;
|
||||
else
|
||||
button.disabled = false;
|
||||
}
|
||||
|
||||
function focusReplyCreatorChange() {
|
||||
var content = document.getElementById('onionr-post-focus-reply-creator-content').value;
|
||||
var message = '';
|
||||
|
||||
var maxlength = 280;
|
||||
|
||||
var disable = true;
|
||||
var warn = false;
|
||||
|
||||
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 <= maxlength) {
|
||||
// 280 max characters
|
||||
message = '<$= LANG.POST_CREATOR_MESSAGE_REMAINING $>'.replaceAll('%s', (280 - content.length));
|
||||
disable = false;
|
||||
|
||||
if(maxlength - content.length < maxlength / 4) {
|
||||
warn = true;
|
||||
}
|
||||
} else {
|
||||
message = '<$= LANG.POST_CREATOR_MESSAGE_OVER $>'.replaceAll('%s', (content.length - maxlength));
|
||||
}
|
||||
}
|
||||
|
||||
var element = document.getElementById('onionr-post-focus-reply-creator-content-message');
|
||||
var button = document.getElementById("onionr-post-focus-reply-creator-create");
|
||||
|
||||
if(message === '')
|
||||
element.style.visibility = 'hidden';
|
||||
else {
|
||||
element.style.visibility = 'visible';
|
||||
|
||||
element.innerHTML = message;
|
||||
|
||||
if(disable)
|
||||
element.style.color = 'red';
|
||||
else if(warn)
|
||||
element.style.color = '#FF8C00';
|
||||
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));
|
||||
|
||||
User.getUser(id, function(data) {
|
||||
if(data !== null) {
|
||||
document.getElementById("onionr-profile-user-icon").src = "data:image/jpeg;base64," + Sanitize.html(data.getIcon());
|
||||
document.getElementById("onionr-profile-user-icon").b64 = Sanitize.html(data.getIcon());
|
||||
document.getElementById("onionr-profile-username").innerHTML = Sanitize.html(Sanitize.username(data.getName()));
|
||||
document.getElementById("onionr-profile-username").title = Sanitize.html(data.getID());
|
||||
document.getElementById("onionr-profile-description").innerHTML = Sanitize.html(Sanitize.description(data.getDescription()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateUser() {
|
||||
toggleSaveButton(false);
|
||||
|
||||
// jQuery('#modal').modal('show');
|
||||
|
||||
var name = jQuery('#onionr-profile-username').text();
|
||||
var id = document.getElementById("onionr-profile-username").title;
|
||||
var icon = document.getElementById("onionr-profile-user-icon").b64;
|
||||
var description = jQuery("#onionr-profile-description").text();
|
||||
|
||||
var user = new User();
|
||||
|
||||
user.setName(name);
|
||||
user.setID(id);
|
||||
user.setIcon(icon);
|
||||
user.setDescription(Sanitize.description(description));
|
||||
|
||||
user.remember();
|
||||
user.save(function() {
|
||||
setCurrentUser(user);
|
||||
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
function cancelUpdate() {
|
||||
toggleSaveButton(false);
|
||||
|
||||
var name = jQuery('#onionr-profile-username').text();
|
||||
var id = document.getElementById("onionr-profile-username").title;
|
||||
|
||||
viewProfile(id, name);
|
||||
}
|
||||
|
||||
function toggleSaveButton(show) {
|
||||
document.getElementById("onionr-profile-edit").style.display = (show ? 'block' : 'none');
|
||||
}
|
||||
|
||||
function makePost() {
|
||||
var content = document.getElementById("onionr-post-creator-content").value;
|
||||
|
||||
if(content.trim() !== '') {
|
||||
var post = new Post();
|
||||
|
||||
post.setUser(getCurrentUser());
|
||||
post.setContent(content);
|
||||
post.setPostDate(new Date());
|
||||
|
||||
post.save(function(data) {}); // async, but no function
|
||||
|
||||
document.getElementById('onionr-timeline-posts').innerHTML = post.getHTML() + document.getElementById('onionr-timeline-posts').innerHTML;
|
||||
|
||||
document.getElementById("onionr-post-creator-content").value = "";
|
||||
document.getElementById("onionr-post-creator-content").focus();
|
||||
postCreatorChange();
|
||||
} else {
|
||||
console.log('Not making empty post.');
|
||||
}
|
||||
}
|
||||
|
||||
function getReplies(id, callback) {
|
||||
Block.getBlocks({'type' : 'onionr-post', 'parent' : id, 'signed' : true, 'reverse' : true}, callback);
|
||||
}
|
||||
|
||||
function focusPost(id) {
|
||||
viewReplies(id);
|
||||
}
|
||||
|
||||
function viewRepliesMobile(id) {
|
||||
var post = document.getElementById('onionr-post-' + id);
|
||||
|
||||
var user_name = '';
|
||||
var user_id = '';
|
||||
var user_id_trunc = '';
|
||||
var user_icon = '';
|
||||
var post_content = '';
|
||||
|
||||
if(post !== null && post !== undefined) {
|
||||
// if the post is in the timeline, get the data from it
|
||||
user_name = post.getElementsByClassName('onionr-post-user-name')[0].innerHTML;
|
||||
user_id = post.getElementsByClassName('onionr-post-user-id')[0].title;
|
||||
user_id_trunc = post.getElementsByClassName('onionr-post-user-id')[0].innerHTML;
|
||||
user_icon = post.getElementsByClassName('onionr-post-user-icon')[0].src;
|
||||
post_content = post.getElementsByClassName('onionr-post-content')[0].innerHTML;
|
||||
} else {
|
||||
// otherwise, fetch the data
|
||||
}
|
||||
|
||||
document.getElementById('onionr-post-focus-user-icon').src = user_icon;
|
||||
document.getElementById('onionr-post-focus-user-name').innerHTML = user_name;
|
||||
document.getElementById('onionr-post-focus-user-id').innerHTML = user_id_trunc;
|
||||
document.getElementById('onionr-post-focus-user-id').title = user_id;
|
||||
document.getElementById('onionr-post-focus-content').innerHTML = post_content;
|
||||
|
||||
document.getElementById('onionr-post-focus-reply-creator-user-name').innerHTML = Sanitize.html(Sanitize.username(getCurrentUser().getName()));
|
||||
document.getElementById('onionr-post-focus-reply-creator-user-icon').src = "data:image/jpeg;base64," + Sanitize.html(getCurrentUser().getIcon());
|
||||
document.getElementById('onionr-post-focus-reply-creator-content').value = '';
|
||||
document.getElementById('onionr-post-focus-reply-creator-content-message').value = '';
|
||||
|
||||
jQuery('#onionr-post-focus').modal('show');
|
||||
}
|
||||
|
||||
function viewReplies(id) {
|
||||
document.getElementById('onionr-replies-title').innerHTML = '<$= LANG.REPLIES $>';
|
||||
document.getElementById('onionr-reply-creator-panel').originalPost = id;
|
||||
document.getElementById('onionr-reply-creator-panel').innerHTML = '<$= jsTemplate('onionr-reply-creator') $>';
|
||||
|
||||
document.getElementById('onionr-reply-creator-content').innerHTML = '';
|
||||
document.getElementById("onionr-reply-creator-content").placeholder = "<$= LANG.POST_CREATOR_PLACEHOLDER $>";
|
||||
document.getElementById('onionr-reply-creator-user-name').innerHTML = Sanitize.html(Sanitize.username(getCurrentUser().getName()));
|
||||
document.getElementById('onionr-reply-creator-user-icon').src = "data:image/jpeg;base64," + Sanitize.html(getCurrentUser().getIcon());
|
||||
|
||||
document.getElementById('onionr-replies').innerHTML = '';
|
||||
getReplies(id, function(data) {
|
||||
var replies = document.getElementById('onionr-replies');
|
||||
|
||||
replies.innerHTML = '';
|
||||
|
||||
for(var i = 0; i < data.length; i++) {
|
||||
try {
|
||||
var block = data[i];
|
||||
|
||||
var finished = false;
|
||||
User.getUser(new String(block.getHeader('signer', 'unknown')), function(user) {
|
||||
var post = new Post();
|
||||
|
||||
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());
|
||||
|
||||
replies.innerHTML += post.getHTML('reply');
|
||||
}
|
||||
|
||||
finished = true;
|
||||
});
|
||||
|
||||
while(!finished);
|
||||
} catch(e) {
|
||||
console.log('Troublemaker block: ' + data[i].getHash());
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function makeReply() {
|
||||
var content = document.getElementById("onionr-reply-creator-content").value;
|
||||
|
||||
if(content.trim() !== '') {
|
||||
var post = new Post();
|
||||
|
||||
var originalPost = document.getElementById('onionr-reply-creator-panel').originalPost;
|
||||
|
||||
console.log('Original post hash: ' + originalPost);
|
||||
|
||||
post.setUser(getCurrentUser());
|
||||
post.setParent(originalPost);
|
||||
post.setContent(content);
|
||||
post.setPostDate(new Date());
|
||||
|
||||
post.save(function(data) {}); // async, but no function
|
||||
|
||||
document.getElementById('onionr-replies').innerHTML = post.getHTML('reply') + document.getElementById('onionr-replies').innerHTML;
|
||||
|
||||
document.getElementById("onionr-reply-creator-content").value = "";
|
||||
document.getElementById("onionr-reply-creator-content").focus();
|
||||
replyCreatorChange();
|
||||
} else {
|
||||
console.log('Not making empty reply.');
|
||||
}
|
||||
}
|
||||
|
||||
jQuery('body').on('click', '[data-editable]', function() {
|
||||
var el = jQuery(this);
|
||||
var txt = el.text();
|
||||
var maxlength = el.attr("maxlength");
|
||||
|
||||
var input = jQuery('<input/>').val(txt);
|
||||
input.attr('maxlength', maxlength);
|
||||
el.replaceWith(input);
|
||||
|
||||
var save = function() {
|
||||
var newTxt = input.val();
|
||||
|
||||
if(el.attr('id') === 'onionr-profile-username')
|
||||
newTxt = Sanitize.username(newTxt);
|
||||
if(el.attr('id') === 'onionr-profile-description')
|
||||
newTxt = Sanitize.description(newTxt);
|
||||
|
||||
var p = el.text(newTxt);
|
||||
|
||||
input.replaceWith(p);
|
||||
|
||||
if(newTxt !== txt)
|
||||
toggleSaveButton(true);
|
||||
};
|
||||
|
||||
var saveEnter = function(event) {
|
||||
console.log(event);
|
||||
console.log(event.keyCode);
|
||||
if (event.keyCode === 13)
|
||||
save();
|
||||
};
|
||||
|
||||
input.one('blur', save).bind('keyup', saveEnter).focus();
|
||||
});
|
||||
//viewProfile('$user-id-url', '$user-name-url')
|
||||
// jQuery('#onionr-post-user-id').on('click', function(e) { alert(3);});
|
||||
//jQuery('#onionr-post *').on('click', function(e) { e.stopPropagation(); });
|
||||
// jQuery('#onionr-post').click(function(e) { alert(1); });
|
||||
|
||||
currentUser = getCurrentUser();
|
||||
if(currentUser !== undefined && currentUser !== null) {
|
||||
document.getElementById("onionr-post-creator-user-name").innerHTML = Sanitize.html(currentUser.getName());
|
||||
document.getElementById("onionr-post-creator-user-id").innerHTML = "<$= LANG.POST_CREATOR_YOU $>";
|
||||
document.getElementById("onionr-post-creator-user-icon").src = "data:image/jpeg;base64," + Sanitize.html(currentUser.getIcon());
|
||||
document.getElementById("onionr-post-creator-user-id").title = currentUser.getID();
|
||||
|
||||
document.getElementById("onionr-post-creator-content").placeholder = "<$= LANG.POST_CREATOR_PLACEHOLDER $>";
|
||||
document.getElementById("onionr-post-focus-reply-creator-content").placeholder = "<$= LANG.POST_CREATOR_PLACEHOLDER $>";
|
||||
|
||||
document.getElementById("onionr-post-focus-reply-creator-user-id").innerHTML = "<$= LANG.POST_CREATOR_YOU $>";
|
||||
}
|
||||
|
||||
viewCurrentProfile = function() {
|
||||
viewProfile(encodeURIComponent(currentUser.getID()), encodeURIComponent(currentUser.getName()));
|
||||
}
|
||||
|
||||
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…
Add table
Add a link
Reference in a new issue