您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Create recent races with simple click on the buttons what appears in the gamelist and home page
// ==UserScript== // @name KG_RecentGames // @namespace klavogonki // @version 0.1 // @description Create recent races with simple click on the buttons what appears in the gamelist and home page // @include https://klavogonki.ru/ // @include https://klavogonki.ru/gamelist/ // @include https://klavogonki.ru/g/* // @include http://klavogonki.ru/gamelist/ // @include http://klavogonki.ru/g/* // ==/UserScript== function main(){ var maxGameCount = 5; if (localStorage['recent_games_limit']) { maxGameCount = Math.max(0, localStorage['recent_games_limit']); } function generateName(aGame) { var gameTypes = { normal: 'Oбычный', abra: 'Абракадабра', referats: 'Яндекс.Рефераты', noerror: 'Безошибочный', marathon: 'Марафон', chars: 'Буквы', digits: 'Цифры', sprint: 'Спринт', voc: 'По словарю' }; var visibilities = { normal: 'открытый', private: 'дружеский', practice: 'одиночный' }; var ranks = ["новички", "любители", "таксисты", "профи", "гонщики", "маньяки", "супермены", "кибергонщики", "экстракиберы"]; var gameType = gameTypes[aGame.params.gametype]; var gameTypeCode = aGame.params.gametype; var vocName = aGame.params.vocName; var timeout = aGame.params.timeout + ' сек.'; var visibility = visibilities[aGame.params.type]; var levelFrom = ranks[aGame.params.level_from - 1]; var levelTo = ranks[aGame.params.level_to - 1]; return '<span class="recent-game-name gametype-' + aGame.params.gametype + '">' + ((vocName == '') ? gameType : '«' + vocName + '»') + '</span>' + '<span class="recent-game-description">' + visibility + ', ' + timeout + '<span class="recent-game-qual">' + (aGame.params.qual ? ' (к)': '') + '</span>' + (aGame.params.level_from != 1 || aGame.params.level_to != 9 ? ' <span class="recent-game-levels">' + levelFrom + ' - ' + levelTo + '</span>' : '') + '</span>'; } function generateLink(aGame) { return 'http://klavogonki.ru/create/?' + 'gametype=' + aGame.params.gametype + (aGame.params.vocId != '' ? '&voc=' + aGame.params.vocId : '') + '&type=' + aGame.params.type + '&level_from=' + aGame.params.level_from + '&level_to=' + aGame.params.level_to + '&timeout=' + aGame.params.timeout + (aGame.params.qual ? '&qual=1' : '') + '&submit=1'; } function addGameLink(elem, aGame, id) { var li = document.createElement('li'); li.className = 'recent-game'; if (aGame.pin) { li.className += ' pin-game'; } li.id = 'recent-game-' + id; li.innerHTML = '<div class="recent-game-handle"><img src="/img/blank.gif"></div>' + '<div class="recent-game-buttons">' + '<div class="recent-game-pin"><img src="http://klavogonki.ru/img/pin.png" title="Зафиксировать" onclick="pinRecentGame(' + id + ')"></div>' + '<div class="recent-game-delete"><img src="http://klavogonki.ru/img/cross_small.png" title="Удалить" onclick="deleteRecentGame(' + id + ');"></div>' + '</div>' + '<a href="' + generateLink(aGame) + '">' + generateName(aGame) + '</a>'; elem.appendChild(li); } function getPinGameCount(aGameList) { var n = 0; for (var i = 0; i < aGameList.length; i++) { if (aGameList[i].pin) { n++; } } return n; } function createHistoryContainer() { recentGames = getRecentGames(); var pinGameCount = getPinGameCount(recentGames); var div = document.createElement('div'); div.id = 'recent-games-container'; for (var i = 0; i < recentGames.length && i < maxGameCount + pinGameCount; i++) { addGameLink(div, recentGames[i], i); } div.innerHTML = '<ul id="recent-games">' + div.innerHTML + '</ul><div style="clear:both;"></div>'; return div; } function saveGameParams () { var desc = document.getElementById('gamedesc'); if (!desc) { throw new Error('#gamedesc element not found.'); } var span = desc.querySelector('span'); if (!span) { throw new Error('#gamedesc span element not found.'); } var descText = desc.textContent; if (/соревнование/.test(descText) || !maxGameCount) { return false; } var gameType = span.className.split('-').pop(); var vocName = gameType === 'voc' ? span.textContent.replace(/[«»]/g, '') : ''; var vocId = gameType === 'voc' ? parseInt(span.querySelector('a').href.match(/vocs\/(\d+)/)[1]) : ''; var type = 'normal'; if (/одиночный/.test(descText)) { type = 'practice'; } else if (/друзьями/.test(descText)) { type = 'private'; } var levelFrom = 1; var levelTo = 9; var matches = descText.match(/для (\S+)–(\S+),/); var ranks = { 'новичков': 1, 'любителей': 2, 'таксистов': 3, 'профи': 4, 'гонщиков': 5, 'маньяков': 6, 'суперменов': 7, 'кибергонщиков': 8, 'экстракиберов': 9, }; if (matches) { levelFrom = ranks[matches[1]]; levelTo = ranks[matches[2]]; } matches = descText.match(/таймаут\s(\d+)\s(сек|мин)/); var timeout = matches[2] === 'сек' ? parseInt(matches[1]) : parseInt(matches[1]) * 60; // OMG var qualification = /квалификация/.test(descText) ? 1 : 0; var lastGameParams = { gametype: gameType, vocName: vocName, vocId: vocId, type: type, level_from: levelFrom, level_to: levelTo, timeout: timeout, qual: qualification, // A legacy property, I guess: premium_abra: 0, }; var sGameParams = JSON.stringify(lastGameParams); var gameList = getRecentGames(); for (var i = 0; i < gameList.length; i++) { if (JSON.stringify(gameList[i].params) == sGameParams) { if (gameList[i].pin) { return; } else { gameList.splice(i, 1); break; } } } var pinGameCount = getPinGameCount(gameList); while (gameList.length >= maxGameCount + pinGameCount) { gameList.pop(); } var lastGame = { params: lastGameParams, id: -1, pin: 0 }; gameList.splice(pinGameCount, 0, lastGame); localStorage.setItem('recent_games', JSON.stringify(gameList)); } if (/http:\/\/klavogonki.ru\/g\/\?gmid=/.test(location.href)) { var gameLoading = document.getElementById('gameloading'); if (!gameLoading) { throw new Error('#gameloading element not found.'); } if (gameLoading.style.display !== 'none') { var observer = new MutationObserver(function () { observer.disconnect(); saveGameParams(); }); observer.observe(gameLoading, { attributes: true }); } else { saveGameParams(); } } if (/^http:\/\/klavogonki.ru\/$/.test(location.href)) { var div = createHistoryContainer(); var e = document.getElementById('head'); e.appendChild(div); sortableRecentGames(); } if (/http:\/\/klavogonki.ru\/gamelist\//.test(location.href)) { var opt = document.createElement('span'); opt.id = 'recent-games-options'; var count = document.createElement('span'); count.id = 'recent-games-count'; count.innerHTML = maxGameCount; var dec = document.createElement('span'); dec.id = 'recent-games-count-dec'; dec.innerHTML = '◄'; var inc = document.createElement('span'); inc.id = 'recent-games-count-inc'; inc.innerHTML = '►'; inc.observe("click", function(evt) { maxGameCount++; count.innerHTML = maxGameCount; localStorage['recent_games_limit'] = maxGameCount; }); dec.observe("click", function(evt) { if (maxGameCount > 0) { maxGameCount--; } count.innerHTML = maxGameCount; localStorage['recent_games_limit'] = maxGameCount; }); opt.innerHTML = 'История: '; opt.appendChild(dec); opt.appendChild(count); opt.appendChild(inc); var div = createHistoryContainer(); var e = document.getElementsByClassName('gamelist-create')[0]; e.appendChild(div); e.getElementsByTagName('form')[0].appendChild(opt); sortableRecentGames(); } var style = document.createElement('style'); style.innerHTML = '#recent-games-container {background:#FFF;}' + '#recent-games-container ul {margin:0; padding:0;}' + '.recent-game {list-style-type:none; position:relative; display:inline-block; vertical-align:top; padding:0; margin:6px 2px 2px; border:1px solid #CCC;}' + '.recent-game.pin-game {margin:4px 2px 0px; border:3px double #AAA;}' + '.recent-game:hover {border:1px solid #666; background:#F4F4F4;}' + '.recent-game.pin-game:hover {border:3px double #888}' + '.recent-game a {text-decoration:none; text-align:center; padding:5px; display:block;}' + '.recent-game-name {display:block; font-weight:bold;}' + '.recent-game-description {display:block; font-size:11px; color:#000;}' + '.recent-game-qual {color:#F00;}' + '.recent-game-levels {display:block; font-size:11px; color:#000;}' + '.recent-game-handle {display:none; position:absolute; left:0px; top:0px; width:16px; height:16px; z-index:100; cursor:move; background:transparent url("http://klavogonki.ru/img/dragdrop2.gif") no-repeat 0 0!important;}' + '.pin-game .recent-game-handle {display:block}' + '.recent-game-buttons {display:none; position:absolute; right:0px;}' + '.recent-game-buttons img:hover {opacity:1; cursor:pointer;}' + '.recent-game-buttons div {margin-left:3px;}' + '.recent-game:hover .recent-game-buttons {display:block}' + '.recent-game-delete {position:relative; left:-4px; top:-5px; width:7px; height:7px; float:left;}' + '.recent-game-delete img {opacity:0.15; position:absolute; clip:rect(5px, 11px, 12px, 4px);}' + '.recent-game-pin {float:left; margin-left:2px;}' + '.pin-game .recent-game-pin {display:none;}' + '.recent-game-pin img {max-width:7px; max-height:7px; opacity:0.3}' + '#recent-games-options {font-family: sans-serif; margin-left:10px;}' + '#recent-games-count {margin:0px 3px;}' + '#recent-games-count-inc {cursor:pointer;}' + '#recent-games-count-dec {cursor:pointer;}' ; document.body.appendChild(style); } function getRecentGames() { var gameList = localStorage['recent_games'] ? JSON.parse(localStorage['recent_games']) : []; // Update old configuration if needed: // TODO: remove this in the future version. gameList = gameList.map(function (game) { if (game.params.qual === 'on' || game.params.qual === '') { game.params.qual = game.params.qual === 'on' ? 1 : 0; } return game; }); for (var i = 0; i < gameList.length; i++) { gameList[i].id = i; } return gameList; } function indexOfRecentGameId(id) { for (var i = 0; i < recentGames.length; i++) { if (recentGames[i].id == id) { return i; } } } function deleteRecentGame(id) { var gameElement = document.getElementById('recent-game-' + id); gameElement.parentNode.removeChild(gameElement); var gameObject = recentGames.splice(indexOfRecentGameId(id), 1); localStorage['recent_games'] = JSON.stringify(recentGames); return gameObject[0]; } function pinRecentGame(id) { function hasClass(element, className) { return element.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)')); } var gameElement = document.getElementById('recent-game-' + id); var gameElementList = document.getElementsByClassName('recent-game'); for (var i = 0; i < gameElementList.length; i++) { if (!(hasClass(gameElementList[i], 'pin-game'))) { gameElement.className += ' pin-game'; if (recentGames[i].id == id) { recentGames[i].pin = 1; } else { var gameObject = deleteRecentGame(id); gameObject.pin = 1; gameElementList[i].parentNode.insertBefore(gameElement, gameElementList[i]); recentGames.splice(i, 0, gameObject); } break; } } sortableRecentGames(); localStorage['recent_games'] = JSON.stringify(recentGames); } function sortableRecentGames() { Sortable.create('recent-games', { overlap: 'horizontal', constraint: 'horizontal', only: 'pin-game', handle: 'recent-game-handle', onChange: function(el) { var id = /\d+$/.exec(el.id)[0]; var oldIndex = indexOfRecentGameId(id); var newIndex = $$$('#recent-games .recent-game').index(el); recentGames.splice(newIndex, 0, recentGames.splice(oldIndex, 1)[0]); localStorage['recent_games'] = JSON.stringify(recentGames); } }); } function addScript(source) { var script = document.createElement('script'); script.type = 'text/javascript'; script.innerHTML = source; document.body.appendChild(script); } function execScript(source) { if (typeof source == 'function') { source = '(' + source + ')();'; } var script = document.createElement('script'); script.type = 'text/javascript'; script.innerHTML = source; document.body.appendChild(script); } if(!document.getElementById('KTS_RecentGames')) { addScript('var recentGames;\n' + getRecentGames + indexOfRecentGameId + deleteRecentGame + pinRecentGame + sortableRecentGames); execScript(main); var tmp_elem = document.createElement('div'); tmp_elem.id = 'KTS_RecentGames'; tmp_elem.style.display = 'none'; document.body.appendChild(tmp_elem); }