A nicer tag interface
Getty Ritter
4 years ago
| 175 | 175 | { |
| 176 | 176 | "id": design.visible_id, |
| 177 | 177 | "title": design.title, |
| 178 |
"tags": |
|
| 178 | "tags": design.tags, | |
| 179 | "all_tags": model.Tag.select(model.Tag.tag_name) | |
| 180 | .distinct() | |
| 181 | .order_by(model.Tag.tag_name), | |
| 179 | 182 | "categories": design.category_list(), |
| 180 | 183 | "description": design.description, |
| 181 | 184 | "photos": ({"image": d} for d in design.photos), |
| 288 | 291 | def do_edit_page(slug): |
| 289 | 292 | text = flask.request.form.get("text", "") |
| 290 | 293 | title = flask.request.form.get("title", slug.capitalize()) |
| 291 |
model.Page.update(title=title, text=text).where(model.Page.name |
|
| 294 | model.Page.update(title=title, text=text).where(model.Page.name == slug).execute() | |
| 292 | 295 | return flask.redirect(f"/edit/pages/{slug}") |
| 293 | 296 | |
| 294 | 297 | |
| 1 | 1 | import woofmark from 'woofmark'; |
| 2 | 2 | import megamark from 'megamark'; |
| 3 | import Tagify from '@yaireo/tagify'; | |
| 3 | 4 | |
| 4 | 5 | window.onload = () => { |
| 6 | let input = document.querySelector('.tag_input'); | |
| 7 | if (input) { | |
| 8 | let tags = new Tagify(input); | |
| 9 | } | |
| 10 | ||
| 5 | 11 | let woof = woofmark(document.getElementById("editor"), { |
| 6 | 12 | parseMarkdown: megamark, |
| 7 | 13 | html: false, |
| 5 | 5 | |
| 6 | 6 | db = peewee.SqliteDatabase("new.db") |
| 7 | 7 | PER_PAGE = 16 |
| 8 | ||
| 8 | 9 | |
| 9 | 10 | def slugify(string): |
| 10 | 11 | def process(char): |
| 29 | 30 | |
| 30 | 31 | @classmethod |
| 31 | 32 | def all(klass): |
| 32 |
elements = ( |
|
| 33 | elements = ( | |
| 34 | {"url": f"/category/{c.name}", "name": c.nicename} for c in klass.select() | |
| 35 | ) | |
| 33 | 36 | return {"elements": elements} |
| 34 | 37 | |
| 35 | 38 | |
| 43 | 46 | return markdown.markdown(self.description) |
| 44 | 47 | |
| 45 | 48 | def id_str(self): |
| 46 |
return f |
|
| 49 | return f"{self.visible_id:05}" | |
| 47 | 50 | |
| 48 | 51 | def slug(self): |
| 49 | 52 | return slugify(self.title) |
| 57 | 60 | |
| 58 | 61 | def category_list(self): |
| 59 | 62 | categories = Category.select() |
| 60 | return [ | |
| 61 | {"name": c.name, "selected": c == self.category} | |
| 62 | for c in categories | |
| 63 | ] | |
| 63 | return [{"name": c.name, "selected": c == self.category} for c in categories] | |
| 64 | 64 | |
| 65 | 65 | def to_json(self): |
| 66 | 66 | return { |
| 86 | 86 | @classmethod |
| 87 | 87 | def get_all(klass, page=0): |
| 88 | 88 | designs = klass.select().paginate(page, PER_PAGE) |
| 89 | return Paginated.paginate( | |
| 90 | page, | |
| 91 | klass.select().count(), | |
| 92 | designs, | |
| 93 |
|
|
| 89 | return Paginated.paginate(page, klass.select().count(), designs,) | |
| 94 | 90 | |
| 95 | 91 | @classmethod |
| 96 | 92 | def get_where(klass, *, tag=None, category=None, page=0): |
| 101 | 97 | query = query.switch(klass).join(Category).where(Category.name == category) |
| 102 | 98 | query = query.group_by(klass).order_by(klass.id) |
| 103 | 99 | designs = query.paginate(page, PER_PAGE) |
| 104 | return Paginated.paginate( | |
| 105 | page, | |
| 106 | query.count(), | |
| 107 | designs, | |
| 108 |
|
|
| 100 | return Paginated.paginate(page, query.count(), designs,) | |
| 109 | 101 | |
| 110 | 102 | |
| 111 | 103 | class Photo(Model): |
| 131 | 123 | |
| 132 | 124 | @classmethod |
| 133 | 125 | def all(klass): |
| 134 |
elements = ( |
|
| 126 | elements = ( | |
| 127 | {"url": f"/tag/{t.tag_name}", "name": t.tag_name} | |
| 128 | for t in klass.select(klass.tag_name).distinct().order_by(klass.tag_name) | |
| 129 | ) | |
| 135 | 130 | return {"elements": elements} |
| 136 | ||
| 137 | 131 | |
| 138 | 132 | |
| 139 | 133 | class PageRef(typing.NamedTuple): |
| 171 | 165 | # prev_page: typing.Optional[dict] |
| 172 | 166 | # last_page: int |
| 173 | 167 | # contents: typing.List[Design] |
| 174 | ||
| 6 | 6 | "author": "Getty Ritter <gettylefou@gmail.com>", |
| 7 | 7 | "license": "MIT", |
| 8 | 8 | "dependencies": { |
| 9 | "@yaireo/tagify": "^4.0.5", | |
| 9 | 10 | "cash-dom": "^8.1.0", |
| 10 | 11 | "easymde": "^2.12.1", |
| 11 | 12 | "megamark": "^3.3.0", |
| 12 | "tagify": "^0.1.1", | |
| 13 | 13 | "woofmark": "^4.2.6" |
| 14 | 14 | }, |
| 15 | 15 | "scripts": { |
| 19 | 19 | <div class="edittile taglist"> |
| 20 | 20 | <label>Tags</label><br> |
| 21 | 21 | <div class="tags"> |
| 22 |
<input |
|
| 22 | <input class="tag_input" type="text" name="tags" | |
| 23 | value="{{#tags}}{{tag_name}},{{/tags}}" | |
| 24 | data-whitelist="{{#all_tags}}{{tag_name}},{{/all_tags}}" | |
| 25 | /> | |
| 23 | 26 | </div> |
| 24 | 27 | </div> |
| 25 | 28 | <div class="edittile"> |
| 14 | 14 | <meta http-equiv="Content-Type" contents="application/xhtml+xml; charset=utf-8;" /> |
| 15 | 15 | <meta name="description" content="Cross-Stitch Patterns and Other Crafts from Frony Ritter Designs" /> |
| 16 | 16 | <link rel="stylesheet" type="text/css" href="/static/standard.css" /> |
| 17 | <link rel="stylesheet" type="text/css" href="/static/tagify.css" /> | |
| 17 | 18 | <title>Frony Ritter Designs – {{title}}</title> |
| 18 | 19 | </head> |
| 19 | 20 | <body> |
| 79 | 80 | <div style="clear: both;"></div> |
| 80 | 81 | </div> |
| 81 | 82 | <div class="nav bottom"> |
| 82 |
<span class="text"> ©202 |
|
| 83 | <span class="text"> ©2021 Frony Ritter Designs</span> <a href="/about/">About</a> <a href="/contact/">Contact</a> | |
| 83 | 84 | </div> |
| 84 | 85 | </div> |
| 85 | 86 | </body> |
| 976 | 976 | resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" |
| 977 | 977 | integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== |
| 978 | 978 | |
| 979 | "@yaireo/tagify@^4.0.5": | |
| 980 | version "4.0.5" | |
| 981 | resolved "https://registry.yarnpkg.com/@yaireo/tagify/-/tagify-4.0.5.tgz#476bbbeaa08d53f6cc469b6309ea1540dbdad2a8" | |
| 982 | integrity sha512-HCIn2bCQ114SBDHafUR+jDutKFDbxDIjlWygg3eQBVpmJIcavKdYX6MdW5Jeh0QEcuDP4Ihby9QnZVNbv3z43Q== | |
| 983 | ||
| 979 | 984 | acorn@^6.4.1: |
| 980 | 985 | version "6.4.1" |
| 981 | 986 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" |
| 2985 | 2990 | dependencies: |
| 2986 | 2991 | wrappy "1" |
| 2987 | 2992 | |
| 2988 | optimist@~0.3: | |
| 2989 | version "0.3.7" | |
| 2990 | resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.3.7.tgz#c90941ad59e4273328923074d2cf2e7cbc6ec0d9" | |
| 2991 | integrity sha1-yQlBrVnkJzMokjB00s8ufLxuwNk= | |
| 2992 | dependencies: | |
| 2993 | wordwrap "~0.0.2" | |
| 2994 | ||
| 2995 | 2993 | os-browserify@^0.3.0: |
| 2996 | 2994 | version "0.3.0" |
| 2997 | 2995 | resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" |
| 3734 | 3732 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== |
| 3735 | 3733 | dependencies: |
| 3736 | 3734 | has-flag "^3.0.0" |
| 3737 | ||
| 3738 | tagify@^0.1.1: | |
| 3739 | version "0.1.1" | |
| 3740 | resolved "https://registry.yarnpkg.com/tagify/-/tagify-0.1.1.tgz#bcd42738a27fc0915e2dd070137859541861a4bc" | |
| 3741 | integrity sha1-vNQnOKJ/wJFeLdBwE3hZVBhhpLw= | |
| 3742 | dependencies: | |
| 3743 | optimist "~0.3" | |
| 3744 | 3735 | |
| 3745 | 3736 | tapable@^1.0.0, tapable@^1.1.3: |
| 3746 | 3737 | version "1.1.3" |
| 4057 | 4048 | local-storage "1.4.2" |
| 4058 | 4049 | seleccion "2.0.0" |
| 4059 | 4050 | |
| 4060 | wordwrap@~0.0.2: | |
| 4061 | version "0.0.3" | |
| 4062 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" | |
| 4063 | integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= | |
| 4064 | ||
| 4065 | 4051 | worker-farm@^1.7.0: |
| 4066 | 4052 | version "1.7.0" |
| 4067 | 4053 | resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" |