diff --git a/.vscode/launch.json b/.vscode/launch.json index 3866bce..09ebc84 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -20,6 +20,24 @@ //"--no-reload" ], "jinja": true + }, + { + "name": "Python: Flask, Public", + "type": "python", + "request": "launch", + "module": "flask", + "env": { + "FLASK_APP": "yadc", + "FLASK_ENV": "development", + "FLASK_DEBUG": "1" + }, + "args": [ + "run", + "--host=0.0.0.0", + //"--no-debugger", + //"--no-reload" + ], + "jinja": true } ] } \ No newline at end of file diff --git a/yadc/__init__.py b/yadc/__init__.py index 2e04fce..22809c0 100644 --- a/yadc/__init__.py +++ b/yadc/__init__.py @@ -53,6 +53,8 @@ def create_app(): with app.app_context(): assets.append_path(os.path.join(app.root_path, 'assets')) + assets.append_path(os.path.join(app.root_path, 'assets/css')) + assets.append_path(os.path.join(app.root_path, 'assets/js')) # print(assets.load_path) #assets.url = app.static_url_path scss = AssetsBundle( @@ -61,7 +63,7 @@ def create_app(): assets.register('scss_all', scss) js = AssetsBundle( 'formswitchers.js', 'base.js', - 'search.js', + 'taginput.js', # filters='rjsmin', output='all.js') assets.register('js_all', js) diff --git a/yadc/assets/base-types.scss b/yadc/assets/css/base-types.scss similarity index 66% rename from yadc/assets/base-types.scss rename to yadc/assets/css/base-types.scss index e055597..7ab33f5 100644 --- a/yadc/assets/base-types.scss +++ b/yadc/assets/css/base-types.scss @@ -22,6 +22,8 @@ width: 250px; padding: 10px; + list-style-type: none; + &:not(:first-child) { margin-bottom: 10px; } @@ -41,16 +43,22 @@ } } +h2 { + margin: 0; + margin-bottom: .5em; + + // font-size: 1.3em; +} h3 { margin: 0; - margin-bottom: 1em; + margin-bottom: .5em; font-size: 1.3em; } - h4 { margin: 0; margin-bottom: .8em; + margin-top: .4em; } .comment-form { @@ -62,14 +70,14 @@ h4 { box-shadow: none; } - textarea { - width: 100%; + // textarea { + // width: 100%; - background: #444a; - border: none; - color: inherit; - font: inherit; - } + // background: #444a; + // border: none; + // color: inherit; + // font: inherit; + // } } .editingable { @@ -85,49 +93,140 @@ h4 { } } -input[type=text], textarea { +input[type=text], input[type=password], textarea { + background: #444a; + border: 1px solid #444; + color: inherit; + // font: inherit; + + display: block; + + padding: .5em; + margin: .3em 0; +} + +input[type=text], input[type=password] { + width: 100%; + // max-width: 25em; +} + +textarea { resize: vertical; width: 100%; +} + +input[type=submit] { + background: #444a; + border: 2px solid #666a; + border-radius: 4px; - &.edit, .edit & { - background: #444a; - border: none; - color: inherit; - font: inherit; + &:active { + background: #000a; + border: 2px solid #444a; + } + + color: inherit; + + + padding: .4em 1.8em; +} + +label { + padding: .4em; + // width: 100%; // DOESN'T WORK? +} + +.baseform, .pageform { + input[type=text], input[type=password], textarea { + width: 100%; + } + + input[type=checkbox] { + margin: .5em; + } + + input[type=submit] { + margin: .2em 0; + } + + form > input, form > div { + margin: .8em 0; + } + + div.row { + padding: .2em; + + display: flex; + align-items: center; + &.stretch { + justify-content: space-between; + } + } + ul { + padding: 0; + + margin: 0; + li { + list-style-type: none; + } } - } +.pageform { + // border: 1px solid white; + // padding: 1.5em; + padding: 1em; -form .tag_input, .tag_input form { + width: 300px; + margin: 0 auto; +} + + +form .tag-input, .tag-input form { .tag-suggester { - width: calc(100% - 50px); + // width: calc(100% - 50px); + width: 100%; position: relative; // input[type=text] { // width: 100%; // } - > .tag_suggest_dropdown { + > .suggest-dropdown { display: flex; - flex-flow: column nowrap; + + // flex-flow: column nowrap; + align-items: start; - // width: 100%; + width: 100%; top: 100%; - left: 0; + // left: 0; position: absolute; z-index: 10; overflow: auto; background-color: #2d2d2de0; + + &:not(:empty) { + padding: .2em; + } } } .tag-container { display: flex; + flex-flow: row wrap; + + // &:not(:empty) { + // padding: .2em; + // } + &:empty { + display: none; + } > a { - margin: 2px 2px; + margin: .2em; + // margin: 2px 2px; // padding: .4em .75em; padding: .35em .6em; @@ -172,7 +271,7 @@ form .tag_input, .tag_input form { } } -form { +// form { // margin: 0 auto; // width: 300px; //text-align: center; @@ -211,13 +310,13 @@ form { // width: unset; // } - input { - margin: 5px 0; +// input { +// margin: 5px 0; //font-size: 1em; - &:not([type=checkbox]):not([type=submit]):not([type=radio]):not([type=file]) { +// &:not([type=checkbox]):not([type=submit]):not([type=radio]):not([type=file]) { // width: 100%; - } +// } // &[type=file] { // //display: none; @@ -245,7 +344,7 @@ form { // width: unset; // margin: .2rem; // } - } +// } // select { // @extend .fb-select; // -moz-appearance: none; @@ -253,4 +352,4 @@ form { // margin: 0; // // width: 100%; // } -} \ No newline at end of file +//} \ No newline at end of file diff --git a/yadc/assets/default.scss b/yadc/assets/css/default.scss similarity index 87% rename from yadc/assets/default.scss rename to yadc/assets/css/default.scss index 7be8c9d..2b14a5b 100644 --- a/yadc/assets/default.scss +++ b/yadc/assets/css/default.scss @@ -1,18 +1,12 @@ .main-wrap { - $bp-desktop: ">=desktop"; - $bp-tablet: "=desktop"; +$bp-tablet: " + + + `) + tag.querySelector("span.name").textContent = tagname.replace(/_/g, ' ') + // tag.querySelector("input[type=hidden]").setAttribute('name', `tag#${tagname}`) + return tag +} + +// Suggestions +function create_suggestion_tag(tagname) { // CLEAR + let tag = document.createElement("a") + tag.classList.add("tagsuggestion") + tag.dataset.tagname = tagname + + tag.insertAdjacentHTML("beforeend", ` + + + + `) + tag.querySelector("span.name").textContent = tagname.replace(/_/g, ' ') + return tag +} + +let taginputs = document.querySelectorAll('.tag-input') +taginputs.forEach(function (tinput) { + 'use strict' + + try { + let selected = tinput.querySelector('.tags-selected') + let predef = tinput.querySelector('.tags-inpage') + + let suggestroot = tinput.querySelector('.tag-suggester') + + suggestroot.insertAdjacentHTML("beforeend", ``) + let hidden_input = 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') + hidden_input.setAttribute('required', '') + } + suggest_input.removeAttribute('value') // Disable prefill by browser + + let suggest_dropdown = suggestroot.querySelector('.suggest-dropdown') + + + function hidden_addtag(tagname) { // 1 reference + let hid_input = hidden_input + + let val = hid_input.value.split(' ') + val.push(tagname) + hid_input.value = val.join(' ').trim() + } + function hidden_removetag(tagname) { // 1 reference + let hid_input = hidden_input + + let val = hid_input.value.split(' ') + val.splice(val.indexOf(tagname), 1) + hid_input.value = val.join(' ').trim() + } + + function add_selected(tagname) { // 2 references + let predf = predef + let sel = selected + + if (predf) { + let pagetag = predf.querySelector(`a[data-tagname=${tagname}]`) + if (pagetag) { + pagetag.classList.add('tag_hide') + } + } + + let newtag = create_selection_tag(tagname) + newtag.addEventListener('click', (event) => { + remove_selected(event.target.dataset.tagname) + // console.log(`Deselected: ${event.target.dataset.tagname}`) + }) + + sel.appendChild(newtag) + hidden_addtag(tagname) + } + function remove_selected(tagname) { // 2 references + let predf = predef + let sel = selected + + if (predf) { + let pagetag = predf.querySelector(`a[data-tagname=${tagname}]`) + if (pagetag) { + pagetag.classList.remove('tag_hide') + } + } + + sel.querySelector(`a[data-tagname=${tagname}]`).remove() + hidden_removetag(tagname) + } + + + // Page tags click to select + if (predef) { + predef.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) => { + add_selected(tag) + }) + } + + function render_suggestions(data) { // 3 references + let drop = suggest_dropdown + let sel = selected + let sug_input = suggest_input + + drop.innerHTML = '' + + let tagnames = Array.from(sel.querySelectorAll('a')).map(a => a.dataset.tagname) + let i = 0 + data.forEach((el) => { + if (i > 5) return + if (tagnames.includes(el.content)) return + + let sugtag = create_suggestion_tag(el.content) + + sugtag.addEventListener('click', (event) => { + add_selected(event.target.dataset.tagname) + sug_input.value = '' + render_suggestions([]) + event.preventDefault() + }) + + drop.appendChild(sugtag) + + i++ + }); + } + + // Ajax suggestion handler + var ajax_timeout + suggest_input.addEventListener('input', (event) => { + clearTimeout(ajax_timeout) + + let value = suggest_input.value.replace(/ /g, '_').trim() + + if (value.length < 2) { + render_suggestions([]) + return + } + + ajax_timeout = setTimeout(() => { + fetch('/post/tags?q='+value).then((response) => { + console.log(response) + return response.json() + }).then((data) => { + // fill suggestions + // console.log(data) + render_suggestions(data) + }) + }, 500) + }) + + // search_input.addEventListener('keypress', (event) => { + // if (event.keyCode == 13) { + // // event.preventDefault() + // } + // }) + // search_input.addEventListener('blur', (event) => { + // if (event.explicitOriginalTarget != null) { + // classlist = event.explicitOriginalTarget.parentNode.classList + // if (classlist.contains('tags_selected') || classlist.contains('tags_inpage') || classlist.contains('search_dropdown')) { + // setTimeout(() => search_input.focus(), 2) + // } + // } + // console.log(event) + // }) + // page_tags.querySelectorAll('a').forEach((el) => el.removeAttribute('href')) + + } catch (error) { + console.log(error) + } +}) + + + + diff --git a/yadc/bp/auth.py b/yadc/bp/auth.py index 9c1fd6d..c8e8639 100644 --- a/yadc/bp/auth.py +++ b/yadc/bp/auth.py @@ -34,6 +34,7 @@ def logout(): if fl.current_user.is_authenticated: fl.current_user.logout() + flash('Successfully logged out.') return redirect(nextpage()) @bp.route('/reset_password', methods=['GET', 'POST']) diff --git a/yadc/static/all.css b/yadc/static/all.css index 5c808b8..cd4180a 100644 --- a/yadc/static/all.css +++ b/yadc/static/all.css @@ -1 +1 @@ -.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}}h3{margin:0;margin-bottom:1em;font-size:1.3em}h4{margin:0;margin-bottom:.8em}.comment-form{margin-left:10px;max-width:500px}.comment-form input:required{box-shadow:none}.comment-form textarea{width:100%;background:#444a;border:none;color:inherit;font:inherit}.editingable:not(.time-to-edit) .edit{display:none}.editingable.time-to-edit .notedit{display:none}input[type=text],textarea{resize:vertical;width:100%}input[type=text].edit,.edit input[type=text],textarea.edit,.edit textarea{background:#444a;border:none;color:inherit;font:inherit}form .tag_input .tag-suggester,.tag_input form .tag-suggester{width:calc(100% - 50px);position:relative}form .tag_input .tag-suggester>.tag_suggest_dropdown,.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}form .tag_input .tag-container,.tag_input form .tag-container{display:flex}form .tag_input .tag-container>a,.tag_input form .tag-container>a{margin:2px 2px;padding:.35em .6em;border-radius:4px;background-color:#121212ff;cursor:pointer}form .tag_input .tag-container>a>*,.tag_input form .tag-container>a>*{pointer-events:none}form .tag_input .tag-container>a>.fa-tag,.tag_input form .tag-container>a>.fa-tag{font-size:.9em;margin-right:2px}form .tag_input .tag-container>a>.count,.tag_input form .tag-container>a>.count{font-size:.8em}form .tag_input .tag-container>a:not(:hover)>span.close,.tag_input form .tag-container>a:not(:hover)>span.close{display:none}form .tag_input .tag-container>a:not(:hover)>span.plus,.tag_input form .tag-container>a:not(:hover)>span.plus{display:none}form .tag_input .tag-container>a:hover>span.count,.tag_input form .tag-container>a:hover>span.count{display:none}form .tag_input .tag-container>a.tagselected,.tag_input form .tag-container>a.tagselected{background-color:#400808ff}form .tag_input .tag-container>a.tag_hide,.tag_input form .tag-container>a.tag_hide{display:none}form input{margin:5px 0}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}}.main-wrap{margin:0 auto;max-width:1300px;padding:8px;padding-top:0;padding-bottom:0}.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.sidepanel{flex-shrink:0;padding:10px}@media(min-width:900px){.main-wrap .important-subwrap>section.sidepanel{width:18rem;height:0}}.main-wrap .important-subwrap>section.sidepanel article{margin-bottom:10px}@media(max-width:899px){.main-wrap .important-subwrap>section.sidepanel article.tags .tag-container{flex-flow:row wrap}}@media(min-width:900px){.main-wrap .important-subwrap>section.sidepanel article.tags .tag-container{flex-flow:column nowrap;align-items:start}}.main-wrap .important-subwrap>section.sidepanel article.post-desc{display:flex;flex-flow:column nowrap;font-size:.9em}.main-wrap .important-subwrap>section.sidepanel article.post-desc>img{display:block;max-width:128px}@media(min-width:900px){.main-wrap .important-subwrap>section:not(.sidepanel){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.comment{overflow:hidden;margin-bottom:1em}.main-wrap section.comments>.comment-container article.comment p,.main-wrap section.comments>.comment-container article.comment textarea{margin:0}.main-wrap section.comments>.comment-container article.comment p.deleted,.main-wrap section.comments>.comment-container article.comment textarea.deleted{color:red}.main-wrap section.comments>.comment-container article.comment .comment-head{display:flex;justify-content:space-between}.main-wrap section.management-table table{margin:0 auto}.main-wrap section.management-table tr{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 th{background-color:#606060}.main-wrap section.management-table tr label>input{display:none}.main-wrap section.management-table tr .fa{padding:4px 4px;align-self:center;font-size:1.5em;cursor:pointer}.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}*{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} \ No newline at end of file +.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;list-style-type:none;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}}h2{margin:0;margin-bottom:.5em}h3{margin:0;margin-bottom:.5em;font-size:1.3em}h4{margin:0;margin-bottom:.8em;margin-top:.4em}.comment-form{margin-left:10px;max-width:500px}.comment-form input:required{box-shadow:none}.comment-form textarea{width:100%;background:#444a;border:none;color:inherit;font:inherit}.editingable:not(.time-to-edit) .edit{display:none}.editingable.time-to-edit .notedit{display:none}textarea{resize:vertical;width:100%}input[type=text],input[type=password],textarea{background:#444a;border:1px solid #444;color:inherit;display:block;padding:.5em;margin:.3em 0}input[type=text],input[type=password]{width:100%}input[type=submit]{background:#444a;border:2px solid #666a;border-radius:4px;color:inherit;padding:.4em 1.8em}input[type=submit]:active{background:#000a;border:2px solid #444a}label{padding:.4em}.baseform input[type=text],.baseform input[type=password],.baseform textarea,.pageform input[type=text],.pageform input[type=password],.pageform textarea{width:100%}.baseform input[type=checkbox],.pageform input[type=checkbox]{margin:.5em}.baseform input[type=submit],.pageform input[type=submit]{margin:.2em 0}.baseform form>input,.baseform form>div,.pageform form>input,.pageform form>div{margin:.8em 0}.baseform div.row,.pageform div.row{padding:.2em;display:flex;align-items:center}.baseform div.row.stretch,.pageform div.row.stretch{justify-content:space-between}.baseform ul,.pageform ul{padding:0;margin:0}.baseform ul li,.pageform ul li{list-style-type:none}.pageform{padding:1em;width:300px;margin:0 auto}form .tag-input .tag-suggester,.tag-input form .tag-suggester{width:100%;position:relative}form .tag-input .tag-suggester>.suggest-dropdown,.tag-input form .tag-suggester>.suggest-dropdown{display:flex;align-items:start;width:100%;top:100%;position:absolute;z-index:10;overflow:auto;background-color:#2d2d2de0}form .tag-input .tag-suggester>.suggest-dropdown:not(:empty),.tag-input form .tag-suggester>.suggest-dropdown:not(:empty){padding:.2em}form .tag-input .tag-container,.tag-input form .tag-container{display:flex;flex-flow:row wrap}form .tag-input .tag-container:empty,.tag-input form .tag-container:empty{display:none}form .tag-input .tag-container>a,.tag-input form .tag-container>a{margin:.2em;padding:.35em .6em;border-radius:4px;background-color:#121212ff;cursor:pointer}form .tag-input .tag-container>a>*,.tag-input form .tag-container>a>*{pointer-events:none}form .tag-input .tag-container>a>.fa-tag,.tag-input form .tag-container>a>.fa-tag{font-size:.9em;margin-right:2px}form .tag-input .tag-container>a>.count,.tag-input form .tag-container>a>.count{font-size:.8em}form .tag-input .tag-container>a:not(:hover)>span.close,.tag-input form .tag-container>a:not(:hover)>span.close{display:none}form .tag-input .tag-container>a:not(:hover)>span.plus,.tag-input form .tag-container>a:not(:hover)>span.plus{display:none}form .tag-input .tag-container>a:hover>span.count,.tag-input form .tag-container>a:hover>span.count{display:none}form .tag-input .tag-container>a.tagselected,.tag-input form .tag-container>a.tagselected{background-color:#400808ff}form .tag-input .tag-container>a.tag_hide,.tag-input form .tag-container>a.tag_hide{display: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}}.main-wrap{margin:0 auto;max-width:1300px;padding:8px;padding-top:0;padding-bottom:0}.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.sidepanel{flex-shrink:0;padding:10px}@media(min-width:900px){.main-wrap .important-subwrap>section.sidepanel{width:18rem;height:0}}.main-wrap .important-subwrap>section.sidepanel article:not(:last-child){margin-bottom:10px}@media(max-width:899px){.main-wrap .important-subwrap>section.sidepanel article.tags .tag-container,.main-wrap .important-subwrap>section.sidepanel article.post-edit .tag-container{flex-flow:row wrap}}@media(min-width:900px){.main-wrap .important-subwrap>section.sidepanel article.tags .tag-container,.main-wrap .important-subwrap>section.sidepanel article.post-edit .tag-container{flex-flow:column nowrap;align-items:start}.main-wrap .important-subwrap>section.sidepanel article.tags .suggest-dropdown,.main-wrap .important-subwrap>section.sidepanel article.post-edit .suggest-dropdown{flex-flow:row wrap}.main-wrap .important-subwrap>section.sidepanel article.tags .suggest-dropdown a,.main-wrap .important-subwrap>section.sidepanel article.post-edit .suggest-dropdown a{width:100%}}.main-wrap .important-subwrap>section.sidepanel article.rating ul{padding:0}.main-wrap .important-subwrap>section.sidepanel article.rating ul li{list-style-type:none}.main-wrap .important-subwrap>section.sidepanel article.post-desc{display:flex;flex-flow:column nowrap;font-size:.9em}.main-wrap .important-subwrap>section.sidepanel article.post-desc>img{display:block;max-width:128px}@media(min-width:900px){.main-wrap .important-subwrap>section:not(.sidepanel){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.comment{overflow:hidden;margin-bottom:1em}.main-wrap section.comments>.comment-container article.comment p,.main-wrap section.comments>.comment-container article.comment textarea{margin:0}.main-wrap section.comments>.comment-container article.comment p.deleted,.main-wrap section.comments>.comment-container article.comment textarea.deleted{color:red}.main-wrap section.comments>.comment-container article.comment .comment-head{display:flex;justify-content:space-between}.main-wrap section.management-table table{margin:0 auto}.main-wrap section.management-table tr{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 th{background-color:#606060}.main-wrap section.management-table tr label>input{display:none}.main-wrap section.management-table tr .fa{padding:4px 4px;align-self:center;font-size:1.5em;cursor:pointer}@media(min-width:900px){.main-wrap section.manage-profile{margin-right:18rem}}.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}*{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} \ No newline at end of file diff --git a/yadc/static/all.js b/yadc/static/all.js index 2999d80..6f18d52 100644 --- a/yadc/static/all.js +++ b/yadc/static/all.js @@ -55,26 +55,6 @@ document.getElementById("user-menu").addEventListener('click', (ev) => { drop.classList.remove("_drop") } }) -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 = '' -suggest_input.removeAttribute('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) { if(!url) url = location.search; @@ -87,7 +67,7 @@ function getJsonFromUrl(url) { return result; } -function create_selection_tag(tagname) { +function create_selection_tag(tagname) { // CLEAR let tag = document.createElement("a") tag.classList.add("tagselected") tag.dataset.tagname = tagname @@ -102,65 +82,8 @@ function create_selection_tag(tagname) { return tag } -function form_addtag(tagname) { - let val = suggest_hidden.value.split(' ') - val.push(tagname) - suggest_hidden.value = val.join(' ').trim() -} -function form_removetag(tagname) { - let val = suggest_hidden.value.split(' ') - val.splice(val.indexOf(tagname), 1) - suggest_hidden.value = val.join(' ').trim() -} - -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 = create_selection_tag(tagname) - newtag.addEventListener('click', (event) => { - remove_selected(event.target.dataset.tagname) - // console.log(`Deselected: ${event.target.dataset.tagname}`) - }) - - sel_tags.appendChild(newtag) - form_addtag(tagname) -} -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() - form_removetag(tagname) -} - -// 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) => { - add_selected(tag) - }) -} - // Suggestions -function create_suggestion_tag(tagname) { +function create_suggestion_tag(tagname) { // CLEAR let tag = document.createElement("a") tag.classList.add("tagsuggestion") tag.dataset.tagname = tagname @@ -173,66 +96,173 @@ function create_suggestion_tag(tagname) { tag.querySelector("span.name").textContent = tagname.replace(/_/g, ' ') return tag } -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) => { - if (i > 5) return - if (tagnames.includes(el.content)) return - - let sugtag = create_suggestion_tag(el.content) - - sugtag.addEventListener('click', (event) => { - add_selected(event.target.dataset.tagname) - suggest_input.value = '' - render_suggestions([]) - event.preventDefault() - }) - tag_suggest_dropdown.appendChild(sugtag) +let taginputs = document.querySelectorAll('.tag-input') +taginputs.forEach(function (tinput) { + 'use strict' - i++ - }); -} + try { + let selected = tinput.querySelector('.tags-selected') + let predef = tinput.querySelector('.tags-inpage') -// Ajax suggestion handler -var ajax_timeout -suggest_input.addEventListener('input', (event) => { - clearTimeout(ajax_timeout) + let suggestroot = tinput.querySelector('.tag-suggester') - let value = suggest_input.value.replace(/ /g, '_').trim() + suggestroot.insertAdjacentHTML("beforeend", ``) + let hidden_input = suggestroot.querySelector(`input[name=${suggestroot.dataset.inputname}][type=hidden]`) - if (value.length < 2) { - render_suggestions([]) - return - } + 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') + hidden_input.setAttribute('required', '') + } + suggest_input.removeAttribute('value') // Disable prefill by browser + + let suggest_dropdown = suggestroot.querySelector('.suggest-dropdown') + + + function hidden_addtag(tagname) { // 1 reference + let hid_input = hidden_input + + let val = hid_input.value.split(' ') + val.push(tagname) + hid_input.value = val.join(' ').trim() + } + function hidden_removetag(tagname) { // 1 reference + let hid_input = hidden_input - ajax_timeout = setTimeout(() => { - fetch('/post/tags?q='+value).then((response) => { - console.log(response) - return response.json() - }).then((data) => { - // fill suggestions - // console.log(data) - render_suggestions(data) + let val = hid_input.value.split(' ') + val.splice(val.indexOf(tagname), 1) + hid_input.value = val.join(' ').trim() + } + + function add_selected(tagname) { // 2 references + let predf = predef + let sel = selected + + if (predf) { + let pagetag = predf.querySelector(`a[data-tagname=${tagname}]`) + if (pagetag) { + pagetag.classList.add('tag_hide') + } + } + + let newtag = create_selection_tag(tagname) + newtag.addEventListener('click', (event) => { + remove_selected(event.target.dataset.tagname) + // console.log(`Deselected: ${event.target.dataset.tagname}`) + }) + + sel.appendChild(newtag) + hidden_addtag(tagname) + } + function remove_selected(tagname) { // 2 references + let predf = predef + let sel = selected + + if (predf) { + let pagetag = predf.querySelector(`a[data-tagname=${tagname}]`) + if (pagetag) { + pagetag.classList.remove('tag_hide') + } + } + + sel.querySelector(`a[data-tagname=${tagname}]`).remove() + hidden_removetag(tagname) + } + + + // Page tags click to select + if (predef) { + predef.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) => { + add_selected(tag) + }) + } + + function render_suggestions(data) { // 3 references + let drop = suggest_dropdown + let sel = selected + let sug_input = suggest_input + + drop.innerHTML = '' + + let tagnames = Array.from(sel.querySelectorAll('a')).map(a => a.dataset.tagname) + let i = 0 + data.forEach((el) => { + if (i > 5) return + if (tagnames.includes(el.content)) return + + let sugtag = create_suggestion_tag(el.content) + + sugtag.addEventListener('click', (event) => { + add_selected(event.target.dataset.tagname) + sug_input.value = '' + render_suggestions([]) + event.preventDefault() + }) + + drop.appendChild(sugtag) + + i++ + }); + } + + // Ajax suggestion handler + var ajax_timeout + suggest_input.addEventListener('input', (event) => { + clearTimeout(ajax_timeout) + + let value = suggest_input.value.replace(/ /g, '_').trim() + + if (value.length < 2) { + render_suggestions([]) + return + } + + ajax_timeout = setTimeout(() => { + fetch('/post/tags?q='+value).then((response) => { + console.log(response) + return response.json() + }).then((data) => { + // fill suggestions + // console.log(data) + render_suggestions(data) + }) + }, 500) }) - }, 500) + + // search_input.addEventListener('keypress', (event) => { + // if (event.keyCode == 13) { + // // event.preventDefault() + // } + // }) + // search_input.addEventListener('blur', (event) => { + // if (event.explicitOriginalTarget != null) { + // classlist = event.explicitOriginalTarget.parentNode.classList + // if (classlist.contains('tags_selected') || classlist.contains('tags_inpage') || classlist.contains('search_dropdown')) { + // setTimeout(() => search_input.focus(), 2) + // } + // } + // console.log(event) + // }) + // page_tags.querySelectorAll('a').forEach((el) => el.removeAttribute('href')) + + } catch (error) { + console.log(error) + } }) -// search_input.addEventListener('keypress', (event) => { -// if (event.keyCode == 13) { -// // event.preventDefault() -// } -// }) -// search_input.addEventListener('blur', (event) => { -// if (event.explicitOriginalTarget != null) { -// classlist = event.explicitOriginalTarget.parentNode.classList -// if (classlist.contains('tags_selected') || classlist.contains('tags_inpage') || classlist.contains('search_dropdown')) { -// setTimeout(() => search_input.focus(), 2) -// } -// } -// console.log(event) -// }) -// page_tags.querySelectorAll('a').forEach((el) => el.removeAttribute('href')) + + + diff --git a/yadc/templates/_includes.html b/yadc/templates/_includes.html index ac8434e..978dff9 100644 --- a/yadc/templates/_includes.html +++ b/yadc/templates/_includes.html @@ -70,14 +70,14 @@ {% endmacro %} {% macro render_tag_input(input_field) %} -
-
- +
+
+ {##} {{ input_field() }} -
+
-
+
{% endmacro %} diff --git a/yadc/templates/auth/login.html b/yadc/templates/auth/login.html index f9c7eff..092d3a8 100644 --- a/yadc/templates/auth/login.html +++ b/yadc/templates/auth/login.html @@ -2,25 +2,26 @@ {% from "_formhelpers.html" import errors %} {% block content %} -
+

Log In

- {{ form.csrf_token }} -
+ + {{ form.csrf_token }} + {{ form.username(placeholder="Username") }} {{ errors(form.username) }} -
-
+ {{ form.password(placeholder="Password") }} {{ errors(form.password) }} -
-
- {{ form.remember_me() }} {{ form.remember_me.label }} - {{ errors(form.remember_me) }} -
-
- {{ form.submit() }} - Forgotten password? -
- - + +
+ {{ form.remember_me() }} {{ form.remember_me.label }} + {{ errors(form.remember_me) }} +
+
+ {{ form.submit() }} + Forgotten password? +
+ + +
{% endblock content %} \ No newline at end of file diff --git a/yadc/templates/auth/register.html b/yadc/templates/auth/register.html index 3cbf922..94fc9ca 100644 --- a/yadc/templates/auth/register.html +++ b/yadc/templates/auth/register.html @@ -2,28 +2,27 @@ {% from "_formhelpers.html" import errors %} {% block content %} -
+

Sign Up

- {{ form.csrf_token }} -
+ + {{ form.csrf_token }} + {{ form.username(placeholder="Username") }} {{ errors(form.username) }} -
-
+ {{ form.email(placeholder="Email address") }} {{ errors(form.email) }} -
-
+ {{ form.password(placeholder="Password") }} {{ errors(form.password) }} -
-
+ {{ form.password_again(placeholder="Repeat password") }} {{ errors(form.password_again) }} -
-
- {{ form.submit() }} - Already registered? -
- + +
+ {{ form.submit() }} + Already registered? +
+ +
{% endblock content %} \ No newline at end of file diff --git a/yadc/templates/auth/reset_password.html b/yadc/templates/auth/reset_password.html index d54e86b..49d661a 100644 --- a/yadc/templates/auth/reset_password.html +++ b/yadc/templates/auth/reset_password.html @@ -2,18 +2,16 @@ {% from "_formhelpers.html" import errors %} {% block content %} -
+

Reset password

-

- Please insert your email address and we will send you a request for password reset. -

- {{ form.csrf_token }} -
+ +

Please insert your email address and we will send you a request for password reset.

+ {{ form.csrf_token }} + {{ form.email(placeholder="Your email address") }} {{ errors(form.email) }} -
-
+ {{ form.submit() }} -
- + +
{% endblock content %} \ 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 7fb5298..3bda2de 100644 --- a/yadc/templates/layout/base_sidebar_tags.html +++ b/yadc/templates/layout/base_sidebar_tags.html @@ -3,13 +3,15 @@ {% block sidebar %}

Rating

-
- {% for rating in ('safe', 'questionable', 'explicit') %} - - -
- {% endfor %} -
+
+
    + {% for rating in ('safe', 'questionable', 'explicit') %} +
  • + +
  • + {% endfor %} +
+

Search

@@ -17,7 +19,7 @@
-
+
@@ -36,7 +38,6 @@
- {% endblock %} diff --git a/yadc/templates/post/post.html b/yadc/templates/post/post.html index 77b80aa..739ba97 100644 --- a/yadc/templates/post/post.html +++ b/yadc/templates/post/post.html @@ -1,5 +1,5 @@ {% extends 'layout/base_sidebar_tags.html' %} -{% from '_includes.html' import render_post_edit, render_tag_input with context %} +{% from '_includes.html' import render_tag_input %} {% from "_formhelpers.html" import errors %} {% block sidebar %} @@ -33,17 +33,17 @@ {% if post.can_edit %}

Edit

-
+
{{ editform.csrf_token }} {{ editform.id() }} - {{ render_tag_input(editform.tags) }} - {{ errors(editform.tags) }} - {{ editform.source }} {{ errors(editform.source) }} + {{ render_tag_input(editform.tags) }} + {{ errors(editform.tags) }} + {{ editform.edit() }}
diff --git a/yadc/templates/post/upload.html b/yadc/templates/post/upload.html index 319a38c..61d6ca8 100644 --- a/yadc/templates/post/upload.html +++ b/yadc/templates/post/upload.html @@ -3,28 +3,36 @@ {% from "_includes.html" import render_tag_input %} {% block content %} -
+

Upload post

- {{ form.csrf_token }} -
- {{ form.post_img.label }} {{ form.post_img() }} + + {{ form.csrf_token }} +
+ {#{{ form.post_img.label }}#} + {{ form.post_img() }} +
{{ errors(form.post_img) }} -
-
+ {{ form.sauce() }} {{ errors(form.sauce) }} -
-
+ {{ render_tag_input(form.tags) }} {{ errors(form.tags) }} -
-
- {{ form.rating.label }} {% for r in form.rating %}
{{ r() }} {{ r.label }}{% endfor %} + +
+ {{ form.rating.label }} +
    + {% for r in form.rating %} +
  • + {{ r() }}{{ r.label }} +
  • + {% endfor %} +
+
{{ errors(form.rating) }} -
-
{{ form.submit() }}
- - + {{ form.submit() }} + +
{% endblock content %} \ No newline at end of file diff --git a/yadc/templates/user/settings.html b/yadc/templates/user/settings.html index 8d74db3..ba61d01 100644 --- a/yadc/templates/user/settings.html +++ b/yadc/templates/user/settings.html @@ -2,77 +2,75 @@ {% from "_formhelpers.html" import errors %} {% block main_content %} -
-
+
+

Change user info

- {{ userinfo_form.csrf_token }} -
- {{ userinfo_form.bio() }} + + {{ userinfo_form.csrf_token }} + + {{ userinfo_form.bio(placeholder="Enter your description") }} {{ errors(userinfo_form.bio) }} -
-
+ {{ userinfo_form.userinfo_submit() }} -
- -
+
+
+

Change password

- {{ pass_form.csrf_token }} -
+
+ {{ pass_form.csrf_token }} + {{ pass_form.password_current(placeholder="Current password") }} {{ errors(pass_form.password_current) }} -
-
+ {{ pass_form.password(placeholder="Password") }} {{ errors(pass_form.password) }} -
-
+ {{ pass_form.password_again(placeholder="Repeat password") }} {{ errors(pass_form.password_again) }} -
-
+ {{ pass_form.pass_submit() }} -
- -
+
+
+

Change e-mail address

- {{ mail_form.csrf_token }} -
+
+ {{ mail_form.csrf_token }} + {{ mail_form.email() }} {{ errors(mail_form.email) }} -
-
+ {{ mail_form.email_again() }} {{ errors(mail_form.email_again) }} -
-
+ {{ mail_form.mail_submit() }} -
- -
+
+
+

Preferred rating

- {{ rating_form.csrf_token }} -
+
+ {{ rating_form.csrf_token }} + {{ rating_form.rating() }} {{ errors(rating_form.rating) }} -
-
- {{ rating_form.rating_submit() }} -
- -
+ + +
+
+

Delete user data

- {{ delete_form.csrf_token }} -
+
+ {{ delete_form.csrf_token }} + {{ delete_form.all_comments() }}{{ delete_form.all_comments.label }} {{ errors(delete_form.all_posts) }} -
-
- {{ delete_form.all_posts() }}{{ delete_form.all_posts.label }} - {{ errors(delete_form.all_posts) }} -
-
+ +
+ {{ delete_form.all_posts() }}{{ delete_form.all_posts.label }} + {{ errors(delete_form.all_posts) }} +
+ {{ delete_form.delete_submit() }} -
- + +
{% endblock %} \ No newline at end of file