A few changes, click for details
- broke post liking - added more reliable replie
This commit is contained in:
parent
04f89383f7
commit
1b193d098b
@ -23,6 +23,7 @@ from onionrblockapi import Block
|
|||||||
import onionrutils, onionrcrypto, onionrproofs, onionrevents as events, onionrexceptions, onionrvalues
|
import onionrutils, onionrcrypto, onionrproofs, onionrevents as events, onionrexceptions, onionrvalues
|
||||||
import onionrblacklist
|
import onionrblacklist
|
||||||
import dbcreator
|
import dbcreator
|
||||||
|
|
||||||
if sys.version_info < (3, 6):
|
if sys.version_info < (3, 6):
|
||||||
try:
|
try:
|
||||||
import sha3
|
import sha3
|
||||||
@ -35,6 +36,7 @@ class Core:
|
|||||||
'''
|
'''
|
||||||
Initialize Core Onionr library
|
Initialize Core Onionr library
|
||||||
'''
|
'''
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.queueDB = 'data/queue.db'
|
self.queueDB = 'data/queue.db'
|
||||||
self.peerDB = 'data/peers.db'
|
self.peerDB = 'data/peers.db'
|
||||||
@ -86,7 +88,9 @@ class Core:
|
|||||||
return
|
return
|
||||||
|
|
||||||
def refreshFirstStartVars(self):
|
def refreshFirstStartVars(self):
|
||||||
'''Hack to refresh some vars which may not be set on first start'''
|
'''
|
||||||
|
Hack to refresh some vars which may not be set on first start
|
||||||
|
'''
|
||||||
if os.path.exists('data/hs/hostname'):
|
if os.path.exists('data/hs/hostname'):
|
||||||
with open('data/hs/hostname', 'r') as hs:
|
with open('data/hs/hostname', 'r') as hs:
|
||||||
self.hsAddress = hs.read().strip()
|
self.hsAddress = hs.read().strip()
|
||||||
@ -95,6 +99,7 @@ class Core:
|
|||||||
'''
|
'''
|
||||||
Adds a public key to the key database (misleading function name)
|
Adds a public key to the key database (misleading function name)
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# This function simply adds a peer to the DB
|
# This function simply adds a peer to the DB
|
||||||
if not self._utils.validatePubKey(peerID):
|
if not self._utils.validatePubKey(peerID):
|
||||||
return False
|
return False
|
||||||
@ -126,6 +131,7 @@ class Core:
|
|||||||
'''
|
'''
|
||||||
Add an address to the address database (only tor currently)
|
Add an address to the address database (only tor currently)
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if address == config.get('i2p.own_addr', None):
|
if address == config.get('i2p.own_addr', None):
|
||||||
|
|
||||||
return False
|
return False
|
||||||
@ -161,6 +167,7 @@ class Core:
|
|||||||
'''
|
'''
|
||||||
Remove an address from the address database
|
Remove an address from the address database
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if self._utils.validateID(address):
|
if self._utils.validateID(address):
|
||||||
conn = sqlite3.connect(self.addressDB)
|
conn = sqlite3.connect(self.addressDB)
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
@ -180,6 +187,7 @@ class Core:
|
|||||||
|
|
||||||
**You may want blacklist.addToDB(blockHash)
|
**You may want blacklist.addToDB(blockHash)
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if self._utils.validateHash(block):
|
if self._utils.validateHash(block):
|
||||||
conn = sqlite3.connect(self.blockDB)
|
conn = sqlite3.connect(self.blockDB)
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
@ -204,18 +212,21 @@ class Core:
|
|||||||
'''
|
'''
|
||||||
Generate the address database
|
Generate the address database
|
||||||
'''
|
'''
|
||||||
|
|
||||||
self.dbCreate.createAddressDB()
|
self.dbCreate.createAddressDB()
|
||||||
|
|
||||||
def createPeerDB(self):
|
def createPeerDB(self):
|
||||||
'''
|
'''
|
||||||
Generate the peer sqlite3 database and populate it with the peers table.
|
Generate the peer sqlite3 database and populate it with the peers table.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
self.dbCreate.createPeerDB()
|
self.dbCreate.createPeerDB()
|
||||||
|
|
||||||
def createBlockDB(self):
|
def createBlockDB(self):
|
||||||
'''
|
'''
|
||||||
Create a database for blocks
|
Create a database for blocks
|
||||||
'''
|
'''
|
||||||
|
|
||||||
self.dbCreate.createBlockDB()
|
self.dbCreate.createBlockDB()
|
||||||
|
|
||||||
def addToBlockDB(self, newHash, selfInsert=False, dataSaved=False):
|
def addToBlockDB(self, newHash, selfInsert=False, dataSaved=False):
|
||||||
@ -224,6 +235,7 @@ class Core:
|
|||||||
|
|
||||||
Should be in hex format!
|
Should be in hex format!
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if not os.path.exists(self.blockDB):
|
if not os.path.exists(self.blockDB):
|
||||||
raise Exception('Block db does not exist')
|
raise Exception('Block db does not exist')
|
||||||
if self._utils.hasBlock(newHash):
|
if self._utils.hasBlock(newHash):
|
||||||
@ -246,6 +258,7 @@ class Core:
|
|||||||
'''
|
'''
|
||||||
Simply return the data associated to a hash
|
Simply return the data associated to a hash
|
||||||
'''
|
'''
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# logger.debug('Opening %s' % (str(self.blockDataLocation) + str(hash) + '.dat'))
|
# logger.debug('Opening %s' % (str(self.blockDataLocation) + str(hash) + '.dat'))
|
||||||
dataFile = open(self.blockDataLocation + hash + '.dat', 'rb')
|
dataFile = open(self.blockDataLocation + hash + '.dat', 'rb')
|
||||||
@ -268,6 +281,7 @@ class Core:
|
|||||||
'''
|
'''
|
||||||
Set the data assciated with a hash
|
Set the data assciated with a hash
|
||||||
'''
|
'''
|
||||||
|
|
||||||
data = data
|
data = data
|
||||||
dataSize = sys.getsizeof(data)
|
dataSize = sys.getsizeof(data)
|
||||||
|
|
||||||
@ -303,6 +317,7 @@ class Core:
|
|||||||
'''
|
'''
|
||||||
Encrypt the data directory on Onionr shutdown
|
Encrypt the data directory on Onionr shutdown
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if os.path.exists('data.tar'):
|
if os.path.exists('data.tar'):
|
||||||
os.remove('data.tar')
|
os.remove('data.tar')
|
||||||
tar = tarfile.open("data.tar", "w")
|
tar = tarfile.open("data.tar", "w")
|
||||||
@ -320,6 +335,7 @@ class Core:
|
|||||||
'''
|
'''
|
||||||
Decrypt the data directory on startup
|
Decrypt the data directory on startup
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if not os.path.exists('data-encrypted.dat'):
|
if not os.path.exists('data-encrypted.dat'):
|
||||||
return (False, 'encrypted archive does not exist')
|
return (False, 'encrypted archive does not exist')
|
||||||
data = open('data-encrypted.dat', 'rb').read()
|
data = open('data-encrypted.dat', 'rb').read()
|
||||||
@ -341,6 +357,7 @@ class Core:
|
|||||||
|
|
||||||
This function intended to be used by the client. Queue to exchange data between "client" and server.
|
This function intended to be used by the client. Queue to exchange data between "client" and server.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
retData = False
|
retData = False
|
||||||
if not os.path.exists(self.queueDB):
|
if not os.path.exists(self.queueDB):
|
||||||
self.makeDaemonDB()
|
self.makeDaemonDB()
|
||||||
@ -364,25 +381,35 @@ class Core:
|
|||||||
return retData
|
return retData
|
||||||
|
|
||||||
def makeDaemonDB(self):
|
def makeDaemonDB(self):
|
||||||
'''generate the daemon queue db'''
|
'''
|
||||||
|
Generate the daemon queue db
|
||||||
|
'''
|
||||||
|
|
||||||
conn = sqlite3.connect(self.queueDB)
|
conn = sqlite3.connect(self.queueDB)
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
|
|
||||||
# Create table
|
# Create table
|
||||||
c.execute('''CREATE TABLE commands
|
c.execute('''CREATE TABLE commands
|
||||||
(id integer primary key autoincrement, command text, data text, date text)''')
|
(id integer primary key autoincrement, command text, data text, date text)''')
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
|
return
|
||||||
|
|
||||||
def daemonQueueAdd(self, command, data=''):
|
def daemonQueueAdd(self, command, data=''):
|
||||||
'''
|
'''
|
||||||
Add a command to the daemon queue, used by the communication daemon (communicator.py)
|
Add a command to the daemon queue, used by the communication daemon (communicator.py)
|
||||||
'''
|
'''
|
||||||
|
|
||||||
retData = True
|
retData = True
|
||||||
# Intended to be used by the web server
|
# Intended to be used by the web server
|
||||||
|
|
||||||
date = self._utils.getEpoch()
|
date = self._utils.getEpoch()
|
||||||
conn = sqlite3.connect(self.queueDB)
|
conn = sqlite3.connect(self.queueDB)
|
||||||
|
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
t = (command, data, date)
|
t = (command, data, date)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
c.execute('INSERT INTO commands (command, data, date) VALUES(?, ?, ?)', t)
|
c.execute('INSERT INTO commands (command, data, date) VALUES(?, ?, ?)', t)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
@ -398,13 +425,16 @@ class Core:
|
|||||||
'''
|
'''
|
||||||
Clear the daemon queue (somewhat dangerous)
|
Clear the daemon queue (somewhat dangerous)
|
||||||
'''
|
'''
|
||||||
|
|
||||||
conn = sqlite3.connect(self.queueDB)
|
conn = sqlite3.connect(self.queueDB)
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
c.execute('DELETE FROM commands;')
|
c.execute('DELETE FROM commands;')
|
||||||
conn.commit()
|
conn.commit()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
events.event('queue_clear', onionr = None)
|
events.event('queue_clear', onionr = None)
|
||||||
|
|
||||||
@ -543,13 +573,16 @@ class Core:
|
|||||||
failure int 6
|
failure int 6
|
||||||
lastConnect 7
|
lastConnect 7
|
||||||
'''
|
'''
|
||||||
|
|
||||||
conn = sqlite3.connect(self.addressDB)
|
conn = sqlite3.connect(self.addressDB)
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
|
|
||||||
command = (address,)
|
command = (address,)
|
||||||
infoNumbers = {'address': 0, 'type': 1, 'knownPeer': 2, 'speed': 3, 'success': 4, 'DBHash': 5, 'failure': 6, 'lastConnect': 7}
|
infoNumbers = {'address': 0, 'type': 1, 'knownPeer': 2, 'speed': 3, 'success': 4, 'DBHash': 5, 'failure': 6, 'lastConnect': 7}
|
||||||
info = infoNumbers[info]
|
info = infoNumbers[info]
|
||||||
iterCount = 0
|
iterCount = 0
|
||||||
retVal = ''
|
retVal = ''
|
||||||
|
|
||||||
for row in c.execute('SELECT * FROM adders WHERE address=?;', command):
|
for row in c.execute('SELECT * FROM adders WHERE address=?;', command):
|
||||||
for i in row:
|
for i in row:
|
||||||
if iterCount == info:
|
if iterCount == info:
|
||||||
@ -558,15 +591,19 @@ class Core:
|
|||||||
else:
|
else:
|
||||||
iterCount += 1
|
iterCount += 1
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return retVal
|
return retVal
|
||||||
|
|
||||||
def setAddressInfo(self, address, key, data):
|
def setAddressInfo(self, address, key, data):
|
||||||
'''
|
'''
|
||||||
Update an address for a key
|
Update an address for a key
|
||||||
'''
|
'''
|
||||||
|
|
||||||
conn = sqlite3.connect(self.addressDB)
|
conn = sqlite3.connect(self.addressDB)
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
|
|
||||||
command = (data, address)
|
command = (data, address)
|
||||||
|
|
||||||
# TODO: validate key on whitelist
|
# TODO: validate key on whitelist
|
||||||
if key not in ('address', 'type', 'knownPeer', 'speed', 'success', 'DBHash', 'failure', 'lastConnect', 'lastConnectAttempt'):
|
if key not in ('address', 'type', 'knownPeer', 'speed', 'success', 'DBHash', 'failure', 'lastConnect', 'lastConnectAttempt'):
|
||||||
raise Exception("Got invalid database key when setting address info")
|
raise Exception("Got invalid database key when setting address info")
|
||||||
@ -574,18 +611,22 @@ class Core:
|
|||||||
c.execute('UPDATE adders SET ' + key + ' = ? WHERE address=?', command)
|
c.execute('UPDATE adders SET ' + key + ' = ? WHERE address=?', command)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def getBlockList(self, unsaved = False): # TODO: Use unsaved??
|
def getBlockList(self, unsaved = False): # TODO: Use unsaved??
|
||||||
'''
|
'''
|
||||||
Get list of our blocks
|
Get list of our blocks
|
||||||
'''
|
'''
|
||||||
|
|
||||||
conn = sqlite3.connect(self.blockDB)
|
conn = sqlite3.connect(self.blockDB)
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
|
|
||||||
if unsaved:
|
if unsaved:
|
||||||
execute = 'SELECT hash FROM hashes WHERE dataSaved != 1 ORDER BY RANDOM();'
|
execute = 'SELECT hash FROM hashes WHERE dataSaved != 1 ORDER BY RANDOM();'
|
||||||
else:
|
else:
|
||||||
execute = 'SELECT hash FROM hashes ORDER BY dateReceived ASC;'
|
execute = 'SELECT hash FROM hashes ORDER BY dateReceived ASC;'
|
||||||
|
|
||||||
rows = list()
|
rows = list()
|
||||||
for row in c.execute(execute):
|
for row in c.execute(execute):
|
||||||
for i in row:
|
for i in row:
|
||||||
@ -597,8 +638,10 @@ class Core:
|
|||||||
'''
|
'''
|
||||||
Returns the date a block was received
|
Returns the date a block was received
|
||||||
'''
|
'''
|
||||||
|
|
||||||
conn = sqlite3.connect(self.blockDB)
|
conn = sqlite3.connect(self.blockDB)
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
|
|
||||||
execute = 'SELECT dateReceived FROM hashes WHERE hash=?;'
|
execute = 'SELECT dateReceived FROM hashes WHERE hash=?;'
|
||||||
args = (blockHash,)
|
args = (blockHash,)
|
||||||
for row in c.execute(execute, args):
|
for row in c.execute(execute, args):
|
||||||
@ -611,14 +654,18 @@ class Core:
|
|||||||
'''
|
'''
|
||||||
Returns a list of blocks by the type
|
Returns a list of blocks by the type
|
||||||
'''
|
'''
|
||||||
|
|
||||||
conn = sqlite3.connect(self.blockDB)
|
conn = sqlite3.connect(self.blockDB)
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
|
|
||||||
if orderDate:
|
if orderDate:
|
||||||
execute = 'SELECT hash FROM hashes WHERE dataType=? ORDER BY dateReceived;'
|
execute = 'SELECT hash FROM hashes WHERE dataType=? ORDER BY dateReceived;'
|
||||||
else:
|
else:
|
||||||
execute = 'SELECT hash FROM hashes WHERE dataType=?;'
|
execute = 'SELECT hash FROM hashes WHERE dataType=?;'
|
||||||
|
|
||||||
args = (blockType,)
|
args = (blockType,)
|
||||||
rows = list()
|
rows = list()
|
||||||
|
|
||||||
for row in c.execute(execute, args):
|
for row in c.execute(execute, args):
|
||||||
for i in row:
|
for i in row:
|
||||||
rows.append(i)
|
rows.append(i)
|
||||||
@ -670,6 +717,7 @@ class Core:
|
|||||||
Inserts a block into the network
|
Inserts a block into the network
|
||||||
encryptType must be specified to encrypt a block
|
encryptType must be specified to encrypt a block
|
||||||
'''
|
'''
|
||||||
|
|
||||||
retData = False
|
retData = False
|
||||||
|
|
||||||
# check nonce
|
# check nonce
|
||||||
|
@ -72,6 +72,7 @@ class Block:
|
|||||||
'''
|
'''
|
||||||
Decrypt a block, loading decrypted data into their vars
|
Decrypt a block, loading decrypted data into their vars
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if self.decrypted:
|
if self.decrypted:
|
||||||
return True
|
return True
|
||||||
retData = False
|
retData = False
|
||||||
@ -104,6 +105,7 @@ class Block:
|
|||||||
'''
|
'''
|
||||||
Verify if a block's signature is signed by its claimed signer
|
Verify if a block's signature is signed by its claimed signer
|
||||||
'''
|
'''
|
||||||
|
|
||||||
core = self.getCore()
|
core = self.getCore()
|
||||||
|
|
||||||
if core._crypto.edVerify(data=self.signedData, key=self.signer, sig=self.signature, encodedData=True):
|
if core._crypto.edVerify(data=self.signedData, key=self.signer, sig=self.signature, encodedData=True):
|
||||||
|
31
onionr/static-data/www/ui/common/onionr-reply-creator.html
Normal file
31
onionr/static-data/www/ui/common/onionr-reply-creator.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<!-- 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 -->
|
@ -0,0 +1,30 @@
|
|||||||
|
<!-- 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 -->
|
31
onionr/static-data/www/ui/common/onionr-timeline-reply.html
Normal file
31
onionr/static-data/www/ui/common/onionr-timeline-reply.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<!-- 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 -->
|
8
onionr/static-data/www/ui/dist/css/main.css
vendored
8
onionr/static-data/www/ui/dist/css/main.css
vendored
@ -37,6 +37,14 @@ body {
|
|||||||
|
|
||||||
/* timeline */
|
/* timeline */
|
||||||
|
|
||||||
|
.onionr-post-focus-separator {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
padding: 1rem;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.onionr-post {
|
.onionr-post {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
@ -5,6 +5,17 @@ body {
|
|||||||
|
|
||||||
/* timeline */
|
/* timeline */
|
||||||
|
|
||||||
|
.onionr-post-focus-separator {
|
||||||
|
border-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
border: 1px solid black;
|
||||||
|
border-radius: 1rem;
|
||||||
|
|
||||||
|
background-color: lightgray;
|
||||||
|
}
|
||||||
|
|
||||||
.onionr-post {
|
.onionr-post {
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
|
79
onionr/static-data/www/ui/dist/index.html
vendored
79
onionr/static-data/www/ui/dist/index.html
vendored
@ -73,7 +73,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- POST -->
|
<!-- POST CREATOR -->
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="onionr-post-creator">
|
<div class="onionr-post-creator">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -97,7 +97,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- END POST -->
|
<!-- END POST CREATOR -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row" id="onionr-timeline-posts">
|
<div class="row" id="onionr-timeline-posts">
|
||||||
@ -108,29 +108,88 @@
|
|||||||
<div class="d-none d-lg-block col-lg-3">
|
<div class="d-none d-lg-block col-lg-3">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="onionr-trending">
|
<div class="onionr-replies">
|
||||||
<h2>Trending</h2>
|
<h2 id="onionr-replies-title"></h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="onionr-reply-creator-panel">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- onionr-post-focus -->
|
<!-- 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 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-dialog modal-dialog-centered" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="row p-3">
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
<div class="col-2">
|
||||||
<span aria-hidden="true">×</span>
|
<img src="" id="onionr-post-focus-user-icon" class="onionr-post-user-icon">
|
||||||
</button>
|
</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>
|
</div>
|
||||||
<div class="modal-body" id="onionr-post-focus-content"></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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="onionr-post-focus-replies"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- END POST FOCUS REPLIES -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- END POST FOCUS DIALOG -->
|
||||||
|
|
||||||
<!-- Modal -->
|
<!-- Modal -->
|
||||||
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="modal-title" aria-hidden="true">
|
<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-dialog modal-dialog-centered" role="document">
|
||||||
|
97
onionr/static-data/www/ui/dist/js/main.js
vendored
97
onionr/static-data/www/ui/dist/js/main.js
vendored
@ -239,7 +239,7 @@ class User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static getUser(id, callback) {
|
static getUser(id, callback) {
|
||||||
console.log(callback);
|
// console.log(callback);
|
||||||
var user = deserializeUser(id);
|
var user = deserializeUser(id);
|
||||||
if(user === null) {
|
if(user === null) {
|
||||||
Block.getBlocks({'type' : 'onionr-user-info', 'signed' : true, 'reverse' : true}, function(data) {
|
Block.getBlocks({'type' : 'onionr-user-info', 'signed' : true, 'reverse' : true}, function(data) {
|
||||||
@ -256,7 +256,7 @@ class User {
|
|||||||
user.setID(id);
|
user.setID(id);
|
||||||
|
|
||||||
user.remember();
|
user.remember();
|
||||||
console.log(callback);
|
// console.log(callback);
|
||||||
callback(user);
|
callback(user);
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
@ -272,7 +272,7 @@ class User {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log(callback);
|
// console.log(callback);
|
||||||
callback(user);
|
callback(user);
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
@ -282,7 +282,39 @@ class User {
|
|||||||
/* post class */
|
/* post class */
|
||||||
class Post {
|
class Post {
|
||||||
/* returns the html content of a post */
|
/* returns the html content of a post */
|
||||||
getHTML() {
|
getHTML(type) {
|
||||||
|
var replyTemplate = '<!-- 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">reply</a>\
|
||||||
|
</div>\
|
||||||
|
</div>\
|
||||||
|
</div>\
|
||||||
|
</div>\
|
||||||
|
</div>\
|
||||||
|
<!-- END POST -->\
|
||||||
|
';
|
||||||
var postTemplate = '<!-- POST -->\
|
var postTemplate = '<!-- POST -->\
|
||||||
<div class="col-12">\
|
<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="onionr-post" id="onionr-post-$post-hash" onclick="focusPost(\'$post-hash\', \'user-id-url\', \'user-name-url\', \'\')">\
|
||||||
@ -317,29 +349,37 @@ class Post {
|
|||||||
<!-- END POST -->\
|
<!-- END POST -->\
|
||||||
';
|
';
|
||||||
|
|
||||||
|
var template = '';
|
||||||
|
|
||||||
|
if(type !== undefined && type !== null && type == 'reply')
|
||||||
|
template = replyTemplate;
|
||||||
|
else
|
||||||
|
template = postTemplate;
|
||||||
|
|
||||||
var device = (jQuery(document).width() < 768 ? 'mobile' : 'desktop');
|
var device = (jQuery(document).width() < 768 ? 'mobile' : 'desktop');
|
||||||
|
|
||||||
postTemplate = postTemplate.replaceAll('$user-name-url', Sanitize.html(Sanitize.url(this.getUser().getName())));
|
template = template.replaceAll('$user-name-url', Sanitize.html(Sanitize.url(this.getUser().getName())));
|
||||||
postTemplate = postTemplate.replaceAll('$user-name', Sanitize.html(this.getUser().getName()));
|
template = template.replaceAll('$user-name', Sanitize.html(this.getUser().getName()));
|
||||||
postTemplate = postTemplate.replaceAll('$user-id-url', Sanitize.html(Sanitize.url(this.getUser().getID())));
|
template = template.replaceAll('$user-id-url', Sanitize.html(Sanitize.url(this.getUser().getID())));
|
||||||
|
|
||||||
postTemplate = postTemplate.replaceAll('$user-id-truncated', Sanitize.html(this.getUser().getID().substring(0, 12) + '...'));
|
template = template.replaceAll('$user-id-truncated', Sanitize.html(this.getUser().getID().substring(0, 12) + '...'));
|
||||||
// postTemplate = postTemplate.replaceAll('$user-id-truncated', Sanitize.html(this.getUser().getID().split('-').slice(0, 4).join('-')));
|
// template = template.replaceAll('$user-id-truncated', Sanitize.html(this.getUser().getID().split('-').slice(0, 4).join('-')));
|
||||||
|
|
||||||
postTemplate = postTemplate.replaceAll('$user-id', Sanitize.html(this.getUser().getID()));
|
template = template.replaceAll('$user-id', Sanitize.html(this.getUser().getID()));
|
||||||
postTemplate = postTemplate.replaceAll('$user-image', "data:image/jpeg;base64," + Sanitize.html(this.getUser().getIcon()));
|
template = template.replaceAll('$user-image', "data:image/jpeg;base64," + Sanitize.html(this.getUser().getIcon()));
|
||||||
postTemplate = postTemplate.replaceAll('$content', Sanitize.html(this.getContent()).replaceAll('\n', '<br />', 16)); // Maximum of 16 lines
|
template = template.replaceAll('$content', Sanitize.html(this.getContent()).replaceAll('\n', '<br />', 16)); // Maximum of 16 lines
|
||||||
postTemplate = postTemplate.replaceAll('$post-hash', this.getHash());
|
template = template.replaceAll('$post-hash', this.getHash());
|
||||||
postTemplate = postTemplate.replaceAll('$date-relative', timeSince(this.getPostDate(), device) + (device === 'desktop' ? ' ago' : ''));
|
template = template.replaceAll('$date-relative-truncated', timeSince(this.getPostDate(), 'mobile'));
|
||||||
postTemplate = postTemplate.replaceAll('$date', this.getPostDate().toLocaleString());
|
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']) {
|
if(this.getHash() in getPostMap() && getPostMap()[this.getHash()]['liked']) {
|
||||||
postTemplate = postTemplate.replaceAll('$liked', 'unlike');
|
template = template.replaceAll('$liked', 'unlike');
|
||||||
} else {
|
} else {
|
||||||
postTemplate = postTemplate.replaceAll('$liked', 'like');
|
template = template.replaceAll('$liked', 'like');
|
||||||
}
|
}
|
||||||
|
|
||||||
return postTemplate;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
setUser(user) {
|
setUser(user) {
|
||||||
@ -358,6 +398,14 @@ class Post {
|
|||||||
return this.content;
|
return this.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setParent(parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
getParent() {
|
||||||
|
return this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
setPostDate(date) { // unix timestamp input
|
setPostDate(date) { // unix timestamp input
|
||||||
if(date instanceof Date)
|
if(date instanceof Date)
|
||||||
this.date = date;
|
this.date = date;
|
||||||
@ -380,6 +428,9 @@ class Post {
|
|||||||
save(callback) {
|
save(callback) {
|
||||||
var args = {'type' : 'onionr-post', 'sign' : true, 'content' : JSON.stringify({'content' : this.getContent()})};
|
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());
|
var url = '/client/?action=insertBlock&data=' + Sanitize.url(JSON.stringify(args)) + '&token=' + Sanitize.url(getWebPassword()) + '&timingToken=' + Sanitize.url(getTimingToken());
|
||||||
|
|
||||||
console.log(url);
|
console.log(url);
|
||||||
@ -458,8 +509,12 @@ class Block {
|
|||||||
|
|
||||||
// returns the parent block's hash (not Block object, for performance)
|
// returns the parent block's hash (not Block object, for performance)
|
||||||
getParent() {
|
getParent() {
|
||||||
if(!(this.parent instanceof Block) && this.parent !== undefined && this.parent !== null)
|
// console.log(this.parent);
|
||||||
this.parent = Block.openBlock(this.parent); // convert hash to Block object
|
|
||||||
|
// 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;
|
return this.parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,7 +617,7 @@ class Block {
|
|||||||
|
|
||||||
// recreates a block by hash
|
// recreates a block by hash
|
||||||
static openBlock(hash) {
|
static openBlock(hash) {
|
||||||
return parseBlock(response);
|
return Block.parseBlock(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
// converts an associative array to a Block
|
// converts an associative array to a Block
|
||||||
|
255
onionr/static-data/www/ui/dist/js/timeline.js
vendored
255
onionr/static-data/www/ui/dist/js/timeline.js
vendored
@ -11,7 +11,7 @@ Block.getBlocks({'type' : 'onionr-post', 'signed' : true, 'reverse' : true}, fun
|
|||||||
var blockContent = JSON.parse(block.getContent());
|
var blockContent = JSON.parse(block.getContent());
|
||||||
|
|
||||||
// just ignore anything shorter than 280 characters
|
// just ignore anything shorter than 280 characters
|
||||||
if(String(blockContent['content']).length <= 280) {
|
if(String(blockContent['content']).length <= 280 && block.getParent() === null) {
|
||||||
post.setContent(blockContent['content']);
|
post.setContent(blockContent['content']);
|
||||||
post.setPostDate(block.getDate());
|
post.setPostDate(block.getDate());
|
||||||
post.setUser(user);
|
post.setUser(user);
|
||||||
@ -104,6 +104,106 @@ function postCreatorChange() {
|
|||||||
button.disabled = false;
|
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) {
|
function viewProfile(id, name) {
|
||||||
id = decodeURIComponent(id);
|
id = decodeURIComponent(id);
|
||||||
document.getElementById("onionr-profile-username").innerHTML = Sanitize.html(decodeURIComponent(name));
|
document.getElementById("onionr-profile-username").innerHTML = Sanitize.html(decodeURIComponent(name));
|
||||||
@ -179,12 +279,155 @@ function makePost() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getReplies(id, callback) {
|
||||||
|
Block.getBlocks({'type' : 'onionr-post', 'parent' : id, 'signed' : true, 'reverse' : true}, callback);
|
||||||
|
}
|
||||||
|
|
||||||
function focusPost(id) {
|
function focusPost(id) {
|
||||||
document.getElementById("onionr-post-focus-content").innerHTML = "";
|
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');
|
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() {
|
jQuery('body').on('click', '[data-editable]', function() {
|
||||||
var el = jQuery(this);
|
var el = jQuery(this);
|
||||||
var txt = el.text();
|
var txt = el.text();
|
||||||
@ -220,9 +463,9 @@ jQuery('body').on('click', '[data-editable]', function() {
|
|||||||
input.one('blur', save).bind('keyup', saveEnter).focus();
|
input.one('blur', save).bind('keyup', saveEnter).focus();
|
||||||
});
|
});
|
||||||
//viewProfile('$user-id-url', '$user-name-url')
|
//viewProfile('$user-id-url', '$user-name-url')
|
||||||
jQuery('#onionr-post-user-id').on('click', function(e) { alert(3);});
|
// jQuery('#onionr-post-user-id').on('click', function(e) { alert(3);});
|
||||||
//jQuery('#onionr-post *').on('click', function(e) { e.stopPropagation(); });
|
//jQuery('#onionr-post *').on('click', function(e) { e.stopPropagation(); });
|
||||||
jQuery('#onionr-post').click(function(e) { alert(1); });
|
// jQuery('#onionr-post').click(function(e) { alert(1); });
|
||||||
|
|
||||||
currentUser = getCurrentUser();
|
currentUser = getCurrentUser();
|
||||||
if(currentUser !== undefined && currentUser !== null) {
|
if(currentUser !== undefined && currentUser !== null) {
|
||||||
@ -230,7 +473,11 @@ if(currentUser !== undefined && currentUser !== null) {
|
|||||||
document.getElementById("onionr-post-creator-user-id").innerHTML = "you";
|
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-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-user-id").title = currentUser.getID();
|
||||||
|
|
||||||
document.getElementById("onionr-post-creator-content").placeholder = "Enter a message here...";
|
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() {
|
viewCurrentProfile = function() {
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
"LATEST" : "Latest...",
|
"LATEST" : "Latest...",
|
||||||
"TRENDING" : "Trending",
|
"TRENDING" : "Trending",
|
||||||
|
"REPLIES" : "Replies",
|
||||||
|
|
||||||
"MODAL_TITLE" : "Loading...",
|
"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.",
|
"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.",
|
||||||
@ -20,10 +21,18 @@
|
|||||||
"POST_CREATOR_PLACEHOLDER" : "Enter a message here...",
|
"POST_CREATOR_PLACEHOLDER" : "Enter a message here...",
|
||||||
"POST_CREATOR_CREATE" : "Create post",
|
"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_MAXIMUM_NEWLINES" : "Please use less than 16 newlines",
|
||||||
"POST_CREATOR_MESSAGE_REMAINING" : "%s characters remaining",
|
"POST_CREATOR_MESSAGE_REMAINING" : "%s characters remaining",
|
||||||
"POST_CREATOR_MESSAGE_OVER" : "%s characters over maximum",
|
"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_SAVE" : "Save",
|
||||||
"PROFILE_EDIT_CANCEL" : "Cancel"
|
"PROFILE_EDIT_CANCEL" : "Cancel"
|
||||||
},
|
},
|
||||||
|
@ -37,6 +37,14 @@ body {
|
|||||||
|
|
||||||
/* timeline */
|
/* timeline */
|
||||||
|
|
||||||
|
.onionr-post-focus-separator {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
padding: 1rem;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.onionr-post {
|
.onionr-post {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
@ -5,6 +5,17 @@ body {
|
|||||||
|
|
||||||
/* timeline */
|
/* timeline */
|
||||||
|
|
||||||
|
.onionr-post-focus-separator {
|
||||||
|
border-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
border: 1px solid black;
|
||||||
|
border-radius: 1rem;
|
||||||
|
|
||||||
|
background-color: lightgray;
|
||||||
|
}
|
||||||
|
|
||||||
.onionr-post {
|
.onionr-post {
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- POST -->
|
<!-- POST CREATOR -->
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="onionr-post-creator">
|
<div class="onionr-post-creator">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -67,7 +67,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- END POST -->
|
<!-- END POST CREATOR -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row" id="onionr-timeline-posts">
|
<div class="row" id="onionr-timeline-posts">
|
||||||
@ -78,28 +78,57 @@
|
|||||||
<div class="d-none d-lg-block col-lg-3">
|
<div class="d-none d-lg-block col-lg-3">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="onionr-trending">
|
<div class="onionr-replies">
|
||||||
<h2><$= LANG.TRENDING $></h2>
|
<h2 id="onionr-replies-title"></h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="onionr-reply-creator-panel">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- onionr-post-focus -->
|
<!-- 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 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-dialog modal-dialog-centered" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="row p-3">
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
<div class="col-2">
|
||||||
<span aria-hidden="true">×</span>
|
<img src="" id="onionr-post-focus-user-icon" class="onionr-post-user-icon">
|
||||||
</button>
|
</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 class="modal-body" id="onionr-post-focus-content"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- END POST FOCUS DIALOG -->
|
||||||
|
|
||||||
<footer />
|
<footer />
|
||||||
<script src="js/timeline.js"></script>
|
<script src="js/timeline.js"></script>
|
||||||
|
@ -239,7 +239,7 @@ class User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static getUser(id, callback) {
|
static getUser(id, callback) {
|
||||||
console.log(callback);
|
// console.log(callback);
|
||||||
var user = deserializeUser(id);
|
var user = deserializeUser(id);
|
||||||
if(user === null) {
|
if(user === null) {
|
||||||
Block.getBlocks({'type' : 'onionr-user-info', 'signed' : true, 'reverse' : true}, function(data) {
|
Block.getBlocks({'type' : 'onionr-user-info', 'signed' : true, 'reverse' : true}, function(data) {
|
||||||
@ -256,7 +256,7 @@ class User {
|
|||||||
user.setID(id);
|
user.setID(id);
|
||||||
|
|
||||||
user.remember();
|
user.remember();
|
||||||
console.log(callback);
|
// console.log(callback);
|
||||||
callback(user);
|
callback(user);
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
@ -272,7 +272,7 @@ class User {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log(callback);
|
// console.log(callback);
|
||||||
callback(user);
|
callback(user);
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
@ -282,32 +282,41 @@ class User {
|
|||||||
/* post class */
|
/* post class */
|
||||||
class Post {
|
class Post {
|
||||||
/* returns the html content of a post */
|
/* returns the html content of a post */
|
||||||
getHTML() {
|
getHTML(type) {
|
||||||
|
var replyTemplate = '<$= jsTemplate('onionr-timeline-reply') $>';
|
||||||
var postTemplate = '<$= jsTemplate('onionr-timeline-post') $>';
|
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');
|
var device = (jQuery(document).width() < 768 ? 'mobile' : 'desktop');
|
||||||
|
|
||||||
postTemplate = postTemplate.replaceAll('$user-name-url', Sanitize.html(Sanitize.url(this.getUser().getName())));
|
template = template.replaceAll('$user-name-url', Sanitize.html(Sanitize.url(this.getUser().getName())));
|
||||||
postTemplate = postTemplate.replaceAll('$user-name', Sanitize.html(this.getUser().getName()));
|
template = template.replaceAll('$user-name', Sanitize.html(this.getUser().getName()));
|
||||||
postTemplate = postTemplate.replaceAll('$user-id-url', Sanitize.html(Sanitize.url(this.getUser().getID())));
|
template = template.replaceAll('$user-id-url', Sanitize.html(Sanitize.url(this.getUser().getID())));
|
||||||
|
|
||||||
postTemplate = postTemplate.replaceAll('$user-id-truncated', Sanitize.html(this.getUser().getID().substring(0, 12) + '...'));
|
template = template.replaceAll('$user-id-truncated', Sanitize.html(this.getUser().getID().substring(0, 12) + '...'));
|
||||||
// postTemplate = postTemplate.replaceAll('$user-id-truncated', Sanitize.html(this.getUser().getID().split('-').slice(0, 4).join('-')));
|
// template = template.replaceAll('$user-id-truncated', Sanitize.html(this.getUser().getID().split('-').slice(0, 4).join('-')));
|
||||||
|
|
||||||
postTemplate = postTemplate.replaceAll('$user-id', Sanitize.html(this.getUser().getID()));
|
template = template.replaceAll('$user-id', Sanitize.html(this.getUser().getID()));
|
||||||
postTemplate = postTemplate.replaceAll('$user-image', "data:image/jpeg;base64," + Sanitize.html(this.getUser().getIcon()));
|
template = template.replaceAll('$user-image', "data:image/jpeg;base64," + Sanitize.html(this.getUser().getIcon()));
|
||||||
postTemplate = postTemplate.replaceAll('$content', Sanitize.html(this.getContent()).replaceAll('\n', '<br />', 16)); // Maximum of 16 lines
|
template = template.replaceAll('$content', Sanitize.html(this.getContent()).replaceAll('\n', '<br />', 16)); // Maximum of 16 lines
|
||||||
postTemplate = postTemplate.replaceAll('$post-hash', this.getHash());
|
template = template.replaceAll('$post-hash', this.getHash());
|
||||||
postTemplate = postTemplate.replaceAll('$date-relative', timeSince(this.getPostDate(), device) + (device === 'desktop' ? ' ago' : ''));
|
template = template.replaceAll('$date-relative-truncated', timeSince(this.getPostDate(), 'mobile'));
|
||||||
postTemplate = postTemplate.replaceAll('$date', this.getPostDate().toLocaleString());
|
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']) {
|
if(this.getHash() in getPostMap() && getPostMap()[this.getHash()]['liked']) {
|
||||||
postTemplate = postTemplate.replaceAll('$liked', '<$= LANG.POST_UNLIKE $>');
|
template = template.replaceAll('$liked', '<$= LANG.POST_UNLIKE $>');
|
||||||
} else {
|
} else {
|
||||||
postTemplate = postTemplate.replaceAll('$liked', '<$= LANG.POST_LIKE $>');
|
template = template.replaceAll('$liked', '<$= LANG.POST_LIKE $>');
|
||||||
}
|
}
|
||||||
|
|
||||||
return postTemplate;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
setUser(user) {
|
setUser(user) {
|
||||||
@ -326,6 +335,14 @@ class Post {
|
|||||||
return this.content;
|
return this.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setParent(parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
getParent() {
|
||||||
|
return this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
setPostDate(date) { // unix timestamp input
|
setPostDate(date) { // unix timestamp input
|
||||||
if(date instanceof Date)
|
if(date instanceof Date)
|
||||||
this.date = date;
|
this.date = date;
|
||||||
@ -348,6 +365,9 @@ class Post {
|
|||||||
save(callback) {
|
save(callback) {
|
||||||
var args = {'type' : 'onionr-post', 'sign' : true, 'content' : JSON.stringify({'content' : this.getContent()})};
|
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());
|
var url = '/client/?action=insertBlock&data=' + Sanitize.url(JSON.stringify(args)) + '&token=' + Sanitize.url(getWebPassword()) + '&timingToken=' + Sanitize.url(getTimingToken());
|
||||||
|
|
||||||
console.log(url);
|
console.log(url);
|
||||||
@ -426,8 +446,12 @@ class Block {
|
|||||||
|
|
||||||
// returns the parent block's hash (not Block object, for performance)
|
// returns the parent block's hash (not Block object, for performance)
|
||||||
getParent() {
|
getParent() {
|
||||||
if(!(this.parent instanceof Block) && this.parent !== undefined && this.parent !== null)
|
// console.log(this.parent);
|
||||||
this.parent = Block.openBlock(this.parent); // convert hash to Block object
|
|
||||||
|
// 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;
|
return this.parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,7 +554,7 @@ class Block {
|
|||||||
|
|
||||||
// recreates a block by hash
|
// recreates a block by hash
|
||||||
static openBlock(hash) {
|
static openBlock(hash) {
|
||||||
return parseBlock(response);
|
return Block.parseBlock(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
// converts an associative array to a Block
|
// converts an associative array to a Block
|
||||||
|
@ -11,7 +11,7 @@ Block.getBlocks({'type' : 'onionr-post', 'signed' : true, 'reverse' : true}, fun
|
|||||||
var blockContent = JSON.parse(block.getContent());
|
var blockContent = JSON.parse(block.getContent());
|
||||||
|
|
||||||
// just ignore anything shorter than 280 characters
|
// just ignore anything shorter than 280 characters
|
||||||
if(String(blockContent['content']).length <= 280) {
|
if(String(blockContent['content']).length <= 280 && block.getParent() === null) {
|
||||||
post.setContent(blockContent['content']);
|
post.setContent(blockContent['content']);
|
||||||
post.setPostDate(block.getDate());
|
post.setPostDate(block.getDate());
|
||||||
post.setUser(user);
|
post.setUser(user);
|
||||||
@ -104,6 +104,106 @@ function postCreatorChange() {
|
|||||||
button.disabled = false;
|
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) {
|
function viewProfile(id, name) {
|
||||||
id = decodeURIComponent(id);
|
id = decodeURIComponent(id);
|
||||||
document.getElementById("onionr-profile-username").innerHTML = Sanitize.html(decodeURIComponent(name));
|
document.getElementById("onionr-profile-username").innerHTML = Sanitize.html(decodeURIComponent(name));
|
||||||
@ -179,12 +279,124 @@ function makePost() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getReplies(id, callback) {
|
||||||
|
Block.getBlocks({'type' : 'onionr-post', 'parent' : id, 'signed' : true, 'reverse' : true}, callback);
|
||||||
|
}
|
||||||
|
|
||||||
function focusPost(id) {
|
function focusPost(id) {
|
||||||
document.getElementById("onionr-post-focus-content").innerHTML = "";
|
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');
|
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() {
|
jQuery('body').on('click', '[data-editable]', function() {
|
||||||
var el = jQuery(this);
|
var el = jQuery(this);
|
||||||
var txt = el.text();
|
var txt = el.text();
|
||||||
@ -220,9 +432,9 @@ jQuery('body').on('click', '[data-editable]', function() {
|
|||||||
input.one('blur', save).bind('keyup', saveEnter).focus();
|
input.one('blur', save).bind('keyup', saveEnter).focus();
|
||||||
});
|
});
|
||||||
//viewProfile('$user-id-url', '$user-name-url')
|
//viewProfile('$user-id-url', '$user-name-url')
|
||||||
jQuery('#onionr-post-user-id').on('click', function(e) { alert(3);});
|
// jQuery('#onionr-post-user-id').on('click', function(e) { alert(3);});
|
||||||
//jQuery('#onionr-post *').on('click', function(e) { e.stopPropagation(); });
|
//jQuery('#onionr-post *').on('click', function(e) { e.stopPropagation(); });
|
||||||
jQuery('#onionr-post').click(function(e) { alert(1); });
|
// jQuery('#onionr-post').click(function(e) { alert(1); });
|
||||||
|
|
||||||
currentUser = getCurrentUser();
|
currentUser = getCurrentUser();
|
||||||
if(currentUser !== undefined && currentUser !== null) {
|
if(currentUser !== undefined && currentUser !== null) {
|
||||||
@ -230,7 +442,11 @@ if(currentUser !== undefined && currentUser !== null) {
|
|||||||
document.getElementById("onionr-post-creator-user-id").innerHTML = "<$= LANG.POST_CREATOR_YOU $>";
|
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-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-user-id").title = currentUser.getID();
|
||||||
|
|
||||||
document.getElementById("onionr-post-creator-content").placeholder = "<$= LANG.POST_CREATOR_PLACEHOLDER $>";
|
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() {
|
viewCurrentProfile = function() {
|
||||||
|
Loading…
Reference in New Issue
Block a user