Merge branch 'main' of gitlab.com:bashrc2/epicyon
150
daemon.py
|
|
@ -154,6 +154,7 @@ from blog import htmlBlogPage
|
||||||
from blog import htmlBlogPost
|
from blog import htmlBlogPost
|
||||||
from blog import htmlEditBlog
|
from blog import htmlEditBlog
|
||||||
from blog import getBlogAddress
|
from blog import getBlogAddress
|
||||||
|
from webapp_themeDesigner import htmlThemeDesigner
|
||||||
from webapp_minimalbutton import setMinimal
|
from webapp_minimalbutton import setMinimal
|
||||||
from webapp_minimalbutton import isMinimal
|
from webapp_minimalbutton import isMinimal
|
||||||
from webapp_utils import getAvatarImageUrl
|
from webapp_utils import getAvatarImageUrl
|
||||||
|
|
@ -316,6 +317,8 @@ from cache import storePersonInCache
|
||||||
from cache import getPersonFromCache
|
from cache import getPersonFromCache
|
||||||
from cache import getPersonPubKey
|
from cache import getPersonPubKey
|
||||||
from httpsig import verifyPostHeaders
|
from httpsig import verifyPostHeaders
|
||||||
|
from theme import resetThemeDesignerSettings
|
||||||
|
from theme import setThemeFromDesigner
|
||||||
from theme import scanThemesForScripts
|
from theme import scanThemesForScripts
|
||||||
from theme import importTheme
|
from theme import importTheme
|
||||||
from theme import exportTheme
|
from theme import exportTheme
|
||||||
|
|
@ -2109,6 +2112,92 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.POSTbusy = False
|
self.server.POSTbusy = False
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def _themeDesigner(self, path: str,
|
||||||
|
callingDomain: str, cookie: str,
|
||||||
|
baseDir: str, httpPrefix: str, nickname: str,
|
||||||
|
domain: str, domainFull: str, port: int,
|
||||||
|
onionDomain: str, i2pDomain: str,
|
||||||
|
debug: bool, accessKeys: {},
|
||||||
|
defaultTimeline: str, themeName: str,
|
||||||
|
allowLocalNetworkAccess: bool,
|
||||||
|
systemLanguage: str) -> None:
|
||||||
|
"""Receive POST from webapp_themeDesigner
|
||||||
|
"""
|
||||||
|
usersPath = '/users/' + nickname
|
||||||
|
originPathStr = \
|
||||||
|
httpPrefix + '://' + domainFull + usersPath + '/' + defaultTimeline
|
||||||
|
length = int(self.headers['Content-length'])
|
||||||
|
|
||||||
|
try:
|
||||||
|
themeParams = self.rfile.read(length).decode('utf-8')
|
||||||
|
except SocketError as e:
|
||||||
|
if e.errno == errno.ECONNRESET:
|
||||||
|
print('WARN: POST themeParams ' +
|
||||||
|
'connection reset by peer')
|
||||||
|
else:
|
||||||
|
print('WARN: POST themeParams socket error')
|
||||||
|
self.send_response(400)
|
||||||
|
self.end_headers()
|
||||||
|
self.server.POSTbusy = False
|
||||||
|
return
|
||||||
|
except ValueError as e:
|
||||||
|
print('ERROR: POST themeParams rfile.read failed, ' + str(e))
|
||||||
|
self.send_response(400)
|
||||||
|
self.end_headers()
|
||||||
|
self.server.POSTbusy = False
|
||||||
|
return
|
||||||
|
themeParams = \
|
||||||
|
urllib.parse.unquote_plus(themeParams)
|
||||||
|
|
||||||
|
# theme designer screen, reset button
|
||||||
|
# See htmlThemeDesigner
|
||||||
|
if 'submitThemeDesignerReset=' in themeParams or \
|
||||||
|
'submitThemeDesigner=' not in themeParams:
|
||||||
|
if 'submitThemeDesignerReset=' in themeParams:
|
||||||
|
resetThemeDesignerSettings(baseDir, themeName, domain,
|
||||||
|
allowLocalNetworkAccess,
|
||||||
|
systemLanguage)
|
||||||
|
|
||||||
|
if callingDomain.endswith('.onion') and onionDomain:
|
||||||
|
originPathStr = \
|
||||||
|
'http://' + onionDomain + usersPath + '/' + defaultTimeline
|
||||||
|
elif callingDomain.endswith('.i2p') and i2pDomain:
|
||||||
|
originPathStr = \
|
||||||
|
'http://' + i2pDomain + usersPath + '/' + defaultTimeline
|
||||||
|
self._redirect_headers(originPathStr, cookie, callingDomain)
|
||||||
|
self.server.POSTbusy = False
|
||||||
|
return
|
||||||
|
|
||||||
|
fields = {}
|
||||||
|
fieldsList = themeParams.split('&')
|
||||||
|
for fieldStr in fieldsList:
|
||||||
|
if '=' not in fieldStr:
|
||||||
|
continue
|
||||||
|
fields[fieldStr.split('=')[0]] = fieldStr.split('=')[1].strip()
|
||||||
|
|
||||||
|
# get the parameters from the theme designer screen
|
||||||
|
themeDesignerParams = {}
|
||||||
|
for variableName, key in fields.items():
|
||||||
|
if variableName.startswith('themeSetting_'):
|
||||||
|
variableName = variableName.replace('themeSetting_', '')
|
||||||
|
themeDesignerParams[variableName] = key
|
||||||
|
|
||||||
|
setThemeFromDesigner(baseDir, themeName, domain,
|
||||||
|
themeDesignerParams,
|
||||||
|
allowLocalNetworkAccess,
|
||||||
|
systemLanguage)
|
||||||
|
|
||||||
|
# redirect back from theme designer screen
|
||||||
|
if callingDomain.endswith('.onion') and onionDomain:
|
||||||
|
originPathStr = \
|
||||||
|
'http://' + onionDomain + usersPath + '/' + defaultTimeline
|
||||||
|
elif callingDomain.endswith('.i2p') and i2pDomain:
|
||||||
|
originPathStr = \
|
||||||
|
'http://' + i2pDomain + usersPath + '/' + defaultTimeline
|
||||||
|
self._redirect_headers(originPathStr, cookie, callingDomain)
|
||||||
|
self.server.POSTbusy = False
|
||||||
|
return
|
||||||
|
|
||||||
def _personOptions(self, path: str,
|
def _personOptions(self, path: str,
|
||||||
callingDomain: str, cookie: str,
|
callingDomain: str, cookie: str,
|
||||||
baseDir: str, httpPrefix: str,
|
baseDir: str, httpPrefix: str,
|
||||||
|
|
@ -10849,6 +10938,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
currNickname = currNickname.split('/')[0]
|
currNickname = currNickname.split('/')[0]
|
||||||
moderator = isModerator(baseDir, currNickname)
|
moderator = isModerator(baseDir, currNickname)
|
||||||
editor = isEditor(baseDir, currNickname)
|
editor = isEditor(baseDir, currNickname)
|
||||||
|
artist = isArtist(baseDir, currNickname)
|
||||||
fullWidthTimelineButtonHeader = \
|
fullWidthTimelineButtonHeader = \
|
||||||
self.server.fullWidthTimelineButtonHeader
|
self.server.fullWidthTimelineButtonHeader
|
||||||
minimalNick = isMinimal(baseDir, domain, nickname)
|
minimalNick = isMinimal(baseDir, domain, nickname)
|
||||||
|
|
@ -10881,7 +10971,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.twitterReplacementDomain,
|
self.server.twitterReplacementDomain,
|
||||||
self.server.showPublishedDateOnly,
|
self.server.showPublishedDateOnly,
|
||||||
self.server.newswire,
|
self.server.newswire,
|
||||||
moderator, editor,
|
moderator, editor, artist,
|
||||||
self.server.positiveVoting,
|
self.server.positiveVoting,
|
||||||
self.server.showPublishAsIcon,
|
self.server.showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
|
|
@ -14363,6 +14453,33 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.debug)
|
self.server.debug)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if htmlGET and usersInPath and authorized and \
|
||||||
|
self.path.endswith('/themedesigner'):
|
||||||
|
nickname = self.path.split('/users/')[1]
|
||||||
|
if '/' in nickname:
|
||||||
|
nickname = nickname.split('/')[0]
|
||||||
|
|
||||||
|
if not isArtist(self.server.baseDir, nickname):
|
||||||
|
self._403()
|
||||||
|
return
|
||||||
|
|
||||||
|
msg = \
|
||||||
|
htmlThemeDesigner(self.server.cssCache,
|
||||||
|
self.server.baseDir,
|
||||||
|
nickname, self.server.domain,
|
||||||
|
self.server.translate,
|
||||||
|
self.server.defaultTimeline,
|
||||||
|
self.server.themeName,
|
||||||
|
self.server.accessKeys)
|
||||||
|
msg = msg.encode('utf-8')
|
||||||
|
msglen = len(msg)
|
||||||
|
self._login_headers('text/html', msglen, callingDomain)
|
||||||
|
self._write(msg)
|
||||||
|
fitnessPerformance(GETstartTime, self.server.fitness,
|
||||||
|
'_GET', 'show theme designer screen',
|
||||||
|
self.server.debug)
|
||||||
|
return
|
||||||
|
|
||||||
fitnessPerformance(GETstartTime, self.server.fitness,
|
fitnessPerformance(GETstartTime, self.server.fitness,
|
||||||
'_GET', 'show about screen done',
|
'_GET', 'show about screen done',
|
||||||
self.server.debug)
|
self.server.debug)
|
||||||
|
|
@ -17728,6 +17845,36 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.defaultTimeline)
|
self.server.defaultTimeline)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# theme designer submit/cancel button
|
||||||
|
if usersInPath and \
|
||||||
|
self.path.endswith('/changeThemeSettings'):
|
||||||
|
nickname = self.path.split('/users/')[1]
|
||||||
|
if '/' in nickname:
|
||||||
|
nickname = nickname.split('/')[0]
|
||||||
|
|
||||||
|
if not self.server.keyShortcuts.get(nickname):
|
||||||
|
accessKeys = self.server.accessKeys
|
||||||
|
self.server.keyShortcuts[nickname] = accessKeys.copy()
|
||||||
|
accessKeys = self.server.keyShortcuts[nickname]
|
||||||
|
|
||||||
|
self._themeDesigner(self.path,
|
||||||
|
callingDomain, cookie,
|
||||||
|
self.server.baseDir,
|
||||||
|
self.server.httpPrefix,
|
||||||
|
nickname,
|
||||||
|
self.server.domain,
|
||||||
|
self.server.domainFull,
|
||||||
|
self.server.port,
|
||||||
|
self.server.onionDomain,
|
||||||
|
self.server.i2pDomain,
|
||||||
|
self.server.debug,
|
||||||
|
accessKeys,
|
||||||
|
self.server.defaultTimeline,
|
||||||
|
self.server.themeName,
|
||||||
|
self.server.allowLocalNetworkAccess,
|
||||||
|
self.server.systemLanguage)
|
||||||
|
return
|
||||||
|
|
||||||
# update the shared item federation token for the calling domain
|
# update the shared item federation token for the calling domain
|
||||||
# if it is within the permitted federation
|
# if it is within the permitted federation
|
||||||
if self.headers.get('Origin') and \
|
if self.headers.get('Origin') and \
|
||||||
|
|
@ -18330,6 +18477,7 @@ def runDaemon(contentLicenseUrl: str,
|
||||||
'enterNotes': 'n',
|
'enterNotes': 'n',
|
||||||
'menuTimeline': 't',
|
'menuTimeline': 't',
|
||||||
'menuEdit': 'e',
|
'menuEdit': 'e',
|
||||||
|
'menuThemeDesigner': 'z',
|
||||||
'menuProfile': 'p',
|
'menuProfile': 'p',
|
||||||
'menuInbox': 'i',
|
'menuInbox': 'i',
|
||||||
'menuSearch': '/',
|
'menuSearch': '/',
|
||||||
|
|
|
||||||
4
posts.py
|
|
@ -2160,8 +2160,8 @@ def threadSendPost(session, postJsonStr: str, federationList: [],
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('ERROR: postJsonString failed ' + str(e))
|
print('ERROR: postJsonString failed ' + str(e))
|
||||||
if unauthorized:
|
if unauthorized:
|
||||||
print(postJsonStr)
|
print('WARN: threadSendPost: Post is unauthorized ' +
|
||||||
print('threadSendPost: Post is unauthorized')
|
inboxUrl + ' ' + postJsonStr)
|
||||||
break
|
break
|
||||||
if postResult:
|
if postResult:
|
||||||
logStr = 'Success on try ' + str(tries) + ': ' + postJsonStr
|
logStr = 'Success on try ' + str(tries) + ': ' + postJsonStr
|
||||||
|
|
|
||||||
45
theme.py
|
|
@ -492,6 +492,31 @@ def _setCustomFont(baseDir: str):
|
||||||
cssfile.write(css)
|
cssfile.write(css)
|
||||||
|
|
||||||
|
|
||||||
|
def setThemeFromDesigner(baseDir: str, themeName: str, domain: str,
|
||||||
|
themeParams: {},
|
||||||
|
allowLocalNetworkAccess: bool,
|
||||||
|
systemLanguage: str):
|
||||||
|
customThemeFilename = baseDir + '/accounts/theme.json'
|
||||||
|
saveJson(themeParams, customThemeFilename)
|
||||||
|
setTheme(baseDir, themeName, domain,
|
||||||
|
allowLocalNetworkAccess, systemLanguage)
|
||||||
|
|
||||||
|
|
||||||
|
def resetThemeDesignerSettings(baseDir: str, themeName: str, domain: str,
|
||||||
|
allowLocalNetworkAccess: bool,
|
||||||
|
systemLanguage: str) -> None:
|
||||||
|
"""Resets the theme designer settings
|
||||||
|
"""
|
||||||
|
customVariablesFile = baseDir + '/accounts/theme.json'
|
||||||
|
if os.path.isfile(customVariablesFile):
|
||||||
|
try:
|
||||||
|
os.remove(customVariablesFile)
|
||||||
|
except OSError:
|
||||||
|
print('EX: unable to remove theme designer settings on reset')
|
||||||
|
setTheme(baseDir, themeName, domain,
|
||||||
|
allowLocalNetworkAccess, systemLanguage)
|
||||||
|
|
||||||
|
|
||||||
def _readVariablesFile(baseDir: str, themeName: str,
|
def _readVariablesFile(baseDir: str, themeName: str,
|
||||||
variablesFile: str,
|
variablesFile: str,
|
||||||
allowLocalNetworkAccess: bool) -> None:
|
allowLocalNetworkAccess: bool) -> None:
|
||||||
|
|
@ -500,6 +525,15 @@ def _readVariablesFile(baseDir: str, themeName: str,
|
||||||
themeParams = loadJson(variablesFile, 0)
|
themeParams = loadJson(variablesFile, 0)
|
||||||
if not themeParams:
|
if not themeParams:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# set custom theme parameters
|
||||||
|
customVariablesFile = baseDir + '/accounts/theme.json'
|
||||||
|
if os.path.isfile(customVariablesFile):
|
||||||
|
customThemeParams = loadJson(customVariablesFile, 0)
|
||||||
|
if customThemeParams:
|
||||||
|
for variableName, value in customThemeParams.items():
|
||||||
|
themeParams[variableName] = value
|
||||||
|
|
||||||
bgParams = {
|
bgParams = {
|
||||||
"login": "jpg",
|
"login": "jpg",
|
||||||
"follow": "jpg",
|
"follow": "jpg",
|
||||||
|
|
@ -789,6 +823,17 @@ def setTheme(baseDir: str, name: str, domain: str,
|
||||||
result = False
|
result = False
|
||||||
|
|
||||||
prevThemeName = getTheme(baseDir)
|
prevThemeName = getTheme(baseDir)
|
||||||
|
|
||||||
|
# if the theme has changed then remove any custom settings
|
||||||
|
if prevThemeName != name:
|
||||||
|
customVariablesFile = baseDir + '/accounts/theme.json'
|
||||||
|
if os.path.isfile(customVariablesFile):
|
||||||
|
print('Removing theme designer settings')
|
||||||
|
try:
|
||||||
|
os.remove(customVariablesFile)
|
||||||
|
except OSError:
|
||||||
|
print('EX: removing theme designer settings')
|
||||||
|
|
||||||
_removeTheme(baseDir)
|
_removeTheme(baseDir)
|
||||||
|
|
||||||
themes = getThemesList(baseDir)
|
themes = getThemesList(baseDir)
|
||||||
|
|
|
||||||
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
|
@ -498,5 +498,7 @@
|
||||||
"Select reaction": "حدد رد الفعل",
|
"Select reaction": "حدد رد الفعل",
|
||||||
"Don't show the Reaction button": "لا تظهر زر رد الفعل",
|
"Don't show the Reaction button": "لا تظهر زر رد الفعل",
|
||||||
"New feed URL": "موجز جديد URL",
|
"New feed URL": "موجز جديد URL",
|
||||||
"New link title and URL": "عنوان الارتباط الجديد وعنوان URL"
|
"New link title and URL": "عنوان الارتباط الجديد وعنوان URL",
|
||||||
|
"Theme Designer": "مصمم المظهر",
|
||||||
|
"Reset": "إعادة ضبط"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -498,5 +498,7 @@
|
||||||
"Select reaction": "Seleccioneu la reacció",
|
"Select reaction": "Seleccioneu la reacció",
|
||||||
"Don't show the Reaction button": "No mostris el botó de reacció",
|
"Don't show the Reaction button": "No mostris el botó de reacció",
|
||||||
"New feed URL": "URL de feed nou",
|
"New feed URL": "URL de feed nou",
|
||||||
"New link title and URL": "Títol i URL de l'enllaç nous"
|
"New link title and URL": "Títol i URL de l'enllaç nous",
|
||||||
|
"Theme Designer": "Dissenyador temàtic",
|
||||||
|
"Reset": "Restableix"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -498,5 +498,7 @@
|
||||||
"Select reaction": "Dewiswch adwaith",
|
"Select reaction": "Dewiswch adwaith",
|
||||||
"Don't show the Reaction button": "Peidiwch â dangos y botwm Adwaith",
|
"Don't show the Reaction button": "Peidiwch â dangos y botwm Adwaith",
|
||||||
"New feed URL": "URL porthiant newydd",
|
"New feed URL": "URL porthiant newydd",
|
||||||
"New link title and URL": "Teitl dolen ac URL newydd"
|
"New link title and URL": "Teitl dolen ac URL newydd",
|
||||||
|
"Theme Designer": "Dylunydd Thema",
|
||||||
|
"Reset": "Ail gychwyn"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -498,5 +498,7 @@
|
||||||
"Select reaction": "Reaktion auswählen",
|
"Select reaction": "Reaktion auswählen",
|
||||||
"Don't show the Reaction button": "Reaktionstaste nicht anzeigen",
|
"Don't show the Reaction button": "Reaktionstaste nicht anzeigen",
|
||||||
"New feed URL": "Neue Feed-URL",
|
"New feed URL": "Neue Feed-URL",
|
||||||
"New link title and URL": "Neuer Linktitel und URL"
|
"New link title and URL": "Neuer Linktitel und URL",
|
||||||
|
"Theme Designer": "Themendesigner",
|
||||||
|
"Reset": "Zurücksetzen"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -498,5 +498,7 @@
|
||||||
"Select reaction": "Select reaction",
|
"Select reaction": "Select reaction",
|
||||||
"Don't show the Reaction button": "Don't show the Reaction button",
|
"Don't show the Reaction button": "Don't show the Reaction button",
|
||||||
"New feed URL": "New feed URL",
|
"New feed URL": "New feed URL",
|
||||||
"New link title and URL": "New link title and URL"
|
"New link title and URL": "New link title and URL",
|
||||||
|
"Theme Designer": "Theme Designer",
|
||||||
|
"Reset": "Reset"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -498,5 +498,7 @@
|
||||||
"Select reaction": "Seleccionar reacción",
|
"Select reaction": "Seleccionar reacción",
|
||||||
"Don't show the Reaction button": "No mostrar el botón de reacción",
|
"Don't show the Reaction button": "No mostrar el botón de reacción",
|
||||||
"New feed URL": "URL de nuevo feed",
|
"New feed URL": "URL de nuevo feed",
|
||||||
"New link title and URL": "Nuevo título de enlace y URL"
|
"New link title and URL": "Nuevo título de enlace y URL",
|
||||||
|
"Theme Designer": "Diseñadora de temas",
|
||||||
|
"Reset": "Reiniciar"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -498,5 +498,7 @@
|
||||||
"Select reaction": "Sélectionnez la réaction",
|
"Select reaction": "Sélectionnez la réaction",
|
||||||
"Don't show the Reaction button": "Ne pas afficher le bouton Réaction",
|
"Don't show the Reaction button": "Ne pas afficher le bouton Réaction",
|
||||||
"New feed URL": "Nouvelle URL de flux",
|
"New feed URL": "Nouvelle URL de flux",
|
||||||
"New link title and URL": "Nouveau titre et URL du lien"
|
"New link title and URL": "Nouveau titre et URL du lien",
|
||||||
|
"Theme Designer": "Concepteur de thème",
|
||||||
|
"Reset": "Réinitialiser"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -498,5 +498,7 @@
|
||||||
"Select reaction": "Roghnaigh imoibriú",
|
"Select reaction": "Roghnaigh imoibriú",
|
||||||
"Don't show the Reaction button": "Ná taispeáin an cnaipe Imoibriú",
|
"Don't show the Reaction button": "Ná taispeáin an cnaipe Imoibriú",
|
||||||
"New feed URL": "URL beathaithe nua",
|
"New feed URL": "URL beathaithe nua",
|
||||||
"New link title and URL": "Teideal nasc nua agus URL"
|
"New link title and URL": "Teideal nasc nua agus URL",
|
||||||
|
"Theme Designer": "Dearthóir Téama",
|
||||||
|
"Reset": "Athshocraigh"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -498,5 +498,7 @@
|
||||||
"Select reaction": "प्रतिक्रिया का चयन करें",
|
"Select reaction": "प्रतिक्रिया का चयन करें",
|
||||||
"Don't show the Reaction button": "प्रतिक्रिया बटन न दिखाएं",
|
"Don't show the Reaction button": "प्रतिक्रिया बटन न दिखाएं",
|
||||||
"New feed URL": "नया फ़ीड URL",
|
"New feed URL": "नया फ़ीड URL",
|
||||||
"New link title and URL": "नया लिंक शीर्षक और URL"
|
"New link title and URL": "नया लिंक शीर्षक और URL",
|
||||||
|
"Theme Designer": "थीम डिजाइनर",
|
||||||
|
"Reset": "रीसेट"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -498,5 +498,7 @@
|
||||||
"Select reaction": "Seleziona reazione",
|
"Select reaction": "Seleziona reazione",
|
||||||
"Don't show the Reaction button": "Non mostrare il pulsante Reazione",
|
"Don't show the Reaction button": "Non mostrare il pulsante Reazione",
|
||||||
"New feed URL": "Nuovo URL del feed",
|
"New feed URL": "Nuovo URL del feed",
|
||||||
"New link title and URL": "Nuovo titolo e URL del collegamento"
|
"New link title and URL": "Nuovo titolo e URL del collegamento",
|
||||||
|
"Theme Designer": "Progettista di temi",
|
||||||
|
"Reset": "Ripristina"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -498,5 +498,7 @@
|
||||||
"Select reaction": "反応を選択",
|
"Select reaction": "反応を選択",
|
||||||
"Don't show the Reaction button": "反応ボタンを表示しない",
|
"Don't show the Reaction button": "反応ボタンを表示しない",
|
||||||
"New feed URL": "新しいフィードURL",
|
"New feed URL": "新しいフィードURL",
|
||||||
"New link title and URL": "新しいリンクのタイトルとURL"
|
"New link title and URL": "新しいリンクのタイトルとURL",
|
||||||
|
"Theme Designer": "テーマデザイナー",
|
||||||
|
"Reset": "リセット"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -498,5 +498,7 @@
|
||||||
"Select reaction": "Reaksiyonê hilbijêrin",
|
"Select reaction": "Reaksiyonê hilbijêrin",
|
||||||
"Don't show the Reaction button": "Bişkoka Reaksiyonê nîşan nede",
|
"Don't show the Reaction button": "Bişkoka Reaksiyonê nîşan nede",
|
||||||
"New feed URL": "URL-ya feed nû",
|
"New feed URL": "URL-ya feed nû",
|
||||||
"New link title and URL": "Sernav û URL-ya girêdana nû"
|
"New link title and URL": "Sernav û URL-ya girêdana nû",
|
||||||
|
"Theme Designer": "Theme Designer",
|
||||||
|
"Reset": "Reset"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -494,5 +494,7 @@
|
||||||
"Select reaction": "Select reaction",
|
"Select reaction": "Select reaction",
|
||||||
"Don't show the Reaction button": "Don't show the Reaction button",
|
"Don't show the Reaction button": "Don't show the Reaction button",
|
||||||
"New feed URL": "New feed URL",
|
"New feed URL": "New feed URL",
|
||||||
"New link title and URL": "New link title and URL"
|
"New link title and URL": "New link title and URL",
|
||||||
|
"Theme Designer": "Theme Designer",
|
||||||
|
"Reset": "Reset"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -498,5 +498,7 @@
|
||||||
"Select reaction": "Selecione a reação",
|
"Select reaction": "Selecione a reação",
|
||||||
"Don't show the Reaction button": "Não mostrar o botão de reação",
|
"Don't show the Reaction button": "Não mostrar o botão de reação",
|
||||||
"New feed URL": "Novo URL de feed",
|
"New feed URL": "Novo URL de feed",
|
||||||
"New link title and URL": "Novo título e URL do link"
|
"New link title and URL": "Novo título e URL do link",
|
||||||
|
"Theme Designer": "Designer de Tema",
|
||||||
|
"Reset": "Redefinir"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -498,5 +498,7 @@
|
||||||
"Select reaction": "Выберите реакцию",
|
"Select reaction": "Выберите реакцию",
|
||||||
"Don't show the Reaction button": "Не показывать кнопку реакции",
|
"Don't show the Reaction button": "Не показывать кнопку реакции",
|
||||||
"New feed URL": "URL нового канала",
|
"New feed URL": "URL нового канала",
|
||||||
"New link title and URL": "Новое название ссылки и URL"
|
"New link title and URL": "Новое название ссылки и URL",
|
||||||
|
"Theme Designer": "Дизайнер тем",
|
||||||
|
"Reset": "Сброс настроек"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -498,5 +498,7 @@
|
||||||
"Select reaction": "Chagua majibu",
|
"Select reaction": "Chagua majibu",
|
||||||
"Don't show the Reaction button": "Usionyeshe kitufe cha Majibu",
|
"Don't show the Reaction button": "Usionyeshe kitufe cha Majibu",
|
||||||
"New feed URL": "URL mpya ya mipasho",
|
"New feed URL": "URL mpya ya mipasho",
|
||||||
"New link title and URL": "Kichwa kipya cha kiungo na URL"
|
"New link title and URL": "Kichwa kipya cha kiungo na URL",
|
||||||
|
"Theme Designer": "Mbuni wa Mandhari",
|
||||||
|
"Reset": "Weka upya"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -498,5 +498,7 @@
|
||||||
"Select reaction": "选择反应",
|
"Select reaction": "选择反应",
|
||||||
"Don't show the Reaction button": "不显示“反应”按钮",
|
"Don't show the Reaction button": "不显示“反应”按钮",
|
||||||
"New feed URL": "新供稿网址",
|
"New feed URL": "新供稿网址",
|
||||||
"New link title and URL": "新链接标题和 URL"
|
"New link title and URL": "新链接标题和 URL",
|
||||||
|
"Theme Designer": "主题设计师",
|
||||||
|
"Reset": "重启"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import os
|
||||||
from utils import getConfigParam
|
from utils import getConfigParam
|
||||||
from utils import getNicknameFromActor
|
from utils import getNicknameFromActor
|
||||||
from utils import isEditor
|
from utils import isEditor
|
||||||
|
from utils import isArtist
|
||||||
from utils import removeDomainPort
|
from utils import removeDomainPort
|
||||||
from utils import localActorUrl
|
from utils import localActorUrl
|
||||||
from webapp_utils import sharesTimelineJson
|
from webapp_utils import sharesTimelineJson
|
||||||
|
|
@ -113,7 +114,7 @@ def _getLeftColumnWanted(baseDir: str,
|
||||||
|
|
||||||
def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
|
def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
|
||||||
httpPrefix: str, translate: {},
|
httpPrefix: str, translate: {},
|
||||||
editor: bool,
|
editor: bool, artist: bool,
|
||||||
showBackButton: bool, timelinePath: str,
|
showBackButton: bool, timelinePath: str,
|
||||||
rssIconAtTop: bool, showHeaderImage: bool,
|
rssIconAtTop: bool, showHeaderImage: bool,
|
||||||
frontPage: bool, theme: str,
|
frontPage: bool, theme: str,
|
||||||
|
|
@ -154,6 +155,7 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
|
||||||
htmlStr += '\n <center>\n'
|
htmlStr += '\n <center>\n'
|
||||||
|
|
||||||
htmlStr += ' <div class="leftColIcons">\n'
|
htmlStr += ' <div class="leftColIcons">\n'
|
||||||
|
|
||||||
if editor:
|
if editor:
|
||||||
# show the edit icon
|
# show the edit icon
|
||||||
htmlStr += \
|
htmlStr += \
|
||||||
|
|
@ -163,6 +165,15 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
|
||||||
translate['Edit Links'] + ' | " title="' + \
|
translate['Edit Links'] + ' | " title="' + \
|
||||||
translate['Edit Links'] + '" src="/icons/edit.png" /></a>\n'
|
translate['Edit Links'] + '" src="/icons/edit.png" /></a>\n'
|
||||||
|
|
||||||
|
if artist:
|
||||||
|
# show the theme designer icon
|
||||||
|
htmlStr += \
|
||||||
|
' <a href="/users/' + nickname + '/themedesigner" ' + \
|
||||||
|
'accesskey="' + accessKeys['menuThemeDesigner'] + '">' + \
|
||||||
|
'<img class="' + editImageClass + '" loading="lazy" alt="' + \
|
||||||
|
translate['Theme Designer'] + ' | " title="' + \
|
||||||
|
translate['Theme Designer'] + '" src="/icons/theme.png" /></a>\n'
|
||||||
|
|
||||||
# RSS icon
|
# RSS icon
|
||||||
if nickname != 'news':
|
if nickname != 'news':
|
||||||
# rss feed for this account
|
# rss feed for this account
|
||||||
|
|
@ -358,8 +369,10 @@ def htmlLinksMobile(cssCache: {}, baseDir: str,
|
||||||
# is the user a site editor?
|
# is the user a site editor?
|
||||||
if nickname == 'news':
|
if nickname == 'news':
|
||||||
editor = False
|
editor = False
|
||||||
|
artist = False
|
||||||
else:
|
else:
|
||||||
editor = isEditor(baseDir, nickname)
|
editor = isEditor(baseDir, nickname)
|
||||||
|
artist = isArtist(baseDir, nickname)
|
||||||
|
|
||||||
domain = removeDomainPort(domainFull)
|
domain = removeDomainPort(domainFull)
|
||||||
|
|
||||||
|
|
@ -383,7 +396,7 @@ def htmlLinksMobile(cssCache: {}, baseDir: str,
|
||||||
htmlStr += \
|
htmlStr += \
|
||||||
getLeftColumnContent(baseDir, nickname, domainFull,
|
getLeftColumnContent(baseDir, nickname, domainFull,
|
||||||
httpPrefix, translate,
|
httpPrefix, translate,
|
||||||
editor,
|
editor, artist,
|
||||||
False, timelinePath,
|
False, timelinePath,
|
||||||
rssIconAtTop, False, False,
|
rssIconAtTop, False, False,
|
||||||
theme, accessKeys,
|
theme, accessKeys,
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,8 @@ def htmlFrontScreen(signingPrivateKeyPem: str,
|
||||||
profileHeaderStr += \
|
profileHeaderStr += \
|
||||||
getLeftColumnContent(baseDir, 'news', domainFull,
|
getLeftColumnContent(baseDir, 'news', domainFull,
|
||||||
httpPrefix, translate,
|
httpPrefix, translate,
|
||||||
False, False, None, rssIconAtTop, True,
|
False, False,
|
||||||
|
False, None, rssIconAtTop, True,
|
||||||
True, theme, accessKeys,
|
True, theme, accessKeys,
|
||||||
sharedItemsFederatedDomains)
|
sharedItemsFederatedDomains)
|
||||||
profileHeaderStr += \
|
profileHeaderStr += \
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ __status__ = "Production"
|
||||||
__module_group__ = "Moderation"
|
__module_group__ = "Moderation"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from utils import isArtist
|
||||||
from utils import isAccountDir
|
from utils import isAccountDir
|
||||||
from utils import getFullDomain
|
from utils import getFullDomain
|
||||||
from utils import isEditor
|
from utils import isEditor
|
||||||
|
|
@ -57,6 +58,7 @@ def htmlModeration(cssCache: {}, defaultTimeline: str,
|
||||||
"""Show the moderation feed as html
|
"""Show the moderation feed as html
|
||||||
This is what you see when selecting the "mod" timeline
|
This is what you see when selecting the "mod" timeline
|
||||||
"""
|
"""
|
||||||
|
artist = isArtist(baseDir, nickname)
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
recentPostsCache, maxRecentPosts,
|
recentPostsCache, maxRecentPosts,
|
||||||
translate, pageNumber,
|
translate, pageNumber,
|
||||||
|
|
@ -66,7 +68,7 @@ def htmlModeration(cssCache: {}, defaultTimeline: str,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
twitterReplacementDomain,
|
twitterReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
newswire, False, False, positiveVoting,
|
newswire, False, False, artist, positiveVoting,
|
||||||
showPublishAsIcon, fullWidthTimelineButtonHeader,
|
showPublishAsIcon, fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, moderationActionStr, theme,
|
authorized, moderationActionStr, theme,
|
||||||
|
|
|
||||||
|
|
@ -878,6 +878,10 @@ def htmlProfile(signingPrivateKeyPem: str,
|
||||||
menuSkills: userPathStr + '/skills#timeline',
|
menuSkills: userPathStr + '/skills#timeline',
|
||||||
menuLogout: '/logout'
|
menuLogout: '/logout'
|
||||||
}
|
}
|
||||||
|
if isArtist(baseDir, nickname):
|
||||||
|
menuThemeDesigner = \
|
||||||
|
htmlHideFromScreenReader('🎨') + ' ' + translate['Theme Designer']
|
||||||
|
navLinks[menuThemeDesigner] = userPathStr + '/themedesigner'
|
||||||
navAccessKeys = {}
|
navAccessKeys = {}
|
||||||
for variableName, key in accessKeys.items():
|
for variableName, key in accessKeys.items():
|
||||||
if not locals().get(variableName):
|
if not locals().get(variableName):
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,262 @@
|
||||||
|
__filename__ = "webapp_themeDesigner.py"
|
||||||
|
__author__ = "Bob Mottram"
|
||||||
|
__license__ = "AGPL3+"
|
||||||
|
__version__ = "1.2.0"
|
||||||
|
__maintainer__ = "Bob Mottram"
|
||||||
|
__email__ = "bob@libreserver.org"
|
||||||
|
__status__ = "Production"
|
||||||
|
__module_group__ = "Web Interface"
|
||||||
|
|
||||||
|
import os
|
||||||
|
from utils import loadJson
|
||||||
|
from utils import getConfigParam
|
||||||
|
from webapp_utils import htmlHeaderWithExternalStyle
|
||||||
|
from webapp_utils import htmlFooter
|
||||||
|
from webapp_utils import getBannerFile
|
||||||
|
|
||||||
|
|
||||||
|
color_to_hex = {
|
||||||
|
"aliceblue": "#f0f8ff",
|
||||||
|
"antiquewhite": "#faebd7",
|
||||||
|
"aqua": "#00ffff",
|
||||||
|
"aquamarine": "#7fffd4",
|
||||||
|
"azure": "#f0ffff",
|
||||||
|
"beige": "#f5f5dc",
|
||||||
|
"bisque": "#ffe4c4",
|
||||||
|
"black": "#000000",
|
||||||
|
"blanchedalmond": "#ffebcd",
|
||||||
|
"blue": "#0000ff",
|
||||||
|
"blueviolet": "#8a2be2",
|
||||||
|
"brown": "#a52a2a",
|
||||||
|
"burlywood": "#deb887",
|
||||||
|
"cadetblue": "#5f9ea0",
|
||||||
|
"chartreuse": "#7fff00",
|
||||||
|
"chocolate": "#d2691e",
|
||||||
|
"coral": "#ff7f50",
|
||||||
|
"cornflowerblue": "#6495ed",
|
||||||
|
"cornsilk": "#fff8dc",
|
||||||
|
"crimson": "#dc143c",
|
||||||
|
"cyan": "#00ffff",
|
||||||
|
"darkblue": "#00008b",
|
||||||
|
"darkcyan": "#008b8b",
|
||||||
|
"darkgoldenrod": "#b8860b",
|
||||||
|
"darkgray": "#a9a9a9",
|
||||||
|
"darkgrey": "#a9a9a9",
|
||||||
|
"darkgreen": "#006400",
|
||||||
|
"darkkhaki": "#bdb76b",
|
||||||
|
"darkmagenta": "#8b008b",
|
||||||
|
"darkolivegreen": "#556b2f",
|
||||||
|
"darkorange": "#ff8c00",
|
||||||
|
"darkorchid": "#9932cc",
|
||||||
|
"darkred": "#8b0000",
|
||||||
|
"darksalmon": "#e9967a",
|
||||||
|
"darkseagreen": "#8fbc8f",
|
||||||
|
"darkslateblue": "#483d8b",
|
||||||
|
"darkslategray": "#2f4f4f",
|
||||||
|
"darkslategrey": "#2f4f4f",
|
||||||
|
"darkturquoise": "#00ced1",
|
||||||
|
"darkviolet": "#9400d3",
|
||||||
|
"deeppink": "#ff1493",
|
||||||
|
"deepskyblue": "#00bfff",
|
||||||
|
"dimgray": "#696969",
|
||||||
|
"dimgrey": "#696969",
|
||||||
|
"dodgerblue": "#1e90ff",
|
||||||
|
"firebrick": "#b22222",
|
||||||
|
"floralwhite": "#fffaf0",
|
||||||
|
"forestgreen": "#228b22",
|
||||||
|
"fuchsia": "#ff00ff",
|
||||||
|
"gainsboro": "#dcdcdc",
|
||||||
|
"ghostwhite": "#f8f8ff",
|
||||||
|
"gold": "#ffd700",
|
||||||
|
"goldenrod": "#daa520",
|
||||||
|
"gray": "#808080",
|
||||||
|
"grey": "#808080",
|
||||||
|
"green": "#008000",
|
||||||
|
"greenyellow": "#adff2f",
|
||||||
|
"honeydew": "#f0fff0",
|
||||||
|
"hotpink": "#ff69b4",
|
||||||
|
"indianred": "#cd5c5c",
|
||||||
|
"indigo": "#4b0082",
|
||||||
|
"ivory": "#fffff0",
|
||||||
|
"khaki": "#f0e68c",
|
||||||
|
"lavender": "#e6e6fa",
|
||||||
|
"lavenderblush": "#fff0f5",
|
||||||
|
"lawngreen": "#7cfc00",
|
||||||
|
"lemonchiffon": "#fffacd",
|
||||||
|
"lightblue": "#add8e6",
|
||||||
|
"lightcoral": "#f08080",
|
||||||
|
"lightcyan": "#e0ffff",
|
||||||
|
"lightgoldenrodyellow": "#fafad2",
|
||||||
|
"lightgray": "#d3d3d3",
|
||||||
|
"lightgrey": "#d3d3d3",
|
||||||
|
"lightgreen": "#90ee90",
|
||||||
|
"lightpink": "#ffb6c1",
|
||||||
|
"lightsalmon": "#ffa07a",
|
||||||
|
"lightseagreen": "#20b2aa",
|
||||||
|
"lightskyblue": "#87cefa",
|
||||||
|
"lightslategray": "#778899",
|
||||||
|
"lightslategrey": "#778899",
|
||||||
|
"lightsteelblue": "#b0c4de",
|
||||||
|
"lightyellow": "#ffffe0",
|
||||||
|
"lime": "#00ff00",
|
||||||
|
"limegreen": "#32cd32",
|
||||||
|
"linen": "#faf0e6",
|
||||||
|
"magenta": "#ff00ff",
|
||||||
|
"maroon": "#800000",
|
||||||
|
"mediumaquamarine": "#66cdaa",
|
||||||
|
"mediumblue": "#0000cd",
|
||||||
|
"mediumorchid": "#ba55d3",
|
||||||
|
"mediumpurple": "#9370db",
|
||||||
|
"mediumseagreen": "#3cb371",
|
||||||
|
"mediumslateblue": "#7b68ee",
|
||||||
|
"mediumspringgreen": "#00fa9a",
|
||||||
|
"mediumturquoise": "#48d1cc",
|
||||||
|
"mediumvioletred": "#c71585",
|
||||||
|
"midnightblue": "#191970",
|
||||||
|
"mintcream": "#f5fffa",
|
||||||
|
"mistyrose": "#ffe4e1",
|
||||||
|
"moccasin": "#ffe4b5",
|
||||||
|
"navajowhite": "#ffdead",
|
||||||
|
"navy": "#000080",
|
||||||
|
"oldlace": "#fdf5e6",
|
||||||
|
"olive": "#808000",
|
||||||
|
"olivedrab": "#6b8e23",
|
||||||
|
"orange": "#ffa500",
|
||||||
|
"orangered": "#ff4500",
|
||||||
|
"orchid": "#da70d6",
|
||||||
|
"palegoldenrod": "#eee8aa",
|
||||||
|
"palegreen": "#98fb98",
|
||||||
|
"paleturquoise": "#afeeee",
|
||||||
|
"palevioletred": "#db7093",
|
||||||
|
"papayawhip": "#ffefd5",
|
||||||
|
"peachpuff": "#ffdab9",
|
||||||
|
"peru": "#cd853f",
|
||||||
|
"pink": "#ffc0cb",
|
||||||
|
"plum": "#dda0dd",
|
||||||
|
"powderblue": "#b0e0e6",
|
||||||
|
"purple": "#800080",
|
||||||
|
"red": "#ff0000",
|
||||||
|
"rosybrown": "#bc8f8f",
|
||||||
|
"royalblue": "#4169e1",
|
||||||
|
"saddlebrown": "#8b4513",
|
||||||
|
"salmon": "#fa8072",
|
||||||
|
"sandybrown": "#f4a460",
|
||||||
|
"seagreen": "#2e8b57",
|
||||||
|
"seashell": "#fff5ee",
|
||||||
|
"sienna": "#a0522d",
|
||||||
|
"silver": "#c0c0c0",
|
||||||
|
"skyblue": "#87ceeb",
|
||||||
|
"slateblue": "#6a5acd",
|
||||||
|
"slategray": "#708090",
|
||||||
|
"slategrey": "#708090",
|
||||||
|
"snow": "#fffafa",
|
||||||
|
"springgreen": "#00ff7f",
|
||||||
|
"steelblue": "#4682b4",
|
||||||
|
"tan": "#d2b48c",
|
||||||
|
"teal": "#008080",
|
||||||
|
"thistle": "#d8bfd8",
|
||||||
|
"tomato": "#ff6347",
|
||||||
|
"turquoise": "#40e0d0",
|
||||||
|
"violet": "#ee82ee",
|
||||||
|
"wheat": "#f5deb3",
|
||||||
|
"white": "#ffffff",
|
||||||
|
"whitesmoke": "#f5f5f5",
|
||||||
|
"yellow": "#ffff00",
|
||||||
|
"yellowgreen": "#9acd32",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def htmlThemeDesigner(cssCache: {}, baseDir: str,
|
||||||
|
nickname: str, domain: str,
|
||||||
|
translate: {}, defaultTimeline: str,
|
||||||
|
themeName: str, accessKeys: {}) -> str:
|
||||||
|
"""Edit theme settings
|
||||||
|
"""
|
||||||
|
themeFilename = baseDir + '/theme/' + themeName + '/theme.json'
|
||||||
|
themeJson = {}
|
||||||
|
if os.path.isfile(themeFilename):
|
||||||
|
themeJson = loadJson(themeFilename)
|
||||||
|
|
||||||
|
# set custom theme parameters
|
||||||
|
customVariablesFile = baseDir + '/accounts/theme.json'
|
||||||
|
if os.path.isfile(customVariablesFile):
|
||||||
|
customThemeParams = loadJson(customVariablesFile, 0)
|
||||||
|
if customThemeParams:
|
||||||
|
for variableName, value in customThemeParams.items():
|
||||||
|
themeJson[variableName] = value
|
||||||
|
|
||||||
|
themeForm = ''
|
||||||
|
cssFilename = baseDir + '/epicyon-profile.css'
|
||||||
|
if os.path.isfile(baseDir + '/epicyon.css'):
|
||||||
|
cssFilename = baseDir + '/epicyon.css'
|
||||||
|
|
||||||
|
instanceTitle = \
|
||||||
|
getConfigParam(baseDir, 'instanceTitle')
|
||||||
|
themeForm = \
|
||||||
|
htmlHeaderWithExternalStyle(cssFilename, instanceTitle, None)
|
||||||
|
bannerFile, bannerFilename = \
|
||||||
|
getBannerFile(baseDir, nickname, domain, themeName)
|
||||||
|
themeForm += \
|
||||||
|
'<a href="/users/' + nickname + '/' + defaultTimeline + '" ' + \
|
||||||
|
'accesskey="' + accessKeys['menuTimeline'] + '">' + \
|
||||||
|
'<img loading="lazy" class="timeline-banner" ' + \
|
||||||
|
'title="' + translate['Switch to timeline view'] + '" ' + \
|
||||||
|
'alt="' + translate['Switch to timeline view'] + '" ' + \
|
||||||
|
'src="/users/' + nickname + '/' + bannerFile + '" /></a>\n'
|
||||||
|
themeForm += '<div class="container">\n'
|
||||||
|
|
||||||
|
themeForm += \
|
||||||
|
' <h1>' + translate['Theme Designer'] + '</h1>\n'
|
||||||
|
|
||||||
|
themeForm += ' <form method="POST" action="' + \
|
||||||
|
'/users/' + nickname + '/changeThemeSettings">\n'
|
||||||
|
|
||||||
|
resetKey = accessKeys['menuLogout']
|
||||||
|
submitKey = accessKeys['submitButton']
|
||||||
|
themeForm += \
|
||||||
|
' <center>\n' + \
|
||||||
|
' <button type="submit" class="button" ' + \
|
||||||
|
'name="submitThemeDesignerReset" ' + \
|
||||||
|
'accesskey="' + resetKey + '">' + \
|
||||||
|
translate['Reset'] + '</button>\n' + \
|
||||||
|
' <button type="submit" class="button" ' + \
|
||||||
|
'name="submitThemeDesigner" accesskey="' + submitKey + '">' + \
|
||||||
|
translate['Submit'] + '</button>\n </center>\n'
|
||||||
|
|
||||||
|
themeForm += ' <table class="accesskeys">\n'
|
||||||
|
themeForm += ' <colgroup>\n'
|
||||||
|
themeForm += ' <col span="1" class="accesskeys-left">\n'
|
||||||
|
themeForm += ' <col span="1" class="accesskeys-center">\n'
|
||||||
|
themeForm += ' </colgroup>\n'
|
||||||
|
themeForm += ' <tbody>\n'
|
||||||
|
|
||||||
|
for variableName, value in themeJson.items():
|
||||||
|
# only use colors defined as hex
|
||||||
|
if not value.startswith('#'):
|
||||||
|
if color_to_hex.get(value):
|
||||||
|
value = color_to_hex[value]
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
if variableName.endswith('-color') or \
|
||||||
|
variableName.endswith('-text'):
|
||||||
|
variableNameStr = variableName.replace('-', ' ')
|
||||||
|
if variableNameStr.endswith(' color'):
|
||||||
|
variableNameStr = variableNameStr.replace(' color', '')
|
||||||
|
if variableNameStr.endswith(' bg'):
|
||||||
|
variableNameStr = variableNameStr.replace(' bg', ' background')
|
||||||
|
elif variableNameStr.endswith(' fg'):
|
||||||
|
variableNameStr = variableNameStr.replace(' fg', ' foreground')
|
||||||
|
variableNameStr = variableNameStr.title()
|
||||||
|
themeForm += \
|
||||||
|
' <tr><td><label class="labels">' + \
|
||||||
|
variableNameStr + '</label></td>'
|
||||||
|
themeForm += \
|
||||||
|
'<td><input type="color" name="themeSetting_' + \
|
||||||
|
variableName + '" value="' + str(value) + \
|
||||||
|
'" title="' + variableNameStr + '"></p></td></tr>\n'
|
||||||
|
|
||||||
|
themeForm += ' </table>\n'
|
||||||
|
themeForm += ' </form>\n'
|
||||||
|
themeForm += '</div>\n'
|
||||||
|
themeForm += htmlFooter()
|
||||||
|
return themeForm
|
||||||
|
|
@ -10,6 +10,7 @@ __module_group__ = "Timeline"
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
|
from utils import isArtist
|
||||||
from utils import dangerousMarkup
|
from utils import dangerousMarkup
|
||||||
from utils import getConfigParam
|
from utils import getConfigParam
|
||||||
from utils import getFullDomain
|
from utils import getFullDomain
|
||||||
|
|
@ -430,7 +431,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
twitterReplacementDomain: str,
|
twitterReplacementDomain: str,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
newswire: {}, moderator: bool,
|
newswire: {}, moderator: bool,
|
||||||
editor: bool,
|
editor: bool, artist: bool,
|
||||||
positiveVoting: bool,
|
positiveVoting: bool,
|
||||||
showPublishAsIcon: bool,
|
showPublishAsIcon: bool,
|
||||||
fullWidthTimelineButtonHeader: bool,
|
fullWidthTimelineButtonHeader: bool,
|
||||||
|
|
@ -744,7 +745,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
leftColumnStr = \
|
leftColumnStr = \
|
||||||
getLeftColumnContent(baseDir, nickname, domainFull,
|
getLeftColumnContent(baseDir, nickname, domainFull,
|
||||||
httpPrefix, translate,
|
httpPrefix, translate,
|
||||||
editor, False, None, rssIconAtTop,
|
editor, artist, False, None, rssIconAtTop,
|
||||||
True, False, theme, accessKeys,
|
True, False, theme, accessKeys,
|
||||||
sharedItemsFederatedDomains)
|
sharedItemsFederatedDomains)
|
||||||
tlStr += ' <td valign="top" class="col-left" ' + \
|
tlStr += ' <td valign="top" class="col-left" ' + \
|
||||||
|
|
@ -1146,6 +1147,7 @@ def htmlShares(cssCache: {}, defaultTimeline: str,
|
||||||
"""
|
"""
|
||||||
manuallyApproveFollowers = \
|
manuallyApproveFollowers = \
|
||||||
followerApprovalActive(baseDir, nickname, domain)
|
followerApprovalActive(baseDir, nickname, domain)
|
||||||
|
artist = isArtist(baseDir, nickname)
|
||||||
|
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
recentPostsCache, maxRecentPosts,
|
recentPostsCache, maxRecentPosts,
|
||||||
|
|
@ -1159,7 +1161,7 @@ def htmlShares(cssCache: {}, defaultTimeline: str,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
twitterReplacementDomain,
|
twitterReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
newswire, False, False,
|
newswire, False, False, artist,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
|
|
@ -1200,6 +1202,7 @@ def htmlWanted(cssCache: {}, defaultTimeline: str,
|
||||||
"""
|
"""
|
||||||
manuallyApproveFollowers = \
|
manuallyApproveFollowers = \
|
||||||
followerApprovalActive(baseDir, nickname, domain)
|
followerApprovalActive(baseDir, nickname, domain)
|
||||||
|
artist = isArtist(baseDir, nickname)
|
||||||
|
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
recentPostsCache, maxRecentPosts,
|
recentPostsCache, maxRecentPosts,
|
||||||
|
|
@ -1213,7 +1216,7 @@ def htmlWanted(cssCache: {}, defaultTimeline: str,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
twitterReplacementDomain,
|
twitterReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
newswire, False, False,
|
newswire, False, False, artist,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
|
|
@ -1255,6 +1258,7 @@ def htmlInbox(cssCache: {}, defaultTimeline: str,
|
||||||
"""
|
"""
|
||||||
manuallyApproveFollowers = \
|
manuallyApproveFollowers = \
|
||||||
followerApprovalActive(baseDir, nickname, domain)
|
followerApprovalActive(baseDir, nickname, domain)
|
||||||
|
artist = isArtist(baseDir, nickname)
|
||||||
|
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
recentPostsCache, maxRecentPosts,
|
recentPostsCache, maxRecentPosts,
|
||||||
|
|
@ -1268,7 +1272,7 @@ def htmlInbox(cssCache: {}, defaultTimeline: str,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
twitterReplacementDomain,
|
twitterReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
newswire, False, False,
|
newswire, False, False, artist,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
|
|
@ -1310,6 +1314,7 @@ def htmlBookmarks(cssCache: {}, defaultTimeline: str,
|
||||||
"""
|
"""
|
||||||
manuallyApproveFollowers = \
|
manuallyApproveFollowers = \
|
||||||
followerApprovalActive(baseDir, nickname, domain)
|
followerApprovalActive(baseDir, nickname, domain)
|
||||||
|
artist = isArtist(baseDir, nickname)
|
||||||
|
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
recentPostsCache, maxRecentPosts,
|
recentPostsCache, maxRecentPosts,
|
||||||
|
|
@ -1323,7 +1328,7 @@ def htmlBookmarks(cssCache: {}, defaultTimeline: str,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
twitterReplacementDomain,
|
twitterReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
newswire, False, False,
|
newswire, False, False, artist,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
|
|
@ -1363,6 +1368,7 @@ def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
|
||||||
CWlists: {}, listsEnabled: str) -> str:
|
CWlists: {}, listsEnabled: str) -> str:
|
||||||
"""Show the DM timeline as html
|
"""Show the DM timeline as html
|
||||||
"""
|
"""
|
||||||
|
artist = isArtist(baseDir, nickname)
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
recentPostsCache, maxRecentPosts,
|
recentPostsCache, maxRecentPosts,
|
||||||
translate, pageNumber,
|
translate, pageNumber,
|
||||||
|
|
@ -1373,7 +1379,7 @@ def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
twitterReplacementDomain,
|
twitterReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
newswire, False, False, positiveVoting,
|
newswire, False, False, artist, positiveVoting,
|
||||||
showPublishAsIcon,
|
showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
|
|
@ -1413,6 +1419,7 @@ def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
|
||||||
CWlists: {}, listsEnabled: str) -> str:
|
CWlists: {}, listsEnabled: str) -> str:
|
||||||
"""Show the replies timeline as html
|
"""Show the replies timeline as html
|
||||||
"""
|
"""
|
||||||
|
artist = isArtist(baseDir, nickname)
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
recentPostsCache, maxRecentPosts,
|
recentPostsCache, maxRecentPosts,
|
||||||
translate, pageNumber,
|
translate, pageNumber,
|
||||||
|
|
@ -1424,7 +1431,7 @@ def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
twitterReplacementDomain,
|
twitterReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
newswire, False, False,
|
newswire, False, False, artist,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
|
|
@ -1464,6 +1471,7 @@ def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
|
||||||
CWlists: {}, listsEnabled: str) -> str:
|
CWlists: {}, listsEnabled: str) -> str:
|
||||||
"""Show the media timeline as html
|
"""Show the media timeline as html
|
||||||
"""
|
"""
|
||||||
|
artist = isArtist(baseDir, nickname)
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
recentPostsCache, maxRecentPosts,
|
recentPostsCache, maxRecentPosts,
|
||||||
translate, pageNumber,
|
translate, pageNumber,
|
||||||
|
|
@ -1475,7 +1483,7 @@ def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
twitterReplacementDomain,
|
twitterReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
newswire, False, False,
|
newswire, False, False, artist,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
|
|
@ -1515,6 +1523,7 @@ def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
|
||||||
CWlists: {}, listsEnabled: str) -> str:
|
CWlists: {}, listsEnabled: str) -> str:
|
||||||
"""Show the blogs timeline as html
|
"""Show the blogs timeline as html
|
||||||
"""
|
"""
|
||||||
|
artist = isArtist(baseDir, nickname)
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
recentPostsCache, maxRecentPosts,
|
recentPostsCache, maxRecentPosts,
|
||||||
translate, pageNumber,
|
translate, pageNumber,
|
||||||
|
|
@ -1526,7 +1535,7 @@ def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
twitterReplacementDomain,
|
twitterReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
newswire, False, False,
|
newswire, False, False, artist,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
|
|
@ -1578,7 +1587,7 @@ def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
twitterReplacementDomain,
|
twitterReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
newswire, False, False,
|
newswire, False, False, False,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
|
|
@ -1601,7 +1610,7 @@ def htmlInboxNews(cssCache: {}, defaultTimeline: str,
|
||||||
YTReplacementDomain: str,
|
YTReplacementDomain: str,
|
||||||
twitterReplacementDomain: str,
|
twitterReplacementDomain: str,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
newswire: {}, moderator: bool, editor: bool,
|
newswire: {}, moderator: bool, editor: bool, artist: bool,
|
||||||
positiveVoting: bool, showPublishAsIcon: bool,
|
positiveVoting: bool, showPublishAsIcon: bool,
|
||||||
fullWidthTimelineButtonHeader: bool,
|
fullWidthTimelineButtonHeader: bool,
|
||||||
iconsAsButtons: bool,
|
iconsAsButtons: bool,
|
||||||
|
|
@ -1629,7 +1638,7 @@ def htmlInboxNews(cssCache: {}, defaultTimeline: str,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
twitterReplacementDomain,
|
twitterReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
newswire, moderator, editor,
|
newswire, moderator, editor, artist,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
|
|
@ -1671,6 +1680,7 @@ def htmlOutbox(cssCache: {}, defaultTimeline: str,
|
||||||
"""
|
"""
|
||||||
manuallyApproveFollowers = \
|
manuallyApproveFollowers = \
|
||||||
followerApprovalActive(baseDir, nickname, domain)
|
followerApprovalActive(baseDir, nickname, domain)
|
||||||
|
artist = isArtist(baseDir, nickname)
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
recentPostsCache, maxRecentPosts,
|
recentPostsCache, maxRecentPosts,
|
||||||
translate, pageNumber,
|
translate, pageNumber,
|
||||||
|
|
@ -1682,7 +1692,7 @@ def htmlOutbox(cssCache: {}, defaultTimeline: str,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
twitterReplacementDomain,
|
twitterReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
newswire, False, False, positiveVoting,
|
newswire, False, False, artist, positiveVoting,
|
||||||
showPublishAsIcon, fullWidthTimelineButtonHeader,
|
showPublishAsIcon, fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None, theme, peertubeInstances,
|
authorized, None, theme, peertubeInstances,
|
||||||
|
|
|
||||||