I have edited this puzzle as I want but I need to show a message after completing the crossword puzzle. Is there a way to do that? Any kind comments warmly welcome.
Here's is the GitHub link- https://github.com/jweisbeck/Crossword
Here mainly activePosition and activeClueIndex are the primary vars that set the UI whenever there's an interaction. all worked as x, y coordinates. is there any way I can add that message?
Here is the checking winning function
/*
- Checks current entry input group value against answer
- If not complete, auto-selects next input for user
*/
checkAnswer: function(e) {
var valToCheck, currVal;
util.getActivePositionFromClassGroup($(e.target));
valToCheck = puzz.data[activePosition].answer.toLowerCase();
currVal = $('.position-' + activePosition + ' input')
.map(function() {
return $(this)
.val()
.toLowerCase();
})
.get()
.join('');
//console.log(currVal + " " + valToCheck);
if(valToCheck === currVal){
$('.active')
.addClass('done')
.removeClass('active');
$('.clues-active').addClass('clue-done');
solved.push(valToCheck);
solvedToggle = true;
return;
}
currOri === 'across' ? nav.nextPrevNav(e, 39) : nav.nextPrevNav(e, 40);
//z++;
//console.log(z);
//console.log('checkAnswer() solvedToggle: '+solvedToggle);
}
}; // end puzInit object
Here is the full code
var puzz = {}; // put data array in object literal to namespace it into safety
puzz.data = entryData;
// append clues markup after puzzle wrapper div
// This should be moved into a configuration object
this.after('<div id="puzzle-clues"><h2>Across</h2><ol id="across"></ol><h2>Down</h2><ol id="down"></ol></div>');
// initialize some variables
var tbl = ['<table id="puzzle">'],
puzzEl = this,
clues = $('#puzzle-clues'),
clueLiEls,
coords,
entryCount = puzz.data.length,
entries = [],
rows = [],
cols = [],
solved = [],
tabindex,
$actives,
activePosition = 0,
activeClueIndex = 0,
currOri,
targetInput,
mode = 'interacting',
solvedToggle = false,
z = 0;
var puzInit = {
init: function() {
currOri = 'across'; // app's init orientation could move to config object
// Reorder the problems array ascending by POSITION
puzz.data.sort(function(a,b) {
return a.position - b.position;
});
// Set keyup handlers for the 'entry' inputs that will be added presently
puzzEl.delegate('input', 'keyup', function(e){
mode = 'interacting';
// need to figure out orientation up front, before we attempt to highlight an entry
switch(e.which) {
case 39:
case 37:
currOri = 'across';
break;
case 38:
case 40:
currOri = 'down';
break;
default:
break;
}
if ( e.keyCode === 9) {
return false;
} else if (
e.keyCode === 37 ||
e.keyCode === 38 ||
e.keyCode === 39 ||
e.keyCode === 40 ||
e.keyCode === 8 ||
e.keyCode === 46 ) {
if (e.keyCode === 8 || e.keyCode === 46) {
currOri === 'across' ? nav.nextPrevNav(e, 37) : nav.nextPrevNav(e, 38);
} else {
nav.nextPrevNav(e);
}
e.preventDefault();
return false;
} else {
console.log('input keyup: '+solvedToggle);
puzInit.checkAnswer(e);
}
e.preventDefault();
return false;
});
// tab navigation handler setup
puzzEl.delegate('input', 'keydown', function(e) {
if ( e.keyCode === 9) {
mode = "setting ui";
if (solvedToggle) solvedToggle = false;
//puzInit.checkAnswer(e)
nav.updateByEntry(e);
} else {
return true;
}
e.preventDefault();
});
// tab navigation handler setup
puzzEl.delegate('input', 'click', function(e) {
mode = "setting ui";
if (solvedToggle) solvedToggle = false;
console.log('input click: '+solvedToggle);
nav.updateByEntry(e);
e.preventDefault();
});
// click/tab clues 'navigation' handler setup
clues.delegate('li', 'click', function(e) {
mode = 'setting ui';
if (!e.keyCode) {
nav.updateByNav(e);
}
e.preventDefault();
});
// highlight the letter in selected 'light' - better ux than making user highlight letter with second action
puzzEl.delegate('#puzzle', 'click', function(e) {
$(e.target).focus();
$(e.target).select();`+`
});
// DELETE FOR BG
puzInit.calcCoords();
// Puzzle clues added to DOM in calcCoords(), so now immediately put mouse focus on first clue
clueLiEls = $('#puzzle-clues li');
$('#' + currOri + ' li' ).eq(0).addClass('clues-active').focus();
// DELETE FOR BG
puzInit.buildTable();
puzInit.buildEntries();
},
/*
- Given beginning coordinates, calculate all coordinates for entries, puts them into entries array
- Builds clue markup and puts screen focus on the first one
*/
calcCoords: function() {
/*
Calculate all puzzle entry coordinates, put into entries array
*/
for (var i = 0, p = entryCount; i < p; ++i) {
// set up array of coordinates for each problem
entries.push(i);
entries[i] = [];
for (var x=0, j = puzz.data[i].answer.length; x < j; ++x) {
entries[i].push(x);
coords = puzz.data[i].orientation === 'across' ? "" + puzz.data[i].startx++ + "," + puzz.data[i].starty + "" : "" + puzz.data[i].startx + "," + puzz.data[i].starty++ + "" ;
entries[i][x] = coords;
}
// while we're in here, add clues to DOM!
$('#' + puzz.data[i].orientation).append('<li tabindex="1" data-position="' + i + '">' + puzz.data[i].clue + '</li>');
}
// Calculate rows/cols by finding max coords of each entry, then picking the highest
for (var i = 0, p = entryCount; i < p; ++i) {
for (var x=0; x < entries[i].length; x++) {
cols.push(entries[i][x].split(',')[0]);
rows.push(entries[i][x].split(',')[1]);
};
}
rows = Math.max.apply(Math, rows) + "";
cols = Math.max.apply(Math, cols) + "";
},
/*
Build the table markup
- adds [data-coords] to each <td> cell
*/
buildTable: function() {
for (var i=1; i <= rows; ++i) {
tbl.push("<tr>");
for (var x=1; x <= cols; ++x) {
tbl.push('<td data-coords="' + x + ',' + i + '"></td>');
};
tbl.push("</tr>");
};
tbl.push("</table>");
puzzEl.append(tbl.join(''));
},
/*
Builds entries into table
- Adds entry class(es) to <td> cells
- Adds tabindexes to <inputs>
*/
buildEntries: function() {
var puzzCells = $('#puzzle td'),
light,
$groupedLights,
hasOffset = false,
positionOffset = entryCount - puzz.data[puzz.data.length-1].position; // diff. between total ENTRIES and highest POSITIONS
for (var x=1, p = entryCount; x <= p; ++x) {
var letters = puzz.data[x-1].answer.split('');
for (var i=0; i < entries[x-1].length; ++i) {
light = $(puzzCells +'[data-coords="' + entries[x-1][i] + '"]');
// check if POSITION property of the entry on current go-round is same as previous.
// If so, it means there's an across & down entry for the position.
// Therefore you need to subtract the offset when applying the entry class.
if(x > 1 ){
if (puzz.data[x-1].position === puzz.data[x-2].position) {
hasOffset = true;
};
}
if($(light).empty()){
$(light)
.addClass('entry-' + (hasOffset ? x - positionOffset : x) + ' position-' + (x-1) )
.append('<input maxlength="1" val="" type="text" tabindex="-1" />');
}
};
};
// Put entry number in first 'light' of each entry, skipping it if already present
for (var i=1, p = entryCount; i < p; ++i) {
$groupedLights = $('.entry-' + i);
if(!$('.entry-' + i +':eq(0) span').length){
$groupedLights.eq(0)
.append('<span>' + puzz.data[i].position + '</span>');
}
}
util.highlightEntry();
util.highlightClue();
$('.active').eq(0).focus();
$('.active').eq(0).select();
},
/*
- Checks current entry input group value against answer
- If not complete, auto-selects next input for user
*/
checkAnswer: function(e) {
var valToCheck, currVal;
util.getActivePositionFromClassGroup($(e.target));
valToCheck = puzz.data[activePosition].answer.toLowerCase();
currVal = $('.position-' + activePosition + ' input')
.map(function() {
return $(this)
.val()
.toLowerCase();
})
.get()
.join('');
//console.log(currVal + " " + valToCheck);
if(valToCheck === currVal){
$('.active')
.addClass('done')
.removeClass('active');
$('.clues-active').addClass('clue-done');
solved.push(valToCheck);
solvedToggle = true;
return;
}
currOri === 'across' ? nav.nextPrevNav(e, 39) : nav.nextPrevNav(e, 40);
//z++;
//console.log(z);
//console.log('checkAnswer() solvedToggle: '+solvedToggle);
}
}; // end puzInit object
var nav = {
nextPrevNav: function(e, override) {
var len = $actives.length,
struck = override ? override : e.which,
el = $(e.target),
p = el.parent(),
ps = el.parents(),
selector;
util.getActivePositionFromClassGroup(el);
util.highlightEntry();
util.highlightClue();
$('.current').removeClass('current');
selector = '.position-' + activePosition + ' input';
//console.log('nextPrevNav activePosition & struck: '+ activePosition + ' '+struck);
// move input focus/select to 'next' input
switch(struck) {
case 39:
p
.next()
.find('input')
.addClass('current')
.select();
break;
case 37:
p
.prev()
.find('input')
.addClass('current')
.select();
break;
case 40:
ps
.next('tr')
.find(selector)
.addClass('current')
.select();
break;
case 38:
ps
.prev('tr')
.find(selector)
.addClass('current')
.select();
break;
default:
break;
}
},
updateByNav: function(e) {
var target;
$('.clues-active').removeClass('clues-active');
$('.active').removeClass('active');
$('.current').removeClass('current');
currIndex = 0;
target = e.target;
activePosition = $(e.target).data('position');
util.highlightEntry();
util.highlightClue();
$('.active').eq(0).focus();
$('.active').eq(0).select();
$('.active').eq(0).addClass('current');
// store orientation for 'smart' auto-selecting next input
currOri = $('.clues-active').parent('ol').prop('id');
activeClueIndex = $(clueLiEls).index(e.target);
//console.log('updateByNav() activeClueIndex: '+activeClueIndex);
},
// Sets activePosition var and adds active class to current entry
updateByEntry: function(e, next) {
var classes, next, clue, e1Ori, e2Ori, e1Cell, e2Cell;
if(e.keyCode === 9 || next){
// handle tabbing through problems, which keys off clues and requires different handling
activeClueIndex = activeClueIndex === clueLiEls.length-1 ? 0 : ++activeClueIndex;
$('.clues-active').removeClass('.clues-active');
next = $(clueLiEls[activeClueIndex]);
currOri = next.parent().prop('id');
activePosition = $(next).data('position');
// skips over already-solved problems
util.getSkips(activeClueIndex);
activePosition = $(clueLiEls[activeClueIndex]).data('position');
} else {
activeClueIndex = activeClueIndex === clueLiEls.length-1 ? 0 : ++activeClueIndex;
util.getActivePositionFromClassGroup(e.target);
clue = $(clueLiEls + '[data-position=' + activePosition + ']');
activeClueIndex = $(clueLiEls).index(clue);
currOri = clue.parent().prop('id');
}
util.highlightEntry();
util.highlightClue();
//$actives.eq(0).addClass('current');
//console.log('nav.updateByEntry() reports activePosition as: '+activePosition);
}
}; // end nav object
var util = {
highlightEntry: function() {
// this routine needs to be smarter because it doesn't need to fire every time, only
// when activePosition changes
$actives = $('.active');
$actives.removeClass('active');
$actives = $('.position-' + activePosition + ' input').addClass('active');
$actives.eq(0).focus();
$actives.eq(0).select();
},
highlightClue: function() {
var clue;
$('.clues-active').removeClass('clues-active');
$(clueLiEls + '[data-position=' + activePosition + ']').addClass('clues-active');
if (mode === 'interacting') {
clue = $(clueLiEls + '[data-position=' + activePosition + ']');
activeClueIndex = $(clueLiEls).index(clue);
};
},
getClasses: function(light, type) {
if (!light.length) return false;
var classes = $(light).prop('class').split(' '),
classLen = classes.length,
positions = [];
// pluck out just the position classes
for(var i=0; i < classLen; ++i){
if (!classes[i].indexOf(type) ) {
positions.push(classes[i]);
}
}
return positions;
},
getActivePositionFromClassGroup: function(el){
classes = util.getClasses($(el).parent(), 'position');
if(classes.length > 1){
// get orientation for each reported position
e1Ori = $(clueLiEls + '[data-position=' + classes[0].split('-')[1] + ']').parent().prop('id');
e2Ori = $(clueLiEls + '[data-position=' + classes[1].split('-')[1] + ']').parent().prop('id');
// test if clicked input is first in series. If so, and it intersects with
// entry of opposite orientation, switch to select this one instead
e1Cell = $('.position-' + classes[0].split('-')[1] + ' input').index(el);
e2Cell = $('.position-' + classes[1].split('-')[1] + ' input').index(el);
if(mode === "setting ui"){
currOri = e1Cell === 0 ? e1Ori : e2Ori; // change orientation if cell clicked was first in a entry of opposite direction
}
if(e1Ori === currOri){
activePosition = classes[0].split('-')[1];
} else if(e2Ori === currOri){
activePosition = classes[1].split('-')[1];
}
} else {
activePosition = classes[0].split('-')[1];
}
console.log('getActivePositionFromClassGroup activePosition: '+activePosition);
},
checkSolved: function(valToCheck) {
for (var i=0, s=solved.length; i < s; i++) {
if(valToCheck === solved[i]){
return true;
}
}
},
getSkips: function(position) {
if ($(clueLiEls[position]).hasClass('clue-done')){
activeClueIndex = position === clueLiEls.length-1 ? 0 : ++activeClueIndex;
util.getSkips(activeClueIndex);
} else {
return false;
}
}
}; // end util object
puzInit.init();
}
This is fun to solve. Did you mean show message when all question has answered? If yes, You can simply create a variable that saving every word that has answered. Then, inside function checkAnswer(), check if total word answered same as data entry.
I made that custom code here https://codeshare.io/G81rmE
I have a cycle of links and I determined click event on them. And I want to define if navbar[1].clicked == true {doing something} else if navbar[2].cliked == true {doing something} etc. "By if else in " reveal functional callbackFn".
Here is the code:
var navbar = document.getElementById("navbar").getElementsByTagName("a");
for (var i = 0; i < navbar.length; i++) {
navbar[i].addEventListener('click', function() { reveal('top'); });
}
function reveal(direction) {
callbackFn = function() {
// this is the part where is running the turning of pages
classie.remove(pages[currentPage], 'page--current');
if (navbar[1].clicked == true) {
currentPage = 0;
} else if(navbar[1].clicked == true) {
currentPage = 1;
} else if(navbar[2].clicked == true) {
currentPage = 2;
} else if(navbar[3].clicked == true) {
currentPage = 3;
} else if(navbar[4].clicked == true) {
currentPage = 4;
};
classie.add(pages[currentPage], 'page--current');
};
}
This is typically a problem of closure.
You can make the following change
Here the call back function of the addEventListener is an IIFE, & in the reveal function pass the value of i
var navbar = document.getElementById("navbar").getElementsByTagName("a");
for (var i = 0; i < navbar.length; i++) {
navbar[i].addEventListener('click', (function(x) {
reveal('top',x);
}(i))};
}
In this function you will have access to
function reveal(direction,index) {
// not sure what this function is mean by, but you will have the value of `i` which is denote the clicked element
callbackFn = function() {
// this is the part where is running the turning of pages
classie.remove(pages[currentPage], 'page--current');
if (index == 1) {
currentPage = 0;
} else if (index == 1) {
currentPage = 1;
} else if (index == 2) {
currentPage = 2;
} else if (index == 3) {
currentPage = 3;
} else if (index == 4) {
currentPage = 4;
};
classie.add(pages[currentPage], 'page--current');
};
}
Here is the solution in my case.
Thank you brk for helping in any case, thanks again.
// determine clicked item
var n;
$('#navbar a').click(function(){
if($(this).attr('id') == 'a') {
n = 0;
} else if($(this).attr('id') == 'b') {
n = 1;
} else if($(this).attr('id') == 'c') {
n = 2;
} else if($(this).attr('id') == 'd') {
n = 3;
} else if($(this).attr('id') == 'e') {
n = 4;
};
});
var pages = [].slice.call(document.querySelectorAll('.pages > .page')),
currentPage = 0,
revealerOpts = {
// the layers are the elements that move from the sides
nmbLayers : 3,
// bg color of each layer
bgcolor : ['#52b7b9', '#ffffff', '#53b7eb'],
// effect classname
effect : 'anim--effect-3'
};
revealer = new Revealer(revealerOpts);
// clicking the page nav
document.querySelector("#a").addEventListener('click', function() { reveal('cornertopleft'); });
document.querySelector("#b").addEventListener('click', function() { reveal('bottom'); });
document.querySelector("#c").addEventListener('click', function() { reveal('left'); });
document.querySelector("#d").addEventListener('click', function() { reveal('right'); });
document.querySelector("#e").addEventListener('click', function() { reveal('top'); });
// moving clicked item's `n` into the function
function reveal(direction) {
var callbackTime = 750;
callbackFn = function() {
classie.remove(pages[currentPage], 'page--current');
currentPage = n;
classie.add(pages[currentPage], 'page--current');
};
revealer.reveal(direction, callbackTime, callbackFn);
}
I am using JavaScript to highlight the occurrence of characters in a UIWebView. I use the following JavaScript code:
var uiWebview_SearchResultCount = 0;
function uiWebview_HighlightAllOccurencesOfStringForElement(element,keyword) {
if (element) {
if (element.nodeType == 3) { // Text node
while (true) {
//if (counter < 1) {
var value = element.nodeValue; // Search for keyword in text node
var idx = value.toLowerCase().indexOf(keyword);
if (idx < 0) break; // not found, abort
//(value.split);
//we create a SPAN element for every parts of matched keywords
var span = document.createElement("span");
var text = document.createTextNode(value.substr(idx,keyword.length));
span.appendChild(text);
span.setAttribute("class","uiWebviewHighlight");
span.style.backgroundColor="yellow";
span.style.color="black";
uiWebview_SearchResultCount++; // update the counter
text = document.createTextNode(value.substr(idx+keyword.length));
element.deleteData(idx, value.length - idx);
var next = element.nextSibling;
element.parentNode.insertBefore(span, next);
element.parentNode.insertBefore(text, next);
element = text;
window.scrollTo(0,span.offsetTop);
}
} else if (element.nodeType == 1) { // Element node
if (element.style.display != "none" && element.nodeName.toLowerCase() != 'select') {
for (var i=element.childNodes.length-1; i>=0; i--) {
uiWebview_HighlightAllOccurencesOfStringForElement(element.childNodes[i],keyword);
}
}
}
}
}
// the main entry point to start the search
function uiWebview_HighlightAllOccurencesOfString(keyword) {
uiWebview_RemoveAllHighlights();
uiWebview_HighlightAllOccurencesOfStringForElement(document.body, keyword.toLowerCase());
}
// helper function, recursively removes the highlights in elements and their childs
function uiWebview_RemoveAllHighlightsForElement(element) {
if (element) {
if (element.nodeType == 1) {
if (element.getAttribute("class") == "uiWebviewHighlight") {
var text = element.removeChild(element.firstChild);
element.parentNode.insertBefore(text,element);
element.parentNode.removeChild(element);
return true;
} else {
var normalize = false;
for (var i=element.childNodes.length-1; i>=0; i--) {
if (uiWebview_RemoveAllHighlightsForElement(element.childNodes[i])) {
normalize = true;
}
}
if (normalize) {
element.normalize();
}
}
}
}
return false;
}
// the main entry point to remove the highlights
function uiWebview_RemoveAllHighlights() {
uiWebview_SearchResultCount = 0;
uiWebview_RemoveAllHighlightsForElement(document.body);
}
I then call this and everything works fine. My problem is that for characters that are in the middle of a word (for example و which is in the middle of توحید), it disconnects the و character from its previous character (and it becomes ت وحید).
All,
I have three cards which can be shuffled by the user, upon hover, the target card pops to the top, the last card on top should sit in the second position. While with the code below, I can have this effect in one direction (left to right), I am struggling to come up with logic & code for getting the effect to work in both directions without having to write multiple scenarios in js (which doesnt sound like very good logic).
Hopefully the demo will do a better explanation.
Code:
$(".cBBTemplates").on (
{
hover: function (e)
{
var aBBTemplates = document.getElementsByClassName ("cBBTemplates");
var i = 2;
while (i < aBBTemplates.length && i >= 0)
{
var eCurVar = aBBTemplates[i];
if (eCurVar === e.target)
{
eCurVar.style.zIndex = 3;
} else if (eCurVar.style.zIndex === 3) {
console.log (eCurVar);
eCurVar.style.zIndex = 3-1;
} else
{
eCurVar.style.zIndex = i;
}
i--;
}
}
});
Try this:
$(function(){
var current = 2;
$(".cBBTemplates").on (
{
hover: function ()
{
var target = this,
newCurrent, templates = $(".cBBTemplates");
templates.each(
function(idx){
if(this === target){
newCurrent = idx;
}
});
if(newCurrent === current){return;}
templates.each(function(index){
var zIndex = 0;
if(this === target) {
zIndex = 2;
}
else if (index == current) {
zIndex = 1;
}
$(this).css('zIndex', zIndex);
});
current = newCurrent;
}
});
});
I'm using jquery with dropdownchecklist item.
this is my code to config selectbox.
jQuery('#selectbox').dropdownchecklist({ width: 120, maxDropHeight: 100, firstItemChecksAll: false, emptyText: 'Select' });
I want to limit the select for only 2 selects.
If the user select 2 options all others item will disable for selecting.
How can I do it?
Update:
I found the easiest way to do this
function Selectbox_limit(jidList) {
var jids = '';
var counter = 0;
for(var i=0; i<jidList.options.length; i++) {
if(jidList.options[i].selected == true)
counter++;
if(counter >= 2) {
jidList.options[i-1].selected = false;
jQuery("#selectbox").dropdownchecklist("destroy");
jQuery("#selectbox option").attr('disabled','disabled');
jQuery("#selectbox option:selected").attr("disabled","");
jQuery('#selectbox').dropdownchecklist({ _propeties_ });
return;
} else if(counter < 2) {
jQuery("#selectbox").dropdownchecklist("destroy");
jQuery("#selectbox option").attr("disabled","");
jQuery('#selectbox').dropdownchecklist({ _propeties_ });
return;
}
}
The dropdownchecklist add the class active to the check boxes so you can use it like this:
$('.active').change(function () {
var num = 0;
$('.active:checked').each(function () {
num++;
});
if(num >= 2)
{
$('.active:checked').attr("disabled", "disabled");
$('.active:checked').each(function () {
$(this).removeAttr();
});
}
else
{
$('.active').removeAttr("disabled", "disabled");
}
});
here is a sample of a jQuery Dropdown Check List with limit
onItemClick: function(checkbox, selector){
var justChecked = checkbox.prop("checked");
var checkCount = (justChecked) ? 1 : -1;
for( i = 0; i < selector.options.length; i++ ){
if ( selector.options[i].selected ) checkCount += 1;
}
if ( checkCount > 3 ) {
alert( "Limit is 3" );
throw "too many";
}
}
You can do it by this
var $b = $('input[type=checkbox]');
if(($b.filter(':checked').length)>2){
$b.attr("disabled", true);
}
or you can use
$(':checkbox:checked").length
$(":checkbox").filter(':checked').length
hope it help.