, extracted from watch-overview.html so the same markup can be
re-rendered on its own and pushed over Socket.IO (realtime row resync) - one renderer,
so the row can never drift from the server-rendered list.
Rendered via {% include %} from the watch list loop, which inherits the full context:
watch, loop, is_checking_now(), queued_uuids, has_proxies, datastore, active_tag_uuid,
system_default_fetcher, ui_settings, favicons_enabled, fetcher_status_icons,
processor_descriptions, get_all_tags_for_watch(), any_has_restock_price_processor
#}
{%- set checking_now = is_checking_now(watch) -%}
{%- set history_n = watch.history_n -%}
{%- set favicon = watch.get_favicon_filename() -%}
{%- set error_texts = watch.compile_error_texts(has_proxies=has_proxies) -%}
{%- set system_use_url_watchlist = datastore.data['settings']['application']['ui'].get('use_page_title_in_list') -%}
{# Class settings mirrored in changedetectionio/static/js/realtime.js for the frontend #}
{# loop.cycle('pure-table-odd', 'pure-table-even'),#}
{%- set row_classes = [
'processor-' ~ watch['processor'],
'has-error' if error_texts|length > 2 else '',
'paused' if watch.paused is defined and watch.paused != False else '',
'unviewed' if watch.has_unviewed else '',
'has-restock-info' if watch.has_restock_info else 'no-restock-info',
'has-favicon' if favicon else '',
'in-stock' if watch.has_restock_info and watch['restock']['in_stock'] else '',
'not-in-stock' if watch.has_restock_info and not watch['restock']['in_stock'] else '',
'queued' if watch.uuid in queued_uuids else '',
'checking-now' if checking_now else '',
'notification_muted' if watch.notification_muted else '',
'single-history' if history_n == 1 else '',
'multiple-history' if history_n >= 2 else '',
'use-html-title' if system_use_url_watchlist else 'no-html-title',
] -%}
{# {{ loop.index+pagination.skip }}#}
{% if 'favicons_enabled' not in ui_settings or ui_settings['favicons_enabled'] %}
{%- set effective_fetcher = watch.get_fetch_backend if watch.get_fetch_backend != "system" else system_default_fetcher -%}
{%- if effective_fetcher and ("html_webdriver" in effective_fetcher or "html_" in effective_fetcher or "extra_browser_" in effective_fetcher) -%}
{{ effective_fetcher|fetcher_status_icons }}
{%- endif -%}
{%- if watch.is_pdf -%}{%- endif -%}
{%- if watch.has_browser_steps -%}{%- endif -%}
{%- if watch['processor'] == 'restock_diff' -%}
{#- @todo - this could be injected somehow watch.extra_row_info or something -#}
{%- if watch.has_restock_info -%}
{%- if watch['restock']['in_stock']-%} {{ _('In stock') }} {%- else-%} {{ _('Not in stock') }} {%- endif -%}
{%- endif -%}
{%- if watch.get('restock') and watch['restock'].get('price') -%}
{%- set restock = watch['restock'] -%}
{%- set price = restock.get('price') -%}
{%- set currency = restock.get('currency') if restock.get('currency','') else '' -%}
{%- if price is not none and (price|string)|regex_search('\d') -%}
{# @todo: make parse_currency/parse_decimal aware of the locale of the actual web page and use that instead changedetectionio/processors/restock_diff/__init__.py #}
{%- if price is number -%}{# It's a number so we can convert it to their locale' #}
{{ price|format_number_locale }} {{ currency }}
{%- else -%}{# It's totally fine if it arrives as something else, the website might be something weird in this field #}
{{ price }} {{ currency }}
{%- endif -%}
{%- set price_change_pct = restock.get_price_change_percent() -%}
{%- if price_change_pct is not none -%}
{%- set prev_price = restock.get('last_price') -%}
{%- set prev_disp = (prev_price|format_number_locale ~ ' ' ~ currency) if prev_price is number else prev_price -%}
{%- if price_change_pct < 0 -%}
▼ {{ '%g'|format(price_change_pct) }}%
{%- else -%}
▲ +{{ '%g'|format(price_change_pct) }}%
{%- endif -%}
{%- endif -%}
{%- endif -%}
{%- elif not watch.has_restock_info -%}
{{ _('No information') }}
{%- endif -%}