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:
Schimon Jehudah, Adv. 2024-08-28 15:03:19 +03:00
parent 164b4d67d4
commit a53c3a3436
34 changed files with 926 additions and 100 deletions

280
blasta.py
View file

@ -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.

View file

@ -1,9 +1,9 @@
# Contact
[contacts]
email = ""
xmpp = ""
xmpp = "sch@pimux.de"
mix = ""
muc = ""
muc = "syndication@conference.movim.eu"
irc_channel = "#blasta"
irc_server = ""

View file

@ -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;
}
/*

View file

@ -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'/>
&#8202;
&#160;
<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'/>
&#8202;
&#160;
<xsl:value-of select='atom:subtitle'/>
</h3>
<!-- xsl:for-each select='atom:entry[position() &lt;21]' -->
@ -164,21 +183,20 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
</a>
</h4>
<h5 class='related'>
&#8202;
<img alt='💡'
height='16'
src='/graphic/xmpp.svg'
width='16' />
&#8202;
<a href='/help/about/xmpp/pubsub'>XMPP</a>
&#8202;
&#160;
<a href='/help/about/xmpp/pubsub'>/help/about/xmpp/pubsub</a>
&#160;
<img alt='⚛'
class='enlarge'
height='16'
src='/graphic/syndicate.svg'
width='16' />
&#8202;
<a href='/help/syndication'>Syndication</a>
&#160;
<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&amp;tags=filetype:atom'>filetype:atom </a>
<a href='?mode=feed&amp;tags=filetype:rss'>filetype:rss </a>
<a href='?mode=feed&amp;tags=filetype:xml'>filetype:xml </a>
<a href='?mode=feed&amp;tags=software:akregator'>software:akregator </a>
<a href='?mode=feed&amp;tags=software:fraidycat'>software:fraidycat </a>
<a href='?mode=feed&amp;tags=software:liferea'>software:liferea </a>
<a href='?mode=feed&amp;tags=software:otter-browser'>software:otter-browser </a>
<a href='?mode=feed&amp;tags=software:raven-reader'>software:raven-reader </a>
<a href='?mode=feed&amp;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>
&#8203;&#8202;
&#160;
💬
<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&amp;tags=<xsl:value-of select='@term'/>
</xsl:attribute>
<xsl:value-of select='@term'/>
</xsl:element>
&#8202;
&#160;
</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'>
&#8202;
<img alt='💡'
height='16'
src='/graphic/xmpp.svg'
width='16' />
&#8202;
<a href='/help/about/xmpp/pubsub'>XMPP</a>
&#8202;
&#160;
<a href='/help/about/xmpp/pubsub'>About XMPP</a>
&#160;
<img alt='⚛'
class='enlarge'
height='16'
src='/graphic/syndicate.svg'
width='16' />
&#8202;
<a href='/help/syndication'>Syndication</a>
&#160;
<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&amp;tags=brand:atompub'>brand:atompub </a>
<a href='?mode=feed&amp;tags=brand:atomsub'>brand:atomsub </a>
<a href='?mode=feed&amp;tags=brand:pubsub'>brand:pubsub </a>
<a href='?mode=feed&amp;tags=code:xslt'>code:xslt </a>
<a href='?mode=feed&amp;tags=filetype:atom'>filetype:atom </a>
<a href='?mode=feed&amp;tags=filetype:rss'>filetype:rss </a>
<a href='?mode=feed&amp;tags=filetype:xml'>filetype:xml </a>
<a href='?mode=feed&amp;tags=software:libervia'>software:libervia </a>
<a href='?mode=feed&amp;tags=software:movim'>software:movim </a>
<a href='?mode=feed&amp;tags=software:reeder'>software:reeder </a>
<a href='?mode=feed&amp;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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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}}"

View file

@ -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>
&#8203;&#8202;
{% endfor %}
{% endif %}
by
@ -167,7 +189,6 @@
<span>details</span>
{% endif %}
</a>
&#8203;&#8202;
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>
&#8203;&#8202;
{% if tags[tag] %}
({{tags[tag]}})
{% endif %}
@ -224,14 +250,12 @@
<a href="xmpp:{{pubsub_jid}}?pubsub;action=subscribe;node={{node_id}}">
PubSub
</a>
&#8203;&#8202;
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 %}&amp;tags={{param_tags}}{% endif %}{% if param_url %}&amp;url={{param_url}}{% endif %}{% if param_hash %}&amp;hash={{param_hash}}{% endif %}">
RSS
<!-- img src="/graphic/atom.svg" width="36" height="14" alt="Atom"/ -->
</a>
&#8203;&#8202;
syndication feeds for this page are available.
</p>
</div>

View file

@ -31,7 +31,7 @@
<a href="/recent">Recent</a>
</dd>
<dd>
<a href="/connect">Connect</a>
<b>Connect</b>
</dd>
</dl>
</div>

View file

@ -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>

View file

@ -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>&nbsp;</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

View file

@ -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
View 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>&nbsp; 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>
&#8203;&#8202;
(adammathes.com)
</li>
<li>
<a href="http://www.sylloge.com/personal/2004/08/folksonomy-social-classification-great.html">
Folksonomy : social classification
</a>
&#8203;&#8202;
(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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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
View 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 %}&amp;tags={{param_tags}}{% endif %}{% if param_url %}&amp;url={{param_url}}{% endif %}{% if param_hash %}&amp;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>&nbsp; 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 %}&amp;tags={{param_tags}}{% endif %}{% if param_query %}&amp;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 %}&amp;tags={{param_tags}}{% endif %}{% if param_query %}&amp;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 %}&amp;tags={{param_tags}}{% endif %}{% if param_query %}&amp;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 %}&amp;tags={{param_tags}}{% endif %}{% if param_query %}&amp;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 %}&amp;tags={{param_tags}}{% endif %}{% if param_url %}&amp;url={{param_url}}{% endif %}{% if param_hash %}&amp;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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>