mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-23 23:58:02 -05:00
merge conflict solved
This commit is contained in:
commit
d3e0299465
49 changed files with 854 additions and 269 deletions
|
@ -160,12 +160,7 @@
|
||||||
*
|
*
|
||||||
* Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
|
* Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
|
||||||
*/
|
*/
|
||||||
var currentWindowOnload = window.onload;
|
window.runJasmine = function() {
|
||||||
|
|
||||||
window.onload = function() {
|
|
||||||
if (currentWindowOnload) {
|
|
||||||
currentWindowOnload();
|
|
||||||
}
|
|
||||||
htmlReporter.initialize();
|
htmlReporter.initialize();
|
||||||
env.execute();
|
env.execute();
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Helper for running tests through Karma.
|
// Helper for running tests through Karma.
|
||||||
// Hooks into the test view logic for running tests.
|
// Hooks into the test view logic for running tests.
|
||||||
|
|
||||||
TestView = require('views/test');
|
require('initialize');
|
||||||
|
TestView = require('views/TestView');
|
||||||
TestView.runTests();
|
TestView.runTests();
|
|
@ -43,135 +43,14 @@
|
||||||
|
|
||||||
<script>require('initialize');</script>
|
<script>require('initialize');</script>
|
||||||
|
|
||||||
<!-- begin LinkedIn code -->
|
|
||||||
<script>
|
|
||||||
window.linkedInAsyncInit = function() {
|
|
||||||
Backbone.Mediator.publish('linkedin-loaded');
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
<script type="text/javascript" src="http://platform.linkedin.com/in.js">
|
|
||||||
api_key: 75v8mv4ictvmx6
|
|
||||||
onLoad: linkedInAsyncInit
|
|
||||||
authorize: true
|
|
||||||
</script>
|
|
||||||
<!-- end LinkedIn code -->
|
|
||||||
<!-- begin segment.io code -->
|
|
||||||
<script type="text/javascript">
|
|
||||||
var analytics=analytics||[];(function(){var e=["identify","track","trackLink","trackForm","trackClick","trackSubmit","page","pageview","ab","alias","ready","group"],t=function(e){return function(){analytics.push([e].concat(Array.prototype.slice.call(arguments,0)))}};for(var n=0;n<e.length;n++)analytics[e[n]]=t(e[n])})(),analytics.load=function(e){var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src=("https:"===document.location.protocol?"https://":"http://")+"d2dq2ahtl5zl1z.cloudfront.net/analytics.js/v1/"+e+"/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(t,n)};
|
|
||||||
analytics.load("jsjzx9n4d2");
|
|
||||||
</script>
|
|
||||||
<!-- end segment.io code -->
|
|
||||||
|
|
||||||
<!-- begin olark code -->
|
|
||||||
<script data-cfasync="false" type='text/javascript'>/*<![CDATA[*/window.olark||(function(c){var f=window,d=document,l=f.location.protocol=="https:"?"https:":"http:",z=c.name,r="load";var nt=function(){
|
|
||||||
f[z]=function(){
|
|
||||||
(a.s=a.s||[]).push(arguments)};var a=f[z]._={
|
|
||||||
},q=c.methods.length;while(q--){(function(n){f[z][n]=function(){
|
|
||||||
f[z]("call",n,arguments)}})(c.methods[q])}a.l=c.loader;a.i=nt;a.p={
|
|
||||||
0:+new Date};a.P=function(u){
|
|
||||||
a.p[u]=new Date-a.p[0]};function s(){
|
|
||||||
a.P(r);f[z](r)}f.addEventListener?f.addEventListener(r,s,false):f.attachEvent("on"+r,s);var ld=function(){function p(hd){
|
|
||||||
hd="head";return["<",hd,"></",hd,"><",i,' onl' + 'oad="var d=',g,";d.getElementsByTagName('head')[0].",j,"(d.",h,"('script')).",k,"='",l,"//",a.l,"'",'"',"></",i,">"].join("")}var i="body",m=d[i];if(!m){
|
|
||||||
return setTimeout(ld,100)}a.P(1);var j="appendChild",h="createElement",k="src",n=d[h]("div"),v=n[j](d[h](z)),b=d[h]("iframe"),g="document",e="domain",o;n.style.display="none";m.insertBefore(n,m.firstChild).id=z;b.frameBorder="0";b.id=z+"-loader";if(/MSIE[ ]+6/.test(navigator.userAgent)){
|
|
||||||
b.src="javascript:false"}b.allowTransparency="true";v[j](b);try{
|
|
||||||
b.contentWindow[g].open()}catch(w){
|
|
||||||
c[e]=d[e];o="javascript:var d="+g+".open();d.domain='"+d.domain+"';";b[k]=o+"void(0);"}try{
|
|
||||||
var t=b.contentWindow[g];t.write(p());t.close()}catch(x){
|
|
||||||
b[k]=o+'d.write("'+p().replace(/"/g,String.fromCharCode(92)+'"')+'");d.close();'}a.P(2)};ld()};nt()})({
|
|
||||||
loader: "static.olark.com/jsclient/loader0.js",name:"olark",methods:["configure","extend","declare","identify"]});
|
|
||||||
/* custom configuration goes here (www.olark.com/documentation) */
|
|
||||||
olark.identify('1451-787-10-5544');/*]]>*/</script>
|
|
||||||
<!-- end olark code -->
|
|
||||||
|
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body class="nano clearfix">
|
<body class="nano clearfix">
|
||||||
<div id="fb-root"></div>
|
<div id="fb-root"></div>
|
||||||
|
|
||||||
<!-- begin facebook code -->
|
|
||||||
<script>
|
|
||||||
// Additional JS functions here
|
|
||||||
window.fbAsyncInit = function() {
|
|
||||||
Backbone.Mediator.publish('fbapi-loaded');
|
|
||||||
FB.init({
|
|
||||||
appId : document.location.origin === 'http://localhost:3000' ? '607435142676437' : '148832601965463', // App ID
|
|
||||||
channelUrl : document.location.origin +'/channel.html', // Channel File
|
|
||||||
status : true, // check login status
|
|
||||||
cookie : true, // enable cookies to allow the server to access the session
|
|
||||||
xfbml : true // parse XFBML
|
|
||||||
});
|
|
||||||
|
|
||||||
// This is fired for any auth related change, such as login, logout or session refresh.
|
|
||||||
FB.Event.subscribe('auth.authResponseChange', function(response) {
|
|
||||||
// Here we specify what we do with the response anytime this event occurs.
|
|
||||||
if (response.status === 'connected') {
|
|
||||||
// They have logged in to the app.
|
|
||||||
Backbone.Mediator.publish('facebook-logged-in', {response:response});
|
|
||||||
} else if (response.status === 'not_authorized') {
|
|
||||||
// The person is logged into Facebook, but not into the app.
|
|
||||||
} else {
|
|
||||||
// The person is not logged into Facebook
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Load the SDK asynchronously
|
|
||||||
(function(d){
|
|
||||||
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
|
|
||||||
if (d.getElementById(id)) {return;}
|
|
||||||
js = d.createElement('script'); js.id = id; js.async = true;
|
|
||||||
js.src = "//connect.facebook.net/en_US/all.js";
|
|
||||||
//js.src = "//connect.facebook.net/en_US/all/debug.js";
|
|
||||||
ref.parentNode.insertBefore(js, ref);
|
|
||||||
}(document));
|
|
||||||
</script>
|
|
||||||
<!-- end facebook code -->
|
|
||||||
|
|
||||||
|
|
||||||
<header class="header-container" id="header-container"></header>
|
<header class="header-container" id="header-container"></header>
|
||||||
|
|
||||||
<div id="page-container" class="nano-content"></div>
|
<div id="page-container" class="nano-content"></div>
|
||||||
|
|
||||||
<div id="modal-wrapper" class="modal-content"></div>
|
<div id="modal-wrapper" class="modal-content"></div>
|
||||||
|
|
||||||
<!-- begin google api/plus code -->
|
|
||||||
<script type="text/javascript">
|
|
||||||
(function() {
|
|
||||||
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
|
|
||||||
po.src = 'https://apis.google.com/js/client:plusone.js?onload=onGPlusLoaded';
|
|
||||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
|
|
||||||
})();
|
|
||||||
|
|
||||||
function onGPlusLoaded() {
|
|
||||||
Backbone.Mediator.publish('gapi-loaded');
|
|
||||||
}
|
|
||||||
|
|
||||||
function signinCallback(authResult) {
|
|
||||||
if (authResult['access_token']) {
|
|
||||||
Backbone.Mediator.publish('gplus-logged-in', authResult)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<!-- end google api/plus code -->
|
|
||||||
|
|
||||||
<!-- begin twitter code -->
|
|
||||||
<script>
|
|
||||||
(function (d,s,id) {
|
|
||||||
var js, fjs = d.getElementsByTagName(s)[0], p = /^http:/.test(d.location) ? 'http' : 'https';
|
|
||||||
if(!d.getElementById(id)) {
|
|
||||||
js = d.createElement(s);
|
|
||||||
js.id = id;
|
|
||||||
js.src = p + '://platform.twitter.com/widgets.js';
|
|
||||||
fjs.parentNode.insertBefore(js, fjs);
|
|
||||||
}
|
|
||||||
})(document, 'script', 'twitter-wjs');
|
|
||||||
</script>
|
|
||||||
<!-- end twitter code -->
|
|
||||||
|
|
||||||
<!-- begin filepicker.io code -->
|
|
||||||
<script type="text/javascript">
|
|
||||||
(function(a){if(window.filepicker){return}var b=a.createElement("script");b.type="text/javascript";b.async=!0;b.src=("https:"===a.location.protocol?"https:":"http:")+"//api.filepicker.io/v1/filepicker.js";var c=a.getElementsByTagName("script")[0];c.parentNode.insertBefore(b,c);var d={};d._queue=[];var e="pick,pickMultiple,pickAndStore,read,write,writeUrl,export,convert,store,storeUrl,remove,stat,setKey,constructWidget,makeDropPane".split(",");var f=function(a,b){return function(){b.push([a,arguments])}};for(var g=0;g<e.length;g++){d[e[g]]=f(e[g],d._queue)}window.filepicker=d})(document);
|
|
||||||
</script>
|
|
||||||
<!-- end filepicker.io code -->
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -18,6 +18,11 @@ definitionSchemas =
|
||||||
'misc': require './schemas/definitions/misc'
|
'misc': require './schemas/definitions/misc'
|
||||||
|
|
||||||
init = ->
|
init = ->
|
||||||
|
path = document.location.pathname
|
||||||
|
testing = path.startsWith '/test'
|
||||||
|
demoing = path.startsWith '/demo'
|
||||||
|
initializeServices() unless testing or demoing
|
||||||
|
|
||||||
# Set up Backbone.Mediator schemas
|
# Set up Backbone.Mediator schemas
|
||||||
setUpDefinitions()
|
setUpDefinitions()
|
||||||
setUpChannels()
|
setUpChannels()
|
||||||
|
@ -28,7 +33,6 @@ init = ->
|
||||||
|
|
||||||
treemaExt = require 'treema-ext'
|
treemaExt = require 'treema-ext'
|
||||||
treemaExt.setup()
|
treemaExt.setup()
|
||||||
filepicker.setKey('AvlkNoldcTOU4PvKi2Xm7z')
|
|
||||||
|
|
||||||
$ -> init()
|
$ -> init()
|
||||||
|
|
||||||
|
@ -60,3 +64,18 @@ setUpChannels = ->
|
||||||
setUpDefinitions = ->
|
setUpDefinitions = ->
|
||||||
for definition of definitionSchemas
|
for definition of definitionSchemas
|
||||||
Backbone.Mediator.addDefSchemas definitionSchemas[definition]
|
Backbone.Mediator.addDefSchemas definitionSchemas[definition]
|
||||||
|
|
||||||
|
initializeServices = ->
|
||||||
|
services = [
|
||||||
|
'./lib/services/filepicker'
|
||||||
|
'./lib/services/segmentio'
|
||||||
|
'./lib/services/olark'
|
||||||
|
'./lib/services/facebook'
|
||||||
|
'./lib/services/google'
|
||||||
|
'./lib/services/twitter'
|
||||||
|
'./lib/services/linkedin'
|
||||||
|
]
|
||||||
|
|
||||||
|
for service in services
|
||||||
|
service = require service
|
||||||
|
service()
|
||||||
|
|
|
@ -16,8 +16,9 @@ module.exports = class CocoRouter extends Backbone.Router
|
||||||
# editor views tend to have the same general structure
|
# editor views tend to have the same general structure
|
||||||
'editor/:model(/:slug_or_id)(/:subview)': 'editorModelView'
|
'editor/:model(/:slug_or_id)(/:subview)': 'editorModelView'
|
||||||
|
|
||||||
# Experimenting with direct links
|
# Direct links
|
||||||
'test/*subpath': go('test')
|
'test/*subpath': go('TestView')
|
||||||
|
'demo/*subpath': go('DemoView')
|
||||||
'play/ladder/:levelID': go('play/ladder/ladder_view')
|
'play/ladder/:levelID': go('play/ladder/ladder_view')
|
||||||
'play/ladder': go('play/ladder_home')
|
'play/ladder': go('play/ladder_home')
|
||||||
|
|
||||||
|
|
48
app/lib/requireUtils.coffee
Normal file
48
app/lib/requireUtils.coffee
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
module.exports.getParentFolders = (subPath, urlPrefix='/test/') ->
|
||||||
|
return [] unless subPath
|
||||||
|
paths = []
|
||||||
|
parts = subPath.split('/')
|
||||||
|
while parts.length
|
||||||
|
parts.pop()
|
||||||
|
paths.unshift {
|
||||||
|
name: parts[parts.length-1] or 'All'
|
||||||
|
url: urlPrefix + parts.join('/')
|
||||||
|
}
|
||||||
|
paths
|
||||||
|
|
||||||
|
module.exports.parseImmediateChildren = (allChildren, subPath, baseRequirePath='test/app/', urlPrefix='/test/') ->
|
||||||
|
return [] unless allChildren
|
||||||
|
folders = {}
|
||||||
|
files = {}
|
||||||
|
|
||||||
|
requirePrefix = baseRequirePath + subPath
|
||||||
|
if requirePrefix[requirePrefix.length-1] isnt '/'
|
||||||
|
requirePrefix += '/'
|
||||||
|
|
||||||
|
for f in allChildren
|
||||||
|
f = f[requirePrefix.length..]
|
||||||
|
continue unless f
|
||||||
|
parts = f.split('/')
|
||||||
|
name = parts[0]
|
||||||
|
group = if parts.length is 1 then files else folders
|
||||||
|
group[name] ?= 0
|
||||||
|
group[name] += 1
|
||||||
|
|
||||||
|
children = []
|
||||||
|
urlPrefix += subPath
|
||||||
|
urlPrefix += '/' if urlPrefix[urlPrefix.length-1] isnt '/'
|
||||||
|
|
||||||
|
for name in _.keys(folders)
|
||||||
|
children.push {
|
||||||
|
type:'folder',
|
||||||
|
url: urlPrefix+name
|
||||||
|
name: name+'/'
|
||||||
|
size: folders[name]
|
||||||
|
}
|
||||||
|
for name in _.keys(files)
|
||||||
|
children.push {
|
||||||
|
type:'file',
|
||||||
|
url: urlPrefix+name
|
||||||
|
name: name
|
||||||
|
}
|
||||||
|
children
|
42
app/lib/services/facebook.coffee
Normal file
42
app/lib/services/facebook.coffee
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
module.exports = initializeFacebook = ->
|
||||||
|
# Additional JS functions here
|
||||||
|
window.fbAsyncInit = ->
|
||||||
|
Backbone.Mediator.publish "fbapi-loaded"
|
||||||
|
FB.init
|
||||||
|
appId: (if document.location.origin is "http://localhost:3000" then "607435142676437" else "148832601965463") # App ID
|
||||||
|
channelUrl: document.location.origin + "/channel.html" # Channel File
|
||||||
|
status: true # check login status
|
||||||
|
cookie: true # enable cookies to allow the server to access the session
|
||||||
|
xfbml: true # parse XFBML
|
||||||
|
|
||||||
|
|
||||||
|
# This is fired for any auth related change, such as login, logout or session refresh.
|
||||||
|
FB.Event.subscribe "auth.authResponseChange", (response) ->
|
||||||
|
|
||||||
|
# Here we specify what we do with the response anytime this event occurs.
|
||||||
|
if response.status is "connected"
|
||||||
|
|
||||||
|
# They have logged in to the app.
|
||||||
|
Backbone.Mediator.publish "facebook-logged-in",
|
||||||
|
response: response
|
||||||
|
|
||||||
|
else if response.status is "not_authorized"
|
||||||
|
#
|
||||||
|
else
|
||||||
|
#
|
||||||
|
|
||||||
|
# Load the SDK asynchronously
|
||||||
|
((d) ->
|
||||||
|
js = undefined
|
||||||
|
id = "facebook-jssdk"
|
||||||
|
ref = d.getElementsByTagName("script")[0]
|
||||||
|
return if d.getElementById(id)
|
||||||
|
js = d.createElement("script")
|
||||||
|
js.id = id
|
||||||
|
js.async = true
|
||||||
|
js.src = "//connect.facebook.net/en_US/all.js"
|
||||||
|
|
||||||
|
#js.src = "//connect.facebook.net/en_US/all/debug.js";
|
||||||
|
ref.parentNode.insertBefore js, ref
|
||||||
|
return
|
||||||
|
) document
|
29
app/lib/services/filepicker.coffee
Normal file
29
app/lib/services/filepicker.coffee
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
module.exports = initializeFilepicker = ->
|
||||||
|
((a) ->
|
||||||
|
return if window.filepicker
|
||||||
|
b = a.createElement("script")
|
||||||
|
b.type = "text/javascript"
|
||||||
|
b.async = not 0
|
||||||
|
b.src = ((if "https:" is a.location.protocol then "https:" else "http:")) + "//api.filepicker.io/v1/filepicker.js"
|
||||||
|
c = a.getElementsByTagName("script")[0]
|
||||||
|
c.parentNode.insertBefore b, c
|
||||||
|
d = {}
|
||||||
|
d._queue = []
|
||||||
|
e = "pick,pickMultiple,pickAndStore,read,write,writeUrl,export,convert,store,storeUrl,remove,stat,setKey,constructWidget,makeDropPane".split(",")
|
||||||
|
f = (a, b) ->
|
||||||
|
->
|
||||||
|
b.push [
|
||||||
|
a
|
||||||
|
arguments
|
||||||
|
]
|
||||||
|
return
|
||||||
|
|
||||||
|
g = 0
|
||||||
|
|
||||||
|
while g < e.length
|
||||||
|
d[e[g]] = f(e[g], d._queue)
|
||||||
|
g++
|
||||||
|
d.setKey('AvlkNoldcTOU4PvKi2Xm7z')
|
||||||
|
window.filepicker = d
|
||||||
|
return
|
||||||
|
) document
|
16
app/lib/services/google.coffee
Normal file
16
app/lib/services/google.coffee
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
module.exports = initializeGoogle = ->
|
||||||
|
onGPlusLoaded = ->
|
||||||
|
Backbone.Mediator.publish "gapi-loaded"
|
||||||
|
return
|
||||||
|
signinCallback = (authResult) ->
|
||||||
|
Backbone.Mediator.publish "gplus-logged-in", authResult if authResult["access_token"]
|
||||||
|
return
|
||||||
|
(->
|
||||||
|
po = document.createElement("script")
|
||||||
|
po.type = "text/javascript"
|
||||||
|
po.async = true
|
||||||
|
po.src = "https://apis.google.com/js/client:plusone.js?onload=onGPlusLoaded"
|
||||||
|
s = document.getElementsByTagName("script")[0]
|
||||||
|
s.parentNode.insertBefore po, s
|
||||||
|
return
|
||||||
|
)()
|
12
app/lib/services/linkedin.coffee
Normal file
12
app/lib/services/linkedin.coffee
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
module.exports = initializeLinkedIn = ->
|
||||||
|
window.linkedInAsyncInit = ->
|
||||||
|
Backbone.Mediator.publish 'linkedin-loaded'
|
||||||
|
|
||||||
|
linkedInSnippet =
|
||||||
|
'<script type="text/javascript" async src="http://platform.linkedin.com/in.js">
|
||||||
|
api_key: 75v8mv4ictvmx6
|
||||||
|
onLoad: linkedInAsyncInit
|
||||||
|
authorize: true
|
||||||
|
</script>'
|
||||||
|
|
||||||
|
$('head').append(linkedInSnippet)
|
116
app/lib/services/olark.coffee
Normal file
116
app/lib/services/olark.coffee
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
module.exports = initializeOlark = ->
|
||||||
|
window.olark or ((c) -> #<![CDATA[
|
||||||
|
f = window
|
||||||
|
d = document
|
||||||
|
l = (if f.location.protocol is "https:" then "https:" else "http:")
|
||||||
|
z = c.name
|
||||||
|
r = "load"
|
||||||
|
nt = ->
|
||||||
|
s = ->
|
||||||
|
a.P r
|
||||||
|
f[z] r
|
||||||
|
return
|
||||||
|
f[z] = ->
|
||||||
|
(a.s = a.s or []).push arguments
|
||||||
|
return
|
||||||
|
|
||||||
|
a = f[z]._ = {}
|
||||||
|
q = c.methods.length
|
||||||
|
while q--
|
||||||
|
((n) ->
|
||||||
|
f[z][n] = ->
|
||||||
|
f[z] "call", n, arguments
|
||||||
|
return
|
||||||
|
|
||||||
|
return
|
||||||
|
) c.methods[q]
|
||||||
|
a.l = c.loader
|
||||||
|
a.i = nt
|
||||||
|
a.p = 0: +new Date
|
||||||
|
a.P = (u) ->
|
||||||
|
a.p[u] = new Date - a.p[0]
|
||||||
|
return
|
||||||
|
|
||||||
|
(if f.addEventListener then f.addEventListener(r, s, false) else f.attachEvent("on" + r, s))
|
||||||
|
ld = ->
|
||||||
|
p = (hd) ->
|
||||||
|
hd = "head"
|
||||||
|
[
|
||||||
|
"<"
|
||||||
|
hd
|
||||||
|
"></"
|
||||||
|
hd
|
||||||
|
"><"
|
||||||
|
i
|
||||||
|
" onl" + "oad=\"var d="
|
||||||
|
g
|
||||||
|
";d.getElementsByTagName('head')[0]."
|
||||||
|
j
|
||||||
|
"(d."
|
||||||
|
h
|
||||||
|
"('script'))."
|
||||||
|
k
|
||||||
|
"='"
|
||||||
|
l
|
||||||
|
"//"
|
||||||
|
a.l
|
||||||
|
"'"
|
||||||
|
"\""
|
||||||
|
"></"
|
||||||
|
i
|
||||||
|
">"
|
||||||
|
].join ""
|
||||||
|
i = "body"
|
||||||
|
m = d[i]
|
||||||
|
return setTimeout(ld, 100) unless m
|
||||||
|
a.P 1
|
||||||
|
j = "appendChild"
|
||||||
|
h = "createElement"
|
||||||
|
k = "src"
|
||||||
|
n = d[h]("div")
|
||||||
|
v = n[j](d[h](z))
|
||||||
|
b = d[h]("iframe")
|
||||||
|
g = "document"
|
||||||
|
e = "domain"
|
||||||
|
o = undefined
|
||||||
|
n.style.display = "none"
|
||||||
|
m.insertBefore(n, m.firstChild).id = z
|
||||||
|
b.frameBorder = "0"
|
||||||
|
b.id = z + "-loader"
|
||||||
|
b.src = "javascript:false" if /MSIE[ ]+6/.test(navigator.userAgent)
|
||||||
|
b.allowTransparency = "true"
|
||||||
|
v[j] b
|
||||||
|
try
|
||||||
|
b.contentWindow[g].open()
|
||||||
|
catch w
|
||||||
|
c[e] = d[e]
|
||||||
|
o = "javascript:var d=" + g + ".open();d.domain='" + d.domain + "';"
|
||||||
|
b[k] = o + "void(0);"
|
||||||
|
try
|
||||||
|
t = b.contentWindow[g]
|
||||||
|
t.write p()
|
||||||
|
t.close()
|
||||||
|
catch x
|
||||||
|
b[k] = o + "d.write(\"" + p().replace(/"/g, String.fromCharCode(92) + "\"") + "\");d.close();"
|
||||||
|
a.P 2
|
||||||
|
return
|
||||||
|
|
||||||
|
ld()
|
||||||
|
return
|
||||||
|
|
||||||
|
nt()
|
||||||
|
return
|
||||||
|
)(
|
||||||
|
loader: "static.olark.com/jsclient/loader0.js"
|
||||||
|
name: "olark"
|
||||||
|
methods: [
|
||||||
|
"configure"
|
||||||
|
"extend"
|
||||||
|
"declare"
|
||||||
|
"identify"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# custom configuration goes here (www.olark.com/documentation)
|
||||||
|
olark.identify "1451-787-10-5544" #]]>
|
||||||
|
|
41
app/lib/services/segmentio.coffee
Normal file
41
app/lib/services/segmentio.coffee
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
module.exports = initializeSegmentio = ->
|
||||||
|
analytics = analytics or []
|
||||||
|
(->
|
||||||
|
e = [
|
||||||
|
"identify"
|
||||||
|
"track"
|
||||||
|
"trackLink"
|
||||||
|
"trackForm"
|
||||||
|
"trackClick"
|
||||||
|
"trackSubmit"
|
||||||
|
"page"
|
||||||
|
"pageview"
|
||||||
|
"ab"
|
||||||
|
"alias"
|
||||||
|
"ready"
|
||||||
|
"group"
|
||||||
|
]
|
||||||
|
t = (e) ->
|
||||||
|
->
|
||||||
|
analytics.push [e].concat(Array::slice.call(arguments, 0))
|
||||||
|
return
|
||||||
|
|
||||||
|
n = 0
|
||||||
|
|
||||||
|
while n < e.length
|
||||||
|
analytics[e[n]] = t(e[n])
|
||||||
|
n++
|
||||||
|
return
|
||||||
|
)()
|
||||||
|
analytics.load = (e) ->
|
||||||
|
t = document.createElement("script")
|
||||||
|
t.type = "text/javascript"
|
||||||
|
t.async = not 0
|
||||||
|
t.src = ((if "https:" is document.location.protocol then "https://" else "http://")) + "d2dq2ahtl5zl1z.cloudfront.net/analytics.js/v1/" + e + "/analytics.min.js"
|
||||||
|
|
||||||
|
n = document.getElementsByTagName("script")[0]
|
||||||
|
n.parentNode.insertBefore t, n
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
analytics.load "jsjzx9n4d2"
|
12
app/lib/services/twitter.coffee
Normal file
12
app/lib/services/twitter.coffee
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
module.exports = initializeTwitter = ->
|
||||||
|
((d, s, id) ->
|
||||||
|
js = undefined
|
||||||
|
fjs = d.getElementsByTagName(s)[0]
|
||||||
|
p = (if /^http:/.test(d.location) then "http" else "https")
|
||||||
|
unless d.getElementById(id)
|
||||||
|
js = d.createElement(s)
|
||||||
|
js.id = id
|
||||||
|
js.src = p + "://platform.twitter.com/widgets.js"
|
||||||
|
fjs.parentNode.insertBefore js, fjs
|
||||||
|
return
|
||||||
|
) document, "script", "twitter-wjs"
|
|
@ -282,6 +282,7 @@
|
||||||
education_description: "Description"
|
education_description: "Description"
|
||||||
education_description_help: "Highlight anything about this educational experience. (140 chars; optional)"
|
education_description_help: "Highlight anything about this educational experience. (140 chars; optional)"
|
||||||
our_notes: "Our Notes"
|
our_notes: "Our Notes"
|
||||||
|
remarks: "Remarks"
|
||||||
projects: "Projects"
|
projects: "Projects"
|
||||||
projects_header: "Add 3 projects"
|
projects_header: "Add 3 projects"
|
||||||
projects_header_2: "Projects (Top 3)"
|
projects_header_2: "Projects (Top 3)"
|
||||||
|
@ -320,6 +321,7 @@
|
||||||
candidate_top_skills: "Top Skills"
|
candidate_top_skills: "Top Skills"
|
||||||
candidate_years_experience: "Yrs Exp"
|
candidate_years_experience: "Yrs Exp"
|
||||||
candidate_last_updated: "Last Updated"
|
candidate_last_updated: "Last Updated"
|
||||||
|
candidate_who: "Who"
|
||||||
featured_developers: "Featured Developers"
|
featured_developers: "Featured Developers"
|
||||||
other_developers: "Other Developers"
|
other_developers: "Other Developers"
|
||||||
inactive_developers: "Inactive Developers"
|
inactive_developers: "Inactive Developers"
|
||||||
|
@ -884,6 +886,7 @@
|
||||||
document: "Document"
|
document: "Document"
|
||||||
sprite_sheet: "Sprite Sheet"
|
sprite_sheet: "Sprite Sheet"
|
||||||
candidate_sessions: "Candidate Sessions"
|
candidate_sessions: "Candidate Sessions"
|
||||||
|
user_remark: "User Remark"
|
||||||
|
|
||||||
delta:
|
delta:
|
||||||
added: "Added"
|
added: "Added"
|
||||||
|
|
|
@ -193,13 +193,13 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
||||||
view_profile: "Voir votre profil"
|
view_profile: "Voir votre profil"
|
||||||
|
|
||||||
account_profile:
|
account_profile:
|
||||||
# settings: "Settings"
|
settings: "Paramètres"
|
||||||
# edit_profile: "Edit Profile"
|
edit_profile: "Editer Profil"
|
||||||
# done_editing: "Done Editing"
|
done_editing: "Modifications effectué"
|
||||||
profile_for_prefix: "Profil pour "
|
profile_for_prefix: "Profil pour "
|
||||||
profile_for_suffix: ""
|
profile_for_suffix: ""
|
||||||
# featured: "Featured"
|
featured: "Complet"
|
||||||
# not_featured: "Not Featured"
|
not_featured: "Incomplet"
|
||||||
looking_for: "à la recherche de:"
|
looking_for: "à la recherche de:"
|
||||||
last_updated: "Dernière Mise à jour:"
|
last_updated: "Dernière Mise à jour:"
|
||||||
contact: "Contact"
|
contact: "Contact"
|
||||||
|
@ -220,7 +220,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
||||||
next_photo: "ajouter une photo professionelle (optionnel)."
|
next_photo: "ajouter une photo professionelle (optionnel)."
|
||||||
next_active: "déclarez vous ouvert aux offres pour apparaitre dans les recherches."
|
next_active: "déclarez vous ouvert aux offres pour apparaitre dans les recherches."
|
||||||
example_blog: "Votre blog"
|
example_blog: "Votre blog"
|
||||||
# example_personal_site: "Personal Site"
|
example_personal_site: "Site Web"
|
||||||
links_header: "Liens personnels"
|
links_header: "Liens personnels"
|
||||||
links_blurb: "Lien vers d'autres sites ou profils que vous souhaitez mettre en avant, comme votre GitHub, LinkedIn ou votre blog."
|
links_blurb: "Lien vers d'autres sites ou profils que vous souhaitez mettre en avant, comme votre GitHub, LinkedIn ou votre blog."
|
||||||
links_name: "Nom du lien"
|
links_name: "Nom du lien"
|
||||||
|
@ -448,7 +448,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
||||||
av_entities_sub_title: "Entités"
|
av_entities_sub_title: "Entités"
|
||||||
av_entities_users_url: "Utilisateurs"
|
av_entities_users_url: "Utilisateurs"
|
||||||
av_entities_active_instances_url: "Instances actives"
|
av_entities_active_instances_url: "Instances actives"
|
||||||
# av_entities_employer_list_url: "Employer List"
|
av_entities_employer_list_url: "Liste des employés"
|
||||||
av_other_sub_title: "Autre"
|
av_other_sub_title: "Autre"
|
||||||
av_other_debug_base_url: "Base (pour debugger base.jade)"
|
av_other_debug_base_url: "Base (pour debugger base.jade)"
|
||||||
u_title: "Liste des utilisateurs"
|
u_title: "Liste des utilisateurs"
|
||||||
|
@ -653,7 +653,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
||||||
introduction_desc_ending: "Nous espérons que vous allez joindre notre aventure!"
|
introduction_desc_ending: "Nous espérons que vous allez joindre notre aventure!"
|
||||||
introduction_desc_signature: "- Nick, George, Scott, Michael, Jeremy et Glen"
|
introduction_desc_signature: "- Nick, George, Scott, Michael, Jeremy et Glen"
|
||||||
alert_account_message_intro: "Et tiens!"
|
alert_account_message_intro: "Et tiens!"
|
||||||
# alert_account_message: "To subscribe for class emails, you'll need to be logged in first."
|
alert_account_message: "Pour souscrire aux e-mails, vous devez être connecté"
|
||||||
# archmage_summary: "Interested in working on game graphics, user interface design, database and server organization, multiplayer networking, physics, sound, or game engine performance? Want to help build a game to help other people learn what you are good at? We have a lot to do and if you are an experienced programmer and want to develop for CodeCombat, this class is for you. We would love your help building the best programming game ever."
|
# archmage_summary: "Interested in working on game graphics, user interface design, database and server organization, multiplayer networking, physics, sound, or game engine performance? Want to help build a game to help other people learn what you are good at? We have a lot to do and if you are an experienced programmer and want to develop for CodeCombat, this class is for you. We would love your help building the best programming game ever."
|
||||||
archmage_introduction: "L'une des meilleures parties de la création d'un jeu est qu'il regroupe tant de choses différentes. Graphismes, sons, réseau en temps réel, réseaux sociaux, et bien sur bien d'autres aspects de la programmation, de la gestion bas niveau de base de données, et de l'administration de serveur à l'élaboration d'interfaces utilisateur. Il y a tant à faire, et si vous êtes un programmeur expérimenté avec une aspiration à vraiment plonger dans le fond de CodeCombat, cette classe est faite pour vous. Nous aimerions avoir votre aide pour le meilleur jeu de développement de tous les temps."
|
archmage_introduction: "L'une des meilleures parties de la création d'un jeu est qu'il regroupe tant de choses différentes. Graphismes, sons, réseau en temps réel, réseaux sociaux, et bien sur bien d'autres aspects de la programmation, de la gestion bas niveau de base de données, et de l'administration de serveur à l'élaboration d'interfaces utilisateur. Il y a tant à faire, et si vous êtes un programmeur expérimenté avec une aspiration à vraiment plonger dans le fond de CodeCombat, cette classe est faite pour vous. Nous aimerions avoir votre aide pour le meilleur jeu de développement de tous les temps."
|
||||||
class_attributes: "Attributs de classe"
|
class_attributes: "Attributs de classe"
|
||||||
|
@ -860,7 +860,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
|
||||||
# facebook_friend_sessions: "Facebook Friend Sessions"
|
# facebook_friend_sessions: "Facebook Friend Sessions"
|
||||||
# gplus_friends: "G+ Friends"
|
# gplus_friends: "G+ Friends"
|
||||||
# gplus_friend_sessions: "G+ Friend Sessions"
|
# gplus_friend_sessions: "G+ Friend Sessions"
|
||||||
# leaderboard: "Leaderboard"
|
leaderboard: "Classement"
|
||||||
# user_schema: "User Schema"
|
# user_schema: "User Schema"
|
||||||
# user_profile: "User Profile"
|
# user_profile: "User Profile"
|
||||||
patches: "Patchs"
|
patches: "Patchs"
|
||||||
|
|
|
@ -26,14 +26,14 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t
|
||||||
minutes: "percek"
|
minutes: "percek"
|
||||||
hour: "óra"
|
hour: "óra"
|
||||||
hours: "órák"
|
hours: "órák"
|
||||||
# day: "day"
|
day: "nap"
|
||||||
# days: "days"
|
days: "napok"
|
||||||
# week: "week"
|
week: "hét"
|
||||||
# weeks: "weeks"
|
weeks: "hetek"
|
||||||
# month: "month"
|
month: "hónap"
|
||||||
# months: "months"
|
months: "hónapok"
|
||||||
# year: "year"
|
year: "év"
|
||||||
# years: "years"
|
years: "évek"
|
||||||
|
|
||||||
modal:
|
modal:
|
||||||
close: "Mégse"
|
close: "Mégse"
|
||||||
|
|
|
@ -161,7 +161,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
autosave: "Настройки сохраняются автоматически"
|
autosave: "Настройки сохраняются автоматически"
|
||||||
me_tab: "Я"
|
me_tab: "Я"
|
||||||
picture_tab: "Аватар"
|
picture_tab: "Аватар"
|
||||||
# upload_picture: "Upload a picture"
|
upload_picture: "Загрузить изображение"
|
||||||
wizard_tab: "Волшебник"
|
wizard_tab: "Волшебник"
|
||||||
password_tab: "Пароль"
|
password_tab: "Пароль"
|
||||||
emails_tab: "Email-адреса"
|
emails_tab: "Email-адреса"
|
||||||
|
@ -175,9 +175,9 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
email_notifications: "Уведомления"
|
email_notifications: "Уведомления"
|
||||||
# email_notifications_summary: "Controls for personalized, automatic email notifications related to your CodeCombat activity."
|
# email_notifications_summary: "Controls for personalized, automatic email notifications related to your CodeCombat activity."
|
||||||
# email_any_notes: "Any Notifications"
|
# email_any_notes: "Any Notifications"
|
||||||
# email_any_notes_description: "Disable to stop all activity notification emails."
|
email_any_notes_description: "Отключите, чтобы больше не получать извещения."
|
||||||
# email_recruit_notes: "Job Opportunities"
|
email_recruit_notes: "Возможности для работы"
|
||||||
# email_recruit_notes_description: "If you play really well, we may contact you about getting you a (better) job."
|
email_recruit_notes_description: "Если вы действительно хорошо играете, то мы можем связаться с вами для предложения (лучшей) работы."
|
||||||
contributor_emails: "Рассылки по классам участников"
|
contributor_emails: "Рассылки по классам участников"
|
||||||
contribute_prefix: "Нам нужны люди, которые присоединятся к нашей команде! Зайдите на "
|
contribute_prefix: "Нам нужны люди, которые присоединятся к нашей команде! Зайдите на "
|
||||||
contribute_page: "страницу участников,"
|
contribute_page: "страницу участников,"
|
||||||
|
@ -206,9 +206,9 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
# active: "Looking for interview offers now"
|
# active: "Looking for interview offers now"
|
||||||
# inactive: "Not looking for offers right now"
|
# inactive: "Not looking for offers right now"
|
||||||
# complete: "complete"
|
# complete: "complete"
|
||||||
# next: "Next"
|
next: "Далее"
|
||||||
# next_city: "city?"
|
next_city: "Город?"
|
||||||
# next_country: "pick your country."
|
next_country: "Выберите вашу страну."
|
||||||
# next_name: "name?"
|
# next_name: "name?"
|
||||||
# next_short_description: "write a short description."
|
# next_short_description: "write a short description."
|
||||||
# next_long_description: "describe your desired position."
|
# next_long_description: "describe your desired position."
|
||||||
|
@ -333,7 +333,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
multiplayer: "Мультиплеер"
|
multiplayer: "Мультиплеер"
|
||||||
restart: "Перезапустить"
|
restart: "Перезапустить"
|
||||||
goals: "Цели"
|
goals: "Цели"
|
||||||
# success: "Success!"
|
success: "Успешно!"
|
||||||
# incomplete: "Incomplete"
|
# incomplete: "Incomplete"
|
||||||
# timed_out: "Ran out of time"
|
# timed_out: "Ran out of time"
|
||||||
# failing: "Failing"
|
# failing: "Failing"
|
||||||
|
@ -358,7 +358,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
multiplayer_hint_label: "Подсказка: "
|
multiplayer_hint_label: "Подсказка: "
|
||||||
multiplayer_hint: "кликните на ссылку, чтобы выделить её, затем нажмите ⌘-С или Ctrl-C, чтобы скопировать."
|
multiplayer_hint: "кликните на ссылку, чтобы выделить её, затем нажмите ⌘-С или Ctrl-C, чтобы скопировать."
|
||||||
multiplayer_coming_soon: "Больше возможностей мультиплеера на подходе!"
|
multiplayer_coming_soon: "Больше возможностей мультиплеера на подходе!"
|
||||||
# multiplayer_sign_in_leaderboard: "Sign in or create an account and get your solution on the leaderboard."
|
multiplayer_sign_in_leaderboard: "Войдите или создайте аккаунт, чтобы ваше решение оказалось в таблице лидеров."
|
||||||
guide_title: "Руководство"
|
guide_title: "Руководство"
|
||||||
tome_minion_spells: "Заклинания ваших миньонов"
|
tome_minion_spells: "Заклинания ваших миньонов"
|
||||||
tome_read_only_spells: "Заклинания только для чтения"
|
tome_read_only_spells: "Заклинания только для чтения"
|
||||||
|
@ -375,9 +375,9 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
skip_tutorial: "Пропуск (Esc)"
|
skip_tutorial: "Пропуск (Esc)"
|
||||||
editor_config: "Настройки редактора"
|
editor_config: "Настройки редактора"
|
||||||
editor_config_title: "Настройки редактора"
|
editor_config_title: "Настройки редактора"
|
||||||
# editor_config_level_language_label: "Language for This Level"
|
editor_config_level_language_label: "Язык для этого уровня"
|
||||||
# editor_config_level_language_description: "Define the programming language for this particular level."
|
# editor_config_level_language_description: "Define the programming language for this particular level."
|
||||||
# editor_config_default_language_label: "Default Programming Language"
|
editor_config_default_language_label: "Язык по умолчанию"
|
||||||
# editor_config_default_language_description: "Define the programming language you want to code in when starting new levels."
|
# editor_config_default_language_description: "Define the programming language you want to code in when starting new levels."
|
||||||
editor_config_keybindings_label: "Сочетания клавиш"
|
editor_config_keybindings_label: "Сочетания клавиш"
|
||||||
editor_config_keybindings_default: "По умолчанию (Ace)"
|
editor_config_keybindings_default: "По умолчанию (Ace)"
|
||||||
|
@ -388,7 +388,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
editor_config_indentguides_description: "Отображение вертикальных линий для лучшего обзора отступов."
|
editor_config_indentguides_description: "Отображение вертикальных линий для лучшего обзора отступов."
|
||||||
editor_config_behaviors_label: "Умное поведение"
|
editor_config_behaviors_label: "Умное поведение"
|
||||||
editor_config_behaviors_description: "Автозавершать квадратные, фигурные скобки и кавычки."
|
editor_config_behaviors_description: "Автозавершать квадратные, фигурные скобки и кавычки."
|
||||||
# keyboard_shortcuts: "Key Shortcuts"
|
keyboard_shortcuts: "Горячие клавиши"
|
||||||
loading_ready: "Готово!"
|
loading_ready: "Готово!"
|
||||||
tip_insert_positions: "Shift+Клик по карте вставит координаты в редактор заклинаний."
|
tip_insert_positions: "Shift+Клик по карте вставит координаты в редактор заклинаний."
|
||||||
tip_toggle_play: "Переключайте воспроизведение/паузу комбинацией Ctrl+P."
|
tip_toggle_play: "Переключайте воспроизведение/паузу комбинацией Ctrl+P."
|
||||||
|
@ -425,12 +425,12 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
infinite_loop_reset_level: "Сбросить уровень"
|
infinite_loop_reset_level: "Сбросить уровень"
|
||||||
infinite_loop_comment_out: "Закомментировать мой код"
|
infinite_loop_comment_out: "Закомментировать мой код"
|
||||||
|
|
||||||
# keyboard_shortcuts:
|
keyboard_shortcuts:
|
||||||
# keyboard_shortcuts: "Keyboard Shortcuts"
|
keyboard_shortcuts: "Горячие клавиши"
|
||||||
# space: "Space"
|
space: "Пробел"
|
||||||
# enter: "Enter"
|
enter: "Enter"
|
||||||
# escape: "Escape"
|
escape: "Escape"
|
||||||
# cast_spell: "Cast current spell."
|
cast_spell: "Произнести текущее заклинание."
|
||||||
# continue_script: "Continue past current script."
|
# continue_script: "Continue past current script."
|
||||||
# skip_scripts: "Skip past all skippable scripts."
|
# skip_scripts: "Skip past all skippable scripts."
|
||||||
# toggle_playback: "Toggle play/pause."
|
# toggle_playback: "Toggle play/pause."
|
||||||
|
@ -471,7 +471,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
thang_description: "Создавайте юнитов, определяйте их логику по умолчанию, графику и звук. В настоящий момент поддерживается импорт только векторной графики Flash."
|
thang_description: "Создавайте юнитов, определяйте их логику по умолчанию, графику и звук. В настоящий момент поддерживается импорт только векторной графики Flash."
|
||||||
level_title: "Редактор уровней"
|
level_title: "Редактор уровней"
|
||||||
level_description: "Включает в себя инструменты для написания сценариев, загрузки аудио и построения собственной логики для создания всевозможных уровней. Всё, что мы используем сами!"
|
level_description: "Включает в себя инструменты для написания сценариев, загрузки аудио и построения собственной логики для создания всевозможных уровней. Всё, что мы используем сами!"
|
||||||
# achievement_title: "Achievement Editor"
|
achievement_title: "Редактор достижений"
|
||||||
got_questions: "Вопросы по использованию редакторов CodeCombat?"
|
got_questions: "Вопросы по использованию редакторов CodeCombat?"
|
||||||
contact_us: "свяжитесь с нами!"
|
contact_us: "свяжитесь с нами!"
|
||||||
hipchat_prefix: "Также вы можете найти нас в нашей"
|
hipchat_prefix: "Также вы можете найти нас в нашей"
|
||||||
|
@ -522,7 +522,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
article_search_title: "Искать статьи"
|
article_search_title: "Искать статьи"
|
||||||
thang_search_title: "Искать типы объектов"
|
thang_search_title: "Искать типы объектов"
|
||||||
level_search_title: "Искать уровни"
|
level_search_title: "Искать уровни"
|
||||||
# achievement_search_title: "Search Achievements"
|
achievement_search_title: "Искать достижения"
|
||||||
read_only_warning2: "Примечание: вы не можете сохранять любые правки здесь, потому что вы не авторизованы."
|
read_only_warning2: "Примечание: вы не можете сохранять любые правки здесь, потому что вы не авторизованы."
|
||||||
|
|
||||||
article:
|
article:
|
||||||
|
@ -653,7 +653,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
|
||||||
introduction_desc_ending: "Мы надеемся, что вы присоединитесь к нашей команде!"
|
introduction_desc_ending: "Мы надеемся, что вы присоединитесь к нашей команде!"
|
||||||
introduction_desc_signature: "- Ник, Джордж, Скотт, Михаэль, Джереми и Глен"
|
introduction_desc_signature: "- Ник, Джордж, Скотт, Михаэль, Джереми и Глен"
|
||||||
alert_account_message_intro: "Привет!"
|
alert_account_message_intro: "Привет!"
|
||||||
# alert_account_message: "To subscribe for class emails, you'll need to be logged in first."
|
alert_account_message: "Чтобы подписаться на классовые сообщения, необходимо войти в аккаунт"
|
||||||
archmage_summary: "Интересует работа над игровой графикой, дизайном пользовательского интерфейса, базой данных и организацией сервера, сетевым мультиплеером, физикой, звуком или производительностью игрового движка? Хотите помочь создать игру для помощи другим людям в изучении того, в чём вы хорошо разбираетесь? У нас много работы, и если вы опытный программист и хотите разрабатывать для CodeCombat, этот класс для вас. Мы будем рады вашей помощи в создании самой лучшей игры для программистов."
|
archmage_summary: "Интересует работа над игровой графикой, дизайном пользовательского интерфейса, базой данных и организацией сервера, сетевым мультиплеером, физикой, звуком или производительностью игрового движка? Хотите помочь создать игру для помощи другим людям в изучении того, в чём вы хорошо разбираетесь? У нас много работы, и если вы опытный программист и хотите разрабатывать для CodeCombat, этот класс для вас. Мы будем рады вашей помощи в создании самой лучшей игры для программистов."
|
||||||
archmage_introduction: "Одна из лучших черт в создании игр - то, что они синтезируют так много различных вещей. Графика, звук, сетевое взаимодействие в режиме реального времени, социальное сетевое взаимодействие, и, конечно, большинство из более распространённых аспектов программирования, от низкоуровневого управления базами данных и администрирования сервера до построения дизайна и интерфейсов, видимых пользователю. У нас много работы, и если вы опытный программист со страстным желанием погрузиться в действительно мельчайшие детали CodeCombat, этот класс для вас. Мы будем рады вашей помощи в создании самой лучшей игры для программистов."
|
archmage_introduction: "Одна из лучших черт в создании игр - то, что они синтезируют так много различных вещей. Графика, звук, сетевое взаимодействие в режиме реального времени, социальное сетевое взаимодействие, и, конечно, большинство из более распространённых аспектов программирования, от низкоуровневого управления базами данных и администрирования сервера до построения дизайна и интерфейсов, видимых пользователю. У нас много работы, и если вы опытный программист со страстным желанием погрузиться в действительно мельчайшие детали CodeCombat, этот класс для вас. Мы будем рады вашей помощи в создании самой лучшей игры для программистов."
|
||||||
class_attributes: "Атрибуты класса"
|
class_attributes: "Атрибуты класса"
|
||||||
|
|
6
app/models/UserRemark.coffee
Normal file
6
app/models/UserRemark.coffee
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
CocoModel = require('./CocoModel')
|
||||||
|
|
||||||
|
module.exports = class UserRemark extends CocoModel
|
||||||
|
@className: "UserRemark"
|
||||||
|
@schema: require 'schemas/models/user_remark'
|
||||||
|
urlRoot: "/db/user.remark"
|
|
@ -7,8 +7,8 @@ module.exports =
|
||||||
type: "object"
|
type: "object"
|
||||||
properties: # TODO
|
properties: # TODO
|
||||||
joined:
|
joined:
|
||||||
type: "boolean"
|
type: ["boolean", "null"]
|
||||||
players:
|
players:
|
||||||
type: "object"
|
type: "object"
|
||||||
required: ["joined", "players"]
|
required: ["joined", "players"]
|
||||||
additionalProperties: false
|
additionalProperties: true
|
||||||
|
|
24
app/schemas/models/user_remark.coffee
Normal file
24
app/schemas/models/user_remark.coffee
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
c = require './../schemas'
|
||||||
|
|
||||||
|
UserRemarkSchema = c.object {
|
||||||
|
title: "Remark"
|
||||||
|
description: "Remarks on a user, point of contact, tasks."
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend UserRemarkSchema.properties,
|
||||||
|
user: c.objectId links: [{rel: 'extra', href: "/db/user/{($)}"}]
|
||||||
|
contact: c.objectId links: [{rel: 'extra', href: "/db/user/{($)}"}]
|
||||||
|
created: c.date title: 'Created', readOnly: true
|
||||||
|
history: c.array {title: 'History', description: 'Records of our interactions with the user.'},
|
||||||
|
c.object {title: 'Record'}, {date: c.date(title: 'Date'), content: {title: 'Content', type: 'string', format: 'markdown'}}
|
||||||
|
tasks: c.array {title: 'Tasks', description: 'Task entries: when to email the contact about something.'},
|
||||||
|
c.object {title: 'Task'}, {date: c.date(title: 'Date'), action: {title: 'Action', type: 'string'}}
|
||||||
|
|
||||||
|
# denormalization
|
||||||
|
userName: { title: "Player Name", type: 'string' }
|
||||||
|
contactName: { title: "Contact Name", type: 'string' } # Not actually our usernames
|
||||||
|
|
||||||
|
|
||||||
|
c.extendBasicProperties UserRemarkSchema, 'user.remark'
|
||||||
|
|
||||||
|
module.exports = UserRemarkSchema
|
|
@ -33,7 +33,7 @@ module.exports =
|
||||||
type: "object"
|
type: "object"
|
||||||
properties:
|
properties:
|
||||||
message:
|
message:
|
||||||
type: "string"
|
type: "object"
|
||||||
bus:
|
bus:
|
||||||
$ref: "bus"
|
$ref: "bus"
|
||||||
|
|
||||||
|
|
|
@ -193,6 +193,11 @@
|
||||||
width: 100%
|
width: 100%
|
||||||
height: 100px
|
height: 100px
|
||||||
|
|
||||||
|
#remark-treema
|
||||||
|
background-color: white
|
||||||
|
border: 0
|
||||||
|
padding-top: 0
|
||||||
|
|
||||||
.right-column
|
.right-column
|
||||||
width: $side-width
|
width: $side-width
|
||||||
background-color: $sideBackground
|
background-color: $sideBackground
|
||||||
|
|
14
app/styles/demo.sass
Normal file
14
app/styles/demo.sass
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#demo-view
|
||||||
|
margin: 0 20px
|
||||||
|
|
||||||
|
h2
|
||||||
|
background: #add8e6
|
||||||
|
font-family: Arial, Geneva, sans-serif
|
||||||
|
padding: 20px
|
||||||
|
font-weight: bold
|
||||||
|
|
||||||
|
#demo-wrapper
|
||||||
|
width: 78%
|
||||||
|
|
||||||
|
#demo-nav
|
||||||
|
width: 20%
|
|
@ -43,7 +43,9 @@ block content
|
||||||
i.icon-eye-close
|
i.icon-eye-close
|
||||||
span(data-i18n='account_profile.not_featured') Not Featured
|
span(data-i18n='account_profile.not_featured') Not Featured
|
||||||
if me.isAdmin() && !myProfile
|
if me.isAdmin() && !myProfile
|
||||||
button.btn.edit-settings-button#enter-espionage-mode 007
|
button.btn#enter-espionage-mode 007
|
||||||
|
if me.isAdmin()
|
||||||
|
button.btn#open-model-modal Raw
|
||||||
|
|
||||||
if profile && allowedToViewJobProfile
|
if profile && allowedToViewJobProfile
|
||||||
div(class="job-profile-container" + (editing ? " editable-profile" : ""))
|
div(class="job-profile-container" + (editing ? " editable-profile" : ""))
|
||||||
|
@ -169,6 +171,10 @@ block content
|
||||||
button#contact-candidate.btn.btn-large.btn-inverse.flat-button
|
button#contact-candidate.btn.btn-large.btn-inverse.flat-button
|
||||||
span(data-i18n="account_profile.contact") Contact
|
span(data-i18n="account_profile.contact") Contact
|
||||||
| #{profile.name.split(' ')[0]}
|
| #{profile.name.split(' ')[0]}
|
||||||
|
if me.isAdmin()
|
||||||
|
select#admin-contact.form-control
|
||||||
|
for contact in adminContacts
|
||||||
|
option(value=contact.id, selected=remark && remark.get('contact') == contact.id)= contact.name
|
||||||
|
|
||||||
if !editing && sessions.length
|
if !editing && sessions.length
|
||||||
h3(data-i18n="account_profile.player_code") Player Code
|
h3(data-i18n="account_profile.player_code") Player Code
|
||||||
|
@ -191,9 +197,12 @@ block content
|
||||||
if editing && !profile.name
|
if editing && !profile.name
|
||||||
h3.edit-label(data-i18n="account_profile.name_header") Fill in your name
|
h3.edit-label(data-i18n="account_profile.name_header") Fill in your name
|
||||||
else if profile.name
|
else if profile.name
|
||||||
h3= profile.name
|
h3= profile.name + (me.isAdmin() ? ' (' + user.get('name') + ')' : '')
|
||||||
else
|
else
|
||||||
h3(data-i18n="account_profile.name_anonymous") Anonymous Developer
|
h3
|
||||||
|
span(data-i18n="account_profile.name_anonymous") Anonymous Developer
|
||||||
|
if me.isAdmin()
|
||||||
|
span (#{user.get('name')})
|
||||||
|
|
||||||
form.editable-form
|
form.editable-form
|
||||||
.editable-icon.glyphicon.glyphicon-remove
|
.editable-icon.glyphicon.glyphicon-remove
|
||||||
|
@ -396,6 +405,10 @@ block content
|
||||||
else
|
else
|
||||||
div!= marked(notes)
|
div!= marked(notes)
|
||||||
|
|
||||||
|
if me.isAdmin()
|
||||||
|
h3(data-i18n="account_profile.remarks") Remarks
|
||||||
|
#remark-treema
|
||||||
|
|
||||||
.right-column.full-height-column
|
.right-column.full-height-column
|
||||||
.sub-column
|
.sub-column
|
||||||
#projects-container.editable-section
|
#projects-container.editable-section
|
||||||
|
|
22
app/templates/demo.jade
Normal file
22
app/templates/demo.jade
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
h2 Demo Page
|
||||||
|
|
||||||
|
ol.breadcrumb
|
||||||
|
for path in parentFolders
|
||||||
|
li
|
||||||
|
a(href=path.url)= path.name
|
||||||
|
li.active= currentFolder
|
||||||
|
|
||||||
|
.well.pull-left#demo-wrapper
|
||||||
|
#demo-area
|
||||||
|
|
||||||
|
.nav.nav-pills.nav-stacked.pull-right.well#demo-nav
|
||||||
|
for child in children
|
||||||
|
li(class=child.type)
|
||||||
|
a(href=child.url).small
|
||||||
|
if child.type == 'folder'
|
||||||
|
span.glyphicon.glyphicon-folder-close
|
||||||
|
else
|
||||||
|
span.glyphicon.glyphicon-file
|
||||||
|
span.spl= child.name
|
||||||
|
if child.type == 'folder'
|
||||||
|
strong (#{child.size})
|
|
@ -84,6 +84,8 @@ block content
|
||||||
th(data-i18n="employers.candidate_top_skills") Top Skills
|
th(data-i18n="employers.candidate_top_skills") Top Skills
|
||||||
th(data-i18n="employers.candidate_years_experience") Yrs Exp
|
th(data-i18n="employers.candidate_years_experience") Yrs Exp
|
||||||
th(data-i18n="employers.candidate_last_updated") Last Updated
|
th(data-i18n="employers.candidate_last_updated") Last Updated
|
||||||
|
if me.isAdmin()
|
||||||
|
th(data-i18n="employers.candidate_who") Who
|
||||||
if me.isAdmin() && area.id == 'inactive-candidates'
|
if me.isAdmin() && area.id == 'inactive-candidates'
|
||||||
th ✓?
|
th ✓?
|
||||||
|
|
||||||
|
@ -95,7 +97,10 @@ block content
|
||||||
td
|
td
|
||||||
if authorized
|
if authorized
|
||||||
img(src=candidate.getPhotoURL(50), alt=profile.name, title=profile.name, height=50)
|
img(src=candidate.getPhotoURL(50), alt=profile.name, title=profile.name, height=50)
|
||||||
|
if profile.name
|
||||||
p= profile.name
|
p= profile.name
|
||||||
|
else if me.isAdmin()
|
||||||
|
p (#{candidate.get('name')})
|
||||||
else
|
else
|
||||||
img(src="/images/pages/contribute/archmage.png", alt="", title="Sign up as an employer to see our candidates", width=50)
|
img(src="/images/pages/contribute/archmage.png", alt="", title="Sign up as an employer to see our candidates", width=50)
|
||||||
p Developer ##{index + 1 + (area.id == 'featured-candidates' ? 0 : featuredCandidates.length)}
|
p Developer ##{index + 1 + (area.id == 'featured-candidates' ? 0 : featuredCandidates.length)}
|
||||||
|
@ -111,6 +116,8 @@ block content
|
||||||
span
|
span
|
||||||
td= profile.experience
|
td= profile.experience
|
||||||
td(data-profile-age=(new Date() - new Date(profile.updated)) / 86400 / 1000)= moment(profile.updated).fromNow()
|
td(data-profile-age=(new Date() - new Date(profile.updated)) / 86400 / 1000)= moment(profile.updated).fromNow()
|
||||||
|
if me.isAdmin()
|
||||||
|
td= remarks[candidate.id] ? remarks[candidate.id].get('contactName') : ''
|
||||||
if me.isAdmin() && area.id == 'inactive-candidates'
|
if me.isAdmin() && area.id == 'inactive-candidates'
|
||||||
if candidate.get('jobProfileApproved')
|
if candidate.get('jobProfileApproved')
|
||||||
td ✓
|
td ✓
|
||||||
|
|
|
@ -4,6 +4,8 @@ block modal-header
|
||||||
|
|
||||||
block modal-body-content
|
block modal-body-content
|
||||||
for model in models
|
for model in models
|
||||||
|
.model-container(data-model-id=model.id)
|
||||||
h3= model.type() + ': ' + model.id
|
h3= model.type() + ': ' + model.id
|
||||||
.model-treema(data-model-id=model.id)
|
.model-treema(data-model-id=model.id)
|
||||||
|
btn.btn.btn-success.save-model(data-i18n="common.save") Save
|
||||||
hr
|
hr
|
||||||
|
|
|
@ -6,6 +6,8 @@ locale = require 'locale/locale'
|
||||||
class DateTimeTreema extends TreemaNode.nodeMap.string
|
class DateTimeTreema extends TreemaNode.nodeMap.string
|
||||||
valueClass: 'treema-date-time'
|
valueClass: 'treema-date-time'
|
||||||
buildValueForDisplay: (el) -> el.text(moment(@data).format('llll'))
|
buildValueForDisplay: (el) -> el.text(moment(@data).format('llll'))
|
||||||
|
buildValueForEditing: (valEl) ->
|
||||||
|
@buildValueForEditingSimply valEl, null, 'date'
|
||||||
|
|
||||||
class VersionTreema extends TreemaNode
|
class VersionTreema extends TreemaNode
|
||||||
valueClass: 'treema-version'
|
valueClass: 'treema-version'
|
||||||
|
|
88
app/views/DemoView.coffee
Normal file
88
app/views/DemoView.coffee
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
CocoView = require 'views/kinds/CocoView'
|
||||||
|
template = require 'templates/demo'
|
||||||
|
requireUtils = require 'lib/requireUtils'
|
||||||
|
|
||||||
|
DEMO_REQUIRE_PREFIX = 'test/demo/'
|
||||||
|
DEMO_URL_PREFIX = '/demo/'
|
||||||
|
|
||||||
|
###
|
||||||
|
What are demo files?
|
||||||
|
|
||||||
|
They could be a function which returns an element to insert into the demo page.
|
||||||
|
But what about demoing achievements? They'll get put into the main html. Or modals.
|
||||||
|
Well, I was thinking that a single folder would show all demos at the same time, line them up.
|
||||||
|
But it'd be confusing to have a whole bunch of achievement demos show up all at the same time?
|
||||||
|
Maybe there could be a button to show all the demos. Hmm, that'd be cool.
|
||||||
|
It could work like Jasmine, where it modifies the path and so when you select to run them, they all run with page reloads.
|
||||||
|
I think for now, I'll just say: have it be a function which we can run anytime.
|
||||||
|
It may or may not return an element to be inserted into the main area.
|
||||||
|
|
||||||
|
Another idea. Do we want root views to just take over the full view?
|
||||||
|
Or should they just go into the central part?
|
||||||
|
Probably should take over the full view, and if you want to get out of the demo, you navigate back.
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
module.exports = DemoView = class DemoView extends CocoView
|
||||||
|
id: "demo-view"
|
||||||
|
template: template
|
||||||
|
|
||||||
|
# INITIALIZE
|
||||||
|
|
||||||
|
constructor: (options, @subPath='') ->
|
||||||
|
super(options)
|
||||||
|
@subPath = @subPath[1..] if @subPath[0] is '/'
|
||||||
|
@loadDemoingLibs() unless DemoView.loaded
|
||||||
|
|
||||||
|
loadDemoingLibs: ->
|
||||||
|
@queue = new createjs.LoadQueue()
|
||||||
|
@queue.on('complete', @scriptsLoaded, @)
|
||||||
|
window.jasmine = {} # so that mock-ajax properly loads. It expects jasmine to be loaded
|
||||||
|
for f in ['mock-ajax', 'demo-app']
|
||||||
|
@queue.loadFile({
|
||||||
|
src: "/javascripts/#{f}.js"
|
||||||
|
type: createjs.LoadQueue.JAVASCRIPT
|
||||||
|
})
|
||||||
|
|
||||||
|
scriptsLoaded: ->
|
||||||
|
@initDemoFiles()
|
||||||
|
@children = requireUtils.parseImmediateChildren(@demoFiles, @subPath, DEMO_REQUIRE_PREFIX, DEMO_URL_PREFIX)
|
||||||
|
@render()
|
||||||
|
@runDemo()
|
||||||
|
|
||||||
|
# RENDER DATA
|
||||||
|
|
||||||
|
getRenderData: ->
|
||||||
|
c = super(arguments...)
|
||||||
|
c.parentFolders = requireUtils.getParentFolders(@subPath, DEMO_URL_PREFIX)
|
||||||
|
c.children = @children or []
|
||||||
|
parts = @subPath.split('/')
|
||||||
|
c.currentFolder = parts[parts.length-1] or parts[parts.length-2] or 'All'
|
||||||
|
c
|
||||||
|
|
||||||
|
# RUNNING DEMOS
|
||||||
|
|
||||||
|
initDemoFiles: ->
|
||||||
|
@demoFiles = @getAllDemoFiles()
|
||||||
|
if @subPath
|
||||||
|
prefix = DEMO_REQUIRE_PREFIX + @subPath
|
||||||
|
@demoFiles = (f for f in @demoFiles when f.startsWith prefix)
|
||||||
|
|
||||||
|
runDemo: ->
|
||||||
|
# TODO: Maybe have an option to run all demos in this folder at the same time?
|
||||||
|
return unless @subPath and _.last(@subPath.split('/')).indexOf('.demo') > -1
|
||||||
|
requirePath = DEMO_REQUIRE_PREFIX + @subPath
|
||||||
|
demoFunc = require requirePath
|
||||||
|
if not _.isFunction(demoFunc)
|
||||||
|
console.error "Demo files must export a function. #{requirePath} does not."
|
||||||
|
return
|
||||||
|
|
||||||
|
jasmine.Ajax.install()
|
||||||
|
view = demoFunc()
|
||||||
|
return unless view
|
||||||
|
@$el.find('#demo-area').empty().append(view.$el)
|
||||||
|
# TODO, maybe handle root views differently than modal views differently than everything else?
|
||||||
|
|
||||||
|
getAllDemoFiles: ->
|
||||||
|
allFiles = window.require.list()
|
||||||
|
(f for f in allFiles when f.indexOf('.demo') > -1)
|
|
@ -1,7 +1,9 @@
|
||||||
CocoView = require 'views/kinds/CocoView'
|
CocoView = require 'views/kinds/CocoView'
|
||||||
template = require 'templates/test'
|
template = require 'templates/test'
|
||||||
|
requireUtils = require 'lib/requireUtils'
|
||||||
|
|
||||||
TEST_BASE_PATH = 'test/app/'
|
TEST_REQUIRE_PREFIX = 'test/app/'
|
||||||
|
TEST_URL_PREFIX = '/test/'
|
||||||
|
|
||||||
module.exports = TestView = class TestView extends CocoView
|
module.exports = TestView = class TestView extends CocoView
|
||||||
id: "test-view"
|
id: "test-view"
|
||||||
|
@ -13,7 +15,7 @@ module.exports = TestView = class TestView extends CocoView
|
||||||
constructor: (options, @subPath='') ->
|
constructor: (options, @subPath='') ->
|
||||||
super(options)
|
super(options)
|
||||||
@subPath = @subPath[1..] if @subPath[0] is '/'
|
@subPath = @subPath[1..] if @subPath[0] is '/'
|
||||||
@loadTestingLibs() unless TestView.loaded
|
@loadTestingLibs()
|
||||||
|
|
||||||
loadTestingLibs: ->
|
loadTestingLibs: ->
|
||||||
@queue = new createjs.LoadQueue()
|
@queue = new createjs.LoadQueue()
|
||||||
|
@ -28,72 +30,24 @@ module.exports = TestView = class TestView extends CocoView
|
||||||
@initSpecFiles()
|
@initSpecFiles()
|
||||||
@render()
|
@render()
|
||||||
TestView.runTests(@specFiles)
|
TestView.runTests(@specFiles)
|
||||||
|
window.runJasmine()
|
||||||
|
|
||||||
# RENDER DATA
|
# RENDER DATA
|
||||||
|
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
c = super(arguments...)
|
c = super(arguments...)
|
||||||
c.parentFolders = @getParentFolders()
|
c.parentFolders = requireUtils.getParentFolders(@subPath, TEST_URL_PREFIX)
|
||||||
c.children = @getChildren()
|
c.children = requireUtils.parseImmediateChildren(@specFiles, @subPath, TEST_REQUIRE_PREFIX, TEST_URL_PREFIX)
|
||||||
parts = @subPath.split('/')
|
parts = @subPath.split('/')
|
||||||
c.currentFolder = parts[parts.length-1] or parts[parts.length-2] or 'All'
|
c.currentFolder = parts[parts.length-1] or parts[parts.length-2] or 'All'
|
||||||
c
|
c
|
||||||
|
|
||||||
getParentFolders: ->
|
|
||||||
return [] unless @subPath
|
|
||||||
paths = []
|
|
||||||
parts = @subPath.split('/')
|
|
||||||
while parts.length
|
|
||||||
parts.pop()
|
|
||||||
paths.unshift {
|
|
||||||
name: parts[parts.length-1] or 'All'
|
|
||||||
url: '/test/' + parts.join('/')
|
|
||||||
}
|
|
||||||
paths
|
|
||||||
|
|
||||||
getChildren: ->
|
|
||||||
return [] unless @specFiles
|
|
||||||
folders = {}
|
|
||||||
files = {}
|
|
||||||
|
|
||||||
requirePrefix = TEST_BASE_PATH + @subPath
|
|
||||||
if requirePrefix[requirePrefix.length-1] isnt '/'
|
|
||||||
requirePrefix += '/'
|
|
||||||
|
|
||||||
for f in @specFiles
|
|
||||||
f = f[requirePrefix.length..]
|
|
||||||
continue unless f
|
|
||||||
parts = f.split('/')
|
|
||||||
name = parts[0]
|
|
||||||
group = if parts.length is 1 then files else folders
|
|
||||||
group[name] ?= 0
|
|
||||||
group[name] += 1
|
|
||||||
|
|
||||||
children = []
|
|
||||||
urlPrefix = '/test/'+@subPath
|
|
||||||
urlPrefix += '/' if urlPrefix[urlPrefix.length-1] isnt '/'
|
|
||||||
|
|
||||||
for name in _.keys(folders)
|
|
||||||
children.push {
|
|
||||||
type:'folder',
|
|
||||||
url: urlPrefix+name
|
|
||||||
name: name+'/'
|
|
||||||
size: folders[name]
|
|
||||||
}
|
|
||||||
for name in _.keys(files)
|
|
||||||
children.push {
|
|
||||||
type:'file',
|
|
||||||
url: urlPrefix+name
|
|
||||||
name: name
|
|
||||||
}
|
|
||||||
children
|
|
||||||
|
|
||||||
# RUNNING TESTS
|
# RUNNING TESTS
|
||||||
|
|
||||||
initSpecFiles: ->
|
initSpecFiles: ->
|
||||||
@specFiles = TestView.getAllSpecFiles()
|
@specFiles = TestView.getAllSpecFiles()
|
||||||
if @subPath
|
if @subPath
|
||||||
prefix = TEST_BASE_PATH + @subPath
|
prefix = TEST_REQUIRE_PREFIX + @subPath
|
||||||
@specFiles = (f for f in @specFiles when f.startsWith prefix)
|
@specFiles = (f for f in @specFiles when f.startsWith prefix)
|
||||||
|
|
||||||
@runTests: (specFiles) ->
|
@runTests: (specFiles) ->
|
|
@ -19,10 +19,10 @@ module.exports = class JobProfileView extends CocoView
|
||||||
|
|
||||||
buildJobProfileTreema: ->
|
buildJobProfileTreema: ->
|
||||||
visibleSettings = @editableSettings.concat @readOnlySettings
|
visibleSettings = @editableSettings.concat @readOnlySettings
|
||||||
data = _.pick (me.get('jobProfile') ? {}), (value, key) => key in visibleSettings
|
data = _.pick (me.get('jobProfile') ? {}), (value, key) -> key in visibleSettings
|
||||||
data.name ?= (me.get('firstName') + ' ' + me.get('lastName')).trim() if me.get('firstName')
|
data.name ?= (me.get('firstName') + ' ' + me.get('lastName')).trim() if me.get('firstName')
|
||||||
schema = _.cloneDeep me.schema().properties.jobProfile
|
schema = _.cloneDeep me.schema().properties.jobProfile
|
||||||
schema.properties = _.pick schema.properties, (value, key) => key in visibleSettings
|
schema.properties = _.pick schema.properties, (value, key) -> key in visibleSettings
|
||||||
schema.required = _.intersection schema.required, visibleSettings
|
schema.required = _.intersection schema.required, visibleSettings
|
||||||
for prop in @readOnlySettings
|
for prop in @readOnlySettings
|
||||||
schema.properties[prop].readOnly = true
|
schema.properties[prop].readOnly = true
|
||||||
|
|
|
@ -6,7 +6,9 @@ CocoCollection = require 'collections/CocoCollection'
|
||||||
{me} = require 'lib/auth'
|
{me} = require 'lib/auth'
|
||||||
JobProfileContactView = require 'views/modal/job_profile_contact_modal'
|
JobProfileContactView = require 'views/modal/job_profile_contact_modal'
|
||||||
JobProfileView = require 'views/account/job_profile_view'
|
JobProfileView = require 'views/account/job_profile_view'
|
||||||
|
UserRemark = require 'models/UserRemark'
|
||||||
forms = require 'lib/forms'
|
forms = require 'lib/forms'
|
||||||
|
ModelModal = require 'views/modal/model_modal'
|
||||||
|
|
||||||
class LevelSessionsCollection extends CocoCollection
|
class LevelSessionsCollection extends CocoCollection
|
||||||
url: -> "/db/user/#{@userID}/level.sessions/employer"
|
url: -> "/db/user/#{@userID}/level.sessions/employer"
|
||||||
|
@ -14,6 +16,14 @@ class LevelSessionsCollection extends CocoCollection
|
||||||
constructor: (@userID) ->
|
constructor: (@userID) ->
|
||||||
super()
|
super()
|
||||||
|
|
||||||
|
adminContacts = [
|
||||||
|
{id: "", name: "Assign a Contact"}
|
||||||
|
{id: "512ef4805a67a8c507000001", name: "Nick"}
|
||||||
|
{id: "5162fab9c92b4c751e000274", name: "Scott"}
|
||||||
|
{id: "51eb2714fa058cb20d0006ef", name: "Michael"}
|
||||||
|
{id: "51538fdb812dd9af02000001", name: "George"}
|
||||||
|
]
|
||||||
|
|
||||||
module.exports = class ProfileView extends View
|
module.exports = class ProfileView extends View
|
||||||
id: "profile-view"
|
id: "profile-view"
|
||||||
template: template
|
template: template
|
||||||
|
@ -28,6 +38,7 @@ module.exports = class ProfileView extends View
|
||||||
'click #save-notes-button': 'onJobProfileNotesChanged'
|
'click #save-notes-button': 'onJobProfileNotesChanged'
|
||||||
'click #contact-candidate': 'onContactCandidate'
|
'click #contact-candidate': 'onContactCandidate'
|
||||||
'click #enter-espionage-mode': 'enterEspionageMode'
|
'click #enter-espionage-mode': 'enterEspionageMode'
|
||||||
|
'click #open-model-modal': 'openModelModal'
|
||||||
'click .editable-profile .profile-photo': 'onEditProfilePhoto'
|
'click .editable-profile .profile-photo': 'onEditProfilePhoto'
|
||||||
'click .editable-profile .project-image': 'onEditProjectImage'
|
'click .editable-profile .project-image': 'onEditProjectImage'
|
||||||
'click .editable-profile .editable-display': 'onEditSection'
|
'click .editable-profile .editable-display': 'onEditSection'
|
||||||
|
@ -36,12 +47,14 @@ module.exports = class ProfileView extends View
|
||||||
'change .editable-profile .editable-array input': 'onEditArray'
|
'change .editable-profile .editable-array input': 'onEditArray'
|
||||||
'keyup .editable-profile .editable-array input': 'onEditArray'
|
'keyup .editable-profile .editable-array input': 'onEditArray'
|
||||||
'click .editable-profile a': 'onClickLinkWhileEditing'
|
'click .editable-profile a': 'onClickLinkWhileEditing'
|
||||||
|
'change #admin-contact': 'onAdminContactChanged'
|
||||||
|
|
||||||
constructor: (options, @userID) ->
|
constructor: (options, @userID) ->
|
||||||
@userID ?= me.id
|
@userID ?= me.id
|
||||||
@onJobProfileNotesChanged = _.debounce @onJobProfileNotesChanged, 1000
|
@onJobProfileNotesChanged = _.debounce @onJobProfileNotesChanged, 1000
|
||||||
|
@onRemarkChanged = _.debounce @onRemarkChanged, 1000
|
||||||
@authorizedWithLinkedIn = IN?.User?.isAuthorized()
|
@authorizedWithLinkedIn = IN?.User?.isAuthorized()
|
||||||
@linkedInLoaded = Boolean(IN.parse)
|
@linkedInLoaded = Boolean(IN?.parse)
|
||||||
@waitingForLinkedIn = false
|
@waitingForLinkedIn = false
|
||||||
window.contractCallback = =>
|
window.contractCallback = =>
|
||||||
@authorizedWithLinkedIn = IN?.User?.isAuthorized()
|
@authorizedWithLinkedIn = IN?.User?.isAuthorized()
|
||||||
|
@ -70,6 +83,22 @@ module.exports = class ProfileView extends View
|
||||||
else
|
else
|
||||||
@user = User.getByID(@userID)
|
@user = User.getByID(@userID)
|
||||||
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(@userID), 'candidate_sessions').model
|
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(@userID), 'candidate_sessions').model
|
||||||
|
if me.isAdmin()
|
||||||
|
# Mimicking how the VictoryModal fetches LevelFeedback
|
||||||
|
@remark = new UserRemark()
|
||||||
|
@remark.setURL "/db/user/#{@userID}/remark"
|
||||||
|
@remark.fetch()
|
||||||
|
@listenToOnce @remark, 'sync', @onRemarkLoaded
|
||||||
|
@listenToOnce @remark, 'error', @onRemarkNotFound
|
||||||
|
|
||||||
|
onRemarkLoaded: ->
|
||||||
|
@remark.setURL "/db/user.remark/#{@remark.id}"
|
||||||
|
@render()
|
||||||
|
|
||||||
|
onRemarkNotFound: ->
|
||||||
|
@remark = new UserRemark() # hmm, why do we create a new one here?
|
||||||
|
@remark.set 'user', @userID
|
||||||
|
@remark.set 'userName', name if name = @user.get('name')
|
||||||
|
|
||||||
onLinkedInLoaded: =>
|
onLinkedInLoaded: =>
|
||||||
@linkedinLoaded = true
|
@linkedinLoaded = true
|
||||||
|
@ -229,6 +258,8 @@ module.exports = class ProfileView extends View
|
||||||
context.sessions.sort (a, b) -> (b.playtime ? 0) - (a.playtime ? 0)
|
context.sessions.sort (a, b) -> (b.playtime ? 0) - (a.playtime ? 0)
|
||||||
else
|
else
|
||||||
context.sessions = []
|
context.sessions = []
|
||||||
|
context.adminContacts = adminContacts
|
||||||
|
context.remark = @remark
|
||||||
context
|
context
|
||||||
|
|
||||||
afterRender: ->
|
afterRender: ->
|
||||||
|
@ -249,6 +280,31 @@ module.exports = class ProfileView extends View
|
||||||
_.delay ->
|
_.delay ->
|
||||||
justSavedSection.removeClass "just-saved", duration: 1500, easing: 'easeOutQuad'
|
justSavedSection.removeClass "just-saved", duration: 1500, easing: 'easeOutQuad'
|
||||||
, 500
|
, 500
|
||||||
|
if me.isAdmin()
|
||||||
|
visibleSettings = ['history', 'tasks']
|
||||||
|
data = _.pick (@remark.attributes), (value, key) -> key in visibleSettings
|
||||||
|
data.history ?= []
|
||||||
|
data.tasks ?= []
|
||||||
|
schema = _.cloneDeep @remark.schema()
|
||||||
|
schema.properties = _.pick schema.properties, (value, key) => key in visibleSettings
|
||||||
|
schema.required = _.intersection (schema.required ? []), visibleSettings
|
||||||
|
treemaOptions =
|
||||||
|
filePath: "db/user/#{@userID}"
|
||||||
|
schema: schema
|
||||||
|
data: data
|
||||||
|
aceUseWrapMode: true
|
||||||
|
callbacks: {change: @onRemarkChanged}
|
||||||
|
@remarkTreema = @$el.find('#remark-treema').treema treemaOptions
|
||||||
|
@remarkTreema.build()
|
||||||
|
@remarkTreema.open(3)
|
||||||
|
|
||||||
|
onRemarkChanged: (e) =>
|
||||||
|
return unless @remarkTreema.isValid()
|
||||||
|
for key in ['history', 'tasks']
|
||||||
|
val = _.filter(@remarkTreema.get(key), (entry) -> entry?.content or entry?.action)
|
||||||
|
entry.date ?= (new Date()).toISOString() for entry in val if key is 'history'
|
||||||
|
@remark.set key, val
|
||||||
|
@saveRemark()
|
||||||
|
|
||||||
initializeAutocomplete: (container) ->
|
initializeAutocomplete: (container) ->
|
||||||
(container ? @$el).find('input[data-autocomplete]').each ->
|
(container ? @$el).find('input[data-autocomplete]').each ->
|
||||||
|
@ -286,6 +342,9 @@ module.exports = class ProfileView extends View
|
||||||
espionageSuccess: (model) ->
|
espionageSuccess: (model) ->
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
|
|
||||||
|
openModelModal: (e) ->
|
||||||
|
@openModalView new ModelModal models: [@user]
|
||||||
|
|
||||||
onJobProfileNotesChanged: (e) =>
|
onJobProfileNotesChanged: (e) =>
|
||||||
notes = @$el.find("#job-profile-notes").val()
|
notes = @$el.find("#job-profile-notes").val()
|
||||||
@user.set 'jobProfileNotes', notes
|
@user.set 'jobProfileNotes', notes
|
||||||
|
@ -455,6 +514,26 @@ module.exports = class ProfileView extends View
|
||||||
onClickLinkWhileEditing: (e) ->
|
onClickLinkWhileEditing: (e) ->
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
|
onAdminContactChanged: (e) ->
|
||||||
|
newContact = @$el.find('#admin-contact').val()
|
||||||
|
newContactName = if newContact then _.find(adminContacts, id: newContact).name else ''
|
||||||
|
@remark.set 'contact', newContact
|
||||||
|
@remark.set 'contactName', newContactName
|
||||||
|
@saveRemark()
|
||||||
|
|
||||||
|
saveRemark: ->
|
||||||
|
@remark.set 'user', @user.id
|
||||||
|
@remark.set 'userName', @user.get('name')
|
||||||
|
if errors = @remark.validate()
|
||||||
|
return console.error "UserRemark", @remark, "failed validation with errors:", errors
|
||||||
|
res = @remark.save()
|
||||||
|
res.error =>
|
||||||
|
return if @destroyed
|
||||||
|
console.error "UserRemark", @remark, "failed to save with error:", res.responseText
|
||||||
|
res.success (model, response, options) =>
|
||||||
|
return if @destroyed
|
||||||
|
console.log "Saved UserRemark", @remark, "with response", response
|
||||||
|
|
||||||
updateProgress: (highlightNext) ->
|
updateProgress: (highlightNext) ->
|
||||||
return unless @user
|
return unless @user
|
||||||
completed = 0
|
completed = 0
|
||||||
|
|
|
@ -25,6 +25,7 @@ module.exports = class LevelComponentEditView extends View
|
||||||
super options
|
super options
|
||||||
@levelComponent = @supermodel.getModelByOriginalAndMajorVersion LevelComponent, options.original, options.majorVersion or 0
|
@levelComponent = @supermodel.getModelByOriginalAndMajorVersion LevelComponent, options.original, options.majorVersion or 0
|
||||||
console.log "Couldn't get levelComponent for", options, "from", @supermodel.models unless @levelComponent
|
console.log "Couldn't get levelComponent for", options, "from", @supermodel.models unless @levelComponent
|
||||||
|
@onEditorChange = _.debounce @onEditorChange, 1500
|
||||||
|
|
||||||
getRenderData: (context={}) ->
|
getRenderData: (context={}) ->
|
||||||
context = super(context)
|
context = super(context)
|
||||||
|
@ -95,6 +96,7 @@ module.exports = class LevelComponentEditView extends View
|
||||||
@editor.on('change', @onEditorChange)
|
@editor.on('change', @onEditorChange)
|
||||||
|
|
||||||
onEditorChange: =>
|
onEditorChange: =>
|
||||||
|
return if @destroyed
|
||||||
@levelComponent.set 'code', @editor.getValue()
|
@levelComponent.set 'code', @editor.getValue()
|
||||||
Backbone.Mediator.publish 'level-component-edited', levelComponent: @levelComponent
|
Backbone.Mediator.publish 'level-component-edited', levelComponent: @levelComponent
|
||||||
null
|
null
|
||||||
|
|
|
@ -2,6 +2,7 @@ View = require 'views/kinds/RootView'
|
||||||
template = require 'templates/employers'
|
template = require 'templates/employers'
|
||||||
app = require 'application'
|
app = require 'application'
|
||||||
User = require 'models/User'
|
User = require 'models/User'
|
||||||
|
UserRemark = require 'models/UserRemark'
|
||||||
{me} = require 'lib/auth'
|
{me} = require 'lib/auth'
|
||||||
CocoCollection = require 'collections/CocoCollection'
|
CocoCollection = require 'collections/CocoCollection'
|
||||||
EmployerSignupView = require 'views/modal/employer_signup_modal'
|
EmployerSignupView = require 'views/modal/employer_signup_modal'
|
||||||
|
@ -10,6 +11,10 @@ class CandidatesCollection extends CocoCollection
|
||||||
url: '/db/user/x/candidates'
|
url: '/db/user/x/candidates'
|
||||||
model: User
|
model: User
|
||||||
|
|
||||||
|
class UserRemarksCollection extends CocoCollection
|
||||||
|
url: '/db/user.remark?project=contact,contactName,user'
|
||||||
|
model: UserRemark
|
||||||
|
|
||||||
module.exports = class EmployersView extends View
|
module.exports = class EmployersView extends View
|
||||||
id: "employers-view"
|
id: "employers-view"
|
||||||
template: template
|
template: template
|
||||||
|
@ -37,6 +42,8 @@ module.exports = class EmployersView extends View
|
||||||
ctx.inactiveCandidates = _.reject ctx.candidates, (c) -> c.get('jobProfile').active
|
ctx.inactiveCandidates = _.reject ctx.candidates, (c) -> c.get('jobProfile').active
|
||||||
ctx.featuredCandidates = _.filter ctx.activeCandidates, (c) -> c.get('jobProfileApproved')
|
ctx.featuredCandidates = _.filter ctx.activeCandidates, (c) -> c.get('jobProfileApproved')
|
||||||
ctx.otherCandidates = _.reject ctx.activeCandidates, (c) -> c.get('jobProfileApproved')
|
ctx.otherCandidates = _.reject ctx.activeCandidates, (c) -> c.get('jobProfileApproved')
|
||||||
|
ctx.remarks = {}
|
||||||
|
ctx.remarks[remark.get('user')] = remark for remark in @remarks.models
|
||||||
ctx.moment = moment
|
ctx.moment = moment
|
||||||
ctx._ = _
|
ctx._ = _
|
||||||
ctx
|
ctx
|
||||||
|
@ -48,11 +55,13 @@ module.exports = class EmployersView extends View
|
||||||
getCandidates: ->
|
getCandidates: ->
|
||||||
@candidates = new CandidatesCollection()
|
@candidates = new CandidatesCollection()
|
||||||
@candidates.fetch()
|
@candidates.fetch()
|
||||||
|
@remarks = new UserRemarksCollection()
|
||||||
|
@remarks.fetch()
|
||||||
# Re-render when we have fetched them, but don't wait and show a progress bar while loading.
|
# Re-render when we have fetched them, but don't wait and show a progress bar while loading.
|
||||||
@listenToOnce @candidates, 'all', @renderCandidatesAndSetupScrolling
|
@listenToOnce @candidates, 'all', @renderCandidatesAndSetupScrolling
|
||||||
|
@listenToOnce @remarks, 'all', @renderCandidatesAndSetupScrolling
|
||||||
|
|
||||||
renderCandidatesAndSetupScrolling: =>
|
renderCandidatesAndSetupScrolling: =>
|
||||||
|
|
||||||
@render()
|
@render()
|
||||||
$(".nano").nanoScroller()
|
$(".nano").nanoScroller()
|
||||||
if window.history?.state?.lastViewedCandidateID
|
if window.history?.state?.lastViewedCandidateID
|
||||||
|
@ -179,7 +188,7 @@ module.exports = class EmployersView extends View
|
||||||
"Last 4 weeks": (e, n, f, i, $r) ->
|
"Last 4 weeks": (e, n, f, i, $r) ->
|
||||||
days = parseFloat $($r.find('td')[i]).data('profile-age')
|
days = parseFloat $($r.find('td')[i]).data('profile-age')
|
||||||
days <= 28
|
days <= 28
|
||||||
7:
|
8:
|
||||||
"✓": filterSelectExactMatch
|
"✓": filterSelectExactMatch
|
||||||
"✗": filterSelectExactMatch
|
"✗": filterSelectExactMatch
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ module.exports = class ModelModal extends View
|
||||||
template: template
|
template: template
|
||||||
plain: true
|
plain: true
|
||||||
|
|
||||||
|
events: 'click .save-model': 'onSaveModel'
|
||||||
|
|
||||||
constructor: (options) ->
|
constructor: (options) ->
|
||||||
super options
|
super options
|
||||||
@models = options.models
|
@models = options.models
|
||||||
|
@ -20,6 +22,7 @@ module.exports = class ModelModal extends View
|
||||||
|
|
||||||
afterRender: ->
|
afterRender: ->
|
||||||
return unless @supermodel.finished()
|
return unless @supermodel.finished()
|
||||||
|
@modelTreemas = {}
|
||||||
for model in @models
|
for model in @models
|
||||||
data = $.extend true, {}, model.attributes
|
data = $.extend true, {}, model.attributes
|
||||||
schema = $.extend true, {}, model.schema()
|
schema = $.extend true, {}, model.schema()
|
||||||
|
@ -31,6 +34,7 @@ module.exports = class ModelModal extends View
|
||||||
modelTreema?.build()
|
modelTreema?.build()
|
||||||
modelTreema?.open()
|
modelTreema?.open()
|
||||||
@openTastyTreemas modelTreema, model
|
@openTastyTreemas modelTreema, model
|
||||||
|
@modelTreemas[model.id] = modelTreema
|
||||||
|
|
||||||
openTastyTreemas: (modelTreema, model) ->
|
openTastyTreemas: (modelTreema, model) ->
|
||||||
# To save on quick inspection, let's auto-open the properties we're most likely to want to see.
|
# To save on quick inspection, let's auto-open the properties we're most likely to want to see.
|
||||||
|
@ -45,3 +49,26 @@ module.exports = class ModelModal extends View
|
||||||
}[team]
|
}[team]
|
||||||
for dessert in desserts
|
for dessert in desserts
|
||||||
child.childrenTreemas[dessert]?.open()
|
child.childrenTreemas[dessert]?.open()
|
||||||
|
|
||||||
|
onSaveModel: (e) ->
|
||||||
|
container = $(e.target).closest('.model-container')
|
||||||
|
model = _.find @models, id: container.data('model-id')
|
||||||
|
treema = @modelTreemas[model.id]
|
||||||
|
changes = {}
|
||||||
|
for key, val of treema.data when not _.isEqual val, model.get key
|
||||||
|
console.log "Updating", key, "from", model.get(key), "to", val
|
||||||
|
model.set key, val
|
||||||
|
changes[key] = val
|
||||||
|
for key, val of model.attributes when treema.get(key) is undefined and not _.string.startsWith key, '_'
|
||||||
|
console.log "Deleting", key, "which was", val, "but man, that ain't going to work, now is it?"
|
||||||
|
#changes[key] = undefined
|
||||||
|
model.unset key
|
||||||
|
if errors = model.validate()
|
||||||
|
return console.warn model, "failed validation with errors:", errors
|
||||||
|
res = model.save changes, {patch: true}
|
||||||
|
res.error =>
|
||||||
|
return if @destroyed
|
||||||
|
console.error model, "failed to save with error:", res.responseText
|
||||||
|
res.success (model, response, options) =>
|
||||||
|
return if @destroyed
|
||||||
|
@hide()
|
||||||
|
|
|
@ -18,19 +18,19 @@ module.exports = class Spell
|
||||||
@supermodel = options.supermodel
|
@supermodel = options.supermodel
|
||||||
@skipProtectAPI = options.skipProtectAPI
|
@skipProtectAPI = options.skipProtectAPI
|
||||||
@worker = options.worker
|
@worker = options.worker
|
||||||
p = options.programmableMethod
|
|
||||||
|
|
||||||
|
p = options.programmableMethod
|
||||||
|
@languages = p.languages ? {}
|
||||||
|
@languages.javascript ?= p.source
|
||||||
@name = p.name
|
@name = p.name
|
||||||
@permissions = read: p.permissions?.read ? [], readwrite: p.permissions?.readwrite ? [] # teams
|
@permissions = read: p.permissions?.read ? [], readwrite: p.permissions?.readwrite ? [] # teams
|
||||||
teamSpells = @session.get('teamSpells')
|
@setLanguage if @canWrite() then options.language else 'javascript'
|
||||||
team = @session.get('team') ? 'humans'
|
@useTranspiledCode = @shouldUseTranspiledCode()
|
||||||
@useTranspiledCode = @permissions.readwrite.length and ((teamSpells and not _.contains(teamSpells[team], @spellKey)) or (@session.get('creator') isnt me.id and not (me.isAdmin() or 'employer' in me.get('permissions'))) or @spectateView)
|
|
||||||
#console.log @spellKey, "using transpiled code?", @useTranspiledCode
|
@source = @originalSource
|
||||||
@source = @originalSource = p.source
|
|
||||||
@parameters = p.parameters
|
@parameters = p.parameters
|
||||||
if @permissions.readwrite.length and sessionSource = @session.getSourceFor(@spellKey)
|
if @permissions.readwrite.length and sessionSource = @session.getSourceFor(@spellKey)
|
||||||
@source = sessionSource
|
@source = sessionSource
|
||||||
@language = if @canWrite() then options.language else 'javascript'
|
|
||||||
@thangs = {}
|
@thangs = {}
|
||||||
@view = new SpellView {spell: @, session: @session, worker: @worker}
|
@view = new SpellView {spell: @, session: @session, worker: @worker}
|
||||||
@view.render() # Get it ready and code loaded in advance
|
@view.render() # Get it ready and code loaded in advance
|
||||||
|
@ -45,6 +45,9 @@ module.exports = class Spell
|
||||||
@thangs = null
|
@thangs = null
|
||||||
@worker = null
|
@worker = null
|
||||||
|
|
||||||
|
setLanguage: (@language) ->
|
||||||
|
@originalSource = @languages[language] ? @languages.javascript
|
||||||
|
|
||||||
addThang: (thang) ->
|
addThang: (thang) ->
|
||||||
if @thangs[thang.id]
|
if @thangs[thang.id]
|
||||||
@thangs[thang.id].thang = thang
|
@thangs[thang.id].thang = thang
|
||||||
|
@ -151,3 +154,14 @@ module.exports = class Spell
|
||||||
|
|
||||||
toString: ->
|
toString: ->
|
||||||
"<Spell: #{@spellKey}>"
|
"<Spell: #{@spellKey}>"
|
||||||
|
|
||||||
|
shouldUseTranspiledCode: ->
|
||||||
|
# Determine whether this code has already been transpiled, or whether it's raw source needing transpilation.
|
||||||
|
return false unless @permissions.readwrite.length # Only player-writable code will be stored transpiled.
|
||||||
|
return true if @spectateView # Use transpiled code for both teams if we're just spectating.
|
||||||
|
teamSpells = @session.get('teamSpells')
|
||||||
|
team = @session.get('team') ? 'humans'
|
||||||
|
return true if teamSpells and not _.contains(teamSpells[team], @spellKey) # Use transpiled for enemy spells.
|
||||||
|
# Players without permissions can't view the raw code.
|
||||||
|
return true if @session.get('creator') isnt me.id and not (me.isAdmin() or 'employer' in me.get('permissions'))
|
||||||
|
false
|
||||||
|
|
|
@ -647,9 +647,12 @@ module.exports = class SpellView extends View
|
||||||
@zatanna.set 'liveCompletion', (aceConfig.liveCompletion ? false)
|
@zatanna.set 'liveCompletion', (aceConfig.liveCompletion ? false)
|
||||||
|
|
||||||
onChangeLanguage: (e) ->
|
onChangeLanguage: (e) ->
|
||||||
if @spell.canWrite()
|
return unless @spell.canWrite()
|
||||||
@aceSession.setMode @editModes[e.language]
|
@aceSession.setMode @editModes[e.language]
|
||||||
@zatanna.set 'language', @editModes[e.language].substr('ace/mode/')
|
@zatanna.set 'language', @editModes[e.language].substr('ace/mode/')
|
||||||
|
wasDefault = @getSource() is @spell.originalSource
|
||||||
|
@spell.setLanguage e.language
|
||||||
|
@reloadCode true if wasDefault
|
||||||
|
|
||||||
dismiss: ->
|
dismiss: ->
|
||||||
@spell.hasChangedSignificantly @getSource(), null, (hasChanged) =>
|
@spell.hasChangedSignificantly @getSource(), null, (hasChanged) =>
|
||||||
|
|
|
@ -35,7 +35,8 @@ exports.config =
|
||||||
(bower_components[\/\\]aether[\/\\]build[\/\\]aether.js)
|
(bower_components[\/\\]aether[\/\\]build[\/\\]aether.js)
|
||||||
)///
|
)///
|
||||||
'javascripts/test-app.js': /^test[\/\\]app/
|
'javascripts/test-app.js': /^test[\/\\]app/
|
||||||
# 'test/javascripts/test-vendor.js': /^test[\/\\](?=vendor)/
|
'javascripts/demo-app.js': /^test[\/\\]demo/
|
||||||
|
|
||||||
order:
|
order:
|
||||||
before: [
|
before: [
|
||||||
'bower_components/jquery/dist/jquery.js'
|
'bower_components/jquery/dist/jquery.js'
|
||||||
|
|
14
multicore.coffee
Normal file
14
multicore.coffee
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
cluster = require 'cluster'
|
||||||
|
numCPUs = require('os').cpus().length
|
||||||
|
|
||||||
|
if cluster.isMaster
|
||||||
|
for i in [0...numCPUs]
|
||||||
|
cluster.fork()
|
||||||
|
cluster.on 'exit', (worker, code, signal) ->
|
||||||
|
console.log 'worker' + worker.process.id + 'died'
|
||||||
|
cluster.fork()
|
||||||
|
else
|
||||||
|
require('coffee-script')
|
||||||
|
require('coffee-script/register')
|
||||||
|
server = require('./server')
|
||||||
|
server.startServer()
|
|
@ -58,7 +58,13 @@ checkDependencies deps[@] basicDependenciesErrorHandling
|
||||||
if command -v node >/dev/null 2>&1; then
|
if command -v node >/dev/null 2>&1; then
|
||||||
checkNodeVersion
|
checkNodeVersion
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
#check if a git repository already exists here
|
||||||
|
if [ -d .git ]; then
|
||||||
|
echo "A git repository already exists here!"
|
||||||
|
else
|
||||||
#install git repository
|
#install git repository
|
||||||
git clone $repositoryUrl coco
|
git clone $repositoryUrl coco
|
||||||
#python ./coco/scripts/devSetup/setup.py
|
#python ./coco/scripts/devSetup/setup.py
|
||||||
echo "Now copy and paste 'sudo python ./coco/scripts/devSetup/setup.py' into the terminal!"
|
echo "Now copy and paste 'sudo python ./coco/scripts/devSetup/setup.py' into the terminal!"
|
||||||
|
fi
|
||||||
|
|
|
@ -33,7 +33,8 @@ class SystemConfiguration(object):
|
||||||
return 64
|
return 64
|
||||||
else:
|
else:
|
||||||
if self.operating_system == u"mac":
|
if self.operating_system == u"mac":
|
||||||
raise NotSupportedError(u"Your processor is determined to have a maxSize of" + sys.maxsize +
|
if os.uname()[4] == u"x86_64":
|
||||||
|
return 64
|
||||||
|
raise NotSupportedError(u"Your processor is determined to have a maxSize of" + str(sys.maxsize) +
|
||||||
u",\n which doesn't correspond with a 64-bit architecture.")
|
u",\n which doesn't correspond with a 64-bit architecture.")
|
||||||
return 32
|
return 32
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,6 @@ module.exports.gatewayTimeoutError = (res, message="Gateway timeout") ->
|
||||||
res.send 504, message
|
res.send 504, message
|
||||||
res.end()
|
res.end()
|
||||||
|
|
||||||
module.exports.clientTimeout = (res, message="The server did not recieve the client response in a timely manner") ->
|
module.exports.clientTimeout = (res, message="The server did not receive the client response in a timely manner") ->
|
||||||
res.send 408, message
|
res.send 408, message
|
||||||
res.end()
|
res.end()
|
||||||
|
|
|
@ -8,6 +8,7 @@ module.exports.handlers =
|
||||||
'patch': 'patches/patch_handler'
|
'patch': 'patches/patch_handler'
|
||||||
'thang_type': 'levels/thangs/thang_type_handler'
|
'thang_type': 'levels/thangs/thang_type_handler'
|
||||||
'user': 'users/user_handler'
|
'user': 'users/user_handler'
|
||||||
|
'user_remark': 'users/remarks/user_remark_handler'
|
||||||
'achievement': 'achievements/achievement_handler'
|
'achievement': 'achievements/achievement_handler'
|
||||||
'earned_achievement': 'achievements/earned_achievement_handler'
|
'earned_achievement': 'achievements/earned_achievement_handler'
|
||||||
|
|
||||||
|
|
11
server/users/remarks/UserRemark.coffee
Normal file
11
server/users/remarks/UserRemark.coffee
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
mongoose = require('mongoose')
|
||||||
|
plugins = require('../../plugins/plugins')
|
||||||
|
jsonschema = require('../../../app/schemas/models/user_remark')
|
||||||
|
|
||||||
|
UserRemarkSchema = new mongoose.Schema({
|
||||||
|
created:
|
||||||
|
type: Date
|
||||||
|
'default': Date.now
|
||||||
|
}, {strict: false})
|
||||||
|
|
||||||
|
module.exports = UserRemark = mongoose.model('user.remark', UserRemarkSchema)
|
12
server/users/remarks/user_remark_handler.coffee
Normal file
12
server/users/remarks/user_remark_handler.coffee
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
UserRemark = require('./UserRemark')
|
||||||
|
Handler = require('../../commons/Handler')
|
||||||
|
|
||||||
|
class UserRemarkHandler extends Handler
|
||||||
|
modelClass: UserRemark
|
||||||
|
editableProperties: ['user', 'contact', 'history', 'tasks', 'userName', 'contactName']
|
||||||
|
jsonSchema: require '../../../app/schemas/models/user_remark'
|
||||||
|
|
||||||
|
hasAccess: (req) ->
|
||||||
|
req.user?.isAdmin()
|
||||||
|
|
||||||
|
module.exports = new UserRemarkHandler()
|
|
@ -11,6 +11,7 @@ log = require 'winston'
|
||||||
LevelSession = require('../levels/sessions/LevelSession')
|
LevelSession = require('../levels/sessions/LevelSession')
|
||||||
LevelSessionHandler = require '../levels/sessions/level_session_handler'
|
LevelSessionHandler = require '../levels/sessions/level_session_handler'
|
||||||
EarnedAchievement = require '../achievements/EarnedAchievement'
|
EarnedAchievement = require '../achievements/EarnedAchievement'
|
||||||
|
UserRemark = require './remarks/UserRemark'
|
||||||
|
|
||||||
serverProperties = ['passwordHash', 'emailLower', 'nameLower', 'passwordReset']
|
serverProperties = ['passwordHash', 'emailLower', 'nameLower', 'passwordReset']
|
||||||
privateProperties = [
|
privateProperties = [
|
||||||
|
@ -23,7 +24,7 @@ candidateProperties = [
|
||||||
|
|
||||||
UserHandler = class UserHandler extends Handler
|
UserHandler = class UserHandler extends Handler
|
||||||
modelClass: User
|
modelClass: User
|
||||||
|
jsonSchema: schema
|
||||||
editableProperties: [
|
editableProperties: [
|
||||||
'name', 'photoURL', 'password', 'anonymous', 'wizardColor1', 'volume',
|
'name', 'photoURL', 'password', 'anonymous', 'wizardColor1', 'volume',
|
||||||
'firstName', 'lastName', 'gender', 'facebookID', 'gplusID', 'emails',
|
'firstName', 'lastName', 'gender', 'facebookID', 'gplusID', 'emails',
|
||||||
|
@ -31,15 +32,11 @@ UserHandler = class UserHandler extends Handler
|
||||||
'wizard', 'aceConfig', 'autocastDelay', 'lastLevel', 'jobProfile'
|
'wizard', 'aceConfig', 'autocastDelay', 'lastLevel', 'jobProfile'
|
||||||
]
|
]
|
||||||
|
|
||||||
jsonSchema: schema
|
|
||||||
|
|
||||||
constructor: ->
|
|
||||||
super(arguments...)
|
|
||||||
@editableProperties.push('permissions') unless config.isProduction
|
|
||||||
|
|
||||||
getEditableProperties: (req, document) ->
|
getEditableProperties: (req, document) ->
|
||||||
props = super req, document
|
props = super req, document
|
||||||
props.push 'jobProfileApproved', 'jobProfileNotes' if req.user.isAdmin()
|
props.push 'permissions' unless config.isProduction
|
||||||
|
props.push 'jobProfileApproved', 'jobProfileNotes' if req.user.isAdmin() # Admins naturally edit these
|
||||||
|
props.push privateProperties... if req.user.isAdmin() # Admins are mad with power
|
||||||
props
|
props
|
||||||
|
|
||||||
formatEntity: (req, document) ->
|
formatEntity: (req, document) ->
|
||||||
|
@ -197,6 +194,7 @@ UserHandler = class UserHandler extends Handler
|
||||||
return @getMySimulatorLeaderboardRank(req, res, args[0]) if args[1] is 'simulator_leaderboard_rank'
|
return @getMySimulatorLeaderboardRank(req, res, args[0]) if args[1] is 'simulator_leaderboard_rank'
|
||||||
return @getEarnedAchievements(req, res, args[0]) if args[1] is 'achievements'
|
return @getEarnedAchievements(req, res, args[0]) if args[1] is 'achievements'
|
||||||
return @trackActivity(req, res, args[0], args[2], args[3]) if args[1] is 'track' and args[2]
|
return @trackActivity(req, res, args[0], args[2], args[3]) if args[1] is 'track' and args[2]
|
||||||
|
return @getRemark(req, res, args[0]) if args[1] is 'remark'
|
||||||
return @sendNotFoundError(res)
|
return @sendNotFoundError(res)
|
||||||
super(arguments...)
|
super(arguments...)
|
||||||
|
|
||||||
|
@ -313,7 +311,7 @@ UserHandler = class UserHandler extends Handler
|
||||||
#query.jobProfileApproved = true unless req.user.isAdmin() # We split into featured and other now.
|
#query.jobProfileApproved = true unless req.user.isAdmin() # We split into featured and other now.
|
||||||
query['jobProfile.active'] = true unless req.user.isAdmin()
|
query['jobProfile.active'] = true unless req.user.isAdmin()
|
||||||
selection = 'jobProfile jobProfileApproved photoURL'
|
selection = 'jobProfile jobProfileApproved photoURL'
|
||||||
selection += ' email' if authorized
|
selection += ' email name' if authorized
|
||||||
User.find(query).select(selection).exec (err, documents) =>
|
User.find(query).select(selection).exec (err, documents) =>
|
||||||
return @sendDatabaseError(res, err) if err
|
return @sendDatabaseError(res, err) if err
|
||||||
candidates = (candidate for candidate in documents when @employerCanViewCandidate req.user, candidate.toObject())
|
candidates = (candidate for candidate in documents when @employerCanViewCandidate req.user, candidate.toObject())
|
||||||
|
@ -321,7 +319,7 @@ UserHandler = class UserHandler extends Handler
|
||||||
@sendSuccess(res, candidates)
|
@sendSuccess(res, candidates)
|
||||||
|
|
||||||
formatCandidate: (authorized, document) ->
|
formatCandidate: (authorized, document) ->
|
||||||
fields = if authorized then ['jobProfile', 'jobProfileApproved', 'photoURL', '_id'] else ['jobProfile', 'jobProfileApproved']
|
fields = if authorized then ['name', 'jobProfile', 'jobProfileApproved', 'photoURL', '_id'] else ['jobProfile', 'jobProfileApproved']
|
||||||
obj = _.pick document.toObject(), fields
|
obj = _.pick document.toObject(), fields
|
||||||
obj.photoURL ||= obj.jobProfile.photoURL if authorized
|
obj.photoURL ||= obj.jobProfile.photoURL if authorized
|
||||||
subfields = ['country', 'city', 'lookingFor', 'jobTitle', 'skills', 'experience', 'updated', 'active']
|
subfields = ['country', 'city', 'lookingFor', 'jobTitle', 'skills', 'experience', 'updated', 'active']
|
||||||
|
@ -342,7 +340,7 @@ UserHandler = class UserHandler extends Handler
|
||||||
|
|
||||||
getEmployers: (req, res) ->
|
getEmployers: (req, res) ->
|
||||||
return @sendUnauthorizedError(res) unless req.user.isAdmin()
|
return @sendUnauthorizedError(res) unless req.user.isAdmin()
|
||||||
query = {employerAt: {$exists: true}}
|
query = {employerAt: {$exists: true, $ne: ''}}
|
||||||
selection = 'name firstName lastName email activity signedEmployerAgreement photoURL employerAt'
|
selection = 'name firstName lastName email activity signedEmployerAgreement photoURL employerAt'
|
||||||
User.find(query).select(selection).lean().exec (err, documents) =>
|
User.find(query).select(selection).lean().exec (err, documents) =>
|
||||||
return @sendDatabaseError res, err if err
|
return @sendDatabaseError res, err if err
|
||||||
|
@ -363,4 +361,17 @@ UserHandler = class UserHandler extends Handler
|
||||||
hash.update(user.get('_id') + '')
|
hash.update(user.get('_id') + '')
|
||||||
hash.digest('hex')
|
hash.digest('hex')
|
||||||
|
|
||||||
|
getRemark: (req, res, userID) ->
|
||||||
|
return @sendUnauthorizedError(res) unless req.user.isAdmin()
|
||||||
|
query = user: userID
|
||||||
|
projection = null
|
||||||
|
if req.query.project
|
||||||
|
projection = {}
|
||||||
|
projection[field] = 1 for field in req.query.project.split(',')
|
||||||
|
UserRemark.findOne(query).select(projection).exec (err, remark) =>
|
||||||
|
return @sendDatabaseError res, err if err
|
||||||
|
return @sendNotFoundError res unless remark?
|
||||||
|
@sendSuccess res, remark
|
||||||
|
|
||||||
|
|
||||||
module.exports = new UserHandler()
|
module.exports = new UserHandler()
|
||||||
|
|
43
test/demo/views/editor/PatchesView.demo.coffee
Normal file
43
test/demo/views/editor/PatchesView.demo.coffee
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
PatchesView = require 'views/editor/patches_view'
|
||||||
|
CocoModel = require 'models/CocoModel'
|
||||||
|
|
||||||
|
class BlandModel extends CocoModel
|
||||||
|
@className: 'Bland'
|
||||||
|
@schema: {
|
||||||
|
type: 'object'
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
number: {type: 'number'}
|
||||||
|
object: {type: 'object'}
|
||||||
|
string: {type: 'string'}
|
||||||
|
_id: {type: 'string'}
|
||||||
|
}
|
||||||
|
urlRoot: '/db/bland'
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = ->
|
||||||
|
model = new BlandModel({_id:'12345', name:'name', original:'original'})
|
||||||
|
v = new PatchesView(model)
|
||||||
|
v.load()
|
||||||
|
|
||||||
|
# Respond to request for pending patches.
|
||||||
|
r = jasmine.Ajax.requests.mostRecent()
|
||||||
|
patches = [
|
||||||
|
{
|
||||||
|
delta: null
|
||||||
|
commitMessage: 'Demo message'
|
||||||
|
creator: '12345'
|
||||||
|
created: "2014-01-01T12:00:00.000Z"
|
||||||
|
status: 'pending'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
r.response({ status:200, responseText: JSON.stringify patches })
|
||||||
|
|
||||||
|
# Respond to request for user ids -> names
|
||||||
|
r = jasmine.Ajax.requests.mostRecent()
|
||||||
|
names = { '12345': { name: 'Patchman' } }
|
||||||
|
r.response({ status:200, responseText: JSON.stringify names })
|
||||||
|
|
||||||
|
v.render()
|
||||||
|
v
|
||||||
|
|
2
vendor/scripts/string_score.js
vendored
2
vendor/scripts/string_score.js
vendored
|
@ -124,7 +124,7 @@
|
||||||
//final_score = (word_score + abbreviation_score) / 2;
|
//final_score = (word_score + abbreviation_score) / 2;
|
||||||
final_score = ((abbreviation_score * (abbreviation_length / string_length)) + abbreviation_score) / 2;
|
final_score = ((abbreviation_score * (abbreviation_length / string_length)) + abbreviation_score) / 2;
|
||||||
|
|
||||||
final_score = final_score / fuzzies;
|
final_score /= fuzzies;
|
||||||
|
|
||||||
if (start_of_string_bonus && (final_score + 0.15 < 1)) {
|
if (start_of_string_bonus && (final_score + 0.15 < 1)) {
|
||||||
final_score += 0.15;
|
final_score += 0.15;
|
||||||
|
|
Loading…
Reference in a new issue