-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhackerrank_firecode.user.js
202 lines (178 loc) · 8.58 KB
/
hackerrank_firecode.user.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// ==UserScript==
// @name HackerRank/FireIO
// @namespace aljgom
// @version 0.1
// @description Run code when F5 is pressed, prevent reload, and handle how output is displayed
// Uses waitFor function from All Pages script
// @author aljgom
// @match https://www.hackerrank.com/*
// @match https://www.firecode.io/problems/index
// @grant none
// ==/UserScript==
(async function() {
while(typeof(waitFor) === "undefined"){
console.log('waiting for All Pages')
await new Promise(resolve=>setInterval(resolve, 200))
}
'use strict';
let url = document.location.toString();
let sleep = ms => new Promise(resolve=>setTimeout(resolve,ms));
/* HACKERRANK */
if(url.match('hackerrank')){
// Hackerrank doesn't reload the page when moving between tabs,
// so we want to re-run the script if the url has changed
/*
With this modifications you can listen to a 'locationChange' event
When the history object changes, there's a `popstate` event, but there are no events for `pushstate`, and `replacestate`
This modifies these three functions so that all fire a `locationchange` event, and also `pushstate` and `replacestate`
*/
history.pushState = ( f => function pushState(){
var ret = f.apply(this, arguments);
window.dispatchEvent(new Event('pushState'));
window.dispatchEvent(new Event('locationchange'));
return ret;
})(history.pushState);
history.replaceState = ( f => function replaceState(){
var ret = f.apply(this, arguments);
window.dispatchEvent(new Event('replaceState'));
window.dispatchEvent(new Event('locationchange'));
return ret;
})(history.replaceState);
window.addEventListener('popstate',()=>{
window.dispatchEvent(new Event('locationchange'))
});
// Now this is the listener that will take care of re-running the code if the location changes
window.addEventListener('locationchange', function(){
url = document.location.toString();
console.log('Location Changed')
// if url matches Script's @match
if(GM_info.script.matches.reduce((prev,m)=>prev||url.match(m) , false)){
runHackerrank();
}
});
let runHackerrank = async function(){
if( !( url.match('hackerrank.com/(challenge|contest|tests)') //&&
//url.match('problem') // problem tab could also not have 'problem' specified, and it could be blank, ignore for now.
)) return; // only run it in the 'problem' tab
if(url.match('challenges')){ // new layout, contests still have old
// Output size is too small, change it to window size
setInterval(()=>{
document.getElementsByClassName('compile-output-message').forEach((e)=>{
e.style.maxHeight = '50vh'
})
},1000)
}
// Add area where cloned output will be placed
var output
if(url.match('hackerrank.com/tests')){
output = await waitFor(()=>gi('runstatus'));
var question = document.querySelector('[aria-label="Question Content"]').innerText;
console.log(question)
}else{
output = await waitFor(()=>gc('challenge-response fs-container')[0]);
}
if(output.modified == true) return; // since we're running the code every time the url changes, make sure we haven't modified already
output.modified = true
var prev = document.createElement('div');
prev.className = 'prev-output';
output.parentElement.insertBefore(prev, output.nextSibling); // insert cointainer after output
// Clone output when submit botton is pressed, to keep the previous output visible
let cloneOutput = function(){
resetOutputPosition();
prev.innerHTML = '';
prev.appendChild( output.cloneNode(true) );
}
// Make output float when run_code is clicked, put it back in original position if output clicked
let floatOutput = function(){
Object.assign(output.style,{
position: 'fixed',
top: '100%',
transform: 'translateY(-100%)',
right: 0,
zIndex: 10,
width: '30%',
maxHeight: '95%',
overflow: 'scroll'
});
output_floating = true;
}
// minimizes output (still floating)
let minimizeOutput = function(){
Object.assign(output.style,{
// position: 'relative',
transform: 'translateY(-50px)',
//width:'100%'
});
output_floating = false;
}
// return output to original position before cloning
let resetOutputPosition = function(){
Object.assign(output.style,{
position: 'relative',
transform: '',
width:'100%',
zIndex: 1
});
}
let toggleFloat = function(){
if(output_floating) minimizeOutput();
else floatOutput();
}
let dissable_autoScroll = async function(){ // float output and prevent scrolling behavior triggered when running code
// Disable Scrolling
// scrolling is done by using jQuery animate, we'll disable it for a second
if(url.match('tests')) return // don't disable if in tests layout
var temp = $.prototype.animate;
if($.prototype.animate.name == 'temp'){ // don't do it if it's already waiting, it would replace the function permanently
//console.log('already disabling scrolling')
}
else{
$.prototype.animate = function temp(){};
await sleep(1000);
$.prototype.animate = temp;
}
}
// select "Run Code" button
var run_code;
if(url.match('hackerrank.com/(tests|challenges)')){
run_code = await waitFor(()=>gc('msR')[0]);
}
else{
run_code = await waitFor(()=> gc('bb-compile')[0]);
}
run_code.addEventListener('mousedown',cloneOutput); // mousedown instead of click so it fires before submission
var output_floating = false;
// $.prototype.animate = ((f)=>function(){log('animating'); f.call(this,...arguments);})($.prototype.animate) // add a logged message to the function for testing
run_code.addEventListener('click', async ()=>{
floatOutput();
});
run_code.addEventListener('mousedown', dissable_autoScroll);
output.addEventListener('click', toggleFloat); // float and minimize when clicking the output
// Keybord listener to click the 'submit code' button if F5 is pressed, and prevent from reloading
document.addEventListener('keydown', function(e){
if (e.keyCode == 116) { //f5
e.returnValue = false;
dissable_autoScroll();
cloneOutput();
run_code.click();
}
});
}
runHackerrank();
}
/* FIRECODE */
if(url.match('firecode')){
// Keybord listener to click the 'submit code' button if F5 is pressed, and prevent from reloading
document.getElementById('console').style.height = "500px";
document.addEventListener('keydown', async function fkey(e){
if (e.keyCode == 116) { //f5
e.returnValue = false;
window.btnRun.click();
var el = await waitFor(()=>gc("modal-backdrop")[0],20*1000);
if (el) el.style.display ='none';
await waitFor(()=> window.testModal.style.display == 'block',20*1000);
window.testModal.click();
}
});
}
})();