מדיה ויקי:Gadget-pgnviewer.js: הבדלים בין גרסאות בדף
לטובת השבירה |
מ 85 גרסאות של הדף wikipedia:he:מדיה_ויקי:Gadget-pgnviewer.js יובאו |
||
| (24 גרסאות ביניים של 2 משתמשים אינן מוצגות) | |||
| שורה 23: | שורה 23: | ||
sides = ['n', 'e', 's', 'w'], // used for legends | sides = ['n', 'e', 's', 'w'], // used for legends | ||
rowClassPrefix = 'pgn-prow-', | rowClassPrefix = 'pgn-prow-', | ||
fileClassPrefix = 'pgn-pfile-', | |||
allFilesAndColumnClasses = "01234567" | allFilesAndColumnClasses = "01234567" | ||
.split("") | .split("") | ||
.map(function(i) { return rowClassPrefix + i + ' ' + fileClassPrefix + i;}) | .map( function( i ) { return rowClassPrefix + i + ' ' + fileClassPrefix + i; } ) | ||
.join(" "), | .join(" "), | ||
hiddenPiece = 'pgn-piece-hidden', | |||
chessboardClass = 'pgn-board-img', | chessboardClass = 'pgn-board-img', | ||
resetGameButtonClass = 'pgn-button-tostart', | resetGameButtonClass = 'pgn-button-tostart', | ||
ffButtonClass = 'pgn-button-toend', | ffButtonClass = 'pgn-button-toend', | ||
| שורה 36: | שורה 35: | ||
retreatButtonClass = 'pgn-button-retreat', | retreatButtonClass = 'pgn-button-retreat', | ||
playButtonClass = 'pgn-button-play', | playButtonClass = 'pgn-button-play', | ||
fasterButtonClass = 'pgn-button-faster', | fasterButtonClass = 'pgn-button-faster', | ||
slowerButtonClass = 'pgn-button-slower', | slowerButtonClass = 'pgn-button-slower', | ||
| שורה 44: | שורה 42: | ||
mw = window.mw, | mw = window.mw, | ||
$ = window.$, | $ = window.$, | ||
domParser = new DOMParser(), | |||
mobile = mw.config.get('skin') === 'minerva'; | mobile = mw.config.get('skin') === 'minerva'; | ||
| שורה 55: | שורה 54: | ||
function indexOfMoveNotation(notation) { | function indexOfMoveNotation(notation) { | ||
var match = notation.match( /(\d+)([ld])/ ); | var match = notation.match( /(\d+)([ld])/ ); | ||
if (match) return parseInt( match[1] ) + ( match[2] === 'l' ? 1 : 2 ); | if (match) return ( parseInt( match[1] ) - 1 ) * 2 + ( match[2] === 'l' ? 1 : 2 ); | ||
return 0; | return 0; | ||
} | } | ||
| שורה 70: | שורה 69: | ||
return res.reverse().join('/'); // fen begins with row 8 file a - go figure... | return res.reverse().join('/'); // fen begins with row 8 file a - go figure... | ||
} | } | ||
function Button( className, action, stateful) { | // Classes | ||
var button = this | function Button( className, action, stateful ) { | ||
var button = this; | |||
$.extend( button, { | $.extend( button, { | ||
state: 0, | state: 0, | ||
| שורה 84: | שורה 81: | ||
if ( stateful ) | if ( stateful ) | ||
this.elem | this.elem | ||
.toggleClass( 'pgn-image-button-on', state ) | .toggleClass( 'pgn-image-button-on', !!state ) | ||
.toggleClass( 'pgn-image-button-off', !state | .toggleClass( 'pgn-image-button-off', !state ); | ||
if ( ( !stateful || state != oldState ) && typeof( action ) == 'function' ) | if ( ( !stateful || state != oldState ) && typeof( action ) == 'function' ) | ||
action( state ); | action( state ); | ||
}, | |||
setVisible: function( visible ) { | |||
this.elem.toggle( !! visible ); | |||
}, | }, | ||
elem: $( '<div>' ) | elem: $( '<div>' ) | ||
.addClass( 'pgn-image-button pgn-image-button-off ' + | .addClass( 'pgn-image-button pgn-image-button-off ' + className ) | ||
.click( function() { | .click( function() { | ||
button.setState( ! button.state ); | button.setState( ! button.state ); | ||
| שורה 110: | שורה 108: | ||
showDetails:false, | showDetails:false, | ||
timer: null, | timer: null, | ||
autoPlayDelay: 750, | |||
// actions | |||
faster: function() { | faster: function() { | ||
gameSet.autoPlayDelay -= 500; | gameSet.autoPlayDelay -= 500; | ||
| שורה 119: | שורה 119: | ||
gameSet.reportDelay(); | gameSet.reportDelay(); | ||
}, | }, | ||
reportDelay: function() { | reportDelay: function() { | ||
gameSet.toggleAutoPlay(); // no param means keep state, but use new delay | gameSet.toggleAutoPlay(); // no param means keep state, but use new delay | ||
| שורה 137: | שורה 128: | ||
}, | }, | ||
// 6 is half letter size (assuming font-size 0.875em) | // 6 is half letter size (assuming font-size 0.875em) | ||
top: function(row, l) { return (((this. | top: function(row, l) { return (((this.isFlipped ? row : (7 - row)) + (l ? 0.3 : 0)) * this.blockSize + (l? boardPadding-6: boardPadding)) + 'px'; }, | ||
left: function(file, l) { return (((this. | left: function(file, l) { return (((this.isFlipped ? 7 - file : file) + (l ? 0.5 : 0)) * this.blockSize + (l? boardPadding-6: boardPadding)) + 'px'; }, | ||
legendLocation: function(side, num) { | legendLocation: function(side, num) { | ||
switch (side) { | switch (side) { | ||
case 'n': | case 'n': return {top: 0, left: this.left(num, true)}; | ||
case 'e': return {top: this.top(num, true), left: this.blockSize * 8 + boardPadding + 5}; | |||
case 'e': | case 's': return {top: this.blockSize * 8 + 20, left: this.left(num, true)}; | ||
case 'w': return {top: this.top(num, true), left: 5}; | |||
case 's': | |||
case 'w': | |||
} | } | ||
}, | }, | ||
| שורה 162: | שורה 148: | ||
game.analyzePgn(); | game.analyzePgn(); | ||
this.currentGame = game; | this.currentGame = game; | ||
this.ccButton.setVisible( game.hasComments() ); | |||
game.show(); | game.show(); | ||
} | } | ||
| שורה 169: | שורה 156: | ||
this.fenDiv.text( boardToFen(board) ); | this.fenDiv.text( boardToFen(board) ); | ||
}, | }, | ||
drawIfNeedRefresh: function( | drawIfNeedRefresh: function() { | ||
if (this.currentGame) | if (this.currentGame) | ||
this.currentGame.drawBoard(); | this.currentGame.drawBoard(); | ||
| שורה 193: | שורה 180: | ||
this.wrapperDiv.toggleClass( 'pgn-comments-hidden', state ); | this.wrapperDiv.toggleClass( 'pgn-comments-hidden', state ); | ||
}, | }, | ||
isFlipped: false, | |||
doFlip: function( state ) { | doFlip: function( state ) { | ||
this.isFlipped = state; | |||
this.changeAppearance(); | this.changeAppearance(); | ||
}, | }, | ||
playing: false, | |||
toggleAutoPlay: function( state ) { | toggleAutoPlay: function( state ) { | ||
clearInterval(this.timer); | clearInterval(this.timer); | ||
if (state == undefined) state = | if (state == undefined) state = this.playing; | ||
this.playing = state; | |||
if ( state ) { | if ( state ) { | ||
this.currentGame.wrapAround(); | this.currentGame.wrapAround(); | ||
this.timer = setInterval(function() { gameSet.currentGame.advance() }, gameSet.autoPlayDelay); | this.timer = setInterval(function() { gameSet.currentGame.advance() }, gameSet.autoPlayDelay); | ||
} | } | ||
}, | |||
stopAutoPlay: function() { | |||
gameSet.autoPlayButton.setState( false ); | |||
} | } | ||
}); | }); | ||
} | } | ||
function ChessPiece(type, color, game) { | function ChessPiece(type, color, game) { | ||
this.game = game; | this.game = game; | ||
| שורה 221: | שורה 207: | ||
this.avatar = $('<div>') | this.avatar = $('<div>') | ||
.addClass('pgn-chessPiece pgn-ptype-color-' + type + color) | .addClass('pgn-chessPiece pgn-ptype-color-' + type + color) | ||
.on('transitionstart', | .on('transitionstart', function(){ $(this).addClass('moving'); } ) //supposedly elevates z-index | ||
.on('transitionend', | .on('transitionend', function(){ $(this).removeClass('moving'); } ); | ||
var piece = this; | |||
$.extend( piece, { | |||
appear: function(file, row) { | |||
if (game.gs.isFlipped) { | |||
file = 7 - file; | |||
row = 7 - row; | |||
} | |||
this.avatar | |||
.removeClass(hiddenPiece) | |||
.removeClass(allFilesAndColumnClasses) // remove them all | |||
.addClass(rowClassPrefix + row) // | |||
.addClass(fileClassPrefix + file); | |||
}, | |||
disappear: function() { return this.avatar.addClass( hiddenPiece ); }, | |||
setSquare: function( file, row ) { | |||
this.file = file; | |||
this.row = row; | |||
this.onBoard = true; | |||
}, | |||
capture: function( file, row ) { | |||
if (this.type == 'p' && !this.game.pieceAt(file, row)) // en passant | |||
this.game.clearPieceAt(file, this.row); | |||
else | |||
this.game.clearPieceAt(file, row); | |||
this.move(file, row); | |||
}, | |||
move: function(file, row) { | |||
// with chess960 castling, we sometimes have to test. | |||
if ( this.game.pieceAt( this.file, this.row ) == this ) | |||
this.game.clearSquare(this.file, this.row); | |||
this.game.pieceAt(file, row, this); // place it on the board) | |||
}, | |||
pawnDirection: function() { return this.color == WHITE ? 1 : -1; }, | |||
toString: function() { return this.type + this.color; }, | |||
fen: function() { return this.color == WHITE ? this.type.toUpperCase() : this.type; }, | |||
pawnStart: function() { return this.color == WHITE ? 1 : 6; }, | |||
remove: function() { this.onBoard = false; }, | |||
canMoveTo: function(file, row, capture) { | |||
if (!this.onBoard) | |||
return false; | |||
var rd = Math.abs(this.row - row), fd = Math.abs(this.file - file); | |||
switch(this.type) { | |||
case 'n': | |||
return rd * fd == 2; // how nice that 2 is prime: its only factors are 2 and 1.... | |||
case 'p': | |||
var dir = this.pawnDirection(); | |||
return ( | |||
((this.row == this.pawnStart() && row == this.row + dir * 2 && !fd && this.game.roadIsClear(this.file, file, this.row, row) && !capture) | |||
|| (this.row + dir == row && fd == !!capture))); // advance 1, and either stay in file and no capture, or move exactly one | |||
case 'k': | |||
return (rd | fd) == 1; // we'll accept 1 and 1 or 1 and 0. | |||
case 'q': | |||
return (rd - fd) * rd * fd == 0 && this.game.roadIsClear(this.file, file, this.row, row); // same row, same file or same diagonal. | |||
case 'r': | |||
return rd * fd == 0 && this.game.roadIsClear(this.file, file, this.row, row); | |||
case 'b': | |||
return rd == fd && this.game.roadIsClear(this.file, file, this.row, row); | |||
} | |||
}, // function canMoveTo | |||
matches: function(oldFile, oldRow, isCapture, file, row) { | |||
if (typeof oldFile == 'number' && oldFile != this.file) | |||
return false; | |||
if (typeof oldRow == 'number' && oldRow != this.row) | |||
return false; | |||
return this.canMoveTo(file, row, isCapture); | |||
} | |||
} ); // extend | |||
} | } | ||
function Game(gameSet) { | function Game(gameSet) { | ||
| שורה 346: | שורה 322: | ||
if (trow) { | if (trow) { | ||
try { | try { | ||
notation = notation.replace(/[12345678]/g, function(c) { return | notation = notation.replace(/[12345678]/g, function(c) { return trow[c] || c; } ); | ||
} catch (e) { | } catch (e) { | ||
mw.log('bad config.translate.row'); | mw.log('bad config.translate.row'); | ||
| שורה 359: | שורה 335: | ||
var desc = $.extend({}, this.descriptions), | var desc = $.extend({}, this.descriptions), | ||
rtl = desc['Direction'] == 'rtl', | rtl = desc['Direction'] == 'rtl', | ||
gs = this.gs; | gs = this.gs; | ||
// cleanup from previous game. | // cleanup from previous game. | ||
gs. | gs.stopAutoPlay(); | ||
// setup descriptions | // setup descriptions | ||
| שורה 370: | שורה 345: | ||
.empty() | .empty() | ||
.css( { direction: rtl ? 'rtl' : 'ltr', textAlign: rtl ? 'right' : 'left' } ); | .css( { direction: rtl ? 'rtl' : 'ltr', textAlign: rtl ? 'right' : 'left' } ); | ||
$.each(desc, function(key, val) { | $.each(desc, function(key, val) { | ||
var line = mw.html.escape(key + ': ' + val) + '<br />'; | |||
gs.descriptionsDiv.append(line); | |||
} ); | |||
// setup pgn section | // setup pgn section | ||
| שורה 442: | שורה 420: | ||
if (0 <= m && m < this.boards.length) { | if (0 <= m && m < this.boards.length) { | ||
this.drawBoard(m); | this.drawBoard(m); | ||
} else this.gs. | } else this.gs.autoPlayButton.setState(false); | ||
} | } | ||
| שורה 567: | שורה 545: | ||
} | } | ||
Game.prototype.addComment = function(str) { | |||
if ( ! str ) return; | if ( ! str ) return; | ||
this.notations.push( $( '<p>' ) | this.notations.push( $( '<p>' ) | ||
| שורה 574: | שורה 552: | ||
); | ); | ||
} | } | ||
Game.prototype.addDescription = function(description) { | Game.prototype.addDescription = function(description) { | ||
description = $.trim(description); | description = $.trim(description); | ||
| שורה 582: | שורה 560: | ||
} | } | ||
Game.prototype.description = function( | Game.prototype.description = function() { | ||
var d = this.descriptions, | var d = this.descriptions, | ||
event = d['Event'] || d['אירוע'], | |||
round = d['Round'] || d['סיבוב'], | |||
white = d['White'] || d['לבן'], | |||
black = d['Black'] || d['שחור'], | |||
name = d['Name'] || d['שם']; | |||
return name | |||
|| ( event ? event + ': ' : '') | |||
+ (white ? white : '') | |||
+ (white || black ? ' – ' : '') | |||
+ (black ? black : '') | |||
+ (round ? ' (' + round + ')' : ''); | |||
} | } | ||
Game.prototype.preAnalyzePgn = function(pgn) { | Game.prototype.preAnalyzePgn = function(pgn) { | ||
function tryMatch(regex) { | function tryMatch(regex) { | ||
| שורה 625: | שורה 609: | ||
if (rmatch) { | if (rmatch) { | ||
removeHead(rmatch[0]); | removeHead(rmatch[0]); | ||
moveNum = rmatch[1] || moveNum | moveNum = rmatch[1] || moveNum; | ||
} | } | ||
return rmatch && rmatch[0]; | return rmatch && rmatch[0]; | ||
| שורה 644: | שורה 628: | ||
var index = game.boards.length - 1; | var index = game.boards.length - 1; | ||
notation.on( 'click', function() { game.drawBoard(index); } ); | notation.on( 'click', function() { | ||
game.gs.stopAutoPlay(); | |||
game.drawBoard(index); | |||
} ); | |||
} | } | ||
| שורה 691: | שורה 678: | ||
} | } | ||
} | } | ||
} | } | ||
function | |||
var | Game.prototype.hasComments = function() { | ||
var hasComment = function( n ){ return n.hasClass( 'pgn-comment' ); }; | |||
return !! this.notations.filter( hasComment ).length; | |||
} | } | ||
| שורה 705: | שורה 693: | ||
fenId = 'pgn-fen-' + id, | fenId = 'pgn-fen-' + id, | ||
controlsDiv, | controlsDiv, | ||
createBotton = function( className, param, todraw ) { | |||
return new Button( className, | |||
forward = new Button( | function() { | ||
gameSet.stopAutoPlay(); | |||
if ( todraw ) gameSet.currentGame.drawBoard( param ) | |||
else gameSet.currentGame.advance( param ); | |||
} ) | |||
}, | |||
gotoend = createBotton( ffButtonClass, -1, true ), | |||
forward = createBotton( advanceButtonClass, 1 ), | |||
backstep = createBotton( retreatButtonClass, -1 ), | |||
gotostart = createBotton( resetGameButtonClass, 0, true ), | |||
flip = new Button( flipBoardButtonClass, function( state ){ gameSet.doFlip( state ); }, true ), | |||
slower = new Button( slowerButtonClass, function(){ gameSet.slower(); } ), | |||
faster = new Button( fasterButtonClass, function(){ gameSet.faster(); } ), | |||
autoplay = new Button( playButtonClass, function( state ){ gameSet.toggleAutoPlay( state ); }, true ), | |||
commentsToggle = new Button( ccButtonClass, function( state ){ gameSet.hideComments( state ); }, true ), | |||
tabnames = $.extend( { | tabnames = $.extend( { | ||
notation: 'Game Notation', | notation: 'Game Notation', | ||
| שורה 722: | שורה 715: | ||
fen: 'FEN' }, | fen: 'FEN' }, | ||
config.tab_names ); | config.tab_names ); | ||
gameSet.autoPlayButton = autoplay; | |||
gameSet.ccButton = commentsToggle | |||
gameSet.descriptionsDiv = $('<div>', {'class': 'pgn-descriptions', id: infoId }) | gameSet.descriptionsDiv = $('<div>', {'class': 'pgn-descriptions', id: infoId }) | ||
gameSet.fixedDelay = 'delay' in config; | gameSet.fixedDelay = 'delay' in config; | ||
| שורה 748: | שורה 742: | ||
.tabs(); | .tabs(); | ||
} | } | ||
var buttons = gameSet.fixedDelay | |||
? [gotostart, backstep, autoplay, forward, gotoend, flip, commentsToggle] | |||
: [gotostart, backstep, slower, autoplay, faster, forward, gotoend, flip, commentsToggle] | |||
controlsDiv = $('<div>', {'class': 'pgn-controls'}) | controlsDiv = $('<div>', {'class': 'pgn-controls'}) | ||
.css({textAlign: 'center'}) | .css( { textAlign: 'center' } ) // todo: move to css | ||
.append( | .append( buttons.map( function(x){ return x.elem; } ) ); | ||
gameSet.boardDiv = $('<div>') | gameSet.boardDiv = $('<div>') | ||
| שורה 796: | שורה 784: | ||
container | container | ||
.append( selector || '' ) | .append( selector || '' ) | ||
.append( | .append($('<div>') | ||
.append(gameSet.boardDiv) | .append(gameSet.boardDiv) | ||
.append( gameSet.tabberDiv ) | |||
.append(controlsDiv) | .append(controlsDiv) | ||
); | |||
} | } | ||
function doIt() { | function doIt() { | ||
$(wrapperSelector | $(wrapperSelector).each(function( ind ) { | ||
var | var | ||
wrapperDiv = $(this), | wrapperDiv = $(this), | ||
initial = wrapperDiv.text(), | initial = wrapperDiv.text(), | ||
pgnSource = $('div.pgn-sourcegame', wrapperDiv), | pgnSource = $('div.pgn-sourcegame', wrapperDiv), | ||
selector, | selector, | ||
gameSet = new Gameset( wrapperDiv ); | gameSet = new Gameset( wrapperDiv ); | ||
try { | |||
if (pgnSource.length > 1) | if (pgnSource.length > 1) | ||
selector = $('<select>', { 'class': 'pgn-selector' } ). | selector = $('<select>', { 'class': 'pgn-selector' } ) | ||
.change( function() { gameSet.selectGame(this.value); } ); | |||
buildBoardDiv(wrapperDiv, selector, gameSet, ind); | buildBoardDiv(wrapperDiv, selector, gameSet, ind); | ||
| שורה 850: | שורה 838: | ||
doIt(); | doIt(); | ||
else | else | ||
mw.loader.using( 'jquery.ui | mw.loader.using( 'jquery.ui' ).done( doIt ); | ||
} | } | ||
}); | }); | ||