add solution word to client
This commit is contained in:
parent
aca27cdae2
commit
c0f5f3f785
@ -1,579 +1,27 @@
|
||||
import { html, css, LitElement, unsafeCSS } from 'https://unpkg.com/lit-element/lit-element.js?module';
|
||||
import './infoBox.js'
|
||||
|
||||
const gridType = {
|
||||
EMPTY: 0,
|
||||
HINT: 1,
|
||||
LETTER: 2
|
||||
};
|
||||
|
||||
export class GridElement {
|
||||
constructor(x, y, grid, type) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.type = type
|
||||
this.grid = grid;
|
||||
|
||||
|
||||
this.gridLetter = null;
|
||||
this.hintBox = null;
|
||||
this.emptyBox = null;
|
||||
}
|
||||
|
||||
setGridLetter(gridLetter) {
|
||||
this.gridLetter = gridLetter;
|
||||
}
|
||||
|
||||
getGridLetter() {
|
||||
return this.gridLetter;
|
||||
}
|
||||
|
||||
setHintBox(hintBox) {
|
||||
this.hintBox = hintBox;
|
||||
}
|
||||
|
||||
getHintBox() {
|
||||
return this.hintBox;
|
||||
}
|
||||
|
||||
setEmptyBox(emptyBox) {
|
||||
this.emptyBox = emptyBox;
|
||||
}
|
||||
|
||||
getEmptyBox() {
|
||||
return this.emptyBox;
|
||||
}
|
||||
|
||||
getGridType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class GridBox extends LitElement {
|
||||
static get styles() {
|
||||
return css`
|
||||
input[type='text'] {
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
text-align: center;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
border-width: 0.2 em;
|
||||
background-color: black;
|
||||
outline: none;
|
||||
color: transparent;
|
||||
text-shadow: 0 0 1 black;
|
||||
font-size: 2em;
|
||||
user-select: none;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
x: { type: Number },
|
||||
y: { type: Number },
|
||||
grid_id: { type: String }
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.gridElement = null;
|
||||
this.grid_id = null;
|
||||
this.crosswordGrid = null;
|
||||
this.isRevealed = false;
|
||||
}
|
||||
|
||||
update(props) {
|
||||
super.update();
|
||||
if (props.has("grid_id")) {
|
||||
this.updateGridElement();
|
||||
}
|
||||
}
|
||||
|
||||
updateGridElement() {
|
||||
if (this.grid_id != null) {
|
||||
|
||||
this.crosswordGrid = document.getElementById(this.grid_id);
|
||||
this.gridElement = this.crosswordGrid.getGridElement(this.x, this.y);
|
||||
this.gridElement.setEmptyBox(this);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<input type="text" id="${this.x}-${this.y}" maxlength="1" value="" disabled></input>`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('grid-box', GridBox);
|
||||
|
||||
|
||||
export class GridLetter extends GridBox {
|
||||
static get styles() {
|
||||
return css`
|
||||
.letter {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
input[type='text'] {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
text-align: center;
|
||||
border-style: solid;
|
||||
border-width: 0.2 em;
|
||||
border-color: black;
|
||||
outline: none;
|
||||
color: black;
|
||||
font-size: 2em;
|
||||
user-select: none;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
input[type='text']:focus {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
background-color: LightYellow;
|
||||
border-color: Yellow;
|
||||
|
||||
}
|
||||
|
||||
input[type='text']:read-only {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
background-color: LightGreen;
|
||||
}
|
||||
|
||||
input[type='text']:selection {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.circle {
|
||||
margin: auto;
|
||||
text-align: left;
|
||||
vertical-align: bottom;
|
||||
bottom: 0;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
border: 0.1em solid lightGray;
|
||||
color: black;
|
||||
height: 80%;
|
||||
width: 80%;
|
||||
border-radius:50%;
|
||||
-moz-border-radius:50%;
|
||||
-webkit-border-radius:50%;
|
||||
background: transparent;
|
||||
|
||||
}
|
||||
|
||||
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
letter: { type: String },
|
||||
x: { type: Number },
|
||||
y: { type: Number },
|
||||
grid_id: { type: String }
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._value = '';
|
||||
this.is_focused = false;
|
||||
this.firstKeydownOver = true;
|
||||
this.solutionIndex = -1;
|
||||
this.lastFocusedX = -1;
|
||||
this.lastFocusedY = -1;
|
||||
this.updateGridElement();
|
||||
}
|
||||
|
||||
|
||||
|
||||
set value(value) {
|
||||
const oldValue = this.value;
|
||||
console.log("update value to: " + value);
|
||||
|
||||
this._value = value;
|
||||
this.requestUpdate('value', oldValue);
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this._value;
|
||||
}
|
||||
|
||||
onInput(e) {
|
||||
|
||||
|
||||
if (!this.is_focused) {
|
||||
e.handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
//if (this.key_delay){
|
||||
// var el = this.shadowRoot.getElementById(`${this.x}-${this.y}`);
|
||||
// el.value = this.value;
|
||||
// el.select();
|
||||
// e.handled = true;
|
||||
// return;
|
||||
//}
|
||||
|
||||
var oldVal = this.value;
|
||||
this.value = e.target.value
|
||||
|
||||
if (this.revealed) {
|
||||
this.value = oldVal;
|
||||
this.crosswordGrid.focusNextCell(this.x, this.y);
|
||||
return
|
||||
}
|
||||
|
||||
if (this.value.length > 1) {
|
||||
this.value = str.slice(0);
|
||||
e.target.value = this.value
|
||||
e.handled = true;
|
||||
}
|
||||
|
||||
if (!e.handled && this.value === " ") {
|
||||
this.value = "";
|
||||
e.target.value = "";
|
||||
e.handled = true;
|
||||
}
|
||||
|
||||
if (!e.handled && this.value.length === 0) {
|
||||
this.crosswordGrid.focusPrevCell(this.x, this.y, this.lastFocusedX, this.lastFocusedY);
|
||||
e.handled = true;
|
||||
}
|
||||
else if (!e.handled && this.value.length === 1) {
|
||||
this.crosswordGrid.focusNextCell(this.x, this.y);
|
||||
e.handled = true;
|
||||
}
|
||||
else {
|
||||
this.focus();
|
||||
}
|
||||
|
||||
if (oldVal != this.value) {
|
||||
this.crosswordGrid.sendMessage({
|
||||
'type': 'update',
|
||||
'x': this.x,
|
||||
'y': this.y,
|
||||
'letter': this.value
|
||||
})
|
||||
}
|
||||
|
||||
if (!e.handled) {
|
||||
|
||||
e.target.select();
|
||||
|
||||
e.handled = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onKeyup(e) {
|
||||
if (!this.firstKeydownOver) {
|
||||
e.handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var key = e.key;
|
||||
if (this.value.length == 0 || this.revealed) {
|
||||
if (key === 'Backspace' || key === 'Delete') {
|
||||
this.crosswordGrid.focusPrevCell(this.x, this.y, this.lastFocusedX, this.lastFocus);
|
||||
e.handled = true;
|
||||
return
|
||||
|
||||
}
|
||||
else if (this.revealed) {
|
||||
this.crosswordGrid.focusNextCell(this.x, this.y);
|
||||
e.handled = true;
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onKeydown(e) {
|
||||
|
||||
this.firstKeydownOver = true;
|
||||
|
||||
if (!this.is_focused) {
|
||||
e.handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var key = e.key;
|
||||
|
||||
console.log(key);
|
||||
|
||||
|
||||
// check arrow keys
|
||||
if (key === "ArrowLeft") {
|
||||
// left
|
||||
this.crosswordGrid.focusPrevCellHorizontal(this.x, this.y);
|
||||
e.handled = true;
|
||||
return;
|
||||
}
|
||||
else if (key === "ArrowUp") {
|
||||
// up
|
||||
this.crosswordGrid.focusPrevCellVertical(this.x, this.y);
|
||||
e.handled = true;
|
||||
return;
|
||||
|
||||
}
|
||||
else if (key === "ArrowRight") {
|
||||
//right
|
||||
this.crosswordGrid.focusNextCellHorizontal(this.x, this.y);
|
||||
e.handled = true;
|
||||
return;
|
||||
}
|
||||
else if (key === "ArrowDown") {
|
||||
//down
|
||||
this.crosswordGrid.focusNextCellVertical(this.x, this.y);
|
||||
e.handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
e.target.select();
|
||||
|
||||
|
||||
}
|
||||
|
||||
onFocus(e) {
|
||||
e.target.select();
|
||||
this.is_focused = true;
|
||||
|
||||
this.crosswordGrid.updateHints(this.x, this.y);
|
||||
}
|
||||
|
||||
focus(lastX = -1, lastY = -1) {
|
||||
if (lastX > 0 && lastY > 0) {
|
||||
this.lastFocusedX = lastX;
|
||||
this.lastFocusedY = lastY;
|
||||
}
|
||||
var element = this.shadowRoot.getElementById(`${this.x}-${this.y}`);
|
||||
this.firstKeydownOver = false;
|
||||
element.focus();
|
||||
|
||||
|
||||
}
|
||||
|
||||
blur() {
|
||||
var element = this.shadowRoot.getElementById(`${this.x}-${this.y}`);
|
||||
element.blur();
|
||||
this.is_focused = false;
|
||||
}
|
||||
|
||||
updateGridElement() {
|
||||
super.updateGridElement()
|
||||
|
||||
if (this.grid_id != null) {
|
||||
|
||||
this.gridElement.setGridLetter(this);
|
||||
this.solutionIndex = this.crosswordGrid.getSolutionIndex(this.x, this.y)
|
||||
}
|
||||
}
|
||||
|
||||
updateLetter(letter, revealed) {
|
||||
this.value = letter;
|
||||
if (revealed) {
|
||||
console.log("rec")
|
||||
this.shadowRoot.getElementById(`${this.x}-${this.y}`).readOnly = true;
|
||||
this.blur();
|
||||
this.revealed = true;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
this.updateGridElement();
|
||||
|
||||
var solutionOverlay = html``;
|
||||
|
||||
if (this.solutionIndex >= 0) {
|
||||
solutionOverlay = html`
|
||||
<div class="circle">${this.solutionIndex}</div>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return html`
|
||||
<div class="letter">
|
||||
<input type="text" id="${this.x}-${this.y}" value="${this.value}" @input=${this.onInput} @focus=${this.onFocus} @keydown=${this.onKeydown} @keyup=${this.onKeyup} autocomplete="off"></input>
|
||||
${solutionOverlay}
|
||||
</div>
|
||||
|
||||
`;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('grid-letter', GridLetter);
|
||||
|
||||
|
||||
|
||||
export class HintBox extends GridBox {
|
||||
|
||||
static get styles() {
|
||||
|
||||
return css`
|
||||
|
||||
.hint {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
|
||||
.triangle-down {
|
||||
position: relative;
|
||||
top: 3em;
|
||||
left: 1em;
|
||||
z-index: 10;
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 0.75em solid transparent;
|
||||
border-right: 0.75em solid transparent;
|
||||
border-top: 1.3em solid #555;
|
||||
|
||||
}
|
||||
|
||||
.triangle-right {
|
||||
position: relative;
|
||||
top: 1em;
|
||||
left: 3em;
|
||||
z-index: 10;
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 0.75em solid transparent;
|
||||
border-bottom: 0.75em solid transparent;
|
||||
border-left: 1.3em solid #555;
|
||||
|
||||
}
|
||||
|
||||
input[type='text']{
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
text-align: center;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
border-width: 0.2 em;
|
||||
background-color: #555;
|
||||
outline: none;
|
||||
color: white;
|
||||
text-shadow: 0 0 1 black;
|
||||
font-size: 2em;
|
||||
user-select: none;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
x: { type: Number },
|
||||
y: { type: Number },
|
||||
grid_id: { type: String },
|
||||
horizontal_hint: { type: String },
|
||||
vertical_hint: { type: String },
|
||||
hint_id: { type: String }
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.vertical_hint = "";
|
||||
this.horizontal_hint = "";
|
||||
this.hint_id = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
getVerticalHint() {
|
||||
return this.vertical_hint;
|
||||
}
|
||||
|
||||
getHorizontalHint() {
|
||||
return this.horizontal_hint;
|
||||
}
|
||||
|
||||
hasVerticalHint() {
|
||||
return this.vertical_hint.length > 0;
|
||||
}
|
||||
|
||||
hasHorizontalHint() {
|
||||
return this.horizontal_hint.length > 0;
|
||||
}
|
||||
|
||||
updateGridElement() {
|
||||
super.updateGridElement()
|
||||
|
||||
if (this.grid_id != null) {
|
||||
|
||||
this.gridElement.setHintBox(this);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
this.updateGridElement();
|
||||
|
||||
var verticalArrow = html``;
|
||||
var horizontalArrow = html``;
|
||||
|
||||
if (this.hasVerticalHint()) {
|
||||
verticalArrow = html`<div class="triangle-down"></div>`;
|
||||
}
|
||||
|
||||
if (this.hasHorizontalHint()) {
|
||||
horizontalArrow = html`<div class="triangle-right"></div>`;
|
||||
}
|
||||
|
||||
return html`
|
||||
<div class="hint">
|
||||
<input type="text" id="${this.x}-${this.y}" value="${this.hint_id}" disabled></input>
|
||||
${verticalArrow}
|
||||
${horizontalArrow}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hint-box', HintBox);
|
||||
import {GridElement, GridLetter, GridBox, gridType} from './gridBoxes.js'
|
||||
import './solutionBox.js'
|
||||
|
||||
export class CrosswordGrid extends LitElement {
|
||||
static get styles() {
|
||||
return css`
|
||||
body {
|
||||
background-color: black;
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
|
||||
table {
|
||||
position: relative;
|
||||
top: 5em;
|
||||
top: 7em;
|
||||
border-spacing: 0px;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
border-width: 1em;
|
||||
text-align: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
td {
|
||||
@ -588,7 +36,7 @@ export class CrosswordGrid extends LitElement {
|
||||
width: { type: Number },
|
||||
height: { type: Number },
|
||||
infobox_id: { type: String }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
@ -607,7 +55,17 @@ export class CrosswordGrid extends LitElement {
|
||||
|
||||
this.serverConnection = null;
|
||||
|
||||
this.solution_locations = null;
|
||||
this.solution_locations = [];
|
||||
|
||||
this.solutionBox = null;
|
||||
|
||||
this.gridCount = 0;
|
||||
}
|
||||
|
||||
setSolutionBox(solBox) {
|
||||
this.solutionBox = solBox;
|
||||
if (self.solution_locations)
|
||||
solBox.length = self.solution_locations.length;
|
||||
}
|
||||
|
||||
getSolutionIndex(x, y) {
|
||||
@ -626,9 +84,15 @@ export class CrosswordGrid extends LitElement {
|
||||
this.grid = [];
|
||||
const width = json_grid.w;
|
||||
const height = json_grid.h;
|
||||
this.gridCount += 1;
|
||||
|
||||
this.solution_locations = json_grid.solution
|
||||
|
||||
if (this.solutionBox)
|
||||
this.solutionBox.length = this.solution_locations.length;
|
||||
this.solutionBox.requestUpdate();
|
||||
console.log("update box");
|
||||
|
||||
var y;
|
||||
var x;
|
||||
|
||||
@ -659,6 +123,10 @@ export class CrosswordGrid extends LitElement {
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
this.requestUpdate();
|
||||
|
||||
|
||||
}
|
||||
|
||||
focusNextCellHorizontal(x, y) {
|
||||
@ -813,11 +281,11 @@ export class CrosswordGrid extends LitElement {
|
||||
renderCell(el) {
|
||||
switch (el.type) {
|
||||
case gridType.LETTER: {
|
||||
return html`<grid-letter grid_id='${this.id}' x='${el.x}' y='${el.y}' ></grid-letter>`;
|
||||
return html`<grid-letter grid_id='${this.id}' gridCount='${this.gridCount}' x='${el.x}' y='${el.y}' ></grid-letter>`;
|
||||
|
||||
}
|
||||
case gridType.EMPTY: {
|
||||
return html`<grid-box grid_id='${this.id}' x='${el.x}' y='${el.y}' ></grid-box>`;
|
||||
return html`<grid-box grid_id='${this.id}' gridCount='${this.gridCount}' x='${el.x}' y='${el.y}' ></grid-box>`;
|
||||
|
||||
}
|
||||
case gridType.HINT: {
|
||||
@ -834,7 +302,7 @@ export class CrosswordGrid extends LitElement {
|
||||
this.num_hints += 1;
|
||||
|
||||
return html`
|
||||
<hint-box grid_id='${this.id}' x='${el.x}' y='${el.y}' horizontal_hint='${horizontal_hint}' vertical_hint='${vertical_hint}' hint_id=${this.num_hints}></hint-box>
|
||||
<hint-box grid_id='${this.id}' gridCount='${this.gridCount}' x='${el.x}' y='${el.y}' horizontal_hint='${horizontal_hint}' vertical_hint='${vertical_hint}' hint_id=${this.num_hints}></hint-box>
|
||||
`;
|
||||
|
||||
}
|
||||
@ -847,6 +315,13 @@ export class CrosswordGrid extends LitElement {
|
||||
console.error("received bad message");
|
||||
}
|
||||
cell.getGridLetter().updateLetter(letter, revealed)
|
||||
if (cell.getGridLetter().solutionIndex >= 0) {
|
||||
this.setSolutionLetter(
|
||||
cell.getGridLetter().solutionIndex,
|
||||
letter,
|
||||
revealed
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
registerServerConnection(connection) {
|
||||
@ -860,13 +335,32 @@ export class CrosswordGrid extends LitElement {
|
||||
this.serverConnection.sendMessage(msg)
|
||||
}
|
||||
|
||||
setSolutionLetter(solutionNumber, letter, revealed = false){
|
||||
this.solutionBox.setLetter(solutionNumber, letter, revealed);
|
||||
const x = this.solution_locations[solutionNumber][1];
|
||||
const y = this.solution_locations[solutionNumber][0];
|
||||
console.log("update solution letter");
|
||||
this.grid[y][x].getGridLetter().value = letter;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
render() {
|
||||
this.num_hints = 0;
|
||||
console.log("refreshing grid");
|
||||
|
||||
var solution_length = 0;
|
||||
if (this.solution_locations){
|
||||
solution_length = this.solution_locations.length;
|
||||
}
|
||||
|
||||
|
||||
return html`
|
||||
<table>
|
||||
${this.grid.map((row) => html`<tr>${row.map((el) => html`<td>${this.renderCell(el)}</td>`)}</tr>`)}
|
||||
</table>
|
||||
<solution-box id="solution-box", grid_id="${this.id}", length="${solution_length}" ></solution-box>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
569
js_client/gridBoxes.js
Normal file
569
js_client/gridBoxes.js
Normal file
@ -0,0 +1,569 @@
|
||||
import { html, css, LitElement, unsafeCSS } from 'https://unpkg.com/lit-element/lit-element.js?module';
|
||||
import './infoBox.js'
|
||||
|
||||
export const gridType = {
|
||||
EMPTY: 0,
|
||||
HINT: 1,
|
||||
LETTER: 2
|
||||
};
|
||||
|
||||
export class GridElement {
|
||||
constructor(x, y, grid, type) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.type = type
|
||||
this.grid = grid;
|
||||
|
||||
|
||||
this.gridLetter = null;
|
||||
this.hintBox = null;
|
||||
this.emptyBox = null;
|
||||
}
|
||||
|
||||
setGridLetter(gridLetter) {
|
||||
this.gridLetter = gridLetter;
|
||||
}
|
||||
|
||||
getGridLetter() {
|
||||
return this.gridLetter;
|
||||
}
|
||||
|
||||
setHintBox(hintBox) {
|
||||
this.hintBox = hintBox;
|
||||
}
|
||||
|
||||
getHintBox() {
|
||||
return this.hintBox;
|
||||
}
|
||||
|
||||
setEmptyBox(emptyBox) {
|
||||
this.emptyBox = emptyBox;
|
||||
}
|
||||
|
||||
getEmptyBox() {
|
||||
return this.emptyBox;
|
||||
}
|
||||
|
||||
getGridType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class GridBox extends LitElement {
|
||||
static get styles() {
|
||||
return css`
|
||||
input[type='text'] {
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
text-align: center;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
border-width: 0.2 em;
|
||||
background-color: black;
|
||||
outline: none;
|
||||
color: transparent;
|
||||
text-shadow: 0 0 1 black;
|
||||
font-size: 2em;
|
||||
user-select: none;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
x: { type: Number },
|
||||
y: { type: Number },
|
||||
gridCount: {type: Number},
|
||||
grid_id: { type: String }
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.gridElement = null;
|
||||
this.grid_id = null;
|
||||
this.crosswordGrid = null;
|
||||
this.isRevealed = false;
|
||||
this.gridCount = 0;
|
||||
}
|
||||
|
||||
update(props) {
|
||||
super.update(props);
|
||||
if (props.has("grid_id") || props.has("gridCount")) {
|
||||
this.updateGridElement();
|
||||
}
|
||||
}
|
||||
|
||||
updateGridElement() {
|
||||
if (this.grid_id != null) {
|
||||
|
||||
this.crosswordGrid = document.getElementById(this.grid_id);
|
||||
this.gridElement = this.crosswordGrid.getGridElement(this.x, this.y);
|
||||
this.gridElement.setEmptyBox(this);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<input type="text" id="${this.x}-${this.y}" maxlength="1" value="" disabled></input>`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('grid-box', GridBox);
|
||||
|
||||
|
||||
export class GridLetter extends GridBox {
|
||||
static get styles() {
|
||||
return css`
|
||||
.letter {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
input[type='text'] {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
text-align: center;
|
||||
border-style: solid;
|
||||
border-width: 0.2 em;
|
||||
border-color: black;
|
||||
outline: none;
|
||||
color: black;
|
||||
font-size: 2em;
|
||||
user-select: none;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
input[type='text']:focus {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
background-color: LightYellow;
|
||||
border-color: Yellow;
|
||||
|
||||
}
|
||||
|
||||
input[type='text']:read-only {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
background-color: LightGreen;
|
||||
}
|
||||
|
||||
input[type='text']:selection {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.circle {
|
||||
margin: auto;
|
||||
text-align: left;
|
||||
vertical-align: bottom;
|
||||
bottom: 0;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
border: 0.1em solid grey;
|
||||
color: black;
|
||||
height: 80%;
|
||||
width: 80%;
|
||||
border-radius:50%;
|
||||
-moz-border-radius:50%;
|
||||
-webkit-border-radius:50%;
|
||||
background: transparent;
|
||||
|
||||
}
|
||||
|
||||
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
letter: { type: String },
|
||||
x: { type: Number },
|
||||
y: { type: Number },
|
||||
gridCount: {type: Number},
|
||||
grid_id: { type: String }
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._value = '';
|
||||
this.is_focused = false;
|
||||
this.firstKeydownOver = true;
|
||||
this.solutionIndex = -1;
|
||||
this.lastFocusedX = -1;
|
||||
this.lastFocusedY = -1;
|
||||
this.updateGridElement();
|
||||
}
|
||||
|
||||
|
||||
|
||||
set value(value) {
|
||||
const oldValue = this.value;
|
||||
console.log("update value to: " + value);
|
||||
|
||||
this._value = value;
|
||||
this.requestUpdate('value', oldValue);
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this._value;
|
||||
}
|
||||
|
||||
onInput(e) {
|
||||
|
||||
|
||||
if (!this.is_focused) {
|
||||
e.handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
//if (this.key_delay){
|
||||
// var el = this.shadowRoot.getElementById(`${this.x}-${this.y}`);
|
||||
// el.value = this.value;
|
||||
// el.select();
|
||||
// e.handled = true;
|
||||
// return;
|
||||
//}
|
||||
|
||||
var oldVal = this.value;
|
||||
this.value = e.target.value
|
||||
|
||||
if (this.revealed) {
|
||||
this.value = oldVal;
|
||||
this.crosswordGrid.focusNextCell(this.x, this.y);
|
||||
return
|
||||
}
|
||||
|
||||
if (this.value.length > 1) {
|
||||
this.value = this.value[0];
|
||||
e.target.value = this.value
|
||||
e.handled = true;
|
||||
}
|
||||
|
||||
if (!e.handled && this.value === " ") {
|
||||
this.value = "";
|
||||
e.target.value = "";
|
||||
e.handled = true;
|
||||
}
|
||||
|
||||
if (!e.handled && this.value.length === 0) {
|
||||
this.crosswordGrid.focusPrevCell(this.x, this.y, this.lastFocusedX, this.lastFocusedY);
|
||||
e.handled = true;
|
||||
}
|
||||
else if (!e.handled && this.value.length === 1) {
|
||||
this.crosswordGrid.focusNextCell(this.x, this.y);
|
||||
e.handled = true;
|
||||
}
|
||||
else {
|
||||
this.focus();
|
||||
}
|
||||
|
||||
if (oldVal != this.value) {
|
||||
if (this.solutionIndex >= 0) {
|
||||
this.crosswordGrid.setSolutionLetter(this.solutionIndex, this.value);
|
||||
|
||||
}
|
||||
this.crosswordGrid.sendMessage({
|
||||
'type': 'update',
|
||||
'x': this.x,
|
||||
'y': this.y,
|
||||
'letter': this.value
|
||||
})
|
||||
}
|
||||
|
||||
if (!e.handled) {
|
||||
|
||||
e.target.select();
|
||||
|
||||
e.handled = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onKeyup(e) {
|
||||
if (!this.firstKeydownOver) {
|
||||
e.handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var key = e.key;
|
||||
if (this.value.length == 0 || this.revealed) {
|
||||
if (key === 'Backspace' || key === 'Delete') {
|
||||
this.crosswordGrid.focusPrevCell(this.x, this.y, this.lastFocusedX, this.lastFocus);
|
||||
e.handled = true;
|
||||
return
|
||||
|
||||
}
|
||||
else if (this.revealed) {
|
||||
this.crosswordGrid.focusNextCell(this.x, this.y);
|
||||
e.handled = true;
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onKeydown(e) {
|
||||
|
||||
this.firstKeydownOver = true;
|
||||
|
||||
if (!this.is_focused) {
|
||||
e.handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var key = e.key;
|
||||
|
||||
console.log(key);
|
||||
|
||||
|
||||
// check arrow keys
|
||||
if (key === "ArrowLeft") {
|
||||
// left
|
||||
this.crosswordGrid.focusPrevCellHorizontal(this.x, this.y);
|
||||
e.handled = true;
|
||||
return;
|
||||
}
|
||||
else if (key === "ArrowUp") {
|
||||
// up
|
||||
this.crosswordGrid.focusPrevCellVertical(this.x, this.y);
|
||||
e.handled = true;
|
||||
return;
|
||||
|
||||
}
|
||||
else if (key === "ArrowRight") {
|
||||
//right
|
||||
this.crosswordGrid.focusNextCellHorizontal(this.x, this.y);
|
||||
e.handled = true;
|
||||
return;
|
||||
}
|
||||
else if (key === "ArrowDown") {
|
||||
//down
|
||||
this.crosswordGrid.focusNextCellVertical(this.x, this.y);
|
||||
e.handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
e.target.select();
|
||||
|
||||
|
||||
}
|
||||
|
||||
onFocus(e) {
|
||||
e.target.select();
|
||||
this.is_focused = true;
|
||||
|
||||
this.crosswordGrid.updateHints(this.x, this.y);
|
||||
}
|
||||
|
||||
focus(lastX = -1, lastY = -1) {
|
||||
if (lastX > 0 && lastY > 0) {
|
||||
this.lastFocusedX = lastX;
|
||||
this.lastFocusedY = lastY;
|
||||
}
|
||||
var element = this.shadowRoot.getElementById(`${this.x}-${this.y}`);
|
||||
this.firstKeydownOver = false;
|
||||
element.focus();
|
||||
|
||||
|
||||
}
|
||||
|
||||
blur() {
|
||||
var element = this.shadowRoot.getElementById(`${this.x}-${this.y}`);
|
||||
element.blur();
|
||||
this.is_focused = false;
|
||||
}
|
||||
|
||||
updateGridElement() {
|
||||
super.updateGridElement()
|
||||
|
||||
if (this.grid_id != null) {
|
||||
|
||||
this.gridElement.setGridLetter(this);
|
||||
this.solutionIndex = this.crosswordGrid.getSolutionIndex(this.x, this.y)
|
||||
}
|
||||
}
|
||||
|
||||
updateLetter(letter, revealed) {
|
||||
this.value = letter;
|
||||
if (revealed) {
|
||||
console.log("rec")
|
||||
this.shadowRoot.getElementById(`${this.x}-${this.y}`).readOnly = true;
|
||||
this.blur();
|
||||
this.revealed = true;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
this.updateGridElement();
|
||||
|
||||
var solutionOverlay = html``;
|
||||
|
||||
if (this.solutionIndex >= 0) {
|
||||
solutionOverlay = html`
|
||||
<div class="circle">${this.solutionIndex + 1}</div>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return html`
|
||||
<div class="letter">
|
||||
<input type="text" id="${this.x}-${this.y}" value="${this.value}" @input=${this.onInput} @focus=${this.onFocus} @keydown=${this.onKeydown} @keyup=${this.onKeyup} autocomplete="off"></input>
|
||||
${solutionOverlay}
|
||||
</div>
|
||||
|
||||
`;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('grid-letter', GridLetter);
|
||||
|
||||
|
||||
|
||||
export class HintBox extends GridBox {
|
||||
|
||||
static get styles() {
|
||||
|
||||
return css`
|
||||
|
||||
.hint {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
|
||||
.triangle-down {
|
||||
position: relative;
|
||||
top: 3em;
|
||||
left: 1em;
|
||||
z-index: 10;
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 0.75em solid transparent;
|
||||
border-right: 0.75em solid transparent;
|
||||
border-top: 1.3em solid #555;
|
||||
|
||||
}
|
||||
|
||||
.triangle-right {
|
||||
position: relative;
|
||||
top: 1em;
|
||||
left: 3em;
|
||||
z-index: 10;
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 0.75em solid transparent;
|
||||
border-bottom: 0.75em solid transparent;
|
||||
border-left: 1.3em solid #555;
|
||||
|
||||
}
|
||||
|
||||
input[type='text']{
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
text-align: center;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
border-width: 0.2 em;
|
||||
background-color: #555;
|
||||
outline: none;
|
||||
color: white;
|
||||
text-shadow: 0 0 1 black;
|
||||
font-size: 2em;
|
||||
user-select: none;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
x: { type: Number },
|
||||
y: { type: Number },
|
||||
grid_id: { type: String },
|
||||
horizontal_hint: { type: String },
|
||||
vertical_hint: { type: String },
|
||||
gridCount: {type: Number},
|
||||
hint_id: { type: String }
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.vertical_hint = "";
|
||||
this.horizontal_hint = "";
|
||||
this.hint_id = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
getVerticalHint() {
|
||||
return this.vertical_hint;
|
||||
}
|
||||
|
||||
getHorizontalHint() {
|
||||
return this.horizontal_hint;
|
||||
}
|
||||
|
||||
hasVerticalHint() {
|
||||
return this.vertical_hint.length > 0;
|
||||
}
|
||||
|
||||
hasHorizontalHint() {
|
||||
return this.horizontal_hint.length > 0;
|
||||
}
|
||||
|
||||
updateGridElement() {
|
||||
super.updateGridElement()
|
||||
|
||||
if (this.grid_id != null) {
|
||||
|
||||
this.gridElement.setHintBox(this);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
this.updateGridElement();
|
||||
|
||||
var verticalArrow = html``;
|
||||
var horizontalArrow = html``;
|
||||
|
||||
if (this.hasVerticalHint()) {
|
||||
verticalArrow = html`<div class="triangle-down"></div>`;
|
||||
}
|
||||
|
||||
if (this.hasHorizontalHint()) {
|
||||
horizontalArrow = html`<div class="triangle-right"></div>`;
|
||||
}
|
||||
|
||||
return html`
|
||||
<div class="hint">
|
||||
<input type="text" id="${this.x}-${this.y}" value="${this.hint_id}" disabled></input>
|
||||
${verticalArrow}
|
||||
${horizontalArrow}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hint-box', HintBox);
|
@ -8,7 +8,7 @@ function copyToClipboard(text) {
|
||||
input.select();
|
||||
document.execCommand('copy');
|
||||
input.parentNode.removeChild(input);
|
||||
alert("copied url to clipboard");
|
||||
alert("copied url to clipboard, you can share this link to work collaboratively on this puzzle in real time");
|
||||
}
|
||||
|
||||
export class InfoBox extends LitElement {
|
||||
@ -34,7 +34,7 @@ export class InfoBox extends LitElement {
|
||||
top: 0em;
|
||||
left: 0em;
|
||||
right: 0em;
|
||||
height: 6em;
|
||||
min-height: 8em;
|
||||
|
||||
border-style: solid;
|
||||
border-color: white;
|
||||
@ -55,7 +55,7 @@ export class InfoBox extends LitElement {
|
||||
border-width: 0.2em;
|
||||
border-style: solid;
|
||||
min-width: 10em;
|
||||
min-height: 2.5em;
|
||||
min-height: 3.5em;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
margin: 0.1em 0.1em;
|
||||
|
@ -1,3 +1,3 @@
|
||||
import '/grid.js'
|
||||
import '/serverConnection.js'
|
||||
import './grid.js'
|
||||
import './serverConnection.js'
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { html, css, LitElement } from 'https://unpkg.com/lit-element/lit-element.js?module';
|
||||
import { WebsocketConnection } from '/websocket.js';
|
||||
import { getCookie, setCookie } from '/cookie.js';
|
||||
import { WebsocketConnection } from './websocket.js';
|
||||
import { getCookie, setCookie } from './cookie.js';
|
||||
|
||||
export class ServerConnection extends WebsocketConnection {
|
||||
static get styles() {
|
||||
|
@ -1,90 +1,183 @@
|
||||
import { html, css, LitElement, unsafeCSS } from 'https://unpkg.com/lit-element/lit-element.js?module';
|
||||
import { GridLetter } from './gridBoxes.js';
|
||||
|
||||
export class SolutionBox extends LitElement {
|
||||
export class SolutionLetter extends LitElement {
|
||||
static get styles() {
|
||||
return css`
|
||||
.letter {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
input[type='text'] {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
text-align: center;
|
||||
border-style: solid;
|
||||
border-width: 0.2 em;
|
||||
border-color: black;
|
||||
outline: none;
|
||||
color: black;
|
||||
font-size: 2em;
|
||||
user-select: none;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
input[type='text']:read-only {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
background-color: LightGreen;
|
||||
}
|
||||
|
||||
input[type='text']:selection {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.circle {
|
||||
margin: auto;
|
||||
text-align: left;
|
||||
vertical-align: bottom;
|
||||
bottom: 0;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
border: 0.1em solid lightGray;
|
||||
color: black;
|
||||
height: 80%;
|
||||
width: 80%;
|
||||
border-radius:50%;
|
||||
-moz-border-radius:50%;
|
||||
-webkit-border-radius:50%;
|
||||
background: transparent;
|
||||
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
return GridLetter.styles;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
length: { type: Number }
|
||||
solutionIndex: { type: Number },
|
||||
grid_id: { type: String }
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._letter = "";
|
||||
this.solutionIndex = 0;
|
||||
this.grid_id = "";
|
||||
this.grid = null;
|
||||
this.revealed = false;
|
||||
}
|
||||
|
||||
update(props) {
|
||||
if (props.has("grid_id")) {
|
||||
this.grid = document.getElementById(this.grid_id);
|
||||
}
|
||||
|
||||
super.update(props);
|
||||
|
||||
}
|
||||
|
||||
reveal(letter) {
|
||||
var el = this.shadowRoot.getElementById("solution" + this.solutionIndex);
|
||||
this.letter = letter;
|
||||
el.readOnly = true;
|
||||
this.revealed = true;
|
||||
|
||||
}
|
||||
|
||||
set letter(letter) {
|
||||
this._letter = letter
|
||||
var e = this.shadowRoot.getElementById("solution" + this.solutionIndex);
|
||||
if (e.value != this.letter)
|
||||
e.value = this.letter
|
||||
|
||||
}
|
||||
|
||||
get letter(){
|
||||
return this._letter;
|
||||
}
|
||||
|
||||
onFocus(e) {
|
||||
e.target.select();
|
||||
}
|
||||
|
||||
|
||||
onInput(e) {
|
||||
|
||||
if (this.revealed) {
|
||||
e.handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var val = e.target.value;
|
||||
|
||||
var el = this.shadowRoot.getElementById("solution" + this.solutionIndex);
|
||||
|
||||
if (val.length > 1) {
|
||||
val = val[0];
|
||||
|
||||
|
||||
}
|
||||
if (e.target.value != this.letter){
|
||||
|
||||
this.letter = val;
|
||||
this.grid.setSolutionLetter(this.solutionIndex, this.letter);
|
||||
}
|
||||
e.target.select();
|
||||
e.handled = true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
console.log("render solution letter");
|
||||
return html`
|
||||
<div class="letter">
|
||||
<input type="text" id="solution${this.solutionIndex}" value="${this.letter}" @input=${this.onInput} @focus=${this.onFocus} autocomplete="off"></input>
|
||||
<div class="circle">${this.solutionIndex + 1}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('solution-letter', SolutionLetter);
|
||||
|
||||
export class SolutionBox extends LitElement {
|
||||
static get styles() {
|
||||
return css`
|
||||
body {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.codewordlabel {
|
||||
z-index: 5;
|
||||
position: relative;
|
||||
top: 5em;
|
||||
font-size: 1.5em;
|
||||
color: white;
|
||||
text-color: white;
|
||||
}
|
||||
|
||||
table {
|
||||
position: relative;
|
||||
top: 7em;
|
||||
border-spacing: 0px;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
border-width: 1em;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 0px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
length: { type: Number },
|
||||
grid_id: { type: String }
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.length = 0;
|
||||
this.values = [];
|
||||
this.values = []
|
||||
this.grid_id = "";
|
||||
this.grid = null;
|
||||
}
|
||||
|
||||
update(props) {
|
||||
if (props.has("length")) {
|
||||
console.log("update colution, grid is " + this.grid_id);
|
||||
if (this.grid_id.length > 0) {
|
||||
this.grid = document.getElementById(this.grid_id);
|
||||
this.grid.setSolutionBox(this);
|
||||
console.log("updated grid parent");
|
||||
|
||||
this.values = [];
|
||||
var i;
|
||||
for (i = 0; i < this.length; i++) {
|
||||
this.values.push("");
|
||||
}
|
||||
this.requestUpdate();
|
||||
console.log("update length");
|
||||
}
|
||||
super.update(props);
|
||||
}
|
||||
|
||||
setLetter(solutionIndex, letter, revealed = false) {
|
||||
var solutionBox = this.shadowRoot.getElementById("solutionLetter" + solutionIndex)
|
||||
solutionBox.letter = letter;
|
||||
|
||||
if (revealed) {
|
||||
solutionBox.reveal(letter);
|
||||
}
|
||||
super.update()
|
||||
}
|
||||
|
||||
render() {
|
||||
console.log("rerender box");
|
||||
return html`
|
||||
|
||||
<div class="codewordlabel">Codeword</div>
|
||||
<table><tr>
|
||||
${this.values.map((el, i) => html`<td><solution-letter id="solutionLetter${i}" grid_id=${this.grid_id} letter="" solutionIndex=${i} ></solution-letter></td>`)}
|
||||
</tr></table>
|
||||
`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('solution-box', SolutionBox);
|
||||
|
@ -25,6 +25,7 @@ export class WebsocketConnection extends LitElement {
|
||||
|
||||
onclose(event){
|
||||
console.log("websocket closed");
|
||||
setTimeout(() => this.connect(), 1000);
|
||||
}
|
||||
|
||||
onerror(event){
|
||||
|
@ -1,6 +1,8 @@
|
||||
import logging
|
||||
import uuid
|
||||
|
||||
import datetime as dt
|
||||
|
||||
from . import json_websockets
|
||||
from . import session
|
||||
|
||||
@ -9,12 +11,27 @@ class CrosswordConnection(json_websockets.JsonWebsocketConnection):
|
||||
|
||||
sessions = {}
|
||||
|
||||
last_cleanup = None
|
||||
|
||||
def clean_sessions():
|
||||
now = dt.datetime.utcnow()
|
||||
if CrosswordConnection.last_cleanup is None or (now - CrosswordConnection.last_cleanup).total_seconds() > 3600:
|
||||
CrosswordConnection.last_cleanup = now
|
||||
|
||||
sessions_to_close = []
|
||||
for key, session in CrosswordConnection.sessions.items():
|
||||
if session.is_expired():
|
||||
sessions_to_close.append(key)
|
||||
|
||||
for key in sessions_to_close:
|
||||
del(CrosswordConnection.sessions[key])
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self._session = None
|
||||
|
||||
async def send_crossword(self, sessionId: str, lang:str = "en"):
|
||||
async def send_crossword(self, sessionId: str, lang: str = "en"):
|
||||
if sessionId not in CrosswordConnection.sessions:
|
||||
await self.send_error(msg="unknown session")
|
||||
return
|
||||
@ -83,6 +100,9 @@ class CrosswordConnection(json_websockets.JsonWebsocketConnection):
|
||||
|
||||
await self.send_crossword(sessionId, lang=lang)
|
||||
|
||||
# clean up old session
|
||||
CrosswordConnection.clean_sessions()
|
||||
|
||||
async def send_error(self, msg: str):
|
||||
await self.send({
|
||||
'type': 'error',
|
||||
@ -103,7 +123,7 @@ class CrosswordConnection(json_websockets.JsonWebsocketConnection):
|
||||
sessionId = message['sessionId']
|
||||
if "lang" in message:
|
||||
lang = message['lang']
|
||||
await self.register(sessionId=sessionId, lang = lang)
|
||||
await self.register(sessionId=sessionId, lang=lang)
|
||||
return
|
||||
|
||||
if self._session is None:
|
||||
|
@ -185,7 +185,7 @@ def create_word_grid(w: int, h: int, lang_code: str = "en", target_density=0.5):
|
||||
# check if there is space before and after
|
||||
if y - 1 >= 0 and grid[y - 1, x] != " ":
|
||||
return False
|
||||
if y + n < grid.shape[0] - 1 and grid[y+n, x] != " ":
|
||||
if y + n < grid.shape[0] and grid[y+n, x] != " ":
|
||||
return False
|
||||
|
||||
if grid.shape[0] - n < y or y < 0:
|
||||
@ -214,7 +214,7 @@ def create_word_grid(w: int, h: int, lang_code: str = "en", target_density=0.5):
|
||||
# check if there is space before and after
|
||||
if x - 1 >= 0 and grid[y, x - 1] != " ":
|
||||
return False
|
||||
if x + n < grid.shape[1] - 1 and grid[y, x + n] != " ":
|
||||
if x + n < grid.shape[1] and grid[y, x + n] != " ":
|
||||
return False
|
||||
|
||||
if grid.shape[1] - n < x or x < 0:
|
||||
|
@ -4,10 +4,12 @@ from . import crossword
|
||||
|
||||
|
||||
class Session(object):
|
||||
def __init__(self) -> None:
|
||||
def __init__(self, days_to_expire:int = 2) -> None:
|
||||
self.crossword = None
|
||||
self.datetime_created = dt.datetime.utcnow()
|
||||
self.connected_sockets = set()
|
||||
self.last_touched = self.datetime_created
|
||||
self.days_to_expire = 2
|
||||
|
||||
def cleanup(self):
|
||||
sockets_to_remove = []
|
||||
@ -46,3 +48,17 @@ class Session(object):
|
||||
self.create_crossword(lang = lang)
|
||||
|
||||
return self.crossword
|
||||
|
||||
def touch(self):
|
||||
self.last_touched = dt.datetime.utcnow()
|
||||
|
||||
def is_expired(self):
|
||||
self.cleanup()
|
||||
if len(self.connected_sockets) > 0:
|
||||
return False
|
||||
now = dt.datetime.utcnow()
|
||||
if (now - self.last_touched).days > self.days_to_expire:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
697425
server/steam@cake:
Normal file
697425
server/steam@cake:
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user