@ -1,25 +1,49 @@ |
|||||
[tool.black] |
[tool.ruff] |
||||
line-length = 79 |
line-length = 79 |
||||
target-version = ['py311'] |
target-version = "py311" |
||||
include = '\.pyi?$' |
#include = '\.pyi?$' |
||||
exclude = ''' |
exclude = [ |
||||
/( |
".bzr", |
||||
\.eggs |
".direnv", |
||||
| \.git |
".eggs", |
||||
| \.hg |
".git", |
||||
| \.mypy_cache |
".git-rewrite", |
||||
| \.tox |
".hg", |
||||
| \.venv |
".ipynb_checkpoints", |
||||
| _build |
".mypy_cache", |
||||
| buck-out |
".nox", |
||||
| build |
".pants.d", |
||||
| dist |
".pyenv", |
||||
|
".pytest_cache", |
||||
# The following are specific to Black, you probably don't want those. |
".pytype", |
||||
| blib2to3 |
".ruff_cache", |
||||
| tests/data |
".svn", |
||||
| profiling |
".tox", |
||||
)/ |
".venv", |
||||
''' |
".vscode", |
||||
|
"__pypackages__", |
||||
|
"_build", |
||||
|
"buck-out", |
||||
|
"build", |
||||
|
"dist", |
||||
|
"node_modules", |
||||
|
"site-packages", |
||||
|
"venv", |
||||
|
] |
||||
|
|
||||
|
[tool.ruff.lint] |
||||
|
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. |
||||
|
select = ["E4", "E7", "E9", "F"] |
||||
|
ignore = [] |
||||
|
# Allow fix for all enabled rules (when `--fix`) is provided. |
||||
|
fixable = ["ALL"] |
||||
|
unfixable = [] |
||||
|
# Allow unused variables when underscore-prefixed. |
||||
|
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" |
||||
|
|
||||
|
[tool.ruff.format] |
||||
|
quote-style = "double" |
||||
|
indent-style = "space" |
||||
|
docstring-code-format = true |
||||
|
line-ending = "auto" |
||||
|
skip-magic-trailing-comma = false |
||||
|
@ -1,3 +0,0 @@ |
|||||
* |
|
||||
*/ |
|
||||
!.gitignore |
|
@ -0,0 +1,9 @@ |
|||||
|
from flask_login import current_user |
||||
|
from models.user_model import User |
||||
|
|
||||
|
|
||||
|
def is_adminuser(): |
||||
|
if not current_user.is_authenticated: |
||||
|
return False |
||||
|
user = User.query.filter_by(email=current_user.email).first() |
||||
|
return user.admin |
@ -0,0 +1,160 @@ |
|||||
|
import os |
||||
|
from flask import ( |
||||
|
Blueprint, |
||||
|
render_template, |
||||
|
redirect, |
||||
|
url_for, |
||||
|
send_from_directory, |
||||
|
flash, |
||||
|
) |
||||
|
from flask_login import current_user, login_required |
||||
|
from sqlalchemy.exc import ( |
||||
|
DatabaseError, |
||||
|
DataError, |
||||
|
IntegrityError, |
||||
|
InterfaceError, |
||||
|
InvalidRequestError, |
||||
|
) |
||||
|
import piexif |
||||
|
from PIL import Image |
||||
|
from app import db |
||||
|
from models.distribusi_model import Distribusis |
||||
|
from models.distribusi_file_model import DistribusiFiles |
||||
|
from describer.forms.describe_files_form import DescribeFilesForm |
||||
|
from describer.forms.redistribusi_form import ReDistribusiForm |
||||
|
from distribusikan.distribusi_workflow import run_distribusi, get_css_file |
||||
|
|
||||
|
describer = Blueprint( |
||||
|
"describer", |
||||
|
__name__, |
||||
|
template_folder="templates/describe_files", |
||||
|
static_folder="static", |
||||
|
) |
||||
|
|
||||
|
|
||||
|
@describer.route("/<string:distribusiname>") |
||||
|
@login_required |
||||
|
def show_distribusi_files(distribusiname): |
||||
|
if not current_user.is_authenticated: |
||||
|
return redirect(url_for("index")) |
||||
|
distribusi = Distribusis.query.filter_by( |
||||
|
distribusiname=distribusiname |
||||
|
).first() |
||||
|
redistribusi_form = ReDistribusiForm() |
||||
|
distribusi_file_forms = get_distribusi_file_forms(distribusi.id) |
||||
|
return render_template( |
||||
|
"describe.html", |
||||
|
distribusiname=distribusiname, |
||||
|
redistribusi_form=redistribusi_form, |
||||
|
distribusi_file_forms=distribusi_file_forms, |
||||
|
) |
||||
|
|
||||
|
|
||||
|
@describer.route("/redistribusi/<string:distribusiname>", methods=["POST"]) |
||||
|
@login_required |
||||
|
def re_distribusi_files(distribusiname): |
||||
|
distribusi = Distribusis.query.filter_by( |
||||
|
distribusiname=distribusiname |
||||
|
).first() |
||||
|
redistribusi_form = ReDistribusiForm() |
||||
|
if redistribusi_form.validate_on_submit(): |
||||
|
userfolder = os.path.join("stash", distribusi.distribusiname) |
||||
|
cssfile = get_css_file(distribusi) |
||||
|
run_distribusi(userfolder, cssfile) |
||||
|
return redirect( |
||||
|
url_for( |
||||
|
"describer.show_distribusi_files", |
||||
|
distribusiname=distribusi.distribusiname, |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
|
||||
|
@describer.route("/describe_file/<int:file_id>", methods=["POST"]) |
||||
|
@login_required |
||||
|
def describe_file(file_id): |
||||
|
distribusi_file = DistribusiFiles.query.filter_by(id=file_id).first() |
||||
|
describe_form = DescribeFilesForm( |
||||
|
distribusi_file.id, distribusi_file.path, distribusi_file.type |
||||
|
) |
||||
|
save_described_file_to_db(describe_form, distribusi_file) |
||||
|
add_alttext_to_file(describe_form, distribusi_file) |
||||
|
add_description_to_file(describe_form, distribusi_file) |
||||
|
distribusi = Distribusis.query.filter_by( |
||||
|
id=distribusi_file.distribusi |
||||
|
).first() |
||||
|
return redirect( |
||||
|
url_for( |
||||
|
"describer.show_distribusi_files", |
||||
|
distribusiname=distribusi.distribusiname, |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
|
||||
|
@describer.route("/stash/<path:path>") |
||||
|
def send_stash_file(path): |
||||
|
return send_from_directory("stash", path) |
||||
|
|
||||
|
|
||||
|
def get_distribusi_file_forms(distribusi_id): |
||||
|
distribusi_file_forms = {} |
||||
|
distribusi_files = DistribusiFiles.query.filter_by( |
||||
|
distribusi=distribusi_id |
||||
|
).all() |
||||
|
for distribusi_file in distribusi_files: |
||||
|
describe_form = DescribeFilesForm( |
||||
|
distribusi_file.id, distribusi_file.path, distribusi_file.type |
||||
|
) |
||||
|
describe_form.description.data = distribusi_file.description |
||||
|
describe_form.alttext.data = distribusi_file.alttext |
||||
|
describe_form.searchtags.data = distribusi_file.tags |
||||
|
distribusi_file_forms[distribusi_file.id] = describe_form |
||||
|
return distribusi_file_forms |
||||
|
|
||||
|
|
||||
|
def save_described_file_to_db(describe_form, distribusi_file): |
||||
|
try: |
||||
|
if describe_form.description.data: |
||||
|
print(distribusi_file.id) |
||||
|
distribusi_file.description = describe_form.description.data |
||||
|
if describe_form.alttext.data: |
||||
|
distribusi_file.alttext = describe_form.alttext.data |
||||
|
if describe_form.searchtags.data: |
||||
|
distribusi_file.tags = describe_form.searchtags.data |
||||
|
db.session.add(distribusi_file) |
||||
|
db.session.commit() |
||||
|
except (InvalidRequestError, IntegrityError): |
||||
|
db.session.rollback() |
||||
|
describe_form.save.errors.append("Something went wrong!") |
||||
|
flash("Something went wrong!", "danger") |
||||
|
except DataError: |
||||
|
db.session.rollback() |
||||
|
describe_form.save.errors.append("Invalid Entry") |
||||
|
flash("Invalid Entry", "warning") |
||||
|
except InterfaceError: |
||||
|
db.session.rollback() |
||||
|
describe_form.save.errors.append("Error connecting to the database") |
||||
|
flash("Error connecting to the database", "danger") |
||||
|
except DatabaseError: |
||||
|
db.session.rollback() |
||||
|
describe_form.save.errors.append("Error connecting to the database") |
||||
|
flash("Error connecting to the database", "danger") |
||||
|
|
||||
|
|
||||
|
def add_alttext_to_file(describe_form, distribusi_file): |
||||
|
if not describe_form.alttext.data: |
||||
|
return |
||||
|
filename_no_ext = os.path.splitext(distribusi_file.path)[0] |
||||
|
with open(f"{filename_no_ext}_alttext.txt", "w") as alttext_file: |
||||
|
alttext_file.write(describe_form.alttext.data) |
||||
|
return |
||||
|
|
||||
|
|
||||
|
def add_description_to_file(describe_form, distribusi_file): |
||||
|
if not describe_form.description.data: |
||||
|
return |
||||
|
filename_no_ext = os.path.splitext(distribusi_file.path)[0] |
||||
|
with open( |
||||
|
f"{filename_no_ext}_dv_description.txt", "w" |
||||
|
) as description_file: |
||||
|
description_file.write(describe_form.description.data) |
||||
|
return |
@ -0,0 +1,48 @@ |
|||||
|
"""Describe File Form to describe files in the distribusi archive""" |
||||
|
|
||||
|
from flask_wtf import FlaskForm |
||||
|
from wtforms import StringField, SubmitField, validators |
||||
|
from wtforms.validators import Length |
||||
|
from wtforms.widgets import TextArea |
||||
|
|
||||
|
|
||||
|
class DescribeFilesForm(FlaskForm): |
||||
|
"""DescribeFileForm selection form.""" |
||||
|
|
||||
|
alttext = StringField( |
||||
|
"Alt-text for this file:", |
||||
|
validators=[ |
||||
|
Length(3, 255), |
||||
|
], |
||||
|
) |
||||
|
searchtags = StringField( |
||||
|
"Add search tags, seperated by commas. No need for the '#' sign:", |
||||
|
validators=[ |
||||
|
Length(3, 500), |
||||
|
], |
||||
|
) |
||||
|
description = StringField( |
||||
|
"Description of this file:", |
||||
|
validators=[ |
||||
|
Length(3, 4096), |
||||
|
], |
||||
|
widget=TextArea(), |
||||
|
) |
||||
|
save = SubmitField("Save") |
||||
|
|
||||
|
def __init__(self, id, file_path=None, type=None): |
||||
|
super(DescribeFilesForm, self).__init__() |
||||
|
self.id = id |
||||
|
self.file_path = file_path |
||||
|
self.type = type |
||||
|
self.alttext.id = f"alttext-{id}" |
||||
|
self.searchtags.id = f"searchtags-{id}" |
||||
|
self.description.id = f"description-{id}" |
||||
|
self.save.id = f"save-{id}" |
||||
|
|
||||
|
|
||||
|
# def StringFieldWithId(form_name, **kwargs): |
||||
|
# name = kwargs.get('name', 'Bar') |
||||
|
# return wtf.StringField(name, render_kw={ |
||||
|
# 'id': f'{}{}'.format(form_name, name.lower(), |
||||
|
# **kwargs.get('render_kw', {})}) |
@ -0,0 +1,8 @@ |
|||||
|
from flask_wtf import FlaskForm |
||||
|
from wtforms import SubmitField |
||||
|
|
||||
|
|
||||
|
class ReDistribusiForm(FlaskForm): |
||||
|
"""Re-Distribusi form class to re-distrusi with desribed files""" |
||||
|
|
||||
|
submit = SubmitField("Re-Distribusi!") |
@ -0,0 +1,32 @@ |
|||||
|
#describe_workflow { |
||||
|
display: flex; |
||||
|
width: 60em; |
||||
|
margin:0 auto; |
||||
|
} |
||||
|
|
||||
|
.redistribusi { |
||||
|
position: sticky; |
||||
|
top: 2em; |
||||
|
margin-top: 2em; |
||||
|
margin-left: 1em; |
||||
|
width: 15em; |
||||
|
height: 10em; |
||||
|
border-style: outset; |
||||
|
float: right; |
||||
|
padding: 0.5em; |
||||
|
} |
||||
|
|
||||
|
.distribusi_file { |
||||
|
margin-top: 2em; |
||||
|
padding: 0.5em; |
||||
|
width: 42em; |
||||
|
background-color:#fdfdfd; |
||||
|
text-decoration: none; |
||||
|
scroll-behavior: smooth; |
||||
|
border-style: outset; |
||||
|
} |
||||
|
|
||||
|
.distribusi_file > img, video { |
||||
|
max-width: 100%; |
||||
|
max-height: 100%; |
||||
|
} |
@ -0,0 +1,78 @@ |
|||||
|
{% extends "base/base.html" %} |
||||
|
{% block main %} |
||||
|
<div id="buttons"> |
||||
|
{% if current_user.is_authenticated %} |
||||
|
<div class="distribusi"> |
||||
|
<a href="{{ url_for('distribusikan.distribusi') }}"> |
||||
|
<input type="button" name="button" value="Distribusi"></input> |
||||
|
</a> |
||||
|
</div> |
||||
|
{% if adminuser %} |
||||
|
<div class="admin"> |
||||
|
<a href="/admin"> |
||||
|
<input type="button" name="button" value="Admin"></input> |
||||
|
</a> |
||||
|
</div> |
||||
|
{% endif %} |
||||
|
<div class="logout"> |
||||
|
<a href="/logout"> |
||||
|
<input type="button" name="button" value="Logout"></input> |
||||
|
</a> |
||||
|
</div> |
||||
|
{% endif %} |
||||
|
<div class="help"> |
||||
|
<a href="/help"> |
||||
|
<input type="button" name="button" value="Help"></input> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div id="describe_workflow"> |
||||
|
<div class="distribusi_files"> |
||||
|
{% for id, describe_form in distribusi_file_forms.items() %} |
||||
|
<div class="distribusi_file"> |
||||
|
{% if describe_form.type == "image" %} |
||||
|
<img src="{{describe_form.file_path}}" alt="" data-src="{{describe_form.file_path}}" loading="lazy"/> |
||||
|
{% elif describe_form.type == "video" %} |
||||
|
<video src="{{describe_form.file_path}}" preload="auto" alt="" controls loading="lazy"></video> |
||||
|
{% elif describe_form.type == "audio" %} |
||||
|
<audio src="{{describe_form.file_path}}" preload="auto" alt="" controls loading="lazy"> </audio> |
||||
|
{% else %} |
||||
|
<a href="{{describe_form.file_path}}">file: {{describe_form.file_path}}</a> |
||||
|
{% endif %} |
||||
|
<form id={{id}} method="POST" enctype="multipart/form-data" action="{{ url_for('describer.describe_file', file_id=id) }}"> |
||||
|
{{ describe_form.csrf_token }} |
||||
|
<p>File path: {{describe_form.file_path}}</p> |
||||
|
<fieldset class="description"> |
||||
|
{{ describe_form.description.label }} |
||||
|
{{ describe_form.description }} |
||||
|
{% for message in describe_form.description.errors %} |
||||
|
<div class="error">{{ message }}</div> |
||||
|
{% endfor %} |
||||
|
</fieldset> |
||||
|
<fieldset class=""> |
||||
|
{{ describe_form.searchtags.label }} |
||||
|
{{ describe_form.searchtags }} |
||||
|
{% for message in describe_form.searchtags.errors %} |
||||
|
<div class="error">{{ message }}</div> |
||||
|
{% endfor %} |
||||
|
</fieldset> |
||||
|
<fieldset class=""> |
||||
|
{{ describe_form.alttext.label }} |
||||
|
{{ describe_form.alttext }} |
||||
|
{% for message in describe_form.alttext.errors %} |
||||
|
<div class="error">{{ message }}</div> |
||||
|
{% endfor %} |
||||
|
</fieldset> |
||||
|
<fieldset class="button"> |
||||
|
{{ describe_form.save }} |
||||
|
</fieldset> |
||||
|
</form> |
||||
|
</div> |
||||
|
{% endfor%} |
||||
|
</div> |
||||
|
{% block redistribusi %} |
||||
|
{% include "redistribusi.html" %} |
||||
|
{% endblock redistribusi%} |
||||
|
</div> |
||||
|
<link rel="stylesheet" type="text/css" href="{{ url_for('describer.static', filename='css/describer.css')}}"> |
||||
|
{% endblock %} |
@ -0,0 +1,13 @@ |
|||||
|
<div class="redistribusi"> |
||||
|
<p class="tooltip">Run distribusi again after describing your files.<span class="tooltiptext">Distribusi will run again and add your alttext and descriptions. |
||||
|
</span></p> |
||||
|
<form id={{distribusiname}} method="POST" enctype="multipart/form-data" action="{{ url_for('describer.re_distribusi_files', distribusiname=distribusiname) }}"> |
||||
|
{{ redistribusi_form.csrf_token }} |
||||
|
<fieldset class=""> |
||||
|
{{ redistribusi_form.submit }} |
||||
|
{% for message in redistribusi_form.submit.errors %} |
||||
|
<div class="error">{{ message }}</div> |
||||
|
{% endfor %} |
||||
|
</fieldset> |
||||
|
</form> |
||||
|
</div> |
@ -0,0 +1,82 @@ |
|||||
|
import os |
||||
|
|
||||
|
import magic |
||||
|
from distribusi.mappings import FILE_TYPES |
||||
|
from models.distribusi_model import Distribusis |
||||
|
from models.distribusi_file_model import DistribusiFiles |
||||
|
from app import create_app, get_app, db |
||||
|
from sqlalchemy.exc import ( |
||||
|
DatabaseError, |
||||
|
DataError, |
||||
|
IntegrityError, |
||||
|
InterfaceError, |
||||
|
InvalidRequestError, |
||||
|
) |
||||
|
|
||||
|
MIME_TYPE = magic.Magic(mime=True) |
||||
|
|
||||
|
|
||||
|
def _distribusi_file_with_type(distribusi, full_path): |
||||
|
mime = MIME_TYPE.from_file(full_path) |
||||
|
type_, subtype = mime.split("/") |
||||
|
if type_ in FILE_TYPES: |
||||
|
_add_distribusi_file_to_db(distribusi, full_path, type_) |
||||
|
|
||||
|
|
||||
|
def _get_distribusi_from_path(path): |
||||
|
distribusi = Distribusis.query.filter_by(distribusiname=path).first() |
||||
|
return distribusi |
||||
|
|
||||
|
|
||||
|
def _add_distribusi_file_to_db(distribusi, full_path, type): |
||||
|
app = get_app() |
||||
|
app.logger.info(f"adding file to database: {full_path} type: {type}") |
||||
|
distribusi_file = DistribusiFiles.query.filter_by(path=full_path).first() |
||||
|
if distribusi_file is not None: |
||||
|
app.logger.error(f"File already in database: {full_path}") |
||||
|
return |
||||
|
try: |
||||
|
new_distribusi_file = DistribusiFiles( |
||||
|
path=full_path, |
||||
|
type=type, |
||||
|
distribusi=distribusi.id, |
||||
|
) |
||||
|
db.session.add(new_distribusi_file) |
||||
|
db.session.commit() |
||||
|
return |
||||
|
except InvalidRequestError: |
||||
|
db.session.rollback() |
||||
|
app.logger.error("Something went wrong!") |
||||
|
except IntegrityError: |
||||
|
db.session.rollback() |
||||
|
app.logger.error("File %s already exists!", full_path) |
||||
|
except DataError: |
||||
|
db.session.rollback() |
||||
|
app.logger.error("%s Invalid Entry", full_path) |
||||
|
except InterfaceError: |
||||
|
db.session.rollback() |
||||
|
app.logger.error("Error connecting to the database") |
||||
|
except DatabaseError: |
||||
|
db.session.rollback() |
||||
|
app.logger.error("Error connecting to the database") |
||||
|
|
||||
|
|
||||
|
def add_distribusi_files_to_db(path): |
||||
|
distribusi = _get_distribusi_from_path(path) |
||||
|
path = os.path.join("stash", path) |
||||
|
for root, dirs, files in os.walk(path, topdown=True): |
||||
|
files = list(filter(lambda f: not f.startswith("."), files)) |
||||
|
files = list(filter(lambda f: not f.endswith(".html"), files)) |
||||
|
files = list(filter(lambda f: not f.endswith("_thumbnail.jpg"), files)) |
||||
|
files = list(filter(lambda f: not f.endswith("_alttext.txt"), files)) |
||||
|
files = list( |
||||
|
filter(lambda f: not f.endswith("_dv_description.txt"), files) |
||||
|
) |
||||
|
|
||||
|
for file in files: |
||||
|
full_path = os.path.join(root, file) |
||||
|
distribusi_file = DistribusiFiles.query.filter_by( |
||||
|
path=full_path |
||||
|
).first() |
||||
|
if distribusi_file is None: |
||||
|
_distribusi_file_with_type(distribusi, full_path) |
@ -0,0 +1,32 @@ |
|||||
|
#publicthemes > ul { |
||||
|
max-height: 20em; |
||||
|
overflow: auto; |
||||
|
} |
||||
|
|
||||
|
#publicthemes > ul > li{ |
||||
|
word-break: break-all; |
||||
|
} |
||||
|
|
||||
|
.workflow{ |
||||
|
margin-top: 1em; |
||||
|
padding: 0.5em; |
||||
|
background-color:#fdfdfd; |
||||
|
text-decoration: none; |
||||
|
scroll-behavior: smooth; |
||||
|
border-style: outset; |
||||
|
} |
||||
|
|
||||
|
.workflow > p { |
||||
|
padding-left: 1em; |
||||
|
} |
||||
|
|
||||
|
.workflow > h2 { |
||||
|
padding-left: 0.4em;; |
||||
|
} |
||||
|
|
||||
|
.workflow input{ |
||||
|
max-width: 20em; |
||||
|
} |
||||
|
.new_divider { |
||||
|
height: 5em; |
||||
|
} |
@ -1,7 +1,7 @@ |
|||||
<div id="edit" class="workflow"> |
<div id="edit" class="workflow"> |
||||
<h2>Step 3: Edit Custom CSS (Optional)</h2> |
<h2>Step 3: Edit Custom CSS (Optional)</h2> |
||||
{% if files_uploaded or distribusi_live %} |
{% if files_uploaded or distribusi_live %} |
||||
<p><a href="/editor">Go to CSS editor</a></p> |
<p><a href="/distribusikan/editor">Go to CSS editor</a></p> |
||||
{% else %} |
{% else %} |
||||
<p> |
<p> |
||||
You need to upload your files first before you can select a css theme |
You need to upload your files first before you can select a css theme |
@ -1,34 +1,34 @@ |
|||||
from flask import render_template |
from flask import render_template |
||||
|
|
||||
from app import APP |
from app import APP |
||||
from distribusikan.distribusiselector import SelectorVisible |
from distribusikan.distribusi_selector import selector_visible |
||||
from distribusikan.distribusisinfo import DistribusisInfo |
from distribusikan.distribusis_info import DistribusisInfo |
||||
from distribusikan.upload import UploadNewDistribusi, UploadUpdatedFiles |
from distribusikan.upload import upload_new_distribusi, upload_updates_files |
||||
from forms.distribusiform import DistribusiForm |
from distribusikan.forms.distribusiform import DistribusiForm |
||||
from forms.publicthemeform import PublicThemeForm |
from distribusikan.forms.publicthemeform import PublicThemeForm |
||||
from forms.selectorform import SelectorForm |
from distribusikan.forms.selectorform import SelectorForm |
||||
from forms.themeform import ThemeForm |
from distribusikan.forms.themeform import ThemeForm |
||||
|
|
||||
# UserPengguna |
# UserPengguna |
||||
from statuspengguna.helper import UserHelper |
from statuspengguna.helper import UserHelper |
||||
|
|
||||
|
|
||||
def UploadPage(): |
def upload_page(): |
||||
"render upload page section of distribusi workflow" |
"render upload page section of distribusi workflow" |
||||
uploadfolder = APP.config["UPLOAD_FOLDER"] |
uploadfolder = APP.config["UPLOAD_FOLDER"] |
||||
distribusiform = DistribusiForm() |
distribusiform = DistribusiForm() |
||||
themeform = ThemeForm() |
themeform = ThemeForm() |
||||
publicthemeform = PublicThemeForm() |
publicthemeform = PublicThemeForm() |
||||
publicthemeform.publicthemes.choices = DistribusisInfo.publicthemes() |
publicthemeform.publicthemes.choices = DistribusisInfo.public_themes() |
||||
selectorform = SelectorForm() |
selectorform = SelectorForm() |
||||
selectorform.distribusis.choices = DistribusisInfo.userdistribusinames() |
selectorform.distribusis.choices = DistribusisInfo.user_distribusinames() |
||||
selectorvisible = SelectorVisible() |
selectorvisible = selector_visible() |
||||
|
|
||||
current_distribusi = UserHelper.current_distribusi() |
current_distribusi = UserHelper.current_distribusi() |
||||
if current_distribusi == "new" or UserHelper.has_distribusi() is False: |
if current_distribusi == "new" or UserHelper.has_distribusi() is False: |
||||
uploadform = UploadNewDistribusi(uploadfolder) |
uploadform = upload_new_distribusi(uploadfolder) |
||||
else: |
else: |
||||
uploadform = UploadUpdatedFiles(uploadfolder) |
uploadform = upload_updates_files(uploadfolder) |
||||
|
|
||||
files_uploaded = UserHelper.is_zip_uploaded(uploadform.sitename.data) |
files_uploaded = UserHelper.is_zip_uploaded(uploadform.sitename.data) |
||||
distribusi_live = UserHelper.is_distribusi_live(current_distribusi) |
distribusi_live = UserHelper.is_distribusi_live(current_distribusi) |
@ -0,0 +1,11 @@ |
|||||
|
"""SearchForm to search files and distribusis in the distribusi archive""" |
||||
|
|
||||
|
from flask_wtf import FlaskForm |
||||
|
from wtforms import StringField, SubmitField, validators |
||||
|
from wtforms.validators import Length |
||||
|
from wtforms.widgets import TextArea |
||||
|
|
||||
|
|
||||
|
class SearchForm(FlaskForm): |
||||
|
searchfield = StringField("Search distribusi-verse archive") |
||||
|
submit = SubmitField("Search") |
@ -0,0 +1,42 @@ |
|||||
|
import os |
||||
|
from flask import Blueprint, render_template |
||||
|
from whoosh.fields import * |
||||
|
from whoosh.index import open_dir |
||||
|
from whoosh.qparser import QueryParser |
||||
|
from search.forms.searchform import SearchForm |
||||
|
|
||||
|
searchpages = Blueprint( |
||||
|
"search", |
||||
|
__name__, |
||||
|
template_folder="templates/search", |
||||
|
static_folder="static", |
||||
|
) |
||||
|
|
||||
|
SCRIPT_DIR = os.path.dirname(__file__) |
||||
|
SEARCH_DATA_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "searchdata")) |
||||
|
|
||||
|
|
||||
|
@searchpages.route("/", methods=["GET", "POST"]) |
||||
|
def searchpage(): |
||||
|
searchform = SearchForm() |
||||
|
found_distribusis = [] |
||||
|
if searchform.validate_on_submit(): |
||||
|
found_distribusis = search(searchform.searchfield.data) |
||||
|
template = render_template( |
||||
|
"search.html", |
||||
|
searchform=searchform, |
||||
|
found_distribusis=found_distribusis, |
||||
|
) |
||||
|
return template |
||||
|
|
||||
|
|
||||
|
def search(searchinput): |
||||
|
"""search and get search result titles and return them as distribusi ids""" |
||||
|
ix = open_dir(SEARCH_DATA_DIR) |
||||
|
with ix.searcher() as searcher: |
||||
|
query = QueryParser("content", ix.schema).parse(searchinput) |
||||
|
search_results = searcher.search(query) |
||||
|
found_distribusis = [] |
||||
|
for result in search_results: |
||||
|
found_distribusis.append(result["title"]) |
||||
|
return found_distribusis |
@ -0,0 +1,52 @@ |
|||||
|
import os |
||||
|
from whoosh.fields import * |
||||
|
from whoosh.index import create_in |
||||
|
from whoosh.qparser import QueryParser |
||||
|
from models.distribusi_model import Distribusis |
||||
|
import flask_apscheduler |
||||
|
|
||||
|
|
||||
|
SCRIPT_DIR = os.path.dirname(__file__) |
||||
|
SEARCH_DATA_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "searchdata")) |
||||
|
|
||||
|
|
||||
|
def init_search_index(APP): |
||||
|
scheduler = flask_apscheduler.APScheduler() |
||||
|
scheduler.api_enabled = False |
||||
|
scheduler.init_app(APP) |
||||
|
scheduler.start() |
||||
|
index_distribusis(APP) |
||||
|
index_distribusi_files(APP) |
||||
|
|
||||
|
@scheduler.task("interval", id="update", minutes=60) |
||||
|
def update_search_index(): |
||||
|
index_distribusis(APP) |
||||
|
index_distribusi_files(APP) |
||||
|
|
||||
|
|
||||
|
def index_distribusis(APP): |
||||
|
schema = Schema( |
||||
|
title=TEXT(stored=True), path=ID(stored=True), content=TEXT |
||||
|
) |
||||
|
ix = create_in(SEARCH_DATA_DIR, schema) |
||||
|
writer = ix.writer() |
||||
|
distribusis = _visible_distribusis(APP) |
||||
|
for distribusi in distribusis: |
||||
|
writer.add_document( |
||||
|
title=distribusi.distribusiname, |
||||
|
path="/a", |
||||
|
content=distribusi.description, |
||||
|
) |
||||
|
writer.commit() |
||||
|
|
||||
|
|
||||
|
def index_distribusi_files(APP): |
||||
|
APP.logger.info("searching distribusi files not implemented yet.") |
||||
|
|
||||
|
|
||||
|
def _visible_distribusis(APP): |
||||
|
with APP.app_context(): |
||||
|
distribusis = Distribusis.query.filter( |
||||
|
Distribusis.visible.isnot(False) |
||||
|
).all() |
||||
|
return distribusis |
@ -0,0 +1,23 @@ |
|||||
|
{% extends "base/base.html" %} |
||||
|
{% block main %} |
||||
|
<div id="distribusiverse" class="maincontent"> |
||||
|
<form method="POST" enctype="multipart/form-data" action="{{ url_for('search.searchpage') }}"> |
||||
|
{{ searchform.csrf_token }} |
||||
|
<fieldset class="required"> |
||||
|
{{ searchform.searchfield.label }} |
||||
|
{{ searchform.searchfield }} |
||||
|
{% for message in searchform.searchfield.errors %} |
||||
|
<div class="error">{{ message }}</div> |
||||
|
{% endfor %} |
||||
|
</fieldset> |
||||
|
<fieldset class="button required"> |
||||
|
{{ searchform.submit }} |
||||
|
</fieldset> |
||||
|
</form> |
||||
|
<div class="searchresults"> |
||||
|
{% for found_distribusi in found_distribusis %} |
||||
|
<a href='{{ url_for('shortstashurl')}}/{{found_distribusi}}/index.html'>{{found_distribusi}}</a> |
||||
|
{% endfor %} |
||||
|
</div> |
||||
|
</div> |
||||
|
{% endblock %} |
@ -1,4 +1,7 @@ |
|||||
title = "Varia Archive X Distribusi-Verse" |
title = "Varia Archive X Distribusi-Verse" |
||||
categories = ["event","gathering","work session","workgroup","performance","music event"] |
categories = [ "article", "booklaunch", "broadcast", "curriculum", "game", |
||||
|
"gathering", "lecture", "opencall", "party", "performance", "presentation", |
||||
|
"publication", "report", "screening", "statement", "workgroup", "worksession", |
||||
|
"workshop"] |
||||
start_time = 2017-11-03 |
start_time = 2017-11-03 |
||||
end_time = 2025-12-31 |
end_time = 2025-12-31 |
||||
|
@ -1,69 +0,0 @@ |
|||||
/* Dropdown Button */ |
|
||||
/* for sorting on year and category |
|
||||
*/ |
|
||||
button { |
|
||||
background-color: #E0B0FF; |
|
||||
text-decoration: none; |
|
||||
border: none; |
|
||||
} |
|
||||
.filter { |
|
||||
display: none; |
|
||||
} |
|
||||
|
|
||||
.activebtn { |
|
||||
background-color: #62b264; |
|
||||
} |
|
||||
|
|
||||
.show { |
|
||||
display: block; |
|
||||
} |
|
||||
.dropdown { |
|
||||
position: relative; |
|
||||
display: inline-block; |
|
||||
} |
|
||||
|
|
||||
/* Dropdown Content (Hidden by Default) */ |
|
||||
.dropdown-content { |
|
||||
display: none; |
|
||||
position: absolute; |
|
||||
background-color: #E0B0FF; |
|
||||
min-width: 120px; |
|
||||
border: 2px solid; |
|
||||
z-index: 1; |
|
||||
border-style: outset; |
|
||||
} |
|
||||
|
|
||||
/* Links inside the dropdown */ |
|
||||
.dropdown-content button { |
|
||||
color: black; |
|
||||
padding: 6px; |
|
||||
border: none; |
|
||||
min-width: inherit; |
|
||||
text-align: left; |
|
||||
text-decoration: none; |
|
||||
display: block; |
|
||||
} |
|
||||
.dropbtn { |
|
||||
margin-top: 1em; |
|
||||
} |
|
||||
/* Change color of dropdown links on hover */ |
|
||||
.dropdown-content button:hover {background-color: #62b264;} |
|
||||
|
|
||||
|
|
||||
/* Show the dropdown menu on hover */ |
|
||||
.dropdown:hover .dropdown-content {display: block;} |
|
||||
|
|
||||
/* Change the background color of the dropdown button when the dropdown content is shown */ |
|
||||
.dropdown:hover .dropbtn {background-color: #62b264;} |
|
||||
|
|
||||
@media only screen and (min-device-width: 320px) and (max-device-width: 480px) { |
|
||||
.dropdown-content button { |
|
||||
font-size: 0.7em; |
|
||||
} |
|
||||
.container > button { |
|
||||
font-size: 0.7em; |
|
||||
} |
|
||||
.dropdown > button { |
|
||||
font-size: 0.7em; |
|
||||
} |
|
||||
} |
|
@ -1,50 +0,0 @@ |
|||||
.editareas { |
|
||||
margin: auto; |
|
||||
display: flex; |
|
||||
justify-content: flex-start; |
|
||||
} |
|
||||
.editarea { |
|
||||
width: 30%; |
|
||||
border: 3px solid #E0B0FF; |
|
||||
border-style: outset; |
|
||||
margin-right: 1em; |
|
||||
margin-left: 0; |
|
||||
} |
|
||||
|
|
||||
.editor { |
|
||||
min-width: 35%; |
|
||||
} |
|
||||
.editform { |
|
||||
width: 100%%; |
|
||||
margin: 0 auto; |
|
||||
} |
|
||||
#editorsubmitform { |
|
||||
padding-top: 1em; |
|
||||
} |
|
||||
.required label { |
|
||||
display: block; |
|
||||
padding-bottom: 2px; |
|
||||
width: 100% |
|
||||
} |
|
||||
textarea { |
|
||||
width: 100%; |
|
||||
height: 100%; |
|
||||
box-sizing: border-box; |
|
||||
min-height: 250px; |
|
||||
background: #E0B0FF; |
|
||||
outline: none; |
|
||||
font-family: Courier, sans-serif; |
|
||||
font-size: 16px; |
|
||||
} |
|
||||
|
|
||||
iframe { |
|
||||
bottom: 0; |
|
||||
position: relative; |
|
||||
margin-top: 1em; |
|
||||
width: 100%; |
|
||||
height: 30em; |
|
||||
} |
|
||||
#html { |
|
||||
background-color: #60337F; |
|
||||
color: lightgrey; |
|
||||
} |
|
@ -0,0 +1,22 @@ |
|||||
|
div#login{ |
||||
|
width: 30%; |
||||
|
margin-left: auto; |
||||
|
margin-right: auto; |
||||
|
background-color:#fdfdfd; |
||||
|
text-decoration: none; |
||||
|
} |
||||
|
|
||||
|
div#login form { |
||||
|
width: 24em; |
||||
|
margin: 0 auto; |
||||
|
padding-left: 15%; |
||||
|
padding-right: 15%; |
||||
|
} |
||||
|
|
||||
|
input[type=text], input[type=password], input[type=file] { |
||||
|
color: #091411; |
||||
|
width: 18em; |
||||
|
max-width: 18em; |
||||
|
background-color: #fdfdfd; |
||||
|
border: 1px solid #9de457; |
||||
|
} |
@ -1,53 +0,0 @@ |
|||||
.selector-style { |
|
||||
padding: 0; |
|
||||
width: 20em; |
|
||||
max-width: 20em; |
|
||||
position: relative; |
|
||||
border: none; |
|
||||
background: #E0B0FF; |
|
||||
text-decoration: none; |
|
||||
text-overflow: ellipsis; |
|
||||
white-space: nowrap; |
|
||||
overflow: hidden; |
|
||||
margin: 1px; |
|
||||
} |
|
||||
|
|
||||
.selector-style select { |
|
||||
padding: 0.2em 0.2em; |
|
||||
width: 20em; |
|
||||
max-width: 20em; |
|
||||
border: none; |
|
||||
box-shadow: none; |
|
||||
background-color: #E0B0FF; |
|
||||
background-image: none; |
|
||||
-webkit-appearance: none; |
|
||||
-moz-appearance: none; |
|
||||
appearance: none; |
|
||||
} |
|
||||
|
|
||||
.selector-style:after { |
|
||||
top: 50%; |
|
||||
left: 95%; |
|
||||
border: solid; |
|
||||
content: " "; |
|
||||
height: 0; |
|
||||
width: 0; |
|
||||
position: absolute; |
|
||||
pointer-events: none; |
|
||||
border-color: rgba(0, 0, 0, 0); |
|
||||
border-top-color: #000000; |
|
||||
margin-top: -2px; |
|
||||
z-index: 100; |
|
||||
} |
|
||||
select.selector option{ |
|
||||
color: white; |
|
||||
background-color: #60337F; |
|
||||
padding: 0 10px; |
|
||||
} |
|
||||
|
|
||||
.selector-style select:focus { |
|
||||
outline: none; |
|
||||
} |
|
||||
.selector-style select option:hover { |
|
||||
background: #60337F; |
|
||||
} |
|
@ -1,281 +0,0 @@ |
|||||
body |
|
||||
{ |
|
||||
font-family: monospace, monospace; |
|
||||
font-size: 15px; |
|
||||
background-color: #fdfdfd; |
|
||||
color:#29d148; |
|
||||
word-wrap: break-word; |
|
||||
line-height: 1.1; |
|
||||
} |
|
||||
|
|
||||
div#login{ |
|
||||
width: 30%; |
|
||||
margin-left: auto; |
|
||||
margin-right: auto; |
|
||||
background-color:#fdfdfd; |
|
||||
text-decoration: none; |
|
||||
} |
|
||||
|
|
||||
div#login form { |
|
||||
width: 24em; |
|
||||
margin: 0 auto; |
|
||||
padding-left: 15%; |
|
||||
padding-right: 15%; |
|
||||
} |
|
||||
|
|
||||
input[type=text], input[type=password], input[type=file] { |
|
||||
color: #C397DF; |
|
||||
width: 18em; |
|
||||
max-width: 18em; |
|
||||
background-color: #fdfdfd; |
|
||||
border: 1px solid #E0B0FF; |
|
||||
} |
|
||||
|
|
||||
div#upload form { |
|
||||
padding-right: 15%; |
|
||||
} |
|
||||
|
|
||||
.workflow{ |
|
||||
margin-top: 1em; |
|
||||
padding: 0.5em; |
|
||||
padding-left: auto; |
|
||||
padding-right: auto; |
|
||||
width: 31em; |
|
||||
background-color:#fdfdfd; |
|
||||
text-decoration: none; |
|
||||
scroll-behavior: smooth; |
|
||||
border-style: outset; |
|
||||
} |
|
||||
.workflow > p { |
|
||||
padding-left: 1em; |
|
||||
} |
|
||||
.workflow > h2 { |
|
||||
padding-left: 0.4em;; |
|
||||
} |
|
||||
|
|
||||
.workflow input{ |
|
||||
max-width: 20em; |
|
||||
} |
|
||||
|
|
||||
#mainworkflow |
|
||||
{ |
|
||||
width: 30em; |
|
||||
margin:0 auto; |
|
||||
} |
|
||||
|
|
||||
#distribusiverse { |
|
||||
margin-bottom: 11em; |
|
||||
} |
|
||||
#distribusi-index { |
|
||||
padding-left: 1em; |
|
||||
} |
|
||||
|
|
||||
div#buttons{ |
|
||||
position: fixed; |
|
||||
top: 0.5em; |
|
||||
right: 0.5em; |
|
||||
display:flex; |
|
||||
flex-direction: row; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
} |
|
||||
|
|
||||
div#buttons .distribusi input{ |
|
||||
border: none; |
|
||||
background: #fff600; |
|
||||
text-decoration: none; |
|
||||
margin: 0.2em; |
|
||||
} |
|
||||
div#buttons .distribusi input:hover{ |
|
||||
background: #ffbf00; |
|
||||
|
|
||||
} |
|
||||
fieldset.required { |
|
||||
border: none; |
|
||||
} |
|
||||
|
|
||||
fieldset.required > ul { |
|
||||
padding-left: 0px; |
|
||||
} |
|
||||
|
|
||||
fieldset.required > ul > li{ |
|
||||
list-style-type: none; |
|
||||
} |
|
||||
fieldset.tagfield > input { |
|
||||
width: 100%; |
|
||||
max-width: 100%; |
|
||||
} |
|
||||
#publicthemes > ul { |
|
||||
max-height: 20em; |
|
||||
overflow: auto; |
|
||||
} |
|
||||
#publicthemes > ul > li{ |
|
||||
word-break: break-all; |
|
||||
} |
|
||||
|
|
||||
input { |
|
||||
border: none; |
|
||||
background: #E0B0FF; |
|
||||
text-decoration: none; |
|
||||
text-overflow: ellipsis; |
|
||||
white-space: nowrap; |
|
||||
overflow: hidden; |
|
||||
margin: 0.2em; |
|
||||
} |
|
||||
|
|
||||
input:hover { |
|
||||
background: #60337F; |
|
||||
} |
|
||||
|
|
||||
input[type="submit"]:disabled:hover, |
|
||||
input[type="submit"]:disabled, |
|
||||
input[type="submit"]:disabled:focus { |
|
||||
background-color: #2D3039; |
|
||||
color: #d28cff; |
|
||||
} |
|
||||
|
|
||||
.error { |
|
||||
font-size: 110%; |
|
||||
color: #F92020; |
|
||||
} |
|
||||
|
|
||||
#delete { |
|
||||
color: black; |
|
||||
background-color: #F92020; |
|
||||
} |
|
||||
|
|
||||
#update { |
|
||||
color: black; |
|
||||
background-color: #62b264; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/* unvisited link */ |
|
||||
a:link { |
|
||||
color: #fff600; |
|
||||
} |
|
||||
|
|
||||
/* visited link */ |
|
||||
a:visited { |
|
||||
color: #d28cff; |
|
||||
} |
|
||||
|
|
||||
/* mouse over link */ |
|
||||
a:hover { |
|
||||
color: #60337F; |
|
||||
} |
|
||||
|
|
||||
/* selected link */ |
|
||||
a:active { |
|
||||
color: white; |
|
||||
} |
|
||||
|
|
||||
/* STOLEN GOODS */ |
|
||||
#fancyboi::before { |
|
||||
content: "$ "; |
|
||||
} |
|
||||
|
|
||||
@media (prefers-reduced-motion: no-preference) { |
|
||||
@keyframes flash { |
|
||||
50% { opacity: 0; } |
|
||||
} |
|
||||
@keyframes reveal { |
|
||||
from { width: 2em; } /* Width of ::before */ |
|
||||
to { width: 55%; } |
|
||||
} |
|
||||
#fancyboi { |
|
||||
width: 55%; |
|
||||
padding: 0.5em; |
|
||||
overflow: hidden; |
|
||||
white-space: nowrap; |
|
||||
animation: reveal 4s linear; |
|
||||
text-overflow: "█"; |
|
||||
background-color: #2D3039; |
|
||||
} |
|
||||
#fancyboi::after { |
|
||||
content: "█"; |
|
||||
animation: flash 0.5s step-end infinite; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
div.maincontent{ |
|
||||
width: 55%; |
|
||||
border: 3px #E0B0FF; |
|
||||
margin-top: 0.5em; |
|
||||
padding: 0.5em; |
|
||||
border-style: outset; |
|
||||
} |
|
||||
|
|
||||
.tags{ |
|
||||
background-color: #000; |
|
||||
color: #fff; |
|
||||
display: inline-block; |
|
||||
padding-left: 4px; |
|
||||
padding-right: 4px; |
|
||||
text-align: center; |
|
||||
margin: 1px; |
|
||||
} |
|
||||
|
|
||||
.searched { |
|
||||
background: #fff600 !important; |
|
||||
color: black !important; |
|
||||
} |
|
||||
|
|
||||
.tooltip { |
|
||||
position: relative; |
|
||||
display: inline-block; |
|
||||
border-bottom: 1px dotted black; |
|
||||
} |
|
||||
|
|
||||
.tooltip .tooltiptext { |
|
||||
visibility: hidden; |
|
||||
width: 120px; |
|
||||
background-color: black; |
|
||||
color: #fff; |
|
||||
text-align: center; |
|
||||
padding: 5px 0; |
|
||||
position: absolute; |
|
||||
z-index: 1; |
|
||||
bottom: 100%; |
|
||||
left: 50%; |
|
||||
margin-left: -60px; |
|
||||
|
|
||||
/* Fade in tooltip - takes 1 second to go from 0% to 100% opac: */ |
|
||||
opacity: 0; |
|
||||
transition: opacity 2s; |
|
||||
} |
|
||||
|
|
||||
.tooltip:hover .tooltiptext { |
|
||||
visibility: visible; |
|
||||
opacity: 1; |
|
||||
} |
|
||||
|
|
||||
.code-example { |
|
||||
width: 100%; |
|
||||
color: black; |
|
||||
padding: 1em; |
|
||||
box-sizing: border-box; |
|
||||
background: #E0B0FF; |
|
||||
outline: none; |
|
||||
font-family: Courier, sans-serif; |
|
||||
font-size: 16px; |
|
||||
} |
|
||||
/* |
|
||||
Project colors so far. |
|
||||
light |
|
||||
#E0B0FF |
|
||||
medium |
|
||||
#d28cff |
|
||||
dark |
|
||||
#60337F |
|
||||
|
|
||||
background dark |
|
||||
#2D3039 |
|
||||
|
|
||||
yellow important |
|
||||
#fff600 |
|
||||
|
|
||||
red: danger |
|
||||
ff5a5a |
|
||||
backgrounds |
|
||||
*/ |
|
@ -1,6 +0,0 @@ |
|||||
This favicon was generated using the following font: |
|
||||
|
|
||||
- Font Title: Klee One |
|
||||
- Font Author: Copyright 2020 The Klee Project Authors (https://github.com/fontworks-fonts/Klee) |
|
||||
- Font Source: http://fonts.gstatic.com/s/kleeone/v5/LDIxapCLNRc6A8oT4q4AOeekWPrP.ttf |
|
||||
- Font License: SIL Open Font License, 1.1 (http://scripts.sil.org/OFL)) |
|
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 322 B |
Before Width: | Height: | Size: 666 B |
Before Width: | Height: | Size: 15 KiB |
@ -1 +0,0 @@ |
|||||
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} |
|
@ -1,92 +0,0 @@ |
|||||
filterSelection("all", "None"); |
|
||||
function filterSelection(c, name, id) { |
|
||||
resetDropDownButtons(); |
|
||||
var i; |
|
||||
var button = document.getElementById(id); |
|
||||
if(button){ |
|
||||
button.innerText = name; |
|
||||
addClass(button, "activebtn"); |
|
||||
} |
|
||||
var alldistribusis = document.getElementsByClassName("filter"); |
|
||||
if (c == "all") { |
|
||||
for (i = 0; i < alldistribusis.length; i++) { |
|
||||
addClass(alldistribusis[i], "show"); |
|
||||
} |
|
||||
} |
|
||||
else { |
|
||||
for (i = 0; i < alldistribusis.length; i++) { |
|
||||
removeClass(alldistribusis[i], "show"); |
|
||||
if (alldistribusis[i].className.indexOf(c) > -1) { |
|
||||
addClass(alldistribusis[i], "show"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function resetDropDownButtons(){ |
|
||||
document.getElementById("Year").innerText = "Year"; |
|
||||
document.getElementById("Category").innerText = "Category"; |
|
||||
allactivebuttons = document.getElementsByClassName("activebtn"); |
|
||||
for(var i = 0;allactivebuttons.length; i++) { |
|
||||
removeClass(allactivebuttons[i], "activebtn"); |
|
||||
} |
|
||||
} |
|
||||
function addClass(element, name) { |
|
||||
var i, arr1, arr2; |
|
||||
arr1 = element.className.split(" "); |
|
||||
arr2 = name.split(" "); |
|
||||
for (i = 0; i < arr2.length; i++) { |
|
||||
if (arr1.indexOf(arr2[i]) == -1) {element.className += " " + arr2[i];} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function removeClass(element, name) { |
|
||||
var i, arr1, arr2; |
|
||||
arr1 = element.className.split(" "); |
|
||||
arr2 = name.split(" "); |
|
||||
for (i = 0; i < arr2.length; i++) { |
|
||||
while (arr1.indexOf(arr2[i]) > -1) { |
|
||||
arr1.splice(arr1.indexOf(arr2[i]), 1); |
|
||||
} |
|
||||
} |
|
||||
element.className = arr1.join(" "); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
let searchInput = document.getElementById('tagsearch'); |
|
||||
let timeout = null; |
|
||||
// Listen for keystroke events
|
|
||||
searchInput.addEventListener('keyup', function (e) { |
|
||||
// Clear the timeout if it has already been set.
|
|
||||
clearTimeout(timeout); |
|
||||
// Make a new timeout set to go off in 1000ms (1 second)
|
|
||||
timeout = setTimeout(function () { |
|
||||
console.log('Input Value:', searchInput.value); |
|
||||
if (searchInput.value.length > 2) { |
|
||||
searchTags(searchInput.value); |
|
||||
} else { |
|
||||
clearSearchTags(); |
|
||||
} |
|
||||
}, 1000); |
|
||||
}); |
|
||||
|
|
||||
function searchTags(searchInput) { |
|
||||
let tag_ele = document.getElementsByClassName('tags'); |
|
||||
for (var i = 0; i < tag_ele.length; ++i) { |
|
||||
let searchText = searchInput.toLowerCase().trim(); |
|
||||
let tagtext = tag_ele[i].innerText.toLowerCase(); |
|
||||
if(searchText.includes(tagtext) || tagtext.includes(searchText)) { |
|
||||
addClass(tag_ele[i], "searched"); |
|
||||
} |
|
||||
else { |
|
||||
removeClass(tag_ele[i], "searched"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function clearSearchTags() { |
|
||||
let tag_ele = document.getElementsByClassName('tags'); |
|
||||
for (var i = 0; i < tag_ele.length; ++i) { |
|
||||
removeClass(tag_ele[i], "searched"); |
|
||||
} |
|
||||
} |
|
@ -1,19 +0,0 @@ |
|||||
function update() { |
|
||||
|
|
||||
var html = document.getElementById("html"); |
|
||||
var css = document.getElementById("css"); |
|
||||
var code = document.getElementById("code").contentWindow.document; |
|
||||
|
|
||||
document.body.onkeyup = function(){ |
|
||||
code.open(); |
|
||||
code.writeln(html.value+"<style>"+css.value+"</style>"); |
|
||||
code.close(); |
|
||||
}; |
|
||||
document.addEventListener("DOMContentLoaded", function(){ |
|
||||
code.open(); |
|
||||
code.writeln(html.value+"<style>"+css.value+"</style>"); |
|
||||
code.close(); |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
update(); |
|
@ -1,25 +0,0 @@ |
|||||
console.log("everything is still smooth") |
|
||||
|
|
||||
function scrollToTheme() { |
|
||||
var uploadsuccessful = document.getElementById("uploadsuccessful"); |
|
||||
if(uploadsuccessful){ |
|
||||
const theme = document.getElementById('theme') |
|
||||
theme.scrollIntoView({ behavior: 'smooth', block: 'start' }); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function scrollToLaunch() { |
|
||||
var cssSelected = document.getElementById("cssSelected"); |
|
||||
if(cssSelected){ |
|
||||
const launch = document.getElementById('launch') |
|
||||
launch.scrollIntoView({ behavior: 'smooth', block: 'end' }); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
document.addEventListener("DOMContentLoaded", scrollToTheme); |
|
||||
document.addEventListener("DOMContentLoaded", scrollToLaunch); |
|
||||
|
|
||||
// function(e) {
|
|
||||
// (e.keyCode === 13 || e.keyCode === 32) && $(this).trigger("click")
|
|
||||
// }
|
|
Before Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 4.5 KiB |