diff --git a/ext/css/getpgn.css b/ext/css/getpgn.css
index fbbbc89..ffbfb44 100644
--- a/ext/css/getpgn.css
+++ b/ext/css/getpgn.css
@@ -16,4 +16,44 @@
-webkit-box-shadow: 0px 0px 24px -1px rgba(56, 56, 56, 1);
-moz-box-shadow: 0px 0px 24px -1px rgba(56, 56, 56, 1);
box-shadow: 0px 0px 24px -1px rgba(56, 56, 56, 1);
-}
\ No newline at end of file
+}
+
+.lichess-review-button {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 14px 22px;
+ white-space: nowrap;
+
+ border-radius: 5px;
+ border: 0;
+ outline: none;
+
+ background-color: #33312e;
+
+ font-family: -apple-system, "system-ui", "Segoe UI", system-ui, Helvetica, Arial, sans-serif;
+ font-size: 16px;
+ font-weight: 600;
+ color: #949494;
+}
+
+.lichess-review-button:hover {
+ background-color: #44413b;
+}
+
+.lichess-review-button__icon {
+ width: 20px;
+ height: 20px;
+ display: block;
+ margin-right: 8px;
+ flex-shrink: 0;
+
+ background-image: url('chrome-extension://__MSG_@@extension_id__/icons/lichess_logo.svg');
+ background-size: contain;
+ background-repeat: no-repeat;
+}
+
+.lichess-review-button__text {
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
diff --git a/ext/icons/lichess_logo.svg b/ext/icons/lichess_logo.svg
new file mode 100644
index 0000000..399e36e
--- /dev/null
+++ b/ext/icons/lichess_logo.svg
@@ -0,0 +1,3 @@
+
diff --git a/ext/manifest.json b/ext/manifest.json
index 36c4a85..02e32ef 100755
--- a/ext/manifest.json
+++ b/ext/manifest.json
@@ -24,7 +24,7 @@
"js/jquery-3.5.1.min.js",
"src/bg/analysis.js"
],
- "matches": [
+ "matches": [
"https://*.lichess.org/paste"
]
},
@@ -67,5 +67,20 @@
},
"permissions": [
"activeTab"
+ ],
+ "web_accessible_resources": [
+ {
+ "resources": [
+ "icons/lichess_logo.svg"
+ ],
+ "matches": [
+ "https://www.chess.com/*",
+ "https://www.chessgames.com/*",
+ "https://chessgames.com/*",
+ "https://chess-db.com/*",
+ "https://chesstempo.com/*",
+ "https://old.chesstempo.com/*"
+ ]
+ }
]
}
diff --git a/ext/src/bg/analysis.js b/ext/src/bg/analysis.js
index c1a4264..aa5f63e 100644
--- a/ext/src/bg/analysis.js
+++ b/ext/src/bg/analysis.js
@@ -3,4 +3,4 @@ chrome.runtime.onMessage.addListener(async function(pgn, sender, sendResponse){
$("input[name='analyse']").prop("checked", true);
$(".submit")[0].click();
sendResponse(undefined);
-});
\ No newline at end of file
+});
diff --git a/ext/src/bg/background.js b/ext/src/bg/background.js
index c06f494..4590e9c 100755
--- a/ext/src/bg/background.js
+++ b/ext/src/bg/background.js
@@ -1,13 +1,3 @@
-function isChessComVersion2(url) {
- if (url.indexOf('livechess/game') >= 0) {
- return true;
- }
- if (url.indexOf('live.chess.com') >= 0) {
- return true;
- }
- return false;
-}
-
function isChessGames(url) {
if (url.indexOf('chessgames.com') >= 0) {
return true;
@@ -47,13 +37,13 @@ function getGameId(url) {
if (refIndex >= 0) {
return url.slice(refIndex + 'game/daily/'.length);
}
-
+
// chesstempo.com
var refIndex = url.indexOf('chesstempo.com/gamedb/game/');
if (refIndex >= 0) {
return url.slice(refIndex + 'chesstempo.com/gamedb/game/'.length).split('/')[0];
}
-
+
// live chess.com game
refIndex = url.indexOf('#');
var ref = refIndex >= 0 ? url.slice(refIndex + 1) : '';
@@ -63,11 +53,11 @@ function getGameId(url) {
return '';
}
-chrome.action.onClicked.addListener(async function(tab) {
+async function runAnalysis(tab) {
var onDone = function(pgn) {
if (!pgn)
return;
- if (tab.url.indexOf("live#a=") > -1 ||
+ if (tab.url.indexOf("live#a=") > -1 ||
(pgn.indexOf('[Result ') > -1 && pgn.indexOf('[Result "*"]') < 0) ||
(pgn.indexOf('[Result "*"]') > -1 && pgn.indexOf(' won on time') > -1)) // chess.com oddity where games can be lost on time but Result is not updated
{
@@ -91,24 +81,24 @@ chrome.action.onClicked.addListener(async function(tab) {
};
if (isChessGames(tab.url)) {
// chessgames.com
- var gameId = getGameId(tab.url);
+ var gameId = getGameId(tab.url);
var results = await getPgn(tab.id, "chessGames", gameId);
- onDone(results);
+ onDone(results);
} else if (isChessTempo(tab.url)) {
// chesstempo.com
var gameId = getGameId(tab.url);
var results = await getPgn(tab.id, "chessTempo", gameId);
- onDone(results);
+ onDone(results);
} else if (isChessDB(tab.url)) {
// chess-db.com
var results = await getPgn(tab.id, "chessDB");
- onDone(results);
+ onDone(results);
} else {
// chess.com
var results = await getPgn(tab.id, "chessCom");
onDone(results);
}
-});
+}
async function getPgn(tabId, site, ...args) {
return await chrome.tabs.sendMessage(tabId, {action: "getPgn", site, actionArgs: args});
@@ -119,3 +109,14 @@ async function notFinished(tabId, site, ...args)
return await chrome.tabs.sendMessage(tabId, {action: "notFinished", site, actionArgs: args});
}
+// Here we handle click on the pinned extension icon
+chrome.action.onClicked.addListener(async function(tab) {
+ await runAnalysis(tab);
+});
+
+// Here we handle click on the injected button
+chrome.runtime.onMessage.addListener(async function(request, sender){
+ if (request.action === "openReview") {
+ await runAnalysis(sender.tab)
+ }
+});
diff --git a/ext/src/bg/getpgn.js b/ext/src/bg/getpgn.js
index 7ceb441..d71d706 100644
--- a/ext/src/bg/getpgn.js
+++ b/ext/src/bg/getpgn.js
@@ -11,7 +11,7 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
.then(sendResponse);
return true;
}
-
+
if (request.action !== "getPgn") {
return false;
}
@@ -24,12 +24,12 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
pgnFunc(...(request.actionArgs || []))
.then(sendResponse);
- return true;
+ return true;
});
// chess.com
-async function getCurrentPgn_chessCom() {
+async function getCurrentPgn_chessCom() {
debuglog("getCurrentPgn_chessCom");
var pgn = await openShareDialog()
@@ -59,7 +59,7 @@ async function getCurrentPgn_chessGames(gameId) {
}
// chess-db.com
-async function getCurrentPgn_chessDB() {
+async function getCurrentPgn_chessDB() {
var pgn = null;
var pgnInput = $('input[name="pgn"]');
if (pgnInput)
@@ -71,7 +71,7 @@ async function getCurrentPgn_chessDB() {
}
// chessTempo.com
-async function getCurrentPgn_chessTempo(gameId) {
+async function getCurrentPgn_chessTempo(gameId) {
debuglog('getCurrentPgn_chessTempo(' + gameId + ')');
if (!gameId || gameId === '') {
// if the gameId is not defined, try to get it from the link
@@ -84,7 +84,7 @@ async function getCurrentPgn_chessTempo(gameId) {
debuglog("gameId = " + gameId);
}
- var pgn = await $.ajax({
+ var pgn = await $.ajax({
url: $('form.ct-download-pgn-form')[0].action,
type: 'POST',
data : 'gameids=' + gameId,
@@ -101,7 +101,7 @@ async function getCurrentPgn_chessTempo(gameId) {
}
async function openPgnTab() {
- debuglog("openPgnTab");
+ debuglog("openPgnTab");
var pgnDiv = document.querySelector('div.share-menu-tab-selector-component > div:nth-child(1)') ||
document.querySelector('div.alt-share-menu-tab.alt-share-menu-tab-image-component')
@@ -113,7 +113,7 @@ async function openPgnTab() {
document.querySelector(".icon-download");
if (!pgnTab) {
var headerElements = document.querySelectorAll(
- ".share-menu-dialog-component header *") || document;
+ ".share-menu-dialog-component header *") || document;
pgnTab = Array.from(headerElements).filter(
(x) => x.textContent == "PGN")[0];
}
@@ -138,7 +138,7 @@ async function openShareDialog() {
document.querySelector("button[data-test='download']") ||
document.querySelector("#shareMenuButton") ||
document.querySelector(".icon-font-chess.share.icon-font-primary") ||
- document.querySelector(".icon-font-chess.share") ||
+ document.querySelector(".icon-font-chess.share") ||
document.querySelector(".icon-share");
if (shareButton) {
return new Promise((resolve, reject) => {
@@ -159,7 +159,7 @@ function closeShareDialog() {
document.querySelector(".icon-font-chess.x.icon-font-primary") ||
document.querySelector(".icon-font-chess.x.icon-font-secondary") ||
document.querySelector(".icon-font-chess.x.ui_outside-close-icon") ||
- document.querySelector("#chessboard_ShareMenuGlobalDialogCloseButton")
+ document.querySelector("#chessboard_ShareMenuGlobalDialogCloseButton")
if (closeButton) {
closeButton.click();
} else
@@ -169,7 +169,7 @@ function closeShareDialog() {
}
async function copyPgn() {
- debuglog("copyPgn");
+ debuglog("copyPgn");
var pgnDiv = document.querySelector('div.alt-share-menu-tab.alt-share-menu-tab-gif-component') ||
document.querySelector('div.alt-share-menu-tab.alt-share-menu-tab-image-component')
@@ -197,7 +197,7 @@ async function copyPgn() {
debuglog("could not find disable analysis radio button!");
}
- var textarea =
+ var textarea =
document.querySelector("#live_ShareMenuPgnContentTextareaId") ||
document.querySelector("textarea[name=pgn]") ||
document.querySelector(".form-textarea-component.pgn-download-textarea") ||
@@ -221,10 +221,50 @@ async function popuptoast(message) {
return Promise.resolve();
}
-function debuglog(message)
+function debuglog(message)
{
var logDebugMessages = false;
if (logDebugMessages) {
console.log(message);
}
}
+
+function injectButton(buttonsContainer) {
+ if(buttonsContainer.querySelector(".lichess-review-button")) {
+ return;
+ }
+
+ var button = document.createElement("button");
+ button.innerHTML = `
+
+ Game Review
+ `
+ button.className = "lichess-review-button";
+
+ button.onclick = function() {
+ chrome.runtime.sendMessage(chrome.runtime.id, {
+ action: "openReview"
+ })
+ };
+
+ buttonsContainer.appendChild(button);
+}
+
+function observeDOM() {
+ var observer = new MutationObserver(function(mutations) {
+ mutations.forEach(function(mutation) {
+ var buttonsContainer = document.querySelector(".game-review-buttons-component");
+
+ if (buttonsContainer) {
+ injectButton(buttonsContainer);
+ observer.disconnect();
+ }
+ });
+ });
+
+ observer.observe(document.body, { childList: true, subtree: true });
+}
+
+if (window.location.origin === "https://www.chess.com") {
+ observeDOM()
+}