diff --git a/.gitignore b/.gitignore index 90d3926..f8406cf 100644 --- a/.gitignore +++ b/.gitignore @@ -107,4 +107,7 @@ venv.bak/ .idea/ # Database. let it always be empty -*.db \ No newline at end of file +*.db + +# CSS assets +all-min.css \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py index 08e17c4..4ca07e9 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,10 +1,15 @@ -from flask import Flask, request from database import Database +from flask import Flask, request from flask_socketio import SocketIO +from flask_assets import Environment +from app.css_asset import css_asset app = Flask(__name__) app.config['SECRET_KEY'] = "qw75rs7fs5je5dd4s3sdf4s5liduf4dgg7fg6h5" +app.config['ASSETS_DEBUG'] = True socketio = SocketIO(app) +assets = Environment(app) +assets.register('css_all', css_asset) db = Database() from app.room_namespace import init_room_namespaces diff --git a/app/css_asset.py b/app/css_asset.py new file mode 100644 index 0000000..fad532c --- /dev/null +++ b/app/css_asset.py @@ -0,0 +1,17 @@ +from flask_assets import Bundle + +css_asset = Bundle( + 'css/vars.css', + 'css/buttons.css', + 'css/groom.css', + 'css/header.css', + 'css/info_block.css', + 'css/light.css', + 'css/room_block.css', + 'css/svg.css', + 'css/user_block.css', + 'css/wroom.css', + 'css/form.css', + filters='cssmin', + output='assets/all-min.css' + ) \ No newline at end of file diff --git a/app/help_functions.py b/app/help_functions.py new file mode 100644 index 0000000..a5f510e --- /dev/null +++ b/app/help_functions.py @@ -0,0 +1,30 @@ +from flask import request, render_template, session, redirect, url_for +from functools import wraps +from app import db + +def login_required(f): + @wraps(f) + def wrapped(*args, **kwargs): + if session.get('username') is None and request.method == 'GET': + return redirect(url_for('index')) + else: + return f(*args, **kwargs) + + return wrapped + + +def simple_render_template(url, **kwargs): + username = session.get('username') + ava_prefix = '/static/images/avatars/' + if username is not None: + user = db.users.get_by_name(username) + user_ava = ava_prefix + db.users.get_avatar(username) + else: + user = None + user_ava = None + return render_template(url, username=username, user_ava=user_ava, user=user, args=request.args, **kwargs) + +def redirect_with_args(url = None, **kwargs): + if url is None: + url = request.referrer.split('?')[0] + return redirect(url+'?'+ '&'.join([str(k)+'='+str(v) for k, v in kwargs.items()])) \ No newline at end of file diff --git a/app/room_namespace.py b/app/room_namespace.py index a88a9f0..3357102 100644 --- a/app/room_namespace.py +++ b/app/room_namespace.py @@ -1,5 +1,7 @@ from flask_socketio import Namespace, emit from app import db, socketio +from app.help_functions import simple_render_template +from flask import session def init_room_namespaces(): @@ -13,12 +15,14 @@ def on_connect(self): room_id = self.namespace[1:] if db.rooms.get(room_id): db.rooms.add_user(room_id) - emit('update', {'event': 'player_enter_or_leave', 'players': ','.join(db.rooms.get(room_id).users)}, - broadcast=True, namespace=self.namespace) + emit('update', {'event': 'player_enter_or_leave', 'data': + simple_render_template('rooms/_players_list.html', room=db.rooms.get(room_id))}, + broadcast = True, namespace = self.namespace) - def on_disconnect(self): + def on_disconnect_request(self): room_id = self.namespace[1:] if db.rooms.get(room_id): db.rooms.remove_user(room_id) - emit('update', {'event': 'player_enter_or_leave', 'players': ','.join(db.rooms.get(room_id).users)}, - broadcast=True, namespace=self.namespace) + emit('update', {'event': 'player_enter_or_leave', 'data': + simple_render_template('rooms/_players_list.html', room=db.rooms.get(room_id))}, + broadcast = True, namespace = self.namespace) \ No newline at end of file diff --git a/app/routes.py b/app/routes.py index e8bd5e4..bfb0d69 100644 --- a/app/routes.py +++ b/app/routes.py @@ -3,43 +3,12 @@ from labyrinth_engine import load_map from app import app, db, socketio from flask_socketio import emit -from functools import wraps +from app.help_functions import * import random import string import json - -''' -help functions -''' - - -def login_required(f): - @wraps(f) - def wrapped(*args, **kwargs): - if session.get('username') is None: - return redirect(url_for('index')) - else: - return f(*args, **kwargs) - - return wrapped - - -def simple_render_template(url, **kwargs): - username = session.get('username') - ava_prefix = '/static/images/avatars/' - if username is not None: - user = db.users.get_by_name(username) - user_ava = ava_prefix + db.users.get_avatar(username) - else: - user = None - user_ava = None - return render_template(url, username=username, user_ava=user_ava, user=user, args=request.args, **kwargs) - - -def redirect_with_args(url=None, **kwargs): - if url is None: - url = request.referrer.split('?')[0] - return redirect(url+'?' + '&'.join([str(k)+'='+str(v) for k, v in kwargs.items()])) +import time +import os @app.route('/') @@ -72,12 +41,22 @@ def logout(): @app.route('/profile') @login_required -def profile(): - return simple_render_template('profile/profile.html', form=request.args.get('form'), - result=request.args.get('result')) +def my_profile(): + return simple_render_template('profile/profile.html', form = request.args.get('form'), result = request.args.get('result')) + +@app.route('/profile/') +def profile(username): + if username == session.get('username'): + return redirect(url_for('my_profile')) + else: + profile_user = db.users.get_by_name(username) or '' + return simple_render_template('profile/profile.html', form = request.args.get('form'), result = request.args.get('result'), + profile_user=profile_user) + @app.route('/profile/change_login', methods=['POST', 'GET']) +@login_required def change_login(): if request.method == 'POST': new_login = request.form.get("new_login") @@ -91,6 +70,7 @@ def change_login(): @app.route('/profile/change_password', methods=['POST', 'GET']) +@login_required def change_password(): if request.method == 'POST': username = session['username'] @@ -108,6 +88,7 @@ def change_password(): @app.route('/profile/change_avatar', methods=['POST', 'GET']) +@login_required def change_avatar(): if request.method == 'POST': username = session['username'] @@ -149,8 +130,9 @@ def add_map(): return simple_render_template('add_map.html') -@app.route('/room_list/', methods=['POST', 'GET']) -def room_list(page): +@app.route('/room_list', methods=['POST', 'GET']) +@login_required +def room_list(): if request.method == 'POST': room_id = request.form.get('join_button') return redirect(url_for('waiting_room', room_id=room_id)) @@ -184,37 +166,47 @@ def waiting_room(room_id): if request.method == 'POST': event_type = request.headers.get('Event-Type') - if event_type == 'change_settings': - name = request.form.get('name') + if event_type == 'changed_settings': + name = request.form.get('roomname') description = request.form.get('description') map_id = request.form.get('map_id') + answer = [] if name: - db.rooms.set_name(room_id, name) + answer.append(db.rooms.set_name(room_id, name).info) if description: - db.rooms.set_description(room_id, description) + answer.append(db.rooms.set_description(room_id, description).info) if map_id: lr_map = db.maps.get(map_id).to_dict() else: lr_map = None - db.rooms.set_map(room_id, map_id) + if map_id: + answer.append(db.rooms.set_map(room_id, map_id).info) room = db.rooms.get(room_id) emit('update', {'event': 'change_settings', 'description': room.description, 'name': room.name, 'map': lr_map}, broadcast=True, namespace='/'+room_id) + return str(answer) elif event_type == 'start_game': - imagepath = '/static/images/button_images/' - map_id = db.rooms.get(room_id).map_id - labyrinth = load_map(db.maps.get(map_id).map, db.rooms.get(room_id).users, imagepath=imagepath) - db.lrm.add_labyrinth(room_id, labyrinth) - emit('update', {'event': 'start_game'}, - broadcast=True, namespace='/'+room_id) + imagepath='/static/images/button_images/' + # map_id = db.rooms.get(room_id).map_id + map_id = 1 + if db.maps.get(map_id).map: + labyrinth = load_map(db.maps.get(map_id).map, db.rooms.get(room_id).usernames, imagepath=imagepath) + db.lrm.add_labyrinth(room_id, labyrinth) + emit('update', {'event': 'start_game'}, + broadcast=True, namespace='/'+room_id) elif event_type == 'delete_room': emit('update', {'event': 'delete_room'}, broadcast=True, namespace='/'+room_id) db.rooms.delete(room_id) + elif event_type == 'get_players_list': + return simple_render_template('rooms/_player_list.html', room=db.rooms.get(room_id)) + + return '' + username = session.get('username') labyrinth = db.lrm.get_labyrinth(room_id) if labyrinth is not None and username in [user.get_username() for user in labyrinth.players_list]: @@ -222,11 +214,11 @@ def waiting_room(room_id): elif db.rooms.get(room_id) is None: return redirect(url_for('room_list', page=0)) else: - return simple_render_template('rooms/waiting_room.html', room=db.rooms.get(room_id), hide_header=True, - maps=db.maps.get_all()) + return simple_render_template('rooms/waiting_room.html', room=db.rooms.get(room_id), maps=db.maps.get_all()) @app.route('/game_room/', methods=['POST', 'GET']) +@login_required def game_room(room_id): username = session.get('username') labyrinth = db.lrm.get_labyrinth(room_id) @@ -263,3 +255,13 @@ def game_room(room_id): return simple_render_template('rooms/game_room.html', room=db.rooms.get(room_id), msgs=labyrinth.get_msgs(username)) + +@app.route('/templates/') +def get_template(template_name): + try: + f = open('app/templates/' + template_name, 'r') + data = f.read() + f.close() + return data + except: + return '' diff --git a/app/static/stylesheets/buttons.css b/app/static/css/buttons.css similarity index 100% rename from app/static/stylesheets/buttons.css rename to app/static/css/buttons.css diff --git a/app/static/stylesheets/form.css b/app/static/css/form.css similarity index 100% rename from app/static/stylesheets/form.css rename to app/static/css/form.css diff --git a/app/static/css/groom.css b/app/static/css/groom.css new file mode 100644 index 0000000..69e6606 --- /dev/null +++ b/app/static/css/groom.css @@ -0,0 +1,103 @@ +.game-room-header { + margin-left: 0% !important; + margin-right: 0% !important; + background-color: var(--clr-m1); + height: 54px; + font-family: Verdana; + text-align: center; + color: white; + font-size: 24pt; +} + +.game-player-condition { + position: absolute; + top: 20%; + width: 15%; + height: 20%; + font-family: Georgia; + border: 1px solid #ba55d3; + text-align: center; + left: 10%; +} + + + +.game-actions { + position: absolute; + bottom: 20%; + border: 1px solid #ba55d3; + height: 20%; + width: 15%; + left: 10%; +} + +.game-button { + position: absolute; + left: 10%; + top: 10%; + background-color: var(--clr-m1); + height: 33%; + border-radius: 10%; + -webkit-border-radius: 10%; + color: white; + width: 80%; + font-size: 16pt; +} + +.game-main { + position: absolute; + top: 20%; + height: 60%; + border: 1px solid #ba55d3; + width: 40%; + left: 30%; +} + +#log { + border-bottom: 1px solid #ba55d3; + position: relative; + height: 66%; + width: 100%; + overflow: auto; +} + +.input-wrapper { + border-bottom: 1px solid #ba55d3; + height: 5%; +} + +#input { + position: relative; + left: 15%; + top: 15%; +} + +.location { + position: absolute; + top: 20%; + width: 15%; + height: 20%; + font-family: Georgia; + border: 1px solid #ba55d3; + text-align: center; + right: 10%; +} + +.players { + position: absolute; + bottom: 20%; + border: 1px solid #ba55d3; + height: 20%; + width: 15%; + right: 10%; + overflow: auto; +} + +.player-block { + text-align: center; + margin-bottom: 7px; + color: #ff7e7e; + background: #efefef; + border: 1px solid #ba55d3; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.22); +} \ No newline at end of file diff --git a/app/static/css/header.css b/app/static/css/header.css new file mode 100644 index 0000000..de498d2 --- /dev/null +++ b/app/static/css/header.css @@ -0,0 +1,36 @@ +#logo { + position: relative; + float: left; + font-size: 30pt; + padding-left: 20px; + padding-right: 20px; + height: inherit; + font-family: var(--font-logo); + text-decoration: none; + color: #ffffff; + text-shadow: 0px 2px 0px #01010124; + background: var(--clr-m1); +} + +.header { + display: flexbox; + height: 50px; + background: var(--clr-m1); +} + +.header a:not(#logo) { + float: right; + margin: 10px; + color: #ffffff; + text-decoration: none; + font-family: var(--font-logo); + font-size: 14pt; + padding: 2px; + padding-left: 10px; + padding-right: 10px; +} + +.header a:hover:not(#logo) { + background: #fefefe24; + border-radius: 50px 50px 50px 50px; +} \ No newline at end of file diff --git a/app/static/stylesheets/info_block.css b/app/static/css/info_block.css similarity index 95% rename from app/static/stylesheets/info_block.css rename to app/static/css/info_block.css index 8559892..6d5ac4e 100644 --- a/app/static/stylesheets/info_block.css +++ b/app/static/css/info_block.css @@ -5,6 +5,7 @@ margin-bottom: 10px; padding-left: 10px; width: calc(100% -10px -2px); + max-width: 300px; } .succes-info-block { diff --git a/app/static/css/light.css b/app/static/css/light.css new file mode 100644 index 0000000..c15b817 --- /dev/null +++ b/app/static/css/light.css @@ -0,0 +1,222 @@ +html, body{ + background: rgb(249, 249, 249); + margin: 0; + height: 100%; +} + +body { + min-width: 1140px; + height: 100%; +} + +h2:first-child { + margin-top: 0; +} + +h1, h2 { + font-family: var(--font-head); +} + +.text-font { + font-family: var(--font-text); +} + +.logo-font { + font-family: var(--font-logo); +} + +.content { + width: calc(100% - 150px); + margin-top: 100px; + margin-right: 75px; + margin-left: 75px; +} + +.content td { + vertical-align: top; +} + +.content td:not(:last-child) { + padding-right: 100px; +} + +.content-main { + padding: 0; +} + +.sidebar-r { + width: 300px; + height: 100%; + padding-top: 0; + border-top-width: 0; +} + +.name-large { + text-decoration: none; + font-family: 'Roboto Slab', serif; + font-size: 20pt; +} + +.name-medium { + text-decoration: none; + font-family: 'Roboto Slab', serif; + font-size: 12pt; +} + +.user-ava-large { + width: 100px; + height: 100px; + vertical-align:bottom; + border: 1px solid black; +} + +.user-ava-medium { + width: 60px; + height: 60px; + vertical-align:bottom; + border: 1px solid black; +} + +.user-ava-small { + width: 40px; + height: 40px; + vertical-align:bottom; + border: 1px solid transparent; + border-radius: 3px; +} + +.navbar-sidebar { + position: absolute; + top: 20%; + left: 68%; + background: rgb(230, 230, 230); + height: 50%; + width: 10%; + padding: 2%; +} + + +.news { + font-size: 17pt; + text-align: justify; +} + +.header { + color: rgb(255, 128, 128); +} + +.create-room { + position: absolute; + top: 20%; + left: 60%; + width: 20%; + background: rgb(230, 230, 230); + color: rgb(128, 128, 255); + height: 50%; + padding-top: 5%; + padding-left: 1%; + padding-right: 1%; +} + +.undone { + color: grey; + font-style: italic; + font-family: var(--font-text); +} + +.btn { + display: block; + margin-top: 10px; + width: 100%; + display: block; + border: 1px solid black; + background: #ffffff; + font-size: 15pt; + + transition: 50ms; + transition-timing-function: ease-in-out; + -webkit-transition: 50ms; + -webkit-transition-timing-function: ease-in-out; + + cursor: pointer; +} + +.btn:hover { + background: var(--clr-m1); + color: white; +} + +.profile-clmn { + display: inline-block; + vertical-align: top; + margin-left: 40px; + margin-bottom: 60px; + width: 270px; +} + +#sidebar-content { + /*padding-left: 10px;*/ + max-height: calc(100vh - 180px); + overflow-y: auto; + overflow-x: hidden; +} + +#sidebar-content > div { + padding-left: 10px; + border-left: 5px solid var(--clr-m1); +} + + +.position-absolute { + position: absolute; +} + +.no-margin-top { + margin-top: 0; +} + +.self { + border-color: var(--clr-m1); + background: var(--clr-m1-l) +} + +.inline-flex-container { + display: -webkit-inline-flex; + display: inline-flex; + width: 100%; +} + +.inline-flex-container.space-between { + justify-conten: space-between; + -webkit-justify-content: space-between; +} + +.inline-flex-container.space-between > div:not(:first-child) { + margin-left: 20px; +} + +.clr-m1 { + color: var(--clr-m1); +} + +.time { + color: grey; + font-family: var(--font-text); + font-size: 10pt; +} + +.auto-width { + width: auto; +} + +.flex-row-reverse { + flex-direction: row-reverse; +} + +.flex-grow { + flex-grow: 1; +} + +.border-grey { + border-color: grey; +} \ No newline at end of file diff --git a/app/static/stylesheets/room_block.css b/app/static/css/room_block.css similarity index 80% rename from app/static/stylesheets/room_block.css rename to app/static/css/room_block.css index 6393bbd..526f49b 100644 --- a/app/static/stylesheets/room_block.css +++ b/app/static/css/room_block.css @@ -8,7 +8,11 @@ margin-bottom: 20px; overflow: hidden; height: 60px; - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.22); + cursor: pointer; +} + +.room-block:hover { + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.22); } .room-block-info { diff --git a/app/static/stylesheets/svg.css b/app/static/css/svg.css similarity index 100% rename from app/static/stylesheets/svg.css rename to app/static/css/svg.css diff --git a/app/static/css/user_block.css b/app/static/css/user_block.css new file mode 100644 index 0000000..853b032 --- /dev/null +++ b/app/static/css/user_block.css @@ -0,0 +1,40 @@ +.user-block { + padding-top:0; +} + +.user-block-small { + width: 200px; + border: 1px solid grey; + border-left-width: 0; + cursor: pointer; +} + +.user-block-small:hover { + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.22); + border-color: #828282; +} + +.user-block > div { + display: inline-block; + vertical-align: top; +} + +.user-block-info { + vertical-align: center; + margin-left: 10px; + /*background: var(--clr-m1-l)*/ +} + +.user-block-info-username { + margin-top: 10px; +} + +.user-block-small-info-username { + margin-top: 0; + color: var(--clr-m1); +} + +.user-block-small-ava { + border-left: 4px solid var(--clr-m1); + padding-left: 1px; +} diff --git a/app/static/stylesheets/vars.css b/app/static/css/vars.css similarity index 61% rename from app/static/stylesheets/vars.css rename to app/static/css/vars.css index 41e7a8e..d51d071 100644 --- a/app/static/stylesheets/vars.css +++ b/app/static/css/vars.css @@ -2,18 +2,22 @@ :root { /* green*/ - /*--clr-m1: #3bb34a;*/ + --clr-m1: #3bb34a; + --clr-m1-l: #d8f5db; /*purple*/ - --clr-m1: #ae0fff; + /*--clr-m1: #ae0fff;*/ + /*--clr-m1-l: #f1dafd;*/ /*orange*/ /*--clr-m1: #e65124;*/ + /*--clr-m1-l: #f3d0c6;*/ /*greyblue*/ /*--clr-m1: #4a94ab;*/ + /*--clr-m1-l: #d8e6ea;*/ /*yellow*/ --clr-c1: #ffdc4b; - --font-text: 'Marmelad', sans-serif ; + --font-text: Verdana, Geneva sans-serif; --font-head: 'Ubuntu', serif; --font-logo: 'Roboto Slab', serif; } \ No newline at end of file diff --git a/app/static/css/wroom.css b/app/static/css/wroom.css new file mode 100644 index 0000000..406074c --- /dev/null +++ b/app/static/css/wroom.css @@ -0,0 +1,90 @@ +.wroom-clmn-fixed { + margin: 0; +} + +.wroom-clmn-grow { + flex-grow: 1; + align-content: stretch; +} + +.wroom-chat-info { + margin-left: 5px; +} + +.wroom-chat-info p { + font-family: var(--font-text); + font-size: 12pt; + text-align: justify; + margin-top: 5px; + margin-right: 10px; +} + +.wroom-chat-msgs { + margin-top: 10px; + max-height: calc(100vh - 450px); + min-height: 200px; + overflow-y: scroll; +} + +.wroom-header { + margin-bottom: 20px; + justify-content: flex-end; +} + +.scroller::-webkit-scrollbar { + width: 5px; +} + +.scroller::-webkit-scrollbar-thumb { + background-color: var(--clr-m1); +} + + +.chat-input { + margin-top: 10px; + font-size: 12pt; + overflow-x: hidden; + font-family: var(--font-text); + border: 1px solid grey; + /*border-radius: 2px;*/ + word-break: break-all; + max-height: 120px; + padding-left: 4px; + padding-right: 4px; + line-height: 25px; +} + +.chat-input:focus { + outline: none; +} + +.chat-input.chat-input-show-placeholder:after { + content:attr(data-placeholder); + color: grey; +} + +.chat-input:focus:after { + content: ''; +} + +#reset_roomname { + margin-left: 10px; +} + + +.edit-icon { + fill: grey; +} + +.edit-icon:hover { + fill: var(--clr-m1-d); +} + +.input-on-focus { + border-width: 0; + background: inherit; +} + +.input-on-focus:focus { + outline: none; +} \ No newline at end of file diff --git a/app/static/js/game_room.js b/app/static/js/game_room.js deleted file mode 100644 index 5438f50..0000000 --- a/app/static/js/game_room.js +++ /dev/null @@ -1,191 +0,0 @@ -function xhrOpen(eventType) { - var xhr = new XMLHttpRequest(); - - xhr.open('POST', document.getElementById('data').dataset.post, false); - xhr.setRequestHeader('Event-Type', eventType); - xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); - - return xhr; -}; - -function makeTurnFromInput(event) { - if (event.keyCode == 13) { - var xhr = xhrOpen('turn'); - var turn = document.getElementById('input').value; - - xhr.send('turn=' + turn); - }; -} - -function makeTurn(turn) { - var xhr = xhrOpen('turn'); - xhr.send('turn=' + turn); -}; - -function getUpdate() { - var xhr = xhrOpen('update'); - xhr.send(); - console.log(xhr.responseText); - responseData = JSON.parse(xhr.responseText); - console.log(responseData); - - var log = document.getElementById('log'); - msg = document.createElement('p'); - msg.innerHTML = responseData.msg.join('
'); - log.appendChild(msg); - - clearBars(); - responseData.bars.forEach(function(entry) { - switch(entry.type) { - case 'common': - addCommonBar(entry.name, entry.value); - }; - }); - - var turnState = document.getElementById('your-turn'); - // 1 - my turn - // 2 - not my turn - // 0 - game ended - - if (responseData.game_state == 1) { - turnState.innerHTML = 'Твой ход'; - removeAllButtons(); - responseData.buttons.forEach(function(entry) { - switch(entry.type) { - case 'button': - addCommonButton(entry.turns[0], entry.image); - break; - case 'lbutton': - addListButton(entry.turns, entry.image, entry.turn_images); - break; - case 'dbutton': - addDirectionButton(entry.turns, entry.image, entry.turn_images); - break; - }; - }); - - } else if (responseData.game_state == 2) { - removeAllButtons(); - turnState.innerHTML = 'Подожди'; - } else if (responseData.game_state == 0) { - removeAllButtons(); - turnState.innerHTML = 'Игра окончена'; - } - - $('#log').scrollTop(1000000000); -}; - -// Interface - -// Buttons -function addCommonButton(turn, image) { - var button = document.createElement('div'); - - button.className = 'common-turn-button' - button.innerHTML = ''; - function mt() { - makeTurn(turn); - }; - button.onclick = mt; - - var buttonsBar = document.getElementById('buttons_bar'); - buttonsBar.appendChild(button); -}; - -function addListButton(turns, image, turn_images) { - var buttonsBar = document.getElementById('buttons_bar'); - - // var buttonContainer document.createElement('div'); - var button = document.createElement('div'); - var buttonImage = document.createElement('img'); - var turnsContainer = document.createElement('div'); - var buttonContainer = document.createElement('div'); - - button.className = 'list-game-button'; - turnsContainer.className = 'list-turns-container'; - buttonContainer.className = 'list-button-container'; - - buttonImage.setAttribute('src', image); - button.appendChild(buttonImage); - - buttonContainer.appendChild(button); - buttonContainer.appendChild(turnsContainer); - - for (var i = 0; i < turns.length; i++) { - var buttonTurn = document.createElement('div'); - - buttonTurn.className = 'list-turn-button'; - - var buttonTurnImage = document.createElement('img'); - buttonTurnImage.setAttribute('src', turn_images[i]); - - function mtg(k) { - function mt() { - makeTurn(turns[k]) - } - return mt - }; - buttonTurn.onclick = mtg(i); - - buttonTurn.appendChild(buttonTurnImage); - turnsContainer.appendChild(buttonTurn); - } - buttonsBar.appendChild(buttonContainer); -}; - -function addDirectionButton() { - var buttonsBar = document.getElementById('buttonsBar') -} - -function removeAllButtons() { - var buttonsBar = document.getElementById('buttons_bar'); - while (buttonsBar.firstChild) { - buttonsBar.removeChild(buttonsBar.firstChild); - }; -}; - - // Bars - -function addCommonBar(name, value) { - // Бомбы: 3
- resourceName = document.createElement('span'); - resourceName.classsName = 'resource-name'; - resourceName.innerHTML = name + ': '; - - resourceValue = document.createElement('span'); - resourceValue.className = 'resource-value'; - resourceValue.innerHTML = value; - - br = document.createElement('br'); - - var turnState = document.getElementById('turn-state'); - turnState.appendChild(resourceName); - turnState.appendChild(resourceValue); - turnState.appendChild(br); -} - -function clearBars() { - var turnState = document.getElementById('turn-state'); - turnState.innerHTML = ''; -} - -// When the document is loaded -function ready() { - getUpdate(); - var socket = io.connect('http://' + document.domain + ':' + location.port + '/' + document.getElementById('data').dataset.room_id); - socket.on('update', function(msg) { - switch (msg.event) { - case 'player_make_turn': - getUpdate(); - break; - }; - }); - socket.on('connect', function() { - socket.emit('player join', {'room_id': document.getElementById('data').dataset.room_id}); - }); -}; - -var turnInput = document.getElementById('input'); -turnInput.onkeydown = makeTurnFromInput; - -document.addEventListener("DOMContentLoaded", ready); diff --git a/app/static/js/toggle.js b/app/static/js/toggle.js deleted file mode 100644 index c2f0bd3..0000000 --- a/app/static/js/toggle.js +++ /dev/null @@ -1,62 +0,0 @@ -function getRealDisplay(elem) { - if (elem.currentStyle) { - return elem.currentStyle.display - } else if (window.getComputedStyle) { - var computedStyle = window.getComputedStyle(elem, null ) - - return computedStyle.getPropertyValue('display') - } -} - -function hide(el) { - if (!el.getAttribute('displayOld')) { - el.setAttribute("displayOld", el.style.display) - } - - el.style.display = "none" -} - -displayCache = {} - -function isHidden(el) { - var width = el.offsetWidth, height = el.offsetHeight, - tr = el.nodeName.toLowerCase() === "tr" - - return width === 0 && height === 0 && !tr ? - true : width > 0 && height > 0 && !tr ? false : getRealDisplay(el) -} - -function toggle(el) { - isHidden(el) ? show(el) : hide(el) -} - - -function show(el) { - - if (getRealDisplay(el) != 'none') return - - var old = el.getAttribute("displayOld"); - el.style.display = old || ""; - - if ( getRealDisplay(el) === "none" ) { - var nodeName = el.nodeName, body = document.body, display - - if ( displayCache[nodeName] ) { - display = displayCache[nodeName] - } else { - var testElem = document.createElement(nodeName) - body.appendChild(testElem) - display = getRealDisplay(testElem) - - if (display === "none" ) { - display = "block" - } - - body.removeChild(testElem) - displayCache[nodeName] = display - } - - el.setAttribute('displayOld', display) - el.style.display = display - } -} diff --git a/app/static/js/waiting_room.js b/app/static/js/waiting_room.js deleted file mode 100644 index 3e40fb6..0000000 --- a/app/static/js/waiting_room.js +++ /dev/null @@ -1,104 +0,0 @@ -function xhrOpen(eventType) { - var xhr = new XMLHttpRequest(); - - xhr.open('POST', document.getElementById('data').dataset.post); - xhr.setRequestHeader('Event-Type', eventType); - xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); - - return xhr; -}; - -//settings -function saveSettings() { - var xhr = xhrOpen('change_settings'); - - var description = document.getElementById('room_description').value; - var name = document.getElementById('room_name').value; - var mapId = document.getElementById('room_map').value; - - console.log(description, name, mapId); - - xhr.send('description='+description+'&name='+name+'&map_id='+mapId) -} - -function deleteRoom() { - var xhr = xhrOpen('delete_room'); - - xhr.send(); -}; - -function startGame() { - var xhr = xhrOpen('start_game'); - - xhr.send(); -}; - -console.log('http://' + document.domain + ':' + location.port + '/' + document.getElementById('data').dataset.room_id); -var socket = io.connect('http://' + document.domain + ':' + location.port + '/' + document.getElementById('data').dataset.room_id); -socket.on('update', function(msg) { - switch (msg.event) { - case 'change_settings': - var title = document.getElementById('title'); - var description = document.getElementById('description'); - var mapName = document.getElementById('map_name'); - var mapDescription = document.getElementById('map_description'); - - title.innerHTML = (msg.name); - description.innerHTML = ('Описание:
' + msg.description.replace(/\n/g, '
')); - mapName.innerHTML = ('Карта:' + msg.map.name) - mapDescription.innerHTML = ('Описание карты:
' + msg.map.description.replace(/\n/g, '
') ) - break; - - case 'player_enter_or_leave': - var player_list = document.getElementById('player_list'); - player_list.innerHTML = ''; - for (var i = 0; i < msg.players.split(',').length; i++) { - player_list.innerHTML += ('

