Js chess call sub function - javascript

My question is: How is it possible to call the function mova from outside the function init?
init.mova("a2-a3"); doesn't work
The full code is here.
This is a chessboard system.
I don't now how to call the function mova from outside init. init.mova doesn't work.
Code:
var init = function() {
//--- start example JS ---
var board,
game = new Chess(),
statusEl = $('#status'),
fenEl = $('#fen'),
pgnEl = $('#pgn');
// do not pick up pieces if the game is over
// only pick up pieces for the side to move
var onDragStart = function(source, piece, position, orientation) {
if (game.game_over() === true ||
(game.turn() === 'w' && piece.search(/^b/) !== -1) ||
(game.turn() === 'b' && piece.search(/^w/) !== -1)) {
return false;
}
};
var onDrop = function(source, target) {
// see if the move is legal
var move = game.move({
from: source,
to: target,
promotion: 'q' // NOTE: always promote to a queen for example simplicity
});
if (move !== null) {
console.log(move.to);
}
// illegal move
if (move === null) return 'snapback';
updateStatus();
};
// update the board position after the piece snap
// for castling, en passant, pawn promotion
var onSnapEnd = function() {
board.position(game.fen());
};
var updateStatus = function() {
var status = '';
var moveColor = 'White';
if (game.turn() === 'b') {
moveColor = 'Black';
}
// checkmate?
if (game.in_checkmate() === true) {
status = 'Game over, ' + moveColor + ' is in checkmate.';
}
// draw?
else if (game.in_draw() === true) {
status = 'Game over, drawn position';
}
// game still on
else {
status = moveColor + ' to move';
// check?
if (game.in_check() === true) {
status += ', ' + moveColor + ' is in check';
}
}
statusEl.html(status);
fenEl.html(game.fen());
pgnEl.html(game.pgn());
};
var cfg = {
draggable: true,
position: 'start',
onDragStart: onDragStart,
onDrop: onDrop,
onSnapEnd: onSnapEnd
};
board = new ChessBoard('board', cfg);
updateStatus();
//--- end example JS ---
var mova = function(positie) {
board.move(positie);
}
}; // end init()
$(document).ready(init);
init.mova("a2-a3");

Variables defined within a function are scoped to that function. They cannot be called from outside of the function.
If you wanted a quick and dirty fix, you could define the variable mova outside the init() function, and then assign its value within it.
var mova;
var init = function() {
// etc. etc.
mova = function(positie) {
board.move(positie);
}
}
then, the mova function would be available outside of the init function once it has run.
You could ensure that you don't try to use the function until it's defined by using a function that is called when your init completes:
var mova;
var init = function() {
// etc. etc.
mova = function(positie) {
board.move(positie);
}
onInitComplete();
}
function onInitComplete() {
// function using mova function
}
It's likely, given the structure of your program, that you will want to use the same technique for many variables other than just mova. You probably don't want all of your game logic inside the init() function. You could define some variables for the state of your game outside the init function and then just assign them their starting values inside it. Hope that helps.

Related

How do I initiate the function on button click?

