Skip to content

Commit

Permalink
Merge pull request #35 from drafear/develop
Browse files Browse the repository at this point in the history
v1.5.4
  • Loading branch information
drafear authored Dec 20, 2018
2 parents 6c71c4d + 21cf692 commit f496973
Show file tree
Hide file tree
Showing 8 changed files with 314 additions and 106 deletions.
16 changes: 15 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,19 @@
"workbench.statusBar.feedback.visible": false,
"xo.format.enable": true,
"xo.enable": true,
"gitlens.views.repositories.files.layout": "list"
"gitlens.views.repositories.files.layout": "list",
"cSpell.words": [
"atcoder",
"betalib",
"brainfuck",
"caml",
"clar",
"commonlib",
"drafear",
"dropdown",
"glyphicon",
"o",
"oninstall",
"unlambda"
]
}
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
"description": "Comfort your atcoder life. For more detail, visit https://github.com/drafear/comfortable-atcoder",
"scripts": {
"build": "run-s build:*",
"build:xo": "xo src/**/*.ts",
"build:init": "rm -rf dist",
"build:cp": "cp -r src dist && rm -rf dist/**/*.less",
"build:css": "less-watch-compiler --run-once src dist",
"build:ts": "parcel build --target node src/**/*.ts",
"start": "npm run watch",
"watch": "run-p watch:*",
"watch:less": "less-watch-compiler src src",
"watch:less": "less-watch-compiler src dist",
"watch:build": "parcel --target node src/**/*.ts",
"watch:test": "jest --watch",
"package": "npm run build && zip -rq Release.zip dist"
Expand Down Expand Up @@ -101,6 +101,7 @@
}
],
"typescript/explicit-function-return-type": 0,
"no-useless-constructor": 0,
"no-alert": 0,
"no-negated-condition": 0,
"capitalized-comments": 0,
Expand Down
80 changes: 80 additions & 0 deletions src/content/add-tweet-button.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import * as Commonlib from './all';
import * as Betalib from './betalib';

Commonlib.runIfEnableAndLoad('add-tweet-button', async () => {
const isMyPage = $('#user-nav-tabs .glyphicon-cog').length >= 1;
if (!isMyPage) {
return;
}

const isDetailPage = /^\/users\/[^/]+\/history\/?$/.test(location.pathname);
const userId = (location.pathname.match(/^\/users\/([^/]+)/) as string[])[1];

async function getTable(): Promise<JQuery<HTMLElement>> {
// if (isDetailPage) {
// return $('#history');
// }
// else {
const html = await (await fetch(`/users/${userId}/history`)).text();
return $(html).find('#history');
// }
}

function getLatestContestResult(contestResults: Betalib.ContestResult[]): Betalib.ContestResult | null {
if (contestResults.length === 0) {
return null;
}
let res = contestResults[0];
for (const result of contestResults) {
if (result.date > res.date) {
res = result;
}
}
return res;
}

function makeTweetText(contestResult: Betalib.ContestResult, isHighest = false): string {
const r = contestResult;
if (r instanceof Betalib.RatedContestResult) {
const highestStr = isHighest ? ', Highest!!' : '';
return `I took ${r.getRankStr()} place in ${r.contestName}\n\nRating: ${r.newRating - r.diff} -> ${r.newRating} (${r.getDiffStr()}${highestStr})\nPerformance: ${r.performance}\n#${r.contestId}`;
}
else {
return `I took ${r.getRankStr()} place in ${r.contestName}\n#${r.contestId}`;
}
}

function isHighest(targetContestResult: Betalib.ContestResult, contestResults: Betalib.ContestResult[]) {
if (!(targetContestResult instanceof Betalib.RatedContestResult)) {
return false;
}
for (const result of contestResults) {
if (result.contestId === targetContestResult.contestId) {
continue;
}
if (!(result instanceof Betalib.RatedContestResult)) {
continue;
}
if (result.newRating >= targetContestResult.newRating) {
return false;
}
}
return true;
}

const $table = await getTable();
const contestResults = Betalib.GetContestResultsFromTable($table);
const latestContestResult = getLatestContestResult(contestResults);
// 一度も参加したことがない
if (latestContestResult === null) {
return;
}
const tweetContent = makeTweetText(latestContestResult, isHighest(latestContestResult, contestResults));
const text = navigator.language === 'ja' ? '最新のコンテスト結果をツイート' : 'Tweet the result of the latest contest';
const $tweetButton = $('<a>').addClass('tweet').text(text)
.prop('href', `https://twitter.com/share?url=''&text=${encodeURIComponent(tweetContent)}`)
.prop('target', '_blank');
if (isDetailPage) {
$('#history_wrapper > div.row:first-child > .col-sm-6:first-child').eq(0).prepend($tweetButton);
}
});
68 changes: 68 additions & 0 deletions src/content/betalib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,45 @@ export class JudgeStatus {
}
}

