add solution word to client
This commit is contained in:
		| @ -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){ | ||||
|  | ||||
		Reference in New Issue
	
	Block a user