diff --git a/yadc/bp/api.py b/yadc/bp/api.py index 090d191..a87a056 100644 --- a/yadc/bp/api.py +++ b/yadc/bp/api.py @@ -16,7 +16,7 @@ def post_index(): def tag_autocomplete(): query = request.args.get('q', '') if query != '': - tags = Tag.query.filter(Tag.content.like("%{}%".format(query))).limit(5).all() + tags = Tag.query.filter(Tag.content.like("%{}%".format(query))).limit(15).all() return jsonify([{"id": t.id, "content": t.content, "content_deser": t.content_deser, "category": {"id": t.category.value, "name": t.category.name}} for t in tags]) return jsonify() diff --git a/yadc/bp/post.py b/yadc/bp/post.py index 4e26390..0735bda 100644 --- a/yadc/bp/post.py +++ b/yadc/bp/post.py @@ -108,9 +108,10 @@ def upload(): file = request.files.get(form.post_img.name) file.data = io.BytesIO(file.read()) - # tags = form.tags.data.split() + f_tags = form.tags.data.split() + tags = Tag.query.filter(Tag.content.in_(f_tags)).all() - post = Post(file, source=form.sauce.data, rating=RATING[form.rating.data], author=current_user) + post = Post(file, source=form.sauce.data, tags=tags, rating=RATING[form.rating.data], author=current_user) with open(post.image_path, "wb") as f: diff --git a/yadc/forms.py b/yadc/forms.py index 9c244b3..15fc69f 100644 --- a/yadc/forms.py +++ b/yadc/forms.py @@ -63,8 +63,8 @@ def validate_file(form, field): class UploadForm(CSRFForm): post_img = FileField('Image', validators=[validate_file], render_kw={'required':''}) - sauce = StringField('Sauce', validators=[DataRequired()]) - tags = StringField('Tags', validators=[DataRequired()]) # CUSTOM VALIDATOR (also for Post edits) + sauce = StringField('Sauce', validators=[DataRequired()], render_kw={'placeholder':'Source URL','autocomplete':'off'}) + tags = StringField('Tags', validators=[DataRequired()], render_kw={'placeholder':'Tags','autocomplete':'off'}) # CUSTOM VALIDATOR (also for Post edits) rating = RadioField('Rating', choices=[('safe', 'Safe'), ('questionable', 'Questionable'), ('explicit', 'Explicit')], default='safe', @@ -82,7 +82,7 @@ class UploadForm(CSRFForm): class CommentForm(CSRFForm): post_id = HiddenField(validators=[DataRequired()]) - content = TextAreaField('Comment', validators=[DataRequired()]) + content = TextAreaField('Comment', validators=[DataRequired()], render_kw={'autocomplete':'off'}) submit = SubmitField('Send') class ChangePassForm(CSRFForm): @@ -116,7 +116,7 @@ class EditPostForm(CSRFForm): status = SelectField('Status', choices=[('pending', 'Pending'), ('active', 'Active'), ('deleted', 'Deleted')], validators=[optional()]) - source = StringField('Source') + source = StringField('Source', render_kw={'autocomplete':'off'}) edit = SubmitField('Modify') delete = SubmitField('Delete') diff --git a/yadc/static/all.css b/yadc/static/all.css index cb6dc1d..ac0976c 100644 --- a/yadc/static/all.css +++ b/yadc/static/all.css @@ -1 +1 @@ -*{box-sizing:border-box}body{margin:0;font-family:Verdana,Geneva,Tahoma,sans-serif;background-color:#222;color:#fff}a{color:#bbb;text-decoration:none}a:hover{color:#909090;text-decoration:none}header{display:flex;align-items:baseline;padding:0 10px;background-color:#222}header>a.logo{font-size:2em;margin:6px}@media(max-width:559px){header{position:relative}}header>nav{flex-grow:1;display:flex}header>nav>._overlay{display:none}@media(max-width:559px){header>nav{display:none}header>nav._drop{display:flex;flex-flow:column nowrap;position:absolute;margin:0;top:100%;left:0;right:0;z-index:10;background-color:#111d}header>nav>a,header>nav a#user-menu,header>nav .user_dropdown>a{padding:12px;padding-left:24px}header>nav>a:hover,header>nav>a:active,header>nav a#user-menu:hover,header>nav a#user-menu:active,header>nav .user_dropdown>a:hover,header>nav .user_dropdown>a:active{background-color:#333}header>nav .user::before{content:"";display:block;border-top:1px solid grey;margin:2px 12px}header>nav .user #user-menu{display:block}header>nav .user .user_dropdown{display:flex;flex-flow:column nowrap}header>nav>._overlay{display:block;position:fixed;width:100%;height:100%;z-index:-1;background-color:#0006}html.oh{overflow:hidden}}@media(min-width:560px){header>nav{margin:0 5px;align-items:center}header>nav>*{margin:0 5px;padding:6px 0}header>nav>.user{padding:0;margin-left:auto;margin-right:0;position:relative}header>nav>.user #user-menu{display:block;padding:6px 10px}header>nav>.user .user_dropdown{display:none}header>nav>.user .user_dropdown a{padding:10px}header>nav>.user .user_dropdown a:hover{background-color:#333}header>nav>.user:hover>.user_dropdown{display:flex;flex-flow:column nowrap;position:absolute;margin:0;top:100%;right:0;z-index:10;background-color:#111d}}header>#nav-menu{display:none}@media(max-width:559px){header>#nav-menu{display:block;margin:5px;margin-left:auto;padding:0 2px;align-self:center;font-size:2em;cursor:pointer}}.flash_msgs{display:flex;flex-flow:column-reverse nowrap;position:fixed;z-index:20;bottom:0;right:0;margin:0;padding:10px;font-size:.9em;pointer-events:none}.flash_msgs>li{width:250px;padding:10px;background-color:#000c;overflow:hidden;opacity:0;animation:fade 7s normal}.flash_msgs>li:not(:first-child){margin-bottom:10px}@keyframes fade{0%,100%{opacity:0}20%,80%{opacity:1}}.main_wrap{margin:0 auto;max-width:1300px;padding:8px;padding-top:0;padding-bottom:0}.main_wrap h3{margin:0;margin-bottom:10px;font-size:1.3em}.main_wrap .important_subwrap{display:flex;overflow:visible}@media(max-width:899px){.main_wrap .important_subwrap{flex-flow:column nowrap}}@media(min-width:900px){.main_wrap .important_subwrap{flex-flow:row nowrap}}.main_wrap .important_subwrap>section.side_panel{flex-shrink:0;padding:10px}@media(min-width:900px){.main_wrap .important_subwrap>section.side_panel{width:18rem;height:0}}.main_wrap .important_subwrap>section.side_panel article{margin-bottom:10px}.main_wrap .important_subwrap>section.side_panel article.tags .searchbox{width:calc(18rem - 50px);position:relative}.main_wrap .important_subwrap>section.side_panel article.tags .searchbox input[name=tagsearch]{width:100%}.main_wrap .important_subwrap>section.side_panel article.tags .searchbox>.search_dropdown{display:flex;flex-flow:column nowrap;align-items:start;top:100%;left:0;position:absolute;z-index:10;overflow:auto;background-color:#2d2d2de0}.main_wrap .important_subwrap>section.side_panel article.tags .tag_container>a,.main_wrap .important_subwrap>section.side_panel article.tags .search_dropdown>a{margin:2px 2px;padding:.35em .6em;border-radius:4px;background-color:#121212ff;cursor:pointer}.main_wrap .important_subwrap>section.side_panel article.tags .tag_container>a>*,.main_wrap .important_subwrap>section.side_panel article.tags .search_dropdown>a>*{pointer-events:none}.main_wrap .important_subwrap>section.side_panel article.tags .tag_container>a>.fa-tag,.main_wrap .important_subwrap>section.side_panel article.tags .search_dropdown>a>.fa-tag{font-size:.9em;margin-right:2px}.main_wrap .important_subwrap>section.side_panel article.tags .tag_container>a>.count,.main_wrap .important_subwrap>section.side_panel article.tags .search_dropdown>a>.count{font-size:.8em}.main_wrap .important_subwrap>section.side_panel article.tags .tag_container>a:not(:hover)>span.close,.main_wrap .important_subwrap>section.side_panel article.tags .search_dropdown>a:not(:hover)>span.close{display:none}.main_wrap .important_subwrap>section.side_panel article.tags .tag_container>a:not(:hover)>span.plus,.main_wrap .important_subwrap>section.side_panel article.tags .search_dropdown>a:not(:hover)>span.plus{display:none}.main_wrap .important_subwrap>section.side_panel article.tags .tag_container>a:hover>span.count,.main_wrap .important_subwrap>section.side_panel article.tags .search_dropdown>a:hover>span.count{display:none}.main_wrap .important_subwrap>section.side_panel article.tags .tag_container>a.tagselected,.main_wrap .important_subwrap>section.side_panel article.tags .search_dropdown>a.tagselected{background-color:#400808ff}.main_wrap .important_subwrap>section.side_panel article.tags .tag_container>a.tag_hide,.main_wrap .important_subwrap>section.side_panel article.tags .search_dropdown>a.tag_hide{display:none}.main_wrap .important_subwrap>section.side_panel article.tags .tag_container{display:flex}@media(max-width:899px){.main_wrap .important_subwrap>section.side_panel article.tags .tag_container{flex-flow:row wrap}}@media(min-width:900px){.main_wrap .important_subwrap>section.side_panel article.tags .tag_container{flex-flow:column nowrap;align-items:start}}.main_wrap .important_subwrap>section.side_panel article.post_desc{display:flex;flex-flow:column nowrap;font-size:.9em}.main_wrap .important_subwrap>section.side_panel article.post_desc>img{display:block;max-width:128px}@media(min-width:900px){.main_wrap .important_subwrap>section:not(.side_panel){width:100%}}.main_wrap section.post_list{overflow:hidden}@media(max-width:559px){.main_wrap section.post_list{margin-left:-8px;margin-right:-8px}}.main_wrap section.post_list .posts{display:flex;flex-flow:row wrap}@media(max-width:899px){.main_wrap section.post_list .posts{margin-left:-8px;margin-right:-8px}}.main_wrap section.post_list .posts::after{content:"";flex:10000 0 350px}.main_wrap section.post_list .posts>figure{position:relative;margin:8px}.main_wrap section.post_list .posts>figure img{display:block;width:100%;height:100%;transition:.2s ease}.main_wrap section.post_list .posts>figure:hover img{opacity:.7}@media(min-width:900px){.main_wrap section.post_single{padding:8px}}@media(max-width:899px){.main_wrap section.post_single{order:-1;margin-bottom:8px}}@media(max-width:559px){.main_wrap section.post_single{margin-left:-8px;margin-right:-8px}}.main_wrap section.post_single img{display:block;max-width:100%}.main_wrap section.comments{padding:10px}@media(min-width:900px){.main_wrap section.comments{margin-left:18rem}}.main_wrap section.comments>.comment_container{padding:0 10px;max-width:500px}.main_wrap section.comments>.comment_container article{overflow:hidden;margin-bottom:1em}.main_wrap section.comments>.comment_container h4{margin:0;margin-bottom:.5em}.main_wrap section.comments>.comment_container p,.main_wrap section.comments>.comment_container textarea{margin:0}.main_wrap section.comments>.comment_container p.deleted,.main_wrap section.comments>.comment_container textarea.deleted{color:red}.main_wrap section.comments>.comment_container .head{display:flex;justify-content:space-between}.main_wrap section.comments>.form>form{margin-left:10px;max-width:500px}.main_wrap section.comments>.form>form input:required{box-shadow:none}.main_wrap section.comments>.form>form textarea{width:100%;background:#444a;border:none;color:inherit;font:inherit}.main_wrap section.management_table table{margin:0 auto}.main_wrap section.management_table tr th{background-color:#606060}.main_wrap section.management_table tr:nth-child(even){background-color:#303030}.main_wrap section.management_table tr th,.main_wrap section.management_table tr td{padding:6px 10px}.main_wrap section.management_table tr:not(.edit) td>.edit{display:none}.main_wrap section.management_table tr.edit td>.show{display:none}.main_wrap section.management_table tr input[type=submit]{display:none}.main_wrap section.management_table tr .fa{padding:4px 4px;align-self:center;font-size:1.5em;cursor:pointer}.main_wrap form.editingable:not(.time-to-edit) .edit{display:none}.main_wrap form.editingable.time-to-edit .notedit{display:none}.main_wrap form.editingable input[type=text],.main_wrap form.editingable textarea{resize:vertical;width:100%}.main_wrap form.editingable input[type=text].edit,.edit .main_wrap form.editingable input[type=text],.main_wrap form.editingable textarea.edit,.edit .main_wrap form.editingable textarea{background:#444a;border:none;color:inherit;font:inherit}.main_wrap form input{margin:5px 0}.main_wrap .pagin{margin:10px 0;display:flex;flex-flow:row nowrap;justify-content:center}.main_wrap .pagin>a{display:block;background-color:#0005;padding:8px 12px;margin:0 2px}footer{padding:10px;text-align:center} \ No newline at end of file +*{box-sizing:border-box}body{margin:0;font-family:Verdana,Geneva,Tahoma,sans-serif;background-color:#222;color:#fff}a{color:#bbb;text-decoration:none}a:hover{color:#909090;text-decoration:none}header{display:flex;align-items:baseline;padding:0 10px;background-color:#222}header>a.logo{font-size:2em;margin:6px}@media(max-width:559px){header{position:relative}}header>nav{flex-grow:1;display:flex}header>nav>._overlay{display:none}@media(max-width:559px){header>nav{display:none}header>nav._drop{display:flex;flex-flow:column nowrap;position:absolute;margin:0;top:100%;left:0;right:0;z-index:10;background-color:#111d}header>nav>a,header>nav a#user-menu,header>nav .user_dropdown>a{padding:12px;padding-left:24px}header>nav>a:hover,header>nav>a:active,header>nav a#user-menu:hover,header>nav a#user-menu:active,header>nav .user_dropdown>a:hover,header>nav .user_dropdown>a:active{background-color:#333}header>nav .user::before{content:"";display:block;border-top:1px solid grey;margin:2px 12px}header>nav .user #user-menu{display:block}header>nav .user .user_dropdown{display:flex;flex-flow:column nowrap}header>nav>._overlay{display:block;position:fixed;width:100%;height:100%;z-index:-1;background-color:#0006}html.oh{overflow:hidden}}@media(min-width:560px){header>nav{margin:0 5px;align-items:center}header>nav>*{margin:0 5px;padding:6px 0}header>nav>.user{padding:0;margin-left:auto;margin-right:0;position:relative}header>nav>.user #user-menu{display:block;padding:6px 10px}header>nav>.user .user_dropdown{display:none}header>nav>.user .user_dropdown a{padding:10px}header>nav>.user .user_dropdown a:hover{background-color:#333}header>nav>.user:hover>.user_dropdown{display:flex;flex-flow:column nowrap;position:absolute;margin:0;top:100%;right:0;z-index:10;background-color:#111d}}header>#nav-menu{display:none}@media(max-width:559px){header>#nav-menu{display:block;margin:5px;margin-left:auto;padding:0 2px;align-self:center;font-size:2em;cursor:pointer}}.flash_msgs{display:flex;flex-flow:column-reverse nowrap;position:fixed;z-index:20;bottom:0;right:0;margin:0;padding:10px;font-size:.9em;pointer-events:none}.flash_msgs>li{width:250px;padding:10px;background-color:#000c;overflow:hidden;opacity:0;animation:fade 7s normal}.flash_msgs>li:not(:first-child){margin-bottom:10px}@keyframes fade{0%,100%{opacity:0}20%,80%{opacity:1}}.main_wrap{margin:0 auto;max-width:1300px;padding:8px;padding-top:0;padding-bottom:0}.main_wrap h3{margin:0;margin-bottom:10px;font-size:1.3em}.main_wrap form .tag_input .tag_suggester,.main_wrap .tag_input form .tag_suggester{width:calc(100% - 50px);position:relative}.main_wrap form .tag_input .tag_suggester>.tag_suggest_dropdown,.main_wrap .tag_input form .tag_suggester>.tag_suggest_dropdown{display:flex;flex-flow:column nowrap;align-items:start;top:100%;left:0;position:absolute;z-index:10;overflow:auto;background-color:#2d2d2de0}.main_wrap form .tag_input .tag_container,.main_wrap .tag_input form .tag_container{display:flex}.main_wrap form .tag_input .tag_container>a,.main_wrap .tag_input form .tag_container>a{margin:2px 2px;padding:.35em .6em;border-radius:4px;background-color:#121212ff;cursor:pointer}.main_wrap form .tag_input .tag_container>a>*,.main_wrap .tag_input form .tag_container>a>*{pointer-events:none}.main_wrap form .tag_input .tag_container>a>.fa-tag,.main_wrap .tag_input form .tag_container>a>.fa-tag{font-size:.9em;margin-right:2px}.main_wrap form .tag_input .tag_container>a>.count,.main_wrap .tag_input form .tag_container>a>.count{font-size:.8em}.main_wrap form .tag_input .tag_container>a:not(:hover)>span.close,.main_wrap .tag_input form .tag_container>a:not(:hover)>span.close{display:none}.main_wrap form .tag_input .tag_container>a:not(:hover)>span.plus,.main_wrap .tag_input form .tag_container>a:not(:hover)>span.plus{display:none}.main_wrap form .tag_input .tag_container>a:hover>span.count,.main_wrap .tag_input form .tag_container>a:hover>span.count{display:none}.main_wrap form .tag_input .tag_container>a.tagselected,.main_wrap .tag_input form .tag_container>a.tagselected{background-color:#400808ff}.main_wrap form .tag_input .tag_container>a.tag_hide,.main_wrap .tag_input form .tag_container>a.tag_hide{display:none}.main_wrap .important_subwrap{display:flex;overflow:visible}@media(max-width:899px){.main_wrap .important_subwrap{flex-flow:column nowrap}}@media(min-width:900px){.main_wrap .important_subwrap{flex-flow:row nowrap}}.main_wrap .important_subwrap>section.side_panel{flex-shrink:0;padding:10px}@media(min-width:900px){.main_wrap .important_subwrap>section.side_panel{width:18rem;height:0}}.main_wrap .important_subwrap>section.side_panel article{margin-bottom:10px}@media(max-width:899px){.main_wrap .important_subwrap>section.side_panel article.tags .tag_container{flex-flow:row wrap}}@media(min-width:900px){.main_wrap .important_subwrap>section.side_panel article.tags .tag_container{flex-flow:column nowrap;align-items:start}}.main_wrap .important_subwrap>section.side_panel article.post_desc{display:flex;flex-flow:column nowrap;font-size:.9em}.main_wrap .important_subwrap>section.side_panel article.post_desc>img{display:block;max-width:128px}@media(min-width:900px){.main_wrap .important_subwrap>section:not(.side_panel){width:100%}}.main_wrap section.post_list{overflow:hidden}@media(max-width:559px){.main_wrap section.post_list{margin-left:-8px;margin-right:-8px}}.main_wrap section.post_list .posts{display:flex;flex-flow:row wrap}@media(max-width:899px){.main_wrap section.post_list .posts{margin-left:-8px;margin-right:-8px}}.main_wrap section.post_list .posts::after{content:"";flex:10000 0 350px}.main_wrap section.post_list .posts>figure{position:relative;margin:8px}.main_wrap section.post_list .posts>figure img{display:block;width:100%;height:100%;transition:.2s ease}.main_wrap section.post_list .posts>figure:hover img{opacity:.7}@media(min-width:900px){.main_wrap section.post_single{padding:8px}}@media(max-width:899px){.main_wrap section.post_single{order:-1;margin-bottom:8px}}@media(max-width:559px){.main_wrap section.post_single{margin-left:-8px;margin-right:-8px}}.main_wrap section.post_single img{display:block;max-width:100%}.main_wrap section.comments{padding:10px}@media(min-width:900px){.main_wrap section.comments{margin-left:18rem}}.main_wrap section.comments>.comment_container{padding:0 10px;max-width:500px}.main_wrap section.comments>.comment_container article{overflow:hidden;margin-bottom:1em}.main_wrap section.comments>.comment_container h4{margin:0;margin-bottom:.5em}.main_wrap section.comments>.comment_container p,.main_wrap section.comments>.comment_container textarea{margin:0}.main_wrap section.comments>.comment_container p.deleted,.main_wrap section.comments>.comment_container textarea.deleted{color:red}.main_wrap section.comments>.comment_container .head{display:flex;justify-content:space-between}.main_wrap section.comments>.form>form{margin-left:10px;max-width:500px}.main_wrap section.comments>.form>form input:required{box-shadow:none}.main_wrap section.comments>.form>form textarea{width:100%;background:#444a;border:none;color:inherit;font:inherit}.main_wrap section.management_table table{margin:0 auto}.main_wrap section.management_table tr th{background-color:#606060}.main_wrap section.management_table tr:nth-child(even){background-color:#303030}.main_wrap section.management_table tr th,.main_wrap section.management_table tr td{padding:6px 10px}.main_wrap section.management_table tr:not(.edit) td>.edit{display:none}.main_wrap section.management_table tr.edit td>.show{display:none}.main_wrap section.management_table tr input[type=submit]{display:none}.main_wrap section.management_table tr .fa{padding:4px 4px;align-self:center;font-size:1.5em;cursor:pointer}.main_wrap form.editingable:not(.time-to-edit) .edit{display:none}.main_wrap form.editingable.time-to-edit .notedit{display:none}.main_wrap form.editingable input[type=text],.main_wrap form.editingable textarea{resize:vertical;width:100%}.main_wrap form.editingable input[type=text].edit,.edit .main_wrap form.editingable input[type=text],.main_wrap form.editingable textarea.edit,.edit .main_wrap form.editingable textarea{background:#444a;border:none;color:inherit;font:inherit}.main_wrap form input{margin:5px 0}.main_wrap .pagin{margin:10px 0;display:flex;flex-flow:row nowrap;justify-content:center}.main_wrap .pagin>a{display:block;background-color:#0005;padding:8px 12px;margin:0 2px}footer{padding:10px;text-align:center} \ No newline at end of file diff --git a/yadc/static/base.js b/yadc/static/base.js index 6b54980..e31d9dc 100644 --- a/yadc/static/base.js +++ b/yadc/static/base.js @@ -1,5 +1,5 @@ let nav_menu = document.querySelectorAll("#nav-menu, nav#main-nav > ._overlay") -let nav_menu_event = function(ev) { +function nav_menu_event(event) { let drop = document.getElementById("main-nav") let html = document.getElementsByTagName('html')[0] if (!drop.classList.contains("_drop")) { diff --git a/yadc/static/default.scss b/yadc/static/default.scss index af9b8c8..d85fbc5 100644 --- a/yadc/static/default.scss +++ b/yadc/static/default.scss @@ -264,6 +264,79 @@ header { font-size: 1.3em; } + form .tag_input, .tag_input form { + .tag_suggester { + width: calc(100% - 50px); + position: relative; + + // input[type=text] { + // width: 100%; + // } + + > .tag_suggest_dropdown { + display: flex; + flex-flow: column nowrap; + align-items: start; + + // width: 100%; + top: 100%; + left: 0; + position: absolute; + z-index: 10; + overflow: auto; + + background-color: #2d2d2de0; + } + } + .tag_container { + display: flex; + + > a { + margin: 2px 2px; + // padding: .4em .75em; + padding: .35em .6em; + + //text-align: center; + border-radius: 4px; + background-color: #121212ff; + + cursor: pointer; + > * { pointer-events: none; } + + > .fa-tag { + font-size: .9em; + margin-right: 2px; + } + + > .count { + // display: none; + font-size: .8em; + } + + &:not(:hover) { + > span.close { + display: none; + } + > span.plus { + display: none; + } + } + &:hover { + > span.count { + display: none; + } + } + + &.tagselected { + background-color: #400808ff; + } + &.tag_hide { + display: none; + } + } + } + } + // $side-panel-width: 14rem; $side-panel-width: 18rem; .important_subwrap { @@ -297,78 +370,6 @@ header { } article.tags { - .searchbox { - width: calc(#{$side-panel-width} - 50px); - position: relative; - - input[name=tagsearch] { - width: 100%; - } - - > .search_dropdown { - display: flex; - flex-flow: column nowrap; - align-items: start; - - // width: 100%; - top: 100%; - left: 0; - position: absolute; - z-index: 10; - overflow: auto; - - background-color: #2d2d2de0; - } - } - .tag_container, .search_dropdown { - > a { - margin: 2px 2px; - // padding: .4em .75em; - padding: .35em .6em; - - //text-align: center; - border-radius: 4px; - background-color: #121212ff; - - cursor: pointer; - > * { pointer-events: none; } - - > .fa-tag { - font-size: .9em; - margin-right: 2px; - } - - > .count { - // display: none; - font-size: .8em; - } - - &:not(:hover) { - > span.close { - display: none; - } - > span.plus { - display: none; - } - } - &:hover { - > span.count { - display: none; - } - } - - &.tagselected { - background-color: #400808ff; - } - &.tag_hide { - display: none; - } - } - } - - .tag_container { - display: flex; - } @include media($bp-tablet) { .tag_container { flex-flow: row wrap; diff --git a/yadc/static/management.js b/yadc/static/management.js index 634c12b..88481bc 100644 --- a/yadc/static/management.js +++ b/yadc/static/management.js @@ -1,6 +1,6 @@ let rows = document.querySelectorAll("section.management_table tbody > tr") -let show_edit_controls = function(ev) { - let row = ev.target.closest("tr") +function show_edit_controls(event) { + let row = event.target.closest("tr") console.log(row) if (!row.classList.contains("edit")) { row.classList.add("edit") diff --git a/yadc/static/search.js b/yadc/static/search.js index 08ea579..daaf998 100644 --- a/yadc/static/search.js +++ b/yadc/static/search.js @@ -1,14 +1,21 @@ -let tagroot = document.querySelector('article.tags') -let sel_tags = tagroot.querySelector('div.tag_container.tags_selected') -let page_tags = tagroot.querySelector('div.tag_container.tags_inpage') - -let searchroot = tagroot.querySelector('.searchbox') -searchroot.insertAdjacentHTML("beforeend", ``) -let search_input = searchroot.querySelector('input[name=tags][type=text]') -search_input.removeAttribute('name') -search_input.value = '' -let search_hidden = document.querySelector('input[name=tags][type=hidden]') -let search_dropdown = searchroot.querySelector('.search_dropdown') +let tagroot = document.querySelector('.tag_input') +let sel_tags = tagroot.querySelector('div.tags_selected') +let predef_tags = tagroot.querySelector('div.tags_inpage') // Should be optional + +let suggestroot = tagroot.querySelector('.tag_suggester') + +suggestroot.insertAdjacentHTML("beforeend", ``) +let suggest_hidden = suggestroot.querySelector(`input[name=${suggestroot.dataset.inputname}][type=hidden]`) + +let suggest_input = suggestroot.querySelector(`input[name=${suggestroot.dataset.inputname}][type=text]`) +suggest_input.removeAttribute('name') +if (suggest_input.hasAttribute('required')) { + suggest_input.removeAttribute('required') + suggest_hidden.setAttribute('required', '') +} +suggest_input.value = '' + +let tag_suggest_dropdown = suggestroot.querySelector('.tag_suggest_dropdown') // https://stackoverflow.com/questions/8486099/how-do-i-parse-a-url-query-parameters-in-javascript function getJsonFromUrl(url) { @@ -22,7 +29,7 @@ function getJsonFromUrl(url) { return result; } -function newseltag(tagname) { +function create_selection_tag(tagname) { let tag = document.createElement("a") tag.classList.add("tagselected") tag.dataset.tagname = tagname @@ -37,60 +44,65 @@ function newseltag(tagname) { return tag } -function tags_input_addtag(tagname) { - let val = search_hidden.value.split(' ') +function form_addtag(tagname) { + let val = suggest_hidden.value.split(' ') val.push(tagname) - search_hidden.value = val.join(' ').trim() - // console.log(search_hidden.value) + suggest_hidden.value = val.join(' ').trim() } -function tags_input_removetag(tagname) { - let val = search_hidden.value.split(' ') +function form_removetag(tagname) { + let val = suggest_hidden.value.split(' ') val.splice(val.indexOf(tagname), 1) - search_hidden.value = val.join(' ').trim() - // console.log(search_hidden.value) + suggest_hidden.value = val.join(' ').trim() } -function addseltag(tagname) { - // let pagetag = page_tags.querySelector("a.tag-"+tagname) - let pagetag = page_tags.querySelector(`a[data-tagname=${tagname}]`) - if (pagetag) { - pagetag.classList.add('tag_hide') +function add_selected(tagname) { + if (predef_tags) { + let pagetag = predef_tags.querySelector(`a[data-tagname=${tagname}]`) + if (pagetag) { + pagetag.classList.add('tag_hide') + } } - let newtag = newseltag(tagname) + let newtag = create_selection_tag(tagname) newtag.addEventListener('click', (event) => { - removeseltag(event.target.dataset.tagname) + remove_selected(event.target.dataset.tagname) // console.log(`Deselected: ${event.target.dataset.tagname}`) }) sel_tags.appendChild(newtag) - tags_input_addtag(tagname) + form_addtag(tagname) } -function removeseltag(tagname) { - let pagetag = page_tags.querySelector(`a[data-tagname=${tagname}]`) - if (pagetag) { - pagetag.classList.remove('tag_hide') +function remove_selected(tagname) { + if (predef_tags) { + let pagetag = predef_tags.querySelector(`a[data-tagname=${tagname}]`) + if (pagetag) { + pagetag.classList.remove('tag_hide') + } } sel_tags.querySelector(`a[data-tagname=${tagname}]`).remove() - tags_input_removetag(tagname) + form_removetag(tagname) } -page_tags.querySelectorAll("a").forEach(element => { - element.addEventListener('click', (event) => { - addseltag(event.target.dataset.tagname) - // console.log(`Selected: ${event.target.dataset.tagname}`) - event.preventDefault() + +// Page tags click to select +if (predef_tags) { + predef_tags.querySelectorAll("a").forEach(element => { + element.addEventListener('click', (event) => { + add_selected(event.target.dataset.tagname) + event.preventDefault() + }) }) -}) +} +// Generate selected by url query let query = getJsonFromUrl() if (query['tags']) { query['tags'].split('+').forEach((tag) => { - addseltag(tag) + add_selected(tag) }) } // Suggestions -function newsugtag(tagname) { +function create_suggestion_tag(tagname) { let tag = document.createElement("a") tag.classList.add("tagsuggestion") tag.dataset.tagname = tagname @@ -103,43 +115,50 @@ function newsugtag(tagname) { tag.querySelector("span.name").textContent = tagname.replace(/_/g, ' ') return tag } -function rendersuggestions(data) { - search_dropdown.innerHTML = '' - // search_dropdown.querySelectorAll('a').forEach((element) => { - // search_dropdown.replaceChild(newsugtag) - // }) +function render_suggestions(data) { + tag_suggest_dropdown.innerHTML = '' + let tagnames = Array.from(sel_tags.querySelectorAll('a')).map(a => a.dataset.tagname) + let i = 0 data.forEach((el) => { - let sugtag = newsugtag(el.content) + if (i > 5) return + if (tagnames.includes(el.content)) return + + let sugtag = create_suggestion_tag(el.content) sugtag.addEventListener('click', (event) => { - addseltag(event.target.dataset.tagname) - console.log(`Selected: ${event.target.dataset.tagname}`) + add_selected(event.target.dataset.tagname) + suggest_input.value = '' + render_suggestions([]) event.preventDefault() }) - search_dropdown.appendChild(sugtag) + tag_suggest_dropdown.appendChild(sugtag) + + i++ }); } -var search_timeout -search_input.addEventListener('input', (event) => { - clearTimeout(search_timeout) - let value = search_input.value.trim() +// Ajax suggestion handler +var ajax_timeout +suggest_input.addEventListener('input', (event) => { + clearTimeout(ajax_timeout) + + let value = suggest_input.value.trim() if (value.length < 2) { - rendersuggestions([]) + render_suggestions([]) return } - search_timeout = setTimeout(() => { + ajax_timeout = setTimeout(() => { fetch('/api/tags?q='+value).then((response) => { console.log(response) return response.json() }).then((data) => { // fill suggestions - console.log(data) - rendersuggestions(data) + // console.log(data) + render_suggestions(data) }) }, 500) }) @@ -159,8 +178,3 @@ search_input.addEventListener('input', (event) => { // console.log(event) // }) // page_tags.querySelectorAll('a').forEach((el) => el.removeAttribute('href')) - - -// console.log(page_tags) -// console.log(sel_tags) -// console.log(search_dropdown.children[0]) diff --git a/yadc/templates/_includes.html b/yadc/templates/_includes.html index 400bbf8..99ef5fc 100644 --- a/yadc/templates/_includes.html +++ b/yadc/templates/_includes.html @@ -64,4 +64,16 @@ {{ name }} {% endfor %} +{% endmacro %} + +{% macro render_tag_input(input_field) %} +
+
+ + {{ input_field() }} +
+
+ +
+
{% endmacro %} \ No newline at end of file diff --git a/yadc/templates/layout/base_sidebar_tags.html b/yadc/templates/layout/base_sidebar_tags.html index fc57a75..059b373 100644 --- a/yadc/templates/layout/base_sidebar_tags.html +++ b/yadc/templates/layout/base_sidebar_tags.html @@ -1,12 +1,12 @@ {% extends 'layout/base_sidebar.html' %} {% block sidebar %} -
+

Search

- diff --git a/yadc/templates/post/upload.html b/yadc/templates/post/upload.html index eddd0ae..319a38c 100644 --- a/yadc/templates/post/upload.html +++ b/yadc/templates/post/upload.html @@ -1,5 +1,6 @@ {% extends 'layout/base.html' %} {% from "_formhelpers.html" import errors %} +{% from "_includes.html" import render_tag_input %} {% block content %} @@ -10,11 +11,12 @@ {{ errors(form.post_img) }}
- {{ form.sauce(placeholder="Source URL") }} + {{ form.sauce() }} {{ errors(form.sauce) }}
- {{ form.tags(placeholder="Tags") }} + {{ render_tag_input(form.tags) }} + {{ errors(form.tags) }}
@@ -22,5 +24,7 @@ {{ errors(form.rating) }}
{{ form.submit() }}
+ +
{% endblock content %} \ No newline at end of file