diff options
| -rw-r--r-- | Makefile | 2 | ||||
| -rwxr-xr-x | avon.py | 154 | ||||
| -rw-r--r-- | requirements.txt | 27 | ||||
| -rw-r--r-- | templates/index.html | 76 |
4 files changed, 211 insertions, 48 deletions
| @@ -1,7 +1,7 @@ | |||
| 1 | all: install | 1 | all: install |
| 2 | 2 | ||
| 3 | run: | 3 | run: |
| 4 | venv/bin/python avon.py -P 8080 & | 4 | PYTHONIOENCODING=UTF-8 venv/bin/python avon.py -H 127.0.1.24 -P 8080 |
| 5 | 5 | ||
| 6 | venv: | 6 | venv: |
| 7 | python3 -m venv ./venv | 7 | python3 -m venv ./venv |
| @@ -4,19 +4,18 @@ import os | |||
| 4 | import sys | 4 | import sys |
| 5 | import pprint | 5 | import pprint |
| 6 | import json | 6 | import json |
| 7 | from flask import Flask,render_template,request | 7 | from flask import Flask,render_template,request,url_for |
| 8 | from argparse import ArgumentParser | 8 | from argparse import ArgumentParser |
| 9 | import psycopg2 | 9 | import psycopg |
| 10 | 10 | ||
| 11 | app = Flask(__name__) | 11 | app = Flask(__name__) |
| 12 | 12 | ||
| 13 | class Convert_jinja_object: | 13 | class Convert_jinja_object: |
| 14 | 14 | ||
| 15 | def __init__(self): | 15 | def __init__(self): |
| 16 | self.myvar = 'sample_var' | 16 | self.year_map = [ "92Q2", "95Q0", "96Q0", "96Q1", "97Q1", "97Q3", "98Q1", "98Q3", "99Q1", "99Q3", "00Q1", "00Q3", "01Q1", "01Q2", "01Q3", "01Q4", "02Q1", "02Q3", "03Q1", "03Q3", "04Q1", "04Q3", "05Q1", "05Q3", "06Q1", "06Q3", "07Q1", "07Q3", "08Q1", "08Q3", "09Q1", "09Q3", "10Q1", "10Q3", "11Q1", "11Q3", "12Q1", "12Q3", "13Q1", "13Q3", "14Q1", "14Q3", "15Q1", "15Q3", "16Q1", "16Q3", "17Q1", "17Q3", "18Q1", "18Q3", "19Q1", "19Q3", "20Q1", "20Q3", "21Q1", "21Q3", "22Q1", "22Q3", "23Q1", "23Q3", "24Q1", "24Q3", "25Q1", "25Q3" ] |
| 17 | 17 | ||
| 18 | def bits_to_years(self, x): | 18 | def bits_to_years(self, x): |
| 19 | year_map = [ "92Q2", "95Q0", "96Q0", "96Q1", "97Q1", "97Q3", "98Q1", "98Q3", "99Q1", "99Q3", "00Q1", "00Q3", "01Q1", "01Q2", "01Q3", "01Q4", "02Q1", "02Q3", "03Q1", "03Q3", "04Q1", "04Q3", "05Q1", "05Q3", "06Q1", "06Q3", "07Q1", "07Q3", "08Q1", "08Q3", "09Q1", "09Q3", "10Q1", "10Q3", "11Q1", "11Q3", "12Q1", "12Q3", "13Q1", "13Q3", "14Q1", "14Q3", "15Q1", "15Q3", "16Q1", "16Q3", "17Q1", "17Q3", "18Q1", "18Q3", "19Q1", "19Q3", "20Q1", "20Q3" ] | ||
| 20 | if x == 0: | 19 | if x == 0: |
| 21 | return '/' | 20 | return '/' |
| 22 | years = '' | 21 | years = '' |
| @@ -28,59 +27,170 @@ class Convert_jinja_object: | |||
| 28 | x = ~(x >> start_off) | 27 | x = ~(x >> start_off) |
| 29 | end_off = (x&-x).bit_length()-1 | 28 | end_off = (x&-x).bit_length()-1 |
| 30 | x = ~(x >> (end_off + 1)) | 29 | x = ~(x >> (end_off + 1)) |
| 31 | years = years + (year_map[index + start_off]) | 30 | years = years + (self.year_map[index + start_off]) |
| 32 | if end_off > 1: | 31 | if end_off > 1: |
| 33 | years = years + '-' + year_map[index + start_off + end_off - 1] | 32 | years = years + '-' + self.year_map[index + start_off + end_off - 1] |
| 34 | index = index + start_off + end_off + 1 | 33 | index = index + start_off + end_off + 1 |
| 35 | return years | 34 | return years |
| 36 | 35 | ||
| 36 | def multirange_to_years(self, row): | ||
| 37 | # Format of multi-ranges is {[low,high),[low,high],(low,high),(low,high)]} | ||
| 38 | # Although Telefonbuch only ever inserts the [low,high) range types, so for now let's keep the parser simple | ||
| 39 | years = [] | ||
| 40 | for range_item in row: | ||
| 41 | low = range_item.lower | ||
| 42 | high = range_item.upper - 1 | ||
| 43 | year = self.year_map[low] | ||
| 44 | if (low != high): | ||
| 45 | year += '-' + self.year_map[high] | ||
| 46 | years.append(year) | ||
| 47 | return ', '.join(years) | ||
| 48 | |||
| 37 | @app.route("/", methods=['GET', 'POST']) | 49 | @app.route("/", methods=['GET', 'POST']) |
| 38 | def root(): | 50 | def root(): |
| 39 | content = request.json | 51 | convert = Convert_jinja_object() |
| 40 | 52 | ||
| 41 | query = "SELECT DISTINCT ON (id) presence_flag, reverse_flag, biz_flag, zip, nachname, vorname, zusaetze, strasse, hausnummer, verweise, ort, vorwahl, rufnummer, web, email, coords FROM Telefonbuch " | 53 | query = "SELECT DISTINCT ON (id) presence_flag, reverse_flag, biz_flag, zip, nachname, vorname, zusaetze, strasse, hausnummer, verweise, ort, vorwahl, rufnummer, web, email, coords FROM Telefonbuch " |
| 42 | where = "" | 54 | where = "" |
| 43 | params = [] | 55 | params = [] |
| 44 | anyjoin = "" | 56 | anyjoin = "" |
| 57 | pastjoin = [] | ||
| 58 | rv = request.values.to_dict(flat=True) | ||
| 59 | |||
| 60 | # pprint.pprint(request.values) | ||
| 45 | 61 | ||
| 46 | for i in range(1,5): | 62 | for i in range(1,5): |
| 47 | search = request.form.get("search_{0}_string".format(i)) | 63 | search = rv.get("s{0}_val".format(i)) |
| 48 | if not search: continue | 64 | if not search: |
| 49 | column = request.form.get("search_{0}_column".format(i)) | 65 | rv.pop("s{0}_val".format(i), '') |
| 50 | operator = request.form.get("search_{0}_operator".format(i)) | 66 | rv.pop("s{0}_col".format(i), '') |
| 51 | isany = request.form.get("search_{0}_any".format(i)) | 67 | rv.pop("s{0}_op".format(i), '') |
| 68 | rv.pop("s{0}_any".format(i), '') | ||
| 69 | continue | ||
| 70 | column = rv.get("s{0}_col".format(i)) | ||
| 71 | operator = rv.get("s{0}_op".format(i)) | ||
| 72 | isany = rv.get("s{0}_any".format(i)) | ||
| 73 | |||
| 74 | if not column in [ 'zip', 'nachname', 'vorname', 'zusaetze', 'strasse', 'hausnummer', 'verweise', 'ort', 'vorwahl', 'rufnummer', 'web', 'email', 'coords', 'id' ]: continue | ||
| 52 | 75 | ||
| 53 | if not column in [ 'zip', 'nachname', 'vorname', 'zusaetze', 'strasse', 'hausnummer', 'verweise', 'ort', 'vorwahl', 'rufnummer', 'web', 'email', 'coords' ]: continue | 76 | if not column in pastjoin: |
| 77 | query = query + "INNER JOIN table_{0} ON Telefonbuch.id = table_{0}.telefonbuch_id ".format(column) | ||
| 78 | pastjoin.append(column) | ||
| 54 | 79 | ||
| 55 | query = query + "INNER JOIN table_{0} ON Telefonbuch.id = table_{0}.telefonbuch_id ".format(column) | ||
| 56 | if len(where): | 80 | if len(where): |
| 57 | where = where + "AND " | 81 | where = where + "AND " |
| 58 | else: | 82 | else: |
| 59 | where = "WHERE " | 83 | where = "WHERE " |
| 60 | where = where + "table_{0}.value {1} %s ".format(column, {'equals': '=', 'equalsnot': '<>', 'contains': 'ILIKE', 'containsnot': 'NOT ILIKE', 'beginswith': 'ILIKE'}[operator]) | 84 | where = where + "table_{0}.value {1} %s ".format(column, {'equals': '=', 'equalsnot': '<>', 'contains': 'ILIKE', 'containsnot': 'NOT ILIKE', 'beginswith': 'LIKE', 'beginslike': 'ILIKE'}[operator]) |
| 61 | if not isany: | 85 | if not isany: |
| 62 | if len(anyjoin) == 0: | 86 | if len(anyjoin) == 0 or "table_" + column == anyjoin: |
| 63 | anyjoin = "table_" + column | 87 | anyjoin = "table_" + column |
| 64 | else: | 88 | else: |
| 65 | where = where + "AND " + anyjoin + ".offs = table_" + column + ".offs " | 89 | where = where + "AND " + anyjoin + ".offs = table_" + column + ".offs " |
| 66 | if operator in ['contains','containsnot']: | 90 | if operator in ['contains','containsnot']: |
| 67 | search = "%" + search + "%" | 91 | search = "%" + search + "%" |
| 68 | if operator in ['beginswith']: | 92 | if operator in ['beginswith', 'beginslike']: |
| 93 | search = search + "%" | ||
| 94 | params.append(search) | ||
| 95 | |||
| 96 | range_min = int(rv.get("year_range_min", '0')) | ||
| 97 | range_max = int(rv.get("year_range_max", len(convert.year_map) - 1)) | ||
| 98 | if range_min > range_max: | ||
| 99 | range_max, range_min = range_min, range_max | ||
| 100 | rv["year_range_min"] = range_min | ||
| 101 | rv["year_range_max"] = range_max | ||
| 102 | |||
| 103 | if range_min > 0 or range_max < len(convert.year_map) - 1: | ||
| 104 | if len(where) > 0: | ||
| 105 | where += "AND presence_flag && int4range({},{})" .format(range_min, range_max) | ||
| 106 | else: | ||
| 107 | rv.pop("year_range_min", 0) | ||
| 108 | rv.pop("year_range_max", 0) | ||
| 109 | |||
| 110 | limit = "10000" | ||
| 111 | if rv.get("huge"): | ||
| 112 | limit = "100000" | ||
| 113 | |||
| 114 | if len(where) > 0: | ||
| 115 | conn = psycopg.connect(dbname="telefonbuch", user="postgres", password="", host="127.0.0.1") | ||
| 116 | cur = conn.cursor() | ||
| 117 | print (query + where + ' LIMIT ' + limit) | ||
| 118 | pprint.pprint( params ) | ||
| 119 | |||
| 120 | cur.execute(query + where + ' LIMIT ' + limit, params) | ||
| 121 | rows = cur.fetchall() | ||
| 122 | else: | ||
| 123 | rows = [] | ||
| 124 | |||
| 125 | return render_template('index.html', rows=rows, request=request, rv=rv, convert=convert) | ||
| 126 | |||
| 127 | @app.route("/facebook", methods=['GET', 'POST']) | ||
| 128 | def facebook(): | ||
| 129 | |||
| 130 | query = "SELECT phone, id, first_name, last_name, gender, location, originally_from, relationship_state, ocupation, email, birthday FROM facebook " | ||
| 131 | where = "" | ||
| 132 | params = [] | ||
| 133 | anyjoin = "" | ||
| 134 | pastjoin = [] | ||
| 135 | rv = request.values.to_dict(flat=True) | ||
| 136 | |||
| 137 | pprint.pprint(request.values) | ||
| 138 | |||
| 139 | for i in range(1,5): | ||
| 140 | search = rv.get("s{0}_val".format(i)) | ||
| 141 | if not search: | ||
| 142 | rv.pop("s{0}_val".format(i), '') | ||
| 143 | rv.pop("s{0}_col".format(i), '') | ||
| 144 | rv.pop("s{0}_op".format(i), '') | ||
| 145 | rv.pop("s{0}_any".format(i), '') | ||
| 146 | continue | ||
| 147 | column = rv.get("s{0}_col".format(i)) | ||
| 148 | operator = rv.get("s{0}_op".format(i)) | ||
| 149 | isany = rv.get("s{0}_any".format(i)) | ||
| 150 | |||
| 151 | if not column in [ 'phone', 'first_name', 'last_name', 'gender', 'location', 'originally_from', 'relationship_state', 'ocupation', 'email', 'id' ]: continue | ||
| 152 | |||
| 153 | if column == 'phone': | ||
| 154 | search = search.lstrip('+') | ||
| 155 | |||
| 156 | if len(where): | ||
| 157 | where = where + "AND " | ||
| 158 | else: | ||
| 159 | where = "WHERE " | ||
| 160 | where = where + "{0} {1} %s ".format(column, {'equals': '=', 'equalsnot': '<>', 'contains': 'ILIKE', 'containsnot': 'NOT ILIKE', 'beginswith': 'LIKE', 'beginslike': 'ILIKE'}[operator]) | ||
| 161 | if operator in ['contains','containsnot']: | ||
| 162 | search = "%" + search + "%" | ||
| 163 | if operator in ['beginswith', 'beginslike']: | ||
| 69 | search = search + "%" | 164 | search = search + "%" |
| 70 | params.append(search) | 165 | params.append(search) |
| 71 | 166 | ||
| 167 | limit = "10000" | ||
| 168 | if rv.get("huge"): | ||
| 169 | limit = "100000" | ||
| 170 | |||
| 72 | if len(where) > 0: | 171 | if len(where) > 0: |
| 73 | conn = psycopg2.connect(database="erdgeist", user="postgres", password="", host="127.0.0.1") | 172 | conn = psycopg.connect(dbname="tbuch", user="postgres", password="", host="127.0.0.1") |
| 74 | cur = conn.cursor() | 173 | cur = conn.cursor() |
| 75 | print (query + where + ' LIMIT 10000') | 174 | print (query + where + ' LIMIT ' + limit) |
| 76 | pprint.pprint( params ) | 175 | pprint.pprint( params ) |
| 77 | 176 | ||
| 78 | cur.execute(query + where + ' LIMIT 10000', params) | 177 | cur.execute(query + where + ' LIMIT ' + limit, params) |
| 79 | rows = cur.fetchall() | 178 | rows = cur.fetchall() |
| 80 | else: | 179 | else: |
| 81 | rows = [[0,0,0,{},{},{},{},{},{},{},{},{},{}]] | 180 | rows = [] |
| 181 | |||
| 182 | return render_template('facebook.html', rows=rows, request=request, rv=rv) | ||
| 183 | |||
| 184 | def column_and_op_to_where(column, operator): | ||
| 185 | return "{0} {1} %s ".format(column, {'equals': '=', 'equalsnot': '<>', 'contains': 'ILIKE', 'containsnot': 'NOT ILIKE', 'beginswith': 'LIKE', 'beginslike': 'ILIKE'}[operator]) | ||
| 186 | |||
| 187 | def search_and_operator_to_search(search, operator): | ||
| 188 | if operator in ['contains','containsnot']: | ||
| 189 | search = "%" + search + "%" | ||
| 190 | if operator in ['beginswith', 'beginslike']: | ||
| 191 | search = search + "%" | ||
| 192 | return search | ||
| 82 | 193 | ||
| 83 | return render_template('index.html', rows=rows, request=request, convert=Convert_jinja_object()) | ||
| 84 | 194 | ||
| 85 | if __name__ == "__main__": | 195 | if __name__ == "__main__": |
| 86 | parser = ArgumentParser(description="AVON") | 196 | parser = ArgumentParser(description="AVON") |
diff --git a/requirements.txt b/requirements.txt index 7ed34e8..40d4446 100644 --- a/requirements.txt +++ b/requirements.txt | |||
| @@ -1,12 +1,15 @@ | |||
| 1 | certifi==2018.11.29 | 1 | certifi |
| 2 | chardet==3.0.4 | 2 | chardet |
| 3 | Click==7.0 | 3 | Click |
| 4 | Flask==1.0.2 | 4 | Flask |
| 5 | idna==2.8 | 5 | idna |
| 6 | itsdangerous==1.1.0 | 6 | itsdangerous |
| 7 | Jinja2==2.10 | 7 | Jinja2 |
| 8 | MarkupSafe==1.1.1 | 8 | MarkupSafe |
| 9 | psycopg2==2.7.7 | 9 | psycopg |
| 10 | requests==2.21.0 | 10 | psycopg-c |
| 11 | urllib3==1.24.1 | 11 | requests |
| 12 | Werkzeug==0.14.1 | 12 | typing_extensions |
| 13 | urllib3 | ||
| 14 | Werkzeug | ||
| 15 | |||
diff --git a/templates/index.html b/templates/index.html index cf4e616..955d813 100644 --- a/templates/index.html +++ b/templates/index.html | |||
| @@ -5,39 +5,89 @@ | |||
| 5 | td { vertical-align: top; } | 5 | td { vertical-align: top; } |
| 6 | tr.color_1 { background: #ccc; } | 6 | tr.color_1 { background: #ccc; } |
| 7 | table { border: none; } | 7 | table { border: none; } |
| 8 | #year-slider { margin: 0.3em; width: 50vw; } | ||
| 9 | #slider-container { display: inline; padding: 0.3em; } | ||
| 8 | </style> | 10 | </style> |
| 11 | <link rel="stylesheet" type="text/css" href="static/nouislider.min.css"> | ||
| 12 | <script src="static/nouislider.min.js"></script> | ||
| 9 | </head> | 13 | </head> |
| 10 | <body> | 14 | <body> |
| 11 | <form action="/" METHOD="POST"> | 15 | <div>Jahre: <div id="slider-container"><div id="year-slider" class="search_entry"></div></div> |
| 16 | <div id="main-form"><form action="/" METHOD="POST"> | ||
| 17 | {% set yrmin = rv.get('year_range_min', 0) | int %} | ||
| 18 | {% set yrmax = rv.get('year_range_max', convert.year_map | length - 1 ) | int %} | ||
| 19 | <label for="year-range-value-min">Ab Jahr</label> | ||
| 20 | <select id="year-range-value-min" name="year_range_min"> | ||
| 21 | {%- for year in convert.year_map -%} | ||
| 22 | <option value="{{loop.index - 1}}" {% if loop.index - 1 == yrmin %} selected="selected"{% endif %}>{{year}}</option> | ||
| 23 | {%- endfor -%} | ||
| 24 | </select> | ||
| 25 | <label for="year-range-value-max">Bis Jahr</label> | ||
| 26 | <select id="year-range-value-max" name="year_range_max"> | ||
| 27 | {%- for year in convert.year_map -%} | ||
| 28 | <option value="{{loop.index - 1}}" {% if loop.index - 1 == yrmax %} selected="selected"{% endif %}>{{year}}</option> | ||
| 29 | {%- endfor -%} | ||
| 30 | </select> | ||
| 31 | |||
| 32 | <!--p><b>Wir importieren momentan das neue Telefonbuch Herbst 2025. Wahrscheinlich wird die Suche solange nicht korrekt funktionieren.</b></p--> | ||
| 33 | |||
| 12 | {%- for field in range(1,5) -%} | 34 | {%- for field in range(1,5) -%} |
| 13 | <div class="search_entry"> | 35 | <div class="search_entry"> |
| 14 | <select name="search_{{ field }}_column"> | 36 | <select name="s{{ field }}_col"> |
| 15 | {% set column_search = request.form.get('search_'+(field|string)+'_string', '') %} | 37 | {% set column_search = rv.get('s'+(field|string)+'_val', '') %} |
| 16 | {% if column_search | length %} | 38 | {% if column_search | length %} |
| 17 | {% set column_val = request.form.get('search_'+(field|string)+'_column') %} | 39 | {% set column_val = rv.get('s'+(field|string)+'_col') %} |
| 18 | {% set operator_val = request.form.get('search_'+(field|string)+'_operator') %} | 40 | {% set operator_val = rv.get('s'+(field|string)+'_op') %} |
| 19 | {% set any_val = request.form.get('search_'+(field|string)+'_any') %} | 41 | {% set any_val = rv.get('s'+(field|string)+'_any') %} |
| 20 | {% else %} | 42 | {% else %} |
| 21 | {% set column_val = ['nachname', 'vorname', 'ort', 'rufnummer'][field-1] %} | 43 | {% set column_val = ['nachname', 'vorname', 'ort', 'rufnummer'][field-1] %} |
| 22 | {% set operator_val = ['equals', 'contains', 'equals', 'contains'][field-1] %} | 44 | {% set operator_val = ['equals', 'equals', 'equals', 'beginswith'][field-1] %} |
| 23 | {% set any_val = ['', '', 'on', ''][field-1] %} | 45 | {% set any_val = ['', '', 'on', ''][field-1] %} |
| 24 | {% endif %} | 46 | {% endif %} |
| 25 | {%- for column in [ ['vorname', 'Vorname'], ['nachname', 'Nachname'], ['zip', 'PLZ'], ['ort', 'Ort'], ['vorwahl', 'Vorwahl'], ['rufnummer', 'Rufnummer'], ['strasse', 'Straße'], ['hausnummer', 'Hausnummer'], ['zusaetze', 'Zusatz'], ['verweise', 'Verweise / Branche'], ['email', 'E-Mail'], ['web', 'Webseite'] ] -%} | 47 | {%- for column in [ ['vorname', 'Vorname'], ['nachname', 'Nachname'], ['zip', 'PLZ'], ['ort', 'Ort'], ['vorwahl', 'Vorwahl'], ['rufnummer', 'Rufnummer'], ['strasse', 'Straße'], ['hausnummer', 'Hausnummer'], ['zusaetze', 'Zusatz'], ['verweise', 'Verweise / Branche'], ['email', 'E-Mail'], ['web', 'Webseite'] ] -%} |
| 26 | <option value="{{ column[0] }}" {%- if column_val== column[0] -%}selected="selected"{%- endif -%}>{{ column[1] }}</option> | 48 | <option value="{{ column[0] }}" {%- if column_val== column[0] -%}selected="selected"{%- endif -%}>{{ column[1] }}</option> |
| 27 | {%- endfor -%} | 49 | {%- endfor -%} |
| 28 | </select> | 50 | </select> |
| 29 | <select name="search_{{ field }}_operator"> | 51 | <select name="s{{ field }}_op"> |
| 30 | {%- for operator in [ [ 'equals', 'equals'], ['beginswith', 'begins with'], ['contains', 'contains' ], ['equalsnot', 'equals not'], ['containsnot', 'contains not'] ] -%} | 52 | {%- for operator in [ [ 'equals', 'equals'], ['beginswith', 'begins with'], ['beginslike', 'begins like'], ['contains', 'contains' ], ['equalsnot', 'equals not'], ['containsnot', 'contains not'] ] -%} |
| 31 | <option value="{{ operator[0] }}" {%- if operator_val == operator[0] -%}selected="selected"{%- endif -%}>{{ operator[1] }}</option> | 53 | <option value="{{ operator[0] }}" {%- if operator_val == operator[0] -%}selected="selected"{%- endif -%}>{{ operator[1] }}</option> |
| 32 | {%- endfor -%} | 54 | {%- endfor -%} |
| 33 | </select> | 55 | </select> |
| 34 | <input type="checkbox" name="search_{{ field }}_any" {%- if any_val == 'on' -%}checked="{%- endif -%}">any</input> | 56 | <input type="checkbox" name="s{{ field }}_any" {%- if any_val == 'on' -%}checked="{%- endif -%}">any</input> |
| 35 | <input type="text" name="search_{{ field }}_string" value="{{ request.form.get('search_'+(field|string)+'_string', '') }}"> | 57 | <input type="text" name="s{{ field }}_val" value="{{ rv.get('s'+(field|string)+'_val', '') }}"> |
| 36 | </div> | 58 | </div> |
| 37 | {%- endfor -%} | 59 | {%- endfor -%} |
| 60 | <input type="checkbox" value="on" name="huge" id="huge" {%- if rv.get('huge', '') == "on" -%}checked{%- endif -%}> | ||
| 61 | <label for="huge">unlimited</label> | ||
| 38 | <input type="submit" value="Search"> | 62 | <input type="submit" value="Search"> |
| 39 | </form> | 63 | </form> |
| 40 | {% if rows | length > 0 -%}<h3>Found {{ rows | length }} matches.</h3>{% endif %} | 64 | <script> |
| 65 | var slider = document.getElementById('year-slider'); | ||
| 66 | var dropdownmin = document.getElementById('year-range-value-min'); | ||
| 67 | var dropdownmax = document.getElementById('year-range-value-max'); | ||
| 68 | noUiSlider.create(slider, { | ||
| 69 | start: [ {{ yrmin }}, {{ yrmax }} ], | ||
| 70 | connect: true, | ||
| 71 | step: 1, | ||
| 72 | range: { 'min': 0, 'max': {{ convert.year_map | length - 1}} }, | ||
| 73 | }); | ||
| 74 | var year_map = [ | ||
| 75 | {%- for year in convert.year_map -%} | ||
| 76 | '{{ year }}', | ||
| 77 | {%- endfor -%} | ||
| 78 | ]; | ||
| 79 | var year_range_display = document.getElementById('year-range-display'); | ||
| 80 | var year_range_value_min = document.getElementById('year-range-value-min'); | ||
| 81 | var year_range_value_max = document.getElementById('year-range-value-max'); | ||
| 82 | slider.noUiSlider.on('update', function (values, handle) { | ||
| 83 | year_range_value_min.value = Math.floor(values[0]); | ||
| 84 | year_range_value_max.value = Math.floor(values[1]); | ||
| 85 | }); | ||
| 86 | dropdownmin.onchange = function() { slider.noUiSlider.set( [this.value, null]); } | ||
| 87 | dropdownmax.onchange = function() { slider.noUiSlider.set( [null, this.value]); } | ||
| 88 | </script> | ||
| 89 | </div> | ||
| 90 | <h3>Found {{ rows | length }} matches for your <a href="{{ url_for(request.endpoint,**rv) }}">query</a>. <small>You may also try <a href="/facebook">the facebook search</a></small>.</h3> <!-- *dict(request.values)) }}">query</a>.</h3--> | ||
| 41 | {% set color = { 'value': 0 } %} | 91 | {% set color = { 'value': 0 } %} |
| 42 | <table> | 92 | <table> |
| 43 | <thead><td>flags</td><td>zip</td></thead> | 93 | <thead><td>flags</td><td>zip</td></thead> |
| @@ -47,7 +97,7 @@ | |||
| 47 | {% if ( r == 0 ) and ( color.update({ 'value': 1 - color.value }) ) %} {% endif %} | 97 | {% if ( r == 0 ) and ( color.update({ 'value': 1 - color.value }) ) %} {% endif %} |
| 48 | <tr class="color_{{ color.value }}"> | 98 | <tr class="color_{{ color.value }}"> |
| 49 | {%- if r == 0 -%} | 99 | {%- if r == 0 -%} |
| 50 | <td rowspan="{{span}}">{{ convert.bits_to_years(row[0]|int) }} : {{ convert.bits_to_years(row[1]|int) }} : {{ convert.bits_to_years(row[2]|int) }}</td> | 100 | <td rowspan="{{span}}">{{ convert.multirange_to_years(row[0]) }} : {{ convert.multirange_to_years(row[1]) }} : {{ convert.multirange_to_years(row[2]) }}</td> |
| 51 | {%- endif -%} | 101 | {%- endif -%} |
| 52 | {%- for c in range(3, 16) -%} | 102 | {%- for c in range(3, 16) -%} |
| 53 | <td>{{ row[c][r] or '' }}</td> | 103 | <td>{{ row[c][r] or '' }}</td> |