' + msg.players.split(',')[i] + '

') - }; - break; - - case 'change_description': - var description = document.getElementById('description'); - - description.innerHTML = ('Description:
' + msg.description.replace(/\n/g, '
')); - break; - - case 'delete_room': - alert('Oups. Room was deleted'); - document.location.href = document.getElementById('data').dataset.delRedirect; - break; - - case 'start_game': - document.location.href = document.getElementById('data').dataset.startRedirect; - break; - }; -}); - -// var changeNameInput = document.getElementById('room_name'); -// changeNameInput.onkeydown = changeName; - -// var changeDescriptionInput = document.getElementById('room_description'); -// changeDescriptionInput.onkeydown = changeDescription; - -var saveSettingsButton = document.getElementById('save_settings_btn'); -saveSettingsButton.onclick = saveSettings; - -var startButton = document.getElementById('start_button'); -if (startButton) { - startButton.onclick = startGame; -} - -var deleteRoomButton = document.getElementById('delete_room_button'); -if (deleteRoomButton) { - deleteRoomButton.onclick = deleteRoom; -} - -var settingButton = document.getElementById('settings_button'); -var roomInfo = document.getElementById('room_info'); -var roomSettings = document.getElementById('room_settings'); -if (settingButton) { - settingButton.onclick = function() { - toggle(roomInfo); - toggle(roomSettings); - }; -} \ No newline at end of file diff --git a/app/static/stylesheets/light.css b/app/static/stylesheets/light.css deleted file mode 100644 index 3ff5a30..0000000 --- a/app/static/stylesheets/light.css +++ /dev/null @@ -1,378 +0,0 @@ -@import url('buttons.css'); -@import url('form.css'); -@import url('info_block.css'); -@import url('vars.css'); -@import url('svg.css'); -@import url('room_block.css'); - -html, body{ - background: rgb(249, 249, 249); - margin: 0; - height: 100%; -} - -body { - min-width: 1100px; - height: 100%; -} - -h2:first-child { - margin-top: 0; -} - -h1, h2 { - font-family: var(--font-head); -} - -.text-font { - font-family: var(--font-text); -} - -.logo-font { - font-family: var(--font-logo); -} - -.content { - width: calc(100% - 150px); - margin-top: 100px; - margin-right: 75px; - margin-left: 75px; - /*table-layout: fixed;*/ -} - -.content td { - vertical-align: top; -} - -.content td:not(:last-child) { - padding-right: 100px; -} - -.content-main { - padding: 0; -} - - -/* HEADER */ -#logo { - position: relative; - float: left; - font-size: 30pt; - padding-left: 20px; - padding-right: 20px; - text-decoration: none; - color: #ffffff; - text-shadow: 0px 2px 0px #00000024; - background: var(--clr-m1); - height: inherit; -} - -.header { - display: flexbox; - height: 50px; - background: var(--clr-m1); -} - -.header a:not(#logo) { - float: right; - margin: 10px; - color: #ffffff; - text-decoration: none; - font-size: 14pt; - padding: 2px; - padding-left: 10px; - padding-right: 10px; -} - -.header a:hover:not(#logo) { - background: #ffffff24; - border-radius: 50px 50px 50px 50px; -} - -.sidebar-r { - /*display: table;*/ - /*float: right;*/ - width: 300px; - height: 100%; - padding-top: 0; - border-top-width: 0; -} - - -.user-block { - padding-top:0; -} - -.user-block > div { - display: inline-block; - vertical-align: top; -} - -.user-block-info { - margin-left: 10px; -} - -.user-block-info-username { - margin-top: 10px; -} - -.name-large { - font-family: 'Roboto Slab', serif; - font-size: 20pt; - font-family: -} - -.user-ava-large { - width: 100px; - height: 100px; - vertical-align:bottom; - border: 1px solid black; -} - -.navbar-sidebar { - position: absolute; - top: 20%; - left: 68%; - background: rgb(230, 230, 230); - height: 50%; - width: 10%; - padding: 2%; -} - - -.news { - font-size: 20pt; - text-align: justify; -} - -.header { - color: rgb(255, 128, 128); -} - -.create-room { - position: absolute; - top: 20%; - left: 60%; - width: 20%; - background: rgb(230, 230, 230); - color: rgb(128, 128, 255); - height: 50%; - padding-top: 5%; - padding-left: 1%; - padding-right: 1%; -} - -.join_form { - position: relative; - float: right; - bottom: 20px; -} - -.action-link { - display: block; - text-decoration: None; - color: #ff7b7b; -} - -.action-link:hover { - background: rgb(174, 15, 255); - color: rgb(230, 230, 230); - cursor: pointer; -} - -.room-name { - width: 20%; - background: rgb(230, 230, 230); - position: absolute; - top: 0%; - left: 40%; - text-align: center; -} - -.player-list { - width: 33%; - position: absolute; - top: 0%; - left: 0%; - overflow: auto; -} - -.room-info { - width: 33%; - position: absolute; - top: 0%; - left: 33.5%; - color: #000000; - text-align: center; -} - -.room-settings { - display: none; - width: 33%; - position: absolute; - top: 0%; - left: 33.5%; -} - -.room-data-wrapper { - background: rgb(230, 230, 230); - color: rgb(128, 128, 255); - position: absolute; - top: 20%; - height: 50%; - width: 60%; - left: 20%; - font-family: Verdana; -} - -.room-actions { - position: absolute; - left: 67%; - width: 33%; -} - -/* Ниже - стили комнаты игры. Их надо будет перенести в новый дизайн целиком */ - -.game-room-header { - margin-left: 0% !important; - margin-right: 0% !important; - background-color: var(--clr-m1); - height: 54px; - font-family: Verdana; - text-align: center; - color: white; - font-size: 24pt; -} - -.game-player-condition { - position: absolute; - top: 20%; - width: 15%; - height: 20%; - font-family: Georgia; - border: 1px solid #ba55d3; - text-align: center; - left: 10%; -} - - - -.game-actions { - position: absolute; - bottom: 20%; - border: 1px solid #ba55d3; - height: 20%; - width: 15%; - left: 10%; -} - -.game-button { - position: absolute; - left: 10%; - top: 10%; - background-color: var(--clr-m1); - height: 33%; - border-radius: 10%; - -webkit-border-radius: 10%; - color: white; - width: 80%; - font-size: 16pt; -} - -.game-main { - position: absolute; - top: 20%; - height: 60%; - border: 1px solid #ba55d3; - width: 40%; - left: 30%; -} - -#log { - border-bottom: 1px solid #ba55d3; - position: relative; - height: 66%; - width: 100%; - overflow: auto; -} - -.input-wrapper { - border-bottom: 1px solid #ba55d3; - height: 5%; -} - -#input { - position: relative; - left: 15%; - top: 15%; -} - -.location { - position: absolute; - top: 20%; - width: 15%; - height: 20%; - font-family: Georgia; - border: 1px solid #ba55d3; - text-align: center; - right: 10%; -} - -.players { - position: absolute; - bottom: 20%; - border: 1px solid #ba55d3; - height: 20%; - width: 15%; - right: 10%; - overflow: auto; -} - -.player { - text-align: center; - margin-bottom: 7px; - color: #ff7e7e; - background: #efefef; - border: 1px solid #ba55d3; - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.22); -} - -.undone { - color: grey; - font-style: italic; -} - -.btn { - display: block; - margin-top: 10px; - width: 100%; - display: block; - border: 1px solid black; - background: #ffffff; - font-size: 15pt; - cursor: pointer; -} - -.btn:hover { - background: var(--clr-m1); - color: white; -} - -.profile-clmn { - display: inline-block; - vertical-align: top; - margin-left: 40px; - margin-bottom: 60px; - width: 270px; -} - -#sidebar-content { - border-left: 5px solid var(--clr-m1); - padding-left: 10px; -} - - -#sidebar-content.fixed { - position: fixed; - top: 30px; -} \ No newline at end of file diff --git a/app/templates/_login_block.html b/app/templates/_login_block.html index 057f993..3eb3310 100644 --- a/app/templates/_login_block.html +++ b/app/templates/_login_block.html @@ -4,10 +4,10 @@