export abstract class ContestResult {
constructor(public readonly date: Date, public readonly contestName: string, public readonly contestId: string, public readonly rank: number, public readonly diff: number) { }
abstract isRated(): boolean;
getRankStr(): string {
switch (this.rank % 10) {
case 1:
return `${this.rank}st`;
case 2:
return `${this.rank}nd`;
case 3:
return `${this.rank}rd`;
default:
return `${this.rank}th`;
}
}
getDiffStr(): string {
if (this.diff > 0) {
return `+${this.diff}`;
}
if (this.diff < 0) {
return this.diff.toString();
}
return '±0';
}
}
export class UnRatedContestResult extends ContestResult {
isRated() {
return false;
}
}
export class RatedContestResult extends ContestResult {
constructor(date: Date, contestName: string, contestId: string, rank: number, diff: number, public readonly performance: number, public readonly newRating: number) {
super(date, contestName, contestId, rank, diff);
}
isRated() {
return true;
}
}

export function parseJudgeStatus(text: string): JudgeStatus {
const reg = /[ \s]/g;
// WJ
Expand Down Expand Up @@ -230,3 +269,32 @@ export async function getProblems(): Promise<Problem[]> {
});
return res;
}

export function GetContestResultsFromTable($table: JQuery<HTMLElement>): ContestResult[] {
const res: ContestResult[] = [];
const $th = $('thead > tr > th', $table);
const indexes = getIndexes($th, {
date: ['Date', '日付'],
contest: ['Contest', 'コンテスト'],
rank: ['Rank', '順位'],
performance: ['Performance', 'パフォーマンス'],
newRating: ['NewRating', '新Rating'],
diff: ['Diff', '差分'],
});
$('tbody > tr', $table).each((idx, tr) => {
const $tds = $(tr).children('td');
const date = new Date($tds.eq(indexes.date).text());
const $contest = $tds.eq(indexes.contest).children('a').eq(0);
const contestName = $contest.text();
const contestId = (($contest.prop('href') as string).match(/\/contests\/([^\/]+)\/?$/) as string[])[1];
const rank = Number($tds.eq(indexes.rank).text());
const performanceStr = $tds.eq(indexes.performance).text();
const newRatingStr = $tds.eq(indexes.newRating).text();
const diff = Number($tds.eq(indexes.diff).text().replace(/[^0-9]/g, ''));
const isRated = performanceStr !== '-';
res[idx] =
isRated ? new RatedContestResult(date, contestName, contestId, rank, diff, Number(performanceStr), Number(newRatingStr))
: new UnRatedContestResult(date, contestName, contestId, rank, diff);
});
return res;
}
9 changes: 9 additions & 0 deletions src/css/add-twitter-button.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.row {
display: flex;
justify-content: space-between;
}
.tweet {
padding: 3px;
background-color: hsl(220, 70%, 60%);
color: white;
}
25 changes: 25 additions & 0 deletions src/css/add-twitter-button.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#history_wrapper > .row {
display: flex;
justify-content: space-between;
align-items: center;
}

