work on contact manager, removed old twitter-like ui for now
parent
4827ef6def
commit
3fc623b8ee
|
@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe
|
|||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at beardog@firemail.cc. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at beardog at mailbox.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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,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>
|
File diff suppressed because one or more lines are too long
|
@ -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…
Reference in New Issue