Following code starts a chess game in initial position integrating chess.js library.
var board = null
var game = new Chess()
var $status = $('#status')
var $fen = $('#fen')
var $pgn = $('#pgn')
function onDragStart (source, piece, position, orientation) {
// do not pick up pieces if the game is over
if (game.game_over()) return false
// only pick up pieces for the side to move
if ((game.turn() === 'w' && piece.search(/^b/) !== -1) ||
(game.turn() === 'b' && piece.search(/^w/) !== -1)) {
return false
}
}
function onDrop (source, target) {
// see if the move is legal
var move = game.move({
from: source,
to: target,
promotion: 'q' // NOTE: always promote to a queen for example simplicity
})
// illegal move
if (move === null) return 'snapback'
updateStatus()
}
// update the board position after the piece snap
// for castling, en passant, pawn promotion
function onSnapEnd () {
board.position(game.fen())
}
function updateStatus () {
var status = ''
var moveColor = 'White'
if (game.turn() === 'b') {
moveColor = 'Black'
}
// checkmate?
if (game.in_checkmate()) {
status = 'Game over, ' + moveColor + ' is in checkmate.'
}
// draw?
else if (game.in_draw()) {
status = 'Game over, drawn position'
}
// game still on
else {
status = moveColor + ' to move'
// check?
if (game.in_check()) {
status += ', ' + moveColor + ' is in check'
}
}
$status.html(status)
$fen.html(game.fen())
$pgn.html(game.pgn())
}
var config = {
draggable: true,
position: 'start',
onDragStart: onDragStart,
onDrop: onDrop,
onSnapEnd: onSnapEnd
}
board = Chessboard('board2', config)
updateStatus()
After checkmate though there is no option to clear the board. Is there a way to integrate the following code so I can only start the game or the clear the board if the respective button is clicked? The start button places the pieces in their default position on a clear board using only the draggable function set to true within Chessboard.
$('#startBtn').on('click', board2.start)
$('#clearBtn').on('click', board2.clear)
I simply added the code for the buttons at the bottom of your code. This code attaches event handlers to the start and clear buttons, so it could be placed anywhere outside of a function. Here's some code to display the two buttons below the board. I also added some code to run the code inside the code snippet.
var board = null
var game = new Chess()
var $status = $('#status')
var $fen = $('#fen')
var $pgn = $('#pgn')
function onDragStart (source, piece, position, orientation) {
// do not pick up pieces if the game is over
if (game.game_over()) return false
// only pick up pieces for the side to move
if ((game.turn() === 'w' && piece.search(/^b/) !== -1) ||
(game.turn() === 'b' && piece.search(/^w/) !== -1)) {
return false
}
}
function onDrop (source, target) {
// see if the move is legal
var move = game.move({
from: source,
to: target,
promotion: 'q' // NOTE: always promote to a queen for example simplicity
})
// illegal move
if (move === null) return 'snapback'
updateStatus()
}
// update the board position after the piece snap
// for castling, en passant, pawn promotion
function onSnapEnd () {
board.position(game.fen())
}
function updateStatus () {
var status = ''
var moveColor = 'White'
if (game.turn() === 'b') {
moveColor = 'Black'
}
// checkmate?
if (game.in_checkmate()) {
status = 'Game over, ' + moveColor + ' is in checkmate.'
}
// draw?
else if (game.in_draw()) {
status = 'Game over, drawn position'
}
// game still on
else {
status = moveColor + ' to move'
// check?
if (game.in_check()) {
status += ', ' + moveColor + ' is in check'
}
}
$status.html(status)
$fen.html(game.fen())
$pgn.html(game.pgn())
}
pieceTemplates = ({wiki:'https://chessboardjs.com/img/chesspieces/wikipedia/{piece}.png',
alpha:'https://chessboardjs.com/img/chesspieces/alpha/{piece}.png'})
var config = {
draggable: true,
pieceTheme:pieceTemplates.wiki,
position: 'start',
onDragStart: onDragStart,
onDrop: onDrop,
onSnapEnd: onSnapEnd
}
board = Chessboard('board', config)
updateStatus()
$('#startBtn').on('click', function () {
game.reset()
board.start()
})
$('#clearBtn').on('click', function () {
game.reset()
board.clear()
})
<link rel="stylesheet"
href="https://unpkg.com/#chrisoakman/chessboardjs#1.0.0/dist/chessboard-1.0.0.min.css"
integrity="sha384-q94+BZtLrkL1/ohfjR8c6L+A6qzNH9R2hBLwyoAfu3i/WCvQjzL2RQJ3uNHDISdU"
crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"
integrity="sha384-ZvpUoO/+PpLXR1lu4jmpXWu80pZlYUAfxl5NsBMWOEPSjUn/6Z/hRTt8+pR6L4N2"
crossorigin="anonymous"></script>
<script src="https://unpkg.com/#chrisoakman/chessboardjs#1.0.0/dist/chessboard-1.0.0.min.js"
integrity="sha384-8Vi8VHwn3vjQ9eUHUxex3JSN/NFqUg3QbPyX8kWyb93+8AC/pPWTzj+nHtbC5bxD"
crossorigin="anonymous"></script>
<script src="https://unpkg.com/chess.js#0.12.1/chess.js"></script>
<div id="board" style="width:400px;"></div>
<button id="startBtn">Start Position</button>
<button id="clearBtn">Clear Board</button>

