CSS : Modify stylesheet due to modifying XHTML;
Python : Improve editing of tags; Python : Fix error upon no results on Atom; SQLite : Add triggers to count instances of entries; SQLite : Add triggers to delete entries SQLite : Add triggers to delete tags; XSLT : Remove control characters in favour of nbsp entity; XSLT : Improve links and design; XHTML : Add a new document about folksonomy; XHTML : Add a new template for URL; XHTML : Add indicators.
This commit is contained in:
parent
164b4d67d4
commit
a53c3a3436
34 changed files with 926 additions and 100 deletions
280
blasta.py
280
blasta.py
|
@ -491,6 +491,18 @@ class HttpInstance:
|
|||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
return response
|
||||
|
||||
@self.app.get('/help/about/folksonomy')
|
||||
def help_about_folksonomies_get(request: Request):
|
||||
jabber_id = Utilities.is_jid_matches_to_session(accounts, sessions, request)
|
||||
template_file = 'folksonomy.xhtml'
|
||||
template_dict = {
|
||||
'request' : request,
|
||||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
return response
|
||||
|
||||
@self.app.get('/help/about/ideas')
|
||||
def help_about_ideas_get(request: Request):
|
||||
jabber_id = Utilities.is_jid_matches_to_session(accounts, sessions, request)
|
||||
|
@ -849,6 +861,11 @@ class HttpInstance:
|
|||
entries_count = SQLite.get_entries_count_by_jid(db_file, jid)
|
||||
for tag, instances in SQLite.get_30_tags_by_jid(db_file, jid, index_first):
|
||||
tags_dict[tag] = instances
|
||||
if not entries_database:
|
||||
message = 'Blasta system message » Error: No entries were found.'
|
||||
description = 'No results'
|
||||
path = 'error'
|
||||
return result_post(request, jabber_id, description, message, path)
|
||||
if entries_count:
|
||||
entries = []
|
||||
for entry in entries_database:
|
||||
|
@ -856,6 +873,8 @@ class HttpInstance:
|
|||
for tag in SQLite.get_tags_by_entry_id(db_file, entry[0]):
|
||||
tags_sorted.append(tag[0])
|
||||
entry_jid = SQLite.get_jid_by_jid_id(db_file, entry[5])
|
||||
url_hash = Utilities.hash_url_to_md5(entry[2])
|
||||
instances = SQLite.get_entry_instances_by_url_hash(db_file, url_hash)
|
||||
entries.append(
|
||||
{'title' : entry[3],
|
||||
'link' : entry[2],
|
||||
|
@ -863,10 +882,10 @@ class HttpInstance:
|
|||
'published' : entry[6],
|
||||
'updated' : entry[7],
|
||||
'tags' : tags_sorted,
|
||||
'url_hash' : Utilities.hash_url_to_md5(entry[2]), #entry[1]
|
||||
'url_hash' : url_hash,
|
||||
'jid' : entry_jid,
|
||||
'name' : entry_jid, # jid.split('@')[0] if '@' in jid else jid,
|
||||
'instances' : entry[8]})
|
||||
'instances' : instances})
|
||||
for entry in entries:
|
||||
try:
|
||||
date_iso = entry['published']
|
||||
|
@ -985,6 +1004,7 @@ class HttpInstance:
|
|||
'jid': jid,
|
||||
'journal': journal,
|
||||
'message': message,
|
||||
'node_type': node_type,
|
||||
'page_next': page_next,
|
||||
'page_prev': page_prev,
|
||||
'pager' : True,
|
||||
|
@ -1095,6 +1115,11 @@ class HttpInstance:
|
|||
entries_database = SQLite.get_entries_recent(db_file, index_first)
|
||||
tags_of_entries = SQLite.get_30_tags_by_entries_recent(db_file, index_first)
|
||||
entries_count = SQLite.get_entries_count(db_file)
|
||||
if not entries_database:
|
||||
message = 'Blasta system message » Error: No entries were found.'
|
||||
description = 'No results'
|
||||
path = 'error'
|
||||
return result_post(request, jabber_id, description, message, path)
|
||||
tags_dict = {}
|
||||
#for tag, instances in SQLite.get_tags_30(db_file):
|
||||
for tag, instances in tags_of_entries:
|
||||
|
@ -1105,6 +1130,8 @@ class HttpInstance:
|
|||
for tag in SQLite.get_tags_by_entry_id(db_file, entry[0]):
|
||||
tags_sorted.append(tag[0])
|
||||
jid = SQLite.get_jid_by_jid_id(db_file, entry[5])
|
||||
url_hash = Utilities.hash_url_to_md5(entry[2])
|
||||
instances = SQLite.get_entry_instances_by_url_hash(db_file, url_hash)
|
||||
entries.append(
|
||||
{'title' : entry[3],
|
||||
'link' : entry[2],
|
||||
|
@ -1112,10 +1139,10 @@ class HttpInstance:
|
|||
'published' : entry[6],
|
||||
'updated' : entry[7],
|
||||
'tags' : tags_sorted,
|
||||
'url_hash' : Utilities.hash_url_to_md5(entry[2]), #entry[1]
|
||||
'url_hash' : url_hash, #entry[1]
|
||||
'jid' : jid,
|
||||
'name' : jid, # jid.split('@')[0] if '@' in jid else jid,
|
||||
'instances' : entry[8]})
|
||||
'instances' : instances})
|
||||
for entry in entries:
|
||||
try:
|
||||
date_iso = entry['published']
|
||||
|
@ -1139,7 +1166,6 @@ class HttpInstance:
|
|||
message = ('Welcome to Blasta, an XMPP PubSub oriented social '
|
||||
'bookmarks manager for organizing online content.')
|
||||
message_link = {'href' : '/help/about', 'text' : 'Learn more'}
|
||||
template_file = 'browse.xhtml'
|
||||
template_dict = {
|
||||
'request' : request,
|
||||
'description' : description,
|
||||
|
@ -1151,6 +1177,7 @@ class HttpInstance:
|
|||
'node_id' : node_id,
|
||||
'page_next' : page_next,
|
||||
'page_prev' : page_prev,
|
||||
'page_type' : page_type,
|
||||
'pager' : True,
|
||||
'param_query' : param_query,
|
||||
'param_tags' : param_tags,
|
||||
|
@ -1159,6 +1186,8 @@ class HttpInstance:
|
|||
'syndicate' : syndicate,
|
||||
'tags' : tags_dict}
|
||||
if param_mode == 'feed':
|
||||
# NOTE Consider scheme "feed" in order to prompt news
|
||||
# reader 'feed://' + request.url.netloc + request.url.path
|
||||
template_file = 'browse.atom'
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xml"
|
||||
|
@ -1507,7 +1536,6 @@ class HttpInstance:
|
|||
'jid' : jabber_id,
|
||||
'name' : name,
|
||||
'instances' : instances}
|
||||
#message = 'Discover new links and see who shares them'
|
||||
xmpp_instance = accounts[jabber_id]
|
||||
payload = Syndication.create_rfc4287_entry(entry_new)
|
||||
iq = await XmppPubsub.publish_node_item(
|
||||
|
@ -1556,12 +1584,19 @@ class HttpInstance:
|
|||
param_tags = request.query_params.get('tags', '')
|
||||
param_summary = request.query_params.get('summary', '')
|
||||
path = 'save'
|
||||
if request.query_params:
|
||||
message = message_link = None
|
||||
else:
|
||||
message = 'For greater ease, you migh want to try our'
|
||||
message_link = {'href' : '/help/utilities#buttons', 'text' : 'bookmarklets'}
|
||||
template_file = 'edit.xhtml'
|
||||
template_dict = {
|
||||
'request' : request,
|
||||
'description' : description,
|
||||
'jabber_id' : jabber_id,
|
||||
'journal' : journal,
|
||||
'message' : message,
|
||||
'message_link' : message_link,
|
||||
'path' : path,
|
||||
'routine' : routine,
|
||||
'summary' : param_summary,
|
||||
|
@ -1873,7 +1908,7 @@ class HttpInstance:
|
|||
entries.append(entry)
|
||||
tags_list = {}
|
||||
tags_and_instances = SQLite.get_tags_and_instances_by_url_hash(db_file, url_hash)
|
||||
for tag, instances in tags_and_instances: tags_list[tag] = instances
|
||||
for tag, tag_instances in tags_and_instances: tags_list[tag] = tag_instances
|
||||
else: # NOTE Is it possible to activate this else statement? Consider removal.
|
||||
# https://fastapi.tiangolo.com/tutorial/handling-errors/
|
||||
#raise HTTPException(status_code=404, detail="Item not found")
|
||||
|
@ -1890,8 +1925,9 @@ class HttpInstance:
|
|||
tags_sorted.append(tag[0])
|
||||
tags_list = {}
|
||||
tags_and_instances = SQLite.get_tags_and_instances_by_entry_id(db_file, entry[0])
|
||||
for tag, instances in tags_and_instances: tags_list[tag] = instances
|
||||
for tag, tag_instances in tags_and_instances: tags_list[tag] = tag_instances
|
||||
jid = SQLite.get_jid_by_jid_id(db_file, entry[5])
|
||||
instances = SQLite.get_entry_instances_by_url_hash(db_file, url_hash)
|
||||
entries.append(
|
||||
{'title' : entry[3],
|
||||
'link' : entry[2],
|
||||
|
@ -1900,10 +1936,10 @@ class HttpInstance:
|
|||
'published_mod' : Utilities.convert_iso8601_to_readable(entry[6]),
|
||||
'updated' : entry[7],
|
||||
'tags' : tags_sorted,
|
||||
'url_hash' : entry[1], # Utilities.hash_url_to_md5(entry[2])
|
||||
'url_hash' : url_hash,
|
||||
'jid' : jid,
|
||||
'name' : jid, # jid.split('@')[0] if '@' in jid else jid,
|
||||
'instances' : entry[8]})
|
||||
'instances' : instances})
|
||||
# message = 'XMPP system message » {}.'.format(iq)
|
||||
# if iq == 'Node not found':
|
||||
# description = 'An error has occurred'
|
||||
|
@ -1925,8 +1961,9 @@ class HttpInstance:
|
|||
tags_sorted.append(tag[0])
|
||||
tags_list = {}
|
||||
tags_and_instances = SQLite.get_tags_and_instances_by_entry_id(db_file, entry[0])
|
||||
for tag, instances in tags_and_instances: tags_list[tag] = instances
|
||||
for tag, tag_instances in tags_and_instances: tags_list[tag] = tag_instances
|
||||
jid = SQLite.get_jid_by_jid_id(db_file, entry[5])
|
||||
instances = SQLite.get_entry_instances_by_url_hash(db_file, url_hash)
|
||||
entries.append(
|
||||
{'title' : entry[3],
|
||||
'link' : entry[2],
|
||||
|
@ -1935,10 +1972,10 @@ class HttpInstance:
|
|||
'published_mod' : Utilities.convert_iso8601_to_readable(entry[6]),
|
||||
'updated' : entry[7],
|
||||
'tags' : tags_sorted,
|
||||
'url_hash' : entry[1], # Utilities.hash_url_to_md5(entry[2])
|
||||
'url_hash' : url_hash,
|
||||
'jid' : jid,
|
||||
'name' : jid, # jid.split('@')[0] if '@' in jid else jid,
|
||||
'instances' : entry[8]})
|
||||
'instances' : instances})
|
||||
else:
|
||||
# https://fastapi.tiangolo.com/tutorial/handling-errors/
|
||||
#raise HTTPException(status_code=404, detail="Item not found")
|
||||
|
@ -1946,8 +1983,20 @@ class HttpInstance:
|
|||
description = 'The requested bookmark does not exist'
|
||||
path = 'error'
|
||||
return result_post(request, jabber_id, description, message, path)
|
||||
message = 'Information for URL {}'.format(entries[0]['link']) # entry[2]
|
||||
description = 'Discover new links and see who shares them'
|
||||
message = 'Information for URI {}'.format(entries[0]['link']) # entry[2]
|
||||
if instances > 1:
|
||||
description = 'Discover new resources and see who shares them'
|
||||
template_file = 'people.xhtml'
|
||||
people_list = {}
|
||||
jids_and_tags = SQLite.get_jids_and_tags_by_url_hash(db_file, url_hash)
|
||||
for jid, tag in jids_and_tags:
|
||||
if jid in people_list and isinstance(people_list[jid], list):
|
||||
people_list[jid].append(tag)
|
||||
else:
|
||||
people_list[jid] = [tag]
|
||||
else:
|
||||
people_list = None
|
||||
description = 'Resource properties'
|
||||
template_file = 'browse.xhtml'
|
||||
template_dict = {
|
||||
'request' : request,
|
||||
|
@ -1960,6 +2009,7 @@ class HttpInstance:
|
|||
'node_id' : node_id,
|
||||
'param_hash' : param_hash,
|
||||
'path' : path,
|
||||
'people' : people_list,
|
||||
'pubsub_jid' : jabber_id_pubsub,
|
||||
'syndicate' : syndicate,
|
||||
'tags' : tags_list}
|
||||
|
@ -2071,14 +2121,17 @@ class HttpInstance:
|
|||
tags_list_new = tags_new
|
||||
tags_list_old = tags_old.split(', ')
|
||||
for tag in tags_list_old:
|
||||
tag_trim = tag.strip()
|
||||
if tag not in tags_list_new:
|
||||
tags_invalid.append(tag)
|
||||
tags_invalid.append(tag_trim)
|
||||
for tag in tags_list_new:
|
||||
if tag not in tags_list_old:
|
||||
tags_valid.append(tag)
|
||||
if tag:
|
||||
tag_trim = tag.strip()
|
||||
if tag_trim not in tags_list_old:
|
||||
tags_valid.append(tag_trim)
|
||||
# FIXME Variable tags_valid is not in use.
|
||||
# NOTE Variable tags_valid might not be needed. See function associate_entries_tags_jids.
|
||||
await SQLite.delete_combination_row_by_entry_id_and_tag_id_and_jid_id(db_file, url_hash, tags_invalid, jabber_id)
|
||||
entry['tags'] = tags_valid
|
||||
await SQLite.add_tags(db_file, [entry])
|
||||
# Slow (high I/O)
|
||||
entry_id = SQLite.get_entry_id_by_url_hash(db_file, url_hash)
|
||||
|
@ -2089,6 +2142,17 @@ class HttpInstance:
|
|||
# await SQLite.associate_entries_tags_jids(db_file, entry)
|
||||
else:
|
||||
await SQLite.associate_entries_tags_jids(db_file, entry)
|
||||
print('tags_new')
|
||||
print(tags_new)
|
||||
print('tags_old')
|
||||
print(tags_old)
|
||||
print('tags_valid')
|
||||
print(tags_valid)
|
||||
print('tags_invalid')
|
||||
print(tags_invalid)
|
||||
print(url_hash)
|
||||
print(jabber_id)
|
||||
await SQLite.delete_combination_row_by_url_hash_and_tag_and_jid(db_file, url_hash, tags_invalid, jabber_id)
|
||||
# Entry for HTML
|
||||
entry['published_mod'] = Utilities.convert_iso8601_to_readable(published)
|
||||
entry['updated_mod'] = Utilities.convert_iso8601_to_readable(timestamp)
|
||||
|
@ -2250,7 +2314,7 @@ class HttpInstance:
|
|||
|
||||
# Remove the item association from database
|
||||
await SQLite.delete_combination_row_by_jid_and_url_hash(db_file, url_hash, jabber_id)
|
||||
#await SQLite.delete_combination_row_by_entry_id_and_tag_id_and_jid_id(db_file, url_hash, entry['tags'], jabber_id)
|
||||
#await SQLite.delete_combination_row_by_url_hash_and_tag_and_jid(db_file, url_hash, entry['tags'], jabber_id)
|
||||
|
||||
# Remove the item from cache
|
||||
Data.remove_item_from_cache(jabber_id, node_type, url_hash)
|
||||
|
@ -2323,6 +2387,8 @@ class HttpInstance:
|
|||
description = 'Edit an existing bookmark'
|
||||
entry = Syndication.extract_items(item_payload)
|
||||
entry['instances'] = SQLite.get_entry_instances_by_url_hash(db_file, url_hash)
|
||||
print(jabber_id)
|
||||
print(entry['tags'])
|
||||
else:
|
||||
# TODO Consider redirect to path /save (function save_get)
|
||||
# NOTE This seems to be the best to do, albeit, perhaps the pathname should be /save instead of /url/hash/edit.
|
||||
|
@ -2338,8 +2404,8 @@ class HttpInstance:
|
|||
'summary' : result[4],
|
||||
'published' : result[6],
|
||||
'updated' : result[7],
|
||||
'tags' : tags_sorted,
|
||||
'instances' : result[8]}
|
||||
'tags' : tags_sorted}
|
||||
#'instances' : result[8],
|
||||
#'jid' = jabber_id,
|
||||
#'name' : name,
|
||||
#'url_hash' : url_hash
|
||||
|
@ -2347,6 +2413,14 @@ class HttpInstance:
|
|||
entry['jid'] = jabber_id
|
||||
entry['name'] = name
|
||||
entry['url_hash'] = url_hash
|
||||
else:
|
||||
message = 'XMPP system message » {}.'.format(iq)
|
||||
if iq == 'Node not found':
|
||||
description = 'An error has occurred'
|
||||
else:
|
||||
description = 'An unknown error has occurred'
|
||||
path = 'error'
|
||||
return result_post(request, jabber_id, description, message, path)
|
||||
template_file = 'edit.xhtml'
|
||||
template_dict = {
|
||||
'request' : request,
|
||||
|
@ -2543,6 +2617,64 @@ class SQLite:
|
|||
);
|
||||
"""
|
||||
)
|
||||
sql_trigger_instances_entry_decrease = (
|
||||
"""
|
||||
CREATE TRIGGER instances_entry_decrease
|
||||
AFTER DELETE ON combination_entries_tags_jids
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE main_entries
|
||||
SET instances = (
|
||||
SELECT COUNT(DISTINCT jid_id)
|
||||
FROM combination_entries_tags_jids
|
||||
WHERE entry_id = OLD.entry_id
|
||||
)
|
||||
WHERE id = OLD.entry_id;
|
||||
END;
|
||||
"""
|
||||
)
|
||||
sql_trigger_instances_entry_increase = (
|
||||
"""
|
||||
CREATE TRIGGER instances_entry_increase
|
||||
AFTER INSERT ON combination_entries_tags_jids
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE main_entries
|
||||
SET instances = (
|
||||
SELECT COUNT(DISTINCT jid_id)
|
||||
FROM combination_entries_tags_jids
|
||||
WHERE entry_id = NEW.entry_id
|
||||
)
|
||||
WHERE id = NEW.entry_id;
|
||||
END;
|
||||
"""
|
||||
)
|
||||
sql_trigger_instances_entry_update = (
|
||||
"""
|
||||
CREATE TRIGGER instances_entry_update
|
||||
AFTER UPDATE ON combination_entries_tags_jids
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
-- Decrease instances for the old tag_id
|
||||
UPDATE main_entries
|
||||
SET instances = (
|
||||
SELECT COUNT(DISTINCT jid_id)
|
||||
FROM combination_entries_tags_jids
|
||||
WHERE entry_id = OLD.entry_id
|
||||
)
|
||||
WHERE id = OLD.entry_id;
|
||||
|
||||
-- Increase instances for the new tag_id
|
||||
UPDATE main_entries
|
||||
SET instances = (
|
||||
SELECT COUNT(DISTINCT jid_id)
|
||||
FROM combination_entries_tags_jids
|
||||
WHERE entry_id = NEW.entry_id
|
||||
)
|
||||
WHERE id = NEW.entry_id;
|
||||
END;
|
||||
"""
|
||||
)
|
||||
sql_trigger_instances_tag_decrease = (
|
||||
"""
|
||||
CREATE TRIGGER instances_tag_decrease
|
||||
|
@ -2643,6 +2775,17 @@ class SQLite:
|
|||
END;
|
||||
"""
|
||||
)
|
||||
sql_trigger_entry_remove = (
|
||||
"""
|
||||
CREATE TRIGGER entry_remove
|
||||
AFTER UPDATE ON main_entries
|
||||
FOR EACH ROW
|
||||
WHEN NEW.instances < 1
|
||||
BEGIN
|
||||
DELETE FROM main_entries WHERE id = OLD.id;
|
||||
END;
|
||||
"""
|
||||
)
|
||||
sql_trigger_jid_count_increase = (
|
||||
"""
|
||||
CREATE TRIGGER jid_count_increase
|
||||
|
@ -2727,6 +2870,17 @@ class SQLite:
|
|||
END;
|
||||
"""
|
||||
)
|
||||
sql_trigger_tag_remove = (
|
||||
"""
|
||||
CREATE TRIGGER tag_remove
|
||||
AFTER UPDATE ON main_tags
|
||||
FOR EACH ROW
|
||||
WHEN NEW.instances < 1
|
||||
BEGIN
|
||||
DELETE FROM main_tags WHERE id = OLD.id;
|
||||
END;
|
||||
"""
|
||||
)
|
||||
cur = conn.cursor()
|
||||
cur.execute(sql_table_main_entries)
|
||||
cur.execute(sql_table_main_jids)
|
||||
|
@ -2736,18 +2890,23 @@ class SQLite:
|
|||
cur.execute(sql_table_authorization_entries_jids)
|
||||
cur.execute(sql_table_report_entries)
|
||||
cur.execute(sql_table_report_jids)
|
||||
cur.execute(sql_trigger_instances_entry_decrease)
|
||||
cur.execute(sql_trigger_instances_entry_increase)
|
||||
cur.execute(sql_trigger_instances_entry_update)
|
||||
cur.execute(sql_trigger_instances_tag_decrease)
|
||||
cur.execute(sql_trigger_instances_tag_increase)
|
||||
cur.execute(sql_trigger_instances_tag_update)
|
||||
cur.execute(sql_trigger_entry_count_increase)
|
||||
cur.execute(sql_trigger_entry_count_decrease)
|
||||
cur.execute(sql_trigger_entry_count_update)
|
||||
cur.execute(sql_trigger_entry_remove)
|
||||
cur.execute(sql_trigger_jid_count_increase)
|
||||
cur.execute(sql_trigger_jid_count_decrease)
|
||||
cur.execute(sql_trigger_jid_count_update)
|
||||
cur.execute(sql_trigger_tag_count_increase)
|
||||
cur.execute(sql_trigger_tag_count_decrease)
|
||||
cur.execute(sql_trigger_tag_count_update)
|
||||
cur.execute(sql_trigger_tag_remove)
|
||||
|
||||
def add_statistics(db_file):
|
||||
"""
|
||||
|
@ -3022,7 +3181,7 @@ class SQLite:
|
|||
result = cur.execute(sql, par).fetchone()
|
||||
return result[0] if result and len(result) == 1 else result
|
||||
|
||||
async def delete_combination_row_by_entry_id_and_tag_id_and_jid_id(db_file, url_hash, tags, jid):
|
||||
async def delete_combination_row_by_url_hash_and_tag_and_jid(db_file, url_hash, tags, jid):
|
||||
"""
|
||||
Delete a row by a given entry ID and a given Jabber ID and given tags.
|
||||
|
||||
|
@ -3042,8 +3201,8 @@ class SQLite:
|
|||
None.
|
||||
"""
|
||||
function_name = sys._getframe().f_code.co_name
|
||||
# logger.debug('{}: db_file: {} entry_id: {} tag_id: {} jid_id: {}'
|
||||
# .format(function_name, db_file, entry_id, tag_id, jid_id))
|
||||
# logger.debug('{}: db_file: {} url_hash: {} tag_id: {} jid_id: {}'
|
||||
# .format(function_name, db_file, url_hash, tag_id, jid_id))
|
||||
sql = (
|
||||
"""
|
||||
DELETE
|
||||
|
@ -3168,6 +3327,77 @@ class SQLite:
|
|||
result = cur.execute(sql, par).fetchall()
|
||||
return result
|
||||
|
||||
def get_jids_and_tags_by_entry_id(db_file, entry_id):
|
||||
"""
|
||||
Get JIDs and tags by a given ID entry.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
db_file : str
|
||||
Path to database file.
|
||||
entry_id : str
|
||||
An ID of an entry.
|
||||
|
||||
Returns
|
||||
-------
|
||||
result : tuple
|
||||
JIDs and tags.
|
||||
"""
|
||||
function_name = sys._getframe().f_code.co_name
|
||||
# logger.debug('{}: db_file: {} index_first: {}'
|
||||
# .format(function_name, db_file, index_first))
|
||||
sql = (
|
||||
"""
|
||||
SELECT main_jids.jid, main_tags.tag
|
||||
FROM main_tags
|
||||
INNER JOIN combination_entries_tags_jids ON main_tags.id = combination_entries_tags_jids.tag_id
|
||||
INNER JOIN main_jids ON main_jids.id = combination_entries_tags_jids.jid_id
|
||||
WHERE combination_entries_tags_jids.entry_id = ?
|
||||
ORDER BY main_tags.instances DESC;
|
||||
"""
|
||||
)
|
||||
par = (entry_id,)
|
||||
with SQLite.create_connection(db_file) as conn:
|
||||
cur = conn.cursor()
|
||||
result = cur.execute(sql, par).fetchall()
|
||||
return result
|
||||
|
||||
def get_jids_and_tags_by_url_hash(db_file, url_hash):
|
||||
"""
|
||||
Get JIDs and tags by a given URI hash.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
db_file : str
|
||||
Path to database file.
|
||||
url_hash : str
|
||||
A URL hash of an entry.
|
||||
|
||||
Returns
|
||||
-------
|
||||
result : tuple
|
||||
JIDs and tags.
|
||||
"""
|
||||
function_name = sys._getframe().f_code.co_name
|
||||
# logger.debug('{}: db_file: {} index_first: {}'
|
||||
# .format(function_name, db_file, index_first))
|
||||
sql = (
|
||||
"""
|
||||
SELECT main_jids.jid, main_tags.tag
|
||||
FROM main_tags
|
||||
INNER JOIN combination_entries_tags_jids ON main_tags.id = combination_entries_tags_jids.tag_id
|
||||
INNER JOIN main_jids ON main_jids.id = combination_entries_tags_jids.jid_id
|
||||
INNER JOIN main_entries ON main_entries.id = combination_entries_tags_jids.entry_id
|
||||
WHERE main_entries.url_hash = ?
|
||||
ORDER BY main_tags.instances DESC;
|
||||
"""
|
||||
)
|
||||
par = (url_hash,)
|
||||
with SQLite.create_connection(db_file) as conn:
|
||||
cur = conn.cursor()
|
||||
result = cur.execute(sql, par).fetchall()
|
||||
return result
|
||||
|
||||
def get_tag_id_by_tag(db_file, tag):
|
||||
"""
|
||||
Get a tag ID by a given tag.
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
# Contact
|
||||
[contacts]
|
||||
email = ""
|
||||
xmpp = ""
|
||||
xmpp = "sch@pimux.de"
|
||||
mix = ""
|
||||
muc = ""
|
||||
muc = "syndication@conference.movim.eu"
|
||||
irc_channel = "#blasta"
|
||||
irc_server = ""
|
||||
|
||||
|
|
|
@ -115,15 +115,15 @@ h3, h4, h5 {
|
|||
padding: 0 0.4em;
|
||||
}
|
||||
|
||||
.title:first-child {
|
||||
#posts > dd:first-child {
|
||||
margin-block-start: 2.22em;
|
||||
}
|
||||
|
||||
.title {
|
||||
#posts > dd {
|
||||
margin-block-start: 1.33em;
|
||||
}
|
||||
|
||||
.title > h4 {
|
||||
article > h4 {
|
||||
display: inline;
|
||||
}
|
||||
/*
|
||||
|
|
|
@ -11,8 +11,7 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
|||
|
||||
<xsl:output
|
||||
method = 'html'
|
||||
indent = 'yes'
|
||||
omit-xml-decleration='no' />
|
||||
indent = 'yes' />
|
||||
|
||||
<!-- set page metadata -->
|
||||
<xsl:template name='metadata'>
|
||||
|
@ -67,7 +66,7 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
|||
<!-- feed title -->
|
||||
<h1>
|
||||
<img src='/graphic/blasta_syndicate.svg'/>
|
||||
 
|
||||
 
|
||||
<xsl:value-of select='atom:title'/>
|
||||
</h1>
|
||||
<dl id='navigation'>
|
||||
|
@ -77,8 +76,18 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
|||
<dd>
|
||||
<xsl:element name='a'>
|
||||
<xsl:attribute name='href'>
|
||||
<xsl:value-of select='atom:link'/>
|
||||
<xsl:value-of select='atom:link[@rel="alternate" and @type="text/html"]/@href'/>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name='title'>Return to Blasta.</xsl:attribute>
|
||||
Return
|
||||
</xsl:element>
|
||||
</dd>
|
||||
<dd>
|
||||
<xsl:element name='a'>
|
||||
<xsl:attribute name='href'>
|
||||
<xsl:value-of select='atom:link[@rel="self"]/@href'/>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name='download'>blasta_atom_syndication_feed.atom</xsl:attribute>
|
||||
<xsl:attribute name='id'>follow</xsl:attribute>
|
||||
<xsl:attribute name='title'>Subscribe to updates with a news reader software.</xsl:attribute>
|
||||
Follow
|
||||
|
@ -102,6 +111,16 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
|||
SubToMe
|
||||
</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<xsl:element name='a'>
|
||||
<xsl:attribute name='href'>
|
||||
<xsl:value-of select='atom:link[@rel="alternate" and @type="x-scheme-handler/xmpp"]/@href'/>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name='id'>subscribe</xsl:attribute>
|
||||
<xsl:attribute name='title'>Subscribe to updates with an XMPP software.</xsl:attribute>
|
||||
Subscribe
|
||||
</xsl:element>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href='/help/about/xmpp'
|
||||
title='Of the benefits of XMPP.'>
|
||||
|
@ -127,7 +146,7 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
|||
<div>
|
||||
<h3>
|
||||
<img src='/graphic/syndicate.svg' height='22' width='22'/>
|
||||
 
|
||||
 
|
||||
<xsl:value-of select='atom:subtitle'/>
|
||||
</h3>
|
||||
<!-- xsl:for-each select='atom:entry[position() <21]' -->
|
||||
|
@ -164,21 +183,20 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
|||
</a>
|
||||
</h4>
|
||||
<h5 class='related'>
|
||||
 
|
||||
<img alt='💡'
|
||||
height='16'
|
||||
src='/graphic/xmpp.svg'
|
||||
width='16' />
|
||||
 
|
||||
<a href='/help/about/xmpp/pubsub'>XMPP</a>
|
||||
 
|
||||
 
|
||||
<a href='/help/about/xmpp/pubsub'>/help/about/xmpp/pubsub</a>
|
||||
 
|
||||
<img alt='⚛'
|
||||
class='enlarge'
|
||||
height='16'
|
||||
src='/graphic/syndicate.svg'
|
||||
width='16' />
|
||||
 
|
||||
<a href='/help/syndication'>Syndication</a>
|
||||
 
|
||||
<a href='/help/syndication'>/help/syndication</a>
|
||||
</h5>
|
||||
<p>
|
||||
<b>Congratulations!</b> You have reached to the final
|
||||
|
@ -196,15 +214,15 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
|||
the ones that would fit to you best!
|
||||
</p>
|
||||
<div class='details'>
|
||||
<a href='?tags=filetype:atom'>filetype:atom </a>
|
||||
<a href='?tags=filetype:rss'>filetype:rss </a>
|
||||
<a href='?tags=filetype:xml'>filetype:xml </a>
|
||||
<a href='?tags=software:akregator'>software:akregator </a>
|
||||
<a href='?tags=software:fraidycat'>software:fraidycat </a>
|
||||
<a href='?tags=software:liferea'>software:liferea </a>
|
||||
<a href='?tags=software:otter-browser'>software:otter-browser </a>
|
||||
<a href='?tags=software:raven-reader'>software:raven-reader </a>
|
||||
<a href='?tags=niche:syndication'>niche:syndication</a>
|
||||
<a href='?mode=feed&tags=filetype:atom'>filetype:atom </a>
|
||||
<a href='?mode=feed&tags=filetype:rss'>filetype:rss </a>
|
||||
<a href='?mode=feed&tags=filetype:xml'>filetype:xml </a>
|
||||
<a href='?mode=feed&tags=software:akregator'>software:akregator </a>
|
||||
<a href='?mode=feed&tags=software:fraidycat'>software:fraidycat </a>
|
||||
<a href='?mode=feed&tags=software:liferea'>software:liferea </a>
|
||||
<a href='?mode=feed&tags=software:otter-browser'>software:otter-browser </a>
|
||||
<a href='?mode=feed&tags=software:raven-reader'>software:raven-reader </a>
|
||||
<a href='?mode=feed&tags=niche:syndication'>niche:syndication</a>
|
||||
<h5 class='updated'>2024-08-22T17:09:04+03:00</h5>
|
||||
<h5 class='author'>
|
||||
<a href='/jid/sch@pimux.de'>sch@pimux.de</a>
|
||||
|
@ -252,13 +270,13 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
|||
</xsl:attribute>
|
||||
PubSub
|
||||
</xsl:element>
|
||||
​ 
|
||||
 
|
||||
💬
|
||||
<xsl:element name='a'>
|
||||
<xsl:attribute name='href'>
|
||||
<xsl:value-of select='atom:link[@rel="related" and @type="text/html"]/@href'/>
|
||||
</xsl:attribute>
|
||||
People
|
||||
Folksonomy
|
||||
</xsl:element>
|
||||
</h5>
|
||||
<!-- entry content -->
|
||||
|
@ -271,11 +289,11 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
|||
<xsl:for-each select='atom:category'>
|
||||
<xsl:element name='a'>
|
||||
<xsl:attribute name='href'>
|
||||
?tags=<xsl:value-of select='@term'/>
|
||||
?mode=feed&tags=<xsl:value-of select='@term'/>
|
||||
</xsl:attribute>
|
||||
<xsl:value-of select='@term'/>
|
||||
</xsl:element>
|
||||
 
|
||||
 
|
||||
</xsl:for-each>
|
||||
<h5 class='date'>
|
||||
<!-- entry date -->
|
||||
|
@ -362,21 +380,20 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
|||
</a>
|
||||
</h4>
|
||||
<h5 class='related'>
|
||||
 
|
||||
<img alt='💡'
|
||||
height='16'
|
||||
src='/graphic/xmpp.svg'
|
||||
width='16' />
|
||||
 
|
||||
<a href='/help/about/xmpp/pubsub'>XMPP</a>
|
||||
 
|
||||
 
|
||||
<a href='/help/about/xmpp/pubsub'>About XMPP</a>
|
||||
 
|
||||
<img alt='⚛'
|
||||
class='enlarge'
|
||||
height='16'
|
||||
src='/graphic/syndicate.svg'
|
||||
width='16' />
|
||||
 
|
||||
<a href='/help/syndication'>Syndication</a>
|
||||
 
|
||||
<a href='/help/syndication'>About Syndication</a>
|
||||
</h5>
|
||||
<p>
|
||||
This is a concise introduction to the syndication
|
||||
|
@ -407,17 +424,17 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
|
|||
Language Family (XSL).
|
||||
</p>
|
||||
<div class='details'>
|
||||
<a href='?tags=brand:atompub'>brand:atompub </a>
|
||||
<a href='?tags=brand:atomsub'>brand:atomsub </a>
|
||||
<a href='?tags=brand:pubsub'>brand:pubsub </a>
|
||||
<a href='?tags=code:xslt'>code:xslt </a>
|
||||
<a href='?tags=filetype:atom'>filetype:atom </a>
|
||||
<a href='?tags=filetype:rss'>filetype:rss </a>
|
||||
<a href='?tags=filetype:xml'>filetype:xml </a>
|
||||
<a href='?tags=software:libervia'>software:libervia </a>
|
||||
<a href='?tags=software:movim'>software:movim </a>
|
||||
<a href='?tags=software:reeder'>software:reeder </a>
|
||||
<a href='?tags=niche:syndication'>niche:syndication</a>
|
||||
<a href='?mode=feed&tags=brand:atompub'>brand:atompub </a>
|
||||
<a href='?mode=feed&tags=brand:atomsub'>brand:atomsub </a>
|
||||
<a href='?mode=feed&tags=brand:pubsub'>brand:pubsub </a>
|
||||
<a href='?mode=feed&tags=code:xslt'>code:xslt </a>
|
||||
<a href='?mode=feed&tags=filetype:atom'>filetype:atom </a>
|
||||
<a href='?mode=feed&tags=filetype:rss'>filetype:rss </a>
|
||||
<a href='?mode=feed&tags=filetype:xml'>filetype:xml </a>
|
||||
<a href='?mode=feed&tags=software:libervia'>software:libervia </a>
|
||||
<a href='?mode=feed&tags=software:movim'>software:movim </a>
|
||||
<a href='?mode=feed&tags=software:reeder'>software:reeder </a>
|
||||
<a href='?mode=feed&tags=niche:syndication'>niche:syndication</a>
|
||||
<h5 class='updated'>2024-08-22T17:09:04+03:00</h5>
|
||||
<h5 class='author'>
|
||||
<a href='/jid/sch@pimux.de'>sch@pimux.de</a>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
@ -104,9 +107,10 @@
|
|||
</p>
|
||||
<p>
|
||||
With the collaborative indexing system which Blasta offers,
|
||||
you can be rest assured that you will find the references
|
||||
and resources that you need in order to be productive and
|
||||
get that you need.
|
||||
and its <a href="/help/about/folksonomy">folksonomical</a>
|
||||
nature you can be rest assured that you will find the
|
||||
references and resources that you need in order to be
|
||||
productive and get that you need.
|
||||
</p>
|
||||
<h4>The things that you can do with Blasta are endless</h4>
|
||||
<p>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<link href="{{request.url}}"
|
||||
rel="self"
|
||||
type="text/html" />
|
||||
<link href="{{request.url.__str__().replace('?mode=feed', '')}}"
|
||||
<link href="{{request.url.__str__().replace('mode=feed&', '', 1)}}"
|
||||
rel="alternate"
|
||||
type="text/html" />
|
||||
<link href="xmpp:{{pubsub_jid}}?pubsub;action=subscribe;node={{node_id}}"
|
||||
|
|
|
@ -30,23 +30,46 @@
|
|||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
{% if node_type == 'public' %}
|
||||
<b>Public</b>
|
||||
{% else %}
|
||||
<a href="/jid">Public</a>
|
||||
{% endif %}
|
||||
</dd>
|
||||
<dd>
|
||||
{% if node_type == 'private' %}
|
||||
<b>Private</b>
|
||||
{% else %}
|
||||
<a href="/private">Private</a>
|
||||
{% endif %}
|
||||
</dd>
|
||||
<dd>
|
||||
{% if node_type == 'read' %}
|
||||
<b>Read</b>
|
||||
{% else %}
|
||||
<a href="/read">Read</a>
|
||||
{% endif %}
|
||||
</dd>
|
||||
{% endif %}
|
||||
<dd>
|
||||
<a href="/search{% if jid %}/jid/{{jid}}{% endif %}">Search</a>
|
||||
</dd>
|
||||
<dd>
|
||||
{% if page_type == 'popular' %}
|
||||
<b>Popular</b>
|
||||
{% else %}
|
||||
<a href="/popular">Popular</a>
|
||||
{% endif %}
|
||||
</dd>
|
||||
<dd>
|
||||
{% if page_type == 'recent' %}
|
||||
<b>Recent</b>
|
||||
{% else %}
|
||||
<a href="/recent">Recent</a>
|
||||
{% endif %}
|
||||
</dd>
|
||||
<dd>
|
||||
{% if jabber_id %}
|
||||
|
@ -97,13 +120,13 @@
|
|||
your PubSub bookmarks directory with Blasta!
|
||||
</p>
|
||||
{% endif %}
|
||||
<dl id="posts">
|
||||
{% if entries %}
|
||||
<dl id="posts">
|
||||
{% for entry in entries %}
|
||||
<dd>
|
||||
<article class="h-entry title">
|
||||
<article class="h-entry">
|
||||
<h4>
|
||||
<a class="p-name"
|
||||
<a class="p-name title"
|
||||
href="{{entry['link']}}">
|
||||
{{entry['title']}}</a>
|
||||
</h4>
|
||||
|
@ -123,7 +146,7 @@
|
|||
delete</a>
|
||||
{% else %}
|
||||
<a href="/url/{{entry['url_hash']}}/edit">
|
||||
add</a>
|
||||
add this</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<p class="p-summary summary">{{entry['summary']}}</p>
|
||||
|
@ -135,7 +158,6 @@
|
|||
href="{% if jid %}/jid/{{jid}}{% elif path in ('query', 'url') %}/{% endif %}?tags={{tag}}">
|
||||
{{tag}}
|
||||
</a>
|
||||
​ 
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
by
|
||||
|
@ -167,7 +189,6 @@
|
|||
<span>details</span>
|
||||
{% endif %}
|
||||
</a>
|
||||
​ 
|
||||
at
|
||||
<span class="dt-published date"
|
||||
datetime="{{entry['published']}}">
|
||||
|
@ -177,18 +198,23 @@
|
|||
</article>
|
||||
</dd>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</dl>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="related-tags">
|
||||
<h3>Related tags</h3>
|
||||
<h3>
|
||||
{% if path == 'url' %}
|
||||
Tags
|
||||
{% else %}
|
||||
Related tags
|
||||
{% endif %}
|
||||
</h3>
|
||||
<dl>
|
||||
{% for tag in tags %}
|
||||
<dd>
|
||||
<a href="{% if jid %}/jid/{{jid}}{% elif path in ('query', 'url') %}/{% endif %}?tags={{tag}}">
|
||||
{{tag}}
|
||||
</a>
|
||||
​ 
|
||||
{% if tags[tag] %}
|
||||
({{tags[tag]}})
|
||||
{% endif %}
|
||||
|
@ -224,14 +250,12 @@
|
|||
<a href="xmpp:{{pubsub_jid}}?pubsub;action=subscribe;node={{node_id}}">
|
||||
PubSub
|
||||
</a>
|
||||
​ 
|
||||
and
|
||||
<img alt="⚛" class="enlarge" src="/graphic/syndicate.svg" width="16" height="16"/>
|
||||
<a href="/{% if jid %}jid/{% endif %}{{syndicate}}?mode=feed{% if param_tags %}&tags={{param_tags}}{% endif %}{% if param_url %}&url={{param_url}}{% endif %}{% if param_hash %}&hash={{param_hash}}{% endif %}">
|
||||
RSS
|
||||
<!-- img src="/graphic/atom.svg" width="36" height="14" alt="Atom"/ -->
|
||||
</a>
|
||||
​ 
|
||||
syndication feeds for this page are available.
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<a href="/recent">Recent</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/connect">Connect</a>
|
||||
<b>Connect</b>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<b>Add</b>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
@ -201,6 +204,17 @@ to view details.">
|
|||
<tr>
|
||||
<td> </td>
|
||||
<td>
|
||||
{% if message %}
|
||||
<p>
|
||||
<i>
|
||||
{{message}}
|
||||
{% if message_link %}
|
||||
<a href="{{message_link['href']}}">
|
||||
{{message_link['text']}}</a>.
|
||||
{% endif %}
|
||||
</i>
|
||||
</p>
|
||||
{% endif %}
|
||||
<p>
|
||||
<i>
|
||||
Fields that are marked with an asterisk
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
209
template/folksonomy.xhtml
Normal file
209
template/folksonomy.xhtml
Normal file
|
@ -0,0 +1,209 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="color-scheme" content="dark light" />
|
||||
<title>Blasta / questions</title>
|
||||
<link rel="shortcut icon" href="/graphic/blasta.svg"/>
|
||||
<link rel='icon' type='image/svg+xml' href='/graphic/blasta.svg'/>
|
||||
<link rel='stylesheet' type='text/css' media='screen' href='/stylesheet/stylesheet.css'/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="header" class="row">
|
||||
<h1>
|
||||
<img src="/graphic/blasta.svg"/>
|
||||
<a href="/">Blasta</a> / <a href="/help">help</a> / <a href="/help/about">about</a> / folksonomy
|
||||
</h1>
|
||||
<dl id="navigation">
|
||||
<dd>
|
||||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/private">Private</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/read">Read</a>
|
||||
</dd>
|
||||
{% endif %}
|
||||
<dd>
|
||||
<a href="/search{% if jabber_id %}/jid/{{jabber_id}}{% endif %}">Search</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/popular">Popular</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/recent">Recent</a>
|
||||
</dd>
|
||||
<dd>
|
||||
{% if jabber_id %}
|
||||
<a href="/disconnect">Disconnect</a>
|
||||
{% else %}
|
||||
<a href="/connect">Connect</a>
|
||||
{% endif %}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div id="main" class="row">
|
||||
<div id="content">
|
||||
<h2> PubSub Bookmarks</h2>
|
||||
<p>
|
||||
» A practice for people to organize and share information in
|
||||
a collaborative and decentralized manner.
|
||||
</p>
|
||||
<h3>
|
||||
Folksonomy
|
||||
</h3>
|
||||
<p>
|
||||
Folksonomy is a system of classification that is created by
|
||||
individual people, rather than by professionals (who
|
||||
sometimes refer themselves as experts) such as archivers or
|
||||
librarians. It is a fashion for people to collaboratively
|
||||
tag and categorize information, often using keywords or
|
||||
labels.
|
||||
</p>
|
||||
<h4>
|
||||
Characteristics
|
||||
</h4>
|
||||
<p>
|
||||
Among the characteristics of folksonomy are: independency,
|
||||
collaborativeness, and being dynamic;
|
||||
</p>
|
||||
<p>
|
||||
Tags are self-generated by individual people, not by a
|
||||
centralized authority;
|
||||
</p>
|
||||
<p>
|
||||
Tags can be added by multiple people to the same item,
|
||||
and thereby they create a collective understanding;
|
||||
</p>
|
||||
<p>
|
||||
Tags can be added, removed, and updated over time,
|
||||
reflecting evolving usage, accuracy and interests;
|
||||
</p>
|
||||
<p>
|
||||
There is no single source of truth or control over the
|
||||
tagging process.
|
||||
</p>
|
||||
<h4>
|
||||
Benefits
|
||||
</h4>
|
||||
<p>
|
||||
Because people can easily find relevant content by searching
|
||||
for specific tags; and shared tagging promotes collective
|
||||
understanding and knowledge creation; and people feel more
|
||||
involved and empowered by contributing their own insights.
|
||||
</p>
|
||||
<p>
|
||||
The benefits of folksonomies spans from improved
|
||||
discoverability of contents to enhanced collaboration and
|
||||
increased engagement of people by contributing and
|
||||
benefiting to the overhaul system.
|
||||
</p>
|
||||
<p>
|
||||
It was written in Adam Mathes' recent paper on folksonomies that:
|
||||
</p>
|
||||
<p class="quote">
|
||||
“There is a fundamental difference in the activities of
|
||||
browsing to find interesting content, as opposed to direct
|
||||
searching to find relevant documents in a query. It is
|
||||
similar to the difference between exploring a problem space
|
||||
to formulate questions, as opposed to actually looking for
|
||||
answers to specifically formulated questions. Information
|
||||
seeking behavior varies based on context.”
|
||||
</p>
|
||||
<h4>
|
||||
Conclusion
|
||||
</h4>
|
||||
<p>
|
||||
By practicing and engaging in folksonomy systems, people
|
||||
find many interesting resources that are related to their
|
||||
special and specific needs, that they could not have found
|
||||
using search engines. Blasta has some interesting advantages
|
||||
over search engines, and one of them is being folksonomy
|
||||
driven.
|
||||
</p>
|
||||
<p>
|
||||
The power of the people cannot be more evident than the
|
||||
awesome resource that is Wikipedia, albeit is has been
|
||||
gradually controlled by
|
||||
<a href="https://www.fivefilters.org/2023/glenn-greenwald-on-wikipedia-bias/">
|
||||
special interests</a>. Imagine what might happen if a search
|
||||
engine (e.g. YaCy) can be engineered by people!
|
||||
</p>
|
||||
<h4>
|
||||
Resources
|
||||
</h4>
|
||||
<p>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://adammathes.com/academic/computer-mediated-communication/folksonomies.html">
|
||||
Folksonomies - Cooperative Classification and Communication Through Shared Metadata
|
||||
</a>
|
||||
​ 
|
||||
(adammathes.com)
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://www.sylloge.com/personal/2004/08/folksonomy-social-classification-great.html">
|
||||
Folksonomy : social classification
|
||||
</a>
|
||||
​ 
|
||||
(sylloge.com)
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
<br/>
|
||||
<p class="quote bottom">
|
||||
“I think the lack of hierarchy, synonym control and semantic
|
||||
precision are precisely why it works. Free typing loose
|
||||
associations is just a lot easier than making a decision
|
||||
about the degree of match to a pre-defined category
|
||||
(especially hierarchical ones).”
|
||||
― Stewart Butterfield
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer" class="row">
|
||||
<dl>
|
||||
<dd>
|
||||
<img src="/graphic/blasta.svg" alt="logo"/>
|
||||
<a href="/">blasta</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/help/about">about</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/help/about/xmpp">xmpp</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/help/about/xmpp/pubsub">pubsub</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="{{journal}}">journal</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/help">help</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/help/policy">policy</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/help/feeds">rss</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/contact">contact</a>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
@ -64,6 +67,7 @@
|
|||
<div>
|
||||
<h4>About</h4>
|
||||
<p><a href="/help/about">Blasta</a></p>
|
||||
<p><a href="/help/about/folksonomy">Folksonomy</a></p>
|
||||
<p><a href="/help/about/ideas">Ideas</a></p>
|
||||
<p><a href="/help/about/philosophy">Philosophy</a></p>
|
||||
<p><a href="/help/about/projects">Projects</a></p>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
256
template/people.xhtml
Normal file
256
template/people.xhtml
Normal file
|
@ -0,0 +1,256 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="color-scheme" content="dark light" />
|
||||
<title>Blasta / {{path}}</title>
|
||||
<link rel="shortcut icon" href="/graphic/blasta.svg" />
|
||||
<link rel="icon" type="image/svg+xml" href="/graphic/blasta.svg" />
|
||||
<link rel="stylesheet" type="text/css" media="screen"
|
||||
href="/stylesheet/stylesheet.css" />
|
||||
<link rel="alternate" type="application/atom+xml"
|
||||
title="Follow updates on /{% if jid %}jid/{% endif %}{{syndicate}}{% if param_tags %} for Tag: #{{param_tags}}{% endif %}{% if param_url %} for URL: {{param_url}}{% endif %}{% if param_hash %} for hash: {{param_hash}}{% endif %}"
|
||||
href="/{% if jid %}jid/{% endif %}{{syndicate}}?mode=feed{% if param_tags %}&tags={{param_tags}}{% endif %}{% if param_url %}&url={{param_url}}{% endif %}{% if param_hash %}&hash={{param_hash}}{% endif %}" />
|
||||
<link rel="alternate" type="application/atom+xml"
|
||||
title="Subscribe to PubSub /{{syndicate}}{% if param_tags %} for Tag: #{{param_tags}}{% endif %}{% if param_url %} for URL: {{param_url}}{% endif %}{% if param_hash %} for hash: {{param_hash}}{% endif %}"
|
||||
href="xmpp:{{pubsub_jid}}?pubsub;action=subscribe;node={{node_id}}" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="header" class="row">
|
||||
<h1>
|
||||
<img src="/graphic/blasta.svg"/>
|
||||
<a href="/">Blasta</a> / {{path}}
|
||||
</h1>
|
||||
<dl id="navigation">
|
||||
<dd>
|
||||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/private">Private</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/read">Read</a>
|
||||
</dd>
|
||||
{% endif %}
|
||||
<dd>
|
||||
<a href="/search{% if jid %}/jid/{{jid}}{% endif %}">Search</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/popular">Popular</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/recent">Recent</a>
|
||||
</dd>
|
||||
<dd>
|
||||
{% if jabber_id %}
|
||||
<a href="/disconnect">Disconnect</a>
|
||||
{% else %}
|
||||
<a href="/connect">Connect</a>
|
||||
{% endif %}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div id="main" class="row">
|
||||
<div id="content">
|
||||
<h2> PubSub Bookmarks</h2>
|
||||
{% if pager %}
|
||||
{% if page_next or page_prev %}
|
||||
<div id="navigate-top">
|
||||
{% if page_prev %}
|
||||
«
|
||||
<a href="?page={{page_prev}}{% if param_tags %}&tags={{param_tags}}{% endif %}{% if param_query %}&q={{param_query}}{% endif %}">
|
||||
<b>retract</b></a>
|
||||
{% else %}
|
||||
<span class="inactive">« retract</span>
|
||||
{% endif %}
|
||||
or
|
||||
{% if page_next %}
|
||||
<a href="?page={{page_next}}{% if param_tags %}&tags={{param_tags}}{% endif %}{% if param_query %}&q={{param_query}}{% endif %}">
|
||||
<b>proceed</b></a>
|
||||
»
|
||||
{% else %}
|
||||
<span class="inactive">proceed »</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<p>» {{message}}</p>
|
||||
<h3>{{description}}</h3>
|
||||
{% if entries %}
|
||||
<dl id="posts">
|
||||
{% for entry in entries %}
|
||||
<dd>
|
||||
<article>
|
||||
<h4>
|
||||
<a class="title"
|
||||
href="{{entry['link']}}">
|
||||
{{entry['title']}}</a>
|
||||
</h4>
|
||||
<!-- TODO Edit to be possible if entry is present -->
|
||||
<!-- {% if jabber_id and entry['present'] %}{% endif %} -->
|
||||
{% if jabber_id %}
|
||||
{% if restore %}
|
||||
<a href="{{link_save}}">restore</a>
|
||||
{% elif delete %}
|
||||
<a href="/url/{{entry['url_hash']}}/delete"
|
||||
id="confirm">confirm deletion</a>
|
||||
{% elif jabber_id == jid or exist or path in ('private', 'read') %}
|
||||
<a href="/url/{{entry['url_hash']}}/edit">
|
||||
edit</a>
|
||||
/
|
||||
<a href="/url/{{entry['url_hash']}}/confirm">
|
||||
delete</a>
|
||||
{% else %}
|
||||
<a href="/url/{{entry['url_hash']}}/edit">
|
||||
add</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<p class="summary">{{entry['summary']}}</p>
|
||||
<div class="details">
|
||||
{% if entry['tags'] | length > 0 %}
|
||||
to
|
||||
{% for tag in entry['tags'] %}
|
||||
<a href="{% if jid %}/jid/{{jid}}{% elif path in ('query', 'url') %}/{% endif %}?tags={{tag}}">
|
||||
{{tag}}
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
at
|
||||
<span>
|
||||
{{entry['published_mod']}}
|
||||
</span>
|
||||
</div>
|
||||
</article>
|
||||
</dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
{% endif %}
|
||||
<br/>
|
||||
<hr/>
|
||||
{% if people %}
|
||||
<h4>
|
||||
This resource is shared amongst {{entries[0]['instances']}} people
|
||||
</h4>
|
||||
<p>
|
||||
<dl id="people">
|
||||
{% for jid in people %}
|
||||
<dt class="h-entry">
|
||||
<dt>
|
||||
<h5>
|
||||
by <a class="p-author" href="/jid/{{jid}}">{{jid}}</a>
|
||||
</h5>
|
||||
</dt>
|
||||
<dd>
|
||||
to
|
||||
{% if people[jid] | length > 0 %}
|
||||
{% for tag in people[jid] %}
|
||||
<a class="p-category"
|
||||
href="{% if jid %}/jid/{{jid}}{% elif path in ('query', 'url') %}/{% endif %}?tags={{tag}}">
|
||||
{{tag}}
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</dd>
|
||||
</dt>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="related-tags">
|
||||
<h3>Your tags</h3>
|
||||
<dl>
|
||||
{% for tag in tags %}
|
||||
<dd>
|
||||
<a href="{% if jid %}/jid/{{jid}}{% elif path in ('query', 'url') %}/{% endif %}?tags={{tag}}">
|
||||
{{tag}}
|
||||
</a>
|
||||
{% if tags[tag] %}
|
||||
({{tags[tag]}})
|
||||
{% endif %}
|
||||
</dd>
|
||||
{% endfor %}
|
||||
<dd>
|
||||
»
|
||||
<a href="/tag/{% if jid %}{{jid}}{% endif %}">see more tags</a>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
{% if pager %}
|
||||
{% if page_next or page_prev %}
|
||||
<div id="navigate-bottom" class="row">
|
||||
{% if page_prev %}
|
||||
« <a href="?page={{page_prev}}{% if param_tags %}&tags={{param_tags}}{% endif %}{% if param_query %}&q={{param_query}}{% endif %}"><b>retract</b></a>
|
||||
{% else %}
|
||||
<span class="inactive">« retract</span>
|
||||
{% endif %}
|
||||
or
|
||||
{% if page_next %}
|
||||
<a href="?page={{page_next}}{% if param_tags %}&tags={{param_tags}}{% endif %}{% if param_query %}&q={{param_query}}{% endif %}"><b>proceed</b></a> »
|
||||
{% else %}
|
||||
<span class="inactive">proceed »</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<div id="subscribe" class="row">
|
||||
<p>
|
||||
<img alt="💡" src="/graphic/xmpp.svg" width="16" height="16"/>
|
||||
<a href="xmpp:{{pubsub_jid}}?pubsub;action=subscribe;node={{node_id}}">
|
||||
PubSub
|
||||
</a>
|
||||
and
|
||||
<img alt="⚛" class="enlarge" src="/graphic/syndicate.svg" width="16" height="16"/>
|
||||
<a href="/{% if jid %}jid/{% endif %}{{syndicate}}?mode=feed{% if param_tags %}&tags={{param_tags}}{% endif %}{% if param_url %}&url={{param_url}}{% endif %}{% if param_hash %}&hash={{param_hash}}{% endif %}">
|
||||
RSS
|
||||
<!-- img src="/graphic/atom.svg" width="36" height="14" alt="Atom"/ -->
|
||||
</a>
|
||||
syndication feeds for this page are available.
|
||||
</p>
|
||||
</div>
|
||||
<div id="footer" class="row">
|
||||
<dl>
|
||||
<dd>
|
||||
<img src="/graphic/blasta.svg" alt="logo"/>
|
||||
<a href="/">blasta</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/help/about">about</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/help/about/xmpp">xmpp</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/help/about/xmpp/pubsub">pubsub</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="{{journal}}">journal</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/help">help</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/help/policy">policy</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/help/feeds">rss</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/contact">contact</a>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
@ -79,7 +82,9 @@
|
|||
<p>
|
||||
The method instance:keyword is a practice which improves
|
||||
bookmarks organizing, archiving, filtering and searching, as
|
||||
it narrows the context of a given bookmark.
|
||||
it narrows the context of a given bookmark, and therefore
|
||||
improves <a href="/help/about/folksonomy">Folksonomy</a>
|
||||
practices.
|
||||
</p>
|
||||
<p>
|
||||
Suppose you have two bookmarks; one is related to
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
@ -33,7 +36,7 @@
|
|||
</dd>
|
||||
{% endif %}
|
||||
<dd>
|
||||
<a href="/search{% if jid %}/jid/{{jid}}{% endif %}">Search</a>
|
||||
<b>Search</b>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/popular">Popular</a>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
<img src="/graphic/blasta.svg"/>
|
||||
</dd>
|
||||
{% if jabber_id %}
|
||||
<dd>
|
||||
<a href="/save">Add</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<a href="/jid">Public</a>
|
||||
</dd>
|
||||
|
|
Loading…
Reference in a new issue