956 Code changes to enable dark mode

pull/1185/head
tanc 2 years ago
parent 87726e0bb2
commit 427cf105a3

@ -202,7 +202,8 @@ def changedetection_app(config=None, datastore_o=None):
watch_api.add_resource(api_v1.SystemInfo, '/api/v1/systeminfo', watch_api.add_resource(api_v1.SystemInfo, '/api/v1/systeminfo',
resource_class_kwargs={'datastore': datastore, 'update_q': update_q}) resource_class_kwargs={'datastore': datastore, 'update_q': update_q})
def getDarkModeSetting():
return datastore.data['settings']['application']['css_dark_mode']
# Setup cors headers to allow all domains # Setup cors headers to allow all domains
# https://flask-cors.readthedocs.io/en/latest/ # https://flask-cors.readthedocs.io/en/latest/
@ -403,6 +404,7 @@ def changedetection_app(config=None, datastore_o=None):
form = forms.quickWatchForm(request.form) form = forms.quickWatchForm(request.form)
output = render_template("watch-overview.html", output = render_template("watch-overview.html",
dark_mode=getDarkModeSetting(),
form=form, form=form,
watches=sorted_watches, watches=sorted_watches,
tags=existing_tags, tags=existing_tags,
@ -661,6 +663,7 @@ def changedetection_app(config=None, datastore_o=None):
browser_steps_config=browser_step_ui_config, browser_steps_config=browser_step_ui_config,
current_base_url=datastore.data['settings']['application']['base_url'], current_base_url=datastore.data['settings']['application']['base_url'],
emailprefix=os.getenv('NOTIFICATION_MAIL_BUTTON_PREFIX', False), emailprefix=os.getenv('NOTIFICATION_MAIL_BUTTON_PREFIX', False),
dark_mode=getDarkModeSetting(),
form=form, form=form,
has_default_notification_urls=True if len(datastore.data['settings']['application']['notification_urls']) else False, has_default_notification_urls=True if len(datastore.data['settings']['application']['notification_urls']) else False,
has_empty_checktime=using_default_check_time, has_empty_checktime=using_default_check_time,
@ -748,6 +751,7 @@ def changedetection_app(config=None, datastore_o=None):
output = render_template("settings.html", output = render_template("settings.html",
form=form, form=form,
dark_mode=getDarkModeSetting(),
current_base_url = datastore.data['settings']['application']['base_url'], current_base_url = datastore.data['settings']['application']['base_url'],
hide_remove_pass=os.getenv("SALTED_PASS", False), hide_remove_pass=os.getenv("SALTED_PASS", False),
api_key=datastore.data['settings']['application'].get('api_access_token'), api_key=datastore.data['settings']['application'].get('api_access_token'),
@ -788,6 +792,7 @@ def changedetection_app(config=None, datastore_o=None):
# Could be some remaining, or we could be on GET # Could be some remaining, or we could be on GET
output = render_template("import.html", output = render_template("import.html",
dark_mode=getDarkModeSetting(),
import_url_list_remaining="\n".join(remaining_urls), import_url_list_remaining="\n".join(remaining_urls),
original_distill_json='' original_distill_json=''
) )
@ -865,6 +870,7 @@ def changedetection_app(config=None, datastore_o=None):
newest=newest_version_file_contents, newest=newest_version_file_contents,
previous=previous_version_file_contents, previous=previous_version_file_contents,
extra_stylesheets=extra_stylesheets, extra_stylesheets=extra_stylesheets,
dark_mode=getDarkModeSetting(),
versions=dates[:-1], # All except current/last versions=dates[:-1], # All except current/last
uuid=uuid, uuid=uuid,
newest_version_timestamp=dates[-1], newest_version_timestamp=dates[-1],
@ -912,6 +918,7 @@ def changedetection_app(config=None, datastore_o=None):
content=content, content=content,
history_n=watch.history_n, history_n=watch.history_n,
extra_stylesheets=extra_stylesheets, extra_stylesheets=extra_stylesheets,
dark_mode=getDarkModeSetting(),
# current_diff_url=watch['url'], # current_diff_url=watch['url'],
watch=watch, watch=watch,
uuid=uuid, uuid=uuid,
@ -958,6 +965,7 @@ def changedetection_app(config=None, datastore_o=None):
content=content, content=content,
history_n=watch.history_n, history_n=watch.history_n,
extra_stylesheets=extra_stylesheets, extra_stylesheets=extra_stylesheets,
dark_mode=getDarkModeSetting(),
ignored_line_numbers=ignored_line_numbers, ignored_line_numbers=ignored_line_numbers,
triggered_line_numbers=trigger_line_numbers, triggered_line_numbers=trigger_line_numbers,
current_diff_url=watch['url'], current_diff_url=watch['url'],
@ -976,6 +984,7 @@ def changedetection_app(config=None, datastore_o=None):
def notification_logs(): def notification_logs():
global notification_debug_log global notification_debug_log
output = render_template("notification-log.html", output = render_template("notification-log.html",
dark_mode=getDarkModeSetting(),
logs=notification_debug_log if len(notification_debug_log) else ["Notification logs are empty - no notifications sent yet."]) logs=notification_debug_log if len(notification_debug_log) else ["Notification logs are empty - no notifications sent yet."])
return output return output
@ -1204,6 +1213,14 @@ def changedetection_app(config=None, datastore_o=None):
flash("{} watches are queued for rechecking.".format(i)) flash("{} watches are queued for rechecking.".format(i))
return redirect(url_for('index', tag=tag)) return redirect(url_for('index', tag=tag))
@app.route("/toggle-theme", methods=['GET'])
@login_required
def toggle_theme():
current_mode = datastore.data['settings']['application']['css_dark_mode']
new_mode = not current_mode
datastore.data['settings']['application']['css_dark_mode'] = new_mode
return ''
@app.route("/form/checkbox-operations", methods=['POST']) @app.route("/form/checkbox-operations", methods=['POST'])
@login_required @login_required
def form_watch_list_checkbox_operations(): def form_watch_list_checkbox_operations():

@ -27,6 +27,7 @@ class model(dict):
'base_url' : None, 'base_url' : None,
'extract_title_as_title': False, 'extract_title_as_title': False,
'empty_pages_are_a_change': False, 'empty_pages_are_a_change': False,
'css_dark_mode': False,
'fetch_backend': getenv("DEFAULT_FETCH_BACKEND", "html_requests"), 'fetch_backend': getenv("DEFAULT_FETCH_BACKEND", "html_requests"),
'filter_failure_notification_threshold_attempts': _FILTER_FAILURE_THRESHOLD_ATTEMPTS_DEFAULT, 'filter_failure_notification_threshold_attempts': _FILTER_FAILURE_THRESHOLD_ATTEMPTS_DEFAULT,
'global_ignore_text': [], # List of text to ignore when calculating the comparison checksum 'global_ignore_text': [], # List of text to ignore when calculating the comparison checksum

@ -1,112 +1,110 @@
var a = document.getElementById('a'); var a = document.getElementById("a");
var b = document.getElementById('b'); var b = document.getElementById("b");
var result = document.getElementById('result'); var result = document.getElementById("result");
function changed() { function changed() {
// https://github.com/kpdecker/jsdiff/issues/389 // https://github.com/kpdecker/jsdiff/issues/389
// I would love to use `{ignoreWhitespace: true}` here but it breaks the formatting // I would love to use `{ignoreWhitespace: true}` here but it breaks the formatting
options = {ignoreWhitespace: document.getElementById('ignoreWhitespace').checked}; options = {
ignoreWhitespace: document.getElementById("ignoreWhitespace").checked,
var diff = Diff[window.diffType](a.textContent, b.textContent, options); };
var fragment = document.createDocumentFragment();
for (var i = 0; i < diff.length; i++) { var diff = Diff[window.diffType](a.textContent, b.textContent, options);
var fragment = document.createDocumentFragment();
if (diff[i].added && diff[i + 1] && diff[i + 1].removed) { for (var i = 0; i < diff.length; i++) {
var swap = diff[i]; if (diff[i].added && diff[i + 1] && diff[i + 1].removed) {
diff[i] = diff[i + 1]; var swap = diff[i];
diff[i + 1] = swap; diff[i] = diff[i + 1];
} diff[i + 1] = swap;
var node;
if (diff[i].removed) {
node = document.createElement('del');
node.classList.add("change");
node.appendChild(document.createTextNode(diff[i].value));
} else if (diff[i].added) {
node = document.createElement('ins');
node.classList.add("change");
node.appendChild(document.createTextNode(diff[i].value));
} else {
node = document.createTextNode(diff[i].value);
}
fragment.appendChild(node);
} }
result.textContent = ''; var node;
result.appendChild(fragment); if (diff[i].removed) {
node = document.createElement("del");
node.classList.add("change");
const wrapper = node.appendChild(document.createElement("span"));
wrapper.appendChild(document.createTextNode(diff[i].value));
} else if (diff[i].added) {
node = document.createElement("ins");
node.classList.add("change");
const wrapper = node.appendChild(document.createElement("span"));
wrapper.appendChild(document.createTextNode(diff[i].value));
} else {
node = document.createTextNode(diff[i].value);
}
fragment.appendChild(node);
}
// Jump at start result.textContent = "";
inputs.current = 0; result.appendChild(fragment);
next_diff();
// Jump at start
inputs.current = 0;
next_diff();
} }
window.onload = function () { window.onload = function () {
/* Convert what is options from UTC time.time() to local browser time */
var diffList = document.getElementById("diff-version");
/* Convert what is options from UTC time.time() to local browser time */ if (typeof diffList != "undefined" && diffList != null) {
var diffList = document.getElementById("diff-version"); for (var option of diffList.options) {
if (typeof (diffList) != 'undefined' && diffList != null) { var dateObject = new Date(option.value * 1000);
for (var option of diffList.options) { option.label = dateObject.toLocaleString();
var dateObject = new Date(option.value * 1000);
option.label = dateObject.toLocaleString();
}
} }
}
/* Set current version date as local time in the browser also */
var current_v = document.getElementById("current-v-date"); /* Set current version date as local time in the browser also */
var dateObject = new Date(newest_version_timestamp*1000); var current_v = document.getElementById("current-v-date");
current_v.innerHTML = dateObject.toLocaleString(); var dateObject = new Date(newest_version_timestamp * 1000);
onDiffTypeChange(document.querySelector('#settings [name="diff_type"]:checked')); current_v.innerHTML = dateObject.toLocaleString();
changed(); onDiffTypeChange(
document.querySelector('#settings [name="diff_type"]:checked'),
);
changed();
}; };
a.onpaste = a.onchange = a.onpaste = a.onchange = b.onpaste = b.onchange = changed;
b.onpaste = b.onchange = changed;
if ('oninput' in a) { if ("oninput" in a) {
a.oninput = b.oninput = changed; a.oninput = b.oninput = changed;
} else { } else {
a.onkeyup = b.onkeyup = changed; a.onkeyup = b.onkeyup = changed;
} }
function onDiffTypeChange(radio) { function onDiffTypeChange(radio) {
window.diffType = radio.value; window.diffType = radio.value;
// Not necessary // Not necessary
// document.title = "Diff " + radio.value.slice(4); // document.title = "Diff " + radio.value.slice(4);
} }
var radio = document.getElementsByName('diff_type'); var radio = document.getElementsByName("diff_type");
for (var i = 0; i < radio.length; i++) { for (var i = 0; i < radio.length; i++) {
radio[i].onchange = function (e) { radio[i].onchange = function (e) {
onDiffTypeChange(e.target); onDiffTypeChange(e.target);
changed();
}
}
document.getElementById('ignoreWhitespace').onchange = function (e) {
changed(); changed();
};
} }
document.getElementById("ignoreWhitespace").onchange = function (e) {
changed();
};
var inputs = document.getElementsByClassName('change'); var inputs = document.getElementsByClassName("change");
inputs.current = 0; inputs.current = 0;
function next_diff() { function next_diff() {
var element = inputs[inputs.current];
var element = inputs[inputs.current]; var headerOffset = 80;
var headerOffset = 80; var elementPosition = element.getBoundingClientRect().top;
var elementPosition = element.getBoundingClientRect().top; var offsetPosition = elementPosition - headerOffset + window.scrollY;
var offsetPosition = elementPosition - headerOffset + window.scrollY;
window.scrollTo({
window.scrollTo({ top: offsetPosition,
top: offsetPosition, behavior: "smooth",
behavior: "smooth" });
});
inputs.current++;
inputs.current++; if (inputs.current >= inputs.length) {
if (inputs.current >= inputs.length) { inputs.current = 0;
inputs.current = 0; }
}
} }

@ -0,0 +1,26 @@
/**
* @file
* Toggles theme between light and dark mode.
*/
$(document).ready(function () {
const url = "/toggle-theme";
const button = document.getElementsByClassName("toggle-theme")[0];
button.onclick = () => {
fetch(url)
.then(function () {
const htmlElement = document.getElementsByTagName("html");
const isDarkMode = htmlElement[0].dataset.darkmode === "true";
htmlElement[0].dataset.darkmode = !isDarkMode;
if (isDarkMode) {
button.classList.remove("dark");
} else {
button.classList.add("dark");
}
})
.catch(function (e) {
console.log("Can't toggle the theme. Error was: ", e);
});
};
});
Loading…
Cancel
Save