Progress towards refactoring
This commit is contained in:
@ -25,7 +25,7 @@
|
|||||||
"font-awesome": "~4.3.0",
|
"font-awesome": "~4.3.0",
|
||||||
"moment": "~2.10.2",
|
"moment": "~2.10.2",
|
||||||
"angular-bootstrap": "~0.13.0",
|
"angular-bootstrap": "~0.13.0",
|
||||||
"jshint": "~2.7.0",
|
"jshint": "~2.9.0",
|
||||||
"lightbox2": "~2.8.1",
|
"lightbox2": "~2.8.1",
|
||||||
"rxjs": "~4.0.6",
|
"rxjs": "~4.0.6",
|
||||||
"CodeMirror": "~5.8.0",
|
"CodeMirror": "~5.8.0",
|
||||||
|
File diff suppressed because it is too large
Load Diff
82
client/commonFramework/codeStorage.js
Normal file
82
client/commonFramework/codeStorage.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// depends on: codeUri
|
||||||
|
window.common = (function(global ) {
|
||||||
|
const {
|
||||||
|
$,
|
||||||
|
localStorage,
|
||||||
|
common = { init: [] }
|
||||||
|
} = global;
|
||||||
|
|
||||||
|
const {
|
||||||
|
codeUri
|
||||||
|
} = common;
|
||||||
|
|
||||||
|
var CodeStorageProps = {
|
||||||
|
version: 0.01,
|
||||||
|
keyVersion: 'saveVersion',
|
||||||
|
keyValue: null,
|
||||||
|
updateWait: 2000,
|
||||||
|
updateTimeoutId: null
|
||||||
|
};
|
||||||
|
|
||||||
|
var CodeStorage = {
|
||||||
|
hasSaved: function() {
|
||||||
|
return this.updateTimeoutId === null;
|
||||||
|
},
|
||||||
|
|
||||||
|
onSave: function(func) {
|
||||||
|
this.eventArray.push(func);
|
||||||
|
},
|
||||||
|
|
||||||
|
setSaveKey: function(key) {
|
||||||
|
this.keyValue = key + 'Val';
|
||||||
|
},
|
||||||
|
|
||||||
|
getStoredValue: function() {
|
||||||
|
return '' + localStorage.getItem(this.keyValue);
|
||||||
|
},
|
||||||
|
|
||||||
|
setEditor: function(editor) {
|
||||||
|
this.editor = editor;
|
||||||
|
},
|
||||||
|
|
||||||
|
isAlive: function() {
|
||||||
|
var val = this.getStoredValue();
|
||||||
|
return val !== 'null' &&
|
||||||
|
val !== 'undefined' &&
|
||||||
|
(val && val.length > 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateStorage: function() {
|
||||||
|
if (typeof localStorage !== 'undefined') {
|
||||||
|
var value = this.editor.getValue();
|
||||||
|
// store in localStorage
|
||||||
|
localStorage.setItem(this.keyValue, value);
|
||||||
|
// also store code in URL
|
||||||
|
codeUri.querify(value);
|
||||||
|
} else {
|
||||||
|
console.log('no web storage');
|
||||||
|
}
|
||||||
|
this.updateTimeoutId = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function codeStorageFactory(editor, challengeName) {
|
||||||
|
var codeStorage = Object.create(CodeStorage);
|
||||||
|
$.extend(codeStorage, CodeStorageProps);
|
||||||
|
codeStorage.setEditor(editor);
|
||||||
|
codeStorage.setSaveKey(challengeName);
|
||||||
|
return codeStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
var savedVersion = localStorage.getItem(CodeStorageProps.keyVersion);
|
||||||
|
if (savedVersion === null) {
|
||||||
|
localStorage.setItem(
|
||||||
|
CodeStorageProps.keyVersion,
|
||||||
|
CodeStorageProps.version
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
common.codeStorageFactory = codeStorageFactory;
|
||||||
|
|
||||||
|
return common;
|
||||||
|
}(window, window.common));
|
118
client/commonFramework/codeUri.js
Normal file
118
client/commonFramework/codeUri.js
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// store code in the URL
|
||||||
|
window.common = (function(global) {
|
||||||
|
const {
|
||||||
|
encodeURIComponent: encode,
|
||||||
|
decodeURIComponent: decode,
|
||||||
|
location,
|
||||||
|
history,
|
||||||
|
common = { init: [] }
|
||||||
|
} = global;
|
||||||
|
|
||||||
|
const {
|
||||||
|
replaceScriptTags,
|
||||||
|
replaceSafeTags,
|
||||||
|
replaceFormActionAttr,
|
||||||
|
replaceFccfaaAttr
|
||||||
|
} = common;
|
||||||
|
|
||||||
|
function encodeFcc(val) {
|
||||||
|
return replaceScriptTags(replaceFormActionAttr(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeFcc(val) {
|
||||||
|
return replaceSafeTags(replaceFccfaaAttr(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
var codeUri = {
|
||||||
|
encode: function(code) {
|
||||||
|
return encode(code);
|
||||||
|
},
|
||||||
|
decode: function(code) {
|
||||||
|
try {
|
||||||
|
return decode(code);
|
||||||
|
} catch (ignore) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isInQuery: function(query) {
|
||||||
|
var decoded = codeUri.decode(query);
|
||||||
|
if (!decoded || typeof decoded.split !== 'function') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return decoded
|
||||||
|
.split('?')
|
||||||
|
.splice(1)
|
||||||
|
.reduce(function(found, param) {
|
||||||
|
var key = param.split('=')[0];
|
||||||
|
if (key === 'solution') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}, false);
|
||||||
|
},
|
||||||
|
isAlive: function() {
|
||||||
|
return codeUri.enabled &&
|
||||||
|
codeUri.isInQuery(location.search) ||
|
||||||
|
codeUri.isInQuery(location.hash);
|
||||||
|
},
|
||||||
|
parse: function() {
|
||||||
|
if (!codeUri.enabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var query;
|
||||||
|
if (location.search && codeUri.isInQuery(location.search)) {
|
||||||
|
query = location.search.replace(/^\?/, '');
|
||||||
|
if (history && typeof history.replaceState === 'function') {
|
||||||
|
history.replaceState(
|
||||||
|
history.state,
|
||||||
|
null,
|
||||||
|
location.href.split('?')[0]
|
||||||
|
);
|
||||||
|
location.hash = '#?' + encodeFcc(query);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
query = location.hash.replace(/^\#\?/, '');
|
||||||
|
}
|
||||||
|
if (!query) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return query
|
||||||
|
.split('&')
|
||||||
|
.reduce(function(solution, param) {
|
||||||
|
var key = param.split('=')[0];
|
||||||
|
var value = param.split('=')[1];
|
||||||
|
if (key === 'solution') {
|
||||||
|
return decodeFcc(codeUri.decode(value || ''));
|
||||||
|
}
|
||||||
|
return solution;
|
||||||
|
}, null);
|
||||||
|
},
|
||||||
|
querify: function(solution) {
|
||||||
|
if (!codeUri.enabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (history && typeof history.replaceState === 'function') {
|
||||||
|
history.replaceState(
|
||||||
|
history.state,
|
||||||
|
null,
|
||||||
|
'?solution=' + codeUri.encode(encodeFcc(solution))
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
location.hash = '?solution=' +
|
||||||
|
codeUri.encode(encodeFcc(solution));
|
||||||
|
}
|
||||||
|
|
||||||
|
return solution;
|
||||||
|
},
|
||||||
|
enabled: true
|
||||||
|
};
|
||||||
|
|
||||||
|
common.init.push(function() {
|
||||||
|
codeUri.parse();
|
||||||
|
});
|
||||||
|
|
||||||
|
common.codeUri = codeUri;
|
||||||
|
|
||||||
|
return common;
|
||||||
|
}(window));
|
113
client/commonFramework/createEditor.js
Normal file
113
client/commonFramework/createEditor.js
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
window.common = (function(global) {
|
||||||
|
const {
|
||||||
|
CodeMirror,
|
||||||
|
emmetCodeMirror,
|
||||||
|
common = { init: [] }
|
||||||
|
} = global;
|
||||||
|
|
||||||
|
if (!CodeMirror) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
var delay;
|
||||||
|
var codeStorageFactory = common.codeStorageFactory;
|
||||||
|
|
||||||
|
var editor = CodeMirror.fromTextArea(document.getElementById('codeEditor'), {
|
||||||
|
lint: true,
|
||||||
|
lineNumbers: true,
|
||||||
|
mode: 'javascript',
|
||||||
|
theme: 'monokai',
|
||||||
|
runnable: true,
|
||||||
|
matchBrackets: true,
|
||||||
|
autoCloseBrackets: true,
|
||||||
|
scrollbarStyle: 'null',
|
||||||
|
lineWrapping: true,
|
||||||
|
gutters: ['CodeMirror-lint-markers']
|
||||||
|
});
|
||||||
|
|
||||||
|
editor.setSize('100%', 'auto');
|
||||||
|
|
||||||
|
var codeStorage = common.codeStorage =
|
||||||
|
codeStorageFactory(editor, common.challengeName);
|
||||||
|
|
||||||
|
editor.on('keyup', function() {
|
||||||
|
clearTimeout(codeStorage.updateTimeoutId);
|
||||||
|
codeStorage.updateTimeoutId = setTimeout(
|
||||||
|
codeStorage.updateStorage.bind(codeStorage),
|
||||||
|
codeStorage.updateWait
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize CodeMirror editor with a nice html5 canvas demo.
|
||||||
|
editor.on('keyup', function() {
|
||||||
|
clearTimeout(delay);
|
||||||
|
delay = setTimeout(common.updatePreview, 300);
|
||||||
|
});
|
||||||
|
|
||||||
|
editor.setOption('extraKeys', {
|
||||||
|
Tab: function(cm) {
|
||||||
|
if (cm.somethingSelected()) {
|
||||||
|
cm.indentSelection('add');
|
||||||
|
} else {
|
||||||
|
var spaces = Array(cm.getOption('indentUnit') + 1).join(' ');
|
||||||
|
cm.replaceSelection(spaces);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Shift-Tab': function(cm) {
|
||||||
|
if (cm.somethingSelected()) {
|
||||||
|
cm.indentSelection('subtract');
|
||||||
|
} else {
|
||||||
|
var spaces = Array(cm.getOption('indentUnit') + 1).join(' ');
|
||||||
|
cm.replaceSelection(spaces);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Ctrl-Enter': function() {
|
||||||
|
common.executeChallenge(true);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
'Cmd-Enter': function() {
|
||||||
|
common.executeChallenge(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var info = editor.getScrollInfo();
|
||||||
|
|
||||||
|
var after = editor.charCoords({
|
||||||
|
line: editor.getCursor().line + 1,
|
||||||
|
ch: 0
|
||||||
|
}, 'local').top;
|
||||||
|
|
||||||
|
if (info.top + info.clientHeight < after) {
|
||||||
|
editor.scrollTo(null, after - info.clientHeight + 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emmetCodeMirror) {
|
||||||
|
emmetCodeMirror(
|
||||||
|
editor,
|
||||||
|
{
|
||||||
|
'Cmd-E': 'emmet.expand_abbreviation',
|
||||||
|
Tab: 'emmet.expand_abbreviation_with_tab',
|
||||||
|
Enter: 'emmet.insert_formatted_line_break_only'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
common.init.push(function() {
|
||||||
|
var editorValue;
|
||||||
|
if (common.codeUri.isAlive()) {
|
||||||
|
editorValue = common.codeUri.parse();
|
||||||
|
} else {
|
||||||
|
editorValue = codeStorage.isAlive() ?
|
||||||
|
codeStorage.getStoredValue() :
|
||||||
|
common.seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
editor.setValue(common.replaceSafeTags(editorValue));
|
||||||
|
editor.refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
common.editor = editor;
|
||||||
|
|
||||||
|
return common;
|
||||||
|
}(window));
|
57
client/commonFramework/detectLoops.js
Normal file
57
client/commonFramework/detectLoops.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
window.common = (function(global) {
|
||||||
|
const {
|
||||||
|
jailed,
|
||||||
|
document: doc,
|
||||||
|
common = { init: [] }
|
||||||
|
} = global;
|
||||||
|
|
||||||
|
if (!jailed) {
|
||||||
|
return (code, cb) => cb(new Error('Could not load jailed plugin'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// obtaining absolute path of this script
|
||||||
|
var scripts = doc.getElementsByTagName('script');
|
||||||
|
var path = scripts[scripts.length - 1].src
|
||||||
|
.split('?')[0]
|
||||||
|
.split('/')
|
||||||
|
.slice(0, -1)
|
||||||
|
.join('/') + '/';
|
||||||
|
|
||||||
|
var sandbox = {
|
||||||
|
timeoutId: null,
|
||||||
|
|
||||||
|
startTimeout() {
|
||||||
|
this.timeoutId = setTimeout(() => {
|
||||||
|
this.disconnect();
|
||||||
|
}, 3000);
|
||||||
|
},
|
||||||
|
endTimeout() {
|
||||||
|
if (this.timeoutId) {
|
||||||
|
clearTimeout(this.timeoutId);
|
||||||
|
this.timeoutId = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
createPlugin() {
|
||||||
|
this.plugin = new jailed.Plugin(path + 'plugin.js');
|
||||||
|
this.plugin.whenDisconnected(() => {
|
||||||
|
this.endTimeout();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
destroyPlugin() {
|
||||||
|
this.plugin.disconnect();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// sends the input to the plugin for evaluation
|
||||||
|
common.detectLoops = function detectLoops(code, callback) {
|
||||||
|
sandbox.createPlugin();
|
||||||
|
sandbox.plugin.whenConnected(() => {
|
||||||
|
this.endTimeout();
|
||||||
|
|
||||||
|
sandbox.plugin.remote.run(code, callback);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return common;
|
||||||
|
}(window));
|
28
client/commonFramework/displayTestResults.js
Normal file
28
client/commonFramework/displayTestResults.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
window.common = (function({ $, common = { init: [] }}) {
|
||||||
|
|
||||||
|
common.displayTestResults = function displayTestResults(data = []) {
|
||||||
|
data.forEach(({ err = false, text = '' }) => {
|
||||||
|
var iconClass = err ?
|
||||||
|
'"ion-checkmark-circled big-success-icon"' :
|
||||||
|
'"ion-close-circled big-error-icon"';
|
||||||
|
|
||||||
|
$('#testSuite').children().remove();
|
||||||
|
$('<div></div>').html(`
|
||||||
|
<div class='row'>
|
||||||
|
<div class='col-xs-2 text-center'>
|
||||||
|
<i class=${iconClass}></i>
|
||||||
|
</div>
|
||||||
|
<div class='col-xs-10 test-output wrappable'>
|
||||||
|
${text.split('message: ').pop().replace(/\'\);/g, '')}
|
||||||
|
</div>
|
||||||
|
<div class='ten-pixel-break'/>
|
||||||
|
</div>
|
||||||
|
`)
|
||||||
|
.appendTo($('#testSuite'));
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
return common;
|
||||||
|
}(window));
|
94
client/commonFramework/executeChallenge.js
Normal file
94
client/commonFramework/executeChallenge.js
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
window.common = (function(global) {
|
||||||
|
const {
|
||||||
|
ga,
|
||||||
|
common = { init: [] }
|
||||||
|
} = global;
|
||||||
|
|
||||||
|
let attempts = 0;
|
||||||
|
common.executeChallenge = function executeChallenge(shouldTest) {
|
||||||
|
const editorValue = common.editor.getValue();
|
||||||
|
const head = common.arrayToNewLineString(common.head);
|
||||||
|
const tail = common.arrayToNewLineString(common.tail);
|
||||||
|
const codeOutput = common.codeOutput;
|
||||||
|
|
||||||
|
attempts++;
|
||||||
|
ga('send', 'event', 'Challenge', 'ran-code', common.challengeName);
|
||||||
|
$('#testSuite').empty();
|
||||||
|
|
||||||
|
const openingComments = editorValue.match(/\/\*/gi);
|
||||||
|
|
||||||
|
// checks if the number of opening comments(/*) matches the number of
|
||||||
|
// closing comments(*/)
|
||||||
|
if (
|
||||||
|
editorValue.match(/\$\s*?\(\s*?\$\s*?\)/gi) &&
|
||||||
|
openingComments &&
|
||||||
|
openingComments.length > editorValue.match(/\*\//gi).length
|
||||||
|
) {
|
||||||
|
|
||||||
|
common.editor.setValue(common.editor.getValue() + '*/');
|
||||||
|
codeOutput.setValue('Unfinished multi-line comment');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (common.challengeType !== '0') {
|
||||||
|
let userJavaScript = head + common.editor.getValue() + tail;
|
||||||
|
|
||||||
|
userJavaScript = common.removeComments(userJavaScript);
|
||||||
|
userJavaScript = common.addTests(userJavaScript);
|
||||||
|
// simple fix in case the user forgets to invoke their function
|
||||||
|
|
||||||
|
if (userJavaScript.match(/function/gi)) {
|
||||||
|
if (userJavaScript.match(/function\s*?\(|function\s+\w+\s*?\(/gi)) {
|
||||||
|
common.runInSand(userJavaScript, function(err, message) {
|
||||||
|
if (err) {
|
||||||
|
codeOutput.setValue(err);
|
||||||
|
if (shouldTest) {
|
||||||
|
common.runTests('Error', null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
codeOutput.setValue(message.output);
|
||||||
|
codeOutput.setValue(codeOutput.getValue().replace(/\\\"/gi, ''));
|
||||||
|
message.input = common.removeLogs(message.input);
|
||||||
|
if (shouldTest) {
|
||||||
|
common.runTests(null, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
codeOutput.setValue('Unsafe or unfinished function declaration');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
common.runInSand(userJavaScript, function(cls, message) {
|
||||||
|
|
||||||
|
if (cls) {
|
||||||
|
codeOutput.setValue(message.error);
|
||||||
|
if (shouldTest) {
|
||||||
|
common.runTests('Error', null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
codeOutput.setValue(message.output);
|
||||||
|
codeOutput.setValue(codeOutput.getValue().replace(/\\\"/gi, ''));
|
||||||
|
message.input = common.removeLogs(message.input);
|
||||||
|
|
||||||
|
if (shouldTest) {
|
||||||
|
common.runTests(null, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
!editorValue.match(/\$\s*?\(\s*?\$\s*?\)/gi) &&
|
||||||
|
common.challengeType === '0'
|
||||||
|
) {
|
||||||
|
common.safeHTMLRun(shouldTest);
|
||||||
|
} else {
|
||||||
|
common.workerError('Unsafe $($)');
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
var $marginFix = $('.innerMarginFix');
|
||||||
|
$marginFix.css('min-height', $marginFix.height());
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
return common;
|
||||||
|
}(window));
|
44
client/commonFramework/outputDisplay.js
Normal file
44
client/commonFramework/outputDisplay.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
window.common = (function(global) {
|
||||||
|
const {
|
||||||
|
CodeMirror,
|
||||||
|
document: doc,
|
||||||
|
common = { init: [] }
|
||||||
|
} = global;
|
||||||
|
|
||||||
|
const { challengeType = '0' } = common;
|
||||||
|
|
||||||
|
if (!CodeMirror) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
challengeType === '0' ||
|
||||||
|
challengeType === '7'
|
||||||
|
) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
common.codeOutput = CodeMirror.fromTextArea(
|
||||||
|
doc.getElementById('codeOutput'),
|
||||||
|
{
|
||||||
|
lineNumbers: false,
|
||||||
|
mode: 'text',
|
||||||
|
theme: 'monokai',
|
||||||
|
readOnly: 'nocursor',
|
||||||
|
lineWrapping: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
common.codeOutput.setValue(`
|
||||||
|
/**
|
||||||
|
* Your output will go here.
|
||||||
|
* Console.log() -type statements
|
||||||
|
* will appear in your browser\'s
|
||||||
|
* DevTools JavaScript console.
|
||||||
|
*/'
|
||||||
|
`);
|
||||||
|
|
||||||
|
common.codeOutput.setSize('100%', '100%');
|
||||||
|
|
||||||
|
return common;
|
||||||
|
}(window));
|
43
client/commonFramework/runTests.js
Normal file
43
client/commonFramework/runTests.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
window.common = (function({ common = { init: [] }}) {
|
||||||
|
common.runTests = function runTests(err, data) {
|
||||||
|
var head = common.arrayToNewLineString(common.head);
|
||||||
|
var tail = common.arrayToNewLineString(common.tail);
|
||||||
|
var userTests = Array.isArray(userTests) ? userTests.slice() : [];
|
||||||
|
|
||||||
|
var editorValue = head + common.editor.getValue() + tail;
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
userTests = [{
|
||||||
|
text: 'Program Execution Failure',
|
||||||
|
err
|
||||||
|
}];
|
||||||
|
return userTests;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add blocks to test exploits here!
|
||||||
|
if (editorValue.match(/if\s\(null\)\sconsole\.log\(1\);/gi)) {
|
||||||
|
userTests = [{
|
||||||
|
text: 'Program Execution Failure',
|
||||||
|
err: 'Invalid if (null) console.log(1); detected'
|
||||||
|
}];
|
||||||
|
|
||||||
|
return userTests;
|
||||||
|
}
|
||||||
|
|
||||||
|
return userTests.map(function(test) {
|
||||||
|
try {
|
||||||
|
if (test) {
|
||||||
|
/* eslint-disable no-eval, no-unused-vars */
|
||||||
|
var output = eval(common.reassembleTest(test, data));
|
||||||
|
/* eslint-enable no-eval, no-unused-vars */
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
test.err = e.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
return test;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return common;
|
||||||
|
}(window));
|
202
client/commonFramework/stepChallenge.js
Normal file
202
client/commonFramework/stepChallenge.js
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
window.common = (function({ $, common = { init: [] }}) {
|
||||||
|
const stepClass = '.challenge-step';
|
||||||
|
const prevBtnClass = '.challenge-step-btn-prev';
|
||||||
|
const nextBtnClass = '.challenge-step-btn-next';
|
||||||
|
const actionBtnClass = '.challenge-step-btn-action';
|
||||||
|
const finishBtnClass = '.challenge-step-btn-finish';
|
||||||
|
const submitBtnId = '#challenge-step-btn-submit';
|
||||||
|
const submitModalId = '#challenge-step-modal';
|
||||||
|
|
||||||
|
function getPreviousStep($challengeSteps) {
|
||||||
|
var length = $challengeSteps.length;
|
||||||
|
var $prevStep = false;
|
||||||
|
var prevStepIndex = 0;
|
||||||
|
$challengeSteps.each(function(index) {
|
||||||
|
var $step = $(this);
|
||||||
|
if (
|
||||||
|
!$step.hasClass('hidden') &&
|
||||||
|
index + 1 !== length
|
||||||
|
) {
|
||||||
|
prevStepIndex = index - 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$prevStep = $challengeSteps[prevStepIndex];
|
||||||
|
|
||||||
|
return $prevStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNextStep($challengeSteps) {
|
||||||
|
var length = $challengeSteps.length;
|
||||||
|
var $nextStep = false;
|
||||||
|
var nextStepIndex = 0;
|
||||||
|
$challengeSteps.each(function(index) {
|
||||||
|
var $step = $(this);
|
||||||
|
if (
|
||||||
|
!$step.hasClass('hidden') &&
|
||||||
|
index + 1 !== length
|
||||||
|
) {
|
||||||
|
nextStepIndex = index + 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$nextStep = $challengeSteps[nextStepIndex];
|
||||||
|
|
||||||
|
return $nextStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePrevStepClick(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var prevStep = getPreviousStep($(stepClass));
|
||||||
|
$(this)
|
||||||
|
.parent()
|
||||||
|
.removeClass('fadeOutLeft')
|
||||||
|
.addClass('animated fadeOutRight fast-animation')
|
||||||
|
.delay(250)
|
||||||
|
.queue(function(prev) {
|
||||||
|
$(this).addClass('hidden');
|
||||||
|
if (prevStep) {
|
||||||
|
$(prevStep)
|
||||||
|
.removeClass('hidden')
|
||||||
|
.removeClass('slideInRight')
|
||||||
|
.addClass('animated slideInLeft fast-animation')
|
||||||
|
.delay(500)
|
||||||
|
.queue(function(prev) {
|
||||||
|
prev();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
prev();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleNextStepClick(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var nextStep = getNextStep($(stepClass));
|
||||||
|
$(this)
|
||||||
|
.parent()
|
||||||
|
.removeClass('fadeOutRight')
|
||||||
|
.addClass('animated fadeOutLeft fast-animation')
|
||||||
|
.delay(250)
|
||||||
|
.queue(function(next) {
|
||||||
|
$(this).addClass('hidden');
|
||||||
|
if (nextStep) {
|
||||||
|
$(nextStep)
|
||||||
|
.removeClass('hidden')
|
||||||
|
.removeClass('slideInLeft')
|
||||||
|
.addClass('animated slideInRight fast-animation')
|
||||||
|
.delay(500)
|
||||||
|
.queue(function(next) {
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleActionClick(e) {
|
||||||
|
var props = common.challengeSeed[0] ||
|
||||||
|
{ stepIndex: [] };
|
||||||
|
|
||||||
|
var $el = $(this);
|
||||||
|
var index = +$el.attr('id');
|
||||||
|
var propIndex = props.stepIndex.indexOf(index);
|
||||||
|
|
||||||
|
if (propIndex === -1) {
|
||||||
|
return $el
|
||||||
|
.parent()
|
||||||
|
.find('.disabled')
|
||||||
|
.removeClass('disabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
// an API action
|
||||||
|
// prevent link from opening
|
||||||
|
e.preventDefault();
|
||||||
|
var prop = props.properties[propIndex];
|
||||||
|
var api = props.apis[propIndex];
|
||||||
|
if (common[prop]) {
|
||||||
|
return $el
|
||||||
|
.parent()
|
||||||
|
.find('.disabled')
|
||||||
|
.removeClass('disabled');
|
||||||
|
}
|
||||||
|
$
|
||||||
|
.post(api)
|
||||||
|
.done(function(data) {
|
||||||
|
// assume a boolean indicates passing
|
||||||
|
if (typeof data === 'boolean') {
|
||||||
|
return $el
|
||||||
|
.parent()
|
||||||
|
.find('.disabled')
|
||||||
|
.removeClass('disabled');
|
||||||
|
}
|
||||||
|
// assume api returns string when fails
|
||||||
|
$el
|
||||||
|
.parent()
|
||||||
|
.find('.disabled')
|
||||||
|
.replaceWith('<p>' + data + '</p>');
|
||||||
|
})
|
||||||
|
.fail(function() {
|
||||||
|
console.log('failed');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFinishClick(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$(submitModalId).modal('show');
|
||||||
|
$(submitModalId + '.modal-header').click();
|
||||||
|
$(submitBtnId).click(handleSubmitClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSubmitClick(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
$('#submit-challenge')
|
||||||
|
.attr('disabled', 'true')
|
||||||
|
.removeClass('btn-primary')
|
||||||
|
.addClass('btn-warning disabled');
|
||||||
|
|
||||||
|
var $checkmarkContainer = $('#checkmark-container');
|
||||||
|
$checkmarkContainer.css({ height: $checkmarkContainer.innerHeight() });
|
||||||
|
|
||||||
|
$('#challenge-checkmark')
|
||||||
|
.addClass('zoomOutUp')
|
||||||
|
.delay(1000)
|
||||||
|
.queue(function(next) {
|
||||||
|
$(this).replaceWith(
|
||||||
|
'<div id="challenge-spinner" ' +
|
||||||
|
'class="animated zoomInUp inner-circles-loader">' +
|
||||||
|
'submitting...</div>'
|
||||||
|
);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
$.post(
|
||||||
|
'/completed-bonfire/', {
|
||||||
|
challengeInfo: {
|
||||||
|
challengeId: common.challengeId,
|
||||||
|
challengeName: common.challengeName,
|
||||||
|
challengeType: common.challengeType
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(res) {
|
||||||
|
if (res) {
|
||||||
|
window.location =
|
||||||
|
'/challenges/next-challenge?id=' + common.challengeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
common.init.push(function($) {
|
||||||
|
if (common.challengeType === '7') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(prevBtnClass).click(handlePrevStepClick);
|
||||||
|
$(nextBtnClass).click(handleNextStepClick);
|
||||||
|
$(actionBtnClass).click(handleActionClick);
|
||||||
|
$(finishBtnClass).click(handleFinishClick);
|
||||||
|
});
|
||||||
|
|
||||||
|
return common;
|
||||||
|
}(window));
|
79
client/commonFramework/utils.js
Normal file
79
client/commonFramework/utils.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
window.common = (function(global) {
|
||||||
|
// common namespace
|
||||||
|
// all classes should be stored here
|
||||||
|
// called at the beginning of dom ready
|
||||||
|
const {
|
||||||
|
common = { init: [] }
|
||||||
|
} = global;
|
||||||
|
|
||||||
|
common.head = common.head || [];
|
||||||
|
common.tail = common.tail || [];
|
||||||
|
common.salt = Math.random();
|
||||||
|
|
||||||
|
common.arrayToNewLineString = function arrayToNewLineString(seedData) {
|
||||||
|
seedData = Array.isArray(seedData) ? seedData : [seedData];
|
||||||
|
return seedData.reduce(function(seed, line) {
|
||||||
|
return '' + seed + line + '\n';
|
||||||
|
}, '');
|
||||||
|
};
|
||||||
|
|
||||||
|
common.seed = common.arrayToNewLineString(common.challengeSeed);
|
||||||
|
|
||||||
|
common.replaceScriptTags = function replaceScriptTags(value) {
|
||||||
|
return value
|
||||||
|
.replace(/<script>/gi, 'fccss')
|
||||||
|
.replace(/<\/script>/gi, 'fcces');
|
||||||
|
};
|
||||||
|
|
||||||
|
common.replaceSafeTags = function replaceSafeTags(value) {
|
||||||
|
return value
|
||||||
|
.replace(/fccss/gi, '<script>')
|
||||||
|
.replace(/fcces/gi, '</script>');
|
||||||
|
};
|
||||||
|
|
||||||
|
common.replaceFormActionAttr = function replaceFormAction(value) {
|
||||||
|
return value.replace(/<form[^>]*>/, function(val) {
|
||||||
|
return val.replace(/action(\s*?)=/, 'fccfaa$1=');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
common.replaceFccfaaAttr = function replaceFccfaaAttr(value) {
|
||||||
|
return value.replace(/<form[^>]*>/, function(val) {
|
||||||
|
return val.replace(/fccfaa(\s*?)=/, 'action$1=');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
common.scopejQuery = function scopejQuery(str) {
|
||||||
|
return str
|
||||||
|
.replace(/\$/gi, 'j$')
|
||||||
|
.replace(/document/gi, 'jdocument')
|
||||||
|
.replace(/jQuery/gi, 'jjQuery');
|
||||||
|
};
|
||||||
|
|
||||||
|
common.unScopeJQuery = function unScopeJQuery(str) {
|
||||||
|
return str
|
||||||
|
.replace(/j\$/gi, '$')
|
||||||
|
.replace(/jdocument/gi, 'document')
|
||||||
|
.replace(/jjQuery/gi, 'jQuery');
|
||||||
|
};
|
||||||
|
|
||||||
|
const commentRegex = /(\/\*[^(\*\/)]*\*\/)|([ \n]\/\/[^\n]*)/g;
|
||||||
|
common.removeLogs = function removeComments(str) {
|
||||||
|
return str.replace(commentRegex, '');
|
||||||
|
};
|
||||||
|
|
||||||
|
const logRegex = /(console\.[\w]+\s*\(.*\;)/g;
|
||||||
|
common.removeLogs = function removeLogs(str) {
|
||||||
|
return str.replace(logRegex, '');
|
||||||
|
};
|
||||||
|
|
||||||
|
common.reassembleTest = function reassembleTest(test, data) {
|
||||||
|
var lineNum = test.line;
|
||||||
|
var regexp = new RegExp('\/\/' + lineNum + common.salt);
|
||||||
|
return data.input.replace(regexp, test.text);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return common;
|
||||||
|
})();
|
||||||
|
|
@ -1,26 +1,26 @@
|
|||||||
/* eslint-disable no-undef, no-unused-vars, no-native-reassign */
|
/* eslint-disable no-undef, no-unused-vars, no-native-reassign */
|
||||||
(function() {
|
window.$ = parent.$;
|
||||||
|
window.$(function() {
|
||||||
|
var _ = parent._;
|
||||||
|
var chai = parent.chai;
|
||||||
var expect = chai.expect;
|
var expect = chai.expect;
|
||||||
var tests = parent.tests;
|
var tests = parent.tests;
|
||||||
var editor = parent.editorValueForIFrame;
|
var common = parent.common;
|
||||||
|
var editorValue = common.editor.getValue();
|
||||||
|
|
||||||
setTimeout(function() {
|
common.tests.forEach(test => {
|
||||||
for (var i = 0; i < tests.length; i++) {
|
try {
|
||||||
var thisTest = true;
|
/* eslint-disable no-eval */
|
||||||
try {
|
eval(test);
|
||||||
/* eslint-disable no-eval */
|
/* eslint-enable no-eval */
|
||||||
eval(parent.tests[i]);
|
} catch (e) {
|
||||||
/* eslint-enable no-eval */
|
parent.postError(JSON.stringify(e.message.split(':').shift()));
|
||||||
} catch (err) {
|
} finally {
|
||||||
allTestsGood = false;
|
parent.postSuccess(
|
||||||
thisTest = false;
|
JSON.stringify(
|
||||||
parent.postError(JSON.stringify(err.message.split(':').shift()));
|
test.split(',').pop().replace(/\'/g, '').replace(/\)/, '')
|
||||||
} finally {
|
)
|
||||||
if (thisTest) {
|
);
|
||||||
parent.postSuccess(JSON.stringify(tests[i].split(',').pop().replace(
|
|
||||||
/\'/g, '').replace(/\)/, '')));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, 10);
|
});
|
||||||
})();
|
});
|
||||||
|
@ -11,11 +11,11 @@ function importScript(url, error) {
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
function run(code) {
|
function run(code, cb) {
|
||||||
|
var err = null;
|
||||||
var result = {
|
var result = {
|
||||||
input: code,
|
input: code,
|
||||||
output: null,
|
output: null,
|
||||||
error: null,
|
|
||||||
type: null
|
type: null
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -24,10 +24,15 @@ function run(code) {
|
|||||||
result.type = typeof codeExec;
|
result.type = typeof codeExec;
|
||||||
result.output = stringify(codeExec);
|
result.output = stringify(codeExec);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
result.error = e.message;
|
err = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
cb(err.message, null);
|
||||||
|
} else {
|
||||||
|
cb(null, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
application.remote.output(result);
|
|
||||||
self.close();
|
self.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ var Rx = require('rx'),
|
|||||||
concat = require('gulp-concat'),
|
concat = require('gulp-concat'),
|
||||||
uglify = require('gulp-uglify'),
|
uglify = require('gulp-uglify'),
|
||||||
merge = require('merge-stream'),
|
merge = require('merge-stream'),
|
||||||
|
babel = require('gulp-babel'),
|
||||||
|
|
||||||
// react app
|
// react app
|
||||||
webpack = require('webpack-stream'),
|
webpack = require('webpack-stream'),
|
||||||
@ -375,6 +376,7 @@ gulp.task('js', function() {
|
|||||||
|
|
||||||
gulp.src(paths.js)
|
gulp.src(paths.js)
|
||||||
.pipe(plumber({ errorHandler: errorHandler }))
|
.pipe(plumber({ errorHandler: errorHandler }))
|
||||||
|
.pipe(babel())
|
||||||
.pipe(__DEV__ ? gutil.noop() : uglify())
|
.pipe(__DEV__ ? gutil.noop() : uglify())
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -395,7 +397,6 @@ gulp.task('js', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// commonFramework depend on iFrameScripts
|
// commonFramework depend on iFrameScripts
|
||||||
// sandbox depends on plugin
|
|
||||||
gulp.task('dependents', ['js'], function() {
|
gulp.task('dependents', ['js'], function() {
|
||||||
var manifestName = 'dependents-manifest.json';
|
var manifestName = 'dependents-manifest.json';
|
||||||
var dest = paths.publicJs;
|
var dest = paths.publicJs;
|
||||||
@ -406,6 +407,7 @@ gulp.task('dependents', ['js'], function() {
|
|||||||
|
|
||||||
return gulp.src(paths.dependents)
|
return gulp.src(paths.dependents)
|
||||||
.pipe(plumber({ errorHandler: errorHandler }))
|
.pipe(plumber({ errorHandler: errorHandler }))
|
||||||
|
.pipe(babel())
|
||||||
.pipe(__DEV__ ? gutil.noop() : uglify())
|
.pipe(__DEV__ ? gutil.noop() : uglify())
|
||||||
.pipe(revReplace({ manifest: manifest }))
|
.pipe(revReplace({ manifest: manifest }))
|
||||||
.pipe(gulp.dest(dest))
|
.pipe(gulp.dest(dest))
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
"forever": "~0.15.1",
|
"forever": "~0.15.1",
|
||||||
"frameguard": "~0.2.2",
|
"frameguard": "~0.2.2",
|
||||||
"gulp": "^3.9.0",
|
"gulp": "^3.9.0",
|
||||||
|
"gulp-babel": "^5.3.0",
|
||||||
"gulp-concat": "^2.6.0",
|
"gulp-concat": "^2.6.0",
|
||||||
"gulp-eslint": "^1.1.0",
|
"gulp-eslint": "^1.1.0",
|
||||||
"gulp-inject": "^3.0.0",
|
"gulp-inject": "^3.0.0",
|
||||||
|
263
public/js/fauxJQuery.js
Normal file
263
public/js/fauxJQuery.js
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
function $() {
|
||||||
|
if (!(this instanceof $)) {
|
||||||
|
return new $();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function returnThis() { return this; }
|
||||||
|
function return$() { return $; }
|
||||||
|
var methods = [
|
||||||
|
'add',
|
||||||
|
'addBack',
|
||||||
|
'addClass',
|
||||||
|
'after',
|
||||||
|
'ajaxComplete',
|
||||||
|
'ajaxError',
|
||||||
|
'ajaxSend',
|
||||||
|
'ajaxStart',
|
||||||
|
'ajaxStop',
|
||||||
|
'ajaxSuccess',
|
||||||
|
'andSelf',
|
||||||
|
'animate',
|
||||||
|
'append',
|
||||||
|
'appendTo',
|
||||||
|
'attr',
|
||||||
|
'before',
|
||||||
|
'bind',
|
||||||
|
'blur',
|
||||||
|
'callbacksadd',
|
||||||
|
'callbacksdisable',
|
||||||
|
'callbacksdisabled',
|
||||||
|
'callbacksempty',
|
||||||
|
'callbacksfire',
|
||||||
|
'callbacksfired',
|
||||||
|
'callbacksfireWith',
|
||||||
|
'callbackshas',
|
||||||
|
'callbackslock',
|
||||||
|
'callbackslocked',
|
||||||
|
'callbacksremove',
|
||||||
|
'change',
|
||||||
|
'children',
|
||||||
|
'clearQueue',
|
||||||
|
'click',
|
||||||
|
'clone',
|
||||||
|
'closest',
|
||||||
|
'contents',
|
||||||
|
'context',
|
||||||
|
'css',
|
||||||
|
'data',
|
||||||
|
'dblclick',
|
||||||
|
'delay',
|
||||||
|
'delegate',
|
||||||
|
'dequeue',
|
||||||
|
'detach',
|
||||||
|
'die',
|
||||||
|
'each',
|
||||||
|
'empty',
|
||||||
|
'end',
|
||||||
|
'eq',
|
||||||
|
'error',
|
||||||
|
'fadeIn',
|
||||||
|
'fadeOut',
|
||||||
|
'fadeTo',
|
||||||
|
'fadeToggle',
|
||||||
|
'filter',
|
||||||
|
'find',
|
||||||
|
'finish',
|
||||||
|
'first',
|
||||||
|
'focus',
|
||||||
|
'focusin',
|
||||||
|
'focusout',
|
||||||
|
'get',
|
||||||
|
'has',
|
||||||
|
'hasClass',
|
||||||
|
'height',
|
||||||
|
'hide',
|
||||||
|
'hover',
|
||||||
|
'html',
|
||||||
|
'index',
|
||||||
|
'innerHeight',
|
||||||
|
'innerWidth',
|
||||||
|
'insertAfter',
|
||||||
|
'insertBefore',
|
||||||
|
'is',
|
||||||
|
'jQuery',
|
||||||
|
'jquery',
|
||||||
|
'keydown',
|
||||||
|
'keypress',
|
||||||
|
'keyup',
|
||||||
|
'last',
|
||||||
|
'length',
|
||||||
|
'live',
|
||||||
|
'load',
|
||||||
|
'load',
|
||||||
|
'map',
|
||||||
|
'mousedown',
|
||||||
|
'mouseenter',
|
||||||
|
'mouseleave',
|
||||||
|
'mousemove',
|
||||||
|
'mouseout',
|
||||||
|
'mouseover',
|
||||||
|
'mouseup',
|
||||||
|
'next',
|
||||||
|
'nextAll',
|
||||||
|
'nextUntil',
|
||||||
|
'not',
|
||||||
|
'off',
|
||||||
|
'offset',
|
||||||
|
'offsetParent',
|
||||||
|
'on',
|
||||||
|
'one',
|
||||||
|
'outerHeight',
|
||||||
|
'outerWidth',
|
||||||
|
'parent',
|
||||||
|
'parents',
|
||||||
|
'parentsUntil',
|
||||||
|
'position',
|
||||||
|
'prepend',
|
||||||
|
'prependTo',
|
||||||
|
'prev',
|
||||||
|
'prevAll',
|
||||||
|
'prevUntil',
|
||||||
|
'promise',
|
||||||
|
'prop',
|
||||||
|
'pushStack',
|
||||||
|
'queue',
|
||||||
|
'ready',
|
||||||
|
'remove',
|
||||||
|
'removeAttr',
|
||||||
|
'removeClass',
|
||||||
|
'removeData',
|
||||||
|
'removeProp',
|
||||||
|
'replaceAll',
|
||||||
|
'replaceWith',
|
||||||
|
'resize',
|
||||||
|
'scroll',
|
||||||
|
'scrollLeft',
|
||||||
|
'scrollTop',
|
||||||
|
'select',
|
||||||
|
'selector',
|
||||||
|
'serialize',
|
||||||
|
'serializeArray',
|
||||||
|
'show',
|
||||||
|
'siblings',
|
||||||
|
'size',
|
||||||
|
'slice',
|
||||||
|
'slideDown',
|
||||||
|
'slideToggle',
|
||||||
|
'slideUp',
|
||||||
|
'stop',
|
||||||
|
'submit',
|
||||||
|
'text',
|
||||||
|
'toArray',
|
||||||
|
'toggle',
|
||||||
|
'toggle',
|
||||||
|
'toggleClass',
|
||||||
|
'trigger',
|
||||||
|
'triggerHandler',
|
||||||
|
'unbind',
|
||||||
|
'undelegate',
|
||||||
|
'unload',
|
||||||
|
'unwrap',
|
||||||
|
'val',
|
||||||
|
'width',
|
||||||
|
'wrap',
|
||||||
|
'wrapAll',
|
||||||
|
'wrapInner'
|
||||||
|
];
|
||||||
|
|
||||||
|
var statics = [
|
||||||
|
'ajax',
|
||||||
|
'ajaxPrefilter',
|
||||||
|
'ajaxSetup',
|
||||||
|
'ajaxTransport',
|
||||||
|
'boxModel',
|
||||||
|
'browser',
|
||||||
|
'Callbacks',
|
||||||
|
'contains',
|
||||||
|
'cssHooks',
|
||||||
|
'cssNumber',
|
||||||
|
'data',
|
||||||
|
'Deferred',
|
||||||
|
'dequeue',
|
||||||
|
'each',
|
||||||
|
'error',
|
||||||
|
'extend',
|
||||||
|
'fnextend',
|
||||||
|
'fxinterval',
|
||||||
|
'fxoff',
|
||||||
|
'get',
|
||||||
|
'getJSON',
|
||||||
|
'getScript',
|
||||||
|
'globalEval',
|
||||||
|
'grep',
|
||||||
|
'hasData',
|
||||||
|
'holdReady',
|
||||||
|
'inArray',
|
||||||
|
'isArray',
|
||||||
|
'isEmptyObject',
|
||||||
|
'isFunction',
|
||||||
|
'isNumeric',
|
||||||
|
'isPlainObject',
|
||||||
|
'isWindow',
|
||||||
|
'isXMLDoc',
|
||||||
|
'makeArray',
|
||||||
|
'map',
|
||||||
|
'merge',
|
||||||
|
'noConflict',
|
||||||
|
'noop',
|
||||||
|
'now',
|
||||||
|
'param',
|
||||||
|
'parseHTML',
|
||||||
|
'parseJSON',
|
||||||
|
'parseXML',
|
||||||
|
'post',
|
||||||
|
'proxy',
|
||||||
|
'queue',
|
||||||
|
'removeData',
|
||||||
|
'sub',
|
||||||
|
'support',
|
||||||
|
'trim',
|
||||||
|
'type',
|
||||||
|
'unique',
|
||||||
|
'when',
|
||||||
|
'always',
|
||||||
|
'done',
|
||||||
|
'fail',
|
||||||
|
'isRejected',
|
||||||
|
'isResolved',
|
||||||
|
'notify',
|
||||||
|
'notifyWith',
|
||||||
|
'pipe',
|
||||||
|
'progress',
|
||||||
|
'promise',
|
||||||
|
'reject',
|
||||||
|
'rejectWith',
|
||||||
|
'resolve',
|
||||||
|
'resolveWith',
|
||||||
|
'state',
|
||||||
|
'then',
|
||||||
|
'currentTarget',
|
||||||
|
'data',
|
||||||
|
'delegateTarget',
|
||||||
|
'isDefaultPrevented',
|
||||||
|
'isImmediatePropagationStopped',
|
||||||
|
'isPropagationStopped',
|
||||||
|
'metaKey',
|
||||||
|
'namespace',
|
||||||
|
'pageX',
|
||||||
|
'pageY',
|
||||||
|
'preventDefault',
|
||||||
|
'relatedTarget',
|
||||||
|
'result',
|
||||||
|
'stopImmediatePropagation',
|
||||||
|
'stopPropagation',
|
||||||
|
'target',
|
||||||
|
'timeStamp',
|
||||||
|
'type',
|
||||||
|
'which'
|
||||||
|
];
|
||||||
|
|
||||||
|
var $Proto = {};
|
||||||
|
methods.forEach(method => $Proto[method] = returnThis);
|
||||||
|
statics.forEach(staticMeth => $[staticMeth] = return$);
|
||||||
|
$.prototype = Object.create($);
|
@ -1,8 +1,8 @@
|
|||||||
extends ../layout-wide
|
extends ../layout-wide
|
||||||
block content
|
block content
|
||||||
link(rel='stylesheet', href='/js/lib/codemirror/lib/codemirror.css')
|
link(rel='stylesheet', href='/bower_components/CodeMirror/lib/codemirror.css')
|
||||||
link(rel='stylesheet', href='/js/lib/codemirror/addon/lint/lint.css')
|
link(rel='stylesheet', href='/bower_components/CodeMirror/addon/lint/lint.css')
|
||||||
link(rel='stylesheet', href='/js/lib/codemirror/theme/monokai.css')
|
link(rel='stylesheet', href='/bower_components/CodeMirror/theme/monokai.css')
|
||||||
link(rel='stylesheet', href='/css/ubuntu.css')
|
link(rel='stylesheet', href='/css/ubuntu.css')
|
||||||
|
|
||||||
.row(ng-controller="pairedWithController")
|
.row(ng-controller="pairedWithController")
|
||||||
|
Reference in New Issue
Block a user