.tweet {
display: inline-block;
padding: 5px;
background-color: hsl(220, 70%, 60%);
border-radius: 3px;
color: white;
text-decoration: none;
transition: all .2s;
&:hover,
&:active,
&:focus,
&:visited {
color: white;
text-decoration: none;
}
&:hover {
background-color: hsl(220, 70%, 50%);
}
}
84 changes: 68 additions & 16 deletions src/manifest.json
Original file line number Diff line number Diff line change
@@ -1,35 +1,83 @@
{
"name": "Comfortable Atcoder",
"version": "1.5.3",
"version": "1.5.4",
"manifest_version": 2,
"description": "Comfort your atcoder life. For more detail, visit https://github.com/drafear/comfortable-atcoder",
"author": "drafear",
"description": "Comfort your atcoder life. For more detail, visit https://github.com/drafear/comfortable-atcoder",
"author": "drafear",
"content_scripts": [
{
"matches": ["*://atcoder.jp/contests/*", "*://*.contest.atcoder.jp/*"],
"exclude_matches": ["*://*.contest.atcoder.jp/users/*"],
"js": ["lib/jquery.min.js", "lib/jquery.cookie.js", "content/all.js"],
"css": ["css/all.css"],
"matches": [
"*://atcoder.jp/contests/*",
"*://atcoder.jp/users/*",
"*://*.contest.atcoder.jp/*"
],
"exclude_matches": [
"*://*.contest.atcoder.jp/users/*"
],
"js": [
"lib/jquery.min.js",
"lib/jquery.cookie.js",
"content/all.js"
],
"css": [
"css/all.css"
],
"run_at": "document_start"
},
{
"matches": ["*://atcoder.jp/contests/*"],
"js": ["content/betalib.js", "content/dropdown-modify.js", "content/clar-notify.js"],
"css": ["css/dropdown-modify.css"],
"matches": [
"*://atcoder.jp/contests/*"
],
"js": [
"content/betalib.js",
"content/dropdown-modify.js",
"content/clar-notify.js"
],
"css": [
"css/dropdown-modify.css"
],
"run_at": "document_start"
},
{
"matches": ["*://atcoder.jp/contests/*/submissions/me"],
"js": ["content/result-notify.js"],
"matches": [
"*://atcoder.jp/contests/*/submissions/me"
],
"js": [
"content/result-notify.js"
],
"run_at": "document_start"
},
{
"matches": ["*://atcoder.jp/contests/*/submit*", "*://atcoder.jp/contests/*/tasks/*"],
"js": ["content/submission-warning.js"],
"matches": [
"*://atcoder.jp/contests/*/submit*",
"*://atcoder.jp/contests/*/tasks/*"
],
"js": [
"content/submission-warning.js"
],
"run_at": "document_start"
},
{
"matches": [
"*://atcoder.jp/users/*/history*"
],
"js": [
"content/add-tweet-button.js"
],
"css": [
"css/add-twitter-button.css"
],
"run_at": "document_start"
},
{
"matches": ["*://*.contest.atcoder.jp/*"],
"js": ["content/link-to-beta.js"],
"run_at": "document_start"
}
],
"web_accessible_resources": ["image/beta.png"],
"web_accessible_resources": [
"image/beta.png"
],
"background": {
"scripts": [
"lib/jquery.min.js",
Expand All @@ -42,7 +90,11 @@
"persistent": false
},
"options_page": "options-page/options.html",
"permissions": ["notifications", "storage", "<all_urls>"],
"permissions": [
"notifications",
"storage",
"<all_urls>"
],
"icons": {
"16": "image/icon.png",
"48": "image/icon.png",
Expand Down
Loading

0 comments on commit f496973

Please sign in to comment.