How to wait for 3rd party JavaScript function to return

Given the following snippet of code
var empowerInstance = null;
function onClick_btnSendMessage() {
var childIFrame = window.document.getElementById("editorFrame");
if (!empowerInstance) {
empowerInstance = EditorAPI.getInstance(childIFrame.contentWindow, window.location.origin);
}
empowerInstance.document.hasChanged(hasChangedCallback);
}
function hasChangedCallback(returnValue) {
console.log("empowerInstance.document.hasChanged = " + returnValue.isDirty);
if (returnValue.success === true && returnValue.isDirty === true) {
empowerInstance.document.save(saveCallback);
}
}
function saveCallback(returnValue) {
console.log("empowerInstance.document.save = " + returnValue.success);
if (returnValue.success === false) {
console.log(returnValue.message);
}
}
window.addEventListener("DOMContentLoaded", function (event) {
console.log("DOM fully loaded and parsed");
if (typeof location.origin === "undefined")
window.location.origin = window.location.protocol + "//" + window.location.host;
document.getElementById("btnSendMessage").addEventListener("click", onClick_btnSendMessage);
});
Instead of wiring the button up , I'd like to fire the code from the activation of a Bootstrap tab event.
$('a[data-toggle="tab"]').on("shown.bs.tab", function (e) {
onClick_btnSendMessage(); // Naive way, as this does not wait
var target = $(e.target).attr("data-EditorUrl"); // activated tab
var childIFrame = $("#editorFrame");
childIFrame.attr("src", target);
});
So my question is "How do I wait on this function to complete before changing the source of childIFrame?".
empowerInstance.document.hasChanged(hasChangedCallback);
I conceptually understand the use of Promises and Callbacks, but writing one that functions correctly is a different story.
UPDATED
This version is refactored to eliminate the button handler, thus improving readability.
The usage is also important. When the page loads for the first time it is positioned on a tab. This tab is associated to a document that is hosted in an iFrame. If the user edits this document then tries to change tabs, I'd like to invoke the check for being dirty/save, then once saved, move to the next tab/document. There is also the case that switching between tabs/documents won't cause a save because the document is not dirty.
var empowerInstance = null;
function hasChangedCallback(returnValue) {
console.log("empowerInstance.document.hasChanged = " + returnValue.isDirty);
if (returnValue.success === true && returnValue.isDirty === true) {
empowerInstance.document.save(saveCallback);
}
}
function saveCallback(returnValue) {
console.log("empowerInstance.document.save = " + returnValue.success);
if (returnValue.success === false) {
console.log(returnValue.message);
}
}
$(function () {
if (typeof location.origin === "undefined") {
window.location.origin = window.location.protocol + "//" + window.location.host;
}
$('a[data-toggle="tab"]').on("shown.bs.tab", function (e) {
var childIFrame = $("#editorFrame");
if (!empowerInstance) {
empowerInstance = EditorAPI.getInstance(childIFrame[0].contentWindow, window.location.origin);
}
empowerInstance.document.hasChanged(hasChangedCallback);// Need to wait for completion
var target = $(e.target).attr("data-EditorUrl"); // activated tab
childIFrame.attr("src", target);
});
});
Thank you,
Stephen
I've refactored your code to show how this can be done using promises.
function onClick_btnSendMessage() {
var childIFrame = window.document.getElementById("editorFrame");
if (!empowerInstance) {
empowerInstance = EditorAPI.getInstance(childIFrame.contentWindow, window.location.origin);
}
var doc = empowerInstance.document;
return hasChanged(doc).then(function() { return save(doc) })
}
function hasChanged(doc) {
return new Promise(function(resolve, reject) {
doc.hasChanged(function(returnValue) {
if (returnValue.success === true && returnValue.isDirty === true) {
resolve(returnValue)
} else {
reject(returnValue)
}
})
})
}
function save(doc) {
return new Promise(function(resolve, reject) {
doc.save(function(returnValue) {
if (returnValue.success === false) {
console.log(returnValue.message);
reject(returnValue)
} else {
resolve(returnValue)
}
})
})
}
// ------
$('a[data-toggle="tab"]').on("shown.bs.tab", function(e) {
onClick_btnSendMessage().then(function() {
var target = $(e.target).attr("data-EditorUrl"); // activated tab
var childIFrame = $("#editorFrame");
childIFrame.attr("src", target);
}).catch(function(error) {
// handle the error
console.error('Error!', error)
})
});
You can use some higher order functions to do what you want. Instead of passing the hasChangedCallback and saveCallback directly to the empowerInstance.document methods, you'll instead invoke a function that returns those callbacks, but also passes along your own callback that you'll call once all the async operations have finally completed. Here's what it'll look like:
$('a[data-toggle="tab"]').on("shown.bs.tab", function (e) {
var target = $(e.target).attr("data-EditorUrl"); // activated tab
onClick_btnSendMessage(function () {
var childIFrame = $("#editorFrame");
childIFrame.attr("src", target);
});
});
function onClick_btnSendMessage(myCallback) {
var childIFrame = window.document.getElementById("editorFrame");
if (!empowerInstance) {
empowerInstance = EditorAPI.getInstance(childIFrame.contentWindow, window.location.origin);
}
empowerInstance.document.hasChanged(getHasChangedCallback(myCallback));
}
function getHasChangedCallback(myCallback) {
return function hasChangedCallback(returnValue, myCallback) {
console.log("empowerInstance.document.hasChanged = " + returnValue.isDirty);
if (returnValue.success === true && returnValue.isDirty === true) {
empowerInstance.document.save(getSaveCallback(myCallback));
}
}
}
function getSaveCallback(myCallback) {
return function saveCallback(returnValue) {
console.log("empowerInstance.document.save = " + returnValue.success);
if (returnValue.success === false) {
console.log(returnValue.message);
}
myCallback && myCallback(); // make sure myCallback isn't null before invoking
}
}
It's not exactly attractive, but it should get you what you want.