Войти

- {% if args.form == 'login' and args.result == 'false' %}
Неверный логин или пароль!
{% endif %} + \ No newline at end of file diff --git a/app/templates/_user_block-small.html b/app/templates/_user_block-small.html new file mode 100644 index 0000000..6b00bf0 --- /dev/null +++ b/app/templates/_user_block-small.html @@ -0,0 +1,18 @@ +{% if not ub__user %} + {% set ub__user = user %} +{% endif %} +
+
+ {# #} + + {# #} +
+
+
+ {{ ub__user.username }} +
+
+ {{ ub__signature }} +
+
+
\ No newline at end of file diff --git a/app/templates/_user_block.html b/app/templates/_user_block.html index 5e51262..8d6cc51 100644 --- a/app/templates/_user_block.html +++ b/app/templates/_user_block.html @@ -1,12 +1,15 @@ +{% if not ub__user %} + {% set ub__user = user %} +{% endif %}
- {{ username }} + {{ ub__user.username }}
{% if not ub__hide_play_button %} diff --git a/app/templates/base.html b/app/templates/base.html index a81b6a7..a1aac23 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -2,7 +2,7 @@ {% block body %} {% if not hide_header %} -
+
{% if username == None %} Регистрация @@ -21,27 +21,33 @@ {% if show_sidebar_r %} - {% endif %} - + {% include 'js/groom.js' %} {% endblock %} \ No newline at end of file diff --git a/app/templates/rooms/room_list.html b/app/templates/rooms/room_list.html index dc3b2b8..84d6a18 100644 --- a/app/templates/rooms/room_list.html +++ b/app/templates/rooms/room_list.html @@ -6,7 +6,7 @@

Список комнат

{% for room in rooms %} -
+
{{ room.name }}
@@ -32,7 +32,7 @@

Список комнат

{% endblock %} -{% block sidebar_content %} +{% block ub__actions %} diff --git a/app/templates/rooms/waiting_room.html b/app/templates/rooms/waiting_room.html index b898c47..201a988 100644 --- a/app/templates/rooms/waiting_room.html +++ b/app/templates/rooms/waiting_room.html @@ -1,51 +1,114 @@ {% extends "base.html" %} {% set title = room.name %} -{% block content %} -
-
{{ room.name }}
-
-
- {% for player in room.users %} -

- {{ player }} -

- {% endfor %} -
-
-

Создана {{ room.date }} пользователем {{ room.creator }}

-

- {% if room.description != None %} - Описание: {% autoescape false %}{{ room.description.split('\n') | join('
')}}{% endautoescape %} - {% endif %} -

-

- Карта: карта не выбрана. -

-

- Описание карты: карта не выбрана. -

+{% block content %} +
+ {% if username == room.creator %} +
+ + + +
+
+ Вы может изменить имя просто нажав на него, или перейдя в настройки.Больше не показывать эту подсказку. +
+ {% else %} + {{ room.name }} + {% endif %} +
+
+
+ Игроки +
-
- Имя комнаты:
- Описание:
- Карта: -
- +
+
+ +
+
+
+ +
+
- +{% endblock %} + +{% set show_sidebar_r = true %} +{% set ub__hide_play_button = true %} +{% block sidebar_content %} +
+
+ Карта +
+
+
+ +
+

+ Описание карты. Lorem Ipsum - это текст-"рыба", часто используемый в печати и вэб-дизайне. Lorem Ipsum является стандартной "рыбой" для текстов на латинице с начала XVI века. В то время некий безымянный печатник создал большую коллекцию размеров и форм шрифтов, используя Lorem Ipsum для распечатки образцов. +

- -{% endblock %} \ No newline at end of file +{% endblock %} + +{% block ub__actions %} +
+ {% if username == room.creator %} + + + {% endif %} + + +
+{% endblock %} + + +{% block scripts %} + + + {% include 'js/contenteditable.js' %} + {% include 'js/onchange.js' %} + {% include 'js/wroom.js' %} + +{% endblock %} diff --git a/database/room.py b/database/room.py index 255c7cc..e774fcf 100644 --- a/database/room.py +++ b/database/room.py @@ -5,24 +5,23 @@ class Room: - def __init__(self, ID, name, creator, description, users, date, map_id): + def __init__(self, ID, name, creator, description, users, date, map_id, db): self.id = ID self.name = name self.description = description self.creator = creator - self.users = users_from_string(users) + self.usernames = usernames_from_string(users) + self.users = list(map(db.users.get_by_name, self.usernames)) self.date = date self.map_id = map_id def __str__(self): return 'id: {}; name: {}; date: {}'.format(self.id, self.name, self.date) - -def users_from_string(users_string): +def usernames_from_string(users_string): return json.loads(users_string) - -def users_to_string(users): +def usernames_to_string(users): return json.dumps(users) @@ -49,7 +48,7 @@ def get(self, ID): if room is None: return None - return Room(*room) + return Room(*room, self.db) def delete(self, ID): if self.get(ID) is None: @@ -68,7 +67,7 @@ def set_name(self, ID, name): 'Name contains invalid characters') self.execute('UPDATE rooms SET name=? WHERE id=?', [name, ID]) - return DBAnswer(True, OK, '') + return DBAnswer(True, OK, 'Room name successfully set') def set_description(self, ID, description): # TODO Answer @@ -85,13 +84,13 @@ def add_user(self, ID, username=None): return DBAnswer(False, DBError.IncorrectUser, 'Can\'t add nonexistent user into room') - users = self.get(ID).users + users = self.get(ID).usernames if username in users: return DBAnswer(False, DBError.IncorrectUser, 'This user already in this room') users.append(username) - users_string = users_to_string(users) + users_string = usernames_to_string(users) self.execute('UPDATE rooms SET users=? WHERE id=?', [users_string, ID]) return DBAnswer(True, OK, 'User successfully added') @@ -104,14 +103,14 @@ def remove_user(self, ID, username=None): return DBAnswer(False, DBError.RoomNotExist, 'Can\'t remove user from nonexistent room') - users = self.get(ID).users + usernames = self.get(ID).usernames - if username not in users: + if username not in usernames: return DBAnswer(False, DBError.IncorrectUser, 'This user not in this room') - users.remove(username) - users_string = users_to_string(users) - self.execute('UPDATE rooms SET users=? WHERE id=?', [users_string, ID]) + usernames.remove(username) + usernames_string = usernames_to_string(usernames) + self.execute('UPDATE rooms SET users=? WHERE id=?', [usernames_string, ID]) return DBAnswer(True, OK, 'User successfully removed') @@ -125,3 +124,4 @@ def page_by_page(self, rooms_on_page): def set_map(self, ID, map_id): # TODO Answer self.execute('UPDATE rooms SET map_id=? WHERE id=?', [map_id, ID]) + return DBAnswer(True, OK, 'Map successfully set') diff --git a/database/user.py b/database/user.py index f401129..2014ea0 100644 --- a/database/user.py +++ b/database/user.py @@ -12,6 +12,7 @@ def __init__(self, ID, username, password_hash, avatar): self.username = username self.password_hash = password_hash self.avatar = avatar + self.avatar_path = '/static/images/avatars/' + avatar def __str__(self): return 'id: {}; username: {}; password_hash: {};'.format( diff --git a/labyrinth_engine/labyrinth.py b/labyrinth_engine/labyrinth.py index 46dab2e..3c6dc37 100644 --- a/labyrinth_engine/labyrinth.py +++ b/labyrinth_engine/labyrinth.py @@ -58,6 +58,9 @@ def __init__(self, locations, items, creatures, players, adjacence_list, setting self.turns_log = [] self.msgs_log = {} + def __str__(self): + return ''.format(self.players_list) + # Сообщения. def send_msg(self, msg, player, priority=0): clear_list = {player.get_username(): [] for player in self.players_list}