From 1a1b118bf9b8e3f2b44a6a20f31f985334bb0944 Mon Sep 17 00:00:00 2001 From: Lily2point0 Date: Thu, 18 May 2017 12:14:38 +0100 Subject: [PATCH 1/9] added prev/next functionality --- src/js/oCrossword.js | 66 +++++++++++++++++++++++++++++++++++++++---- src/scss/_base.scss | 25 ++++++++++++++-- src/scss/_mobile.scss | 18 ++++-------- 3 files changed, 89 insertions(+), 20 deletions(-) diff --git a/src/js/oCrossword.js b/src/js/oCrossword.js index 2178741..d2cd9a9 100644 --- a/src/js/oCrossword.js +++ b/src/js/oCrossword.js @@ -82,6 +82,8 @@ function buildGrid( rootEl.parentElement.setAttribute('data-o-crossword-title', name); if (clues) { + rootEl.parentElement.setAttribute('data-o-crossword-clue-length', clues.across.length + clues.down.length); + const acrossEl = document.createElement('ul'); acrossEl.classList.add('o-crossword-clues-across'); @@ -97,7 +99,7 @@ function buildGrid( downWrapper.appendChild(downEl); cluesEl.appendChild(downWrapper); - clues.across.forEach(function acrossForEach(across) { + clues.across.forEach(function acrossForEach(across, index) { const tempLi = document.createElement('li'); const tempSpan = document.createElement('span'); const answerLength = across[2].filter(isFinite).filter(isFinite).reduce((a,b)=>a+b,0); @@ -105,11 +107,12 @@ function buildGrid( tempLi.dataset.oCrosswordNumber = across[0]; tempLi.dataset.oCrosswordAnswerLength = answerLength; tempLi.dataset.oCrosswordDirection = 'across'; + tempLi.dataset.oCrosswordClueId = index; acrossEl.appendChild(tempLi); tempLi.appendChild(tempSpan); }); - clues.down.forEach(function acrossForEach(down) { + clues.down.forEach(function acrossForEach(down, index) { const tempLi = document.createElement('li'); const tempSpan = document.createElement('span'); const answerLength = down[2].filter(isFinite).filter(isFinite).reduce((a,b)=>a+b,0); @@ -117,6 +120,7 @@ function buildGrid( tempLi.dataset.oCrosswordNumber = down[0]; tempLi.dataset.oCrosswordAnswerLength = answerLength; tempLi.dataset.oCrosswordDirection = 'down'; + tempLi.dataset.oCrosswordClueId = clues.across.length + index; downEl.appendChild(tempLi); tempLi.appendChild(tempSpan); }); @@ -242,6 +246,8 @@ OCrossword.prototype.assemble = function assemble() { }); } if (cluesEl) { + let currentClue = 0; + const cluesUlEls = Array.from(cluesEl.querySelectorAll('ul')); const gridWrapper = document.createElement('div'); @@ -257,6 +263,28 @@ OCrossword.prototype.assemble = function assemble() { clueDisplayer.classList.add('o-crossword-clue-displayer'); gridScaleWrapper.appendChild(clueDisplayer); + const clueDisplayerText = document.createElement('span'); + clueDisplayer.appendChild(clueDisplayerText); + + const clueNavigation = document.createElement('nav'); + clueNavigation.classList.add('o-crossword-clue-navigation'); + // clueNavigation.classList.add('hidden'); + + const clueNavigationPrev = document.createElement('a'); + clueNavigationPrev.classList.add('o-crossword-clue-nav-prev'); + clueNavigationPrev.setAttribute('href', '#'); + clueNavigationPrev.textContent = 'Previous'; + clueNavigation.appendChild(clueNavigationPrev); + + const clueNavigationNext = document.createElement('a'); + clueNavigationNext.classList.add('o-crossword-clue-nav-next'); + clueNavigationNext.setAttribute('href', '#'); + clueNavigationNext.textContent = 'Next'; + clueNavigation.appendChild(clueNavigationNext); + + clueDisplayer.appendChild(clueNavigation); + + const wrapper = document.createElement('div'); wrapper.classList.add('o-crossword-clues-wrapper'); this.rootEl.insertBefore(wrapper, cluesEl); @@ -476,10 +504,11 @@ OCrossword.prototype.assemble = function assemble() { function setClue(number, direction) { const el = cluesEl.querySelector(`li[data-o-crossword-number="${number}"][data-o-crossword-direction="${direction}"]`); if (el) { - clueDisplayer.textContent = el.textContent; + clueDisplayerText.textContent = el.textContent; const els = Array.from(cluesEl.getElementsByClassName('has-hover')); els.filter(el2 => el2 !== el).forEach(el => el.classList.remove('has-hover')); el.classList.add('has-hover'); + currentClue = parseInt(el.getAttribute('data-o-crossword-clue-id')); } } @@ -503,7 +532,7 @@ OCrossword.prototype.assemble = function assemble() { } if (el) { - clueDisplayer.textContent = ''; + clueDisplayerText.textContent = ''; const els = Array.from(cluesEl.getElementsByClassName('has-hover')); els.forEach(el => el.classList.remove('has-hover')); el.classList.remove('has-hover'); @@ -556,7 +585,13 @@ OCrossword.prototype.assemble = function assemble() { target = e.target; blockHighlight = true; } else { - const defEl = (e.target.nodeName === 'SPAN')?e.target.parentElement:e.target; + let defEl; + + if(e.target.nodeName === 'A') { + defEl = navigateClues(e); + } else { + defEl = (e.target.nodeName === 'SPAN')?e.target.parentElement:e.target; + } const num = defEl.getAttribute('data-o-crossword-number'); clueDetails = {}; @@ -632,6 +667,27 @@ OCrossword.prototype.assemble = function assemble() { } }.bind(this); + const navigateClues = function navigateClues (e) { + e.preventDefault(); + const dir = (e.target === clueNavigationNext)?'forward':'backward'; + const cluesTotal = parseInt(this.rootEl.parentElement.getAttribute('data-o-crossword-clue-length')) - 1; + + if (dir === 'forward') { + ++currentClue; + + if(currentClue > cluesTotal) { + currentClue = 0; + } + } else { + --currentClue; + if(currentClue < 0) { + currentClue = cluesTotal; + } + } + + return cluesEl.querySelector('li[data-o-crossword-clue-id="'+ currentClue +'"]'); + }.bind(this); + this.addEventListener(cluesEl, 'mousemove', e => highlightGridByCluesEl(e.target)); this.hammerMC.on('tap', onTap); diff --git a/src/scss/_base.scss b/src/scss/_base.scss index 910d1a1..90916c7 100644 --- a/src/scss/_base.scss +++ b/src/scss/_base.scss @@ -83,6 +83,26 @@ @include oColorsFor(o-crossword-border, border); text-transform: none; margin: 0 auto; + position: relative + } + + .o-crossword-clue-navigation { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + + a { + display: inline-block; + background: rgba(0,0,0,.2); + height: 100%; + width: 50%; + + &.o-crossword-clue-nav-next { + text-align: right; + } + } } .o-crossword-magic-input { @@ -157,14 +177,13 @@ .o-crossword-clues-wrapper { position: relative; - pointer-events: none; - z-index: 2; width: 20em; + margin-top: 2em; @include oGridRespondTo(M) { - position: relative; float: left; width: auto; + margin-top: 0; } } diff --git a/src/scss/_mobile.scss b/src/scss/_mobile.scss index 7794bb0..f1560ad 100644 --- a/src/scss/_mobile.scss +++ b/src/scss/_mobile.scss @@ -2,24 +2,18 @@ .o-crossword table, .o-crossword .o-crossword-grid-wrapper .o-crossword-magic-input { font-size: 1.2rem; } - .o-crossword-clues-wrapper { - display: block; - } - .o-crossword div.o-crossword-clues-wrapper { - position: relative; + .o-crossword .o-crossword-clues-wrapper { + display: block; width: auto; overflow: auto; } - .o-crossword .o-crossword-clues li, .o-crossword .o-crossword-clues ul li { - line-height: 1.1em; + .o-crossword-clue-displayer { + height: 3em; } - .o-crossword-clues.magnify { - display: none !important; - } - .o-crossword-clues-wrapper { - pointer-events: all; + .o-crossword .o-crossword-clues li, .o-crossword .o-crossword-clues ul li { + line-height: 1.1em; } } From e1dc1c38f1a861dc89233873dda116f1ce04fb2b Mon Sep 17 00:00:00 2001 From: Lily2point0 Date: Thu, 18 May 2017 15:52:06 +0100 Subject: [PATCH 2/9] mobile fixes --- src/js/oCrossword.js | 14 ++++++++------ src/scss/_base.scss | 32 +++++++++++++++++++++++++++++--- src/scss/_mobile.scss | 42 ++++++++++++++++++++++++++++-------------- 3 files changed, 65 insertions(+), 23 deletions(-) diff --git a/src/js/oCrossword.js b/src/js/oCrossword.js index d2cd9a9..6dbefdc 100644 --- a/src/js/oCrossword.js +++ b/src/js/oCrossword.js @@ -344,14 +344,14 @@ OCrossword.prototype.assemble = function assemble() { return; } - if( e.keyCode === 229) { - //fix safari press down - magicInput.value = ''; - return; - } - if(!isAndroid()) { magicInput.value = String.fromCharCode(e.keyCode); + + if( e.keyCode === 229) { + //fix safari press down + magicInput.value = ''; + return; + } } progress(); @@ -382,9 +382,11 @@ OCrossword.prototype.assemble = function assemble() { magicInput.value = ''; blockHighlight = false; }, 16); + this.addEventListener(magicInput, 'focus', magicInput.select()); function takeInput(el, nextEls) { + console.log(el); if ( magicInputTargetEl && magicInput.value.match(/^[^\s]/) diff --git a/src/scss/_base.scss b/src/scss/_base.scss index 90916c7..baeb80a 100644 --- a/src/scss/_base.scss +++ b/src/scss/_base.scss @@ -83,7 +83,15 @@ @include oColorsFor(o-crossword-border, border); text-transform: none; margin: 0 auto; - position: relative + position: relative; + display: table; + + span { + display: table-cell; + vertical-align: middle; + padding: 0; + width: 100%; + } } .o-crossword-clue-navigation { @@ -92,15 +100,33 @@ left: 0; width: 100%; height: 100%; + display: none; a { + background: transparent; display: inline-block; - background: rgba(0,0,0,.2); height: 100%; width: 50%; + font-size: 0; + vertical-align: middle; + + &:before { + content: ''; + display: block; + width: 30px; + height: 30px; + background-image: url('https://www.ft.com/__origami/service/image/v2/images/raw/fticon-v1:arrow-left?source=o-crossword'); + background-repeat: no-repeat; + background-size: cover; + margin-top: 8px; + } &.o-crossword-clue-nav-next { - text-align: right; + &:before { + background-image: url('https://www.ft.com/__origami/service/image/v2/images/raw/fticon-v1:arrow-right?source=o-crossword'); + float: right; + } + } } } diff --git a/src/scss/_mobile.scss b/src/scss/_mobile.scss index f1560ad..bc24a15 100644 --- a/src/scss/_mobile.scss +++ b/src/scss/_mobile.scss @@ -1,19 +1,33 @@ @media screen and (max-width: $break-phone) { - .o-crossword table, .o-crossword .o-crossword-grid-wrapper .o-crossword-magic-input { - font-size: 1.2rem; - } + .o-crossword table, .o-crossword .o-crossword-grid-wrapper .o-crossword-magic-input { + font-size: 1.2rem; + } - .o-crossword .o-crossword-clues-wrapper { - display: block; - width: auto; - overflow: auto; - } + .o-crossword table td { + line-height: 1; + } - .o-crossword-clue-displayer { - height: 3em; - } + .o-crossword .o-crossword-clues-wrapper { + display: block; + width: auto; + overflow: auto; + } - .o-crossword .o-crossword-clues li, .o-crossword .o-crossword-clues ul li { - line-height: 1.1em; - } + .o-crossword .o-crossword-grid-wrapper .o-crossword-clue-displayer { + height: 3.6em; + font-size: .85rem; + padding: 0 0.5em; + + span { + padding: 0 10%; + } + } + + .o-crossword .o-crossword-grid-wrapper .o-crossword-clue-navigation { + display: initial; + } + + .o-crossword .o-crossword-clues li, .o-crossword .o-crossword-clues ul li { + line-height: 1.1em; + } } From 1034c1c9f825ee77b3539b40dfc60f99b5221c51 Mon Sep 17 00:00:00 2001 From: Sean Tracey Date: Thu, 18 May 2017 16:44:48 +0100 Subject: [PATCH 3/9] Sean's contribution --- src/js/oCrossword.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/js/oCrossword.js b/src/js/oCrossword.js index 6dbefdc..45b266b 100644 --- a/src/js/oCrossword.js +++ b/src/js/oCrossword.js @@ -415,6 +415,11 @@ OCrossword.prototype.assemble = function assemble() { magicInput.style.top = magicInputTargetEl.offsetTop + 'px'; magicInput.focus(); magicInput.select(); + + setTimeout(function(){ + magicInput.focus(); + }.bind(this), 300); + } const onResize = function onResize() { From fce46333cd059da8fe9ad1bd8ca67fdfc77d1cf4 Mon Sep 17 00:00:00 2001 From: Sean Tracey Date: Thu, 18 May 2017 16:50:34 +0100 Subject: [PATCH 4/9] Removing the hammer. --- src/js/oCrossword.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/js/oCrossword.js b/src/js/oCrossword.js index 45b266b..1aaaec4 100644 --- a/src/js/oCrossword.js +++ b/src/js/oCrossword.js @@ -43,7 +43,6 @@ function writeErrorsAsClues(rootEl, json) { cluesEl.appendChild(textList); } -const Hammer = require('hammerjs'); const HORIZ_PAN_SPRING = 0.2; function buildGrid( @@ -300,11 +299,11 @@ OCrossword.prototype.assemble = function assemble() { let blockHighlight = false; - this.hammerMC = new Hammer.Manager(this.rootEl, { + /*this.hammerMC = new Hammer.Manager(this.rootEl, { recognizers: [ [Hammer.Tap] ] - }); + });*/ this.addEventListener(magicInput, 'keydown', function (e) { if (!isAndroid()) { @@ -697,7 +696,8 @@ OCrossword.prototype.assemble = function assemble() { this.addEventListener(cluesEl, 'mousemove', e => highlightGridByCluesEl(e.target)); - this.hammerMC.on('tap', onTap); + // this.hammerMC.on('tap', onTap); + this.rootEl.addEventListener('click', onTap, false); onResize(); this.addEventListener(window, 'resize', this.onResize); @@ -725,9 +725,9 @@ OCrossword.prototype.removeAllEventListeners = function() { OCrossword.prototype.destroy = function destroy() { this.removeAllEventListeners(); - if (this.hammerMC) { + /*if (this.hammerMC) { this.hammerMC.destroy(); - } + }*/ if (this._raf) { cancelAnimationFrame(this._raf); From db9417a0d148e2188edcd820f0517d4f0bf40390 Mon Sep 17 00:00:00 2001 From: Lily2point0 Date: Thu, 18 May 2017 16:52:33 +0100 Subject: [PATCH 5/9] swap tiemout for debounce --- src/js/oCrossword.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/js/oCrossword.js b/src/js/oCrossword.js index 45b266b..3905695 100644 --- a/src/js/oCrossword.js +++ b/src/js/oCrossword.js @@ -386,7 +386,6 @@ OCrossword.prototype.assemble = function assemble() { this.addEventListener(magicInput, 'focus', magicInput.select()); function takeInput(el, nextEls) { - console.log(el); if ( magicInputTargetEl && magicInput.value.match(/^[^\s]/) @@ -413,13 +412,11 @@ OCrossword.prototype.assemble = function assemble() { magicInputNextEls = nextEls; magicInput.style.left = magicInputTargetEl.offsetLeft + 'px'; magicInput.style.top = magicInputTargetEl.offsetTop + 'px'; - magicInput.focus(); - magicInput.select(); - setTimeout(function(){ + debounce(function(){ magicInput.focus(); - }.bind(this), 300); - + magicInput.select(); + }, 100); } const onResize = function onResize() { From 92a8f8ea25ed6b3336f449e9b3f28a24dd6cf9d8 Mon Sep 17 00:00:00 2001 From: Sean Tracey Date: Thu, 18 May 2017 16:57:17 +0100 Subject: [PATCH 6/9] Hammer begone. --- bower.json | 1 - src/js/oCrossword.js | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/bower.json b/bower.json index 9daedc1..d47376c 100644 --- a/bower.json +++ b/bower.json @@ -4,7 +4,6 @@ "o-colors": ">=2.5.0 <4", "o-grid": "^4.0.6", "o-typography": ">=2.0.0 <5", - "hammerjs": "^2.0.8", "o-viewport": "^2.2.0" }, "main": [ diff --git a/src/js/oCrossword.js b/src/js/oCrossword.js index 1aaaec4..7a7b507 100644 --- a/src/js/oCrossword.js +++ b/src/js/oCrossword.js @@ -283,7 +283,6 @@ OCrossword.prototype.assemble = function assemble() { clueDisplayer.appendChild(clueNavigation); - const wrapper = document.createElement('div'); wrapper.classList.add('o-crossword-clues-wrapper'); this.rootEl.insertBefore(wrapper, cluesEl); @@ -299,12 +298,6 @@ OCrossword.prototype.assemble = function assemble() { let blockHighlight = false; - /*this.hammerMC = new Hammer.Manager(this.rootEl, { - recognizers: [ - [Hammer.Tap] - ] - });*/ - this.addEventListener(magicInput, 'keydown', function (e) { if (!isAndroid()) { e.preventDefault(); @@ -696,7 +689,6 @@ OCrossword.prototype.assemble = function assemble() { this.addEventListener(cluesEl, 'mousemove', e => highlightGridByCluesEl(e.target)); - // this.hammerMC.on('tap', onTap); this.rootEl.addEventListener('click', onTap, false); onResize(); @@ -725,9 +717,6 @@ OCrossword.prototype.removeAllEventListeners = function() { OCrossword.prototype.destroy = function destroy() { this.removeAllEventListeners(); - /*if (this.hammerMC) { - this.hammerMC.destroy(); - }*/ if (this._raf) { cancelAnimationFrame(this._raf); From 4e6e24e7caac092fe568e05a51b79a93c52ad28b Mon Sep 17 00:00:00 2001 From: Lily2point0 Date: Thu, 18 May 2017 17:15:46 +0100 Subject: [PATCH 7/9] trigger the first clue on mobile view --- src/js/oCrossword.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/js/oCrossword.js b/src/js/oCrossword.js index 1d7e3a3..bd93975 100644 --- a/src/js/oCrossword.js +++ b/src/js/oCrossword.js @@ -245,7 +245,7 @@ OCrossword.prototype.assemble = function assemble() { }); } if (cluesEl) { - let currentClue = 0; + let currentClue = -1; const cluesUlEls = Array.from(cluesEl.querySelectorAll('ul')); @@ -404,14 +404,16 @@ OCrossword.prototype.assemble = function assemble() { magicInputNextEls = nextEls; magicInput.style.left = magicInputTargetEl.offsetLeft + 'px'; magicInput.style.top = magicInputTargetEl.offsetTop + 'px'; - + magicInput.focus(); + magicInput.select(); + debounce(function(){ magicInput.focus(); magicInput.select(); }, 100); } - const onResize = function onResize() { + const onResize = function onResize(init) { var isMobile = false; const cellSizeMax = 40; @@ -421,6 +423,10 @@ OCrossword.prototype.assemble = function assemble() { isMobile = true; } + if(isMobile && !!init) { + clueNavigationNext.click(); + } + const d1 = cluesEl.getBoundingClientRect(); let d2 = gridEl.getBoundingClientRect(); const width1 = d1.width; @@ -688,7 +694,7 @@ OCrossword.prototype.assemble = function assemble() { this.rootEl.addEventListener('click', onTap, false); - onResize(); + onResize(true); this.addEventListener(window, 'resize', this.onResize); } From 13918179322fabce3d97a8cfed7d343aa4853839 Mon Sep 17 00:00:00 2001 From: Lily2point0 Date: Thu, 18 May 2017 17:19:32 +0100 Subject: [PATCH 8/9] fix scrolling issue --- src/scss/_base.scss | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/scss/_base.scss b/src/scss/_base.scss index baeb80a..0873c6a 100644 --- a/src/scss/_base.scss +++ b/src/scss/_base.scss @@ -67,8 +67,6 @@ .o-crossword-grid-wrapper { flex-shrink: 0; - overflow: auto; - -webkit-overflow-scrolling: touch; position: relative; font-size: 1.5em; text-transform: uppercase; From 45cc4f5c01f1e5f439f92fd37fc890eab44e6142 Mon Sep 17 00:00:00 2001 From: Lily2point0 Date: Thu, 18 May 2017 17:40:04 +0100 Subject: [PATCH 9/9] disable input when swiping through clues --- src/js/oCrossword.js | 19 ++++++++++++------- src/scss/_base.scss | 1 + 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/js/oCrossword.js b/src/js/oCrossword.js index bd93975..a5d3127 100644 --- a/src/js/oCrossword.js +++ b/src/js/oCrossword.js @@ -406,7 +406,7 @@ OCrossword.prototype.assemble = function assemble() { magicInput.style.top = magicInputTargetEl.offsetTop + 'px'; magicInput.focus(); magicInput.select(); - + debounce(function(){ magicInput.focus(); magicInput.select(); @@ -581,6 +581,7 @@ OCrossword.prototype.assemble = function assemble() { const onTap = function onTap(e) { let target; let clueDetails; + let isNavigation = false; blockHighlight = false; if (e.target.nodeName === 'TD' || e.target.nodeName === 'INPUT') { @@ -591,6 +592,7 @@ OCrossword.prototype.assemble = function assemble() { if(e.target.nodeName === 'A') { defEl = navigateClues(e); + isNavigation = true; } else { defEl = (e.target.nodeName === 'SPAN')?e.target.parentElement:e.target; } @@ -660,12 +662,15 @@ OCrossword.prototype.assemble = function assemble() { currentlySelectedGridItem.direction, currentlySelectedGridItem.answerLength ); - takeInput(cell, getGridCellsByNumber( - gridEl, - currentlySelectedGridItem.number, - currentlySelectedGridItem.direction, - currentlySelectedGridItem.answerLength - )); + + if(!isNavigation) { + takeInput(cell, getGridCellsByNumber( + gridEl, + currentlySelectedGridItem.number, + currentlySelectedGridItem.direction, + currentlySelectedGridItem.answerLength + )); + } } }.bind(this); diff --git a/src/scss/_base.scss b/src/scss/_base.scss index 0873c6a..a573383 100644 --- a/src/scss/_base.scss +++ b/src/scss/_base.scss @@ -117,6 +117,7 @@ background-repeat: no-repeat; background-size: cover; margin-top: 8px; + user-select: none; } &.o-crossword-clue-nav-next {