how to arcgis javascript vertex undoManager

I try to undo / redo the edit vertex using undomanager.
Graphic objects are tested. But I do not know what to do Edit vertex undo / redo.
Is it possible the vertex undo / redo?
I looked to find many examples have not found the answer.
i`m korean beginner programmer. help me~ T.T
function initEditing(evt) {
console.log("initEditing", evt);
var currentLayer = null;
var layers = arrayUtils.map(evt.layers, function(result) {
return result.layer;
console.log("result ==== "+result);
});
console.log("layers", layers);
editToolbar = new Edit(map);
editToolbar.on("deactivate", function(evt) {
console.log("deactivate !!!! ");
currentLayer.applyEdits(null, [evt.graphic], null);
});
arrayUtils.forEach(layers, function(layer) {
var editingEnabled = false;
layer.on("dbl-click", function(evt) {
event.stop(evt);
if (editingEnabled === false) {
editingEnabled = true;
editToolbar.activate(Edit.EDIT_VERTICES , evt.graphic);
pre_evt = evt.graphic;
editToolbar.on("vertex-move-stop", function(evt){
console.log("vertex-move-stop~");
g_evt = evt;
console.log("evt.transform ===== " +evt.transform);
var operation = new esri.dijit.editing.Update({
featureLayer : landusePointLayer,
preUpdatedGraphics:pre_evt,
postUpdatedGraphics: evt.graphic
})
var operation = new CustomOperation.Add({
graphicsLayer: pre_evt._graphicsLayer,
addedGraphic: evt.graphic
});
undoManager.add(operation);
console.log("operation ======== ",operation);
});
console.log("dbl-click & eidt true");
} else {
currentLayer = this;
editToolbar.deactivate();
editingEnabled = false;
console.log("dbl-click & eidt false ");
}
});
The sample you are refering to, just gives you an idea how you can use UndoManager. You need to create your own operations if you need undo/redo for vertices. Below I have provided one for AddVertex. You would need to create your own for other operations.
define(["dojo/_base/declare",
"esri/OperationBase"],
function(declare,
OperationBase) {
var customOp = {};
customOp.AddVertex = declare(OperationBase, {
label: "Add Vertex",
_editedGraphic: null,
_vertexInfo: null,
_vertex: null,
_editTool: null,
constructor: function (params) {
params = params || {};
if (!params.editTool) {
console.error("no edit toolbar provided");
return;
}
this._editTool = params.editTool;
if (!params.editedGraphic) {
console.error("no graphics provided");
return;
}
this._editedGraphic = params.editedGraphic;
if (!params.vertexinfo) {
console.error("no vertexinfo provided");
return;
}
this._vertexInfo = params.vertexinfo;
var geometry = this._editedGraphic.geometry;
if(geometry.type === "multipoint") {
this._vertex = geometry.getPoint(this._vertexInfo.pointIndex);
} else if(geometry.type === "polyline" || geometry.type === "polygon") {
this._vertex = geometry.getPoint(this._vertexInfo.segmentIndex, this._vertexInfo.pointIndex);
} else {
console.error("Not valid geometry type.");
}
},
performUndo: function () {
var geometry = this._editedGraphic.geometry;
if(geometry.type === "multipoint"){
geometry.removePoint(this._vertexInfo.pointIndex);
} else if(geometry.type === "polyline" || geometry.type === "polygon") {
geometry.removePoint(this._vertexInfo.segmentIndex, this._vertexInfo.pointIndex);
}
this._editedGraphic.draw();
this._editTool.refresh();
},
performRedo: function () {
var geometry = this._editedGraphic.geometry;
if(geometry.type === "multipoint"){
geometry.removePoint(this._vertexInfo.pointIndex, this._vertex);
} else if(geometry.type === "polyline" || geometry.type === "polygon") {
geometry.insertPoint(this._vertexInfo.segmentIndex, this._vertexInfo.pointIndex, this._vertex);
}
this._editedGraphic.draw();
this._editTool.refresh();
}
});
return customOp;
});
Make sure you clear the UndoManager when you deactivate the edit toolbar. Otherwise the Operations will remain. Do not combine the Add graphics operations with Vertex Operations. It will not work as they use different toolbar and edit toolbar state will be lost as soon as you deactive it.
One more thing to note is when you use the UndoManager, the graphics isModified state will always be true, since we are adding and deleting vertex during undo/redo, even if undo all changes. Hence, make sure you need to applyedit by checking if there are any pending undo (geometry is really modified).
Hope this was helpful.

Trouble with Flexslider and YouTube Iframe API on Firefox ("* is not a function")

I'm trying to implement a site with a slider that plays videos. I followed one of the answers here to be able to stop the sliders from drifting off while a video was playing, but now I need to be able to stop the actual playback of the video when the user leaves the slide.
This is my current code:
// Define YT_ready function.
var YT_ready = (function(){
var onReady_funcs = [], api_isReady = false;
/* #param func function Function to execute on ready
* #param func Boolean If true, all qeued functions are executed
* #param b_before Boolean If true, the func will added to the first
position in the queue*/
return function(func, b_before){
if (func === true) {
api_isReady = true;
for (var i=0; i<onReady_funcs.length; i++){
// Removes the first func from the array, and execute func
onReady_funcs.shift()();
}
}
else if(typeof func == "function") {
if (api_isReady) func();
else onReady_funcs[b_before?"unshift":"push"](func);
}
}
})();
// This function will be called when the API is fully loaded
function onYouTubePlayerAPIReady() {YT_ready(true)}
// Load YouTube Frame API
(function(){ //Closure, to not leak to the scope
var s = document.createElement("script");
s.src = "http://www.youtube.com/player_api"; /* Load Player API*/
var before = document.getElementsByTagName("script")[0];
before.parentNode.insertBefore(s, before);
})();
var players = {};
//Define a player storage object, to enable later function calls,
// without having to create a new class instance again.
YT_ready(function() {
(function($) {
$(".framevideo").each(function(index) {
var identifier = this.id;
var frameID = getFrameID(identifier);
if (frameID) { //If the frame exists
players[frameID] = new YT.Player(frameID, {
events: {
"onStateChange": function(event) {
if(event.data == 1 || event.data == 3) {
//console.log("The video two is playing and the cycle is paused = " + event.data);
$('.flexslider').flexslider('pause');
}
else if(/* event.data == -1 || */ event.data == 0 || event.data == 2 || event.data == 5) {
//console.log("The video two is not playing and the cycle is started = " + event.data);
$('.flexslider').flexslider('play');
}
}
}
});
}
});
$('.flexslider').bind('before', function() {
for (var key in players)
{
/* this works in Chrome and IE9, doesn't work on Firefox?! */
players[key].pauseVideo();
}
});
})(jQuery);
});
I know that players is looping correctly, I've debugged it with console.log and I get the keys for all the players, but players[key].pauseVideo(); gives me an error TypeError: players[key].pauseVideo is not a function.
Thanks for any help.
I ended up writing the function so that it would load the YouTube player only when each slide was active, then storing it in the container object. It was the only way to ensure that it was displaying and didn't fail.
var players = {};
//Define a player storage object, to enable later function calls,
// without having to create a new class instance again.
YT_ready(function() {
(function($) {
createPlayers();
//console.log('binding');
$('.flexslider').bind('after', function() {
createPlayers();
});
$('.flexslider').bind('before', function() {
for (key in players) {
//console.log('pausing '+key);
players[key].pauseVideo();
}
});
})(jQuery);
});
// this function will check for all frames that don't have a display:none attribute, and create a player for them
function createPlayers() {
(function($) {
//console.log('attempting to create players');
$(".framevideo").each(function(index) {
var frameID = getFrameID(this.id);
if (frameID) { //If the frame exists
// we check if frame already has associated key in container object
if (!(frameID in players)) {
// now we check if the parent slider "row" is displayed
if ($(this).parents('.flexslider-views-slideshow-main-frame-row').css('display') !== 'none') {
// we create the player and add it to the container
//console.log('creating '+frameID);
players[frameID] = new YT.Player(frameID, {
events: {
"onStateChange": function(event) {
if(event.data == 1 || event.data == 3) {
$('.flexslider').flexslider('pause');
}
else if(/* event.data == -1 || */ event.data == 0 || event.data == 2 || event.data == 5) {
$('.flexslider').flexslider('play');
}
}
}
});
}
}
}
});
})(jQuery);
}

jQuery debug functionlity in a "class" file

im creating a simple game and, I need some direction for debuging some data.
i have a div in my HTML file, that I want him to show some data that change when some variables get change by the user actions.
for exmple i got var xPosition, I want to send the data to a div in the HTML, so i can see the current state of xPosition.
i realy dont have any idea where to start creating this functionlity.
my questions:
is it possible to create event inside this class and register some
element to him that will show all the changing data?
do i have to use a some a timer for that sort of thing?
this is the "class":
(function ($) {
$.Player = function (element) {
this.element = (element instanceof $) ? element : $(element);
this.movmentSpeed = 10;
this.size = $(element).width();
this.xPos = 0;
this.yPos = 0;
};
$.Player.prototype = {
//register events
InitEvents: function () {
var that = this;
$(document).keydown(function (e) {
var key = e.which;
if (key == 39) {
that.moveRight(400);
} else if (key == 37) {
that.moveLeft();
}
});
this.element.css({
left: this.xPos
});
},
//movment functions
moveRight: function (worldWidth) {
if ((this.xPos + this.size) <= worldWidth) {
this.xPos += this.movmentSpeed;
this.element.css("left", '+=' + this.movmentSpeed);
}
},
moveLeft: function () {
if (this.xPos > 0) {
this.xPos -= this.movmentSpeed;
this.element.css("left", '-=' + this.movmentSpeed);
}
}
};
} (jQuery));
here the HTML:
<div id="player">
<div id="debugData"> <div>
<script>
var player = new $.Player($("#player"));
player.InitEvents();
</script>
(sorry for my english)
jsFiddle Demo
I'd say having an internal function inside the Class would help. Maybe even having a setting where you turn the logging on by doing player.logging = true;, and having it default to false;
In your prototype just add a public prototype variable for logging = false, and our prototype function log().
The internal function you could use could be something as simple as:
logging : false, // our default
log : function (str) {
if (this.logging) {
$('#debugData').html(str);
}
},
This way you could leave your log(this.xPos); (or whatever you want to log) within your code, and by removing the player.logging = true; when you instantiate your class, they won't show up, till you put that code back in.

Categories