diff --git a/.travis.yml b/.travis.yml index 31cfaec28..705bb9070 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ -nguage: node_js +language: node_js node_js: - 0.10 + before_script: - "npm install" - export DISPLAY=:99.0 @@ -11,3 +12,4 @@ before_script: script: - "./node_modules/.bin/karma start --browsers Firefox --single-run" + diff --git a/README.md b/README.md index 748a90d80..9ed94553b 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ CodeCombat ![](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/readme_00.png) [![Build Status](https://travis-ci.org/codecombat/codecombat.png?branch=master)](https://travis-ci.org/codecombat/codecombat) -CodeCombat is a multiplayer programming game for learning how to code. **See the [Archmage developer wiki](https://github.com/codecombat/codecombat/wiki) for a dev setup guide, extensive documentation, and much more.** +CodeCombat is a multiplayer programming game for learning how to code. **See the [Archmage developer wiki](https://github.com/codecombat/codecombat/wiki/Archmage-Home) for a dev setup guide, extensive documentation, and much more.** It's both a startup and a community project, completely open source under the [MIT and Creative Commons licenses](http://codecombat.com/legal). It's the largest open source [CoffeeScript](http://coffeescript.org/) project by lines of code, and since it's a game (with [really cool tech](https://github.com/codecombat/codecombat/wiki/Third-party-software-and-services)), it's really fun to hack on. Join us in teaching the world to code! Your contribution will go on to show millions of players how cool programming can be. diff --git a/app/assets/javascripts/workers/worker_world.coffee b/app/assets/javascripts/workers/worker_world.coffee new file mode 100644 index 000000000..1503051a7 --- /dev/null +++ b/app/assets/javascripts/workers/worker_world.coffee @@ -0,0 +1,140 @@ + +throw "Attempt to load worker_world into main window instead of web worker." if not self.importScripts or not window? + +self.window = self +self.workerID = "Worker" + +self.logLimit = 200 +self.logsLogged = 0 +console = + log: -> + self.logsLogged += 1 + if self.logsLogged is self.logLimit + self.postMessage + type: 'console-log' + args: ["Log limit " + self.logLimit + " reached; shutting up."] + id: self.workerID + else if self.logsLogged < self.logLimit + args = [].slice.call arguments + for arg in args + if arg and arg.constructor and (arg.constructor.className is "Thang" or arg.isComponent) + arg = arg.toString() + + try + self.postMessage + type: 'console-log' + args: args + id: self.workerID + + catch error + self.postMessage + type: 'console-log' + args: ["Could not post log: " + args, error.toString(), error.stack, error.stackTrace] + id: self.workerID + + +console.error = console.info = console.log +self.console = console + +importScripts '/javascripts/world.js' + + +self.transferableSupported = transferableSupported = -> + try + ab = new ArrayBuffer 1 + worker.postMessage ab, [ab] + return ab.byteLength is 0 + catch error + return false + return false + + + World = self.require 'lib/world/world' + GoalManager = self.require 'lib/world/GoalManager' + + self.runWorld = runWorld = (args) -> + self.postedErrors = {} + self.t0 = new Date() + self.firstWorld = args.firstWorld + self.postedErrors = false + self.logsLogged = 0 + + try + self.world = new World args.worldName, args.userCodeMap + if args.level + self.world.loadFromLevel args.level, true + self.goalManager = new GoalManager self.world + self.goalManager.setGoals args.goals + self.goalManager.setCode args.userCodeMap + self.goalManager.worldGenerationWillBegin() + self.world.setGoalManager self.goalManager + catch error + self.onWorldError error + return + Math.random = self.world.rand.randf + self.world.loadFrames self.onWorldLoaded, self.onWorldError, self.onWorldLoadProgress + +self.onWorldLoaded = onWorldLoaded = () -> + self.goalManager.worldGenerationEnded() + t1 = new Date() + diff = t1 - self.t0 + transferableSupported = self.transferableSupported() + try + serialized = self.world.serialize() + catch error + console.log "World serialization error:", error.toString() + "\n" + error.stack or error.stackTrace + + + t2 = new Date() + + try + if transferableSupported + self.postMessage( + type: 'new-world' + serialized: serialized.serializedWorld + goalStates: self.goalManager.getGoalStates() + , serialized.transferableObjects) + else + self.postMessage + type: 'new-world' + serialized: serialized.serializedWorld + goalStates: self.goalManager.getGoalStates() + catch error + console.log "World delivery error:", error.toString + "\n" + error.stack or error.stackTrace + t3 = new Date() + console.log "And it was so: (" + (diff / self.world.totalFrames).toFixed(3) + "ms per frame,", self.world.totalFrames, "frames)\nSimulation :" + self.world = null + +self.onWorldError = onWorldError = (error) -> + if error instanceof Aether.problems.UserCodeProblem + unless self.postedErrors[error.key] + problem = error.serialize() + self.postMessage + type: 'user-code-problem' + problem: problem + self.postedErrors[error.key] = problem + + else + console.log "Non-UserCodeError:", error.toString() + "\n" + error.stack or error.stackTrace + return true + +self.onWorldLoadProgress = onWorldLoadProgress = (progress) -> + self.postMessage + type: 'world-load-progress-changed' + progress: progress + +self.abort = abort = -> + if self.world and self.world.name + console.log "About to abort:", self.world.name, typeof self.world.abort + self.world?.abort() + self.world = null + + self.postMessage + type: 'abort' + +self.reportIn = reportIn = -> + self.postMessage + type: 'reportIn' + +self.addEventListener 'message', (event) -> + self[event.data.func](event.data.args) diff --git a/app/assets/javascripts/workers/worker_world.js b/app/assets/javascripts/workers/worker_world.js index ae3cbec8a..d694e5743 100644 --- a/app/assets/javascripts/workers/worker_world.js +++ b/app/assets/javascripts/workers/worker_world.js @@ -43,6 +43,12 @@ importScripts('/javascripts/world.js'); //xhr.open("get", "script.js"); //xhr.send(); +// We could do way more from this: http://stackoverflow.com/questions/10653809/making-webworkers-a-safe-environment +Object.defineProperty(self, "XMLHttpRequest", { + get: function() { throw new Error("Access to XMLHttpRequest is forbidden."); }, + configurable: false +}); + self.transferableSupported = function transferableSupported() { // Not in IE, even in IE 11 try { diff --git a/app/assets/lib/ace/mode-javascript.js b/app/assets/lib/ace/mode-javascript.js index 9544bf619..e5237d738 100644 --- a/app/assets/lib/ace/mode-javascript.js +++ b/app/assets/lib/ace/mode-javascript.js @@ -1 +1,892 @@ -ace.define("ace/mode/javascript",["require","exports","module","ace/lib/oop","ace/mode/text","ace/tokenizer","ace/mode/javascript_highlight_rules","ace/mode/matching_brace_outdent","ace/range","ace/worker/worker_client","ace/mode/behaviour/cstyle","ace/mode/folding/cstyle"],function(e,t,n){var r=e("../lib/oop"),i=e("./text").Mode,s=e("../tokenizer").Tokenizer,o=e("./javascript_highlight_rules").JavaScriptHighlightRules,u=e("./matching_brace_outdent").MatchingBraceOutdent,a=e("../range").Range,f=e("../worker/worker_client").WorkerClient,l=e("./behaviour/cstyle").CstyleBehaviour,c=e("./folding/cstyle").FoldMode,h=function(){this.HighlightRules=o,this.$outdent=new u,this.$behaviour=new l,this.foldingRules=new c};r.inherits(h,i),function(){this.lineCommentStart="//",this.blockComment={start:"/*",end:"*/"},this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.getTokenizer().getLineTokens(t,e),s=i.tokens,o=i.state;if(s.length&&s[s.length-1].type=="comment")return r;if(e=="start"||e=="no_regex"){var u=t.match(/^.*(?:\bcase\b.*\:|[\{\(\[])\s*$/);u&&(r+=n)}else if(e=="doc-start"){if(o=="start"||o=="no_regex")return"";var u=t.match(/^\s*(\/?)\*/);u&&(u[1]&&(r+=" "),r+="* ")}return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.createWorker=function(e){var t=new f(["ace"],"ace/mode/javascript_worker","JavaScriptWorker");return t.attachToDocument(e.getDocument()),t.on("jslint",function(t){e.setAnnotations(t.data)}),t.on("terminate",function(){e.clearAnnotations()}),t}}.call(h.prototype),t.Mode=h}),ace.define("ace/mode/javascript_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/doc_comment_highlight_rules","ace/mode/text_highlight_rules"],function(e,t,n){var r=e("../lib/oop"),i=e("./doc_comment_highlight_rules").DocCommentHighlightRules,s=e("./text_highlight_rules").TextHighlightRules,o=function(){var e=this.createKeywordMapper({"variable.language":"Array|Boolean|Date|Function|Iterator|Number|Object|RegExp|String|Proxy|Namespace|QName|XML|XMLList|ArrayBuffer|Float32Array|Float64Array|Int16Array|Int32Array|Int8Array|Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray|Error|EvalError|InternalError|RangeError|ReferenceError|StopIteration|SyntaxError|TypeError|URIError|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|eval|isFinite|isNaN|parseFloat|parseInt|JSON|Math|this|arguments|prototype|window|document",keyword:"const|yield|import|get|set|break|case|catch|continue|default|delete|do|else|finally|for|function|if|in|instanceof|new|return|switch|throw|try|typeof|let|var|while|with|debugger|__parent__|__count__|escape|unescape|with|__proto__|class|enum|extends|super|export|implements|private|public|interface|package|protected|static","storage.type":"const|let|var|function","constant.language":"null|Infinity|NaN|undefined","support.function":"alert","constant.language.boolean":"true|false"},"identifier"),t="case|do|else|finally|in|instanceof|return|throw|try|typeof|yield|void",n="[a-zA-Z\\$_¡-￿][a-zA-Z\\d\\$_¡-￿]*\\b",r="\\\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)";this.$rules={no_regex:[{token:"comment",regex:"\\/\\/",next:"line_comment"},i.getStartRule("doc-start"),{token:"comment",regex:/\/\*/,next:"comment"},{token:"string",regex:"'(?=.)",next:"qstring"},{token:"string",regex:'"(?=.)',next:"qqstring"},{token:"constant.numeric",regex:/0[xX][0-9a-fA-F]+\b/},{token:"constant.numeric",regex:/[+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/},{token:["storage.type","punctuation.operator","support.function","punctuation.operator","entity.name.function","text","keyword.operator"],regex:"("+n+")(\\.)(prototype)(\\.)("+n+")(\\s*)(=)",next:"function_arguments"},{token:["storage.type","punctuation.operator","entity.name.function","text","keyword.operator","text","storage.type","text","paren.lparen"],regex:"("+n+")(\\.)("+n+")(\\s*)(=)(\\s*)(function)(\\s*)(\\()",next:"function_arguments"},{token:["entity.name.function","text","keyword.operator","text","storage.type","text","paren.lparen"],regex:"("+n+")(\\s*)(=)(\\s*)(function)(\\s*)(\\()",next:"function_arguments"},{token:["storage.type","punctuation.operator","entity.name.function","text","keyword.operator","text","storage.type","text","entity.name.function","text","paren.lparen"],regex:"("+n+")(\\.)("+n+")(\\s*)(=)(\\s*)(function)(\\s+)(\\w+)(\\s*)(\\()",next:"function_arguments"},{token:["storage.type","text","entity.name.function","text","paren.lparen"],regex:"(function)(\\s+)("+n+")(\\s*)(\\()",next:"function_arguments"},{token:["entity.name.function","text","punctuation.operator","text","storage.type","text","paren.lparen"],regex:"("+n+")(\\s*)(:)(\\s*)(function)(\\s*)(\\()",next:"function_arguments"},{token:["text","text","storage.type","text","paren.lparen"],regex:"(:)(\\s*)(function)(\\s*)(\\()",next:"function_arguments"},{token:"keyword",regex:"(?:"+t+")\\b",next:"start"},{token:["punctuation.operator","support.function"],regex:/(\.)(s(?:h(?:ift|ow(?:Mod(?:elessDialog|alDialog)|Help))|croll(?:X|By(?:Pages|Lines)?|Y|To)?|t(?:op|rike)|i(?:n|zeToContent|debar|gnText)|ort|u(?:p|b(?:str(?:ing)?)?)|pli(?:ce|t)|e(?:nd|t(?:Re(?:sizable|questHeader)|M(?:i(?:nutes|lliseconds)|onth)|Seconds|Ho(?:tKeys|urs)|Year|Cursor|Time(?:out)?|Interval|ZOptions|Date|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(?:ome|andleEvent)|navigate|c(?:har(?:CodeAt|At)|o(?:s|n(?:cat|textual|firm)|mpile)|eil|lear(?:Timeout|Interval)?|a(?:ptureEvents|ll)|reate(?:StyleSheet|Popup|EventObject))|t(?:o(?:GMTString|S(?:tring|ource)|U(?:TCString|pperCase)|Lo(?:caleString|werCase))|est|a(?:n|int(?:Enabled)?))|i(?:s(?:NaN|Finite)|ndexOf|talics)|d(?:isableExternalCapture|ump|etachEvent)|u(?:n(?:shift|taint|escape|watch)|pdateCommands)|j(?:oin|avaEnabled)|p(?:o(?:p|w)|ush|lugins.refresh|a(?:ddings|rse(?:Int|Float)?)|r(?:int|ompt|eference))|e(?:scape|nableExternalCapture|val|lementFromPoint|x(?:p|ec(?:Script|Command)?))|valueOf|UTC|queryCommand(?:State|Indeterm|Enabled|Value)|f(?:i(?:nd|le(?:ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(?:nt(?:size|color)|rward)|loor|romCharCode)|watch|l(?:ink|o(?:ad|g)|astIndexOf)|a(?:sin|nchor|cos|t(?:tachEvent|ob|an(?:2)?)|pply|lert|b(?:s|ort))|r(?:ou(?:nd|teEvents)|e(?:size(?:By|To)|calc|turnValue|place|verse|l(?:oad|ease(?:Capture|Events)))|andom)|g(?:o|et(?:ResponseHeader|M(?:i(?:nutes|lliseconds)|onth)|Se(?:conds|lection)|Hours|Year|Time(?:zoneOffset)?|Da(?:y|te)|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear)|FullYear|A(?:ttention|llResponseHeaders)))|m(?:in|ove(?:B(?:y|elow)|To(?:Absolute)?|Above)|ergeAttributes|a(?:tch|rgins|x))|b(?:toa|ig|o(?:ld|rderWidths)|link|ack))\b(?=\()/},{token:["punctuation.operator","support.function.dom"],regex:/(\.)(s(?:ub(?:stringData|mit)|plitText|e(?:t(?:NamedItem|Attribute(?:Node)?)|lect))|has(?:ChildNodes|Feature)|namedItem|c(?:l(?:ick|o(?:se|neNode))|reate(?:C(?:omment|DATASection|aption)|T(?:Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(?:ntityReference|lement)|Attribute))|tabIndex|i(?:nsert(?:Row|Before|Cell|Data)|tem)|open|delete(?:Row|C(?:ell|aption)|T(?:Head|Foot)|Data)|focus|write(?:ln)?|a(?:dd|ppend(?:Child|Data))|re(?:set|place(?:Child|Data)|move(?:NamedItem|Child|Attribute(?:Node)?)?)|get(?:NamedItem|Element(?:sBy(?:Name|TagName)|ById)|Attribute(?:Node)?)|blur)\b(?=\()/},{token:["punctuation.operator","support.constant"],regex:/(\.)(s(?:ystemLanguage|cr(?:ipts|ollbars|een(?:X|Y|Top|Left))|t(?:yle(?:Sheets)?|atus(?:Text|bar)?)|ibling(?:Below|Above)|ource|uffixes|e(?:curity(?:Policy)?|l(?:ection|f)))|h(?:istory|ost(?:name)?|as(?:h|Focus))|y|X(?:MLDocument|SLDocument)|n(?:ext|ame(?:space(?:s|URI)|Prop))|M(?:IN_VALUE|AX_VALUE)|c(?:haracterSet|o(?:n(?:structor|trollers)|okieEnabled|lorDepth|mp(?:onents|lete))|urrent|puClass|l(?:i(?:p(?:boardData)?|entInformation)|osed|asses)|alle(?:e|r)|rypto)|t(?:o(?:olbar|p)|ext(?:Transform|Indent|Decoration|Align)|ags)|SQRT(?:1_2|2)|i(?:n(?:ner(?:Height|Width)|put)|ds|gnoreCase)|zIndex|o(?:scpu|n(?:readystatechange|Line)|uter(?:Height|Width)|p(?:sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(?:i(?:splay|alog(?:Height|Top|Width|Left|Arguments)|rectories)|e(?:scription|fault(?:Status|Ch(?:ecked|arset)|View)))|u(?:ser(?:Profile|Language|Agent)|n(?:iqueID|defined)|pdateInterval)|_content|p(?:ixelDepth|ort|ersonalbar|kcs11|l(?:ugins|atform)|a(?:thname|dding(?:Right|Bottom|Top|Left)|rent(?:Window|Layer)?|ge(?:X(?:Offset)?|Y(?:Offset)?))|r(?:o(?:to(?:col|type)|duct(?:Sub)?|mpter)|e(?:vious|fix)))|e(?:n(?:coding|abledPlugin)|x(?:ternal|pando)|mbeds)|v(?:isibility|endor(?:Sub)?|Linkcolor)|URLUnencoded|P(?:I|OSITIVE_INFINITY)|f(?:ilename|o(?:nt(?:Size|Family|Weight)|rmName)|rame(?:s|Element)|gColor)|E|whiteSpace|l(?:i(?:stStyleType|n(?:eHeight|kColor))|o(?:ca(?:tion(?:bar)?|lName)|wsrc)|e(?:ngth|ft(?:Context)?)|a(?:st(?:M(?:odified|atch)|Index|Paren)|yer(?:s|X)|nguage))|a(?:pp(?:MinorVersion|Name|Co(?:deName|re)|Version)|vail(?:Height|Top|Width|Left)|ll|r(?:ity|guments)|Linkcolor|bove)|r(?:ight(?:Context)?|e(?:sponse(?:XML|Text)|adyState))|global|x|m(?:imeTypes|ultiline|enubar|argin(?:Right|Bottom|Top|Left))|L(?:N(?:10|2)|OG(?:10E|2E))|b(?:o(?:ttom|rder(?:Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(?:Color|Image)))\b/},{token:["storage.type","punctuation.operator","support.function.firebug"],regex:/(console)(\.)(warn|info|log|error|time|timeEnd|assert)\b/},{token:e,regex:n},{token:"keyword.operator",regex:/--|\+\+|[!$%&*+\-~]|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\|\||\?\:|\*=|%=|\+=|\-=|&=|\^=/,next:"start"},{token:"punctuation.operator",regex:/\?|\:|\,|\;|\./,next:"start"},{token:"paren.lparen",regex:/[\[({]/,next:"start"},{token:"paren.rparen",regex:/[\])}]/},{token:"keyword.operator",regex:/\/=?/,next:"start"},{token:"comment",regex:/^#!.*$/}],start:[i.getStartRule("doc-start"),{token:"comment",regex:"\\/\\*",next:"comment_regex_allowed"},{token:"comment",regex:"\\/\\/",next:"line_comment_regex_allowed"},{token:"string.regexp",regex:"\\/",next:"regex"},{token:"text",regex:"\\s+|^$",next:"start"},{token:"empty",regex:"",next:"no_regex"}],regex:[{token:"regexp.keyword.operator",regex:"\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)"},{token:"string.regexp",regex:"/\\w*",next:"no_regex"},{token:"invalid",regex:/\{\d+\b,?\d*\}[+*]|[+*$^?][+*]|[$^][?]|\?{3,}/},{token:"constant.language.escape",regex:/\(\?[:=!]|\)|\{\d+\b,?\d*\}|[+*]\?|[()$^+*?]/},{token:"constant.language.delimiter",regex:/\|/},{token:"constant.language.escape",regex:/\[\^?/,next:"regex_character_class"},{token:"empty",regex:"$",next:"no_regex"},{defaultToken:"string.regexp"}],regex_character_class:[{token:"regexp.keyword.operator",regex:"\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)"},{token:"constant.language.escape",regex:"]",next:"regex"},{token:"constant.language.escape",regex:"-"},{token:"empty",regex:"$",next:"no_regex"},{defaultToken:"string.regexp.charachterclass"}],function_arguments:[{token:"variable.parameter",regex:n},{token:"punctuation.operator",regex:"[, ]+"},{token:"punctuation.operator",regex:"$"},{token:"empty",regex:"",next:"no_regex"}],comment_regex_allowed:[{token:"comment",regex:"\\*\\/",next:"start"},{defaultToken:"comment"}],comment:[{token:"comment",regex:"\\*\\/",next:"no_regex"},{defaultToken:"comment"}],line_comment_regex_allowed:[{token:"comment",regex:"$|^",next:"start"},{defaultToken:"comment"}],line_comment:[{token:"comment",regex:"$|^",next:"no_regex"},{defaultToken:"comment"}],qqstring:[{token:"constant.language.escape",regex:r},{token:"string",regex:"\\\\$",next:"qqstring"},{token:"string",regex:'"|$',next:"no_regex"},{defaultToken:"string"}],qstring:[{token:"constant.language.escape",regex:r},{token:"string",regex:"\\\\$",next:"qstring"},{token:"string",regex:"'|$",next:"no_regex"},{defaultToken:"string"}]},this.embedRules(i,"doc-",[i.getEndRule("no_regex")])};r.inherits(o,s),t.JavaScriptHighlightRules=o}),ace.define("ace/mode/doc_comment_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"comment.doc.tag",regex:"@[\\w\\d_]+"},{token:"comment.doc.tag",regex:"\\bTODO\\b"},{defaultToken:"comment.doc"}]}};r.inherits(s,i),s.getStartRule=function(e){return{token:"comment.doc",regex:"\\/\\*(?=\\*)",next:e}},s.getEndRule=function(e){return{token:"comment.doc",regex:"\\*\\/",next:e}},t.DocCommentHighlightRules=s}),ace.define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){return e.match(/^\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),ace.define("ace/mode/behaviour/cstyle",["require","exports","module","ace/lib/oop","ace/mode/behaviour","ace/token_iterator","ace/lib/lang"],function(e,t,n){var r=e("../../lib/oop"),i=e("../behaviour").Behaviour,s=e("../../token_iterator").TokenIterator,o=e("../../lib/lang"),u=["text","paren.rparen","punctuation.operator"],a=["text","paren.rparen","punctuation.operator","comment"],f=0,l=-1,c="",h=0,p=-1,d="",v="",m=function(){m.isSaneInsertion=function(e,t){var n=e.getCursorPosition(),r=new s(t,n.row,n.column);if(!this.$matchTokenType(r.getCurrentToken()||"text",u)){var i=new s(t,n.row,n.column+1);if(!this.$matchTokenType(i.getCurrentToken()||"text",u))return!1}return r.stepForward(),r.getCurrentTokenRow()!==n.row||this.$matchTokenType(r.getCurrentToken()||"text",a)},m.$matchTokenType=function(e,t){return t.indexOf(e.type||e)>-1},m.recordAutoInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isAutoInsertedClosing(r,i,c[0])||(f=0),l=r.row,c=n+i.substr(r.column),f++},m.recordMaybeInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isMaybeInsertedClosing(r,i)||(h=0),p=r.row,d=i.substr(0,r.column)+n,v=i.substr(r.column),h++},m.isAutoInsertedClosing=function(e,t,n){return f>0&&e.row===l&&n===c[0]&&t.substr(e.column)===c},m.isMaybeInsertedClosing=function(e,t){return h>0&&e.row===p&&t.substr(e.column)===v&&t.substr(0,e.column)==d},m.popAutoInsertedClosing=function(){c=c.substr(1),f--},m.clearMaybeInsertedClosing=function(){h=0,p=-1},this.add("braces","insertion",function(e,t,n,r,i){var s=n.getCursorPosition(),u=r.doc.getLine(s.row);if(i=="{"){var a=n.getSelectionRange(),f=r.doc.getTextRange(a);if(f!==""&&f!=="{"&&n.getWrapBehavioursEnabled())return{text:"{"+f+"}",selection:!1};if(m.isSaneInsertion(n,r))return/[\]\}\)]/.test(u[s.column])?(m.recordAutoInsert(n,r,"}"),{text:"{}",selection:[1,1]}):(m.recordMaybeInsert(n,r,"{"),{text:"{",selection:[1,1]})}else if(i=="}"){var l=u.substring(s.column,s.column+1);if(l=="}"){var c=r.$findOpeningBracket("}",{column:s.column+1,row:s.row});if(c!==null&&m.isAutoInsertedClosing(s,u,i))return m.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}else if(i=="\n"||i=="\r\n"){var p="";m.isMaybeInsertedClosing(s,u)&&(p=o.stringRepeat("}",h),m.clearMaybeInsertedClosing());var l=u.substring(s.column,s.column+1);if(l=="}"||p!==""){var d=r.findMatchingBracket({row:s.row,column:s.column+1},"}");if(!d)return null;var v=this.getNextLineIndent(e,u.substring(0,s.column),r.getTabString()),g=this.$getIndent(u);return{text:"\n"+v+"\n"+g+p,selection:[1,v.length,1,v.length]}}}}),this.add("braces","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="{"){var o=r.doc.getLine(i.start.row),u=o.substring(i.end.column,i.end.column+1);if(u=="}")return i.end.column++,i;h--}}),this.add("parens","insertion",function(e,t,n,r,i){if(i=="("){var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&n.getWrapBehavioursEnabled())return{text:"("+o+")",selection:!1};if(m.isSaneInsertion(n,r))return m.recordAutoInsert(n,r,")"),{text:"()",selection:[1,1]}}else if(i==")"){var u=n.getCursorPosition(),a=r.doc.getLine(u.row),f=a.substring(u.column,u.column+1);if(f==")"){var l=r.$findOpeningBracket(")",{column:u.column+1,row:u.row});if(l!==null&&m.isAutoInsertedClosing(u,a,i))return m.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("parens","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="("){var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u==")")return i.end.column++,i}}),this.add("brackets","insertion",function(e,t,n,r,i){if(i=="["){var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&n.getWrapBehavioursEnabled())return{text:"["+o+"]",selection:!1};if(m.isSaneInsertion(n,r))return m.recordAutoInsert(n,r,"]"),{text:"[]",selection:[1,1]}}else if(i=="]"){var u=n.getCursorPosition(),a=r.doc.getLine(u.row),f=a.substring(u.column,u.column+1);if(f=="]"){var l=r.$findOpeningBracket("]",{column:u.column+1,row:u.row});if(l!==null&&m.isAutoInsertedClosing(u,a,i))return m.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("brackets","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="["){var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u=="]")return i.end.column++,i}}),this.add("string_dquotes","insertion",function(e,t,n,r,i){if(i=='"'||i=="'"){var s=i,o=n.getSelectionRange(),u=r.doc.getTextRange(o);if(u!==""&&u!=="'"&&u!='"'&&n.getWrapBehavioursEnabled())return{text:s+u+s,selection:!1};var a=n.getCursorPosition(),f=r.doc.getLine(a.row),l=f.substring(a.column-1,a.column);if(l=="\\")return null;var c=r.getTokens(o.start.row),h=0,p,d=-1;for(var v=0;vo.start.column)break;h+=c[v].value.length}if(!p||d<0&&p.type!=="comment"&&(p.type!=="string"||o.start.column!==p.value.length+h-1&&p.value.lastIndexOf(s)===p.value.length-1)){if(!m.isSaneInsertion(n,r))return;return{text:s+s,selection:[1,1]}}if(p&&p.type==="string"){var g=f.substring(a.column,a.column+1);if(g==s)return{text:"",selection:[1,1]}}}}),this.add("string_dquotes","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&(s=='"'||s=="'")){var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u==s)return i.end.column++,i}})};r.inherits(m,i),t.CstyleBehaviour=m}),ace.define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/(\{|\[)[^\}\]]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/,this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n),s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++tf)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)}}.call(o.prototype)}) \ No newline at end of file +// Edited by Nick to remove some browser-specific stuff and make more things identifiers, not support constants. +ace.define('ace/mode/javascript', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/text', 'ace/tokenizer', 'ace/mode/javascript_highlight_rules', 'ace/mode/matching_brace_outdent', 'ace/range', 'ace/worker/worker_client', 'ace/mode/behaviour/cstyle', 'ace/mode/folding/cstyle'], function(require, exports, module) { + + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var Tokenizer = require("../tokenizer").Tokenizer; +var JavaScriptHighlightRules = require("./javascript_highlight_rules").JavaScriptHighlightRules; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; +var Range = require("../range").Range; +var WorkerClient = require("../worker/worker_client").WorkerClient; +var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; +var CStyleFoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.HighlightRules = JavaScriptHighlightRules; + + this.$outdent = new MatchingBraceOutdent(); + this.$behaviour = new CstyleBehaviour(); + this.foldingRules = new CStyleFoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.lineCommentStart = "//"; + this.blockComment = {start: "/*", end: "*/"}; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + var tokenizedLine = this.getTokenizer().getLineTokens(line, state); + var tokens = tokenizedLine.tokens; + var endState = tokenizedLine.state; + + if (tokens.length && tokens[tokens.length-1].type == "comment") { + return indent; + } + + if (state == "start" || state == "no_regex") { + var match = line.match(/^.*(?:\bcase\b.*\:|[\{\(\[])\s*$/); + if (match) { + indent += tab; + } + } else if (state == "doc-start") { + if (endState == "start" || endState == "no_regex") { + return ""; + } + var match = line.match(/^\s*(\/?)\*/); + if (match) { + if (match[1]) { + indent += " "; + } + indent += "* "; + } + } + + return indent; + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + + this.createWorker = function(session) { + var worker = new WorkerClient(["ace"], "ace/mode/javascript_worker", "JavaScriptWorker"); + worker.attachToDocument(session.getDocument()); + + worker.on("jslint", function(results) { + session.setAnnotations(results.data); + }); + + worker.on("terminate", function() { + session.clearAnnotations(); + }); + + return worker; + }; + + this.$id = "ace/mode/javascript"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); + +ace.define('ace/mode/javascript_highlight_rules', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/doc_comment_highlight_rules', 'ace/mode/text_highlight_rules'], function(require, exports, module) { + + +var oop = require("../lib/oop"); +var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocCommentHighlightRules; +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var JavaScriptHighlightRules = function() { + var keywordMapper = this.createKeywordMapper({ + "variable.language": + "Array|Boolean|Date|Function|Iterator|Number|Object|RegExp|String|Proxy|" + // Constructors + "Namespace|QName|XML|XMLList|" + // E4X + "ArrayBuffer|Float32Array|Float64Array|Int16Array|Int32Array|Int8Array|" + + "Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray|" + + "Error|EvalError|InternalError|RangeError|ReferenceError|StopIteration|" + // Errors + "SyntaxError|TypeError|URIError|" + + "decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|eval|isFinite|" + // Non-constructor functions + "isNaN|parseFloat|parseInt|" + + "JSON|Math|" + // Other + "this|arguments|prototype" , // Pseudo + "keyword": + "const|yield|import|get|set|" + + "break|case|catch|continue|default|delete|do|else|finally|for|function|" + + "if|in|instanceof|new|return|switch|throw|try|typeof|let|var|while|with|debugger|" + + "__parent__|__count__|escape|unescape|with|__proto__|" + + "class|enum|extends|super|export|implements|private|public|interface|package|protected|static", + "storage.type": + "const|let|var|function", + "constant.language": + "null|Infinity|NaN|undefined", + "support.function": + "alert", + "constant.language.boolean": "true|false" + }, "identifier"); + var kwBeforeRe = "case|do|else|finally|in|instanceof|return|throw|try|typeof|yield|void"; + var identifierRe = "[a-zA-Z\\$_\u00a1-\uffff][a-zA-Z\\d\\$_\u00a1-\uffff]*\\b"; + + var escapedRe = "\\\\(?:x[0-9a-fA-F]{2}|" + // hex + "u[0-9a-fA-F]{4}|" + // unicode + "[0-2][0-7]{0,2}|" + // oct + "3[0-6][0-7]?|" + // oct + "37[0-7]?|" + // oct + "[4-7][0-7]?|" + //oct + ".)"; + + this.$rules = { + "no_regex" : [ + { + token : "comment", + regex : "\\/\\/", + next : "line_comment" + }, + DocCommentHighlightRules.getStartRule("doc-start"), + { + token : "comment", // multi line comment + regex : /\/\*/, + next : "comment" + }, { + token : "string", + regex : "'(?=.)", + next : "qstring" + }, { + token : "string", + regex : '"(?=.)', + next : "qqstring" + }, { + token : "constant.numeric", // hex + regex : /0[xX][0-9a-fA-F]+\b/ + }, { + token : "constant.numeric", // float + regex : /[+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/ + }, { + token : [ + "storage.type", "punctuation.operator", "support.function", + "punctuation.operator", "entity.name.function", "text","keyword.operator" + ], + regex : "(" + identifierRe + ")(\\.)(prototype)(\\.)(" + identifierRe +")(\\s*)(=)", + next: "function_arguments" + }, { + token : [ + "storage.type", "punctuation.operator", "entity.name.function", "text", + "keyword.operator", "text", "storage.type", "text", "paren.lparen" + ], + regex : "(" + identifierRe + ")(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function)(\\s*)(\\()", + next: "function_arguments" + }, { + token : [ + "entity.name.function", "text", "keyword.operator", "text", "storage.type", + "text", "paren.lparen" + ], + regex : "(" + identifierRe +")(\\s*)(=)(\\s*)(function)(\\s*)(\\()", + next: "function_arguments" + }, { + token : [ + "storage.type", "punctuation.operator", "entity.name.function", "text", + "keyword.operator", "text", + "storage.type", "text", "entity.name.function", "text", "paren.lparen" + ], + regex : "(" + identifierRe + ")(\\.)(" + identifierRe +")(\\s*)(=)(\\s*)(function)(\\s+)(\\w+)(\\s*)(\\()", + next: "function_arguments" + }, { + token : [ + "storage.type", "text", "entity.name.function", "text", "paren.lparen" + ], + regex : "(function)(\\s+)(" + identifierRe + ")(\\s*)(\\()", + next: "function_arguments" + }, { + token : [ + "entity.name.function", "text", "punctuation.operator", + "text", "storage.type", "text", "paren.lparen" + ], + regex : "(" + identifierRe + ")(\\s*)(:)(\\s*)(function)(\\s*)(\\()", + next: "function_arguments" + }, { + token : [ + "text", "text", "storage.type", "text", "paren.lparen" + ], + regex : "(:)(\\s*)(function)(\\s*)(\\()", + next: "function_arguments" + }, { + token : "keyword", + regex : "(?:" + kwBeforeRe + ")\\b", + next : "start" + }, { + token : keywordMapper, + regex : identifierRe + }, { + token : "keyword.operator", + regex : /--|\+\+|[!$%&*+\-~]|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\|\||\?\:|\*=|%=|\+=|\-=|&=|\^=/, + next : "start" + }, { + token : "punctuation.operator", + regex : /\?|\:|\,|\;|\./, + next : "start" + }, { + token : "paren.lparen", + regex : /[\[({]/, + next : "start" + }, { + token : "paren.rparen", + regex : /[\])}]/ + }, { + token : "keyword.operator", + regex : /\/=?/, + next : "start" + }, { + token: "comment", + regex: /^#!.*$/ + } + ], + "start": [ + DocCommentHighlightRules.getStartRule("doc-start"), + { + token : "comment", // multi line comment + regex : "\\/\\*", + next : "comment_regex_allowed" + }, { + token : "comment", + regex : "\\/\\/", + next : "line_comment_regex_allowed" + }, { + token: "string.regexp", + regex: "\\/", + next: "regex" + }, { + token : "text", + regex : "\\s+|^$", + next : "start" + }, { + token: "empty", + regex: "", + next: "no_regex" + } + ], + "regex": [ + { + token: "regexp.keyword.operator", + regex: "\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)" + }, { + token: "string.regexp", + regex: "/[sxngimy]*", + next: "no_regex" + }, { + token : "invalid", + regex: /\{\d+\b,?\d*\}[+*]|[+*$^?][+*]|[$^][?]|\?{3,}/ + }, { + token : "constant.language.escape", + regex: /\(\?[:=!]|\)|\{\d+\b,?\d*\}|[+*]\?|[()$^+*?.]/ + }, { + token : "constant.language.delimiter", + regex: /\|/ + }, { + token: "constant.language.escape", + regex: /\[\^?/, + next: "regex_character_class" + }, { + token: "empty", + regex: "$", + next: "no_regex" + }, { + defaultToken: "string.regexp" + } + ], + "regex_character_class": [ + { + token: "regexp.keyword.operator", + regex: "\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)" + }, { + token: "constant.language.escape", + regex: "]", + next: "regex" + }, { + token: "constant.language.escape", + regex: "-" + }, { + token: "empty", + regex: "$", + next: "no_regex" + }, { + defaultToken: "string.regexp.charachterclass" + } + ], + "function_arguments": [ + { + token: "variable.parameter", + regex: identifierRe + }, { + token: "punctuation.operator", + regex: "[, ]+" + }, { + token: "punctuation.operator", + regex: "$" + }, { + token: "empty", + regex: "", + next: "no_regex" + } + ], + "comment_regex_allowed" : [ + {token : "comment", regex : "\\*\\/", next : "start"}, + {defaultToken : "comment"} + ], + "comment" : [ + {token : "comment", regex : "\\*\\/", next : "no_regex"}, + {defaultToken : "comment"} + ], + "line_comment_regex_allowed" : [ + {token : "comment", regex : "$|^", next : "start"}, + {defaultToken : "comment"} + ], + "line_comment" : [ + {token : "comment", regex : "$|^", next : "no_regex"}, + {defaultToken : "comment"} + ], + "qqstring" : [ + { + token : "constant.language.escape", + regex : escapedRe + }, { + token : "string", + regex : "\\\\$", + next : "qqstring" + }, { + token : "string", + regex : '"|$', + next : "no_regex" + }, { + defaultToken: "string" + } + ], + "qstring" : [ + { + token : "constant.language.escape", + regex : escapedRe + }, { + token : "string", + regex : "\\\\$", + next : "qstring" + }, { + token : "string", + regex : "'|$", + next : "no_regex" + }, { + defaultToken: "string" + } + ] + }; + + this.embedRules(DocCommentHighlightRules, "doc-", + [ DocCommentHighlightRules.getEndRule("no_regex") ]); +}; + +oop.inherits(JavaScriptHighlightRules, TextHighlightRules); + +exports.JavaScriptHighlightRules = JavaScriptHighlightRules; +}); + +ace.define('ace/mode/doc_comment_highlight_rules', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/text_highlight_rules'], function(require, exports, module) { + + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var DocCommentHighlightRules = function() { + + this.$rules = { + "start" : [ { + token : "comment.doc.tag", + regex : "@[\\w\\d_]+" // TODO: fix email addresses + }, { + token : "comment.doc.tag", + regex : "\\bTODO\\b" + }, { + defaultToken : "comment.doc" + }] + }; +}; + +oop.inherits(DocCommentHighlightRules, TextHighlightRules); + +DocCommentHighlightRules.getStartRule = function(start) { + return { + token : "comment.doc", // doc comment + regex : "\\/\\*(?=\\*)", + next : start + }; +}; + +DocCommentHighlightRules.getEndRule = function (start) { + return { + token : "comment.doc", // closing comment + regex : "\\*\\/", + next : start + }; +}; + + +exports.DocCommentHighlightRules = DocCommentHighlightRules; + +}); + +ace.define('ace/mode/matching_brace_outdent', ['require', 'exports', 'module' , 'ace/range'], function(require, exports, module) { + + +var Range = require("../range").Range; + +var MatchingBraceOutdent = function() {}; + +(function() { + + this.checkOutdent = function(line, input) { + if (! /^\s+$/.test(line)) + return false; + + return /^\s*\}/.test(input); + }; + + this.autoOutdent = function(doc, row) { + var line = doc.getLine(row); + var match = line.match(/^(\s*\})/); + + if (!match) return 0; + + var column = match[1].length; + var openBracePos = doc.findMatchingBracket({row: row, column: column}); + + if (!openBracePos || openBracePos.row == row) return 0; + + var indent = this.$getIndent(doc.getLine(openBracePos.row)); + doc.replace(new Range(row, 0, row, column-1), indent); + }; + + this.$getIndent = function(line) { + return line.match(/^\s*/)[0]; + }; + +}).call(MatchingBraceOutdent.prototype); + +exports.MatchingBraceOutdent = MatchingBraceOutdent; +}); + +ace.define('ace/mode/behaviour/cstyle', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/behaviour', 'ace/token_iterator', 'ace/lib/lang'], function(require, exports, module) { + + +var oop = require("../../lib/oop"); +var Behaviour = require("../behaviour").Behaviour; +var TokenIterator = require("../../token_iterator").TokenIterator; +var lang = require("../../lib/lang"); + +var SAFE_INSERT_IN_TOKENS = + ["text", "paren.rparen", "punctuation.operator"]; +var SAFE_INSERT_BEFORE_TOKENS = + ["text", "paren.rparen", "punctuation.operator", "comment"]; + + +var autoInsertedBrackets = 0; +var autoInsertedRow = -1; +var autoInsertedLineEnd = ""; +var maybeInsertedBrackets = 0; +var maybeInsertedRow = -1; +var maybeInsertedLineStart = ""; +var maybeInsertedLineEnd = ""; + +var CstyleBehaviour = function () { + + CstyleBehaviour.isSaneInsertion = function(editor, session) { + var cursor = editor.getCursorPosition(); + var iterator = new TokenIterator(session, cursor.row, cursor.column); + if (!this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) { + var iterator2 = new TokenIterator(session, cursor.row, cursor.column + 1); + if (!this.$matchTokenType(iterator2.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) + return false; + } + iterator.stepForward(); + return iterator.getCurrentTokenRow() !== cursor.row || + this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_BEFORE_TOKENS); + }; + + CstyleBehaviour.$matchTokenType = function(token, types) { + return types.indexOf(token.type || token) > -1; + }; + + CstyleBehaviour.recordAutoInsert = function(editor, session, bracket) { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + if (!this.isAutoInsertedClosing(cursor, line, autoInsertedLineEnd[0])) + autoInsertedBrackets = 0; + autoInsertedRow = cursor.row; + autoInsertedLineEnd = bracket + line.substr(cursor.column); + autoInsertedBrackets++; + }; + + CstyleBehaviour.recordMaybeInsert = function(editor, session, bracket) { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + if (!this.isMaybeInsertedClosing(cursor, line)) + maybeInsertedBrackets = 0; + maybeInsertedRow = cursor.row; + maybeInsertedLineStart = line.substr(0, cursor.column) + bracket; + maybeInsertedLineEnd = line.substr(cursor.column); + maybeInsertedBrackets++; + }; + + CstyleBehaviour.isAutoInsertedClosing = function(cursor, line, bracket) { + return autoInsertedBrackets > 0 && + cursor.row === autoInsertedRow && + bracket === autoInsertedLineEnd[0] && + line.substr(cursor.column) === autoInsertedLineEnd; + }; + + CstyleBehaviour.isMaybeInsertedClosing = function(cursor, line) { + return maybeInsertedBrackets > 0 && + cursor.row === maybeInsertedRow && + line.substr(cursor.column) === maybeInsertedLineEnd && + line.substr(0, cursor.column) == maybeInsertedLineStart; + }; + + CstyleBehaviour.popAutoInsertedClosing = function() { + autoInsertedLineEnd = autoInsertedLineEnd.substr(1); + autoInsertedBrackets--; + }; + + CstyleBehaviour.clearMaybeInsertedClosing = function() { + maybeInsertedBrackets = 0; + maybeInsertedRow = -1; + }; + + this.add("braces", "insertion", function (state, action, editor, session, text) { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + if (text == '{') { + var selection = editor.getSelectionRange(); + var selected = session.doc.getTextRange(selection); + if (selected !== "" && selected !== "{" && editor.getWrapBehavioursEnabled()) { + return { + text: '{' + selected + '}', + selection: false + }; + } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { + if (/[\]\}\)]/.test(line[cursor.column]) || editor.inMultiSelectMode) { + CstyleBehaviour.recordAutoInsert(editor, session, "}"); + return { + text: '{}', + selection: [1, 1] + }; + } else { + CstyleBehaviour.recordMaybeInsert(editor, session, "{"); + return { + text: '{', + selection: [1, 1] + }; + } + } + } else if (text == '}') { + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar == '}') { + var matching = session.$findOpeningBracket('}', {column: cursor.column + 1, row: cursor.row}); + if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { + CstyleBehaviour.popAutoInsertedClosing(); + return { + text: '', + selection: [1, 1] + }; + } + } + } else if (text == "\n" || text == "\r\n") { + var closing = ""; + if (CstyleBehaviour.isMaybeInsertedClosing(cursor, line)) { + closing = lang.stringRepeat("}", maybeInsertedBrackets); + CstyleBehaviour.clearMaybeInsertedClosing(); + } + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar === '}') { + var openBracePos = session.findMatchingBracket({row: cursor.row, column: cursor.column+1}, '}'); + if (!openBracePos) + return null; + var next_indent = this.$getIndent(session.getLine(openBracePos.row)); + } else if (closing) { + var next_indent = this.$getIndent(line); + } else { + return; + } + var indent = next_indent + session.getTabString(); + + return { + text: '\n' + indent + '\n' + next_indent + closing, + selection: [1, indent.length, 1, indent.length] + }; + } else { + CstyleBehaviour.clearMaybeInsertedClosing(); + } + }); + + this.add("braces", "deletion", function (state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && selected == '{') { + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.end.column, range.end.column + 1); + if (rightChar == '}') { + range.end.column++; + return range; + } else { + maybeInsertedBrackets--; + } + } + }); + + this.add("parens", "insertion", function (state, action, editor, session, text) { + if (text == '(') { + var selection = editor.getSelectionRange(); + var selected = session.doc.getTextRange(selection); + if (selected !== "" && editor.getWrapBehavioursEnabled()) { + return { + text: '(' + selected + ')', + selection: false + }; + } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { + CstyleBehaviour.recordAutoInsert(editor, session, ")"); + return { + text: '()', + selection: [1, 1] + }; + } + } else if (text == ')') { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar == ')') { + var matching = session.$findOpeningBracket(')', {column: cursor.column + 1, row: cursor.row}); + if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { + CstyleBehaviour.popAutoInsertedClosing(); + return { + text: '', + selection: [1, 1] + }; + } + } + } + }); + + this.add("parens", "deletion", function (state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && selected == '(') { + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.start.column + 1, range.start.column + 2); + if (rightChar == ')') { + range.end.column++; + return range; + } + } + }); + + this.add("brackets", "insertion", function (state, action, editor, session, text) { + if (text == '[') { + var selection = editor.getSelectionRange(); + var selected = session.doc.getTextRange(selection); + if (selected !== "" && editor.getWrapBehavioursEnabled()) { + return { + text: '[' + selected + ']', + selection: false + }; + } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { + CstyleBehaviour.recordAutoInsert(editor, session, "]"); + return { + text: '[]', + selection: [1, 1] + }; + } + } else if (text == ']') { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar == ']') { + var matching = session.$findOpeningBracket(']', {column: cursor.column + 1, row: cursor.row}); + if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { + CstyleBehaviour.popAutoInsertedClosing(); + return { + text: '', + selection: [1, 1] + }; + } + } + } + }); + + this.add("brackets", "deletion", function (state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && selected == '[') { + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.start.column + 1, range.start.column + 2); + if (rightChar == ']') { + range.end.column++; + return range; + } + } + }); + + this.add("string_dquotes", "insertion", function (state, action, editor, session, text) { + if (text == '"' || text == "'") { + var quote = text; + var selection = editor.getSelectionRange(); + var selected = session.doc.getTextRange(selection); + if (selected !== "" && selected !== "'" && selected != '"' && editor.getWrapBehavioursEnabled()) { + return { + text: quote + selected + quote, + selection: false + }; + } else { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var leftChar = line.substring(cursor.column-1, cursor.column); + if (leftChar == '\\') { + return null; + } + var tokens = session.getTokens(selection.start.row); + var col = 0, token; + var quotepos = -1; // Track whether we're inside an open quote. + + for (var x = 0; x < tokens.length; x++) { + token = tokens[x]; + if (token.type == "string") { + quotepos = -1; + } else if (quotepos < 0) { + quotepos = token.value.indexOf(quote); + } + if ((token.value.length + col) > selection.start.column) { + break; + } + col += tokens[x].value.length; + } + if (!token || (quotepos < 0 && token.type !== "comment" && (token.type !== "string" || ((selection.start.column !== token.value.length+col-1) && token.value.lastIndexOf(quote) === token.value.length-1)))) { + if (!CstyleBehaviour.isSaneInsertion(editor, session)) + return; + return { + text: quote + quote, + selection: [1,1] + }; + } else if (token && token.type === "string") { + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar == quote) { + return { + text: '', + selection: [1, 1] + }; + } + } + } + } + }); + + this.add("string_dquotes", "deletion", function (state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && (selected == '"' || selected == "'")) { + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.start.column + 1, range.start.column + 2); + if (rightChar == selected) { + range.end.column++; + return range; + } + } + }); + +}; + +oop.inherits(CstyleBehaviour, Behaviour); + +exports.CstyleBehaviour = CstyleBehaviour; +}); + +ace.define('ace/mode/folding/cstyle', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/range', 'ace/mode/folding/fold_mode'], function(require, exports, module) { + + +var oop = require("../../lib/oop"); +var Range = require("../../range").Range; +var BaseFoldMode = require("./fold_mode").FoldMode; + +var FoldMode = exports.FoldMode = function(commentRegex) { + if (commentRegex) { + this.foldingStartMarker = new RegExp( + this.foldingStartMarker.source.replace(/\|[^|]*?$/, "|" + commentRegex.start) + ); + this.foldingStopMarker = new RegExp( + this.foldingStopMarker.source.replace(/\|[^|]*?$/, "|" + commentRegex.end) + ); + } +}; +oop.inherits(FoldMode, BaseFoldMode); + +(function() { + + this.foldingStartMarker = /(\{|\[)[^\}\]]*$|^\s*(\/\*)/; + this.foldingStopMarker = /^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/; + + this.getFoldWidgetRange = function(session, foldStyle, row, forceMultiline) { + var line = session.getLine(row); + var match = line.match(this.foldingStartMarker); + if (match) { + var i = match.index; + + if (match[1]) + return this.openingBracketBlock(session, match[1], row, i); + + var range = session.getCommentFoldRange(row, i + match[0].length, 1); + + if (range && !range.isMultiLine()) { + if (forceMultiline) { + range = this.getSectionRange(session, row); + } else if (foldStyle != "all") + range = null; + } + + return range; + } + + if (foldStyle === "markbegin") + return; + + var match = line.match(this.foldingStopMarker); + if (match) { + var i = match.index + match[0].length; + + if (match[1]) + return this.closingBracketBlock(session, match[1], row, i); + + return session.getCommentFoldRange(row, i, -1); + } + }; + + this.getSectionRange = function(session, row) { + var line = session.getLine(row); + var startIndent = line.search(/\S/); + var startRow = row; + var startColumn = line.length; + row = row + 1; + var endRow = row; + var maxRow = session.getLength(); + while (++row < maxRow) { + line = session.getLine(row); + var indent = line.search(/\S/); + if (indent === -1) + continue; + if (startIndent > indent) + break; + var subRange = this.getFoldWidgetRange(session, "all", row); + + if (subRange) { + if (subRange.start.row <= startRow) { + break; + } else if (subRange.isMultiLine()) { + row = subRange.end.row; + } else if (startIndent == indent) { + break; + } + } + endRow = row; + } + + return new Range(startRow, startColumn, endRow, session.getLine(endRow).length); + }; + +}).call(FoldMode.prototype); + +}); diff --git a/app/lib/FacebookHandler.coffee b/app/lib/FacebookHandler.coffee index a916a5b7b..ffd61b5a1 100644 --- a/app/lib/FacebookHandler.coffee +++ b/app/lib/FacebookHandler.coffee @@ -1,7 +1,7 @@ CocoClass = require 'lib/CocoClass' {me, CURRENT_USER_KEY} = require 'lib/auth' {backboneFailure} = require 'lib/errors' -{saveObjectToStorage} = require 'lib/storage' +storage = require 'lib/storage' # facebook user object props to userPropsToSave = @@ -59,7 +59,7 @@ module.exports = FacebookHandler = class FacebookHandler extends CocoClass error: backboneFailure, url: "/db/user?facebookID=#{r.id}&facebookAccessToken=#{@authResponse.accessToken}" success: (model) -> - saveObjectToStorage(CURRENT_USER_KEY, model.attributes) + storage.save(CURRENT_USER_KEY, model.attributes) window.location.reload() if model.get('email') isnt oldEmail }) diff --git a/app/lib/GPlusHandler.coffee b/app/lib/GPlusHandler.coffee index 566058ada..996b6ded0 100644 --- a/app/lib/GPlusHandler.coffee +++ b/app/lib/GPlusHandler.coffee @@ -1,7 +1,7 @@ CocoClass = require 'lib/CocoClass' {me, CURRENT_USER_KEY} = require 'lib/auth' {backboneFailure} = require 'lib/errors' -{saveObjectToStorage} = require 'lib/storage' +storage = require 'lib/storage' # gplus user object props to userPropsToSave = @@ -73,7 +73,7 @@ module.exports = GPlusHandler = class GPlusHandler extends CocoClass error: backboneFailure, url: "/db/user?gplusID=#{gplusID}&gplusAccessToken=#{@accessToken}" success: (model) -> - saveObjectToStorage(CURRENT_USER_KEY, model.attributes) + storage.save(CURRENT_USER_KEY, model.attributes) window.location.reload() }) diff --git a/app/lib/Router.coffee b/app/lib/Router.coffee index 927401749..d20963cd7 100644 --- a/app/lib/Router.coffee +++ b/app/lib/Router.coffee @@ -20,6 +20,12 @@ module.exports = class CocoRouter extends Backbone.Router 'db/*path': 'routeToServer' 'file/*path': 'routeToServer' + + #multiplayer routes + 'scoring/queue': 'routeToServer' + 'play/level/:levelID/leaderboard/:teamID/:startRank/:endRank': 'getPaginatedLevelRank' + 'play/level/:levelID/player/:playerID': 'getPlayerLevelInfo' + # most go through here '*name': 'general' @@ -27,6 +33,13 @@ module.exports = class CocoRouter extends Backbone.Router general: (name) -> @openRoute(name) + getPaginatedLevelRank: (levelID,teamID,startRank,endRank) -> + return + + getPlayerLevelInfo: (levelID,playerID) -> + return + + editorModelView: (modelName, slugOrId, subview) -> modulePrefix = "views/editor/#{modelName}/" suffix = subview or (if slugOrId then 'edit' else 'home') diff --git a/app/lib/auth.coffee b/app/lib/auth.coffee index 4752fac86..2af810b37 100644 --- a/app/lib/auth.coffee +++ b/app/lib/auth.coffee @@ -1,6 +1,6 @@ {backboneFailure, genericFailure} = require 'lib/errors' User = require 'models/User' -{saveObjectToStorage, loadObjectFromStorage} = require 'lib/storage' +storage = require 'lib/storage' module.exports.CURRENT_USER_KEY = CURRENT_USER_KEY = 'whoami' BEEN_HERE_BEFORE_KEY = 'beenHereBefore' @@ -10,7 +10,7 @@ module.exports.createUser = (userObject, failure=backboneFailure) -> user.save({}, { error: failure, success: (model) -> - saveObjectToStorage(CURRENT_USER_KEY, model) + storage.save(CURRENT_USER_KEY, model) window.location.reload() }) @@ -21,7 +21,7 @@ module.exports.loginUser = (userObject, failure=genericFailure) -> password:userObject.password }, (model) -> - saveObjectToStorage(CURRENT_USER_KEY, model) + storage.save(CURRENT_USER_KEY, model) window.location.reload() ) jqxhr.fail(failure) @@ -29,7 +29,7 @@ module.exports.loginUser = (userObject, failure=genericFailure) -> module.exports.logoutUser = -> FB?.logout?() res = $.post('/auth/logout', {}, -> - saveObjectToStorage(CURRENT_USER_KEY, null) + storage.save(CURRENT_USER_KEY, null) window.location.reload() ) res.fail(genericFailure) @@ -38,7 +38,7 @@ init = -> # Load the user from local storage, and refresh it from the server. # Also refresh and cache the gravatar info. - storedUser = loadObjectFromStorage(CURRENT_USER_KEY) + storedUser = storage.load(CURRENT_USER_KEY) firstTime = not storedUser module.exports.me = window.me = new User(storedUser) me.url = -> '/auth/whoami' @@ -50,14 +50,14 @@ init = -> # Assign testGroupNumber to returning visitors; new ones in server/handlers/user me.set 'testGroupNumber', Math.floor(Math.random() * 256) me.save() - saveObjectToStorage(CURRENT_USER_KEY, me.attributes) + storage.save(CURRENT_USER_KEY, me.attributes) me.loadGravatarProfile() if me.get('email') me.on('sync', userSynced) userSynced = (user) -> Backbone.Mediator.publish('me:synced', {me:user}) - saveObjectToStorage(CURRENT_USER_KEY, user) + storage.save(CURRENT_USER_KEY, user) init() @@ -71,7 +71,7 @@ Backbone.Mediator.subscribe('level-set-volume', onSetVolume, module.exports) trackFirstArrival = -> # will have to filter out users who log in with existing accounts separately # but can at least not track logouts as first arrivals using local storage - beenHereBefore = loadObjectFromStorage(BEEN_HERE_BEFORE_KEY) + beenHereBefore = storage.load(BEEN_HERE_BEFORE_KEY) return if beenHereBefore window.tracker?.trackEvent 'First Arrived' - saveObjectToStorage(BEEN_HERE_BEFORE_KEY, true) + storage.save(BEEN_HERE_BEFORE_KEY, true) diff --git a/app/lib/forms.coffee b/app/lib/forms.coffee index 4fa9e8b8d..ba1bdc4fe 100644 --- a/app/lib/forms.coffee +++ b/app/lib/forms.coffee @@ -23,16 +23,15 @@ module.exports.applyErrorsToForm = (el, errors) -> prop = error.property input = $("[name='#{prop}']", el) - if not input[0] + if not input.length missingErrors.push(error) continue - controls = input.closest('.controls') - controls.append($("#{message}")) - group = controls.closest('.control-group') - group.addClass('error') + formGroup = input.closest('.form-group') + formGroup.addClass 'has-error' + formGroup.append($("#{message}")) return missingErrors module.exports.clearFormAlerts = (el) -> - $('.error', el).removeClass('error') - $('.error-inline', el).remove() - $('.alert', el).remove() \ No newline at end of file + $('.has-error', el).removeClass('has-error') + $('.alert', el).remove() + el.find('.help-block.error-help-block').remove() \ No newline at end of file diff --git a/app/lib/sprites/SpriteBuilder.coffee b/app/lib/sprites/SpriteBuilder.coffee index db4fe78ff..babf5178a 100644 --- a/app/lib/sprites/SpriteBuilder.coffee +++ b/app/lib/sprites/SpriteBuilder.coffee @@ -13,7 +13,9 @@ module.exports = class SpriteBuilder buildMovieClip: (animationName, movieClipArgs...) -> animData = @animationStore[animationName] - console.log "couldn't find animData from", @animationStore, "for", animationName unless animData + unless animData + console.error "couldn't find animData from", @animationStore, "for", animationName + return null locals = {} _.extend locals, @buildMovieClipShapes(animData.shapes) _.extend locals, @buildMovieClipContainers(animData.containers) diff --git a/app/lib/storage.coffee b/app/lib/storage.coffee index d6c1b45a3..10ecaf1a7 100644 --- a/app/lib/storage.coffee +++ b/app/lib/storage.coffee @@ -1,4 +1,4 @@ -module.exports.loadObjectFromStorage = (key) -> +module.exports.load = (key) -> s = localStorage.getItem(key) return null unless s try @@ -8,6 +8,8 @@ module.exports.loadObjectFromStorage = (key) -> console.warning('error loading from storage', key) return null -module.exports.saveObjectToStorage = (key, value) -> +module.exports.save = (key, value) -> s = JSON.stringify(value) - localStorage.setItem(key, s) \ No newline at end of file + localStorage.setItem(key, s) + +module.exports.remove = (key) -> localStorage.removeItem key \ No newline at end of file diff --git a/app/lib/surface/Camera.coffee b/app/lib/surface/Camera.coffee index ff7bb5e07..b41c50887 100644 --- a/app/lib/surface/Camera.coffee +++ b/app/lib/surface/Camera.coffee @@ -186,6 +186,7 @@ module.exports = class Camera extends CocoClass # Target is either just a {x, y} pos or a display object with {x, y} that might change; surface coordinates. time = 0 if @instant newTarget ?= {x:0, y:0} + newTarget = (@newTarget or @target) if @locked newZoom = Math.min((Math.max @minZoom, newZoom), MAX_ZOOM) return if @zoom is newZoom and newTarget is newTarget.x and newTarget.y is newTarget.y diff --git a/app/lib/surface/CocoSprite.coffee b/app/lib/surface/CocoSprite.coffee index 3dcb70a2a..c76959036 100644 --- a/app/lib/surface/CocoSprite.coffee +++ b/app/lib/surface/CocoSprite.coffee @@ -54,14 +54,14 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass 'surface:ticked': 'onSurfaceTicked' constructor: (@thangType, options) -> - super() + super() @options = _.extend(_.cloneDeep(@options), options) @setThang @options.thang console.error @toString(), "has no ThangType!" unless @thangType @actionQueue = [] @marks = {} @labels = {} - @ticker = 0 + @age = 0 @displayObject = new createjs.Container() if @thangType.get('actions') @onThangTypeLoaded() @@ -69,7 +69,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass @stillLoading = true @thangType.fetch() @thangType.once 'sync', @onThangTypeLoaded, @ - + onThangTypeLoaded: -> @stillLoading = false @actions = @thangType.getActions() @@ -95,7 +95,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass sprite = new createjs.Shape() sprite.scaleX = sprite.scaleY = 1 / @options.resolutionFactor # temp, until these are re-exported with perspective - if @options.camera and @thangType.get('name') in ['Dungeon Floor', 'Grass', 'Goal Trigger', 'Obstacle'] + if @options.camera and @thangType.get('name') in ['Dungeon Floor', 'Indoor Floor', 'Grass', 'Goal Trigger', 'Obstacle'] sprite.scaleY *= @options.camera.y2x @imageObject = sprite @displayObject.addChild(sprite) @@ -124,7 +124,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass @playNextAction() onActionEnd: (e) => @playNextAction() - onSurfaceTicked: -> @ticker += 1 + onSurfaceTicked: (e) -> @age += e.dt playNextAction: -> @playAction(@actionQueue.splice(0,1)[0]) if @actionQueue.length @@ -159,16 +159,21 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass @displayObject.cache 0, 0, bounds.width, bounds.height #console.log "just cached", @thang.id, "which was at", @imageObject.x, @imageObject.y, bounds.width, bounds.height, "with scale", Math.max(@imageObject.scaleX, @imageObject.scaleY) + getBobOffset: -> + return 0 unless @thang.bobHeight + @thang.bobHeight * (1 + Math.sin(@age * Math.PI / @thang.bobTime)) + updatePosition: -> return unless @thang?.pos and @options.camera? - if @thang.bobHeight - @thang.pos.z = @thang.pos.z + (Math.sin @ticker / @thang.bobTime) * 0.1 * @thang.bobHeight [p0, p1] = [@lastPos, @thang.pos] + if bobOffset = @getBobOffset() + p1 = p1.copy?() or _.clone(p1) + p1.z += bobOffset return if p0 and p0.x is p1.x and p0.y is p1.y and p0.z is p1.z and not @options.camera.tweeningZoomTo wop = x: p1.x, y: p1.y, z: if @thang.isLand then 0 else p1.z - @thang.depth / 2 sup = @options.camera.worldToSurface wop [@displayObject.x, @displayObject.y] = [sup.x, sup.y] - @lastPos = _.clone(p1) + @lastPos = p1.copy?() or _.clone(p1) @hasMoved = true updateScale: -> @@ -207,19 +212,10 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass rotation updateIsometricRotation: (rotation, imageObject) -> - action = @currentRootAction - return unless action -# @flipOccasionally() if action.name is 'idle' - imageObject ?= @imageObject - imageObject.scaleX *= -1 if imageObject.scaleX < 0 # normalize to point right - imageObject.scaleX *= -1 if Math.abs(rotation) >= 135 -# imageObject.scaleX *= -1 if @flipped and action.name is 'idle' - - flipOccasionally: -> - @flippedCount += 1 - return unless _.random(0,1000) <= 15 and @flippedCount > 30 - @flipped = not @flipped - @flippedCount = 0 + return unless @currentAction + return if _.string.endsWith(@currentAction.name, 'back') + return if _.string.endsWith(@currentAction.name, 'fore') + @imageObject.scaleX *= -1 if Math.abs(rotation) >= 90 ################################################## updateAction: -> @@ -439,4 +435,4 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass name = AudioPlayer.nameForSoundReference sound instance = createjs.Sound.play name, "none", delay, 0, 0, volume # console.log @thang?.id, "played sound", name, "with delay", delay, "volume", volume, "and got sound instance", instance - instance \ No newline at end of file + instance diff --git a/app/lib/surface/IndieSprite.coffee b/app/lib/surface/IndieSprite.coffee index 5681350a7..8e3f65dc3 100644 --- a/app/lib/surface/IndieSprite.coffee +++ b/app/lib/surface/IndieSprite.coffee @@ -21,7 +21,7 @@ module.exports = IndieSprite = class IndieSprite extends CocoSprite thang.exists = true thang.width = thang.height = thang.depth = 4 thang.pos = pos ? @defaultPos() - thang.pos.z ?= @defaultPos().z + thang.pos.z = thang.depth / 2 thang.rotation = 0 thang.action = 'idle' thang.setAction = (action) -> thang.action = action diff --git a/app/lib/surface/Mark.coffee b/app/lib/surface/Mark.coffee index 54cead432..50d45bb9d 100644 --- a/app/lib/surface/Mark.coffee +++ b/app/lib/surface/Mark.coffee @@ -137,7 +137,7 @@ module.exports = class Mark extends CocoClass if @name in ['shadow', 'debug'] pos = @camera.worldToSurface x: @sprite.thang.pos.x, y: @sprite.thang.pos.y if @name is 'shadow' - worldZ = @sprite.thang.pos.z - @sprite.thang.depth / 2 + worldZ = @sprite.thang.pos.z - @sprite.thang.depth / 2 + @sprite.getBobOffset() @mark.alpha = 0.451 / Math.sqrt(worldZ / 2 + 1) else pos ?= @sprite?.displayObject @@ -166,7 +166,7 @@ module.exports = class Mark extends CocoClass size += 60 if @name is 'selection' size += 60 if @name is 'repair' scale = size / {selection: 128, target: 128, repair: 320, highlight: 160}[@name] - if @sprite?.thang.spriteName.search(/dungeon.wall/i) isnt -1 + if @sprite?.thang.spriteName.search(/(dungeon|indoor).wall/i) isnt -1 scale *= 2 @mark.scaleX = @mark.scaleY = Math.min 1, scale if @name in ['selection', 'target', 'repair'] diff --git a/app/lib/surface/SpriteBoss.coffee b/app/lib/surface/SpriteBoss.coffee index e5da46c50..319449141 100644 --- a/app/lib/surface/SpriteBoss.coffee +++ b/app/lib/surface/SpriteBoss.coffee @@ -76,7 +76,7 @@ module.exports = class SpriteBoss extends CocoClass id ?= sprite.thang.id console.error "Sprite collision! Already have:", id if @sprites[id] @sprites[id] = sprite - layer ?= @spriteLayers["Obstacle"] if sprite.thang?.spriteName.search(/dungeon.wall/i) isnt -1 + layer ?= @spriteLayers["Obstacle"] if sprite.thang?.spriteName.search(/(dungeon|indoor).wall/i) isnt -1 layer ?= @layerForChild sprite.displayObject, sprite layer.addChild sprite.displayObject layer.updateLayerOrder() @@ -163,7 +163,8 @@ module.exports = class SpriteBoss extends CocoClass if sprite = @sprites[thang.id] sprite.setThang thang # make sure Sprite has latest Thang else - sprite = @addThangToSprites(thang) or updateOrder + sprite = @addThangToSprites(thang) + Backbone.Mediator.publish 'surface:new-thang-added', thang:thang, sprite:sprite updateCache = updateCache or sprite.displayObject.parent is @spriteLayers["Obstacle"] sprite.playSounds() for thangID, sprite of @sprites @@ -176,7 +177,7 @@ module.exports = class SpriteBoss extends CocoClass cache: (update=false) -> return if @cached and not update - wallSprites = (sprite for thangID, sprite of @sprites when sprite.thangType?.get('name') is 'Dungeon Wall') + wallSprites = (sprite for thangID, sprite of @sprites when sprite.thangType?.get('name').search(/(dungeon|indoor).wall/i) isnt -1) walls = (sprite.thang for sprite in wallSprites) @world.calculateBounds() wallGrid = new Grid walls, @world.size()... diff --git a/app/lib/surface/Surface.coffee b/app/lib/surface/Surface.coffee index 704f27220..5fef799bd 100644 --- a/app/lib/surface/Surface.coffee +++ b/app/lib/surface/Surface.coffee @@ -55,6 +55,7 @@ module.exports = Surface = class Surface extends CocoClass 'level-toggle-debug': 'onToggleDebug' 'level-set-grid': 'onSetGrid' 'level-toggle-grid': 'onToggleGrid' + 'level-toggle-pathfinding': 'onTogglePathFinding' 'level-set-time': 'onSetTime' 'level-set-surface-camera': 'onSetCamera' 'level:restarted': 'onLevelRestarted' @@ -63,9 +64,9 @@ module.exports = Surface = class Surface extends CocoClass 'level-set-letterbox': 'onSetLetterbox' shortcuts: - '\\': 'onToggleDebug' - 'g': 'onToggleGrid' - 'w': 'onTogglePathFinding' + 'ctrl+\\, ⌘+\\': 'onToggleDebug' + 'ctrl+g, ⌘+g': 'onToggleGrid' + 'ctrl+o, ⌘+o': 'onTogglePathFinding' # external functions @@ -102,19 +103,20 @@ module.exports = Surface = class Surface extends CocoClass @onFrameChanged() Backbone.Mediator.publish 'surface:world-set-up' - onTogglePathFinding: -> + onTogglePathFinding: (e) -> + e?.preventDefault?() @hidePathFinding() @showingPathFinding = not @showingPathFinding if @showingPathFinding then @showPathFinding() else @hidePathFinding() - + hidePathFinding: -> @surfaceLayer.removeChild @navRectangles if @navRectangles @surfaceLayer.removeChild @navPaths if @navPaths @navRectangles = @navPaths = null - + showPathFinding: -> @hidePathFinding() - + mesh = _.values(@world.navMeshes or {})[0] return unless mesh @navRectangles = new createjs.Container() @@ -122,7 +124,7 @@ module.exports = Surface = class Surface extends CocoClass @addMeshRectanglesToContainer mesh, @navRectangles @surfaceLayer.addChild @navRectangles @surfaceLayer.updateLayerOrder() - + graph = _.values(@world.graphs or {})[0] return @surfaceLayer.updateLayerOrder() unless graph @navPaths = new createjs.Container() @@ -130,7 +132,7 @@ module.exports = Surface = class Surface extends CocoClass @addNavPathsToContainer graph, @navPaths @surfaceLayer.addChild @navPaths @surfaceLayer.updateLayerOrder() - + addMeshRectanglesToContainer: (mesh, container) -> for rect in mesh shape = new createjs.Shape() @@ -397,14 +399,15 @@ module.exports = Surface = class Surface extends CocoClass gridShowing: -> @gridLayer?.parent? - onToggleGrid: -> + onToggleGrid: (e) -> + e?.preventDefault?() if @gridShowing() then @hideGrid() else @showGrid() onSetGrid: (e) -> if e.grid then @showGrid() else @hideGrid() onToggleDebug: (e) -> - e?.preventDefault() + e?.preventDefault?() Backbone.Mediator.publish 'level-set-debug', {debug: not @debug} onSetDebug: (e) -> @@ -455,7 +458,7 @@ module.exports = Surface = class Surface extends CocoClass @drawCurrentFrame() @onFrameChanged() @updatePaths() if (@totalFramesDrawn % 2) is 0 or createjs.Ticker.getMeasuredFPS() > createjs.Ticker.getFPS() - 5 - Backbone.Mediator.publish('surface:ticked', {}) + Backbone.Mediator.publish('surface:ticked', {dt: @world.dt}) mib = @stage.mouseInBounds if @mouseInBounds isnt mib Backbone.Mediator.publish('surface:mouse-' + (if mib then "over" else "out"), {}) diff --git a/app/lib/surface/WizardSprite.coffee b/app/lib/surface/WizardSprite.coffee index 7e4ec018c..4050fa6c0 100644 --- a/app/lib/surface/WizardSprite.coffee +++ b/app/lib/surface/WizardSprite.coffee @@ -3,8 +3,6 @@ Camera = require './Camera' {me} = require 'lib/auth' module.exports = class WizardSprite extends IndieSprite - ticker: 0 - # Wizard targets are constantly changing, so a simple tween doesn't work. # Instead, the wizard stores its origin point and the (possibly) moving target. # Then it figures out its current position based on tween percentage and @@ -16,12 +14,11 @@ module.exports = class WizardSprite extends IndieSprite reachedTarget: true spriteXOffset: 4 # meters from target sprite spriteYOffset: 0 # meters from target sprite - spriteZOffset: 1 # meters from ground (in middle of float) subscriptions: 'bus:player-states-changed': 'onPlayerStatesChanged' 'me:synced': 'onMeSynced' - 'surface:sprite-selected': 'onSpriteSelected' + 'surface:sprite-selected': 'onSpriteSelected' 'echo-self-wizard-sprite': 'onEchoSelfWizardSprite' 'echo-all-wizard-sprites': 'onEchoAllWizardSprites' @@ -38,6 +35,9 @@ module.exports = class WizardSprite extends IndieSprite makeIndieThang: (thangType, thangID, pos) -> thang = super thangType, thangID, pos thang.isSelectable = false + thang.bobHeight = 1.5 + thang.bobTime = 2 + thang.pos.z += thang.bobHeight thang onPlayerStatesChanged: (e) -> @@ -73,18 +73,8 @@ module.exports = class WizardSprite extends IndieSprite .to({scaleX: 0, scaleY: 0, alpha: 0}, 1000, createjs.Ease.getPowInOut(2.2)) tween.call(callback) if callback - # We need the generalizable tinting system included in spritesheet making - #updateColorFilters: -> - # return if @colorHue is undefined - # rgb = hslToRgb(@colorHue, 1.0, 0.75) - # rgb = (parseInt(val) / 256 for val in rgb) - # rgb = rgb.concat([1, 0, 0, 0, 0]) - # filter = new createjs.ColorFilter(rgb...) - # dob = @imageObject - # dob.filters = [filter] - # dob.cache(0, 0, @data.width, @data.height, Math.abs(dob.scaleX*2)) - setColorHue: (newColorHue) -> + # TODO: is this needed any more? return if @colorHue is newColorHue @colorHue = newColorHue #@updateColorFilters() @@ -102,8 +92,7 @@ module.exports = class WizardSprite extends IndieSprite onEchoSelfWizardSprite: (e) -> e.payload = @ if @isSelf onEchoAllWizardSprites: (e) -> e.payload.push @ - defaultPos: -> x: 35, y: 24, z: @thang.depth / 2 + @spriteZOffset - getZOffset: -> @thang.depth / 2 + @spriteZOffset + Math.sin @ticker / 20 # Cloud bobbing. + defaultPos: -> x: 35, y: 24, z: @thang.depth / 2 + @thang.bobHeight move: (pos, duration) -> @setTarget(pos, duration) setTarget: (newTarget, duration) -> @@ -196,7 +185,7 @@ module.exports = class WizardSprite extends IndieSprite """ @targetPos = @targetSprite.thang.pos if @targetSprite pos = _.clone(@targetPos) - pos.z = @getZOffset() + pos.z = @defaultPos().z + @getBobOffset() @adjustPositionToSideOfTarget(pos) if @targetSprite # be off to the side depending on placement in world return pos if @reachedTarget # stick like glue @@ -227,10 +216,5 @@ module.exports = class WizardSprite extends IndieSprite if @targetSprite @pointToward(@targetSprite.thang.pos) - updateIsometricRotation: (rotation, imageObject) -> - super rotation, imageObject - imageObject ?= @imageObject - imageObject.scaleX *= -1 if Math.abs(rotation) <= 45 or Math.abs(rotation) >= 135 # reverse it - updateMarks: -> super() if @displayObject.visible # not if we hid the wiz diff --git a/app/lib/world/names.coffee b/app/lib/world/names.coffee index 30e1639dc..c2303cc77 100644 --- a/app/lib/world/names.coffee +++ b/app/lib/world/names.coffee @@ -1,5 +1,5 @@ module.exports.thangNames = thangNames = - "Soldier": [ + "Soldier M": [ "William" "Lucas" "Marcus" @@ -45,16 +45,18 @@ module.exports.thangNames = thangNames = "Sterling" "Alistair" "Remy" - "Lana" "Stormy" "Halle" + "Sage" + ] + "Soldier F": [ "Sarah" "Alexandra" "Holly" "Trinity" "Nikita" "Alana" - "Sage" + "Lana" ] "Peasant": [ "Yorik" @@ -77,7 +79,7 @@ module.exports.thangNames = thangNames = "Bernadette" "Hershell" ] - "Archer": [ + "Archer F": [ "Phoebe" "Mira" "Agapi" @@ -98,13 +100,15 @@ module.exports.thangNames = thangNames = "Clare" "Rowan" "Omar" - "Brian" - "Cole" "Alden" "Cairn" "Jensen" ] - "Ogre Munchkin": [ + "Archer M": [ + "Brian" + "Cole" + ] + "Ogre Munchkin M": [ "Brack" "Gort" "Weeb" @@ -120,15 +124,17 @@ module.exports.thangNames = thangNames = "Skoggen" "Treg" "Goreball" - "Shmeal" "Gert" "Thabt" - "Iyert" - "Palt" "Snortt" "Kog" ] - "Ogre": [ + "Ogre Munchkin F": [ + "Iyert" + "Palt" + "Shmeal" + ] + "Ogre M": [ "Krogg" "Dronck" "Trogdor" @@ -137,6 +143,8 @@ module.exports.thangNames = thangNames = "Mak Fod" "Trung" "Axe Ox" + ] + "Ogre F": [ "Nareng" "Morthrug" "Glonc" diff --git a/app/lib/world/rand.coffee b/app/lib/world/rand.coffee index dc6102a4e..0def76c4c 100644 --- a/app/lib/world/rand.coffee +++ b/app/lib/world/rand.coffee @@ -32,8 +32,4 @@ class Rand rand2: (min, max) => min + @rand max - min - # return an array of numbers from 0 to n-1, shuffled - randArray: (n) => - _.shuffle [0...n] - module.exports = Rand \ No newline at end of file diff --git a/app/lib/world/rectangle.coffee b/app/lib/world/rectangle.coffee index e87fbac6c..f4f5400a4 100644 --- a/app/lib/world/rectangle.coffee +++ b/app/lib/world/rectangle.coffee @@ -8,6 +8,8 @@ class Rectangle Rectangle[name] = (a, b) -> a.copy()[name](b) + apiProperties: ['x', 'y', 'width', 'height', 'rotation', 'getPos', 'vertices', 'touchesRect', 'touchesPoint', 'distanceToPoint', 'containsPoint', 'copy'] + constructor: (@x=0, @y=0, @width=0, @height=0, @rotation=0) -> copy: -> @@ -114,4 +116,7 @@ class Rectangle @deserialize: (o, world, classMap) -> new Rectangle o.x, o.y, o.w, o.h, o.r + serializeForAether: -> @serialize() + @deserializeFromAether: (o) -> @deserialize o + module.exports = Rectangle diff --git a/app/lib/world/script_event_prereqs.coffee b/app/lib/world/script_event_prereqs.coffee index fa250f7ce..128a8f6bd 100644 --- a/app/lib/world/script_event_prereqs.coffee +++ b/app/lib/world/script_event_prereqs.coffee @@ -10,7 +10,9 @@ module.exports.scriptMatchesEventPrereqs = scriptMatchesEventPrereqs = (script, return false if ap.greaterThanOrEqualTo? and not (v >= ap.greaterThanOrEqualTo) return false if ap.lessThan? and not (v < ap.lessThan) return false if ap.lessThanOrEqualTo? and not (v <= ap.lessThanOrEqualTo) - return false if ap.containingString? and v?.search(ap.containingString) == -1 - return false if ap.notContainingString? and v?.search(ap.containingString) != -1 + return false if ap.containingString? and (not v or v.search(ap.containingString) is -1) + return false if ap.notContainingString? and v?.search(ap.notContainingString) isnt -1 + return false if ap.containingRegexp? and (not v or v.search(new RegExp(ap.containingRegexp)) is -1) + return false if ap.notContainingRegexp? and v?.search(new RegExp(ap.notContainingRegexp)) isnt -1 return true diff --git a/app/lib/world/thang.coffee b/app/lib/world/thang.coffee index 11de09ae3..6e909cb2f 100644 --- a/app/lib/world/thang.coffee +++ b/app/lib/world/thang.coffee @@ -4,44 +4,31 @@ ThangState = require './thang_state' Rand = require './rand' module.exports = class Thang - @className: "Thang" - @random = new Rand + @className: 'Thang' + @remainingThangNames: {} - # Random ordering for each sprite name - @ordering: (spriteName) -> - Thang.orders ?= {} - names = thangNames[spriteName] - if names - len = names.length - array = Thang.orders[spriteName] - unless array? - array = @random.randArray len - Thang.orders[spriteName] = array - else - array = [] - array - - @nextID: (spriteName) -> + @nextID: (spriteName, world) -> Thang.lastIDNums ?= {} - names = thangNames[spriteName] - order = @ordering spriteName - if names - lastIDNum = Thang.lastIDNums[spriteName] - idNum = (if lastIDNum? then lastIDNum + 1 else 0) - Thang.lastIDNums[spriteName] = idNum - id = names[order[idNum % names.length]] - if idNum >= names.length - id += Math.floor(idNum / names.length) + 1 - else - Thang.lastIDNums[spriteName] = if Thang.lastIDNums[spriteName]? then Thang.lastIDNums[spriteName] + 1 else 0 - id = spriteName + (Thang.lastIDNums[spriteName] or '') - id + originals = thangNames[spriteName] or [spriteName] + remaining = Thang.remainingThangNames[spriteName] + remaining = Thang.remainingThangNames[spriteName] = originals.slice() unless remaining?.length - @resetThangIDs: -> Thang.lastIDNums = {} + baseName = remaining.splice(world.rand.rand(remaining.length), 1)[0] + i = 0 + while true + name = if i then "#{baseName} #{i}" else baseName + extantThang = world.thangMap[name] + break unless extantThang + i++ + name + + @resetThangIDs: -> Thang.remainingThangNames = {} + + apiProperties: ['id', 'spriteName', 'health', 'pos', 'team'] constructor: (@world, @spriteName, @id) -> @spriteName ?= @constructor.className - @id ?= @constructor.nextID @spriteName + @id ?= @constructor.nextID @spriteName, @world @addTrackedProperties ['exists', 'boolean'] # TODO: move into Systems/Components, too? #console.log "Generated #{@toString()}." @@ -158,6 +145,9 @@ module.exports = class Thang t[prop] = val t + serializeForAether: -> + {CN: @constructor.className, id: @id} + getSpriteOptions: -> colorConfigs = @world?.getTeamColors() or {} options = {} diff --git a/app/lib/world/vector.coffee b/app/lib/world/vector.coffee index 1427879fc..dd9efe891 100644 --- a/app/lib/world/vector.coffee +++ b/app/lib/world/vector.coffee @@ -8,6 +8,7 @@ class Vector a.copy()[name](b, useZ) isVector: true + apiProperties: ['x', 'y', 'magnitude', 'heading', 'distance', 'dot', 'equals', 'copy'] constructor: (@x=0, @y=0, @z=0) -> @@ -119,4 +120,7 @@ class Vector @deserialize: (o, world, classMap) -> new Vector o.x, o.y, o.z + serializeForAether: -> @serialize() + @deserializeFromAether: (o) -> @deserialize o + module.exports = Vector diff --git a/app/lib/world/world.coffee b/app/lib/world/world.coffee index 1d5b2ee34..1ff7a6101 100644 --- a/app/lib/world/world.coffee +++ b/app/lib/world/world.coffee @@ -14,6 +14,9 @@ DESERIALIZATION_INTERVAL = 20 module.exports = class World @className: "World" + age: 0 + ended: false + apiProperties: ['age', 'dt'] constructor: (name, @userCodeMap, classMap) -> # classMap is needed for deserializing Worlds, Thangs, and other classes @classMap = classMap ? {Vector: Vector, Rectangle: Rectangle, Thang: Thang} @@ -28,8 +31,6 @@ module.exports = class World @scriptNotes = [] @rand = new Rand 0 @frames = [new WorldFrame(@, 0)] - age: 0 - ended: false # --- This config needs to move into Systems config --- TODO playableTeams: ["humans"] @@ -221,7 +222,7 @@ module.exports = class World channel = 'world:' + channel for script in @scripts continue if script.channel isnt channel - scriptNote = new WorldScriptNote script, event, world + scriptNote = new WorldScriptNote script, event continue if scriptNote.invalid @scriptNotes.push scriptNote return unless @goalManager diff --git a/app/lib/world/world_frame.coffee b/app/lib/world/world_frame.coffee index 5891b8ad0..997cf548f 100644 --- a/app/lib/world/world_frame.coffee +++ b/app/lib/world/world_frame.coffee @@ -38,11 +38,11 @@ module.exports = class WorldFrame map = ((' ' for x in [0 .. @world.width]) \ for y in [0 .. @world.height]) symbols = ".ox@dfga[]/D" - for thang, i in @thangs + for thang, i in @world.thangs when thang.rectangle rect = thang.rectangle().axisAlignedBoundingBox() for y in [Math.floor(rect.y - rect.height / 2) ... Math.ceil(rect.y + rect.height / 2)] for x in [Math.floor(rect.x - rect.width / 2) ... Math.ceil(rect.x + rect.width / 2)] - map[y][x] = symbols[i] + map[y][x] = symbols[i % symbols.length] if 0 <= y < @world.height and 0 <= x < @world.width @time + "\n" + (xs.join(' ') for xs in map).join('\n') + '\n' serialize: (frameIndex, trackedPropertiesThangIDs, trackedPropertiesPerThangIndices, trackedPropertiesPerThangTypes, trackedPropertiesPerThangValues, specialValuesToKeys, specialKeysToValues) -> diff --git a/app/locale/cs.coffee b/app/locale/cs.coffee index ec290ae80..f08ad7d3a 100644 --- a/app/locale/cs.coffee +++ b/app/locale/cs.coffee @@ -1,441 +1,440 @@ module.exports = nativeDescription: "čeština", englishDescription: "Czech", translation: common: - loading: "Loading..." -# saving: "Saving..." -# sending: "Sending..." -# cancel: "Cancel" -# save: "Save" -# delay_1_sec: "1 second" -# delay_3_sec: "3 seconds" -# delay_5_sec: "5 seconds" -# manual: "Manual" -# fork: "Fork" -# play: "Play" + loading: "Načítání..." + saving: "Ukládání..." + sending: "Odesílání..." + cancel: "Zrušit" + save: "Uložit" + delay_1_sec: "1 vteřina" + delay_3_sec: "3 vteřiny" + delay_5_sec: "5 vteřin" + manual: "Ručně" + fork: "Klonovat" + play: "Přehrát" -# modal: -# close: "Close" -# okay: "Okay" + modal: + close: "Zavřít" + okay: "Budiž" -# not_found: -# page_not_found: "Page not found" + not_found: + page_not_found: "Stránka nenalezena" -# nav: -# play: "Levels" -# editor: "Editor" -# blog: "Blog" -# forum: "Forum" -# admin: "Admin" -# home: "Home" -# contribute: "Contribute" -# legal: "Legal" -# about: "About" -# contact: "Contact" -# twitter_follow: "Follow" -# employers: "Employers" + nav: + play: "Úrovně" + editor: "Editor" + blog: "Blog" + forum: "Fórum" + admin: "Admin" + home: "Domů" + contribute: "Přispívat" + legal: "Licence" + about: "O programu" + contact: "Kontakt" + twitter_follow: "Sledovat na twitteru" + employers: "Pro zaměstnavatele" -# versions: -# save_version_title: "Save New Version" -# new_major_version: "New Major Version" -# cla_prefix: "To save changes, first you must agree to our" -# cla_url: "CLA" -# cla_suffix: "." -# cla_agree: "I AGREE" + versions: + save_version_title: "Uložit novou Verzi" + new_major_version: "Nová hlavní Verze" + cla_prefix: "Před uložením musíte souhlasit s" + cla_url: "licencí" + cla_suffix: "." + cla_agree: "SOUHLASÍM" -# login: -# sign_up: "Create Account" -# log_in: "Log In" -# log_out: "Log Out" -# recover: "recover account" + login: + sign_up: "Vytvořit účet" + log_in: "Přihlásit" + log_out: "Odhlásit" + recover: "obnovit účet" -# recover: -# recover_account_title: "Recover Account" -# send_password: "Send Recovery Password" + recover: + recover_account_title: "Obnovení účtu" + send_password: "Zaslat nové heslo" -# signup: -# create_account_title: "Create Account to Save Progress" -# description: "It's free. Just need a couple things and you'll be good to go:" -# email_announcements: "Receive announcements by email" -# coppa: "13+ or non-USA " -# coppa_why: "(Why?)" -# creating: "Creating Account..." -# sign_up: "Sign Up" -# log_in: "log in with password" + signup: + create_account_title: "Vytvořit účet k uložení úrovně" + description: "Registrace je zdarma. Vyplňte pouze několik údajů:" + email_announcements: "Dostávat novinky emailem" + coppa: "starší 13 let nebo nejste z USA " + coppa_why: "(Proč?)" + creating: "Vytvářím účet..." + sign_up: "Přihlášení" + log_in: "zadejte vaše heslo" -# home: -# slogan: "Learn to Code JavaScript by Playing a Game" -# no_ie: "CodeCombat does not run in Internet Explorer 9 or older. Sorry!" -# no_mobile: "CodeCombat wasn't designed for mobile devices and may not work!" -# play: "Play" + home: + slogan: "Naučte se programování JavaScriptu při hraní více-hráčové programovací hry." + no_ie: "Omlouváme se, ale CodeCombat boužel nefunguje v Internet Exploreru 9 nebo starším." + no_mobile: "CodeCombat není navržen pro mobilní zařízení a nemusí fungovat správně!" + play: "Hrát" -# play: -# choose_your_level: "Choose Your Level" -# adventurer_prefix: "You can jump to any level below, or discuss the levels on " -# adventurer_forum: "the Adventurer forum" -# adventurer_suffix: "." -# campaign_beginner: "Beginner Campaign" -# campaign_beginner_description: "... in which you learn the wizardry of programming." -# campaign_dev: "Random Harder Levels" -# campaign_dev_description: "... in which you learn the interface while doing something a little harder." -# campaign_multiplayer: "Multiplayer Arenas" -# campaign_multiplayer_description: "... in which you code head-to-head against other players." -# campaign_player_created: "Player-Created" -# campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards." -# level_difficulty: "Difficulty: " + play: + choose_your_level: "Zvolte si úroveň" + adventurer_prefix: "Můžete přejít do dalších úrovní, nebo debatovat o úrovních na " + adventurer_forum: "fóru Dobrodruhů" + adventurer_suffix: "." + campaign_beginner: "Začátečnická úroveň" + campaign_beginner_description: "...ve které se naučíte kouzla programování." + campaign_dev: "Náhodné težší úrovně" + campaign_dev_description: "...ve kterých se dozvíte více o prostředí při plnění těžších úkolů." + campaign_multiplayer: "Multiplayer Aréna" + campaign_multiplayer_description: "...ve které programujete proti jiným hráčům." + campaign_player_created: "Uživatelsky vytvořené úrovně" + campaign_player_created_description: "...ve kterých bojujete proti kreativitě ostatních Zdatných Kouzelníků." + level_difficulty: "Obtížnost: " -# contact: -# contact_us: "Contact CodeCombat" -# welcome: "Good to hear from you! Use this form to send us email. " -# contribute_prefix: "If you're interested in contributing, check out our " -# contribute_page: "contribute page" -# contribute_suffix: "!" -# forum_prefix: "For anything public, please try " -# forum_page: "our forum" -# forum_suffix: " instead." -# send: "Send Feedback" + contact: + contact_us: "Konktujte CodeCombat" + welcome: "Rádi od vás uslyšíme. Použijte tento formulář pro odeslání emailu. " + contribute_prefix: "Chcete-li nám přispět, prohlédněte si naši stránku " + contribute_page: "přispivatelů" + contribute_suffix: "!" + forum_prefix: "Pro ostatní veřejné věci, prosím zkuste " + forum_page: "naše fórum" + forum_suffix: "." + send: "Odeslat připomínku" diplomat_suggestion: -# title: "Help translate CodeCombat!" -# sub_heading: "We need your language skills." - pitch_body: "We develop CodeCombat in English, but we already have players all over the world. Many of them want to play in Czech but don't speak English, so if you can speak both, please consider signing up to be a Diplomat and help translate both the CodeCombat website and all the levels into Czech." - missing_translations: "Until we can translate everything into Czech, you'll see English when Czech isn't available." -# learn_more: "Learn more about being a Diplomat" -# subscribe_as_diplomat: "Subscribe as a Diplomat" + title: "Pomozte přeložit CodeCombat!" + sub_heading: "Potřebujeme vaše dovednosti." + pitch_body: "Přestože vyvíjíme CodeCombat v angličtině, máme spoustu hráčů z celého světa a mnozí z nich by si rádi zahráli česky, neboť anglicky neumí. Pokud anglicky umíte, přihlaste se prosím jako Diplomat a pomozte nám v překladu webu i jednotlivých úrovní." + missing_translations: "Dokud nebude vše přeloženo, bude se vám na zatím nepřeložených místech zobrazovat text anglicky." + learn_more: "Dozvědět se více o Diplomatech" + subscribe_as_diplomat: "Přihlásit se jako Diplomat" -# wizard_settings: -# title: "Wizard Settings" -# customize_avatar: "Customize Your Avatar" + wizard_settings: + title: "Nastavení Kouzelníka" + customize_avatar: "Upravte vás Avatar" -# account_settings: -# title: "Account Settings" -# not_logged_in: "Log in or create an account to change your settings." -# autosave: "Changes Save Automatically" -# me_tab: "Me" -# picture_tab: "Picture" -# wizard_tab: "Wizard" -# password_tab: "Password" -# emails_tab: "Emails" -# gravatar_select: "Select which Gravatar photo to use" -# gravatar_add_photos: "Add thumbnails and photos to a Gravatar account for your email to choose an image." -# gravatar_add_more_photos: "Add more photos to your Gravatar account to access them here." -# wizard_color: "Wizard Clothes Color" -# new_password: "New Password" -# new_password_verify: "Verify" -# email_subscriptions: "Email Subscriptions" -# email_announcements: "Announcements" -# email_notifications_description: "Get periodic notifications for your account." -# email_announcements_description: "Get emails on the latest news and developments at CodeCombat." -# contributor_emails: "Contributor Class Emails" -# contribute_prefix: "We're looking for people to join our party! Check out the " -# contribute_page: "contribute page" -# contribute_suffix: " to find out more." -# email_toggle: "Toggle All" -# error_saving: "Error Saving" -# saved: "Changes Saved" -# password_mismatch: "Password does not match." + account_settings: + title: "Nastavení účtu" + not_logged_in: "Přihlaste se, nebo vytvořte si účet pro uložení nastavení." + autosave: "Automatické ukládání změn" + me_tab: "O mne" + picture_tab: "Obrázek" + wizard_tab: "Kouzelník" + password_tab: "Heslo" + emails_tab: "Emaily" + gravatar_select: "Zvolte kterou Gravatar fotografii použít" + gravatar_add_photos: "Přidat náhledy a fotografie do Gravatar účtu pro zvolení obrázku" + gravatar_add_more_photos: "Přidat do vašeho Gravatar účtu další fotografie." + wizard_color: "Barva Kouzelníkova oblečení" + new_password: "Nové heslo" + new_password_verify: "Potvrdit" + email_subscriptions: "Doručovat emailem" + email_announcements: "Oznámení" + email_notifications_description: "Zasílat na váš účet opakovaná oznámení." + email_announcements_description: "Zasílat emaily o posledních novinkách a o postupu ve vývoji CodeCombat." + contributor_emails: "Emaily pro přispívatele" + contribute_prefix: "Hledáme další přispívatele! Čtěte prosím " + contribute_page: "stránku přispívatelům" + contribute_suffix: " pro více informací." + email_toggle: "Zvolit vše" + error_saving: "Chyba při ukládání" + saved: "Změny uloženy" + password_mismatch: "Hesla nesouhlasí." -# account_profile: -# edit_settings: "Edit Settings" -# profile_for_prefix: "Profile for " -# profile_for_suffix: "" -# profile: "Profile" -# user_not_found: "No user found. Check the URL?" -# gravatar_not_found_mine: "We couldn't find your profile associated with:" -# gravatar_not_found_email_suffix: "." -# gravatar_signup_prefix: "Sign up at " -# gravatar_signup_suffix: " to get set up!" -# gravatar_not_found_other: "Alas, there's no profile associated with this person's email address." -# gravatar_contact: "Contact" -# gravatar_websites: "Websites" -# gravatar_accounts: "As Seen On" -# gravatar_profile_link: "Full Gravatar Profile" + account_profile: + edit_settings: "Editovat Nastavení" + profile_for_prefix: "Profil pro " + profile_for_suffix: "" + profile: "Profil" + user_not_found: "Uživatel nenalezen. Zkontrolujte adresu URL?" + gravatar_not_found_mine: "Nenalezli jsme profil asociovaný s:" + gravatar_not_found_email_suffix: "." + gravatar_signup_prefix: "Přihlásit se " + gravatar_signup_suffix: " k nastavení!" + gravatar_not_found_other: "Bohužel, neexistuje profil asociovaný s touto emailovou adresou." + gravatar_contact: "Kontakt" + gravatar_websites: "Weby" + gravatar_accounts: "Jak zobrazeno na" + gravatar_profile_link: "Účet Gravatar" -# play_level: -# level_load_error: "Level could not be loaded." -# done: "Done" -# grid: "Grid" -# customize_wizard: "Customize Wizard" -# home: "Home" -# guide: "Guide" -# multiplayer: "Multiplayer" -# restart: "Restart" -# goals: "Goals" -# action_timeline: "Action Timeline" -# click_to_select: "Click on a unit to select it." -# reload_title: "Reload All Code?" -# reload_really: "Are you sure you want to reload this level back to the beginning?" -# reload_confirm: "Reload All" -# victory_title_prefix: "" -# victory_title_suffix: " Complete" -# victory_sign_up: "Sign Up to Save Progress" -# victory_sign_up_poke: "Want to save your code? Create a free account!" -# victory_rate_the_level: "Rate the level: " -# victory_play_next_level: "Play Next Level" -# victory_go_home: "Go Home" -# victory_review: "Tell us more!" -# victory_hour_of_code_done: "Are You Done?" -# victory_hour_of_code_done_yes: "Yes, I'm finished with my Hour of Code!" -# multiplayer_title: "Multiplayer Settings" -# multiplayer_link_description: "Give this link to anyone to have them join you." -# multiplayer_hint_label: "Hint:" -# multiplayer_hint: " Click the link to select all, then press ⌘-C or Ctrl-C to copy the link." -# multiplayer_coming_soon: "More multiplayer features to come!" -# guide_title: "Guide" -# tome_minion_spells: "Your Minions' Spells" -# tome_read_only_spells: "Read-Only Spells" -# tome_other_units: "Other Units" -# tome_cast_button_castable: "Cast" -# tome_cast_button_casting: "Casting" -# tome_cast_button_cast: "Spell Cast" -# tome_autocast_delay: "Autocast Delay" -# tome_select_spell: "Select a Spell" -# tome_select_a_thang: "Select Someone for " -# tome_available_spells: "Available Spells" -# hud_continue: "Continue (press shift-space)" -# spell_saved: "Spell Saved" + play_level: + level_load_error: "Úroveň se nepodařilo otevřít." + done: "Hotovo" + grid: "Mřížka" + customize_wizard: "Upravit Kouzelníka" + home: "Domů" + guide: "Průvodce" + multiplayer: "Multiplayer" + restart: "Restartovat" + goals: "Cíl" + action_timeline: "Časová osa" + click_to_select: "Vyberte kliknutím." + reload_title: "Znovunačíst veškerý kód?" + reload_really: "Opravdu chcete resetovat tuto úroveň do počátečního stavu?" + reload_confirm: "Znovu načíst vše" + victory_title_prefix: "" + victory_title_suffix: " Hotovo" + victory_sign_up: "Přihlásit se pro uložení postupu" + victory_sign_up_poke: "Chcete uložit váš kód? Vytvořte si účet zdarma!" + victory_rate_the_level: "Ohodnoťte tuto úroveň: " + victory_play_next_level: "Hrát další úroveň" + victory_go_home: "Přejít domů" + victory_review: "Připomínky!" + victory_hour_of_code_done: "Skončili jste?" + victory_hour_of_code_done_yes: "Ano, pro dnešek jsem skončil!" + multiplayer_title: "Nastavení Multiplayeru" + multiplayer_link_description: "Sdílejte tento odkaz s lidmi, kteří se k vám mohou přidat ve hře." + multiplayer_hint_label: "Tip:" + multiplayer_hint: " Klikněte na odkaz pro jeho výběr, poté stiskněte ⌘-C nebo Ctrl-C pro kopírování odkazu." + multiplayer_coming_soon: "Další vlastnosti multiplayeru jsou na cestě!" + guide_title: "Průvodce" + tome_minion_spells: "Vaše oblíbená kouzla" + tome_read_only_spells: "Kouzla jen pro čtení" + tome_other_units: "Ostatní jednotky" + tome_cast_button_castable: "Spustit" + tome_cast_button_casting: "Spouštění" + tome_cast_button_cast: "Spustit Kouzlo" + tome_autocast_delay: "Prodleva Autospouštení" + tome_select_spell: "Zvolte Kouzlo" + tome_select_a_thang: "Zvolte někoho pro " + tome_available_spells: "Dostupná kouzla" + hud_continue: "Pokračovat (stiskněte shift-mezera)" + spell_saved: "Kouzlo uloženo" -# admin: -# av_title: "Admin Views" -# av_entities_sub_title: "Entities" -# av_entities_users_url: "Users" -# av_entities_active_instances_url: "Active Instances" -# av_other_sub_title: "Other" -# av_other_debug_base_url: "Base (for debugging base.jade)" -# u_title: "User List" -# lg_title: "Latest Games" + admin: + av_title: "Administrátorský pohled" + av_entities_sub_title: "Entity" + av_entities_users_url: "Uživatelé" + av_entities_active_instances_url: "Aktivní instance" + av_other_sub_title: "Ostatní" + av_other_debug_base_url: "Base (pro debugování base.jade)" + u_title: "Seznam uživatelů" + lg_title: "Poslední hry" -# editor: -# main_title: "CodeCombat Editors" -# main_description: "Build your own levels, campaigns, units and educational content. We provide all the tools you need!" -# article_title: "Article Editor" -# article_description: "Write articles that give players overviews of programming concepts which can be used across a variety of levels and campaigns." -# thang_title: "Thang Editor" -# thang_description: "Build units, defining their default logic, graphics and audio. Currently only supports importing Flash exported vector graphics." -# level_title: "Level Editor" -# level_description: "Includes the tools for scripting, uploading audio, and constructing custom logic to create all sorts of levels. Everything we use ourselves!" -# security_notice: "Many major features in these editors are not currently enabled by default. As we improve the security of these systems, they will be made generally available. If you'd like to use these features sooner, " -# contact_us: "contact us!" -# hipchat_prefix: "You can also find us in our" -# hipchat_url: "HipChat room." -# level_some_options: "Some Options?" -# level_tab_thangs: "Thangs" -# level_tab_scripts: "Scripts" -# level_tab_settings: "Settings" -# level_tab_components: "Components" -# level_tab_systems: "Systems" -# level_tab_thangs_title: "Current Thangs" -# level_tab_thangs_conditions: "Starting Conditions" -# level_tab_thangs_add: "Add Thangs" -# level_settings_title: "Settings" -# level_component_tab_title: "Current Components" -# level_component_btn_new: "Create New Component" -# level_systems_tab_title: "Current Systems" -# level_systems_btn_new: "Create New System" -# level_systems_btn_add: "Add System" -# level_components_title: "Back to All Thangs" -# level_components_type: "Type" -# level_component_edit_title: "Edit Component" -# level_system_edit_title: "Edit System" -# create_system_title: "Create New System" -# new_component_title: "Create New Component" -# new_component_field_system: "System" + editor: + main_title: "Editory CodeCombatu" + main_description: "Vytvořte vlastní úrovně, kampaně, jednotky a vzdělávací obsah. My vám poskytujeme všechny potřebné nástroje!" + article_title: "Editor článků" + article_description: "Napište články, které objasní hráčům koncepty programování využitelné v úrovních a kampaních." + thang_title: "Editor Thangů - objektů" + thang_description: "Vytvořte jednotky, definujte jejich logiku, vlastnosti, grafiku a zvuk. Momentálně jsou podporovány pouze importy vektorové grafiky exportované z Flashe." + level_title: "Editor úrovní" + level_description: "Zahrnuje pomůcky pro skriptování, nahrávání audia a tvorbu vlastní logiky pro vytvoření vlastních úrovní. Obsahuje vše, čeho využíváme k tvorbě úrovní my!" + security_notice: "Velké množství důležitých funkcí těchto editorů je standardně vypnuto. Jak postupem času vylepšujeme bezpečnost celého systému, jsou tyto funkce uvolňovány k veřejnému použití. Potřebujete-li některé funkce dříve, " + contact_us: "kontaktujte nás!" + hipchat_prefix: "Můžete nás také najít v naší" + hipchat_url: "HipChat diskusní místnosti." + level_some_options: "Volby?" + level_tab_thangs: "Thangy" + level_tab_scripts: "Skripty" + level_tab_settings: "Nastavení" + level_tab_components: "Komponenty" + level_tab_systems: "Systémy" + level_tab_thangs_title: "Současné Thangy" + level_tab_thangs_conditions: "Výchozí prostředí" + level_tab_thangs_add: "Přidat Thangy" + level_settings_title: "Nastavení" + level_component_tab_title: "Současné komponenty" + level_component_btn_new: "Vytvořit novou komponentu" + level_systems_tab_title: "Současné systémy" + level_systems_btn_new: "Vytvořit nový systém" + level_systems_btn_add: "Přidat systém" + level_components_title: "Zpět na všechny Thangy" + level_components_type: "Druh" + level_component_edit_title: "Editovat komponentu" + level_system_edit_title: "Editovat systém" + create_system_title: "Vytvořit nový systém" + new_component_title: "Vytvořit novou komponentu" + new_component_field_system: "Systém" + article: + edit_btn_preview: "Náhled" + edit_article_title: "Editovat článek" -# article: -# edit_btn_preview: "Preview" -# edit_article_title: "Edit Article" + general: + and: "a" + name: "Jméno" + body: "Tělo" + version: "Verze" + commit_msg: "Popisek ukládání" + version_history_for: "Verze historie pro: " + results: "Výsledky" + description: "Popis" + or: "nebo" + email: "Email" + message: "Zpráva" -# general: -# and: "and" -# name: "Name" -# body: "Body" -# version: "Version" -# commit_msg: "Commit Message" -# version_history_for: "Version History for: " -# results: "Results" -# description: "Description" -# or: "or" -# email: "Email" -# message: "Message" + about: + who_is_codecombat: "Kdo je CodeCombat?" + why_codecombat: "Proč CodeCombat?" + who_description_prefix: "společně přišli s projektem CodeCombat v roce 2013. V roce 2008 jsme vytvořili také " + who_description_suffix: ", jedničku mezi webovými a IOS aplikacemi pro učení psaní japonských a čínských znaků." + who_description_ending: "Nyní nastal čas pomoci lidem s programováním." + why_paragraph_1: "Při vytváření Skritteru neznal George základy programování a byl neustále frustrován svou neschopností implementovat vlastní nápady. Zkoušel se naučit programovat, ale lekce programování byly na něj příliš pomalé. Jeho spolubydlící se rozhodl o rekvalifikaci a tak zkusil Codeacademy, ale brzy toho nechal s tím, že je to příliš velká nuda. Týden co týden se někdo z Georgových přátel pokoušel využít Codeacademyk učení programování, ale po chvíli odpadl. Uvědomili jsme si, že se jedná o stejný problém, který jsme již vyřešili při tvorbě Skitteru: lidé se pokouší učit na pomalých, intenzivních teoretických lekcích, ale místo toho potřebují rychlé, ale obsáhlé praktické cvičení. A na tento problém známe řešení." + why_paragraph_2: "Potřebujete se naučit programovat? Pak nepotřebujete lekce, potřebuje příležitost psát spoustu kódu a při tom se u toho dobře bavit." + why_paragraph_3_prefix: "To je to o čem musí programování být. Ne rádoby zábava typu" + why_paragraph_3_italic: "hmm, další odznáček" + why_paragraph_3_center: "ale nadšení typu" + why_paragraph_3_italic_caps: "POČKEJ MAMI, MUSÍM DOKONČIT ÚROVEŇ!" + why_paragraph_3_suffix: "Proto je CodeCombat opravdová multiplayer hra, ne lekce kurzu s herními odznáčky. Neskončí, dokud sami nepřestanete, což je tentokrát dobrá věc." + why_paragraph_4: "A jestli se máte stát závislými na nějaké hře, pak ať je to hra tato, a staňte se díky tomu kouzelníky a odborníky v této technické době." + why_ending: "A mimochodem - je to zdarma. " + why_ending_url: "Začněte kouzlit!" + george_description: "CEO, obchodník, návrhář webů i her a šampión všech začátečníků programování." + scott_description: "Výtečný programátor, softwarový architekt, kouzelník v kuchyni i pán financí. Scott je v týmu pan rozumný." + nick_description: "Programátorský kouzelník, excentrický motivační mág i experimentátor. Nick by mohl dělat de-facto cokoliv, ale zvolil si vytvořit CodeCombat." + jeremy_description: "Mistr zákaznické podpory, tester použitelnosti a organizátor komunity. Je velmi pravděpodobné, že jste si spolu již psali." + michael_description: "Programátor, systémový administrátor a král podsvětí technického zázemí. Michael udržuje naše servery online." -# about: -# who_is_codecombat: "Who is CodeCombat?" -# why_codecombat: "Why CodeCombat?" -# who_description_prefix: "together started CodeCombat in 2013. We also created " -# who_description_suffix: "in 2008, growing it to the #1 web and iOS application for learning to write Chinese and Japanese characters." -# who_description_ending: "Now it's time to teach people to write code." -# why_paragraph_1: "When making Skritter, George didn't know how to program and was constantly frustrated by his inability to implement his ideas. Afterwards, he tried learning, but the lessons were too slow. His housemate, wanting to reskill and stop teaching, tried Codecademy, but \"got bored.\" Each week another friend started Codecademy, then dropped off. We realized it was the same problem we'd solved with Skritter: people learning a skill via slow, intensive lessons when what they need is fast, extensive practice. We know how to fix that." -# why_paragraph_2: "Need to learn to code? You don't need lessons. You need to write a lot of code and have a great time doing it." -# why_paragraph_3_prefix: "That's what programming is about. It's gotta be fun. Not fun like" -# why_paragraph_3_italic: "yay a badge" -# why_paragraph_3_center: "but fun like" -# why_paragraph_3_italic_caps: "NO MOM I HAVE TO FINISH THE LEVEL!" -# why_paragraph_3_suffix: "That's why CodeCombat is a multiplayer game, not a gamified lesson course. We won't stop until you can't stop--but this time, that's a good thing." -# why_paragraph_4: "If you're going to get addicted to some game, get addicted to this one and become one of the wizards of the tech age." -# why_ending: "And hey, it's free. " -# why_ending_url: "Start wizarding now!" -# george_description: "CEO, business guy, web designer, game designer, and champion of beginning programmers everywhere." -# scott_description: "Programmer extraordinaire, software architect, kitchen wizard, and master of finances. Scott is the reasonable one." -# nick_description: "Programming wizard, eccentric motivation mage, and upside-down experimenter. Nick can do anything and chooses to build CodeCombat." -# jeremy_description: "Customer support mage, usability tester, and community organizer; you've probably already spoken with Jeremy." -# michael_description: "Programmer, sys-admin, and undergrad technical wunderkind, Michael is the person keeping our servers online." + legal: + page_title: "Licence" + opensource_intro: "CodeCombat je zdarma a plně open source." + opensource_description_prefix: "Podívejte se na " + github_url: "naši stránku na GitHubu" + opensource_description_center: "a pokud se vám chce, můžete i pomoct! CodeCombat je vystavěn na několika oblíbených svobodných projektech. Podívejte se na" + archmage_wiki_url: "naši wiki Arcikouzelníků " + opensource_description_suffix: "pro seznam projektů, díky kterým může tato hra existovat." + practices_title: "Doporučené postupy" + practices_description: "Toto je příslib našeho přístupu v jednoduchém jazyce." + privacy_title: "Soukromí" + privacy_description: "Neprodáme vaše osobní informace. Náš plán na zhodnocení je založen na poskytování pracovních příležitostí, přesto si můžete být jisti, že vaše osobní informace nebudou distribuovány bez vašeho plného souhlasu." + security_title: "Zabezpečení" + security_description: "Usilujeme o to, abychom udrželi vaše osobní informace v bezpečí. Jako otevřený projekt jsme přístupni komukoliv k provedení kontroly kódu pro zlepšení našich bezpečnostních systémů." + email_title: "Email" + email_description_prefix: "Nebudeme vás zaplavovat nevyžádanou korespondencí. Pomocí " + email_settings_url: " nastavení emailu" + email_description_suffix: "nebo skrze odkazy v odeslaných emailech si můžete nastavit nebo se kdykoliv odhlásit z naší korespondence." + cost_title: "Cena" + cost_description: "Momentálně je CodeCombat 100% zdarma! Naší snahou je udržet přístup zdarma, abychom dali možnost hrát co největšímu množství lidí. V případě nutnosti budeme muset přejít na placený vstup nebo platbu za přístup k určitému obsahu, ale raději bychom se tomu vyhnuli. S trochou štěstí doufáme v následující plán monetizace:" + recruitment_title: "Nábor" + recruitment_description_prefix: "Zde na CodeCombatu se stanete mocným kouzelníkem a to nejen ve hře, ale i v reálném životě." + url_hire_programmers: "O dobré programátory je stále velký zájem " + recruitment_description_suffix: "takže až se vypracujete a pokud budete souhlasit, budeme demonstrovat vaše nejlepší programátorské úspěchy tisícovkám zaměstnavatelů, kteří by vás rádi zaměstnali. Ti nám zaplatí něco málo, ale vám pak zaplatí " + recruitment_description_italic: "daleko více," + recruitment_description_ending: "tato hra zůstane zdarma a všichni budou spokojeni. Takový je plán." + copyrights_title: "Copyrights a Licence" + contributor_title: "Licenční ujednání přispívatelů (CLA)" + contributor_description_prefix: "Všichni přispívatelé jak na webu tak do projektu na GitHubu spadají pod naše " + cla_url: "CLA" + contributor_description_suffix: "se kterým je nutno souhlasit před tím, nežli přispějete." + code_title: "Kód - MIT" + code_description_prefix: "Veškerý kód vlastněný CodeCombatem nebo hostovaným na codecombat.com, kód v repozitáři na GitHub repository nebo v databázi codecombat.com, je licencován pod " + mit_license_url: "MIT licencí" + code_description_suffix: "Zahrnut je veškerý kód v systémech a komponentech, které jsou zpřístupněné CodeCombatem pro vytváření úrovní." + art_title: "Art/Hudba - Creative Commons " + art_description_prefix: "Veškerý obecný obsah je dostupný pod " + cc_license_url: "Mezinárodní Licencí Creative Commons Attribution 4.0" + art_description_suffix: "Obecným obsahem se rozumí vše dostupné na CodeCombatu, určené k vytváření úrovní. To zahrnuje:" + art_music: "Hudbu" + art_sound: "Zvuky" + art_artwork: "Umělecká díla" + art_sprites: "Doplňkový kód" + art_other: "A veškeré další kreativní práce použité při vytváření úrovní." + art_access: "Momentálně neexistuje jednoduchý systém pro stažení těchto součástí, částí úrovní a podobně. Lze je stáhnout z URL adres na tomto webu, můžete nás kontaktovat se žádostí o informace nebo nám i pomoci ve sdílení a vytváření systému pro jednoduché sdílení těchto doplňkových součástí." + art_paragraph_1: "Při uvádění zdroje, uvádějte prosím jméno a odkaz na codecombat.com v místech, která jsou vhodná a kde je to možné. Například:" + use_list_1: "Při použití ve filmu uveďte codecombat.com v titulcích." + use_list_2: "Při použití na webu, zahrňte odkaz například pod obrázkem/odkazem, nebo na stránce uvádějící zdroj, kde také zmíníte další Creative Commons díla a další použité open source projekty. Ostatní, na CodeCombat odkazující se práce (například článek na blogu zmiňující CodeCombat) není nutno separátně označovat a uvádět zdroj." + art_paragraph_2: "Využíváte-li obsah vytvořený některým uživatelem na codecombat.com, uvádějte odkaz na zdroj přímo na tohoto autora a následujte doporučení uvádění zdroje daného obsahu, je-li uvedeno." + rights_title: "Práva vyhrazena" + rights_desc: "Všechna práva jsou vyhrazena jednotlivým samostatným úrovním. To zahrnuje" + rights_scripts: "Skripty" + rights_unit: "Unit konfigurace" + rights_description: "Popisy" + rights_writings: "Zápisy" + rights_media: "Média (zvuky, hudba) a další tvořivý obsah vytvořený specificky pro tuto úroveň, který nebyl zpřístupněn při vytváření úrovně." + rights_clarification: "Pro ujasnění - vše, co je dostupné v editoru úrovní při vytváření úrovně spadá pod CC, ale obsah vytvořený v editoru úrovní nebo nahraný při vytváření spadá pod úroveň." + nutshell_title: "Ve zkratce" + nutshell_description: "Vše co je poskytnuto v editoru úrovní je zdarma a mžete toho využít při vytváření úrovní. Ale vyhrazujeme si právo omezit distribuci úrovní samotných (těch, které byly vytvořeny na codecombat.com), takže v budoucnu bude možno tyto zpoplatnit, bude-li to v nejhorším případě nutné" + canonical: "Anglická verze tohoto dokumentu je původní, rozhodující verzí. Nastane-li rozdíl v překladu, Anglická verze bude mít vždy přednost." -# legal: -# page_title: "Legal" -# opensource_intro: "CodeCombat is free to play and completely open source." -# opensource_description_prefix: "Check out " -# github_url: "our GitHub" -# opensource_description_center: "and help out if you like! CodeCombat is built on dozens of open source projects, and we love them. See " -# archmage_wiki_url: "our Archmage wiki" -# opensource_description_suffix: "for a list of the software that makes this game possible." -# practices_title: "Respectful Best Practices" -# practices_description: "These are our promises to you, the player, in slightly less legalese." -# privacy_title: "Privacy" -# privacy_description: "We will not sell any of your personal information. We intend to make money through recruitment eventually, but rest assured we will not distribute your personal information to interested companies without your explicit consent." -# security_title: "Security" -# security_description: "We strive to keep your personal information safe. As an open source project, our site is freely open to anyone to review and improve our security systems." -# email_title: "Email" -# email_description_prefix: "We will not inundate you with spam. Through" -# email_settings_url: "your email settings" -# email_description_suffix: "or through links in the emails we send, you can change your preferences and easily unsubscribe at any time." -# cost_title: "Cost" -# cost_description: "Currently, CodeCombat is 100% free! One of our main goals is to keep it that way, so that as many people can play as possible, regardless of place in life. If the sky darkens, we might have to charge subscriptions or for some content, but we'd rather not. With any luck, we'll be able to sustain the company with:" -# recruitment_title: "Recruitment" -# recruitment_description_prefix: "Here on CodeCombat, you're going to become a powerful wizard–not just in the game, but also in real life." -# url_hire_programmers: "No one can hire programmers fast enough" -# recruitment_description_suffix: "so once you've sharpened your skills and if you agree, we will demo your best coding accomplishments to the thousands of employers who are drooling for the chance to hire you. They pay us a little, they pay you" -# recruitment_description_italic: "a lot" -# recruitment_description_ending: "the site remains free and everybody's happy. That's the plan." -# copyrights_title: "Copyrights and Licenses" -# contributor_title: "Contributor License Agreement" -# contributor_description_prefix: "All contributions, both on the site and on our GitHub repository, are subject to our" -# cla_url: "CLA" -# contributor_description_suffix: "to which you should agree before contributing." -# code_title: "Code - MIT" -# code_description_prefix: "All code owned by CodeCombat or hosted on codecombat.com, both in the GitHub repository or in the codecombat.com database, is licensed under the" -# mit_license_url: "MIT license" -# code_description_suffix: "This includes all code in Systems and Components that are made available by CodeCombat for the purpose of creating levels." -# art_title: "Art/Music - Creative Commons " -# art_description_prefix: "All common content is available under the" -# cc_license_url: "Creative Commons Attribution 4.0 International License" -# art_description_suffix: "Common content is anything made generally available by CodeCombat for the purpose of creating Levels. This includes:" -# art_music: "Music" -# art_sound: "Sound" -# art_artwork: "Artwork" -# art_sprites: "Sprites" -# art_other: "Any and all other non-code creative works that are made available when creating Levels." -# art_access: "Currently there is no universal, easy system for fetching these assets. In general, fetch them from the URLs as used by the site, contact us for assistance, or help us in extending the site to make these assets more easily accessible." -# art_paragraph_1: "For attribution, please name and link to codecombat.com near where the source is used or where appropriate for the medium. For example:" -# use_list_1: "If used in a movie or another game, include codecombat.com in the credits." -# use_list_2: "If used on a website, include a link near the usage, for example underneath an image, or in a general attributions page where you might also mention other Creative Commons works and open source software being used on the site. Something that's already clearly referencing CodeCombat, such as a blog post mentioning CodeCombat, does not need some separate attribution." -# art_paragraph_2: "If the content being used is created not by CodeCombat but instead by a user of codecombat.com, attribute them instead, and follow attribution directions provided in that resource's description if there are any." -# rights_title: "Rights Reserved" -# rights_desc: "All rights are reserved for Levels themselves. This includes" -# rights_scripts: "Scripts" -# rights_unit: "Unit configuration" -# rights_description: "Description" -# rights_writings: "Writings" -# rights_media: "Media (sounds, music) and any other creative content made specifically for that Level and not made generally available when creating Levels." -# rights_clarification: "To clarify, anything that is made available in the Level Editor for the purpose of making levels is under CC, whereas the content created with the Level Editor or uploaded in the course of creation of Levels is not." -# nutshell_title: "In a Nutshell" -# nutshell_description: "Any resources we provide in the Level Editor are free to use as you like for creating Levels. But we reserve the right to restrict distribution of the Levels themselves (that are created on codecombat.com) so that they may be charged for in the future, if that's what ends up happening." -# canonical: "The English version of this document is the definitive, canonical version. If there are any discrepencies between translations, the English document takes precedence." + contribute: + page_title: "Přispívání" + character_classes_title: "Obsazení rolí" + introduction_desc_intro: "Vkládáme do CodeCombatu velké naděje." + introduction_desc_pref: "Chceme být to místo, ve kterém se všichni programátoři sejdou pro společnou hru a učení, uvedou další do úžasného světa programování a kde se předvede elita. Víme, že toto sami nezvládneme, jsou to lidé, kteří dělají projekty typu GitHub, Stack Overflow a Linux úspěšnými. Za tímto účelem, " + introduction_desc_github_url: "CodeCombat je kompletně open source" + introduction_desc_suf: "a snažíme se jak jen to jde, abychom vám umožnili se do tohoto projektu zapojit." + introduction_desc_ending: "Doufáme, že se k nám přidáte!" + introduction_desc_signature: "- Nick, George, Scott, Michael a Jeremy" + alert_account_message_intro: "Vítejte!" + alert_account_message_pref: "K přihlášení odebírání emailů si nejprve musíte " + alert_account_message_suf: "vytvořit účet" + alert_account_message_create_url: "." + archmage_introduction: "Jedna z nejlepších věcí na vytváření her je to, že se jedná o spojení různých procesů. Grafika, zvuk, síťování v reálném čase, mezilidské vztahy a samozřejmě také spousta běžných aspektů programování, od nízkoúrovňového managementu databáze přes administraci serverů až po tvorbu uživatelská rozhraní. Je zde spousta práce a pokud jste zkušený programátor a všeuměl připravený k ponoření se do hloubek CodeCombatu, tato skupina je pro vás. Budeme moc rádi za vaši pomoc při tvorbě té nejlepší programovací hry." + class_attributes: "Vlastnosti" + archmage_attribute_1_pref: "Znáte " + archmage_attribute_1_suf: "nebo se jej chcete naučit. Je v něm většina našeho kódu. Je-li vaším oblíbeným jazykem Ruby nebo Python, budete se cítit jako doma. Je to JavaScript, ale s lepší syntaxí." + archmage_attribute_2: "Zkušenosti s programováním a osobní iniciativa. Pomůžeme vám se zorientovat, ale nemůžeme vás učit." + how_to_join: "Jak se přidat" + join_desc_1: "Pomoct může kdokoliv! Pro začátek se podívejte na naši stránku na " + join_desc_2: " , zaškrtněte políčko níže - označíte se tím jako statečný Arcimág a začnete dostávat informace o novinkách emailem. Chcete popovídat o tom jak začít? " + join_desc_3: ", nebo se s námi spojte v naší " + join_desc_4: "!" + join_url_email: "Pošlete nám email" + join_url_hipchat: "veřejné HipChat chatovací místnosti" + more_about_archmage: "Dozvědět se více o tom, jak se stát mocným Arcimágem" + archmage_subscribe_desc: "Dostávat emailem oznámení a informacemi nových programovacích příležitostech" + artisan_introduction_pref: "Musíme vytvářet další úrovně! Lidé nás prosí o další obsah, ale sami zvládáme vytvořit jen málo. Naším prvním pracovním zastavením je první úroveň. Editor úrovní je tak-tak použitelný i pro jeho vlastní tvůrce. Máte-li vizi pro vytvoření vnořených úrovní alá " + artisan_introduction_suf: "pak neváhejte, toto je vaše destinace." + artisan_attribute_1: "Předchozí zkušenosti s vytvářením podobného obsahu by byly vítány, například z editorů úrovní Blizzardu, ale nejsou vyžadovány!" + artisan_attribute_2: "Připraveni ke spoustě testování a pokusů. K vytvoření dobré úrovně je potřeba je představit ostatním, nechat je hrát a pak je z velké části měnit a opravovat." + artisan_attribute_3: "Pro teď, stejné jako Dobrodruh - tester úrovní. Náš editor úrovní je ve velmi raném stádiu a frustrující při používání. Varovali jsme vás!" + artisan_join_desc: "Použijte editor úrovní v těchto postupných krocích:" + artisan_join_step1: "Přečtěte si dokumentaci." + artisan_join_step2: "Vytvořte novou úroveň a prozkoumejte existující úrovně." + artisan_join_step3: "Požádejte nás o pomoc ve veřejné HipChat místnosti." + artisan_join_step4: "Zveřejněte vaši úroveň na fóru pro připomínkování." + more_about_artisan: "Dozvědět se více o tom, jak se stát kreativním Řemeslníkem" + artisan_subscribe_desc: "Dostávat emailem oznámení a informace o aktualizacích editoru úrovní." + adventurer_introduction: "Ujasněme si dopředu jednu věc o vaší roli: budete jako tank. Projdete ohněm. Potřebujeme někoho, kdo odzkouší zbrusu nové úrovně a pomůže identifikovat kde je možno je zlepšit. Ten boj bude ohromný - tvorba her je dlouhý proces, který nikdo nezvládne na první pokus. Máte-li na to a vydržíte-li to, pak toto je vaše skupina." + adventurer_attribute_1: "Touha po učení se. Vy se chcete naučit programovat a my vás to chceme naučit. Jenom, v tomto případě to budete vy, kdo bude vyučovat." + adventurer_attribute_2: "Charismatický. Buďte mírný a pečlivě artikulujte co a jak je potřeba zlepšit." + adventurer_join_pref: "Buďto se spojte (nebo si najděte!) Dobrodruha a pracujte s ním, nebo zaškrtněte políčko níže a dostávejte emaily o dostupnosti nových úrovní k testování. Budeme také posílat informace o nových úrovních k recenzím na sociálních webech, " + adventurer_forum_url: " našem fóru" + adventurer_join_suf: "takže pokud chcete být v obraze, připojte se k nám!" + more_about_adventurer: "Dozvědět se více o tom, jak se stát statečným Dobrodruhem" + adventurer_subscribe_desc: "Dostávat emailem oznámení a informace nových úrovních k testování." + scribe_introduction_pref: "CodeCombat nebude pouze kupa úrovní. Bude také zahrnovat informační zdroje a wiki programovacích konceptů na které se úrovně mohou navázat. Takto, namísto toho aby každý Řemeslník musel sám do detailu popsatco který operátor dělá, mohou jednoduše nalinkovat svoji úroveň na článek existující k edukaci hráčů. Něco ve stylu " + scribe_introduction_url_mozilla: "Mozilla Developer Network" + scribe_introduction_suf: ". Jestliže vás baví popisovat a předávat koncept programování v Markdown editoru, pak tato role může být právě pro vás." + scribe_attribute_1: "Zkušenost s psaním je jediné co budete potřebovat. Nejen gramatika, ale také schopnost popsat složité koncepty a myšlenky ostatním." + contact_us_url: "Spojte se s námi" + scribe_join_description: "dejte nám o vás vědět, o vašich zkušenostech s programováním a o čm byste rádi psali. Od toho začneme!" + more_about_scribe: "Dozvědět se více o tom, jak se stát pilným Pisálkem" + scribe_subscribe_desc: "Dostávat emailem oznámení a informace o článcích." + diplomat_introduction_pref: "Jedna z věcí, kterou jsme zjistili během " + diplomat_launch_url: "zahájení v Říjnu" + diplomat_introduction_suf: "bylo, že o CodeCombat je velký zájem i v jiných zemích, obzvláště v Brazílii! Chystáme regiment překladatelů ke zpřístupnění CodeCombatu světu. Pokud chcete nakouknout pod pokličku, dozvědět se o připravovaných novinkách a zpřístupnit úrovně vašim národním kolegům, toto je role pro vás." + diplomat_attribute_1: "Plynulost v angličtině a v jazyce do kterého budete překládat. Při předávání komplexních myšlenek je důležité si být jistí v kramflecích v obou jazycích!" + diplomat_join_pref: "Úvodní překladatelský počin začal v tomto " + diplomat_doc_url: "příspěvku na fóru" + diplomat_join_suf: ", tak si jej přečtěte a případně doplňte informace o vašem překladu. Přihlaste se také k odběru informací o vývoji v internacionalizaci!" + more_about_diplomat: "Dozvědět se více o tom, jak se stát Diplomatem" + diplomat_subscribe_desc: "Dostávat emailem oznámení a informace o internacionalizaci a o úrovních k překladu." + ambassador_introduction: "Zde se tvoří komunita a vy jste její spojení. Využíváme chat, emaily a sociální sítě se spoustou lidí k informování a diskuzím a seznámení s naší hrou. Chcete-li pomoci lidem se přidat a pobavit se a získat dobrý náhled na CodeCombat a kam směřujeme, pak toto je vaše role." + ambassador_attribute_1: "Komunikační schopnosti. Schopnost identifikovat problémy hráčů a pomoci jim je řešit. Naslouchat co hráči říkají, co mají rádi a co rádi nemají a komunikovat to zpět ostatním!" + ambassador_join_desc: "dejte nám o sobě vědět, o tom co děláte a co byste rádi dělali. Od toho začneme!" + ambassador_join_note_strong: "Poznámka" + ambassador_join_note_desc: "Jedna z našich priorit je vytvoření vícehráčové hry, kde hráč, který má problém s řešením úrovní může oslovit a požádat o pomoc zkušenější kouzelníky. To je přesně ten případ a místo pro pomoc Velvyslance . Dáme vám vědět více!" + more_about_ambassador: "Dozvědět se více o tom, jak se stát nápomocným Velvyslancem" + ambassador_subscribe_desc: "Dostávat emailem oznámení a informace o vývoji v podpoře a vícehráčové hře." + counselor_introduction_1: "Máte životní zkušenosti? Máte odlišný náhled na věci a jste schopni nám tímto pomoci v dalším vývoji CodeCombatu? Jedna z důležitých rolí i když asi nejméně časově náročná, nicméně každá individualita je schopná udělat velký rozdíl. Hledáme zkušené odborníky, zvláště pak v oblastech vzdělávání, vývoji her managementu open source, source project management, náboru lidských zdrojů, podnikání nebo designu." + counselor_introduction_2: "Nebo cokoliv, co je relevantní ve vývoji CodeCombatu. Máte-li znalosti a jste-li ochotni se o ně podělit pro další růst tohoto projektu , pak toto je role pro vás." + counselor_attribute_1: "Zkušenosti ve výše zmíněných oblastech, nebo něco, čím byste mohli být nápomocni." + counselor_attribute_2: "Troška volného času!" + counselor_join_desc: "dejte nám o sobě vědět, o tom co děláte a co byste rádi dělali. Přidáme si vás do seznamu a budeme vás kontaktovat v případě, že to bude potřeba (ne moc často)." + more_about_counselor: "Dozvědět se více o tom, jak se stát Poradcem" + changes_auto_save: "Změny jsou automaticky uloženy při kliknutí na zaškrtávací políčka." + diligent_scribes: "Naši pilní Písaři:" + powerful_archmages: "Naši mocní Arcimágové:" + creative_artisans: "Naši kreativní Řemeslníci:" + brave_adventurers: "Naši stateční Dobrodruzi:" + translating_diplomats: "Naši překladatelští Diplomati:" + helpful_ambassadors: "Naši nápomocní Velvyslanci:" -# contribute: -# page_title: "Contributing" -# character_classes_title: "Character Classes" -# introduction_desc_intro: "We have high hopes for CodeCombat." -# introduction_desc_pref: "We want to be where programmers of all stripes come to learn and play together, introduce others to the wonderful world of coding, and reflect the best parts of the community. We can't and don't want to do that alone; what makes projects like GitHub, Stack Overflow and Linux great are the people who use them and build on them. To that end, " -# introduction_desc_github_url: "CodeCombat is totally open source" -# introduction_desc_suf: ", and we aim to provide as many ways as possible for you to take part and make this project as much yours as ours." -# introduction_desc_ending: "We hope you'll join our party!" -# introduction_desc_signature: "- Nick, George, Scott, Michael, and Jeremy" -# alert_account_message_intro: "Hey there!" -# alert_account_message_pref: "To subscribe for class emails, you'll need to " -# alert_account_message_suf: "first." -# alert_account_message_create_url: "create an account" -# archmage_introduction: "One of the best parts about building games is they synthesize so many different things. Graphics, sound, real-time networking, social networking, and of course many of the more common aspects of programming, from low-level database management, and server administration to user facing design and interface building. There's a lot to do, and if you're an experienced programmer with a hankering to really dive into the nitty-gritty of CodeCombat, this class might be for you. We would love to have your help building the best programming game ever." -# class_attributes: "Class Attributes" -# archmage_attribute_1_pref: "Knowledge in " -# archmage_attribute_1_suf: ", or a desire to learn. Most of our code is in this language. If you're a fan of Ruby or Python, you'll feel right at home. It's JavaScript, but with a nicer syntax." -# archmage_attribute_2: "Some experience in programming and personal initiative. We'll help you get oriented, but we can't spend much time training you." -# how_to_join: "How To Join" -# join_desc_1: "Anyone can help out! Just check out our " -# join_desc_2: "to get started, and check the box below to mark yourself as a brave Archmage and get the latest news by email. Want to chat about what to do or how to get more deeply involved? " -# join_desc_3: ", or find us in our " -# join_desc_4: "and we'll go from there!" -# join_url_email: "Email us" -# join_url_hipchat: "public HipChat room" -# more_about_archmage: "Learn More About Becoming A Powerful Archmage" -# archmage_subscribe_desc: "Get emails on new coding opportunities and announcements." -# artisan_introduction_pref: "We must construct additional levels! People be clamoring for more content, and we can only build so many ourselves. Right now your workstation is level one; our level editor is barely usable even by its creators, so be wary. If you have visions of campaigns spanning for-loops to" -# artisan_introduction_suf: "to then this class might be for you." -# artisan_attribute_1: "Any experience in building content like this would be nice, such as using Blizzard's level editors. But not required!" -# artisan_attribute_2: "A hankering to do a whole lot of testing and iteration. To make good levels, you need to take it to others and watch them play it, and be prepared to find a lot of things to fix." -# artisan_attribute_3: "For the time being, endurance en par with an Adventurer. Our Level Editor is super preliminary and frustrating to use. You have been warned!" -# artisan_join_desc: "Use the Level Editor in these steps, give or take:" -# artisan_join_step1: "Read the documentation." -# artisan_join_step2: "Create a new level and explore existing levels." -# artisan_join_step3: "Find us in our public HipChat room for help." -# artisan_join_step4: "Post your levels on the forum for feedback." -# more_about_artisan: "Learn More About Becoming A Creative Artisan" -# artisan_subscribe_desc: "Get emails on level editor updates and announcements." -# adventurer_introduction: "Let's be clear about your role: you are the tank. You're going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class might be for you." -# adventurer_attribute_1: "A thirst for learning. You want to learn how to code and we want to teach you how to code. You'll probably be doing most of the teaching in this case, though." -# adventurer_attribute_2: "Charismatic. Be gentle but articulate about what needs improving, and offer suggestions on how to improve." -# adventurer_join_pref: "Either get together with (or recruit!) an Artisan and work with them, or check the box below to receive emails when there are new levels to test. We'll also be posting about levels to review on our networks like" -# adventurer_forum_url: "our forum" -# adventurer_join_suf: "so if you prefer to be notified those ways, sign up there!" -# more_about_adventurer: "Learn More About Becoming A Brave Adventurer" -# adventurer_subscribe_desc: "Get emails when there are new levels to test." -# scribe_introduction_pref: "CodeCombat isn't just going to be a bunch of levels. It will also include a resource for knowledge, a wiki of programming concepts that levels can hook into. That way rather than each Artisan having to describe in detail what a comparison operator is, they can simply link their level to the Article describing them that is already written for the player's edification. Something along the lines of what the " -# scribe_introduction_url_mozilla: "Mozilla Developer Network" -# scribe_introduction_suf: " has built. If your idea of fun is articulating the concepts of programming in Markdown form, then this class might be for you." -# scribe_attribute_1: "Skill in words is pretty much all you need. Not only grammar and spelling, but able to convey complicated ideas to others." -# contact_us_url: "Contact us" -# scribe_join_description: "tell us a little about yourself, your experience with programming and what sort of things you'd like to write about. We'll go from there!" -# more_about_scribe: "Learn More About Becoming A Diligent Scribe" -# scribe_subscribe_desc: "Get emails about article writing announcements." -# diplomat_introduction_pref: "So, if there's one thing we learned from the " -# diplomat_launch_url: "launch in October" -# diplomat_introduction_suf: "it's that there is sizeable interest in CodeCombat in other countries, particularly Brazil! We're building a corps of translators eager to turn one set of words into another set of words to get CodeCombat as accessible across the world as possible. If you like getting sneak peeks at upcoming content and getting these levels to your fellow nationals ASAP, then this class might be for you." -# diplomat_attribute_1: "Fluency in English and the language you would like to translate to. When conveying complicated ideas, it's important to have a strong grasp in both!" -# diplomat_join_pref: "We've started a lot of initial translations at " -# diplomat_doc_url: "this forum post" -# diplomat_join_suf: "so check it out and add things for your language. Also, check this box below to keep up-to-date on new internationalization developments!" -# more_about_diplomat: "Learn More About Becoming A Great Diplomat" -# diplomat_subscribe_desc: "Get emails about i18n developments and levels to translate." -# ambassador_introduction: "This is a community we're building, and you are the connections. We've got Olark chats, emails, and social networks with lots of people to talk with and help get acquainted with the game and learn from. If you want to help people get involved and have fun, and get a good feel of the pulse of CodeCombat and where we're going, then this class might be for you." -# ambassador_attribute_1: "Communication skills. Be able to identify the problems players are having and help them solve them. Also, keep the rest of us informed about what players are saying, what they like and don't like and want more of!" -# ambassador_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll go from there!" -# ambassador_join_note_strong: "Note" -# ambassador_join_note_desc: "One of our top priorities is to build multiplayer where players having difficulty solving levels can summon higher level wizards to help them. This will be a great way for ambassadors to do their thing. We'll keep you posted!" -# more_about_ambassador: "Learn More About Becoming A Helpful Ambassador" -# ambassador_subscribe_desc: "Get emails on support updates and multiplayer developments." -# counselor_introduction_1: "Do you have life experience? A different perspective on things that can help us decide how to shape CodeCombat? Of all these roles, this will probably take the least time, but individually you may make the most difference. We're on the lookout for wisened sages, particularly in areas like: teaching, game development, open source project management, technical recruiting, entrepreneurship, or design." -# counselor_introduction_2: "Or really anything that is relevant to the development of CodeCombat. If you have knowledge and want to share it to help grow this project, then this class might be for you." -# counselor_attribute_1: "Experience, in any of the areas above or something you think might be helpful." -# counselor_attribute_2: "A little bit of free time!" -# counselor_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll put you in our contact list and be in touch when we could use advice (not too often)." -# more_about_counselor: "Learn More About Becoming A Valuable Counselor" -# changes_auto_save: "Changes are saved automatically when you toggle checkboxes." -# diligent_scribes: "Our Diligent Scribes:" -# powerful_archmages: "Our Powerful Archmages:" -# creative_artisans: "Our Creative Artisans:" -# brave_adventurers: "Our Brave Adventurers:" -# translating_diplomats: "Our Translating Diplomats:" -# helpful_ambassadors: "Our Helpful Ambassadors:" - -# classes: -# archmage_title: "Archmage" -# archmage_title_description: "(Coder)" -# artisan_title: "Artisan" -# artisan_title_description: "(Level Builder)" -# adventurer_title: "Adventurer" -# adventurer_title_description: "(Level Playtester)" -# scribe_title: "Scribe" -# scribe_title_description: "(Article Editor)" -# diplomat_title: "Diplomat" -# diplomat_title_description: "(Translator)" -# ambassador_title: "Ambassador" -# ambassador_title_description: "(Support)" -# counselor_title: "Counselor" -# counselor_title_description: "(Expert/Teacher)" + classes: + archmage_title: "Arcikouzelník" + archmage_title_description: "(Programátor)" + artisan_title: "Řemeslník" + artisan_title_description: "(Tvůrce úrovní)" + adventurer_title: "Dobrodruh" + adventurer_title_description: "(Tester úrovní)" + scribe_title: "Pisálek" + scribe_title_description: "(Editor článků)" + diplomat_title: "Diplomat" + diplomat_title_description: "(Překladatel)" + ambassador_title: "Velvyslanec" + ambassador_title_description: "(Podpora)" + counselor_title: "Poradce" + counselor_title_description: "(Odborník)" diff --git a/app/locale/da.coffee b/app/locale/da.coffee index 5684f5331..3703108f1 100644 --- a/app/locale/da.coffee +++ b/app/locale/da.coffee @@ -4,13 +4,13 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans saving: "Gemmer..." sending: "Sender..." cancel: "Annuller" -# save: "Save" -# delay_1_sec: "1 second" -# delay_3_sec: "3 seconds" -# delay_5_sec: "5 seconds" -# manual: "Manual" -# fork: "Fork" -# play: "Spil" + save: "Gem" + delay_1_sec: "1 sekund" + delay_3_sec: "3 sekunder" + delay_5_sec: "5 sekunder" + manual: "Manual" + fork: "Forgren" + play: "Spil" modal: close: "Luk" @@ -31,28 +31,28 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans about: "Om" contact: "Kontakt" twitter_follow: "Følg" -# employers: "Employers" + employers: "Arbejdsgivere" -# versions: -# save_version_title: "Save New Version" -# new_major_version: "New Major Version" -# cla_prefix: "To save changes, first you must agree to our" -# cla_url: "CLA" -# cla_suffix: "." -# cla_agree: "I AGREE" + versions: + save_version_title: "Gem ny version" + new_major_version: "Ny hoved Version" + cla_prefix: "For at gemme dine ændringer, må du acceptere brugerbetingelserne" + cla_url: "CLA" + cla_suffix: "." + cla_agree: "Jeg er enig" login: sign_up: "opret ny konto" log_in: "Log Ind" -# log_out: "Log Out" + log_out: "Log Ud" recover: "genskab konto" recover: recover_account_title: "genskab konto" -# send_password: "Send Recovery Password" + send_password: "Send kodeord" signup: -# create_account_title: "Create Account to Save Progress" + create_account_title: "Opret en konto for at gemme dit fremskridt" description: "Det er gratis. Du skal bare indtaste et par ting, så er du klar til at komme igang:" email_announcements: "Modtag nyheder på email" coppa: "13+ eller ikke-USA" @@ -91,7 +91,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans forum_prefix: "For noget offentligt, prøv venligst " forum_page: "vores forum" forum_suffix: " istedet." -# send: "Send Feedback" + send: "Send Feedback" diplomat_suggestion: title: "Hjælp med at oversætte CodeCombat!" @@ -101,9 +101,9 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans learn_more: "Lær mere om at være Diplomat" subscribe_as_diplomat: "Meld dig som Diplomat" -# wizard_settings: -# title: "Wizard Settings" -# customize_avatar: "Customize Your Avatar" + wizard_settings: + title: "Troldmandsinstillinger" + customize_avatar: "Tilpas din avatar" account_settings: title: "Kontoindstillinger" @@ -122,7 +122,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans new_password_verify: "Bekræft" email_subscriptions: "Emailtilmeldinger" email_announcements: "Nyheder" -# email_notifications_description: "Get periodic notifications for your account." + email_notifications_description: "Få periodevise meldinger om din konto." email_announcements_description: "Få emails om de seneste nyheder og udvikling på CodeCombat." contributor_emails: "Bidragsklasse-emails" contribute_prefix: "Vi leder efter folk til at joine vores gruppe! Tjek " @@ -135,75 +135,75 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans account_profile: edit_settings: "Redigér Indstillinger" -# profile_for_prefix: "Profile for " -# profile_for_suffix: "" + profile_for_prefix: "Profil for " + profile_for_suffix: "" profile: "Profil" user_not_found: "Ingen bruger fundet. Tjek URL'en?" -# gravatar_not_found_mine: "We couldn't find your profile associated with:" -# gravatar_not_found_email_suffix: "." -# gravatar_signup_prefix: "Sign up at " -# gravatar_signup_suffix: " to get set up!" -# gravatar_not_found_other: "Alas, there's no profile associated with this person's email address." + gravatar_not_found_mine: "Vi kunne ikke finde din profil associeret med:" + gravatar_not_found_email_suffix: "." + gravatar_signup_prefix: "Opret dig hos " + gravatar_signup_suffix: " for at påbegynde" + gravatar_not_found_other: "Hov, der er ingen profil associeret med denne persons e-mail konto" gravatar_contact: "Kontakt" -# gravatar_websites: "Websites" -# gravatar_accounts: "As Seen On" -# gravatar_profile_link: "Full Gravatar Profile" + gravatar_websites: "Gravatar hjemmesider" + gravatar_accounts: "Som set på" + gravatar_profile_link: "Fuld Gravatar Profil" -# play_level: - level_load_error: "Niveauer kunne ikke indlæses." + play_level: + level_load_error: "Banen kunne ikke indlæses." done: "Færdig" -# grid: "Grid" -# customize_wizard: "Customize Wizard" -# home: "Home" -# guide: "Guide" -# multiplayer: "Multiplayer" -# restart: "Restart" -# goals: "Goals" -# action_timeline: "Action Timeline" -# click_to_select: "Click on a unit to select it." -# reload_title: "Reload All Code?" -# reload_really: "Are you sure you want to reload this level back to the beginning?" -# reload_confirm: "Reload All" + grid: "Gitter" + customize_wizard: "Tilpas troldmand" + home: "Hjem" + guide: "Guide" + multiplayer: "Flere spillere" + restart: "Start forfra" + goals: "Mål" + action_timeline: "Handlingstidslinje" + click_to_select: "Klik på en enhed for at vælge" + reload_title: "Genindlæs alt kode?" + reload_really: "Er du sikker på at du ønsker at genindlæse denne bane helt fra begyndelsen?" + reload_confirm: "Genindlæs alt" # victory_title_prefix: "" -# victory_title_suffix: " Complete" -# victory_sign_up: "Sign Up to Save Progress" -# victory_sign_up_poke: "Want to save your code? Create a free account!" -# victory_rate_the_level: "Rate the level: " -# victory_play_next_level: "Play Next Level" -# victory_go_home: "Go Home" -# victory_review: "Tell us more!" -# victory_hour_of_code_done: "Are You Done?" -# victory_hour_of_code_done_yes: "Yes, I'm finished with my Hour of Code!" -# multiplayer_title: "Multiplayer Settings" -# multiplayer_link_description: "Give this link to anyone to have them join you." -# multiplayer_hint_label: "Hint:" -# multiplayer_hint: " Click the link to select all, then press ⌘-C or Ctrl-C to copy the link." -# multiplayer_coming_soon: "More multiplayer features to come!" -# guide_title: "Guide" + victory_title_suffix: " Færdig" + victory_sign_up: "Opret dig for at gemme dit fremskridt" + victory_sign_up_poke: "Ønsker du at gemme din kode? Opret en gratis konto!" + victory_rate_the_level: "Bedøm denne bane: " + victory_play_next_level: "Spil næste bane" + victory_go_home: "Gå hjem" + victory_review: "Fortæl os mere!" + victory_hour_of_code_done: "Er du færdig?" + victory_hour_of_code_done_yes: "Ja, jeg er færdig med min Kodetime!" + multiplayer_title: "Flerspillerinstillinger" + multiplayer_link_description: "Del dette link med andre deltagere." + multiplayer_hint_label: "Tip:" + multiplayer_hint: " Klik på linket for markere alt; tryk derefter ⌘-C eller Ctrl-C tfr at kopiere linket." + multiplayer_coming_soon: "Yderligere flerspillermuligheder er på vej!" + guide_title: "Instruktioner" # tome_minion_spells: "Your Minions' Spells" # tome_read_only_spells: "Read-Only Spells" -# tome_other_units: "Other Units" + tome_other_units: "Andre enheder" # tome_cast_button_castable: "Cast" # tome_cast_button_casting: "Casting" # tome_cast_button_cast: "Spell Cast" # tome_autocast_delay: "Autocast Delay" -# tome_select_spell: "Select a Spell" -# tome_select_a_thang: "Select Someone for " -# tome_available_spells: "Available Spells" -# hud_continue: "Continue (press shift-space)" -# spell_saved: "Spell Saved" + tome_select_spell: "Vælg en trylleformular" + tome_select_a_thang: "Vælg nogen til at " + tome_available_spells: "Tilgængelige trylleformularer" + hud_continue: "Fortsæt (tryk skift-mellemrum)" + spell_saved: "Trylleformularen er gemt" -# admin: + admin: # av_title: "Admin Views" # av_entities_sub_title: "Entities" -# av_entities_users_url: "Users" + av_entities_users_url: "Brugere" # av_entities_active_instances_url: "Active Instances" -# av_other_sub_title: "Other" + av_other_sub_title: "Andre" # av_other_debug_base_url: "Base (for debugging base.jade)" -# u_title: "User List" -# lg_title: "Latest Games" + u_title: "Brugerliste" + lg_title: "Seneste spil" -# editor: + editor: # main_title: "CodeCombat Editors" # main_description: "Build your own levels, campaigns, units and educational content. We provide all the tools you need!" # article_title: "Article Editor" @@ -213,52 +213,52 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # level_title: "Level Editor" # level_description: "Includes the tools for scripting, uploading audio, and constructing custom logic to create all sorts of levels. Everything we use ourselves!" # security_notice: "Many major features in these editors are not currently enabled by default. As we improve the security of these systems, they will be made generally available. If you'd like to use these features sooner, " -# contact_us: "contact us!" -# hipchat_prefix: "You can also find us in our" -# hipchat_url: "HipChat room." + contact_us: "kontact os!" + hipchat_prefix: "Du kan også finde os på vores" + hipchat_url: "HipChat kanal." # level_some_options: "Some Options?" # level_tab_thangs: "Thangs" # level_tab_scripts: "Scripts" -# level_tab_settings: "Settings" -# level_tab_components: "Components" -# level_tab_systems: "Systems" + level_tab_settings: "Instillinger" + level_tab_components: "Komponenter" + level_tab_systems: "Systemer" # level_tab_thangs_title: "Current Thangs" # level_tab_thangs_conditions: "Starting Conditions" # level_tab_thangs_add: "Add Thangs" -# level_settings_title: "Settings" -# level_component_tab_title: "Current Components" -# level_component_btn_new: "Create New Component" -# level_systems_tab_title: "Current Systems" -# level_systems_btn_new: "Create New System" -# level_systems_btn_add: "Add System" + level_settings_title: "Instillinger" + level_component_tab_title: "Nuværende komponenter" + level_component_btn_new: "Opret ny komponent" + level_systems_tab_title: "Nuværende systemer" + level_systems_btn_new: "Opret nyt system" + level_systems_btn_add: "Tilføj system" # level_components_title: "Back to All Thangs" # level_components_type: "Type" -# level_component_edit_title: "Edit Component" -# level_system_edit_title: "Edit System" -# create_system_title: "Create New System" -# new_component_title: "Create New Component" -# new_component_field_system: "System" + level_component_edit_title: "Redigér komponent" + level_system_edit_title: "Redigér system" + create_system_title: "Opret nyt system" + new_component_title: "Opret ny komponent" + new_component_field_system: "System" -# article: -# edit_btn_preview: "Preview" -# edit_article_title: "Edit Article" + article: + edit_btn_preview: "Forhåndsvisning" + edit_article_title: "Ændr artikkel" -# general: -# and: "and" -# name: "Name" -# body: "Body" -# version: "Version" -# commit_msg: "Commit Message" -# version_history_for: "Version History for: " -# results: "Results" -# description: "Description" - email: "Email" + general: + and: "og" + name: "navn" + body: "krop" + version: "version" + commit_msg: "ændringsnotat" + version_history_for: "versionhistorie for: " + results: "resultater" + description: "beskrivelse" + email: "e-mail" message: "Besked" or: "eller" -# about: -# who_is_codecombat: "Who is CodeCombat?" -# why_codecombat: "Why CodeCombat?" + about: + who_is_codecombat: "Hvem er CodeCombat?" + why_codecombat: "Hvorfor CodeCombat?" # who_description_prefix: "together started CodeCombat in 2013. We also created " # who_description_suffix: "in 2008, growing it to the #1 web and iOS application for learning to write Chinese and Japanese characters." # who_description_ending: "Now it's time to teach people to write code." @@ -270,7 +270,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # why_paragraph_3_italic_caps: "NO MOM I HAVE TO FINISH THE LEVEL!" # why_paragraph_3_suffix: "That's why CodeCombat is a multiplayer game, not a gamified lesson course. We won't stop until you can't stop--but this time, that's a good thing." # why_paragraph_4: "If you're going to get addicted to some game, get addicted to this one and become one of the wizards of the tech age." -# why_ending: "And hey, it's free. " + why_ending: "Og det er ovenikøbet gratis." # why_ending_url: "Start wizarding now!" # george_description: "CEO, business guy, web designer, game designer, and champion of beginning programmers everywhere." # scott_description: "Programmer extraordinaire, software architect, kitchen wizard, and master of finances. Scott is the reasonable one." @@ -282,7 +282,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # page_title: "Legal" # opensource_intro: "CodeCombat is free to play and completely open source." # opensource_description_prefix: "Check out " -# github_url: "our GitHub" + github_url: "vores GitHub" # opensource_description_center: "and help out if you like! CodeCombat is built on dozens of open source projects, and we love them. See " # archmage_wiki_url: "our Archmage wiki" # opensource_description_suffix: "for a list of the software that makes this game possible." @@ -290,11 +290,11 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # practices_description: "These are our promises to you, the player, in slightly less legalese." # privacy_title: "Privacy" # privacy_description: "We will not sell any of your personal information. We intend to make money through recruitment eventually, but rest assured we will not distribute your personal information to interested companies without your explicit consent." -# security_title: "Security" + security_title: "Sikkerhed" # security_description: "We strive to keep your personal information safe. As an open source project, our site is freely open to anyone to review and improve our security systems." -# email_title: "Email" + email_title: "E-mail" # email_description_prefix: "We will not inundate you with spam. Through" -# email_settings_url: "your email settings" + email_settings_url: "dine e-mail instillinger" # email_description_suffix: "or through links in the emails we send, you can change your preferences and easily unsubscribe at any time." # cost_title: "Cost" # cost_description: "Currently, CodeCombat is 100% free! One of our main goals is to keep it that way, so that as many people can play as possible, regardless of place in life. If the sky darkens, we might have to charge subscriptions or for some content, but we'd rather not. With any luck, we'll be able to sustain the company with:" @@ -317,8 +317,8 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # art_description_prefix: "All common content is available under the" # cc_license_url: "Creative Commons Attribution 4.0 International License" # art_description_suffix: "Common content is anything made generally available by CodeCombat for the purpose of creating Levels. This includes:" -# art_music: "Music" -# art_sound: "Sound" + art_music: "Musik" + art_sound: "Lyd" # art_artwork: "Artwork" # art_sprites: "Sprites" # art_other: "Any and all other non-code creative works that are made available when creating Levels." @@ -335,20 +335,20 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # rights_writings: "Writings" # rights_media: "Media (sounds, music) and any other creative content made specifically for that Level and not made generally available when creating Levels." # rights_clarification: "To clarify, anything that is made available in the Level Editor for the purpose of making levels is under CC, whereas the content created with the Level Editor or uploaded in the course of creation of Levels is not." -# nutshell_title: "In a Nutshell" + nutshell_title: "I en nødeskal" # nutshell_description: "Any resources we provide in the Level Editor are free to use as you like for creating Levels. But we reserve the right to restrict distribution of the Levels themselves (that are created on codecombat.com) so that they may be charged for in the future, if that's what ends up happening." # canonical: "The English version of this document is the definitive, canonical version. If there are any discrepencies between translations, the English document takes precedence." -# contribute: + contribute: # page_title: "Contributing" # character_classes_title: "Character Classes" # introduction_desc_intro: "We have high hopes for CodeCombat." # introduction_desc_pref: "We want to be where programmers of all stripes come to learn and play together, introduce others to the wonderful world of coding, and reflect the best parts of the community. We can't and don't want to do that alone; what makes projects like GitHub, Stack Overflow and Linux great are the people who use them and build on them. To that end, " # introduction_desc_github_url: "CodeCombat is totally open source" # introduction_desc_suf: ", and we aim to provide as many ways as possible for you to take part and make this project as much yours as ours." -# introduction_desc_ending: "We hope you'll join our party!" -# introduction_desc_signature: "- Nick, George, Scott, Michael, and Jeremy" -# alert_account_message_intro: "Hey there!" + introduction_desc_ending: "Vi håber du vil deltage i vores fest!" + introduction_desc_signature: "- Nick, George, Scott, Michael, ogJeremy" + alert_account_message_intro: "Hej med dig!" # alert_account_message_pref: "To subscribe for class emails, you'll need to " # alert_account_message_suf: "first." # alert_account_message_create_url: "create an account" @@ -362,7 +362,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # join_desc_2: "to get started, and check the box below to mark yourself as a brave Archmage and get the latest news by email. Want to chat about what to do or how to get more deeply involved? " # join_desc_3: ", or find us in our " # join_desc_4: "and we'll go from there!" -# join_url_email: "Email us" + join_url_email: "Skriv til os" # join_url_hipchat: "public HipChat room" # more_about_archmage: "Learn More About Becoming A Powerful Archmage" # archmage_subscribe_desc: "Get emails on new coding opportunities and announcements." @@ -372,8 +372,8 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # artisan_attribute_2: "A hankering to do a whole lot of testing and iteration. To make good levels, you need to take it to others and watch them play it, and be prepared to find a lot of things to fix." # artisan_attribute_3: "For the time being, endurance en par with an Adventurer. Our Level Editor is super preliminary and frustrating to use. You have been warned!" # artisan_join_desc: "Use the Level Editor in these steps, give or take:" -# artisan_join_step1: "Read the documentation." -# artisan_join_step2: "Create a new level and explore existing levels." + artisan_join_step1: "Læs dokumentationen." + artisan_join_step2: "Lav en ny bane og udforsk eksisterende baner." # artisan_join_step3: "Find us in our public HipChat room for help." # artisan_join_step4: "Post your levels on the forum for feedback." # more_about_artisan: "Learn More About Becoming A Creative Artisan" @@ -424,18 +424,18 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # translating_diplomats: "Our Translating Diplomats:" # helpful_ambassadors: "Our Helpful Ambassadors:" -# classes: -# archmage_title: "Archmage" -# archmage_title_description: "(Coder)" -# artisan_title: "Artisan" -# artisan_title_description: "(Level Builder)" -# adventurer_title: "Adventurer" -# adventurer_title_description: "(Level Playtester)" -# scribe_title: "Scribe" -# scribe_title_description: "(Article Editor)" -# diplomat_title: "Diplomat" -# diplomat_title_description: "(Translator)" -# ambassador_title: "Ambassador" -# ambassador_title_description: "(Support)" -# counselor_title: "Counselor" -# counselor_title_description: "(Expert/Teacher)" + classes: + archmage_title: "Ærkemager" + archmage_title_description: "(Programmør)" + artisan_title: "Artisan" + artisan_title_description: "(Banedesigner)" + adventurer_title: "Eventyrer" + adventurer_title_description: "(Banetester)" + scribe_title: "Skriver" + scribe_title_description: "(Artikkel redaktør)" + diplomat_title: "Diplomat" + diplomat_title_description: "(Oversætter)" + ambassador_title: "Ambassadør" + ambassador_title_description: "(Brugerstøtte)" + counselor_title: "Rådgiver" + counselor_title_description: "(Ekspert/Lærer)" diff --git a/app/locale/de.coffee b/app/locale/de.coffee index 37af9fdd7..1b55e2eb0 100644 --- a/app/locale/de.coffee +++ b/app/locale/de.coffee @@ -36,10 +36,10 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra versions: save_version_title: "Neue Version speichern" new_major_version: "Neue Hauptversion" -# cla_prefix: "Damit Änderungen gespeichert werden können, musst du unsere ... akzeptieren " # To save changes, first you must agree to our" ... -# cla_url: "CLA" ? What is this? - cla_suffix: "." - cla_agree: "Ich akzeptiere" # die Bestimmungen / I agree the rules + cla_prefix: "Damit Änderungen gespeichert werden können, musst du unsere Lizenzbedingungen (" # To save changes, first you must agree to our ... + cla_url: "CLA" # ? CLA: What is this? -> CodeCombat Individual Contributor License Agreement + cla_suffix: ") akzeptieren." + cla_agree: "Ich stimme zu" # die Bestimmungen / I agree the rules login: sign_up: "Registrieren" @@ -71,7 +71,7 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra choose_your_level: "Wähle dein Level" adventurer_prefix: "Du kannst zu jedem Level springen oder diskutiere die Level " adventurer_forum: "im Abenteurerforum" -# adventurer_suffix: "." + adventurer_suffix: "." campaign_beginner: "Anfängerkampagne" campaign_beginner_description: "... in der Du die Zauberei der Programmierung lernst." campaign_dev: "Beliebiges schwierigeres Level" @@ -88,9 +88,9 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra contribute_prefix: "Wenn Du Interesse hast, uns zu unterstützen dann sieh dir die " contribute_page: "Unterstützer Seite" contribute_suffix: " an!" - forum_prefix: "Für alle öffentlichen Themen, benutze " + forum_prefix: "Für alle öffentlichen Themen, benutze stattdessen " forum_page: "unser Forum" - forum_suffix: " stattdessen." + forum_suffix: "." send: "Sende Feedback" diplomat_suggestion: @@ -103,7 +103,7 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra wizard_settings: title: "Zauberer Einstellungen" - customize_avatar: "Individualisiere dein Avatar" + customize_avatar: "Individualisiere deinen Avatar" account_settings: title: "Accounteinstellungen" @@ -115,16 +115,15 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra password_tab: "Passwort" emails_tab: "Emails" gravatar_select: "Wähle ein Gravatar Bild aus" - gravatar_add_photos: "Füge Vorschaubilder und Fotos zu Deinem Gravatar Account (für Deine Email) hinzu um ein Bild auswählen zu können" + gravatar_add_photos: "Füge Vorschaubilder und Fotos zu Deinem Gravatar Account (für Deine Email) hinzu, um ein Bild auswählen zu können" gravatar_add_more_photos: "Füge mehr Fotos bei deinem Gravatar Account hinzu, um hier mehr Bilder wählen zu können" wizard_color: "Die Farbe der Kleidung des Zauberers" new_password: "Neues Passwort" new_password_verify: "Passwort verifizieren" email_subscriptions: "Email Abonnements" email_announcements: "Ankündigungen" -# email_notifications_description: "Get periodic notifications for your account." - email_announcements_description: "Bekomme die aktuellesten Nachrichten und Entwicklungen bei CodeCombat." - contributor_emails: "Untersützer Emails" + email_announcements_description: "Erhalte regelmäßig Mitteilungen für deinen Account." + contributor_emails: "Unterstützer Email" contribute_prefix: "Wir suchen nach Leuten, die mitmachen! Schau dir die" contribute_page: "Unterstützer Seite" contribute_suffix: " an um mehr zu erfahren." @@ -191,7 +190,7 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra tome_select_a_thang: "Wähle jemanden aus, um " tome_available_spells: "Verfügbare Zauber" hud_continue: "Weiter (drücke Shift + Leertaste)" -# spell_saved: "Spell Saved" + spell_saved: "Zauber gespeichert" admin: av_title: "Administrator Übersicht" @@ -217,21 +216,22 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra hipchat_prefix: "Besuche uns auch in unserem" hipchat_url: "HipChat room." level_some_options: "Einige Einstellungsmöglichkeiten?" -# level_tab_thangs: "Thangs" # Things? +# level_tab_thangs: "Thangs" # Things? # <= no Thangs are the components of the level. Check the editor if you're not sure what it is. +# rather dont't translate it level_tab_scripts: "Skripte" level_tab_settings: "Einstellungen" level_tab_components: "Komponenten" level_tab_systems: "Systeme" -# level_tab_thangs_title: "Current Thangs" + level_tab_thangs_title: "Aktuelle Thangs" level_tab_thangs_conditions: "Startbedingungen" -# level_tab_thangs_add: "Add Thangs" + level_tab_thangs_add: "Thangs hinzufügen" level_settings_title: "Einstellungen" level_component_tab_title: "Aktuelle Komponenten" level_component_btn_new: "neue Komponente erstellen" level_systems_tab_title: "Aktuelle Systeme" level_systems_btn_new: "neues System erstellen" level_systems_btn_add: "System hinzufügen" -# level_components_title: "Back to All Thangs" + level_components_title: "Zurück zu allen Thangs" level_components_type: "Typ" level_component_edit_title: "Komponente bearbeiten" level_system_edit_title: "System bearbeiten" @@ -249,7 +249,7 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra body: "Inhalt" version: "Version" commit_msg: "Commit Nachricht" -# version_history_for: "Version History for: " + version_history_for: "Versionsgeschichte für: " results: "Ergebnisse" description: "Beschreibung" email: "Email" @@ -260,50 +260,50 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra who_is_codecombat: "Wer ist CodeCombat?" # Wer steckt hinter CodeCombat # behind why_codecombat: "Warum CodeCombat?" who_description_prefix: "gründeten CodeCombat im Jahre 2013 zusammen. Wir entwickelten außerdem " - who_description_suffix: ", die meist benutzte (Position #1) Web and iOS Applikation 2008 zum Schreiben lernen der Chinesischen und Japanischen Schriftzeichen." # need improvements + who_description_suffix: ", die meist benutzte (#1) Web and iOS Applikation 2008 zum Lernen des Schreibens von chinesischen und japanischen Schriftzeichen." # need improvements who_description_ending: "Nun ist es an der Zeit, den Leuten das Programmieren beizubringen." -# why_paragraph_1: "When making Skritter, George didn't know how to program and was constantly frustrated by his inability to implement his ideas. Afterwards, he tried learning, but the lessons were too slow. His housemate, wanting to reskill and stop teaching, tried Codecademy, but \"got bored.\" Each week another friend started Codecademy, then dropped off. We realized it was the same problem we'd solved with Skritter: people learning a skill via slow, intensive lessons when what they need is fast, extensive practice. We know how to fix that." -# why_paragraph_2: "Need to learn to code? You don't need lessons. You need to write a lot of code and have a great time doing it." -# why_paragraph_3_prefix: "That's what programming is about. It's gotta be fun. Not fun like" -# why_paragraph_3_italic: "yay a badge" -# why_paragraph_3_center: "but fun like" -# why_paragraph_3_italic_caps: "NO MOM I HAVE TO FINISH THE LEVEL!" -# why_paragraph_3_suffix: "That's why CodeCombat is a multiplayer game, not a gamified lesson course. We won't stop until you can't stop--but this time, that's a good thing." -# why_paragraph_4: "If you're going to get addicted to some game, get addicted to this one and become one of the wizards of the tech age." -# why_ending: "And hey, it's free. " -# why_ending_url: "Start wizarding now!" -# george_description: "CEO, business guy, web designer, game designer, and champion of beginning programmers everywhere." -# scott_description: "Programmer extraordinaire, software architect, kitchen wizard, and master of finances. Scott is the reasonable one." -# nick_description: "Programming wizard, eccentric motivation mage, and upside-down experimenter. Nick can do anything and chooses to build CodeCombat." -# jeremy_description: "Customer support mage, usability tester, and community organizer; you've probably already spoken with Jeremy." -# michael_description: "Programmer, sys-admin, and undergrad technical wunderkind, Michael is the person keeping our servers online." + why_paragraph_1: "Als er Skritter machte, wusste George nicht wie man programmiert und war permanent darüber frustriert, dass er seine Ideen nicht umsetzen konnte. Danach versuchte er es zu lernen, aber das ging ihm zu langsam. Sein Mitbewohner versuchte Codecademy, als er sich umorientierte und aufhörte zu lehren, aber \"langweilte sich\". Jede Woche begann ein neuer Freund mit Codecademy und ließ es dann wieder bleiben. Wir erkannten, dass es das gleiche Problem war, welches wir mit Skritter gelöst hatten: Leute lernen eine Fähigkeit mittels langsamer, intersiver Lerneinheiten, wobei sie schnelle, umfassende Übung bräuchten. Wir kennen Abhilfe." + why_paragraph_2: "Programmieren lernen? Du brauchst keine Stunden. Du musst einen Haufen Code schreiben und dabei Spaß haben." + why_paragraph_3_prefix: "Darum geht's beim Programmieren. Es soll Spaß machen. Nicht so einen Spaß wie" + why_paragraph_3_italic: "jau, 'ne Plakette" + why_paragraph_3_center: "sondern Spaß wie" + why_paragraph_3_italic_caps: "NEIN MUTTI ICH MUSS NOCH DEN LEVEL BEENDEN !" + why_paragraph_3_suffix: "Deshalb ist CodeCombat ein Multiplayerspiel und kein spielähnlicher Kurs. Wir werden nicht aufhören bis du nicht mehr aufhören kannst -- nur diesmal ist das eine gute Sache." + why_paragraph_4: "Wenn dich Spiele süchtig machen, dass lass dich von diesem süchtig machen und werde ein Zauberer des Technologiezeitalters." + why_ending: "Und hey, es kostet nichts. " + why_ending_url: "Beginne jetzt zu zaubern!" + george_description: "CEO, Businesstyp, Web Designer, Game Designer und Champion der Programmieranfänger überall." + scott_description: "Außergewöhnlicher Programmierer, Softwarearchitekt, Küchenzauberer und Finanzmeister. Scott ist der Vernünftige." + nick_description: "Programmierzauberer, exzentrischer Motivationskünstler und Auf-den-Kopf-stell-Experimentierer. Nick könnte alles mögliche tun und entschied CodeCombat zu bauen." + jeremy_description: "Kundendienstmagier, Usability Tester und Community-Organisator. Wahrscheinlich hast du schon mit Jeremy gesprochen." + michael_description: "Programmierer, Systemadministrator und studentisch technisches Wunderkind, Michael hält unsere Server am Laufen." -# legal: -# page_title: "Legal" -# opensource_intro: "CodeCombat is free to play and completely open source." -# opensource_description_prefix: "Check out " -# github_url: "our GitHub" -# opensource_description_center: "and help out if you like! CodeCombat is built on dozens of open source projects, and we love them. See " -# archmage_wiki_url: "our Archmage wiki" -# opensource_description_suffix: "for a list of the software that makes this game possible." -# practices_title: "Respectful Best Practices" -# practices_description: "These are our promises to you, the player, in slightly less legalese." -# privacy_title: "Privacy" -# privacy_description: "We will not sell any of your personal information. We intend to make money through recruitment eventually, but rest assured we will not distribute your personal information to interested companies without your explicit consent." -# security_title: "Security" -# security_description: "We strive to keep your personal information safe. As an open source project, our site is freely open to anyone to review and improve our security systems." -# email_title: "Email" -# email_description_prefix: "We will not inundate you with spam. Through" -# email_settings_url: "your email settings" -# email_description_suffix: "or through links in the emails we send, you can change your preferences and easily unsubscribe at any time." -# cost_title: "Cost" -# cost_description: "Currently, CodeCombat is 100% free! One of our main goals is to keep it that way, so that as many people can play as possible, regardless of place in life. If the sky darkens, we might have to charge subscriptions or for some content, but we'd rather not. With any luck, we'll be able to sustain the company with:" -# recruitment_title: "Recruitment" -# recruitment_description_prefix: "Here on CodeCombat, you're going to become a powerful wizard–not just in the game, but also in real life." -# url_hire_programmers: "No one can hire programmers fast enough" -# recruitment_description_suffix: "so once you've sharpened your skills and if you agree, we will demo your best coding accomplishments to the thousands of employers who are drooling for the chance to hire you. They pay us a little, they pay you" -# recruitment_description_italic: "a lot" -# recruitment_description_ending: "the site remains free and everybody's happy. That's the plan." + legal: + page_title: "Rechtliches" + opensource_intro: "CodeCombat ist Free-to-Play und vollständig Open Source." + opensource_description_prefix: "Schau dir " + github_url: "unsere GitHub-Seite" + opensource_description_center: " an und mach mit wenn Du möchtest! CodeCombat baut auf duzenden Open Source Projekten auf, und wir lieben sie. Schau dir die Liste in " + archmage_wiki_url: "unserem Erzmagier-Wiki" + opensource_description_suffix: " an, welche Software dieses Spiel möglich macht." + practices_title: "Best Practices" + practices_description: "Dies sind unsere Versprechen an dich, den Spieler, in weniger Fachchinesisch." + privacy_title: "Datenschutz" + privacy_description: "Wir werden deine persönlichen Daten nicht verkaufen. Letztenendes beabsichtigen wir, durch Vermittlung von Jobs zu verdienen, aber sei versichert, dass wir nicht deine persönlichen Daten ohne deine ausdrückliche Einwilligung interessierten Firmen zur Verfügung stellen werden." + security_title: "Datensicherheit" + security_description: "Wir streben an, deine persönlichen Daten sicher zu verwahren. Als Open Source Projekt ist unsere Site frei zugänglich für jedermann, auch um unsere Sicherheitsmaßnahmen in Augenschein zu nehmen und zu verbessern." + email_title: "Email" + email_description_prefix: "Wir werden dich nicht mit Spam überschwemmen. Mittels" + email_settings_url: "deiner Emaileinstellungen" + email_description_suffix: "oder durch von uns gesendete Links kannst du jederzeit deine Einstellungen ändern und Abonnements kündigen." + cost_title: "Kosten" + cost_description: "CodeCombat ist zur Zeit 100% kostenlos! Eines unserer Hauptziele ist, es dabei zu belassen, so dass es so viele Leute wie möglich spielen können, unabhängig davon in welcher Lebenssituation sie sich befinden. Falls dunkle Wolken aufziehen, könnten wir manche Inhalte im Rahmen eines Abonnements anbieten, aber lieber nicht. Mit etwas Glück können wir die Firma erhalten durch:" + recruitment_title: "Recruiting" + recruitment_description_prefix: "Hier bei CodeCombat kannst du ein mächtiger Zauberer werden, nicht nur im Spiel, sondern auch in der Realität." + url_hire_programmers: "Niemand kann schnell genug Programmierer einstellen." + recruitment_description_suffix: "So wenn du deine Fähigkeiten entwickelt hast und zustimmst, werden wir deine besten Leistungen den tausenden Arbeitgebern demonstrieren, welche nur auf die Gelegentheit warten, dich einzustellen. Sie bezahlen uns ein bisschen, und sie bezahlen dir " + recruitment_description_italic: "jede Menge" + recruitment_description_ending: ", die Seite bleibt kostenlos und jeder ist glücklich. So der Plan." # copyrights_title: "Copyrights and Licenses" # contributor_title: "Contributor License Agreement" # contributor_description_prefix: "All contributions, both on the site and on our GitHub repository, are subject to our" diff --git a/app/locale/es-ES.coffee b/app/locale/es-ES.coffee index 270524666..4620e91ca 100644 --- a/app/locale/es-ES.coffee +++ b/app/locale/es-ES.coffee @@ -4,12 +4,12 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis saving: "Guardando..." sending: "Enviando..." cancel: "Cancelar" -# save: "Save" + save: "Guardar" delay_1_sec: "1 segundo" delay_3_sec: "3 segundos" delay_5_sec: "5 segundos" manual: "Manual" -# fork: "Fork" + fork: "Bifurcar" play: "Jugar" modal: @@ -31,15 +31,15 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis about: "Sobre nosotros" contact: "Contacta" twitter_follow: "Síguenos" -# employers: "Employers" + employers: "Empresas" -# versions: -# save_version_title: "Save New Version" -# new_major_version: "New Major Version" -# cla_prefix: "To save changes, first you must agree to our" -# cla_url: "CLA" -# cla_suffix: "." -# cla_agree: "I AGREE" + versions: + save_version_title: "Guardar nueva versión" + new_major_version: "Nueva versión principal" + cla_prefix: "Para guardar los cambios, primero debes aceptar nuestro" + cla_url: "CLA" + cla_suffix: "." + cla_agree: "De acuerdo" login: sign_up: "Crear una cuenta" @@ -49,10 +49,10 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis recover: recover_account_title: "recuperar cuenta" -# send_password: "Send Recovery Password" + send_password: "Enviar recuperación de contraseña" signup: -# create_account_title: "Create Account to Save Progress" + create_account_title: "Crea una cuenta para guardar tu progreso" description: "Es gratis. Solo necesitamos un par de cosas y listo para comenzar!" email_announcements: "Recibir noticias por correo electrónico" coppa: "Soy mayor de 13 o de fuera de los Estados Unidos" @@ -70,25 +70,25 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis play: choose_your_level: "Elige tu nivel" adventurer_prefix: "Puedes elegir cualquier pantalla o charlar en " - adventurer_forum: "el foro del aventurero" + adventurer_forum: "el foro del aventurero " adventurer_suffix: "sobre ello." campaign_beginner: "Campaña de Principiante" campaign_beginner_description: "... en la que aprenderás la magia de la programación." campaign_dev: "Niveles aleatorios más dificiles" - campaign_dev_description: "... en la que aprenderás sobre la interfaz mientras haces algo más difícil." + campaign_dev_description: "... en los que aprenderás sobre la interfaz mientras haces algo más difícil." campaign_multiplayer: "Arenas Multijugador" campaign_multiplayer_description: "... en las que tu código se enfrentará al de otros jugadores." campaign_player_created: "Creaciones de los Jugadores" - campaign_player_created_description: "... en la que luchas contra la creatividad de tus compañeros Magos Artesanos." + campaign_player_created_description: "... en las que luchas contra la creatividad de tus compañeros Magos Artesanos." level_difficulty: "Dificultad: " contact: contact_us: "Contacta con CodeCombat" - welcome: "¡Nos gusta saber de ti! Usa este formulario para enviarnos un correo." + welcome: "¡Nos gusta saber de ti! Usa este formulario para enviarnos un correo. " contribute_prefix: "Si estás interesado en colaborar, ¡échale un vistazo a nuestra " contribute_page: "página de contribuciones" contribute_suffix: "!" - forum_prefix: "Para cosas públicos, por favor usa " + forum_prefix: "Para asuntos públicos, por favor usa " forum_page: "nuestro foro" forum_suffix: " en su lugar." send: "Envía tu comentario" @@ -96,14 +96,14 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis diplomat_suggestion: title: "¡Ayuda a traducir CodeCombat!" sub_heading: "Necesitamos tus habilidades lingüisticas." - pitch_body: "Nosotros desarrollamos CodeCombat en inglés, pero ya tenemos jugadores de todo el mundo. Muchos de ellos quieren jugar en Español porque no hablan inglés, así quesi hablas ambos idiomas, inscríbete como Diplomático y ayuda a traducir la web y todos los niveles de CodeCombat al Español." - missing_translations: "Mientras terminamos la traducción al Español, verás en inglés las partes que no estén todavía disponibles." + pitch_body: "Nosotros desarrollamos CodeCombat en inglés, pero ya tenemos jugadores de todo el mundo. Muchos de ellos quieren jugar en español porque no hablan inglés, así que si hablas ambos idiomas, inscríbete como Diplomático y ayuda a traducir la web y todos los niveles de CodeCombat al español." + missing_translations: "Mientras terminamos la traducción al español, verás en inglés las partes que no estén todavía disponibles." learn_more: "Aprende más sobre ser un Diplomático" subscribe_as_diplomat: "Suscríbete como Diplomático" -# wizard_settings: -# title: "Wizard Settings" -# customize_avatar: "Customize Your Avatar" + wizard_settings: + title: "Ajustes del mago" + customize_avatar: "Personaliza tu Avatar" account_settings: title: "Ajustes de la cuenta" @@ -118,11 +118,11 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis gravatar_add_photos: "Añade fotos a la cuenta de Gravatar asociada a tu correo electrónico para elegir la imagen." gravatar_add_more_photos: "Añade más fotos a tu cuenta de Gravatar para tener acceso a ellas aquí." wizard_color: "Color de la ropa del Mago" - new_password: "Nuevo contraseña" + new_password: "Nueva contraseña" new_password_verify: "Verificar" email_subscriptions: "Suscripciones de correo electrónico" email_announcements: "Noticias" -# email_notifications_description: "Get periodic notifications for your account." + email_notifications_description: "Recibe notificaciones periódicas en tu cuenta." email_announcements_description: "Recibe correos electrónicos con las últimas noticias y desarrollos de CodeCombat." contributor_emails: "Correos para colaboradores" contribute_prefix: "¡Buscamos gente que se una a nuestro comunidad! Comprueba la " @@ -139,15 +139,15 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis # profile_for_suffix: "" profile: "Perfil" user_not_found: "No se encontró al usuario. ¿Comprueba la URL?" - gravatar_not_found_mine: "No podemos encontrar el prefil asociado con:" + gravatar_not_found_mine: "No podemos encontrar el perfil asociado con:" # gravatar_not_found_email_suffix: "." - gravatar_signup_prefix: "Suscribete " + gravatar_signup_prefix: "¡Suscribete a " gravatar_signup_suffix: " para ponerte en marcha!" gravatar_not_found_other: "Vaya, no hay un perfil asociado a la dirección de correo electrónico de esta persona." gravatar_contact: "Contacto" gravatar_websites: "Paginas web" - gravatar_accounts: "Como se vé en" - gravatar_profile_link: "Prefil de Gravatar completo" + gravatar_accounts: "Como se ve en" + gravatar_profile_link: "Perfil de Gravatar completo" play_level: level_load_error: "No se pudo cargar el nivel." @@ -191,251 +191,251 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis tome_select_a_thang: "Selecciona a alguien para " tome_available_spells: "Hechizos disponibles" hud_continue: "Continuar (pulsa Shift+Space)" -# spell_saved: "Spell Saved" + spell_saved: "Hechizo guardado" # admin: -# av_title: "Admin Views" -# av_entities_sub_title: "Entities" -# av_entities_users_url: "Users" -# av_entities_active_instances_url: "Active Instances" -# av_other_sub_title: "Other" -# av_other_debug_base_url: "Base (for debugging base.jade)" -# u_title: "User List" -# lg_title: "Latest Games" + av_title: "Vista de Administrador" + av_entities_sub_title: "Entidades" + av_entities_users_url: "Usuarios" + av_entities_active_instances_url: "Instancias Activas" + av_other_sub_title: "Otras" + av_other_debug_base_url: "Base (para depurar base.jade)" + u_title: "Lista de Usuario" + lg_title: "Últimos juegos" -# editor: -# main_title: "CodeCombat Editors" -# main_description: "Build your own levels, campaigns, units and educational content. We provide all the tools you need!" -# article_title: "Article Editor" -# article_description: "Write articles that give players overviews of programming concepts which can be used across a variety of levels and campaigns." -# thang_title: "Thang Editor" -# thang_description: "Build units, defining their default logic, graphics and audio. Currently only supports importing Flash exported vector graphics." -# level_title: "Level Editor" -# level_description: "Includes the tools for scripting, uploading audio, and constructing custom logic to create all sorts of levels. Everything we use ourselves!" -# security_notice: "Many major features in these editors are not currently enabled by default. As we improve the security of these systems, they will be made generally available. If you'd like to use these features sooner, " -# contact_us: "contact us!" -# hipchat_prefix: "You can also find us in our" -# hipchat_url: "HipChat room." -# level_some_options: "Some Options?" -# level_tab_thangs: "Thangs" -# level_tab_scripts: "Scripts" -# level_tab_settings: "Settings" -# level_tab_components: "Components" -# level_tab_systems: "Systems" -# level_tab_thangs_title: "Current Thangs" -# level_tab_thangs_conditions: "Starting Conditions" -# level_tab_thangs_add: "Add Thangs" -# level_settings_title: "Settings" -# level_component_tab_title: "Current Components" -# level_component_btn_new: "Create New Component" -# level_systems_tab_title: "Current Systems" -# level_systems_btn_new: "Create New System" -# level_systems_btn_add: "Add System" -# level_components_title: "Back to All Thangs" -# level_components_type: "Type" -# level_component_edit_title: "Edit Component" -# level_system_edit_title: "Edit System" -# create_system_title: "Create New System" -# new_component_title: "Create New Component" -# new_component_field_system: "System" + editor: + main_title: "Editores de CodeCombat" + main_description: "Construye tus propios niveles, campañas, unidades y contenido educativo. ¡Nosotros te ofrecemos todas las herramientas que necesitas!" + article_title: "Editor de artículos" + article_description: "Escribe artículos que den a los jugadores una visión general de los conceptos de programación que se pueden utilizar a lo largo de una gran variedad de niveles y campañas." + thang_title: "Editor de Objetos" + thang_description: "Construye unidades, su lógica predeterminada, gráficos y audio. Actualmente sólo se permite importar gráficos vectoriales exportados de Flash." + level_title: "Editor de Niveles" + level_description: "Incluye las herramientas para escribir scripts, subir audio, y construir una lógica personalidad con la que crear todo tipo de niveles. ¡Todo lo que usamos nosotros!" + security_notice: "Muchas de las funciones principales de estos editores no están habilitadas todavía por defecto. A medida que mejoremos la seguridad de los sistemas, se irán poniendo a disposición de todos. Si quieres utilizar estas funciones antes, " + contact_us: "¡Contacta con nosotros!" + hipchat_prefix: "También puedes encontrarnos en nuestra" + hipchat_url: "sala de HipChat." + level_some_options: "¿Algunas opciones?" + level_tab_thangs: "Objetos" + level_tab_scripts: "Scripts" + level_tab_settings: "Ajustes" + level_tab_components: "Componentes" + level_tab_systems: "Sistemas" + level_tab_thangs_title: "Objetos actuales" + level_tab_thangs_conditions: "Condiciones de inicio" + level_tab_thangs_add: "Añadir Objetos" + level_settings_title: "Ajustes" + level_component_tab_title: "Componentes Actuales" + level_component_btn_new: "Crear Nuevo Componente" + level_systems_tab_title: "Sistemas Actuales" + level_systems_btn_new: "Crear Nuevo Sistema" + level_systems_btn_add: "Añadir Sistema" + level_components_title: "Volver a Todos los Objetos" + level_components_type: "Tipo" + level_component_edit_title: "Editar Componente" + level_system_edit_title: "Editar Sistema" + create_system_title: "Crear Nuevo Sistema" + new_component_title: "Crear Nuevo Componente" + new_component_field_system: "Sistema" -# article: -# edit_btn_preview: "Preview" -# edit_article_title: "Edit Article" + article: + edit_btn_preview: "Vista preliminar" + edit_article_title: "Editar artículo" -# general: -# and: "and" + general: + and: "y" or: "o" -# name: "Name" -# body: "Body" -# version: "Version" -# commit_msg: "Commit Message" -# version_history_for: "Version History for: " -# results: "Results" -# description: "Description" + name: "Nombre" + body: "Cuerpo" + version: "Versión" + commit_msg: "Mensaje de Asignación o Commit" + version_history_for: "Historial de las versiones de: " + results: "Resultados" + description: "Descripción" email: "Correo electrónico" message: "Mensaje" -# about: -# who_is_codecombat: "Who is CodeCombat?" -# why_codecombat: "Why CodeCombat?" -# who_description_prefix: "together started CodeCombat in 2013. We also created " -# who_description_suffix: "in 2008, growing it to the #1 web and iOS application for learning to write Chinese and Japanese characters." -# who_description_ending: "Now it's time to teach people to write code." -# why_paragraph_1: "When making Skritter, George didn't know how to program and was constantly frustrated by his inability to implement his ideas. Afterwards, he tried learning, but the lessons were too slow. His housemate, wanting to reskill and stop teaching, tried Codecademy, but \"got bored.\" Each week another friend started Codecademy, then dropped off. We realized it was the same problem we'd solved with Skritter: people learning a skill via slow, intensive lessons when what they need is fast, extensive practice. We know how to fix that." -# why_paragraph_2: "Need to learn to code? You don't need lessons. You need to write a lot of code and have a great time doing it." -# why_paragraph_3_prefix: "That's what programming is about. It's gotta be fun. Not fun like" -# why_paragraph_3_italic: "yay a badge" -# why_paragraph_3_center: "but fun like" -# why_paragraph_3_italic_caps: "NO MOM I HAVE TO FINISH THE LEVEL!" -# why_paragraph_3_suffix: "That's why CodeCombat is a multiplayer game, not a gamified lesson course. We won't stop until you can't stop--but this time, that's a good thing." -# why_paragraph_4: "If you're going to get addicted to some game, get addicted to this one and become one of the wizards of the tech age." -# why_ending: "And hey, it's free. " -# why_ending_url: "Start wizarding now!" -# george_description: "CEO, business guy, web designer, game designer, and champion of beginning programmers everywhere." -# scott_description: "Programmer extraordinaire, software architect, kitchen wizard, and master of finances. Scott is the reasonable one." -# nick_description: "Programming wizard, eccentric motivation mage, and upside-down experimenter. Nick can do anything and chooses to build CodeCombat." -# jeremy_description: "Customer support mage, usability tester, and community organizer; you've probably already spoken with Jeremy." -# michael_description: "Programmer, sys-admin, and undergrad technical wunderkind, Michael is the person keeping our servers online." + about: + who_is_codecombat: "¿Qué es CodeCombat?" + why_codecombat: "¿Por qué CodeCombat?" + who_description_prefix: "juntos comenzamos CodeCombat en 2013. También creamos " + who_description_suffix: "en 2008, llegando a alcanzar el primer puesto en aplicaciones web, una app para iOS para el aprendizaje de la escritura de caracteres chinos y japoneses." + who_description_ending: "Es hora de empezar a enseñar a la gente a escribir código." + why_paragraph_1: "Mientras desarrollaba Skritter, George no sabía cómo programar y estaba constantemente frustrado por su incapacidad para implementar sus ideas. Posteriormente, intentó aprender, pero las lecciones eran demasiado lentas. Su compañero de piso, queriendo dejar de enseñar y reorientar su carrera, probó Codecademy, pero \"se aburrió. \" Cada semana otro amigo comenzaba en Codecademy, para terminar dejándolo posteriormente. Nos dimos cuenta de que era el mismo problema que habíamos resuelto con Skritter: gente aprendiendo una habilidad lentamente con lecciones intensivas cuando lo que necesitaban era una práctica rápida y extensa. Sabemos cómo solucionar eso." + why_paragraph_2: "¿Necesitas aprender a programar? No necesitas lecciones. Necesitas escribir muchísimo código y pasarlo bien haciéndolo." + why_paragraph_3_prefix: "De eso va la programación. Tiene que ser divertido. No divertido como:" + why_paragraph_3_italic: "¡bien una insignia!," + why_paragraph_3_center: "sino más bien como:" + why_paragraph_3_italic_caps: "¡NO MAMA, TENGO QUE TERMINAR EL NIVEL!" + why_paragraph_3_suffix: "Por eso Codecombat es multijugador, no un curso con lecciones \"gamificadas\" . No pararemos hasta que tú no puedas parar... pero esta vez, eso será buena señal." + why_paragraph_4: "Si vas a engancharte a algún juego, engánchate a este y conviértete en uno de los magos de la era tecnológica." + why_ending: "Y, oye, es gratis. " + why_ending_url: "Comienza a hacer magia ¡ya!" + george_description: "CEO, el tipo de los negocios, diseñador web, diseñador de juegos y campeón de los programadores principiantes de todo el mundo." + scott_description: "Programador extraordinario, arquitecto de software, mago de la cocina y maestro de las finanzas. Scott es el razonable." + nick_description: "Mago de la programación, hechicero excéntrico de la motivación y experimentador del revés. Nick pudo haber hecho cualquier cosa y eligió desarrollar CodeCombat." + jeremy_description: "Mago de la atención al cliente, tester de usabilidad y organizador de la comunidad; es probable que ya hayas hablado con Jeremy." + michael_description: "Programador, administrador de sistemas y prodigio técnico, Michael es el encargado de mantener nuestros servidores en línea." -# legal: -# page_title: "Legal" -# opensource_intro: "CodeCombat is free to play and completely open source." -# opensource_description_prefix: "Check out " -# github_url: "our GitHub" -# opensource_description_center: "and help out if you like! CodeCombat is built on dozens of open source projects, and we love them. See " -# archmage_wiki_url: "our Archmage wiki" -# opensource_description_suffix: "for a list of the software that makes this game possible." -# practices_title: "Respectful Best Practices" -# practices_description: "These are our promises to you, the player, in slightly less legalese." -# privacy_title: "Privacy" -# privacy_description: "We will not sell any of your personal information. We intend to make money through recruitment eventually, but rest assured we will not distribute your personal information to interested companies without your explicit consent." -# security_title: "Security" -# security_description: "We strive to keep your personal information safe. As an open source project, our site is freely open to anyone to review and improve our security systems." -# email_title: "Email" -# email_description_prefix: "We will not inundate you with spam. Through" -# email_settings_url: "your email settings" -# email_description_suffix: "or through links in the emails we send, you can change your preferences and easily unsubscribe at any time." -# cost_title: "Cost" -# cost_description: "Currently, CodeCombat is 100% free! One of our main goals is to keep it that way, so that as many people can play as possible, regardless of place in life. If the sky darkens, we might have to charge subscriptions or for some content, but we'd rather not. With any luck, we'll be able to sustain the company with:" -# recruitment_title: "Recruitment" -# recruitment_description_prefix: "Here on CodeCombat, you're going to become a powerful wizard–not just in the game, but also in real life." -# url_hire_programmers: "No one can hire programmers fast enough" -# recruitment_description_suffix: "so once you've sharpened your skills and if you agree, we will demo your best coding accomplishments to the thousands of employers who are drooling for the chance to hire you. They pay us a little, they pay you" -# recruitment_description_italic: "a lot" -# recruitment_description_ending: "the site remains free and everybody's happy. That's the plan." -# copyrights_title: "Copyrights and Licenses" -# contributor_title: "Contributor License Agreement" -# contributor_description_prefix: "All contributions, both on the site and on our GitHub repository, are subject to our" -# cla_url: "CLA" -# contributor_description_suffix: "to which you should agree before contributing." -# code_title: "Code - MIT" -# code_description_prefix: "All code owned by CodeCombat or hosted on codecombat.com, both in the GitHub repository or in the codecombat.com database, is licensed under the" -# mit_license_url: "MIT license" -# code_description_suffix: "This includes all code in Systems and Components that are made available by CodeCombat for the purpose of creating levels." -# art_title: "Art/Music - Creative Commons " -# art_description_prefix: "All common content is available under the" -# cc_license_url: "Creative Commons Attribution 4.0 International License" -# art_description_suffix: "Common content is anything made generally available by CodeCombat for the purpose of creating Levels. This includes:" -# art_music: "Music" -# art_sound: "Sound" -# art_artwork: "Artwork" -# art_sprites: "Sprites" -# art_other: "Any and all other non-code creative works that are made available when creating Levels." -# art_access: "Currently there is no universal, easy system for fetching these assets. In general, fetch them from the URLs as used by the site, contact us for assistance, or help us in extending the site to make these assets more easily accessible." -# art_paragraph_1: "For attribution, please name and link to codecombat.com near where the source is used or where appropriate for the medium. For example:" -# use_list_1: "If used in a movie or another game, include codecombat.com in the credits." -# use_list_2: "If used on a website, include a link near the usage, for example underneath an image, or in a general attributions page where you might also mention other Creative Commons works and open source software being used on the site. Something that's already clearly referencing CodeCombat, such as a blog post mentioning CodeCombat, does not need some separate attribution." -# art_paragraph_2: "If the content being used is created not by CodeCombat but instead by a user of codecombat.com, attribute them instead, and follow attribution directions provided in that resource's description if there are any." -# rights_title: "Rights Reserved" -# rights_desc: "All rights are reserved for Levels themselves. This includes" -# rights_scripts: "Scripts" -# rights_unit: "Unit configuration" -# rights_description: "Description" -# rights_writings: "Writings" -# rights_media: "Media (sounds, music) and any other creative content made specifically for that Level and not made generally available when creating Levels." -# rights_clarification: "To clarify, anything that is made available in the Level Editor for the purpose of making levels is under CC, whereas the content created with the Level Editor or uploaded in the course of creation of Levels is not." -# nutshell_title: "In a Nutshell" -# nutshell_description: "Any resources we provide in the Level Editor are free to use as you like for creating Levels. But we reserve the right to restrict distribution of the Levels themselves (that are created on codecombat.com) so that they may be charged for in the future, if that's what ends up happening." -# canonical: "The English version of this document is the definitive, canonical version. If there are any discrepencies between translations, the English document takes precedence." + legal: + page_title: "Legal" + opensource_intro: "CodeCombat es gratis y totalmente open source." + opensource_description_prefix: "Echa un vistazo a " + github_url: "nuestro GitHub" + opensource_description_center: "y ayúdanos si quieres. CodeCombat está desarrollado sobre docenas de proyectos open source, y nos encantana. Mira " + archmage_wiki_url: "nuestra wiki del Archimago" + opensource_description_suffix: "para encontrar una lista del software que hace este juego posible." + practices_title: "Prácticas respetuosas" + practices_description: "Esto es lo que te prometemos a ti, el jugador, sin usar mucha jerga legal." + privacy_title: "Privacidad" + privacy_description: "No venderemos tu información personal. Tenemos la intención de hacer dinero a través de la contratación con el tiempo, pero puedes estar seguro que no vamos a distribuir tu información personal a las empresas interesadas sin tu consentimiento expreso." + security_title: "Seguridad" + security_description: "Nos esforzamos por mantener segura tu información personal. Como proyecto de código abierto, nuestro sitio está abierto a cualquiera que quiera revisarlo y mejorar nuestros sistemas de seguridad." + email_title: "Correo electrónico" + email_description_prefix: "No te inundaremos con spam. Mediante" + email_settings_url: "tus ajustes de correo electrónico" + email_description_suffix: "o a través de los enlaces en los correos que te enviemos, puedes cambiar tus preferencias y darte de baja fácilmente en cualquier momento." + cost_title: "Precio" + cost_description: "Actualmente, ¡CodeCombat es 100% gratis! Uno de nuestros principales objetivos es mantenerlo así, de forma que el mayor número posible de gente pueda jugar, independientemente de sus posibilidades económicas. Si las cosas se tuercen, quizás tengamos que cobrar suscripciones o por algún contenido, pero preferimos no hacerlo. Con un poco de suerte, podremos mantener la empresa con: " + recruitment_title: "Contratación" + recruitment_description_prefix: "En CodeCombat, te vas a convertir en un poderoso mago no solo en el juego, también en el mundo real." + url_hire_programmers: "Nadie puede contratar programadores con la suficiente rapidez" + recruitment_description_suffix: "así que una vez que hayas afilado tus habilidades y si estás de acuerdo, mostraremos tus mejores logros en programación a los miles de empresas que están deseando tener la oportunidad de contratarte. Ellos nos pagan un poco y ellos te pagan a ti" + recruitment_description_italic: "un montón." + recruitment_description_ending: "La web permanece gratuita y todo el mundo es feliz. Ese es el plan." + copyrights_title: "Copyrights y Licencias" + contributor_title: "Acuerdo de Licencia del Colaborador" + contributor_description_prefix: "Todas las colaboraciones, tanto en la web como en nuestro repositorio de GitHub, están sujetas a nuestro" + cla_url: "CLA" + contributor_description_suffix: "con el que deberás estar de acuerdo antes de colaborar." + code_title: "Código - MIT" + code_description_prefix: "Todo el código propiedad de CodeCombat o alojado en codecombat.com, ambos en el repositorio GitHub repository o en la base de datos de codecombat.com, está licenciado bajo la " + mit_license_url: "Licencia MIT" + code_description_suffix: "Esto incluye todo el código en Sistemas y Componentes puesto a disposición por CodeCombat para la creación de niveles." + art_title: "Arte/Música - Creative Commons " + art_description_prefix: "Todo el contenido común está disponible bajo la" + cc_license_url: "Creative Commons Attribution 4.0 International License" + art_description_suffix: "Contenido común es cualquier cosa puesta a disposición por CodeCombat con el propósito de la creación de niveles. Esto incluye:" + art_music: "Música" + art_sound: "Sonido" + art_artwork: "Arte" + art_sprites: "Sprites" + art_other: "Otros trabajos creativos no relacionados con código puestos a disposición para la creación de Niveles." + art_access: "Actualmente no hay un sistema universal y fácil para ir en busca de esos recursos. En general, recógelos de las URLs como las usadas en el sitio, contáctanos para recibir asistencia, o ayúdanos a extender el sitio para hacer más facilmente accesibles estos recursos." + art_paragraph_1: "Para la atribución, por favor pon tu nombre y enlaza a codecombat.com cerca del lugar donde se utiliza la fuente o en su caso para el medio. Por ejemplo:" + use_list_1: "Si se usa en una película u otro juego, incluye codecombat.com en los créditos." + use_list_2: "Si se usa en una página web, incluye un enlace cerca de donde se use, por ejemplo bajo una imagen, o en una página general de atribuciones donde también menciones otros trabajos Creative Commons y software de código abierto que uses en tu web. Si ya se hace clara referencia a CodeCombat, como en el post de un blog mencionando a CodeCombat, no es necesaria una atribución del contenido por separado." + art_paragraph_2: "Si el contenido usado ha sido creado no por CodeCombat sino por un usuario de codecombat.com, deberá serle atribuido a dicho usuario y seguir las directrices de atribución proporcionadas en la descripción del recurso, si la hay." + rights_title: "Derechos Reservados" + rights_desc: "Todos los derechos reservados para los Niveles. Esto incluye" + rights_scripts: "Scripts" + rights_unit: "Configuración de la Unidad" + rights_description: "Descripción" + rights_writings: "Escritos" + rights_media: "Media (sonidos, música) y cualquier otro contenido creativo creado específicamente para ese Nivel y que no estuviera disponible para todos al crear el/los niveles." + rights_clarification: "Para aclarar, cualquier cosa que se pone a disposición en el editor de niveles con el fin de crear Niveles se encuentra bajo licencia CC, mientras que el contenido creado con el editor de niveles o subido en el curso de la creación de niveles no lo es." + nutshell_title: "En una palabra" + nutshell_description: "Todos los recursos que ofrecemos en el editor de niveles son libres de ser utilizados para crear niveles. Pero nos reservamos el derecho de restringir la distribución de los propios niveles (que se crean en codecombat.com) de modo que se pueda cobrar por ellos en el futuro, si eso es lo que termina sucediendo." + canonical: "La versión inglesa de este documento es la canónica, la definitiva. Si hay alguna diferencia con lo que pueda aparecer en las traducciones, la versión inglesa es la que prevalece sobre las demás." -# contribute: -# page_title: "Contributing" -# character_classes_title: "Character Classes" -# introduction_desc_intro: "We have high hopes for CodeCombat." -# introduction_desc_pref: "We want to be where programmers of all stripes come to learn and play together, introduce others to the wonderful world of coding, and reflect the best parts of the community. We can't and don't want to do that alone; what makes projects like GitHub, Stack Overflow and Linux great are the people who use them and build on them. To that end, " -# introduction_desc_github_url: "CodeCombat is totally open source" -# introduction_desc_suf: ", and we aim to provide as many ways as possible for you to take part and make this project as much yours as ours." -# introduction_desc_ending: "We hope you'll join our party!" -# introduction_desc_signature: "- Nick, George, Scott, Michael, and Jeremy" -# alert_account_message_intro: "Hey there!" -# alert_account_message_pref: "To subscribe for class emails, you'll need to " -# alert_account_message_suf: "first." -# alert_account_message_create_url: "create an account" -# archmage_introduction: "One of the best parts about building games is they synthesize so many different things. Graphics, sound, real-time networking, social networking, and of course many of the more common aspects of programming, from low-level database management, and server administration to user facing design and interface building. There's a lot to do, and if you're an experienced programmer with a hankering to really dive into the nitty-gritty of CodeCombat, this class might be for you. We would love to have your help building the best programming game ever." -# class_attributes: "Class Attributes" -# archmage_attribute_1_pref: "Knowledge in " -# archmage_attribute_1_suf: ", or a desire to learn. Most of our code is in this language. If you're a fan of Ruby or Python, you'll feel right at home. It's JavaScript, but with a nicer syntax." -# archmage_attribute_2: "Some experience in programming and personal initiative. We'll help you get oriented, but we can't spend much time training you." -# how_to_join: "How To Join" -# join_desc_1: "Anyone can help out! Just check out our " -# join_desc_2: "to get started, and check the box below to mark yourself as a brave Archmage and get the latest news by email. Want to chat about what to do or how to get more deeply involved? " -# join_desc_3: ", or find us in our " -# join_desc_4: "and we'll go from there!" -# join_url_email: "Email us" -# join_url_hipchat: "public HipChat room" -# more_about_archmage: "Learn More About Becoming A Powerful Archmage" -# archmage_subscribe_desc: "Get emails on new coding opportunities and announcements." -# artisan_introduction_pref: "We must construct additional levels! People be clamoring for more content, and we can only build so many ourselves. Right now your workstation is level one; our level editor is barely usable even by its creators, so be wary. If you have visions of campaigns spanning for-loops to" -# artisan_introduction_suf: "to then this class might be for you." -# artisan_attribute_1: "Any experience in building content like this would be nice, such as using Blizzard's level editors. But not required!" -# artisan_attribute_2: "A hankering to do a whole lot of testing and iteration. To make good levels, you need to take it to others and watch them play it, and be prepared to find a lot of things to fix." -# artisan_attribute_3: "For the time being, endurance en par with an Adventurer. Our Level Editor is super preliminary and frustrating to use. You have been warned!" -# artisan_join_desc: "Use the Level Editor in these steps, give or take:" -# artisan_join_step1: "Read the documentation." -# artisan_join_step2: "Create a new level and explore existing levels." -# artisan_join_step3: "Find us in our public HipChat room for help." -# artisan_join_step4: "Post your levels on the forum for feedback." -# more_about_artisan: "Learn More About Becoming A Creative Artisan" -# artisan_subscribe_desc: "Get emails on level editor updates and announcements." -# adventurer_introduction: "Let's be clear about your role: you are the tank. You're going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class might be for you." -# adventurer_attribute_1: "A thirst for learning. You want to learn how to code and we want to teach you how to code. You'll probably be doing most of the teaching in this case, though." -# adventurer_attribute_2: "Charismatic. Be gentle but articulate about what needs improving, and offer suggestions on how to improve." -# adventurer_join_pref: "Either get together with (or recruit!) an Artisan and work with them, or check the box below to receive emails when there are new levels to test. We'll also be posting about levels to review on our networks like" -# adventurer_forum_url: "our forum" -# adventurer_join_suf: "so if you prefer to be notified those ways, sign up there!" -# more_about_adventurer: "Learn More About Becoming A Brave Adventurer" -# adventurer_subscribe_desc: "Get emails when there are new levels to test." -# scribe_introduction_pref: "CodeCombat isn't just going to be a bunch of levels. It will also include a resource for knowledge, a wiki of programming concepts that levels can hook into. That way rather than each Artisan having to describe in detail what a comparison operator is, they can simply link their level to the Article describing them that is already written for the player's edification. Something along the lines of what the " -# scribe_introduction_url_mozilla: "Mozilla Developer Network" -# scribe_introduction_suf: " has built. If your idea of fun is articulating the concepts of programming in Markdown form, then this class might be for you." -# scribe_attribute_1: "Skill in words is pretty much all you need. Not only grammar and spelling, but able to convey complicated ideas to others." -# contact_us_url: "Contact us" -# scribe_join_description: "tell us a little about yourself, your experience with programming and what sort of things you'd like to write about. We'll go from there!" -# more_about_scribe: "Learn More About Becoming A Diligent Scribe" -# scribe_subscribe_desc: "Get emails about article writing announcements." -# diplomat_introduction_pref: "So, if there's one thing we learned from the " -# diplomat_launch_url: "launch in October" -# diplomat_introduction_suf: "it's that there is sizeable interest in CodeCombat in other countries, particularly Brazil! We're building a corps of translators eager to turn one set of words into another set of words to get CodeCombat as accessible across the world as possible. If you like getting sneak peeks at upcoming content and getting these levels to your fellow nationals ASAP, then this class might be for you." -# diplomat_attribute_1: "Fluency in English and the language you would like to translate to. When conveying complicated ideas, it's important to have a strong grasp in both!" -# diplomat_join_pref: "We've started a lot of initial translations at " -# diplomat_doc_url: "this forum post" -# diplomat_join_suf: "so check it out and add things for your language. Also, check this box below to keep up-to-date on new internationalization developments!" -# more_about_diplomat: "Learn More About Becoming A Great Diplomat" -# diplomat_subscribe_desc: "Get emails about i18n developments and levels to translate." -# ambassador_introduction: "This is a community we're building, and you are the connections. We've got Olark chats, emails, and social networks with lots of people to talk with and help get acquainted with the game and learn from. If you want to help people get involved and have fun, and get a good feel of the pulse of CodeCombat and where we're going, then this class might be for you." -# ambassador_attribute_1: "Communication skills. Be able to identify the problems players are having and help them solve them. Also, keep the rest of us informed about what players are saying, what they like and don't like and want more of!" -# ambassador_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll go from there!" -# ambassador_join_note_strong: "Note" -# ambassador_join_note_desc: "One of our top priorities is to build multiplayer where players having difficulty solving levels can summon higher level wizards to help them. This will be a great way for ambassadors to do their thing. We'll keep you posted!" -# more_about_ambassador: "Learn More About Becoming A Helpful Ambassador" -# ambassador_subscribe_desc: "Get emails on support updates and multiplayer developments." -# counselor_introduction_1: "Do you have life experience? A different perspective on things that can help us decide how to shape CodeCombat? Of all these roles, this will probably take the least time, but individually you may make the most difference. We're on the lookout for wisened sages, particularly in areas like: teaching, game development, open source project management, technical recruiting, entrepreneurship, or design." -# counselor_introduction_2: "Or really anything that is relevant to the development of CodeCombat. If you have knowledge and want to share it to help grow this project, then this class might be for you." -# counselor_attribute_1: "Experience, in any of the areas above or something you think might be helpful." -# counselor_attribute_2: "A little bit of free time!" -# counselor_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll put you in our contact list and be in touch when we could use advice (not too often)." -# more_about_counselor: "Learn More About Becoming A Valuable Counselor" -# changes_auto_save: "Changes are saved automatically when you toggle checkboxes." -# diligent_scribes: "Our Diligent Scribes:" -# powerful_archmages: "Our Powerful Archmages:" -# creative_artisans: "Our Creative Artisans:" -# brave_adventurers: "Our Brave Adventurers:" -# translating_diplomats: "Our Translating Diplomats:" -# helpful_ambassadors: "Our Helpful Ambassadors:" + contribute: + page_title: "Colaborar" + character_classes_title: "Clases de Personajes" + introduction_desc_intro: "Tenemos muchas esperanzas en CodeCombat." + introduction_desc_pref: "Queremos estar donde programadores de todo tipo vengan a aprender y jugar juntos, introducir a otros en el maravilloso mundo de la programación y reflejar la mejor parte de la comunidad. No podemos, ni queremos, hacerlo solos; lo que hace grandes a proyectos como GitHub, Stack Overflow y Linux es la gente que los usa y crea con ellos. A tal fin, " + introduction_desc_github_url: "CodeCombat es totalmente de código abierto" + introduction_desc_suf: ", y nuestro objetivo es ofrecer tantas maneras como sea posible para que tomes parte y hagas de este proyecto algo tan tuyo como nuestro." + introduction_desc_ending: "¡Esperamos que te unas a nuestro equipo!" + introduction_desc_signature: "- Nick, George, Scott, Michael y Jeremy" + alert_account_message_intro: "¡Hola!" + alert_account_message_pref: "Para suscribirte a los correos electrónicos de las distintas Clases, necesitarás " + alert_account_message_suf: "primero." + alert_account_message_create_url: "crear una cuenta" + archmage_introduction: "Una de las mejores partes de desarrollar juegos es que combinan cosas muy diferentes. Gráficos, sonido, uso de redes en tiempo real, redes sociales y por supuesto mucho de los aspectos comunes de la programación, desde gestión de bases de datos a bajo nivel y administración de servidores hasta diseño de experiencia del usuario y creación de interfaces. Hay un montón de cosas por hacer y si eres un programador experimentado con interés en conocer lo que se cuece en la trastienda de CodeCombat, esta Clase puede ser la ideal para ti. Nos encantaría recibir tu ayuda para crear el mejor juego de programación de la historia." + class_attributes: "Atributos de las Clases" + archmage_attribute_1_pref: "Conocimiento en " + archmage_attribute_1_suf: ", o deseo por aprender. La mayor parte de nuestro código está escrito en este lenguaje. Si eres un fan de Ruby o Python te sentirás como en casa. Es JavaScript pero con una sintaxis más agradable." + archmage_attribute_2: "Alguna experiencia en programación e iniciativa personal. Te orientaremos, pero no podemos pasar mucho tiempo enseñándote." + how_to_join: "Cómo unirse" + join_desc_1: "¡Cualquiera puede ayudar! Solo echa un vistazo a nuestro " + join_desc_2: "para comenzar y marca la casilla de abajo para etiquetarte como un bravo Archimago y obtener las últimas noticias por correo electrónico. ¿Quieres charlar sobre qué hacer o como involucrarte más? " + join_desc_3: ", o encuéntranos en nuestro " + join_desc_4: "¡y partiremos desde ese punto!" + join_url_email: "Escríbenos un correo electrónico" + join_url_hipchat: "sala pública en HipChat" + more_about_archmage: "Aprende más sobre convertirte en un poderoso Archimago" + archmage_subscribe_desc: "Recibe correos sobre nuevos anuncios y oportunidades de codificar." + artisan_introduction_pref: "¡Debemos construir niveles adicionales! La gente clama por más contenido y solo podemos crear unos cuantos. Ahora mismo tu estación de trabajo es el nivel uno; nuestro editor de niveles es apenas usable por sus creadores, así que ten cuidado. Si tienes visiones de campañas que alcanzan el infinito" + artisan_introduction_suf: "entonces esta Clase es ideal para ti." + artisan_attribute_1: "Cualquier experiencia creando contenido similar estaría bien, como por ejemplo el editor de niveles de Blizzard. ¡Aunque no es necesaria!" + artisan_attribute_2: "Un anhelo de hacer un montón de testeo e iteraciones. Para hacer buenos niveles necesitas mostrárselos a otros y mirar como juegan, además de estar preparado para encontrar los fallos a reparar." + artisan_attribute_3: "Por el momento, la resistencia va a la par con el Aventurero. Nuestro editor de niveles está a un nivel de desarrollo temprano y puede ser muy frustrante usarlo. ¡Estás advertido!" + artisan_join_desc: "Sigue las siguientes indicaciones para usar el editor de niveles. Tómalo o déjalo:" + artisan_join_step1: "Lee la documentación." + artisan_join_step2: "Crea un nuevo nivel y explora los niveles existentes." + artisan_join_step3: "Busca nuestra sala pública de HipChat en busca de ayuda." + artisan_join_step4: "Publica tus niveles en el foro para recibir comentarios críticos." + more_about_artisan: "Aprende más sobre convertirte en un Artesano creativo" + artisan_subscribe_desc: "Recibe correos sobre actualizaciones del editor de niveles y anuncios." + adventurer_introduction: "Hablemos claro sobre tu papel: eres el tanque. Vas a recibir fuertes daños. Necesitamos gente para probar nuestros flamantes niveles y ayudar a mejorarlos. El dolor será enorme; hacer buenos juegos es un proceso largo y nadie lo consigue a la primera. Si puedes resistir y tener una puntuación alta en Resistencia, entonces esta Clase es para ti." + adventurer_attribute_1: "Estar sediento de conocimientos. Quieres aprender a programar y nosotros queremos enseñarte cómo hacerlo. Aunque en este caso es más probable que seas tú el que esté haciendo la mayor parte de la enseñanza." + adventurer_attribute_2: "Carismático. Se amable pero claro a la hora de desglosar qué necesita ser mejorado y sugiere de qué formas podría hacerse." + adventurer_join_pref: "Reúnete con (¡o recluta!) un Artesano y trabaja con ellos, o marca la casilla de abajo para recibir un correo cuando haya nuevos niveles para testar. También publicaremos en nuestras redes nuevos niveles para revisar" + adventurer_forum_url: "nuestro foro" + adventurer_join_suf: "así que si prefieres estar informado en esa forma, ¡crea una cuenta allí!" + more_about_adventurer: "Aprende más sobre cómo convertirte en un bravo Aventurero" + adventurer_subscribe_desc: "Recibe correos cuando haya nuevos niveles para testar." + scribe_introduction_pref: "CodeCombat no será solo un montón de niveles. También será una fuente de conocimientos, una wiki de conceptos de programación a la que los niveles se engancharan. De esa forma, en lugar de que cada Artesano tenga que describir en detalle qué es un operador de comparación, podrá simplemente enlazar el nivel al Artículo que los describe y que ya ha sido escrito para edificación del jugador. Algo en la línea de lo que la " + scribe_introduction_url_mozilla: "Mozilla Developer Network" + scribe_introduction_suf: " ha construido. Si tu idea de diversión es articular los conceptos de la programación de una forma sencilla, entonces esta clase es para ti." + scribe_attribute_1: "Habilidad a la hora de escribir es casi todo lo que necesitas. No solo dominar la gramática y la ortografía sino también expresar ideas complicadas a los demás de forma sencilla." + contact_us_url: "Escribenos un correo electrónico" + scribe_join_description: "cuéntanos más sobre ti, tu experiencia en el mundo de la programación y sobre qué cosas te gustaría escribir. ¡Y continuaremos a partir de ahí!" + more_about_scribe: "Aprende más sobre convertirte en un Escriba diligente" + scribe_subscribe_desc: "Recibe correos sobre anuncios de redacción de Artículos." + diplomat_introduction_pref: "Así, si hemos aprendido algo desde el " + diplomat_launch_url: "lanzamiento en octubre" + diplomat_introduction_suf: "hay un interés considerable en CodeCombat en otros paises, ¡especialmente Brasil! Estamos formando un cuerpo de traductores con ganas de traducir un grupo de palabras tras otro para hacer CodeCombat tan accesible para todo el mundo como sea posible. Si quieres recibir avances de próximos contenidos y quieres poner esos niveles a disposición de los que comparten tu idioma tan pronto como sea posible, entonces esta Clase es para ti." + diplomat_attribute_1: "Fluidez con el ingles y el lenguaje al que quieras traducir. Cuando de transmitir ideas complejas se trata, ¡es importante tener grandes conocimientos de ambas!" + diplomat_join_pref: "Hemos comenzado un montón de traducciones en " + diplomat_doc_url: "este post del foro" + diplomat_join_suf: "así que échale un vistazo y añade cosas para tu idioma. También, marca la casilla de abajo para mantenerte al día en nuevos desarrollos de internacionalización!" + more_about_diplomat: "Aprende más sobre cómo convertirte en un gran Diplomático" + diplomat_subscribe_desc: "Recibe correos sobre nuevos niveles y desarrollos para traducir." + ambassador_introduction: "Esta es una comunidad en construcción y tú eres parte de las conexiones. Tenemos chat Olark, correos electrónicos y las redes sociales con una gran cantidad de personas con quienes hablar, ayudar a familiarizarse con el juego y aprender. Si quieres ayudar a la gente a que se involucre, se divierta, y tenga buenas sensaciones sobre CodeCombat y hacia dónde vamos, entonces esta clase es para ti." + ambassador_attribute_1: "Habilidades de comunicación. Ser capaz de identificar los problemas que los jugadores están teniendo y ayudarles a resolverlos. Además, mantener al resto de nosotros informados sobre lo que los jugadores están diciendo, lo que les gusta, lo que no ¡y de lo que quieren más!" + ambassador_join_desc: "cuéntanos más sobre ti, que has hecho y qué estarías interesado en hacer. ¡Y continuaremos a partir de ahí!" + ambassador_join_note_strong: "Nota" + ambassador_join_note_desc: "Una de nuestras principales prioridades es construir un modo multijugador donde los jugadores con mayores dificultades a la hora de resolver un nivel, puedan invocar a los magos más avanzados para que les ayuden. Será una buena manera de que los Embajadores puedan hacer su trabajo. ¡Te mantendremos informado!" + more_about_ambassador: "Aprende más sobre cómo convertirte en un amable Embajador" + ambassador_subscribe_desc: "Recibe correos sobre actualizaciones de soporte y desarrollo del multijugador." + counselor_introduction_1: "¿Tienes mucha experiencia vital? ¿Una perspectiva diferente de las cosas que nos puede ayudar a decidir cómo moldear CodeCombat? De todos estos papeles, este es el que te llevará menos tiempo pero en el que marcarás más la diferencia. Estamos buscando eruditos particularmente en áreas como: enseñanza, desarrollo de juegos, gestión de proyectos de código abierto, contratación de técnicos, iniciativa empresarial o diseño." + counselor_introduction_2: "O realmente cualquier cosa que sea relevante para el desarrollo de CodeCombat. Si tienes el conocimiento y quieres compartirlo para ayudar a que este proyecto crezca, entonces esta Clase es ideal para ti." + counselor_attribute_1: "Experiencia en cualquiera de las áreas mencionadas, o en lo que creas que puede ser de utilidad." + counselor_attribute_2: "¡Un poco de tiempo libre!" + counselor_join_desc: "cuéntanos un poco sobre ti, qué has hecho y qué estarías interesado en hacer. Te pondremos en nuestra lista de contactos y te daremos un toque cuando necesitemos consejo (no muy a menudo)." + more_about_counselor: "Aprende más sobre cómo convertirte en un valioso Consejero" + changes_auto_save: "Los cambios son guardados automáticamente cuando marcas las casillas de verificación." + diligent_scribes: "Nuestros diligentes Escribas:" + powerful_archmages: "Nuestros poderosos Archimagos:" + creative_artisans: "Nuestros creativos Artesanos:" + brave_adventurers: "Nuestros bravos Aventureros:" + translating_diplomats: "Nuestros políglotas Diplomáticos:" + helpful_ambassadors: "Nuestros amables Embajadores:" -# classes: -# archmage_title: "Archmage" -# archmage_title_description: "(Coder)" -# artisan_title: "Artisan" -# artisan_title_description: "(Level Builder)" -# adventurer_title: "Adventurer" -# adventurer_title_description: "(Level Playtester)" -# scribe_title: "Scribe" -# scribe_title_description: "(Article Editor)" -# diplomat_title: "Diplomat" -# diplomat_title_description: "(Translator)" -# ambassador_title: "Ambassador" -# ambassador_title_description: "(Support)" -# counselor_title: "Counselor" -# counselor_title_description: "(Expert/Teacher)" + classes: + archmage_title: "Archimago" + archmage_title_description: "(Programador)" + artisan_title: "Artesano" + artisan_title_description: "(Diseñador de Niveles)" + adventurer_title: "Aventurero" + adventurer_title_description: "(Tester de Niveles)" + scribe_title: "Escriba" + scribe_title_description: "(Editor de Artículos)" + diplomat_title: "Diplomático" + diplomat_title_description: "(Traductor)" + ambassador_title: "Embajador" + ambassador_title_description: "(Soporte)" + counselor_title: "Consejero" + counselor_title_description: "(Experto/Profesor)" diff --git a/app/locale/hu.coffee b/app/locale/hu.coffee index a40025c55..54fc0a6c7 100644 --- a/app/locale/hu.coffee +++ b/app/locale/hu.coffee @@ -205,46 +205,46 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t editor: main_title: "CodeCombat szerkesztők" - main_description: "KLészíts saját pályákat, hadjáratokat, egységeket és oktatési célú tartalmakat. Mi megadunk hozzá minden eszközt amire csak szükséged lehet!" -# article_title: "Article Editor" -# article_description: "Write articles that give players overviews of programming concepts which can be used across a variety of levels and campaigns." -# thang_title: "Thang Editor" -# thang_description: "Build units, defining their default logic, graphics and audio. Currently only supports importing Flash exported vector graphics." -# level_title: "Level Editor" -# level_description: "Includes the tools for scripting, uploading audio, and constructing custom logic to create all sorts of levels. Everything we use ourselves!" -# security_notice: "Many major features in these editors are not currently enabled by default. As we improve the security of these systems, they will be made generally available. If you'd like to use these features sooner, " -# contact_us: "contact us!" -# hipchat_prefix: "You can also find us in our" -# hipchat_url: "HipChat room." -# level_some_options: "Some Options?" -# level_tab_thangs: "Thangs" -# level_tab_scripts: "Scripts" -# level_tab_settings: "Settings" -# level_tab_components: "Components" -# level_tab_systems: "Systems" -# level_tab_thangs_title: "Current Thangs" -# level_tab_thangs_conditions: "Starting Conditions" -# level_tab_thangs_add: "Add Thangs" -# level_settings_title: "Settings" -# level_component_tab_title: "Current Components" -# level_component_btn_new: "Create New Component" -# level_systems_tab_title: "Current Systems" -# level_systems_btn_new: "Create New System" -# level_systems_btn_add: "Add System" -# level_components_title: "Back to All Thangs" -# level_components_type: "Type" -# level_component_edit_title: "Edit Component" -# level_system_edit_title: "Edit System" -# create_system_title: "Create New System" -# new_component_title: "Create New Component" -# new_component_field_system: "System" + main_description: "Készíts saját pályákat, hadjáratokat, egységeket és oktatési célú tartalmakat. Mi megadunk hozzá minden eszközt amire csak szükséged lehet!" + article_title: "Cikk szerkesztő" + article_description: "Írhatsz cikkeket, hogy átfogó képet adhass olyan programozási szemléletekről, melyeket a különböző pályákon és küldetések során felhasználhatnak." + thang_title: "Eszköz szerkesztő" + thang_description: "Építs egységeket, határozd meg az működésüket, kinézetüket és hangjukat. Jelenleg csak a Flash-ből exportált vektorgrafika támogatott." + level_title: "Pálya szerkesztő" + level_description: "Mindent magába foglal, ami kódolás, hangok feltöltése, és a pályák teljesen egyedi felépítése. Minden, amit mi használunk!" + security_notice: "Számos főbb funkció ezekben a szerkesztőkben még nincs engedélyezve alapesetben. Amint a rendszer biztonságát növelni tudjuk, elérhetővé teszzük ezeket. Ha a későbbiekben használni szeretnéf ezeket a funkciókat, " + contact_us: "lépj kapcsolatba velünk!" + hipchat_prefix: "Megtalálhatsz bennünket a " + hipchat_url: "HipChat szobában." + level_some_options: "Néhány beállítás?" + level_tab_thangs: "Eszközök" + level_tab_scripts: "Kódok" + level_tab_settings: "Beállítások" + level_tab_components: "Komponensek" + level_tab_systems: "Rendszerek" + level_tab_thangs_title: "Jelenlegi eszközök" + level_tab_thangs_conditions: "Kezdő feltételek" + level_tab_thangs_add: "Eszköz hozzáadása" + level_settings_title: "Beállítások" + level_component_tab_title: "Jelenlegi komponensek" + level_component_btn_new: "Új komponens készítése" + level_systems_tab_title: "Jelenlegi rendszerek" + level_systems_btn_new: "Új rendszer készítése" + level_systems_btn_add: "Rendszer hozzáadása" + level_components_title: "Vissza az összes eszközhöz" + level_components_type: "Típus" + level_component_edit_title: "Komponens szerkesztése" + level_system_edit_title: "Rendszer szerkesztése" + create_system_title: "Új rendszer készítése" + new_component_title: "Új komponens készítése" + new_component_field_system: "Rendszer" -# article: -# edit_btn_preview: "Preview" -# edit_article_title: "Edit Article" + article: + edit_btn_preview: "Előnézet" + edit_article_title: "Cikk szerkesztése" general: -# and: "and" + and: "és" or: "vagy " name: "Név" # body: "Body" diff --git a/app/models/Article.coffee b/app/models/Article.coffee index 14d2a6edd..29e5dd8c5 100644 --- a/app/models/Article.coffee +++ b/app/models/Article.coffee @@ -3,3 +3,4 @@ CocoModel = require('./CocoModel') module.exports = class Article extends CocoModel @className: "Article" urlRoot: "/db/article" + saveBackups: true diff --git a/app/models/CocoModel.coffee b/app/models/CocoModel.coffee index 9a2a0dd63..8801fc038 100644 --- a/app/models/CocoModel.coffee +++ b/app/models/CocoModel.coffee @@ -1,3 +1,5 @@ +storage = require 'lib/storage' + class CocoSchema extends Backbone.Model constructor: (path, args...) -> super(args...) @@ -9,6 +11,7 @@ class CocoModel extends Backbone.Model idAttribute: "_id" loaded: false loading: false + saveBackups: false @schema: null initialize: -> @@ -20,15 +23,32 @@ class CocoModel extends Backbone.Model @addSchemaDefaults() else @loadSchema() - @once 'sync', @onLoaded + @once 'sync', @onLoaded, @ + @saveBackup = _.debounce(@saveBackup, 500) type: -> @constructor.className - onLoaded: => + onLoaded: -> @loaded = true @loading = false @markToRevert() + if @saveBackups + existing = storage.load @id + if existing + @set(existing, {silent:true}) + CocoModel.backedUp[@id] = @ + + set: -> + res = super(arguments...) + @saveBackup() if @saveBackups and @loaded + res + + saveBackup: -> + storage.save(@id, @attributes) + CocoModel.backedUp[@id] = @ + + @backedUp = {} loadSchema: -> unless @constructor.schema @@ -38,7 +58,6 @@ class CocoModel extends Backbone.Model @constructor.schema.on 'sync', => @constructor.schema.loaded = true @addSchemaDefaults() - @markToRevert() @trigger 'schema-loaded' @hasSchema: -> return @schema?.loaded @@ -57,6 +76,7 @@ class CocoModel extends Backbone.Model @trigger "save:success", @ success(@, resp) if success @markToRevert() + @clearBackup() @trigger "save", @ return super attrs, options @@ -69,6 +89,10 @@ class CocoModel extends Backbone.Model revert: -> @set(@_revertAttributes, {silent: true}) if @_revertAttributes + @clearBackup() + + clearBackup: -> + storage.remove @id hasLocalChanges: -> not _.isEqual @attributes, @_revertAttributes diff --git a/app/models/SuperModel.coffee b/app/models/SuperModel.coffee index 7164594c6..50cb5906c 100644 --- a/app/models/SuperModel.coffee +++ b/app/models/SuperModel.coffee @@ -6,6 +6,7 @@ class SuperModel populateModel: (model) -> @mustPopulate = model + model.saveBackups = @shouldSaveBackups(model) model.fetch() unless model.loaded or model.loading model.on('sync', @modelLoaded) unless model.loaded model.once('error', @modelErrored) unless model.loaded @@ -13,7 +14,9 @@ class SuperModel @models[url] = model unless @models[url]? @modelLoaded(model) if model.loaded - shouldPopulate: (url) -> return true # replace or overwrite + # replace or overwrite + shouldPopulate: (url) -> return true + shouldSaveBackups: (model) -> return false modelErrored: (model) => @trigger 'error' @@ -25,6 +28,7 @@ class SuperModel refs = [] unless @mustPopulate is model or @shouldPopulate(model) # console.log 'Loaded', model.get('name') for ref, i in refs + ref.saveBackups = @shouldSaveBackups(ref) refURL = ref.url() continue if @models[refURL] @models[refURL] = ref diff --git a/app/models/ThangType.coffee b/app/models/ThangType.coffee index 94e54ed4a..d538ba4dd 100644 --- a/app/models/ThangType.coffee +++ b/app/models/ThangType.coffee @@ -91,6 +91,7 @@ module.exports = class ThangType extends CocoModel for animation in @requiredRawAnimations() name = animation.animation mc = @vectorParser.buildMovieClip name + continue unless mc @builder.addMovieClip mc, null, animation.scale * @options.resolutionFactor framesMap[animation.scale + "_" + name] = @builder._animations[name].frames @@ -98,6 +99,7 @@ module.exports = class ThangType extends CocoModel continue if name is 'portrait' scale = action.scale ? @get('scale') ? 1 frames = framesMap[scale + "_" + action.animation] + continue unless frames frames = @mapFrames(action.frames, frames[0]) if action.frames? next = true next = action.goesTo if action.goesTo @@ -108,6 +110,7 @@ module.exports = class ThangType extends CocoModel continue if name is 'portrait' scale = @options.resolutionFactor * (action.scale or @get('scale') or 1) s = @vectorParser.buildContainerFromStore(action.container) + continue unless s frame = @builder.addFrame(s, s.bounds, scale) @builder.addAnimation name, [frame], false diff --git a/app/styles/about.sass b/app/styles/about.sass index 7d6889183..00c708381 100644 --- a/app/styles/about.sass +++ b/app/styles/about.sass @@ -3,9 +3,19 @@ @import "bootstrap/variables" .team-column - margin-left: 50px + padding-left: 0 + + ul.thumbnails + margin-left: 40px + padding: 0 + + li + list-style-type: none + padding-bottom: 20px + img float: left width: 150px height: 150px + diff --git a/app/styles/account/profile.sass b/app/styles/account/profile.sass index de4816a47..2edec8f24 100644 --- a/app/styles/account/profile.sass +++ b/app/styles/account/profile.sass @@ -4,7 +4,7 @@ i margin-right: 5px - img.img-polaroid + img.img-thumbnail margin: 20px 0 li @@ -12,3 +12,4 @@ ul margin: 0 + padding: 0 diff --git a/app/styles/account/settings.sass b/app/styles/account/settings.sass index 2df6b14c4..4eccfb708 100644 --- a/app/styles/account/settings.sass +++ b/app/styles/account/settings.sass @@ -1,20 +1,22 @@ #account-settings-view - .nav-tabs - margin-bottom: 0 + .nav + margin-bottom: 10px .tab-content border: 1px solid #aaa - border-top-width: 0 padding: 20px background: #eee + border-radius: 5px #save-button float: right .thumbnails text-align: center - div + .thumbnail margin-bottom: 30px + margin-right: 20px + float: left input.range position: relative @@ -34,6 +36,9 @@ left: 10px font-size: 12px + .form + max-width: 600px + #wizard-settings-tab-view #color-settings float: left diff --git a/app/styles/account/unsubscribe.sass b/app/styles/account/unsubscribe.sass index ad75f5e30..a8afd30f0 100644 --- a/app/styles/account/unsubscribe.sass +++ b/app/styles/account/unsubscribe.sass @@ -4,5 +4,5 @@ p margin: 20px 0 - .bar - width: 100% \ No newline at end of file + .progress-bar + width: 100% diff --git a/app/styles/base.sass b/app/styles/base.sass index 136e5289e..663326fcc 100644 --- a/app/styles/base.sass +++ b/app/styles/base.sass @@ -4,12 +4,6 @@ h1 h2 h3 h4 letter-spacing: 2px -#widget-bounds - display: none - -.navbar a.brand - padding: 4px 20px 0px 20px - .main-content-area position: relative width: 1024px @@ -18,63 +12,12 @@ h1 h2 h3 h4 padding: 14px 12px 5px 12px @include box-sizing(border-box) -.navbuttontext, .fancy-select .trigger - font-family: 'Bangers', cursive - font-size: 20px - font-weight: normal - letter-spacing: 1px - -.navbuttontext-user-name - max-width: 125px - overflow: hidden - text-overflow: ellipsis - white-space: nowrap - display: inline-block - padding: 0 - margin: 0 - height: 18px - -.navbar .nav.navbar-link-text, .navbar .nav.navbar-link-text > li > a - font-family: 'Bangers', cursive - font-weight: normal - font-size: 25px - letter-spacing: 2px - -.navbar .btn, .navbar .btn-group, .navbar .fancy-select - margin-top: 13px - -.nav-tabs > .active > a, .nav-tabs > .active > a:hover, .nav-tabs > .active > a:focus - background-color: #eee - -.nav-tabs > li - cursor: pointer - #outer-content-wrapper background: #8cc63f url(/images/pages/base/repeat-tile.png) top center #inner-content-wrapper background: url(/images/pages/base/background_texture.png) top center no-repeat -.navbar-inner - font-size: 25px - a:not(.btn) - line-height: 25px - - .btn, .fancy-select - float: right - margin-left: 10px - - select - opacity: 0 - - .fancy-select - .trigger - padding: 5px 25px 3px 10px - width: auto - &:after - top: 13px - max-width: 140px - #front-summary-points-left width: 250px margin: 0px 20px 10px 15px @@ -110,6 +53,8 @@ h1 h2 h3 h4 color: #ffffff cursor: pointer margin: 0px 10px + &:hover + color: $white a[data-toggle="modal"] cursor: pointer @@ -117,13 +62,13 @@ a[data-toggle="modal"] .share-buttons, .partner-badges margin-top: 10px text-align: center - @include opacity(75) + @include opacity(0.75) &.fade-in @include opacity(0) &:hover, &:active - @include opacity(100) + @include opacity(1) @include transition(opacity .10s linear) .github-star-button @@ -135,13 +80,16 @@ a[data-toggle="modal"] .selectable cursor: pointer -.modal +.modal-dialog padding: 5px background: transparent url(/images/pages/base/modal_background.png) background-size: 100% 100% border: 0 @include box-shadow(0 0 0 #000) + .modal-content + @include box-shadow(none) + .modal-header margin: 0 14px padding: 8px 0 @@ -149,9 +97,9 @@ a[data-toggle="modal"] .close font-size: 28px - @include opacity(60) + @include opacity(0.60) &:hover - @include opacity(100) + @include opacity(1) .modal-footer background-color: transparent @@ -197,7 +145,7 @@ a[data-toggle="modal"] .progress width: 50% margin: 0 25% - .bar + .progress-bar width: 100% .modal @@ -207,44 +155,15 @@ a[data-toggle="modal"] .progress width: 50% margin: 10px auto - .bar + .progress-bar width: 100% table.table background-color: white -.ui-autocomplete - z-index: $zindexAutocomplete +//.ui-autocomplete +// z-index: $zindexAutocomplete -div.fancy-select - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25) - div.trigger - background-color: #9d8f5a - background-image: linear-gradient(to bottom, #a4955e, #948754) - background-repeat: repeat-x - border: 1px solid #cccccc - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25) - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05) - color: white - &:after - border-top-color: white - &.open - background-color: #8B7F51 - color: #ebebeb - &:after - border-top-color: #ebebeb - ul.options - max-height: 415px - background-color: #9d8f5a - right: 0 - left: auto - overflow-x: hidden - &.open - top: 36px - li - color: #ebebeb - padding: 8px 20px - .ui-slider border: 1px solid black .ui-slider-handle diff --git a/app/styles/bootstrap-responsive.scss b/app/styles/bootstrap-responsive.scss deleted file mode 100644 index 6a1b58000..000000000 --- a/app/styles/bootstrap-responsive.scss +++ /dev/null @@ -1,48 +0,0 @@ -/*! - * Bootstrap Responsive v2.3.1 - * - * Copyright 2012 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world @twitter by @mdo and @fat. - */ - - -// Responsive -// For phone and tablet devices -// ------------------------------------------------------------- - - -// REPEAT VARIABLES & MIXINS -// ------------------------- -// Required since we compile the responsive stuff separately - -@import "bootstrap/variables"; // Modify this for custom colors, font-sizes, etc -@import "bootstrap/mixins"; - - -// RESPONSIVE CLASSES -// ------------------ - -@import "bootstrap/responsive-utilities"; - - -// MEDIA QUERIES -// ------------------ - -// Large desktops -@import "bootstrap/responsive-1200px-min"; - -// Tablets to regular desktops -@import "bootstrap/responsive-768px-979px"; - -// Phones to portrait tablets and narrow desktops -@import "bootstrap/responsive-767px-max"; - - -// RESPONSIVE NAVBAR -// ------------------ - -// From 979px and below, show a button to toggle navbar contents -@import "bootstrap/responsive-navbar"; \ No newline at end of file diff --git a/app/styles/bootstrap.scss b/app/styles/bootstrap.scss index 01e64b022..457a7ab36 100644 --- a/app/styles/bootstrap.scss +++ b/app/styles/bootstrap.scss @@ -1,66 +1 @@ -/*! - * Bootstrap v2.3.1 - * - * Copyright 2012 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world @twitter by @mdo and @fat. - */ - -// Core variables and mixins -@import "bootstrap/variables"; // Modify this for custom colors, font-sizes, etc -@import "bootstrap/mixins"; - -// CSS Reset -@import "bootstrap/reset"; - -// Grid system and page structure -@import "bootstrap/scaffolding"; -@import "bootstrap/grid"; -@import "bootstrap/layouts"; - -// Base CSS -@import "bootstrap/type"; -@import "bootstrap/code"; -@import "bootstrap/forms"; -@import "bootstrap/tables"; - -// Components: common -@import "bootstrap/sprites"; -@import "bootstrap/dropdowns"; -@import "bootstrap/wells"; -@import "bootstrap/component-animations"; -@import "bootstrap/close"; - -// Components: Buttons & Alerts -@import "bootstrap/buttons"; -@import "bootstrap/button-groups"; -@import "bootstrap/alerts"; // Note: alerts share common CSS with buttons and thus have styles in _buttons.scss - -// Components: Nav -@import "bootstrap/navs"; -@import "bootstrap/navbar"; -@import "bootstrap/breadcrumbs"; -@import "bootstrap/pagination"; -@import "bootstrap/pager"; - -// Components: Popovers -@import "bootstrap/modals"; -@import "bootstrap/tooltip"; -@import "bootstrap/popovers"; - -// Components: Misc -@import "bootstrap/thumbnails"; -@import "bootstrap/media"; -@import "bootstrap/labels-badges"; -@import "bootstrap/progress-bars"; -@import "bootstrap/accordion"; -@import "bootstrap/carousel"; -@import "bootstrap/hero-unit"; - -// Addition: Bootswatch structural changes -@import "bootstrap/bootswatch"; - -// Utility classes -@import "bootstrap/utilities"; // Has to be last to override when necessary \ No newline at end of file +@import "bootstrap/bootstrap"; \ No newline at end of file diff --git a/app/styles/bootstrap/_alerts.scss b/app/styles/bootstrap/_alerts.scss index 65335110b..4685ac3a9 100644 --- a/app/styles/bootstrap/_alerts.scss +++ b/app/styles/bootstrap/_alerts.scss @@ -7,73 +7,61 @@ // ------------------------- .alert { - padding: 8px 35px 8px 14px; - margin-bottom: $baseLineHeight; - text-shadow: 0 1px 0 rgba(255,255,255,.5); - background-color: $warningBackground; - border: 1px solid $warningBorder; - @include border-radius($baseBorderRadius); -} -.alert, -.alert h4 { - // Specified for the h4 to prevent conflicts of changing $headingsColor - color: $warningText; -} -.alert h4 { - margin: 0; + padding: $alert-padding; + margin-bottom: $line-height-computed; + border: 1px solid transparent; + border-radius: $alert-border-radius; + + // Headings for larger alerts + h4 { + margin-top: 0; + // Specified for the h4 to prevent conflicts of changing $headings-color + color: inherit; + } + // Provide class for links that match alerts + .alert-link { + font-weight: $alert-link-font-weight; + } + + // Improve alignment and spacing of inner content + > p, + > ul { + margin-bottom: 0; + } + > p + p { + margin-top: 5px; + } } -// Adjust close link position -.alert .close { - position: relative; - top: -2px; - right: -21px; - line-height: $baseLineHeight; -} +// Dismissable alerts +// +// Expand the right padding and account for the close button's positioning. +.alert-dismissable { + padding-right: ($alert-padding + 20); + + // Adjust close link position + .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; + } +} // Alternate styles -// ------------------------- +// +// Generate contextual modifier classes for colorizing the alert. .alert-success { - background-color: $successBackground; - border-color: $successBorder; - color: $successText; -} -.alert-success h4 { - color: $successText; -} -.alert-danger, -.alert-error { - background-color: $errorBackground; - border-color: $errorBorder; - color: $errorText; -} -.alert-danger h4, -.alert-error h4 { - color: $errorText; + @include alert-variant($alert-success-bg, $alert-success-border, $alert-success-text); } .alert-info { - background-color: $infoBackground; - border-color: $infoBorder; - color: $infoText; + @include alert-variant($alert-info-bg, $alert-info-border, $alert-info-text); } -.alert-info h4 { - color: $infoText; +.alert-warning { + @include alert-variant($alert-warning-bg, $alert-warning-border, $alert-warning-text); } - - -// Block alerts -// ------------------------- - -.alert-block { - padding-top: 14px; - padding-bottom: 14px; -} -.alert-block > p, -.alert-block > ul { - margin-bottom: 0; -} -.alert-block p + p { - margin-top: 5px; +.alert-danger { + @include alert-variant($alert-danger-bg, $alert-danger-border, $alert-danger-text); } diff --git a/app/styles/bootstrap/_badges.scss b/app/styles/bootstrap/_badges.scss new file mode 100644 index 000000000..1190d4e32 --- /dev/null +++ b/app/styles/bootstrap/_badges.scss @@ -0,0 +1,51 @@ +// +// Badges +// -------------------------------------------------- + + +// Base classes +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: $font-size-small; + font-weight: $badge-font-weight; + color: $badge-color; + line-height: $badge-line-height; + vertical-align: baseline; + white-space: nowrap; + text-align: center; + background-color: $badge-bg; + border-radius: $badge-border-radius; + + // Empty badges collapse automatically (not available in IE8) + &:empty { + display: none; + } + + // Quick fix for badges in buttons + .btn & { + position: relative; + top: -1px; + } +} + +// Hover state, but only for links +a.badge { + &:hover, + &:focus { + color: $badge-link-hover-color; + text-decoration: none; + cursor: pointer; + } +} + +// Account for counters in navs +a.list-group-item.active > .badge, +.nav-pills > .active > a > .badge { + color: $badge-active-color; + background-color: $badge-active-bg; +} +.nav-pills > li > a > .badge { + margin-left: 3px; +} diff --git a/app/styles/bootstrap/_bootswatch.scss b/app/styles/bootstrap/_bootswatch.scss index 65dd070ed..3f82b5882 100644 --- a/app/styles/bootstrap/_bootswatch.scss +++ b/app/styles/bootstrap/_bootswatch.scss @@ -14,11 +14,11 @@ // NAVBAR // ----------------------------------------------------- -.navbar { +.navbar { .brand { padding: 14px 20px 16px; - font-family: $headingsFontFamily; + font-family: $headings-font-family; text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2); } @@ -28,12 +28,12 @@ .nav > li > a { padding: 16px 10px 14px; - font-family: $headingsFontFamily; + font-family: $headings-font-family; text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2); } .search-query { - border: 1px solid darken($linkColor, 10%); + border: 1px solid darken($link-color, 10%); line-height: normal; } @@ -49,23 +49,22 @@ .navbar-inverse { .navbar-search .search-query { - color: $textColor; + color: $text-color; } } -@media (max-width: $navbarCollapseWidth) { +@media (max-width: $grid-float-breakpoint) { .navbar .nav-collapse { - .nav li > a { + .navbar-nav li > a { - font-family: $headingsFontFamily; + font-family: $headings-font-family; font-weight: normal; color: $white; text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2); &:hover { - background-color: #2B7CAC; } } @@ -93,7 +92,7 @@ .navbar-inverse .nav-collapse { .nav li > a { - color: $navbarInverseLinkColor; + color: $navbar-inverse-color; &:hover { background-color: rgba(0, 0, 0, 0.1); @@ -110,13 +109,13 @@ div.subnav { - font-family: $headingsFontFamily; + font-family: $headings-font-family; text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.2); } div.subnav-fixed { - top: $navbarHeight + 1; + top: $navbar-height + 1; } @@ -136,28 +135,30 @@ div.subnav-fixed { } } +//The following were oring buttonBackground + .btn-primary { - @include buttonBackground(lighten($btnPrimaryBackground, 5%), $btnPrimaryBackground); + @include button-background(lighten($btn-primary-bg, 5%), $btn-primary-bg); } .btn-info { - @include buttonBackground(lighten($btnInfoBackground, 5%), $btnInfoBackground); + @include button-background(lighten($btn-info-bg, 5%), $btn-info-bg); } .btn-success { - @include buttonBackground(lighten($btnSuccessBackground, 5%), $btnSuccessBackground); + @include button-background(lighten($btn-success-bg, 5%), $btn-success-bg); } .btn-warning { - @include buttonBackground(lighten($btnWarningBackground, 5%), $btnWarningBackground); + @include button-background(lighten($btn-warning-bg, 5%), $btn-warning-bg); } .btn-danger { - @include buttonBackground(lighten($btnDangerBackground, 5%), $btnDangerBackground); + @include button-background(lighten($btn-danger-bg, 5%), $btn-danger-bg); } .btn-inverse { - @include buttonBackground(lighten($btnInverseBackground, 5%), $btnInverseBackground); + @include button-background(lighten($btn-default-color, 5%), $btn-default-color);//this should be btn-inverse but I can't find it at the moment } // TABLES diff --git a/app/styles/bootstrap/_breadcrumbs.scss b/app/styles/bootstrap/_breadcrumbs.scss index cc3f327a5..c35ef9460 100644 --- a/app/styles/bootstrap/_breadcrumbs.scss +++ b/app/styles/bootstrap/_breadcrumbs.scss @@ -5,20 +5,19 @@ .breadcrumb { padding: 8px 15px; - margin: 0 0 $baseLineHeight; + margin-bottom: $line-height-computed; list-style: none; - background-color: #f5f5f5; - @include border-radius($baseBorderRadius); + background-color: $breadcrumb-bg; + border-radius: $border-radius-base; > li { display: inline-block; - @include ie7-inline-block(); - text-shadow: 0 1px 0 $white; - > .divider { + + li:before { + content: "#{$breadcrumb-separator}\00a0"; // Unicode space added since inline-block means non-collapsing white-space padding: 0 5px; - color: #ccc; + color: $breadcrumb-color; } } - .active { - color: $grayLight; + > .active { + color: $breadcrumb-active-color; } } diff --git a/app/styles/bootstrap/_button-groups.scss b/app/styles/bootstrap/_button-groups.scss index 1b08d50f5..1fc6ae84c 100644 --- a/app/styles/bootstrap/_button-groups.scss +++ b/app/styles/bootstrap/_button-groups.scss @@ -2,90 +2,88 @@ // Button groups // -------------------------------------------------- - // Make the div behave like a button -.btn-group { +.btn-group, +.btn-group-vertical { position: relative; display: inline-block; - @include ie7-inline-block(); - font-size: 0; // remove as part 1 of font-size inline-block hack vertical-align: middle; // match .btn alignment given font-size hack above - white-space: nowrap; // prevent buttons from wrapping when in tight spaces (e.g., the table on the tests page) - @include ie7-restore-left-whitespace(); + > .btn { + position: relative; + float: left; + // Bring the "active" button to the front + &:hover, + &:focus, + &:active, + &.active { + z-index: 2; + } + &:focus { + // Remove focus outline when dropdown JS adds it after closing the menu + outline: none; + } + } } -// Space out series of button groups -.btn-group + .btn-group { - margin-left: 5px; +// Prevent double borders when buttons are next to each other +.btn-group { + .btn + .btn, + .btn + .btn-group, + .btn-group + .btn, + .btn-group + .btn-group { + margin-left: -1px; + } } // Optional: Group multiple button groups together for a toolbar .btn-toolbar { - font-size: 0; // Hack to remove whitespace that results from using inline-block - margin-top: $baseLineHeight / 2; - margin-bottom: $baseLineHeight / 2; - > .btn + .btn, - > .btn-group + .btn, - > .btn + .btn-group { - margin-left: 5px; + @include clearfix(); + + .btn-group { + float: left; + } + // Space out series of button groups + > .btn, + > .btn-group { + + .btn, + + .btn-group { + margin-left: 5px; + } } } -// Float them, remove border radius, then re-add to first and last elements -.btn-group > .btn { - position: relative; - @include border-radius(0); -} -.btn-group > .btn + .btn { - margin-left: -1px; -} -.btn-group > .btn, -.btn-group > .dropdown-menu, -.btn-group > .popover { - font-size: $baseFontSize; // redeclare as part 2 of font-size inline-block hack -} - -// Reset fonts for other sizes -.btn-group > .btn-mini { - font-size: $fontSizeMini; -} -.btn-group > .btn-small { - font-size: $fontSizeSmall; -} -.btn-group > .btn-large { - font-size: $fontSizeLarge; +.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { + border-radius: 0; } // Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match .btn-group > .btn:first-child { margin-left: 0; - @include border-top-left-radius($baseBorderRadius); - @include border-bottom-left-radius($baseBorderRadius); + &:not(:last-child):not(.dropdown-toggle) { + @include border-right-radius(0); + } } // Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it -.btn-group > .btn:last-child, -.btn-group > .dropdown-toggle { - @include border-top-right-radius($baseBorderRadius); - @include border-bottom-right-radius($baseBorderRadius); -} -// Reset corners for large buttons -.btn-group > .btn.large:first-child { - margin-left: 0; - @include border-top-left-radius($borderRadiusLarge); - @include border-bottom-left-radius($borderRadiusLarge); -} -.btn-group > .btn.large:last-child, -.btn-group > .large.dropdown-toggle { - @include border-top-right-radius($borderRadiusLarge); - @include border-bottom-right-radius($borderRadiusLarge); +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + @include border-left-radius(0); } -// On hover/focus/active, bring the proper btn to front -.btn-group > .btn:hover, -.btn-group > .btn:focus, -.btn-group > .btn:active, -.btn-group > .btn.active { - z-index: 2; +// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group) +.btn-group > .btn-group { + float: left; +} +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child { + > .btn:last-child, + > .dropdown-toggle { + @include border-right-radius(0); + } +} +.btn-group > .btn-group:last-child > .btn:first-child { + @include border-left-radius(0); } // On active and open, don't show outline @@ -95,6 +93,14 @@ } +// Sizing +// +// Remix the default button sizing classes into new ones for easier manipulation. + +.btn-group-xs > .btn { @extend .btn-xs; } +.btn-group-sm > .btn { @extend .btn-sm; } +.btn-group-lg > .btn { @extend .btn-lg; } + // Split button dropdowns // ---------------------- @@ -103,127 +109,119 @@ .btn-group > .btn + .dropdown-toggle { padding-left: 8px; padding-right: 8px; - @include box-shadow(inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)); - *padding-top: 5px; - *padding-bottom: 5px; } -.btn-group > .btn-mini + .dropdown-toggle { - padding-left: 5px; - padding-right: 5px; - *padding-top: 2px; - *padding-bottom: 2px; -} -.btn-group > .btn-small + .dropdown-toggle { - *padding-top: 5px; - *padding-bottom: 4px; -} -.btn-group > .btn-large + .dropdown-toggle { +.btn-group > .btn-lg + .dropdown-toggle { padding-left: 12px; padding-right: 12px; - *padding-top: 7px; - *padding-bottom: 7px; } -.btn-group.open { +// The clickable button for toggling the menu +// Remove the gradient and set the same inset shadow as the :active state +.btn-group.open .dropdown-toggle { + @include box-shadow(inset 0 3px 5px rgba(0,0,0,.125)); - // The clickable button for toggling the menu - // Remove the gradient and set the same inset shadow as the :active state - .dropdown-toggle { - background-image: none; - @include box-shadow(inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)); - } - - // Keep the hover's background when dropdown is open - .btn.dropdown-toggle { - background-color: $btnBackgroundHighlight; - } - .btn-primary.dropdown-toggle { - background-color: $btnPrimaryBackgroundHighlight; - } - .btn-warning.dropdown-toggle { - background-color: $btnWarningBackgroundHighlight; - } - .btn-danger.dropdown-toggle { - background-color: $btnDangerBackgroundHighlight; - } - .btn-success.dropdown-toggle { - background-color: $btnSuccessBackgroundHighlight; - } - .btn-info.dropdown-toggle { - background-color: $btnInfoBackgroundHighlight; - } - .btn-inverse.dropdown-toggle { - background-color: $btnInverseBackgroundHighlight; + // Show no shadow for `.btn-link` since it has no other button styles. + &.btn-link { + @include box-shadow(none); } } // Reposition the caret .btn .caret { - margin-top: 8px; margin-left: 0; } // Carets in other button sizes -.btn-large .caret { - margin-top: 6px; -} -.btn-large .caret { - border-left-width: 5px; - border-right-width: 5px; - border-top-width: 5px; -} -.btn-mini .caret, -.btn-small .caret { - margin-top: 8px; +.btn-lg .caret { + border-width: $caret-width-large $caret-width-large 0; + border-bottom-width: 0; } // Upside down carets for .dropup -.dropup .btn-large .caret { - border-bottom-width: 5px; +.dropup .btn-lg .caret { + border-width: 0 $caret-width-large $caret-width-large; } - -// Account for other colors -.btn-primary, -.btn-warning, -.btn-danger, -.btn-info, -.btn-success, -.btn-inverse { - .caret { - border-top-color: $white; - border-bottom-color: $white; - } -} - - - // Vertical button groups // ---------------------- .btn-group-vertical { - display: inline-block; // makes buttons only take up the width they need - @include ie7-inline-block(); + > .btn, + > .btn-group, + > .btn-group > .btn { + display: block; + float: none; + width: 100%; + max-width: 100%; + } + + // Clear floats so dropdown menus can be properly placed + > .btn-group { + @include clearfix(); + > .btn { + float: none; + } + } + + > .btn + .btn, + > .btn + .btn-group, + > .btn-group + .btn, + > .btn-group + .btn-group { + margin-top: -1px; + margin-left: 0; + } } + .btn-group-vertical > .btn { - display: block; - float: none; - max-width: 100%; - @include border-radius(0); + &:not(:first-child):not(:last-child) { + border-radius: 0; + } + &:first-child:not(:last-child) { + border-top-right-radius: $border-radius-base; + @include border-bottom-radius(0); + } + &:last-child:not(:first-child) { + border-bottom-left-radius: $border-radius-base; + @include border-top-radius(0); + } } -.btn-group-vertical > .btn + .btn { - margin-left: 0; - margin-top: -1px; +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; } -.btn-group-vertical > .btn:first-child { - @include border-radius($baseBorderRadius $baseBorderRadius 0 0); +.btn-group-vertical > .btn-group:first-child { + > .btn:last-child, + > .dropdown-toggle { + @include border-bottom-radius(0); + } } -.btn-group-vertical > .btn:last-child { - @include border-radius(0 0 $baseBorderRadius $baseBorderRadius); +.btn-group-vertical > .btn-group:last-child > .btn:first-child { + @include border-top-radius(0); } -.btn-group-vertical > .btn-large:first-child { - @include border-radius($borderRadiusLarge $borderRadiusLarge 0 0); + + + +// Justified button groups +// ---------------------- + +.btn-group-justified { + display: table; + width: 100%; + table-layout: fixed; + border-collapse: separate; + > .btn, + > .btn-group { + float: none; + display: table-cell; + width: 1%; + } + > .btn-group .btn { + width: 100%; + } } -.btn-group-vertical > .btn-large:last-child { - @include border-radius(0 0 $borderRadiusLarge $borderRadiusLarge); + + +// Checkbox and radio options +[data-toggle="buttons"] > .btn > input[type="radio"], +[data-toggle="buttons"] > .btn > input[type="checkbox"] { + display: none; } diff --git a/app/styles/bootstrap/_buttons.scss b/app/styles/bootstrap/_buttons.scss index a92268b5f..0e862f587 100644 --- a/app/styles/bootstrap/_buttons.scss +++ b/app/styles/bootstrap/_buttons.scss @@ -6,109 +6,138 @@ // Base styles // -------------------------------------------------- -// Core .btn { display: inline-block; - @include ie7-inline-block(); - padding: 4px 12px; margin-bottom: 0; // For input.btn - font-size: $baseFontSize; - line-height: $baseLineHeight; + font-weight: $btn-font-weight; text-align: center; vertical-align: middle; cursor: pointer; - @include buttonBackground($btnBackground, $btnBackgroundHighlight, $grayDark, 0 1px 1px rgba(255,255,255,.75)); - border: 1px solid $btnBorder; - *border: 0; // Remove the border to prevent IE7's black border on input:focus - border-bottom-color: darken($btnBorder, 10%); - @include border-radius($baseBorderRadius); - @include ie7-restore-left-whitespace(); // Give IE7 some love - @include box-shadow(inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)); + background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214 + border: 1px solid transparent; + white-space: nowrap; + @include button-size($padding-base-vertical, $padding-base-horizontal, $font-size-base, $line-height-base, $border-radius-base); + @include user-select(none); - // Hover/focus state - &:hover, - &:focus { - color: $grayDark; - text-decoration: none; - background-position: 0 -15px; - - // transition is only when going to hover/focus, otherwise the background - // behind the gradient (there for IE<=9 fallback) gets mismatched - @include transition(background-position .1s linear); - } - - // Focus state for keyboard and accessibility &:focus { @include tab-focus(); } - // Active state - &.active, - &:active { - background-image: none; - outline: 0; - @include box-shadow(inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)); + &:hover, + &:focus { + color: $btn-default-color; + text-decoration: none; } - // Disabled state - &.disabled, - &[disabled] { - cursor: default; + &:active, + &.active { + outline: 0; background-image: none; - @include opacity(65); + @include box-shadow(inset 0 3px 5px rgba(0,0,0,.125)); + } + + &.disabled, + &[disabled], + fieldset[disabled] & { + cursor: not-allowed; + pointer-events: none; // Future-proof disabling of clicks + @include opacity(.65); @include box-shadow(none); } - } +// Alternate buttons +// -------------------------------------------------- + +.btn-default { + @include button-variant($btn-default-color, $btn-default-bg, $btn-default-border); +} +.btn-primary { + @include button-variant($btn-primary-color, $btn-primary-bg, $btn-primary-border); +} +// Warning appears as orange +.btn-warning { + @include button-variant($btn-warning-color, $btn-warning-bg, $btn-warning-border); +} +// Danger and error appear as red +.btn-danger { + @include button-variant($btn-danger-color, $btn-danger-bg, $btn-danger-border); +} +// Success appears as green +.btn-success { + @include button-variant($btn-success-color, $btn-success-bg, $btn-success-border); +} +// Info appears as blue-green +.btn-info { + @include button-variant($btn-info-color, $btn-info-bg, $btn-info-border); +} + + +// Link buttons +// ------------------------- + +// Make a button look and behave like a link +.btn-link { + color: $link-color; + font-weight: normal; + cursor: pointer; + border-radius: 0; + + &, + &:active, + &[disabled], + fieldset[disabled] & { + background-color: transparent; + @include box-shadow(none); + } + &, + &:hover, + &:focus, + &:active { + border-color: transparent; + } + &:hover, + &:focus { + color: $link-hover-color; + text-decoration: underline; + background-color: transparent; + } + &[disabled], + fieldset[disabled] & { + &:hover, + &:focus { + color: $btn-link-disabled-color; + text-decoration: none; + } + } +} + // Button Sizes // -------------------------------------------------- -// Large -.btn-large { - padding: $paddingLarge; - font-size: $fontSizeLarge; - @include border-radius($borderRadiusLarge); +.btn-lg { + // line-height: ensure even-numbered height of button next to large input + @include button-size($padding-large-vertical, $padding-large-horizontal, $font-size-large, $line-height-large, $border-radius-large); } -.btn-large [class^="icon-"], -.btn-large [class*=" icon-"] { - margin-top: 4px; +.btn-sm { + // line-height: ensure proper height of button next to small input + @include button-size($padding-small-vertical, $padding-small-horizontal, $font-size-small, $line-height-small, $border-radius-small); } - -// Small -.btn-small { - padding: $paddingSmall; - font-size: $fontSizeSmall; - @include border-radius($borderRadiusSmall); -} -.btn-small [class^="icon-"], -.btn-small [class*=" icon-"] { - margin-top: 0; -} -.btn-mini [class^="icon-"], -.btn-mini [class*=" icon-"] { - margin-top: -1px; -} - -// Mini -.btn-mini { - padding: $paddingMini; - font-size: $fontSizeMini; - @include border-radius($borderRadiusSmall); +.btn-xs { + @include button-size($padding-xs-vertical, $padding-xs-horizontal, $font-size-small, $line-height-small, $border-radius-small); } // Block button -// ------------------------- +// -------------------------------------------------- .btn-block { display: block; width: 100%; padding-left: 0; padding-right: 0; - @include box-sizing(border-box); } // Vertically space out multiple block buttons @@ -124,105 +153,3 @@ input[type="button"] { width: 100%; } } - - - -// Alternate buttons -// -------------------------------------------------- - -// Provide *some* extra contrast for those who can get it -.btn-primary.active, -.btn-warning.active, -.btn-danger.active, -.btn-success.active, -.btn-info.active, -.btn-inverse.active { - color: rgba(255,255,255,.75); -} - -// Set the backgrounds -// ------------------------- -.btn-primary { - @include buttonBackground($btnPrimaryBackground, $btnPrimaryBackgroundHighlight); -} -// Warning appears are orange -.btn-warning { - @include buttonBackground($btnWarningBackground, $btnWarningBackgroundHighlight); -} -// Danger and error appear as red -.btn-danger { - @include buttonBackground($btnDangerBackground, $btnDangerBackgroundHighlight); -} -// Success appears as green -.btn-success { - @include buttonBackground($btnSuccessBackground, $btnSuccessBackgroundHighlight); -} -// Info appears as a neutral blue -.btn-info { - @include buttonBackground($btnInfoBackground, $btnInfoBackgroundHighlight); -} -// Inverse appears as dark gray -.btn-inverse { - @include buttonBackground($btnInverseBackground, $btnInverseBackgroundHighlight); -} - - -// Cross-browser Jank -// -------------------------------------------------- - -button.btn, -input[type="submit"].btn { - - // Firefox 3.6 only I believe - &::-moz-focus-inner { - padding: 0; - border: 0; - } - - // IE7 has some default padding on button controls - *padding-top: 3px; - *padding-bottom: 3px; - - &.btn-large { - *padding-top: 7px; - *padding-bottom: 7px; - } - &.btn-small { - *padding-top: 3px; - *padding-bottom: 3px; - } - &.btn-mini { - *padding-top: 1px; - *padding-bottom: 1px; - } -} - - -// Link buttons -// -------------------------------------------------- - -// Make a button look and behave like a link -.btn-link, -.btn-link:active, -.btn-link[disabled] { - background-color: transparent; - background-image: none; - @include box-shadow(none); -} -.btn-link { - border-color: transparent; - cursor: pointer; - color: $linkColor; - @include border-radius(0); -} -.btn-link:hover, -.btn-link:focus { - color: $linkColorHover; - text-decoration: underline; - background-color: transparent; -} -.btn-link[disabled]:hover, -.btn-link[disabled]:focus { - color: $grayDark; - text-decoration: none; -} diff --git a/app/styles/bootstrap/_carousel.scss b/app/styles/bootstrap/_carousel.scss index 22eaddb90..1134a8e29 100644 --- a/app/styles/bootstrap/_carousel.scss +++ b/app/styles/bootstrap/_carousel.scss @@ -3,29 +3,25 @@ // -------------------------------------------------- +// Wrapper for the slide container and indicators .carousel { position: relative; - margin-bottom: $baseLineHeight; - line-height: 1; } .carousel-inner { + position: relative; overflow: hidden; width: 100%; - position: relative; -} - -.carousel-inner { > .item { display: none; position: relative; @include transition(.6s ease-in-out left); - // Account for jankitude on images + // Account for jankitude on images > img, > a > img { - display: block; + @include img-responsive(); line-height: 1; } } @@ -70,89 +66,167 @@ .carousel-control { position: absolute; - top: 40%; - left: 15px; - width: 40px; - height: 40px; - margin-top: -20px; - font-size: 60px; - font-weight: 100; - line-height: 30px; - color: $white; + top: 0; + left: 0; + bottom: 0; + width: $carousel-control-width; + @include opacity($carousel-control-opacity); + font-size: $carousel-control-font-size; + color: $carousel-control-color; text-align: center; - background: $grayDarker; - border: 3px solid $white; - @include border-radius(23px); - @include opacity(50); + text-shadow: $carousel-text-shadow; + // We can't have this transition here because WebKit cancels the carousel + // animation if you trip this while in the middle of another animation. - // we can't have this transition here - // because webkit cancels the carousel - // animation if you trip this while - // in the middle of another animation - // ;_; - // .transition(opacity .2s linear); - - // Reposition the right one + // Set gradients for backgrounds + &.left { + @include gradient-horizontal($start-color: rgba(0,0,0,.5), $end-color: rgba(0,0,0,.0001)); + } &.right { left: auto; - right: 15px; + right: 0; + @include gradient-horizontal($start-color: rgba(0,0,0,.0001), $end-color: rgba(0,0,0,.5)); } // Hover/focus state &:hover, &:focus { - color: $white; + outline: none; + color: $carousel-control-color; text-decoration: none; - @include opacity(90); + @include opacity(.9); + } + + // Toggles + .icon-prev, + .icon-next, + .glyphicon-chevron-left, + .glyphicon-chevron-right { + position: absolute; + top: 50%; + z-index: 5; + display: inline-block; + } + .icon-prev, + .glyphicon-chevron-left { + left: 50%; + } + .icon-next, + .glyphicon-chevron-right { + right: 50%; + } + .icon-prev, + .icon-next { + width: 20px; + height: 20px; + margin-top: -10px; + margin-left: -10px; + font-family: serif; + } + + .icon-prev { + &:before { + content: '\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039) + } + } + .icon-next { + &:before { + content: '\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A) + } } } -// Carousel indicator pips -// ----------------------------- +// Optional indicator pips +// +// Add an unordered list with the following class and add a list item for each +// slide your carousel holds. + .carousel-indicators { position: absolute; - top: 15px; - right: 15px; - z-index: 5; - margin: 0; + bottom: 10px; + left: 50%; + z-index: 15; + width: 60%; + margin-left: -30%; + padding-left: 0; list-style: none; + text-align: center; li { - display: block; - float: left; - width: 10px; + display: inline-block; + width: 10px; height: 10px; - margin-left: 5px; + margin: 1px; text-indent: -999px; - background-color: #ccc; - background-color: rgba(255,255,255,.25); - border-radius: 5px; + border: 1px solid $carousel-indicator-border-color; + border-radius: 10px; + cursor: pointer; + + // IE8-9 hack for event handling + // + // Internet Explorer 8-9 does not support clicks on elements without a set + // `background-color`. We cannot use `filter` since that's not viewed as a + // background color by the browser. Thus, a hack is needed. + // + // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we + // set alpha transparency for the best results possible. + background-color: #000 \9; // IE8 + background-color: rgba(0,0,0,0); // IE9 } .active { - background-color: #fff; + margin: 0; + width: 12px; + height: 12px; + background-color: $carousel-indicator-active-bg; } } -// Caption for text below images +// Optional captions // ----------------------------- - +// Hidden by default for smaller viewports .carousel-caption { position: absolute; - left: 0; - right: 0; - bottom: 0; - padding: 15px; - background: $grayDark; - background: rgba(0,0,0,.75); + left: 15%; + right: 15%; + bottom: 20px; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: $carousel-caption-color; + text-align: center; + text-shadow: $carousel-text-shadow; + & .btn { + text-shadow: none; // No shadow for button elements in carousel-caption + } } -.carousel-caption h4, -.carousel-caption p { - color: $white; - line-height: $baseLineHeight; -} -.carousel-caption h4 { - margin: 0 0 5px; -} -.carousel-caption p { - margin-bottom: 0; + + +// Scale up controls for tablets and up +@media screen and (min-width: $screen-sm-min) { + + // Scale up the controls a smidge + .carousel-control { + .glyphicons-chevron-left, + .glyphicons-chevron-right, + .icon-prev, + .icon-next { + width: 30px; + height: 30px; + margin-top: -15px; + margin-left: -15px; + font-size: 30px; + } + } + + // Show and left align the captions + .carousel-caption { + left: 20%; + right: 20%; + padding-bottom: 30px; + } + + // Move up the indicators + .carousel-indicators { + bottom: 20px; + } } diff --git a/app/styles/bootstrap/_close.scss b/app/styles/bootstrap/_close.scss index ee14a6ba9..62ce30fa3 100644 --- a/app/styles/bootstrap/_close.scss +++ b/app/styles/bootstrap/_close.scss @@ -5,19 +5,22 @@ .close { float: right; - font-size: 20px; - font-weight: bold; - line-height: $baseLineHeight; - color: $black; - text-shadow: 0 1px 0 rgba(255,255,255,1); - @include opacity(20); + font-size: ($font-size-base * 1.5); + font-weight: $close-font-weight; + line-height: 1; + color: $close-color; + text-shadow: $close-text-shadow; + @include opacity(.2); + &:hover, &:focus { - color: $black; + color: $close-color; text-decoration: none; cursor: pointer; - @include opacity(40); + @include opacity(.5); } + + // [converter] extracted button& to button.close } // Additional properties for button version diff --git a/app/styles/bootstrap/_code.scss b/app/styles/bootstrap/_code.scss index b9e2f6f22..240dc1d14 100644 --- a/app/styles/bootstrap/_code.scss +++ b/app/styles/bootstrap/_code.scss @@ -1,61 +1,53 @@ // -// Code (inline and blocK) +// Code (inline and block) // -------------------------------------------------- // Inline and block code styles code, -pre { - padding: 0 3px 2px; - @include font-family-monospace; - font-size: $baseFontSize - 2; - color: $grayDark; - @include border-radius(3px); +kbd, +pre, +samp { + font-family: $font-family-monospace; } // Inline code code { padding: 2px 4px; - color: #d14; - background-color: #f7f7f9; - border: 1px solid #e1e1e8; + font-size: 90%; + color: $code-color; + background-color: $code-bg; white-space: nowrap; + border-radius: $border-radius-base; } // Blocks of code pre { display: block; - padding: ($baseLineHeight - 1) / 2; - margin: 0 0 $baseLineHeight / 2; - font-size: $baseFontSize - 1; // 14px to 13px - line-height: $baseLineHeight; + padding: (($line-height-computed - 1) / 2); + margin: 0 0 ($line-height-computed / 2); + font-size: ($font-size-base - 1); // 14px to 13px + line-height: $line-height-base; word-break: break-all; word-wrap: break-word; - white-space: pre; - white-space: pre-wrap; - background-color: #f5f5f5; - border: 1px solid #ccc; // fallback for IE7-8 - border: 1px solid rgba(0,0,0,.15); - @include border-radius($baseBorderRadius); - - // Make prettyprint styles more spaced out for readability - &.prettyprint { - margin-bottom: $baseLineHeight; - } + color: $pre-color; + background-color: $pre-bg; + border: 1px solid $pre-border-color; + border-radius: $border-radius-base; // Account for some code outputs that place code tags in pre tags code { padding: 0; + font-size: inherit; color: inherit; - white-space: pre; white-space: pre-wrap; background-color: transparent; - border: 0; + border-radius: 0; } } // Enable scrollable blocks of code .pre-scrollable { - max-height: 340px; + max-height: $pre-scrollable-max-height; overflow-y: scroll; } diff --git a/app/styles/bootstrap/_component-animations.scss b/app/styles/bootstrap/_component-animations.scss index 5ef86b097..86632fd34 100644 --- a/app/styles/bootstrap/_component-animations.scss +++ b/app/styles/bootstrap/_component-animations.scss @@ -2,6 +2,10 @@ // Component animations // -------------------------------------------------- +// Heads up! +// +// We don't use the `.opacity()` mixin here since it causes a bug with text +// fields in IE7-8. Source: https://github.com/twitter/bootstrap/pull/3552. .fade { opacity: 0; @@ -12,11 +16,14 @@ } .collapse { + display: none; + &.in { + display: block; + } +} +.collapsing { position: relative; height: 0; overflow: hidden; @include transition(height .35s ease); - &.in { - height: auto; - } } diff --git a/app/styles/bootstrap/_dropdowns.scss b/app/styles/bootstrap/_dropdowns.scss index dbe1cb708..74502ce60 100644 --- a/app/styles/bootstrap/_dropdowns.scss +++ b/app/styles/bootstrap/_dropdowns.scss @@ -3,62 +3,47 @@ // -------------------------------------------------- -// Use the .menu class on any
  • element within the topbar or ul.tabs and you'll get some superfancy dropdowns -.dropup, -.dropdown { - position: relative; -} -.dropdown-toggle { - // The caret makes the toggle a bit too tall in IE7 - *margin-bottom: -3px; -} -.dropdown-toggle:active, -.open .dropdown-toggle { - outline: 0; -} - // Dropdown arrow/caret -// -------------------- .caret { display: inline-block; width: 0; height: 0; - vertical-align: top; - border-top: 4px solid $black; - border-right: 4px solid transparent; - border-left: 4px solid transparent; - content: ""; + margin-left: 2px; + vertical-align: middle; + border-top: $caret-width-base solid; + border-right: $caret-width-base solid transparent; + border-left: $caret-width-base solid transparent; } -// Place the caret -.dropdown .caret { - margin-top: 8px; - margin-left: 2px; +// The dropdown wrapper (div) +.dropdown { + position: relative; +} + +// Prevent the focus on the dropdown toggle when closing dropdowns +.dropdown-toggle:focus { + outline: 0; } // The dropdown menu (ul) -// ---------------------- .dropdown-menu { position: absolute; top: 100%; left: 0; - z-index: $zindexDropdown; + z-index: $zindex-dropdown; display: none; // none by default, but block on "open" of the menu float: left; min-width: 160px; padding: 5px 0; margin: 2px 0 0; // override default ul list-style: none; - background-color: $dropdownBackground; - border: 1px solid #ccc; // Fallback for IE7-8 - border: 1px solid $dropdownBorder; - *border-right-width: 2px; - *border-bottom-width: 2px; - @include border-radius(6px); - @include box-shadow(0 5px 10px rgba(0,0,0,.2)); - -webkit-background-clip: padding-box; - -moz-background-clip: padding; - background-clip: padding-box; + font-size: $font-size-base; + background-color: $dropdown-bg; + border: 1px solid $dropdown-fallback-border; // IE8 fallback + border: 1px solid $dropdown-border; + border-radius: $border-radius-base; + @include box-shadow(0 6px 12px rgba(0,0,0,.175)); + background-clip: padding-box; // Aligns the dropdown menu to right &.pull-right { @@ -68,7 +53,7 @@ // Dividers (basically an hr) within the dropdown .divider { - @include nav-divider($dropdownDividerTop, $dropdownDividerBottom); + @include nav-divider($dropdown-divider-bg); } // Links within the dropdown menu @@ -77,81 +62,106 @@ padding: 3px 20px; clear: both; font-weight: normal; - line-height: $baseLineHeight; - color: $dropdownLinkColor; - white-space: nowrap; + line-height: $line-height-base; + color: $dropdown-link-color; + white-space: nowrap; // prevent links from randomly breaking onto new lines } } // Hover/Focus state -// ----------- -.dropdown-menu > li > a:hover, -.dropdown-menu > li > a:focus, -.dropdown-submenu:hover > a, -.dropdown-submenu:focus > a { - text-decoration: none; - color: $dropdownLinkColorHover; - @include gradient-vertical($dropdownLinkBackgroundHover, darken($dropdownLinkBackgroundHover, 5%)); -} - -// Active state -// ------------ -.dropdown-menu > .active > a, -.dropdown-menu > .active > a:hover, -.dropdown-menu > .active > a:focus { - color: $dropdownLinkColorActive; - text-decoration: none; - outline: 0; - @include gradient-vertical($dropdownLinkBackgroundActive, darken($dropdownLinkBackgroundActive, 5%)); -} - -// Disabled state -// -------------- -// Gray out text and ensure the hover/focus state remains gray -.dropdown-menu > .disabled > a, -.dropdown-menu > .disabled > a:hover, -.dropdown-menu > .disabled > a:focus { - color: $grayLight; -} -// Nuke hover/focus effects -.dropdown-menu > .disabled > a:hover, -.dropdown-menu > .disabled > a:focus { - text-decoration: none; - background-color: transparent; - background-image: none; // Remove CSS gradient - @include reset-filter(); - cursor: default; -} - -// Open state for the dropdown -// --------------------------- -.open { - // IE7's z-index only goes to the nearest positioned ancestor, which would - // make the menu appear below buttons that appeared later on the page - *z-index: $zindexDropdown; - - & > .dropdown-menu { - display: block; +.dropdown-menu > li > a { + &:hover, + &:focus { + text-decoration: none; + color: $dropdown-link-hover-color; + background-color: $dropdown-link-hover-bg; } } +// Active state +.dropdown-menu > .active > a { + &, + &:hover, + &:focus { + color: $dropdown-link-active-color; + text-decoration: none; + outline: 0; + background-color: $dropdown-link-active-bg; + } +} + +// Disabled state +// +// Gray out text and ensure the hover/focus state remains gray + +.dropdown-menu > .disabled > a { + &, + &:hover, + &:focus { + color: $dropdown-link-disabled-color; + } +} +// Nuke hover/focus effects +.dropdown-menu > .disabled > a { + &:hover, + &:focus { + text-decoration: none; + background-color: transparent; + background-image: none; // Remove CSS gradient + @include reset-filter(); + cursor: not-allowed; + } +} + +// Open state for the dropdown +.open { + // Show the menu + > .dropdown-menu { + display: block; + } + + // Remove the outline when :focus is triggered + > a { + outline: 0; + } +} + +// Dropdown section headers +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: $font-size-small; + line-height: $line-height-base; + color: $dropdown-header-color; +} + +// Backdrop to catch body clicks on mobile, etc. +.dropdown-backdrop { + position: fixed; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: $zindex-dropdown - 10; +} + // Right aligned dropdowns -// --------------------------- .pull-right > .dropdown-menu { right: 0; left: auto; } // Allow for dropdowns to go bottom up (aka, dropup-menu) -// ------------------------------------------------------ +// // Just add .dropup after the standard .dropdown class and you're set, bro. // TODO: abstract this so that the navbar fixed styles are not placed here? + .dropup, .navbar-fixed-bottom .dropdown { // Reverse the caret .caret { border-top: 0; - border-bottom: 4px solid $black; + border-bottom: $caret-width-base solid; content: ""; } // Different positioning for bottom up menu @@ -162,76 +172,17 @@ } } -// Sub menus -// --------------------------- -.dropdown-submenu { - position: relative; -} -// Default dropdowns -.dropdown-submenu > .dropdown-menu { - top: 0; - left: 100%; - margin-top: -6px; - margin-left: -1px; - @include border-radius(0 6px 6px 6px); -} -.dropdown-submenu:hover > .dropdown-menu { - display: block; -} -// Dropups -.dropup .dropdown-submenu > .dropdown-menu { - top: auto; - bottom: 0; - margin-top: 0; - margin-bottom: -2px; - @include border-radius(5px 5px 5px 0); -} +// Component alignment +// +// Reiterate per navbar.less and the modified component alignment there. -// Caret to indicate there is a submenu -.dropdown-submenu > a:after { - display: block; - content: " "; - float: right; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; - border-width: 5px 0 5px 5px; - border-left-color: darken($dropdownBackground, 20%); - margin-top: 5px; - margin-right: -10px; -} -.dropdown-submenu:hover > a:after { - border-left-color: $dropdownLinkColorHover; -} - -// Left aligned submenus -.dropdown-submenu.pull-left { - // Undo the float - // Yes, this is awkward since .pull-left adds a float, but it sticks to our conventions elsewhere. - float: none; - - // Positioning the submenu - > .dropdown-menu { - left: -100%; - margin-left: 10px; - @include border-radius(6px 0 6px 6px); +@media (min-width: $grid-float-breakpoint) { + .navbar-right { + .dropdown-menu { + right: 0; + left: auto; + } } } -// Tweak nav headers -// ----------------- -// Increase padding from 15px to 20px on sides -.dropdown .dropdown-menu .nav-header { - padding-left: 20px; - padding-right: 20px; -} - -// Typeahead -// --------- -.typeahead { - z-index: 1051; - margin-top: 2px; // give it some space to breathe - @include border-radius($baseBorderRadius); -} diff --git a/app/styles/bootstrap/_forms.scss b/app/styles/bootstrap/_forms.scss index 6b05636cd..6f1383ec7 100644 --- a/app/styles/bootstrap/_forms.scss +++ b/app/styles/bootstrap/_forms.scss @@ -3,13 +3,9 @@ // -------------------------------------------------- -// GENERAL STYLES -// -------------- - -// Make all forms have space below them -form { - margin: 0 0 $baseLineHeight; -} +// Normalize non-controls +// +// Restyle and baseline non-control form elements. fieldset { padding: 0; @@ -17,153 +13,43 @@ fieldset { border: 0; } -// Groups of fields with labels on top (legends) legend { display: block; width: 100%; padding: 0; - margin-bottom: $baseLineHeight; - font-size: $baseFontSize * 1.5; - line-height: $baseLineHeight * 2; - color: $grayDark; + margin-bottom: $line-height-computed; + font-size: ($font-size-base * 1.5); + line-height: inherit; + color: $legend-color; border: 0; - border-bottom: 1px solid #e5e5e5; - - // Small - small { - font-size: $baseLineHeight * .75; - color: $grayLight; - } + border-bottom: 1px solid $legend-border-color; } -// Set font for forms -label, -input, -button, -select, -textarea { - @include font-shorthand($baseFontSize, normal, $baseLineHeight); // Set size, weight, line-height here -} -input, -button, -select, -textarea { - font-family: $baseFontFamily; // And only set font-family here for those that need it (note the missing label element) -} - -// Identify controls by their labels label { - display: block; - margin-bottom: 5px; -} - -// Form controls -// ------------------------- - -// Shared size and type resets -select, -textarea, -input[type="text"], -input[type="password"], -input[type="datetime"], -input[type="datetime-local"], -input[type="date"], -input[type="month"], -input[type="time"], -input[type="week"], -input[type="number"], -input[type="email"], -input[type="url"], -input[type="search"], -input[type="tel"], -input[type="color"], -.uneditable-input { display: inline-block; - height: $baseLineHeight; - padding: 4px 6px; - margin-bottom: $baseLineHeight / 2;; - font-size: $baseFontSize; - line-height: $baseLineHeight; - color: $gray; - @include border-radius($inputBorderRadius); - vertical-align: middle; + margin-bottom: 5px; + font-weight: bold; } -// Reset appearance properties for textual inputs and textarea -// Declare width for legacy (can't be on input[type=*] selectors or it's too specific) -input, -textarea, -.uneditable-input { - width: 206px; // plus 12px padding and 2px border -} -// Reset height since textareas have rows -textarea { - height: auto; -} -// Everything else -textarea, -input[type="text"], -input[type="password"], -input[type="datetime"], -input[type="datetime-local"], -input[type="date"], -input[type="month"], -input[type="time"], -input[type="week"], -input[type="number"], -input[type="email"], -input[type="url"], -input[type="search"], -input[type="tel"], -input[type="color"], -.uneditable-input { - background-color: $inputBackground; - border: 1px solid $inputBorder; - @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); - @include transition(border linear .2s, box-shadow linear .2s); - // Focus state - &:focus { - border-color: rgba(82,168,236,.8); - outline: 0; - outline: thin dotted \9; /* IE6-9 */ - @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6)); - } +// Normalize form controls + +// Override content-box in Normalize (* isn't specific enough) +input[type="search"] { + @include box-sizing(border-box); } // Position radios and checkboxes better input[type="radio"], input[type="checkbox"] { margin: 4px 0 0; - *margin-top: 0; /* IE7 */ margin-top: 1px \9; /* IE8-9 */ line-height: normal; } -// Reset width of input images, buttons, radios, checkboxes -input[type="file"], -input[type="image"], -input[type="submit"], -input[type="reset"], -input[type="button"], -input[type="radio"], -input[type="checkbox"] { - width: auto; // Override of generic input selector -} - // Set the height of select and file controls to match text inputs -select, input[type="file"] { - height: $inputHeight; /* In IE7, the height of the select element cannot be changed by height, only font-size */ - *margin-top: 4px; /* For IE7, add top margin to align select with labels */ - line-height: $inputHeight; -} - -// Make select elements obey height by applying a border -select { - width: 220px; // default input width + 10px of padding that doesn't get applied - border: 1px solid $inputBorder; - background-color: $inputBackground; // Chrome on Linux and Mobile Safari need background-color + display: block; } // Make multiple select elements height not fixed @@ -172,518 +58,317 @@ select[size] { height: auto; } +// Fix optgroup Firefox bug per https://github.com/twbs/bootstrap/issues/7611 +select optgroup { + font-size: inherit; + font-style: inherit; + font-family: inherit; +} + // Focus for select, file, radio, and checkbox -select:focus, input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus { @include tab-focus(); } - -// Uneditable inputs -// ------------------------- - -// Make uneditable inputs look inactive -.uneditable-input, -.uneditable-textarea { - color: $grayLight; - background-color: darken($inputBackground, 1%); - border-color: $inputBorder; - @include box-shadow(inset 0 1px 2px rgba(0,0,0,.025)); - cursor: not-allowed; +// Fix for Chrome number input +// Setting certain font-sizes causes the `I` bar to appear on hover of the bottom increment button. +// See https://github.com/twbs/bootstrap/issues/8350 for more. +input[type="number"] { + &::-webkit-outer-spin-button, + &::-webkit-inner-spin-button { + height: auto; + } } -// For text that needs to appear as an input but should not be an input -.uneditable-input { - overflow: hidden; // prevent text from wrapping, but still cut it off like an input does - white-space: nowrap; +// Adjust output element +output { + display: block; + padding-top: ($padding-base-vertical + 1); + font-size: $font-size-base; + line-height: $line-height-base; + color: $input-color; + vertical-align: middle; } -// Make uneditable textareas behave like a textarea -.uneditable-textarea { - width: auto; + +// Common form controls +// +// Shared size and type resets for form controls. Apply `.form-control` to any +// of the following form controls: +// +// select +// textarea +// input[type="text"] +// input[type="password"] +// input[type="datetime"] +// input[type="datetime-local"] +// input[type="date"] +// input[type="month"] +// input[type="time"] +// input[type="week"] +// input[type="number"] +// input[type="email"] +// input[type="url"] +// input[type="search"] +// input[type="tel"] +// input[type="color"] + +.form-control { + display: block; + width: 100%; + height: $input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border) + padding: $padding-base-vertical $padding-base-horizontal; + font-size: $font-size-base; + line-height: $line-height-base; + color: $input-color; + vertical-align: middle; + background-color: $input-bg; + background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214 + border: 1px solid $input-border; + border-radius: $input-border-radius; + @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); + @include transition(border-color ease-in-out .15s, box-shadow ease-in-out .15s); + + // Customize the `:focus` state to imitate native WebKit styles. + @include form-control-focus(); + + // Placeholder + // + // Placeholder text gets special styles because when browsers invalidate entire + // lines if it doesn't understand a selector/ + @include placeholder(); + + // Disabled and read-only inputs + // Note: HTML5 says that controls under a fieldset > legend:first-child won't + // be disabled if the fieldset is disabled. Due to implementation difficulty, + // we don't honor that edge case; we style them as disabled anyway. + &[disabled], + &[readonly], + fieldset[disabled] & { + cursor: not-allowed; + background-color: $input-bg-disabled; + } + + // [converter] extracted textarea& to textarea.form-control +} + +// Reset height for `textarea`s +textarea.form-control { height: auto; } -// Placeholder -// ------------------------- +// Form groups +// +// Designed to help with the organization and spacing of vertical forms. For +// horizontal forms, use the predefined grid classes. -// Placeholder text gets special styles because when browsers invalidate entire lines if it doesn't understand a selector -input, -textarea { - @include placeholder(); +.form-group { + margin-bottom: 15px; } -// CHECKBOXES & RADIOS -// ------------------- +// Checkboxes and radios +// +// Indent the labels to position radios/checkboxes as hanging controls. -// Indent the labels to position radios/checkboxes as hanging .radio, .checkbox { - min-height: $baseLineHeight; // clear the floating input if there is no label text + display: block; + min-height: $line-height-computed; // clear the floating input if there is no label text + margin-top: 10px; + margin-bottom: 10px; padding-left: 20px; + vertical-align: middle; + label { + display: inline; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; + } } .radio input[type="radio"], -.checkbox input[type="checkbox"] { +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { float: left; margin-left: -20px; } - -// Move the options list down to align with labels -.controls > .radio:first-child, -.controls > .checkbox:first-child { - padding-top: 5px; // has to be padding because margin collaspes +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing } // Radios and checkboxes on same line -// TODO v3: Convert .inline to .control-inline -.radio.inline, -.checkbox.inline { +.radio-inline, +.checkbox-inline { display: inline-block; - padding-top: 5px; + padding-left: 20px; margin-bottom: 0; vertical-align: middle; + font-weight: normal; + cursor: pointer; } -.radio.inline + .radio.inline, -.checkbox.inline + .checkbox.inline { +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; margin-left: 10px; // space out consecutive inline controls } - - -// INPUT SIZES -// ----------- - -// General classes for quick sizes -.input-mini { width: 60px; } -.input-small { width: 90px; } -.input-medium { width: 150px; } -.input-large { width: 210px; } -.input-xlarge { width: 270px; } -.input-xxlarge { width: 530px; } - -// Grid style input sizes -input[class*="span"], -select[class*="span"], -textarea[class*="span"], -.uneditable-input[class*="span"], -// Redeclare since the fluid row class is more specific -.row-fluid input[class*="span"], -.row-fluid select[class*="span"], -.row-fluid textarea[class*="span"], -.row-fluid .uneditable-input[class*="span"] { - float: none; - margin-left: 0; -} -// Ensure input-prepend/append never wraps -.input-append input[class*="span"], -.input-append .uneditable-input[class*="span"], -.input-prepend input[class*="span"], -.input-prepend .uneditable-input[class*="span"], -.row-fluid input[class*="span"], -.row-fluid select[class*="span"], -.row-fluid textarea[class*="span"], -.row-fluid .uneditable-input[class*="span"], -.row-fluid .input-prepend [class*="span"], -.row-fluid .input-append [class*="span"] { - display: inline-block; -} - - - -// GRID SIZING FOR INPUTS -// ---------------------- - -// Grid sizes -@include grid-input($gridColumnWidth, $gridGutterWidth); - -// Control row for multiple inputs per line -.controls-row { - @include clearfix(); // Clear the float from controls -} - -// Float to collapse white-space for proper grid alignment -.controls-row [class*="span"], -// Redeclare the fluid grid collapse since we undo the float for inputs -.row-fluid .controls-row [class*="span"] { - float: left; -} -// Explicity set top padding on all checkboxes/radios, not just first-child -.controls-row .checkbox[class*="span"], -.controls-row .radio[class*="span"] { - padding-top: 5px; -} - - - - -// DISABLED STATE -// -------------- - -// Disabled and read-only inputs -input[disabled], -select[disabled], -textarea[disabled], -input[readonly], -select[readonly], -textarea[readonly] { - cursor: not-allowed; - background-color: $inputDisabledBackground; -} -// Explicitly reset the colors here -input[type="radio"][disabled], -input[type="checkbox"][disabled], -input[type="radio"][readonly], -input[type="checkbox"][readonly] { - background-color: transparent; -} - - - - -// FORM FIELD FEEDBACK STATES -// -------------------------- - -// Warning -.control-group.warning { - @include formFieldState($warningText, $warningText, $warningBackground); -} -// Error -.control-group.error { - @include formFieldState($errorText, $errorText, $errorBackground); -} -// Success -.control-group.success { - @include formFieldState($successText, $successText, $successBackground); -} -// Info -.control-group.info { - @include formFieldState($infoText, $infoText, $infoBackground); -} - -// HTML5 invalid states -// Shares styles with the .control-group.error above -input:focus:invalid, -textarea:focus:invalid, -select:focus:invalid { - color: #b94a48; - border-color: #ee5f5b; - &:focus { - border-color: darken(#ee5f5b, 10%); - @include box-shadow(0 0 6px lighten(#ee5f5b, 20%)); +// Apply same disabled cursor tweak as for inputs +// +// Note: Neither radios nor checkboxes can be readonly. +input[type="radio"], +input[type="checkbox"], +.radio, +.radio-inline, +.checkbox, +.checkbox-inline { + &[disabled], + fieldset[disabled] & { + cursor: not-allowed; } } +// Form control sizing + +@include input-size('.input-sm', $input-height-small, $padding-small-vertical, $padding-small-horizontal, $font-size-small, $line-height-small, $border-radius-small); + +@include input-size('.input-lg', $input-height-large, $padding-large-vertical, $padding-large-horizontal, $font-size-large, $line-height-large, $border-radius-large); -// FORM ACTIONS -// ------------ +// Form control feedback states +// +// Apply contextual and semantic states to individual form controls. -.form-actions { - padding: ($baseLineHeight - 1) 20px $baseLineHeight; - margin-top: $baseLineHeight; - margin-bottom: $baseLineHeight; - background-color: $formActionsBackground; - border-top: 1px solid #e5e5e5; - @include clearfix(); // Adding clearfix to allow for .pull-right button containers +// Warning +.has-warning { + @include form-control-validation($state-warning-text, $state-warning-text, $state-warning-bg); +} +// Error +.has-error { + @include form-control-validation($state-danger-text, $state-danger-text, $state-danger-bg); +} +// Success +.has-success { + @include form-control-validation($state-success-text, $state-success-text, $state-success-bg); } +// Static form control text +// +// Apply class to a `p` element to make any string of text align with labels in +// a horizontal form layout. -// HELP TEXT -// --------- - -.help-block, -.help-inline { - color: lighten($textColor, 15%); // lighten the text some for contrast +.form-control-static { + margin-bottom: 0; // Remove default margin from `p` } + +// Help text +// +// Apply to any element you wish to create light text for placement immediately +// below a form control. Use for general help, formatting, or instructional text. + .help-block { display: block; // account for any element using help-block - margin-bottom: $baseLineHeight / 2; -} - -.help-inline { - display: inline-block; - @include ie7-inline-block(); - vertical-align: middle; - padding-left: 5px; + margin-top: 5px; + margin-bottom: 10px; + color: lighten($text-color, 25%); // lighten the text some for contrast } -// INPUT GROUPS -// ------------ +// Inline forms +// +// Make forms appear inline(-block) by adding the `.form-inline` class. Inline +// forms begin stacked on extra small (mobile) devices and then go inline when +// viewports reach <768px. +// +// Requires wrapping inputs and labels with `.form-group` for proper display of +// default HTML form controls and our custom form controls (e.g., input groups). +// +// Heads up! This is mixin-ed into `.navbar-form` in navbars.less. -// Allow us to put symbols and text within the input field for a cleaner look -.input-append, -.input-prepend { - display: inline-block; - margin-bottom: $baseLineHeight / 2; - vertical-align: middle; - font-size: 0; // white space collapse hack - white-space: nowrap; // Prevent span and input from separating +.form-inline { - // Reset the white space collapse hack - input, - select, - .uneditable-input, - .dropdown-menu, - .popover { - font-size: $baseFontSize; - } + // Kick in the inline + @media (min-width: $screen-sm) { + // Inline-block all the things for "inline" + .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } - input, - select, - .uneditable-input { - position: relative; // placed here by default so that on :focus we can place the input above the .add-on for full border and box-shadow goodness - margin-bottom: 0; // prevent bottom margin from screwing up alignment in stacked forms - *margin-left: 0; - vertical-align: top; - @include border-radius(0 $inputBorderRadius $inputBorderRadius 0); - // Make input on top when focused so blue border and shadow always show - &:focus { - z-index: 2; + // In navbar-form, allow folks to *not* use `.form-group` + .form-control { + display: inline-block; + } + + // Override `width: 100%;` when not within a `.form-group` + select.form-control { + width: auto; + } + + // Remove default margin on radios/checkboxes that were used for stacking, and + // then undo the floating of radios and checkboxes to match (which also avoids + // a bug in WebKit: https://github.com/twbs/bootstrap/issues/1969). + .radio, + .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + padding-left: 0; + } + .radio input[type="radio"], + .checkbox input[type="checkbox"] { + float: none; + margin-left: 0; } } - .add-on { - display: inline-block; - width: auto; - height: $baseLineHeight; - min-width: 16px; - padding: 4px 5px; - font-size: $baseFontSize; - font-weight: normal; - line-height: $baseLineHeight; - text-align: center; - text-shadow: 0 1px 0 $white; - background-color: $grayLighter; - border: 1px solid #ccc; - } - .add-on, - .btn, - .btn-group > .dropdown-toggle { - vertical-align: top; - @include border-radius(0); - } - .active { - background-color: lighten($green, 30); - border-color: $green; - } -} - -.input-prepend { - .add-on, - .btn { - margin-right: -1px; - } - .add-on:first-child, - .btn:first-child { - // FYI, `.btn:first-child` accounts for a button group that's prepended - @include border-radius($inputBorderRadius 0 0 $inputBorderRadius); - } -} - -.input-append { - input, - select, - .uneditable-input { - @include border-radius($inputBorderRadius 0 0 $inputBorderRadius); - + .btn-group .btn:last-child { - @include border-radius(0 $inputBorderRadius $inputBorderRadius 0); - } - } - .add-on, - .btn, - .btn-group { - margin-left: -1px; - } - .add-on:last-child, - .btn:last-child, - .btn-group:last-child > .dropdown-toggle { - @include border-radius(0 $inputBorderRadius $inputBorderRadius 0); - } -} - -// Remove all border-radius for inputs with both prepend and append -.input-prepend.input-append { - input, - select, - .uneditable-input { - @include border-radius(0); - + .btn-group .btn { - @include border-radius(0 $inputBorderRadius $inputBorderRadius 0); - } - } - .add-on:first-child, - .btn:first-child { - margin-right: -1px; - @include border-radius($inputBorderRadius 0 0 $inputBorderRadius); - } - .add-on:last-child, - .btn:last-child { - margin-left: -1px; - @include border-radius(0 $inputBorderRadius $inputBorderRadius 0); - } - .btn-group:first-child { - margin-left: 0; - } } - - -// SEARCH FORM -// ----------- - -input.search-query { - padding-right: 14px; - padding-right: 4px \9; - padding-left: 14px; - padding-left: 4px \9; /* IE7-8 doesn't have border-radius, so don't indent the padding */ - margin-bottom: 0; // Remove the default margin on all inputs - @include border-radius(15px); -} - -/* Allow for input prepend/append in search forms */ -.form-search .input-append .search-query, -.form-search .input-prepend .search-query { - @include border-radius(0); // Override due to specificity -} -.form-search .input-append .search-query { - @include border-radius(14px 0 0 14px); -} -.form-search .input-append .btn { - @include border-radius(0 14px 14px 0); -} -.form-search .input-prepend .search-query { - @include border-radius(0 14px 14px 0); -} -.form-search .input-prepend .btn { - @include border-radius(14px 0 0 14px); -} - - - - -// HORIZONTAL & VERTICAL FORMS -// --------------------------- - -// Common properties -// ----------------- - -.form-search, -.form-inline, -.form-horizontal { - input, - textarea, - select, - .help-inline, - .uneditable-input, - .input-prepend, - .input-append { - display: inline-block; - @include ie7-inline-block(); - margin-bottom: 0; - vertical-align: middle; - } - // Re-hide hidden elements due to specifity - .hide { - display: none; - } -} -.form-search label, -.form-inline label, -.form-search .btn-group, -.form-inline .btn-group { - display: inline-block; -} -// Remove margin for input-prepend/-append -.form-search .input-append, -.form-inline .input-append, -.form-search .input-prepend, -.form-inline .input-prepend { - margin-bottom: 0; -} -// Inline checkbox/radio labels (remove padding on left) -.form-search .radio, -.form-search .checkbox, -.form-inline .radio, -.form-inline .checkbox { - padding-left: 0; - margin-bottom: 0; - vertical-align: middle; -} -// Remove float and margin, set to inline-block -.form-search .radio input[type="radio"], -.form-search .checkbox input[type="checkbox"], -.form-inline .radio input[type="radio"], -.form-inline .checkbox input[type="checkbox"] { - float: left; - margin-right: 3px; - margin-left: 0; -} - - -// Margin to space out fieldsets -.control-group { - margin-bottom: $baseLineHeight / 2; -} - -// Legend collapses margin, so next element is responsible for spacing -legend + .control-group { - margin-top: $baseLineHeight; - -webkit-margin-top-collapse: separate; -} - -// Horizontal-specific styles -// -------------------------- +// Horizontal forms +// +// Horizontal forms are built on grid classes and allow you to create forms with +// labels on the left and inputs on the right. .form-horizontal { - // Increase spacing between groups - .control-group { - margin-bottom: $baseLineHeight; - @include clearfix(); - } - // Float the labels left - .control-label { - float: left; - width: $horizontalComponentOffset - 20; - padding-top: 5px; - text-align: right; - } - // Move over all input controls and content - .controls { - // Super jank IE7 fix to ensure the inputs in .input-append and input-prepend - // don't inherit the margin of the parent, in this case .controls - *display: inline-block; - *padding-left: 20px; - margin-left: $horizontalComponentOffset; - *margin-left: 0; - &:first-child { - *padding-left: $horizontalComponentOffset; - } - } - // Remove bottom margin on block level help text since that's accounted for on .control-group - .help-block { + + // Consistent vertical alignment of labels, radios, and checkboxes + .control-label, + .radio, + .checkbox, + .radio-inline, + .checkbox-inline { + margin-top: 0; margin-bottom: 0; + padding-top: ($padding-base-vertical + 1); // Default padding plus a border } - // And apply it only to .help-block instances that follow a form control - input, - select, - textarea, - .uneditable-input, - .input-prepend, - .input-append { - + .help-block { - margin-top: $baseLineHeight / 2; + // Account for padding we're adding to ensure the alignment and of help text + // and other content below items + .radio, + .checkbox { + min-height: $line-height-computed + ($padding-base-vertical + 1); + } + + // Make form groups behave like rows + .form-group { + @include make-row(); + } + + .form-control-static { + padding-top: ($padding-base-vertical + 1); + } + + // Only right align form labels here when the columns stop stacking + @media (min-width: $screen-sm-min) { + .control-label { + text-align: right; } } - // Move over buttons in .form-actions to align with .controls - .form-actions { - padding-left: $horizontalComponentOffset; - } } diff --git a/app/styles/bootstrap/_glyphicons.scss b/app/styles/bootstrap/_glyphicons.scss new file mode 100644 index 000000000..9ba2abd05 --- /dev/null +++ b/app/styles/bootstrap/_glyphicons.scss @@ -0,0 +1,237 @@ +// +// Glyphicons for Bootstrap +// +// Since icons are fonts, they can be placed anywhere text is placed and are +// thus automatically sized to match the surrounding child. To use, create an +// inline element with the appropriate classes, like so: +// +// Star + +// Import the fonts +@font-face { + font-family: 'Glyphicons Halflings'; + src: url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.eot'), '#{$icon-font-path}#{$icon-font-name}.eot')); + src: url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.eot?#iefix'), '#{$icon-font-path}#{$icon-font-name}.eot?#iefix')) format('embedded-opentype'), + url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.woff'), '#{$icon-font-path}#{$icon-font-name}.woff')) format('woff'), + url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.ttf'), '#{$icon-font-path}#{$icon-font-name}.ttf')) format('truetype'), + url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.svg#glyphicons-halflingsregular'), '#{$icon-font-path}#{$icon-font-name}.svg#glyphicons-halflingsregular')) format('svg'); +} + +// Catchall baseclass +.glyphicon { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + &:empty { + width: 1em; + } +} + +// Individual icons +.glyphicon-asterisk { &:before { content: "\2a"; } } +.glyphicon-plus { &:before { content: "\2b"; } } +.glyphicon-euro { &:before { content: "\20ac"; } } +.glyphicon-minus { &:before { content: "\2212"; } } +.glyphicon-cloud { &:before { content: "\2601"; } } +.glyphicon-envelope { &:before { content: "\2709"; } } +.glyphicon-pencil { &:before { content: "\270f"; } } +.glyphicon-glass { &:before { content: "\e001"; } } +.glyphicon-music { &:before { content: "\e002"; } } +.glyphicon-search { &:before { content: "\e003"; } } +.glyphicon-heart { &:before { content: "\e005"; } } +.glyphicon-star { &:before { content: "\e006"; } } +.glyphicon-star-empty { &:before { content: "\e007"; } } +.glyphicon-user { &:before { content: "\e008"; } } +.glyphicon-film { &:before { content: "\e009"; } } +.glyphicon-th-large { &:before { content: "\e010"; } } +.glyphicon-th { &:before { content: "\e011"; } } +.glyphicon-th-list { &:before { content: "\e012"; } } +.glyphicon-ok { &:before { content: "\e013"; } } +.glyphicon-remove { &:before { content: "\e014"; } } +.glyphicon-zoom-in { &:before { content: "\e015"; } } +.glyphicon-zoom-out { &:before { content: "\e016"; } } +.glyphicon-off { &:before { content: "\e017"; } } +.glyphicon-signal { &:before { content: "\e018"; } } +.glyphicon-cog { &:before { content: "\e019"; } } +.glyphicon-trash { &:before { content: "\e020"; } } +.glyphicon-home { &:before { content: "\e021"; } } +.glyphicon-file { &:before { content: "\e022"; } } +.glyphicon-time { &:before { content: "\e023"; } } +.glyphicon-road { &:before { content: "\e024"; } } +.glyphicon-download-alt { &:before { content: "\e025"; } } +.glyphicon-download { &:before { content: "\e026"; } } +.glyphicon-upload { &:before { content: "\e027"; } } +.glyphicon-inbox { &:before { content: "\e028"; } } +.glyphicon-play-circle { &:before { content: "\e029"; } } +.glyphicon-repeat { &:before { content: "\e030"; } } +.glyphicon-refresh { &:before { content: "\e031"; } } +.glyphicon-list-alt { &:before { content: "\e032"; } } +.glyphicon-lock { &:before { content: "\e033"; } } +.glyphicon-flag { &:before { content: "\e034"; } } +.glyphicon-headphones { &:before { content: "\e035"; } } +.glyphicon-volume-off { &:before { content: "\e036"; } } +.glyphicon-volume-down { &:before { content: "\e037"; } } +.glyphicon-volume-up { &:before { content: "\e038"; } } +.glyphicon-qrcode { &:before { content: "\e039"; } } +.glyphicon-barcode { &:before { content: "\e040"; } } +.glyphicon-tag { &:before { content: "\e041"; } } +.glyphicon-tags { &:before { content: "\e042"; } } +.glyphicon-book { &:before { content: "\e043"; } } +.glyphicon-bookmark { &:before { content: "\e044"; } } +.glyphicon-print { &:before { content: "\e045"; } } +.glyphicon-camera { &:before { content: "\e046"; } } +.glyphicon-font { &:before { content: "\e047"; } } +.glyphicon-bold { &:before { content: "\e048"; } } +.glyphicon-italic { &:before { content: "\e049"; } } +.glyphicon-text-height { &:before { content: "\e050"; } } +.glyphicon-text-width { &:before { content: "\e051"; } } +.glyphicon-align-left { &:before { content: "\e052"; } } +.glyphicon-align-center { &:before { content: "\e053"; } } +.glyphicon-align-right { &:before { content: "\e054"; } } +.glyphicon-align-justify { &:before { content: "\e055"; } } +.glyphicon-list { &:before { content: "\e056"; } } +.glyphicon-indent-left { &:before { content: "\e057"; } } +.glyphicon-indent-right { &:before { content: "\e058"; } } +.glyphicon-facetime-video { &:before { content: "\e059"; } } +.glyphicon-picture { &:before { content: "\e060"; } } +.glyphicon-map-marker { &:before { content: "\e062"; } } +.glyphicon-adjust { &:before { content: "\e063"; } } +.glyphicon-tint { &:before { content: "\e064"; } } +.glyphicon-edit { &:before { content: "\e065"; } } +.glyphicon-share { &:before { content: "\e066"; } } +.glyphicon-check { &:before { content: "\e067"; } } +.glyphicon-move { &:before { content: "\e068"; } } +.glyphicon-step-backward { &:before { content: "\e069"; } } +.glyphicon-fast-backward { &:before { content: "\e070"; } } +.glyphicon-backward { &:before { content: "\e071"; } } +.glyphicon-play { &:before { content: "\e072"; } } +.glyphicon-pause { &:before { content: "\e073"; } } +.glyphicon-stop { &:before { content: "\e074"; } } +.glyphicon-forward { &:before { content: "\e075"; } } +.glyphicon-fast-forward { &:before { content: "\e076"; } } +.glyphicon-step-forward { &:before { content: "\e077"; } } +.glyphicon-eject { &:before { content: "\e078"; } } +.glyphicon-chevron-left { &:before { content: "\e079"; } } +.glyphicon-chevron-right { &:before { content: "\e080"; } } +.glyphicon-plus-sign { &:before { content: "\e081"; } } +.glyphicon-minus-sign { &:before { content: "\e082"; } } +.glyphicon-remove-sign { &:before { content: "\e083"; } } +.glyphicon-ok-sign { &:before { content: "\e084"; } } +.glyphicon-question-sign { &:before { content: "\e085"; } } +.glyphicon-info-sign { &:before { content: "\e086"; } } +.glyphicon-screenshot { &:before { content: "\e087"; } } +.glyphicon-remove-circle { &:before { content: "\e088"; } } +.glyphicon-ok-circle { &:before { content: "\e089"; } } +.glyphicon-ban-circle { &:before { content: "\e090"; } } +.glyphicon-arrow-left { &:before { content: "\e091"; } } +.glyphicon-arrow-right { &:before { content: "\e092"; } } +.glyphicon-arrow-up { &:before { content: "\e093"; } } +.glyphicon-arrow-down { &:before { content: "\e094"; } } +.glyphicon-share-alt { &:before { content: "\e095"; } } +.glyphicon-resize-full { &:before { content: "\e096"; } } +.glyphicon-resize-small { &:before { content: "\e097"; } } +.glyphicon-exclamation-sign { &:before { content: "\e101"; } } +.glyphicon-gift { &:before { content: "\e102"; } } +.glyphicon-leaf { &:before { content: "\e103"; } } +.glyphicon-fire { &:before { content: "\e104"; } } +.glyphicon-eye-open { &:before { content: "\e105"; } } +.glyphicon-eye-close { &:before { content: "\e106"; } } +.glyphicon-warning-sign { &:before { content: "\e107"; } } +.glyphicon-plane { &:before { content: "\e108"; } } +.glyphicon-calendar { &:before { content: "\e109"; } } +.glyphicon-random { &:before { content: "\e110"; } } +.glyphicon-comment { &:before { content: "\e111"; } } +.glyphicon-magnet { &:before { content: "\e112"; } } +.glyphicon-chevron-up { &:before { content: "\e113"; } } +.glyphicon-chevron-down { &:before { content: "\e114"; } } +.glyphicon-retweet { &:before { content: "\e115"; } } +.glyphicon-shopping-cart { &:before { content: "\e116"; } } +.glyphicon-folder-close { &:before { content: "\e117"; } } +.glyphicon-folder-open { &:before { content: "\e118"; } } +.glyphicon-resize-vertical { &:before { content: "\e119"; } } +.glyphicon-resize-horizontal { &:before { content: "\e120"; } } +.glyphicon-hdd { &:before { content: "\e121"; } } +.glyphicon-bullhorn { &:before { content: "\e122"; } } +.glyphicon-bell { &:before { content: "\e123"; } } +.glyphicon-certificate { &:before { content: "\e124"; } } +.glyphicon-thumbs-up { &:before { content: "\e125"; } } +.glyphicon-thumbs-down { &:before { content: "\e126"; } } +.glyphicon-hand-right { &:before { content: "\e127"; } } +.glyphicon-hand-left { &:before { content: "\e128"; } } +.glyphicon-hand-up { &:before { content: "\e129"; } } +.glyphicon-hand-down { &:before { content: "\e130"; } } +.glyphicon-circle-arrow-right { &:before { content: "\e131"; } } +.glyphicon-circle-arrow-left { &:before { content: "\e132"; } } +.glyphicon-circle-arrow-up { &:before { content: "\e133"; } } +.glyphicon-circle-arrow-down { &:before { content: "\e134"; } } +.glyphicon-globe { &:before { content: "\e135"; } } +.glyphicon-wrench { &:before { content: "\e136"; } } +.glyphicon-tasks { &:before { content: "\e137"; } } +.glyphicon-filter { &:before { content: "\e138"; } } +.glyphicon-briefcase { &:before { content: "\e139"; } } +.glyphicon-fullscreen { &:before { content: "\e140"; } } +.glyphicon-dashboard { &:before { content: "\e141"; } } +.glyphicon-paperclip { &:before { content: "\e142"; } } +.glyphicon-heart-empty { &:before { content: "\e143"; } } +.glyphicon-link { &:before { content: "\e144"; } } +.glyphicon-phone { &:before { content: "\e145"; } } +.glyphicon-pushpin { &:before { content: "\e146"; } } +.glyphicon-usd { &:before { content: "\e148"; } } +.glyphicon-gbp { &:before { content: "\e149"; } } +.glyphicon-sort { &:before { content: "\e150"; } } +.glyphicon-sort-by-alphabet { &:before { content: "\e151"; } } +.glyphicon-sort-by-alphabet-alt { &:before { content: "\e152"; } } +.glyphicon-sort-by-order { &:before { content: "\e153"; } } +.glyphicon-sort-by-order-alt { &:before { content: "\e154"; } } +.glyphicon-sort-by-attributes { &:before { content: "\e155"; } } +.glyphicon-sort-by-attributes-alt { &:before { content: "\e156"; } } +.glyphicon-unchecked { &:before { content: "\e157"; } } +.glyphicon-expand { &:before { content: "\e158"; } } +.glyphicon-collapse-down { &:before { content: "\e159"; } } +.glyphicon-collapse-up { &:before { content: "\e160"; } } +.glyphicon-log-in { &:before { content: "\e161"; } } +.glyphicon-flash { &:before { content: "\e162"; } } +.glyphicon-log-out { &:before { content: "\e163"; } } +.glyphicon-new-window { &:before { content: "\e164"; } } +.glyphicon-record { &:before { content: "\e165"; } } +.glyphicon-save { &:before { content: "\e166"; } } +.glyphicon-open { &:before { content: "\e167"; } } +.glyphicon-saved { &:before { content: "\e168"; } } +.glyphicon-import { &:before { content: "\e169"; } } +.glyphicon-export { &:before { content: "\e170"; } } +.glyphicon-send { &:before { content: "\e171"; } } +.glyphicon-floppy-disk { &:before { content: "\e172"; } } +.glyphicon-floppy-saved { &:before { content: "\e173"; } } +.glyphicon-floppy-remove { &:before { content: "\e174"; } } +.glyphicon-floppy-save { &:before { content: "\e175"; } } +.glyphicon-floppy-open { &:before { content: "\e176"; } } +.glyphicon-credit-card { &:before { content: "\e177"; } } +.glyphicon-transfer { &:before { content: "\e178"; } } +.glyphicon-cutlery { &:before { content: "\e179"; } } +.glyphicon-header { &:before { content: "\e180"; } } +.glyphicon-compressed { &:before { content: "\e181"; } } +.glyphicon-earphone { &:before { content: "\e182"; } } +.glyphicon-phone-alt { &:before { content: "\e183"; } } +.glyphicon-tower { &:before { content: "\e184"; } } +.glyphicon-stats { &:before { content: "\e185"; } } +.glyphicon-sd-video { &:before { content: "\e186"; } } +.glyphicon-hd-video { &:before { content: "\e187"; } } +.glyphicon-subtitles { &:before { content: "\e188"; } } +.glyphicon-sound-stereo { &:before { content: "\e189"; } } +.glyphicon-sound-dolby { &:before { content: "\e190"; } } +.glyphicon-sound-5-1 { &:before { content: "\e191"; } } +.glyphicon-sound-6-1 { &:before { content: "\e192"; } } +.glyphicon-sound-7-1 { &:before { content: "\e193"; } } +.glyphicon-copyright-mark { &:before { content: "\e194"; } } +.glyphicon-registration-mark { &:before { content: "\e195"; } } +.glyphicon-cloud-download { &:before { content: "\e197"; } } +.glyphicon-cloud-upload { &:before { content: "\e198"; } } +.glyphicon-tree-conifer { &:before { content: "\e199"; } } +.glyphicon-tree-deciduous { &:before { content: "\e200"; } } diff --git a/app/styles/bootstrap/_grid.scss b/app/styles/bootstrap/_grid.scss index f2b910a16..3763e024e 100644 --- a/app/styles/bootstrap/_grid.scss +++ b/app/styles/bootstrap/_grid.scss @@ -2,20 +2,78 @@ // Grid system // -------------------------------------------------- +// Set the container width, and override it for fixed navbars in media queries +.container { + @include container-fixed(); -// Fixed (940px) -@include grid-core($gridColumnWidth, $gridGutterWidth); - -// Fluid (940px) -@include grid-fluid($fluidGridColumnWidth, $fluidGridGutterWidth); - -// Reset utility classes due to specificity -[class*="span"].hide, -.row-fluid [class*="span"].hide { - display: none; + @media (min-width: $screen-sm) { + width: $container-sm; + } + @media (min-width: $screen-md) { + width: $container-md; + } + @media (min-width: $screen-lg-min) { + width: $container-lg; + } } -[class*="span"].pull-right, -.row-fluid [class*="span"].pull-right { - float: right; +// mobile first defaults +.row { + @include make-row(); } + +// Common styles for small and large grid columns +@include make-grid-columns(); + + +// Extra small grid +// +// Columns, offsets, pushes, and pulls for extra small devices like +// smartphones. + +@include make-grid-columns-float(xs); +@include make-grid($grid-columns, xs, width); +@include make-grid($grid-columns, xs, pull); +@include make-grid($grid-columns, xs, push); +@include make-grid($grid-columns, xs, offset); + + +// Small grid +// +// Columns, offsets, pushes, and pulls for the small device range, from phones +// to tablets. + +@media (min-width: $screen-sm-min) { + @include make-grid-columns-float(sm); + @include make-grid($grid-columns, sm, width); + @include make-grid($grid-columns, sm, pull); + @include make-grid($grid-columns, sm, push); + @include make-grid($grid-columns, sm, offset); +} + + +// Medium grid +// +// Columns, offsets, pushes, and pulls for the desktop device range. + +@media (min-width: $screen-md-min) { + @include make-grid-columns-float(md); + @include make-grid($grid-columns, md, width); + @include make-grid($grid-columns, md, pull); + @include make-grid($grid-columns, md, push); + @include make-grid($grid-columns, md, offset); +} + + +// Large grid +// +// Columns, offsets, pushes, and pulls for the large desktop device range. + +@media (min-width: $screen-lg-min) { + @include make-grid-columns-float(lg); + @include make-grid($grid-columns, lg, width); + @include make-grid($grid-columns, lg, pull); + @include make-grid($grid-columns, lg, push); + @include make-grid($grid-columns, lg, offset); +} + diff --git a/app/styles/bootstrap/_input-groups.scss b/app/styles/bootstrap/_input-groups.scss new file mode 100644 index 000000000..4be458aa2 --- /dev/null +++ b/app/styles/bootstrap/_input-groups.scss @@ -0,0 +1,136 @@ +// +// Input groups +// -------------------------------------------------- + +// Base styles +// ------------------------- +.input-group { + position: relative; // For dropdowns + display: table; + border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table + + // Undo padding and float of grid classes + &[class*="col-"] { + float: none; + padding-left: 0; + padding-right: 0; + } + + .form-control { + width: 100%; + margin-bottom: 0; + } +} + +// Sizing options +// +// Remix the default form control sizing classes into new ones for easier +// manipulation. + +.input-group-lg > .form-control, +.input-group-lg > .input-group-addon, +.input-group-lg > .input-group-btn > .btn { @extend .input-lg; } +.input-group-sm > .form-control, +.input-group-sm > .input-group-addon, +.input-group-sm > .input-group-btn > .btn { @extend .input-sm; } + + +// Display as table-cell +// ------------------------- +.input-group-addon, +.input-group-btn, +.input-group .form-control { + display: table-cell; + + &:not(:first-child):not(:last-child) { + border-radius: 0; + } +} +// Addon and addon wrapper for buttons +.input-group-addon, +.input-group-btn { + width: 1%; + white-space: nowrap; + vertical-align: middle; // Match the inputs +} + +// Text input groups +// ------------------------- +.input-group-addon { + padding: $padding-base-vertical $padding-base-horizontal; + font-size: $font-size-base; + font-weight: normal; + line-height: 1; + color: $input-color; + text-align: center; + background-color: $input-group-addon-bg; + border: 1px solid $input-group-addon-border-color; + border-radius: $border-radius-base; + + // Sizing + &.input-sm { + padding: $padding-small-vertical $padding-small-horizontal; + font-size: $font-size-small; + border-radius: $border-radius-small; + } + &.input-lg { + padding: $padding-large-vertical $padding-large-horizontal; + font-size: $font-size-large; + border-radius: $border-radius-large; + } + + // Nuke default margins from checkboxes and radios to vertically center within. + input[type="radio"], + input[type="checkbox"] { + margin-top: 0; + } +} + +// Reset rounded corners +.input-group .form-control:first-child, +.input-group-addon:first-child, +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) { + @include border-right-radius(0); +} +.input-group-addon:first-child { + border-right: 0; +} +.input-group .form-control:last-child, +.input-group-addon:last-child, +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child) { + @include border-left-radius(0); +} +.input-group-addon:last-child { + border-left: 0; +} + +// Button input groups +// ------------------------- +.input-group-btn { + position: relative; + white-space: nowrap; + + // Negative margin to only have a 1px border between the two + &:first-child > .btn { + margin-right: -1px; + } + &:last-child > .btn { + margin-left: -1px; + } +} +.input-group-btn > .btn { + position: relative; + // Jankily prevent input button groups from wrapping + + .btn { + margin-left: -4px; + } + // Bring the "active" button to the front + &:hover, + &:active { + z-index: 2; + } +} diff --git a/app/styles/bootstrap/_jumbotron.scss b/app/styles/bootstrap/_jumbotron.scss new file mode 100644 index 000000000..221a65d14 --- /dev/null +++ b/app/styles/bootstrap/_jumbotron.scss @@ -0,0 +1,46 @@ +// +// Jumbotron +// -------------------------------------------------- + + +.jumbotron { + padding: $jumbotron-padding; + margin-bottom: $jumbotron-padding; + font-size: $jumbotron-font-size; + font-weight: 200; + line-height: ($line-height-base * 1.5); + color: $jumbotron-color; + background-color: $jumbotron-bg; + + h1, + .h1 { + line-height: 1; + color: $jumbotron-heading-color; + } + p { + line-height: 1.4; + } + + .container & { + border-radius: $border-radius-large; // Only round corners at higher resolutions if contained in a container + } + + .container { + max-width: 100%; + } + + @media screen and (min-width: $screen-sm-min) { + padding-top: ($jumbotron-padding * 1.6); + padding-bottom: ($jumbotron-padding * 1.6); + + .container & { + padding-left: ($jumbotron-padding * 2); + padding-right: ($jumbotron-padding * 2); + } + + h1, + .h1 { + font-size: ($font-size-base * 4.5); + } + } +} diff --git a/app/styles/bootstrap/_labels.scss b/app/styles/bootstrap/_labels.scss new file mode 100644 index 000000000..8353eb1a6 --- /dev/null +++ b/app/styles/bootstrap/_labels.scss @@ -0,0 +1,64 @@ +// +// Labels +// -------------------------------------------------- + +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: $label-color; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; + + // Add hover effects, but only for links + &[href] { + &:hover, + &:focus { + color: $label-link-hover-color; + text-decoration: none; + cursor: pointer; + } + } + + // Empty labels collapse automatically (not available in IE8) + &:empty { + display: none; + } + + // Quick fix for labels in buttons + .btn & { + position: relative; + top: -1px; + } +} + +// Colors +// Contextual variations (linked labels get darker on :hover) + +.label-default { + @include label-variant($label-default-bg); +} + +.label-primary { + @include label-variant($label-primary-bg); +} + +.label-success { + @include label-variant($label-success-bg); +} + +.label-info { + @include label-variant($label-info-bg); +} + +.label-warning { + @include label-variant($label-warning-bg); +} + +.label-danger { + @include label-variant($label-danger-bg); +} diff --git a/app/styles/bootstrap/_list-group.scss b/app/styles/bootstrap/_list-group.scss new file mode 100644 index 000000000..19f85d44a --- /dev/null +++ b/app/styles/bootstrap/_list-group.scss @@ -0,0 +1,88 @@ +// +// List groups +// -------------------------------------------------- + +// Base class +// +// Easily usable on
      ,
        , or
        . +.list-group { + // No need to set list-style: none; since .list-group-item is block level + margin-bottom: 20px; + padding-left: 0; // reset padding because ul and ol +} + +// Individual list items +// ------------------------- + +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + // Place the border on the list items and negative margin up for better styling + margin-bottom: -1px; + background-color: $list-group-bg; + border: 1px solid $list-group-border; + + // Round the first and last items + &:first-child { + @include border-top-radius($list-group-border-radius); + } + &:last-child { + margin-bottom: 0; + @include border-bottom-radius($list-group-border-radius); + } + + // Align badges within list items + > .badge { + float: right; + } + > .badge + .badge { + margin-right: 5px; + } +} + +// Linked list items +a.list-group-item { + color: $list-group-link-color; + + .list-group-item-heading { + color: $list-group-link-heading-color; + } + + // Hover state + &:hover, + &:focus { + text-decoration: none; + background-color: $list-group-hover-bg; + } + + // Active class on item itself, not parent + &.active, + &.active:hover, + &.active:focus { + z-index: 2; // Place active items above their siblings for proper border styling + color: $list-group-active-color; + background-color: $list-group-active-bg; + border-color: $list-group-active-border; + + // Force color to inherit for custom content + .list-group-item-heading { + color: inherit; + } + .list-group-item-text { + color: lighten($list-group-active-bg, 40%); + } + } +} + +// Custom content options +// ------------------------- + +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} diff --git a/app/styles/bootstrap/_media.scss b/app/styles/bootstrap/_media.scss index e461e446d..5ad22cd6d 100644 --- a/app/styles/bootstrap/_media.scss +++ b/app/styles/bootstrap/_media.scss @@ -10,7 +10,6 @@ .media, .media-body { overflow: hidden; - *overflow: visible; zoom: 1; } @@ -37,11 +36,13 @@ // Media image alignment // ------------------------- -.media > .pull-left { - margin-right: 10px; -} -.media > .pull-right { - margin-left: 10px; +.media { + > .pull-left { + margin-right: 10px; + } + > .pull-right { + margin-left: 10px; + } } @@ -50,6 +51,6 @@ // Undo default ul/ol styles .media-list { - margin-left: 0; + padding-left: 0; list-style: none; } diff --git a/app/styles/bootstrap/_mixins.scss b/app/styles/bootstrap/_mixins.scss index 8959ee8e4..d9e1ba660 100644 --- a/app/styles/bootstrap/_mixins.scss +++ b/app/styles/bootstrap/_mixins.scss @@ -3,73 +3,48 @@ // -------------------------------------------------- -// UTILITY MIXINS -// -------------------------------------------------- +// Utilities +// ------------------------- // Clearfix -// -------- -// For clearing floats like a boss h5bp.com/q -@mixin clearfix { - *zoom: 1; +// Source: http://nicolasgallagher.com/micro-clearfix-hack/ +// +// For modern browsers +// 1. The space content is one way to avoid an Opera bug when the +// contenteditable attribute is included anywhere else in the document. +// Otherwise it causes space to appear at the top and bottom of elements +// that are clearfixed. +// 2. The use of `table` rather than `block` is only necessary if using +// `:before` to contain the top-margins of child elements. +@mixin clearfix() { &:before, &:after { - display: table; - content: ""; - // Fixes Opera/contenteditable bug: - // http://nicolasgallagher.com/micro-clearfix-hack/#comment-36952 - line-height: 0; + content: " "; // 1 + display: table; // 2 } &:after { clear: both; } } -// Webkit-style focus -// ------------------ +// WebKit-style focus @mixin tab-focus() { // Default - outline: thin dotted #333; - // Webkit + outline: thin dotted; + // WebKit outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } // Center-align a block level element -// ---------------------------------- @mixin center-block() { display: block; margin-left: auto; margin-right: auto; } -// IE7 inline-block -// ---------------- -@mixin ie7-inline-block() { - *display: inline; /* IE7 inline-block hack */ - *zoom: 1; -} - -// IE7 likes to collapse whitespace on either side of the inline-block elements. -// Ems because we're attempting to match the width of a space character. Left -// version is for form buttons, which typically come after other elements, and -// right version is for icons, which come before. Applying both is ok, but it will -// mean that space between those elements will be .6em (~2 space characters) in IE7, -// instead of the 1 space in other browsers. -@mixin ie7-restore-left-whitespace() { - *margin-left: .3em; - - &:first-child { - *margin-left: 0; - } -} - -@mixin ie7-restore-right-whitespace() { - *margin-right: .3em; -} - // Sizing shortcuts -// ------------------------- -@mixin size($height, $width) { +@mixin size($width, $height) { width: $width; height: $height; } @@ -78,21 +53,15 @@ } // Placeholder text -// ------------------------- -@mixin placeholder($color: $placeholderText) { - &:-moz-placeholder { - color: $color; - } - &:-ms-input-placeholder { - color: $color; - } - &::-webkit-input-placeholder { - color: $color; - } +@mixin placeholder($color: $input-color-placeholder) { + &:-moz-placeholder { color: $color; } // Firefox 4-18 + &::-moz-placeholder { color: $color; // Firefox 19+ + opacity: 1; } // See https://github.com/twbs/bootstrap/pull/11526 + &:-ms-input-placeholder { color: $color; } // Internet Explorer 10+ + &::-webkit-input-placeholder { color: $color; } // Safari and Chrome } // Text overflow -// ------------------------- // Requires inline-block or block for proper styling @mixin text-overflow() { overflow: hidden; @@ -101,94 +70,25 @@ } // CSS image replacement -// ------------------------- +// +// Heads up! v3 launched with with only `.hide-text()`, but per our pattern for +// mixins being reused as classes with the same name, this doesn't hold up. As +// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. Note +// that we cannot chain the mixins together in Less, so they are repeated. +// // Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757 -@mixin hide-text { - font: 0/0 a; + +// Deprecated as of v3.0.1 (will be removed in v4) +@mixin hide-text() { + font: #{0/0} a; color: transparent; text-shadow: none; background-color: transparent; border: 0; } - - -// FONTS -// -------------------------------------------------- - -@mixin font-family-serif() { - font-family: $serifFontFamily; -} -@mixin font-family-sans-serif() { - font-family: $sansFontFamily; -} -@mixin font-family-monospace() { - font-family: $monoFontFamily; -} -@mixin font-shorthand($size: $baseFontSize, $weight: normal, $lineHeight: $baseLineHeight) { - font-size: $size; - font-weight: $weight; - line-height: $lineHeight; -} -@mixin font-serif($size: $baseFontSize, $weight: normal, $lineHeight: $baseLineHeight) { - @include font-family-serif(); - @include font-shorthand($size, $weight, $lineHeight); -} -@mixin font-sans-serif($size: $baseFontSize, $weight: normal, $lineHeight: $baseLineHeight) { - @include font-family-sans-serif(); - @include font-shorthand($size, $weight, $lineHeight); -} -@mixin font-monospace($size: $baseFontSize, $weight: normal, $lineHeight: $baseLineHeight) { - @include font-family-monospace(); - @include font-shorthand($size, $weight, $lineHeight); -} - - -// FORMS -// -------------------------------------------------- - -// Block level inputs -@mixin input-block-level { - display: block; - width: 100%; - min-height: $inputHeight; // Make inputs at least the height of their button counterpart (base line-height + padding + border) - @include box-sizing(border-box); // Makes inputs behave like true block-level elements -} - - - -// Mixin for form field states -@mixin formFieldState($textColor: #555, $borderColor: #ccc, $backgroundColor: #f5f5f5) { - // Set the text color - .control-label, - .help-block, - .help-inline { - color: $textColor; - } - // Style inputs accordingly - .checkbox, - .radio, - input, - select, - textarea { - color: $textColor; - } - input, - select, - textarea { - border-color: $borderColor; - @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work - &:focus { - border-color: darken($borderColor, 10%); - @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten($borderColor, 20%)); - } - } - // Give a small background color for input-prepend/-append - .input-prepend .add-on, - .input-append .add-on { - color: $textColor; - background-color: $backgroundColor; - border-color: $textColor; - } +// New mixin to use as of v3.0.1 +@mixin text-hide() { + @include hide-text(); } @@ -196,144 +96,121 @@ // CSS3 PROPERTIES // -------------------------------------------------- -// Border Radius -@mixin border-radius($radius) { - -webkit-border-radius: $radius; - -moz-border-radius: $radius; - border-radius: $radius; -} - -// Single Corner Border Radius -@mixin border-top-left-radius($radius) { - -webkit-border-top-left-radius: $radius; - -moz-border-radius-topleft: $radius; - border-top-left-radius: $radius; -} -@mixin border-top-right-radius($radius) { - -webkit-border-top-right-radius: $radius; - -moz-border-radius-topright: $radius; - border-top-right-radius: $radius; -} -@mixin border-bottom-right-radius($radius) { - -webkit-border-bottom-right-radius: $radius; - -moz-border-radius-bottomright: $radius; - border-bottom-right-radius: $radius; -} -@mixin border-bottom-left-radius($radius) { - -webkit-border-bottom-left-radius: $radius; - -moz-border-radius-bottomleft: $radius; - border-bottom-left-radius: $radius; -} - -// Single Side Border Radius +// Single side border-radius @mixin border-top-radius($radius) { - @include border-top-right-radius($radius); - @include border-top-left-radius($radius); + border-top-right-radius: $radius; + border-top-left-radius: $radius; } @mixin border-right-radius($radius) { - @include border-top-right-radius($radius); - @include border-bottom-right-radius($radius); + border-bottom-right-radius: $radius; + border-top-right-radius: $radius; } @mixin border-bottom-radius($radius) { - @include border-bottom-right-radius($radius); - @include border-bottom-left-radius($radius); + border-bottom-right-radius: $radius; + border-bottom-left-radius: $radius; } @mixin border-left-radius($radius) { - @include border-top-left-radius($radius); - @include border-bottom-left-radius($radius); + border-bottom-left-radius: $radius; + border-top-left-radius: $radius; } // Drop shadows @mixin box-shadow($shadow...) { - -webkit-box-shadow: $shadow; - -moz-box-shadow: $shadow; + -webkit-box-shadow: $shadow; // iOS <4.3 & Android <4.1 box-shadow: $shadow; } // Transitions @mixin transition($transition...) { -webkit-transition: $transition; - -moz-transition: $transition; - -o-transition: $transition; transition: $transition; } +@mixin transition-property($transition-property...) { + -webkit-transition-property: $transition-property; + transition-property: $transition-property; +} @mixin transition-delay($transition-delay) { -webkit-transition-delay: $transition-delay; - -moz-transition-delay: $transition-delay; - -o-transition-delay: $transition-delay; transition-delay: $transition-delay; } -@mixin transition-duration($transition-duration) { +@mixin transition-duration($transition-duration...) { -webkit-transition-duration: $transition-duration; - -moz-transition-duration: $transition-duration; - -o-transition-duration: $transition-duration; transition-duration: $transition-duration; } +@mixin transition-transform($transition...) { + -webkit-transition: -webkit-transform $transition; + -moz-transition: -moz-transform $transition; + -o-transition: -o-transform $transition; + transition: transform $transition; +} // Transformations @mixin rotate($degrees) { -webkit-transform: rotate($degrees); - -moz-transform: rotate($degrees); - -ms-transform: rotate($degrees); - -o-transform: rotate($degrees); + -ms-transform: rotate($degrees); // IE9+ transform: rotate($degrees); } @mixin scale($ratio) { -webkit-transform: scale($ratio); - -moz-transform: scale($ratio); - -ms-transform: scale($ratio); - -o-transform: scale($ratio); + -ms-transform: scale($ratio); // IE9+ transform: scale($ratio); } @mixin translate($x, $y) { -webkit-transform: translate($x, $y); - -moz-transform: translate($x, $y); - -ms-transform: translate($x, $y); - -o-transform: translate($x, $y); + -ms-transform: translate($x, $y); // IE9+ transform: translate($x, $y); } @mixin skew($x, $y) { -webkit-transform: skew($x, $y); - -moz-transform: skew($x, $y); - -ms-transform: skewX($x) skewY($y); // See https://github.com/twitter/bootstrap/issues/4885 - -o-transform: skew($x, $y); + -ms-transform: skewX($x) skewY($y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+ transform: skew($x, $y); - -webkit-backface-visibility: hidden; // See https://github.com/twitter/bootstrap/issues/5319 } @mixin translate3d($x, $y, $z) { -webkit-transform: translate3d($x, $y, $z); - -moz-transform: translate3d($x, $y, $z); - -o-transform: translate3d($x, $y, $z); transform: translate3d($x, $y, $z); } +@mixin rotateX($degrees) { + -webkit-transform: rotateX($degrees); + -ms-transform: rotateX($degrees); // IE9+ + transform: rotateX($degrees); +} +@mixin rotateY($degrees) { + -webkit-transform: rotateY($degrees); + -ms-transform: rotateY($degrees); // IE9+ + transform: rotateY($degrees); +} +@mixin perspective($perspective) { + -webkit-perspective: $perspective; + -moz-perspective: $perspective; + perspective: $perspective; +} +@mixin perspective-origin($perspective) { + -webkit-perspective-origin: $perspective; + -moz-perspective-origin: $perspective; + perspective-origin: $perspective; +} +@mixin transform-origin($origin) { + -webkit-transform-origin: $origin; + -moz-transform-origin: $origin; + transform-origin: $origin; +} + +// Animations +@mixin animation($animation) { + -webkit-animation: $animation; + animation: $animation; +} + // Backface visibility // Prevent browsers from flickering when using CSS 3D transforms. -// Default value is `visible`, but can be changed to `hidden -// See git pull https://github.com/dannykeane/bootstrap.git backface-visibility for examples +// Default value is `visible`, but can be changed to `hidden` @mixin backface-visibility($visibility){ -webkit-backface-visibility: $visibility; -moz-backface-visibility: $visibility; backface-visibility: $visibility; } -// Background clipping -// Heads up: FF 3.6 and under need "padding" instead of "padding-box" -@mixin background-clip($clip) { - -webkit-background-clip: $clip; - -moz-background-clip: $clip; - background-clip: $clip; -} - -// Background sizing -@mixin background-size($size) { - -webkit-background-size: $size; - -moz-background-size: $size; - -o-background-size: $size; - background-size: $size; -} - - // Box sizing @mixin box-sizing($boxmodel) { -webkit-box-sizing: $boxmodel; @@ -346,7 +223,7 @@ @mixin user-select($select) { -webkit-user-select: $select; -moz-user-select: $select; - -ms-user-select: $select; + -ms-user-select: $select; // IE10+ -o-user-select: $select; user-select: $select; } @@ -358,13 +235,13 @@ } // CSS3 Content Columns -@mixin content-columns($columnCount, $columnGap: $gridGutterWidth) { - -webkit-column-count: $columnCount; - -moz-column-count: $columnCount; - column-count: $columnCount; - -webkit-column-gap: $columnGap; - -moz-column-gap: $columnGap; - column-gap: $columnGap; +@mixin content-columns($column-count, $column-gap: $grid-gutter-width) { + -webkit-column-count: $column-count; + -moz-column-count: $column-count; + column-count: $column-count; + -webkit-column-gap: $column-gap; + -moz-column-gap: $column-gap; + column-gap: $column-gap; } // Optional hyphenation @@ -372,129 +249,255 @@ word-wrap: break-word; -webkit-hyphens: $mode; -moz-hyphens: $mode; - -ms-hyphens: $mode; + -ms-hyphens: $mode; // IE10+ -o-hyphens: $mode; hyphens: $mode; } // Opacity @mixin opacity($opacity) { - opacity: $opacity / 100; - filter: alpha(opacity=$opacity); + opacity: $opacity; + // IE8 filter + $opacity-ie: ($opacity * 100); + filter: #{alpha(opacity=$opacity-ie)}; } -// BACKGROUNDS +// GRADIENTS // -------------------------------------------------- -// Add an alphatransparency value to any background or border color (via Elyse Holladay) -@mixin translucent-background($color: $white, $alpha: 1) { - background-color: hsla(hue($color), saturation($color), lightness($color), $alpha); + + +// Horizontal gradient, from left to right +// +// Creates two color stops, start and end, by specifying a color and position for each color stop. +// Color stops are not available in IE9 and below. +@mixin gradient-horizontal($start-color: #555, $end-color: #333, $start-percent: 0%, $end-percent: 100%) { + background-image: -webkit-linear-gradient(left, color-stop($start-color $start-percent), color-stop($end-color $end-percent)); // Safari 5.1-6, Chrome 10+ + background-image: linear-gradient(to right, $start-color $start-percent, $end-color $end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+ + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($start-color)}', endColorstr='#{ie-hex-str($end-color)}', GradientType=1); // IE9 and down } -@mixin translucent-border($color: $white, $alpha: 1) { - border-color: hsla(hue($color), saturation($color), lightness($color), $alpha); - @include background-clip(padding-box); +// Vertical gradient, from top to bottom +// +// Creates two color stops, start and end, by specifying a color and position for each color stop. +// Color stops are not available in IE9 and below. +@mixin gradient-vertical($start-color: #555, $end-color: #333, $start-percent: 0%, $end-percent: 100%) { + background-image: -webkit-linear-gradient(top, $start-color $start-percent, $end-color $end-percent); // Safari 5.1-6, Chrome 10+ + background-image: linear-gradient(to bottom, $start-color $start-percent, $end-color $end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+ + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($start-color)}', endColorstr='#{ie-hex-str($end-color)}', GradientType=0); // IE9 and down } -// Gradient Bar Colors for buttons and alerts -@mixin gradientBar($primaryColor, $secondaryColor, $textColor: #fff, $textShadow: 0 -1px 0 rgba(0,0,0,.25)) { - color: $textColor; - text-shadow: $textShadow; - @include gradient-vertical($primaryColor, $secondaryColor); - border-color: $secondaryColor $secondaryColor darken($secondaryColor, 15%); - border-color: rgba(0,0,0,.1) rgba(0,0,0,.1) fade-in(rgba(0,0,0,.1), 0.15); -} - -// Gradients -@mixin gradient-horizontal($startColor: #555, $endColor: #333) { - background-color: $endColor; - background-image: -moz-linear-gradient(left, $startColor, $endColor); // FF 3.6+ - background-image: -webkit-gradient(linear, 0 0, 100% 0, from($startColor), to($endColor)); // Safari 4+, Chrome 2+ - background-image: -webkit-linear-gradient(left, $startColor, $endColor); // Safari 5.1+, Chrome 10+ - background-image: -o-linear-gradient(left, $startColor, $endColor); // Opera 11.10 - background-image: linear-gradient(to right, $startColor, $endColor); // Standard, IE10 +@mixin gradient-directional($start-color: #555, $end-color: #333, $deg: 45deg) { background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($startColor)}', endColorstr='#{ie-hex-str($endColor)}', GradientType=1); // IE9 and down + background-image: -webkit-linear-gradient($deg, $start-color, $end-color); // Safari 5.1-6, Chrome 10+ + background-image: linear-gradient($deg, $start-color, $end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+ } -@mixin gradient-vertical($startColor: #555, $endColor: #333) { - background-color: mix($startColor, $endColor, 60%); - background-image: -moz-linear-gradient(top, $startColor, $endColor); // FF 3.6+ - background-image: -webkit-gradient(linear, 0 0, 0 100%, from($startColor), to($endColor)); // Safari 4+, Chrome 2+ - background-image: -webkit-linear-gradient(top, $startColor, $endColor); // Safari 5.1+, Chrome 10+ - background-image: -o-linear-gradient(top, $startColor, $endColor); // Opera 11.10 - background-image: linear-gradient(to bottom, $startColor, $endColor); // Standard, IE10 - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($startColor)}', endColorstr='#{ie-hex-str($endColor)}', GradientType=0); // IE9 and down -} -@mixin gradient-directional($startColor: #555, $endColor: #333, $deg: 45deg) { - background-color: $endColor; - background-repeat: repeat-x; - background-image: -moz-linear-gradient($deg, $startColor, $endColor); // FF 3.6+ - background-image: -webkit-linear-gradient($deg, $startColor, $endColor); // Safari 5.1+, Chrome 10+ - background-image: -o-linear-gradient($deg, $startColor, $endColor); // Opera 11.10 - background-image: linear-gradient($deg, $startColor, $endColor); // Standard, IE10 -} -@mixin gradient-vertical-three-colors($startColor: #00b3ee, $midColor: #7a43b6, $colorStop: 50%, $endColor: #c3325f) { - background-color: mix($midColor, $endColor, 80%); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from($startColor), color-stop($colorStop, $midColor), to($endColor)); - background-image: -webkit-linear-gradient($startColor, $midColor $colorStop, $endColor); - background-image: -moz-linear-gradient(top, $startColor, $midColor $colorStop, $endColor); - background-image: -o-linear-gradient($startColor, $midColor $colorStop, $endColor); - background-image: linear-gradient($startColor, $midColor $colorStop, $endColor); +@mixin gradient-horizontal-three-colors($start-color: #00b3ee, $mid-color: #7a43b6, $color-stop: 50%, $end-color: #c3325f) { + background-image: -webkit-linear-gradient(left, $start-color, $mid-color $color-stop, $end-color); + background-image: linear-gradient(to right, $start-color, $mid-color $color-stop, $end-color); background-repeat: no-repeat; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($startColor)}', endColorstr='#{ie-hex-str($endColor)}', GradientType=0); // IE9 and down, gets no color-stop at all for proper fallback + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($start-color)}', endColorstr='#{ie-hex-str($end-color)}', GradientType=1); // IE9 and down, gets no color-stop at all for proper fallback } -@mixin gradient-radial($innerColor: #555, $outerColor: #333) { - background-color: $outerColor; - background-image: -webkit-gradient(radial, center center, 0, center center, 460, from($innerColor), to($outerColor)); - background-image: -webkit-radial-gradient(circle, $innerColor, $outerColor); - background-image: -moz-radial-gradient(circle, $innerColor, $outerColor); - background-image: -o-radial-gradient(circle, $innerColor, $outerColor); +@mixin gradient-vertical-three-colors($start-color: #00b3ee, $mid-color: #7a43b6, $color-stop: 50%, $end-color: #c3325f) { + background-image: -webkit-linear-gradient($start-color, $mid-color $color-stop, $end-color); + background-image: linear-gradient($start-color, $mid-color $color-stop, $end-color); + background-repeat: no-repeat; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($start-color)}', endColorstr='#{ie-hex-str($end-color)}', GradientType=0); // IE9 and down, gets no color-stop at all for proper fallback +} +@mixin gradient-radial($inner-color: #555, $outer-color: #333) { + background-image: -webkit-radial-gradient(circle, $inner-color, $outer-color); + background-image: radial-gradient(circle, $inner-color, $outer-color); background-repeat: no-repeat; } -@mixin gradient-striped($color: #555, $angle: 45deg) { - background-color: $color; - background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,.15)), color-stop(.75, rgba(255,255,255,.15)), color-stop(.75, transparent), to(transparent)); - background-image: -webkit-linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); - background-image: -moz-linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); - background-image: linear-gradient($angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); +@mixin gradient-striped($color: rgba(255,255,255,.15), $angle: 45deg) { + background-image: -webkit-linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent); + background-image: linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent); } // Reset filters for IE +// +// When you need to remove a gradient background, do not forget to use this to reset +// the IE filter for IE9 and below. @mixin reset-filter() { - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); } +// Retina images +// +// Short retina mixin for setting background-image and -size + +@mixin img-retina($file-1x, $file-2x, $width-1x, $height-1x) { + background-image: url(if($bootstrap-sass-asset-helper, twbs-image-path("#{$file-1x}"), "#{$file-1x}")); + + @media + only screen and (-webkit-min-device-pixel-ratio: 2), + only screen and ( min--moz-device-pixel-ratio: 2), + only screen and ( -o-min-device-pixel-ratio: 2/1), + only screen and ( min-device-pixel-ratio: 2), + only screen and ( min-resolution: 192dpi), + only screen and ( min-resolution: 2dppx) { + background-image: url(if($bootstrap-sass-asset-helper, twbs-image-path("#{$file-2x}"), "#{$file-2x}")); + background-size: $width-1x $height-1x; + } +} + + +// Responsive image +// +// Keep images from scaling beyond the width of their parents. + +@mixin img-responsive($display: block) { + display: $display; + max-width: 100%; // Part 1: Set a maximum relative to the parent + height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching +} + + // COMPONENT MIXINS // -------------------------------------------------- // Horizontal dividers // ------------------------- // Dividers (basically an hr) within dropdowns and nav lists -@mixin nav-divider($top: #e5e5e5, $bottom: $white) { - // IE7 needs a set width since we gave a height. Restricting just - // to IE7 to keep the 1px left/right space in other browsers. - // It is unclear where IE is getting the extra space that we need - // to negative-margin away, but so it goes. - *width: 100%; +@mixin nav-divider($color: #e5e5e5) { height: 1px; - margin: (($baseLineHeight / 2) - 1) 1px; // 8px 1px - *margin: -5px 0 5px; + margin: (($line-height-computed / 2) - 1) 0; overflow: hidden; - background-color: $top; - border-bottom: 1px solid $bottom; + background-color: $color; +} + +// Panels +// ------------------------- +@mixin panel-variant($border, $heading-text-color, $heading-bg-color, $heading-border) { + border-color: $border; + + & > .panel-heading { + color: $heading-text-color; + background-color: $heading-bg-color; + border-color: $heading-border; + + + .panel-collapse .panel-body { + border-top-color: $border; + } + } + & > .panel-footer { + + .panel-collapse .panel-body { + border-bottom-color: $border; + } + } +} + +// Alerts +// ------------------------- +@mixin alert-variant($background, $border, $text-color) { + background-color: $background; + border-color: $border; + color: $text-color; + + hr { + border-top-color: darken($border, 5%); + } + .alert-link { + color: darken($text-color, 10%); + } +} + +// Tables +// ------------------------- +@mixin table-row-variant($state, $background) { + // Exact selectors below required to override `.table-striped` and prevent + // inheritance to nested tables. + .table { + > thead, + > tbody, + > tfoot { + > tr > .#{$state}, + > .#{$state} > td, + > .#{$state} > th { + background-color: $background; + } + } + } + + // Hover states for `.table-hover` + // Note: this is not available for cells or rows within `thead` or `tfoot`. + .table-hover > tbody { + > tr > .#{$state}:hover, + > .#{$state}:hover > td, + > .#{$state}:hover > th { + background-color: darken($background, 5%); + } + } +} + +// Button variants +// ------------------------- +// Easily pump out default styles, as well as :hover, :focus, :active, +// and disabled options for all buttons +@mixin button-variant($color, $background, $border) { + color: $color; + background-color: $background; + border-color: $border; + + &:hover, + &:focus, + &:active, + &.active { + color: $color; + background-color: darken($background, 8%); + border-color: darken($border, 12%); + } + .open & { &.dropdown-toggle { + color: $color; + background-color: darken($background, 8%); + border-color: darken($border, 12%); + } } + &:active, + &.active { + background-image: none; + } + .open & { &.dropdown-toggle { + background-image: none; + } } + &.disabled, + &[disabled], + fieldset[disabled] & { + &, + &:hover, + &:focus, + &:active, + &.active { + background-color: $background; + border-color: $border; + } + } + + .badge { + color: $background; + background-color: #fff; + } +} + +// Button sizes +// ------------------------- +@mixin button-size($padding-vertical, $padding-horizontal, $font-size, $line-height, $border-radius) { + padding: $padding-vertical $padding-horizontal; + font-size: $font-size; + line-height: $line-height; + border-radius: $border-radius; } // Button backgrounds // ------------------ -@mixin buttonBackground($startColor, $endColor, $textColor: #fff, $textShadow: 0 -1px 0 rgba(0,0,0,.25)) { +@mixin button-background($startColor, $endColor, $textColor: #fff, $textShadow: 0 -1px 0 rgba(0,0,0,.25)) { // gradientBar will set the background to a pleasing blend of these, to support IE<=9 - @include gradientBar($startColor, $endColor, $textColor, $textShadow); + @include gradient-bar($startColor, $endColor, $textColor, $textShadow); *background-color: $endColor; /* Darken IE7 buttons by default so they stand out more given they won't have borders */ @include reset-filter(); @@ -512,14 +515,89 @@ } } +// Gradient Bar Colors for buttons and alerts +@mixin gradient-bar($primaryColor, $secondaryColor, $textColor: #fff, $textShadow: 0 -1px 0 rgba(0,0,0,.25)) { + color: $textColor; + text-shadow: $textShadow; + @include gradient-vertical($primaryColor, $secondaryColor); + border-color: $secondaryColor $secondaryColor darken($secondaryColor, 15%); + border-color: rgba(0,0,0,.1) rgba(0,0,0,.1) fade-in(rgba(0,0,0,.1), 0.15); +} + + +// Pagination +// ------------------------- +@mixin pagination-size($padding-vertical, $padding-horizontal, $font-size, $border-radius) { + > li { + > a, + > span { + padding: $padding-vertical $padding-horizontal; + font-size: $font-size; + } + &:first-child { + > a, + > span { + @include border-left-radius($border-radius); + } + } + &:last-child { + > a, + > span { + @include border-right-radius($border-radius); + } + } + } +} + +// Labels +// ------------------------- +@mixin label-variant($color) { + background-color: $color; + &[href] { + &:hover, + &:focus { + background-color: darken($color, 10%); + } + } +} + // Navbar vertical align // ------------------------- // Vertically center elements in the navbar. -// Example: an element has a height of 30px, so write out `.navbarVerticalAlign(30px);` to calculate the appropriate top margin. -@mixin navbarVerticalAlign($elementHeight) { - margin-top: ($navbarHeight - $elementHeight) / 2; +// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin. +@mixin navbar-vertical-align($element-height) { + margin-top: (($navbar-height - $element-height) / 2); + margin-bottom: (($navbar-height - $element-height) / 2); } +// Progress bars +// ------------------------- +@mixin progress-bar-variant($color) { + background-color: $color; + .progress-striped & { + @include gradient-striped(); + } +} + +// Responsive utilities +// ------------------------- +// More easily include all the states for responsive-utilities.less. +// [converter] $parent hack +@mixin responsive-visibility($parent) { + #{$parent} { display: block !important; } + table#{$parent} { display: table; } + tr#{$parent} { display: table-row !important; } + th#{$parent}, + td#{$parent} { display: table-cell !important; } +} + +// [converter] $parent hack +@mixin responsive-invisibility($parent) { + #{$parent}, + tr#{$parent}, + th#{$parent}, + td#{$parent} { display: none !important; } +} // Grid System @@ -529,162 +607,274 @@ @mixin container-fixed() { margin-right: auto; margin-left: auto; + padding-left: ($grid-gutter-width / 2); + padding-right: ($grid-gutter-width / 2); @include clearfix(); } -// Table columns -@mixin tableColumns($columnSpan: 1) { - float: none; // undo default grid column styles - width: (($gridColumnWidth) * $columnSpan) + ($gridGutterWidth * ($columnSpan - 1)) - 16; // 16 is total padding on left and right of table cells - margin-left: 0; // undo default grid column styles -} - -// Make a Grid -// Use .makeRow and .makeColumn to assign semantic layouts grid system behavior -@mixin makeRow() { - margin-left: $gridGutterWidth * -1; +// Creates a wrapper for a series of columns +@mixin make-row($gutter: $grid-gutter-width) { + margin-left: ($gutter / -2); + margin-right: ($gutter / -2); @include clearfix(); } -@mixin makeColumn($columns: 1, $offset: 0) { + +// Generate the extra small columns +@mixin make-xs-column($columns, $gutter: $grid-gutter-width) { + position: relative; float: left; - margin-left: ($gridColumnWidth * $offset) + ($gridGutterWidth * ($offset - 1)) + ($gridGutterWidth * 2); - width: ($gridColumnWidth * $columns) + ($gridGutterWidth * ($columns - 1)); + width: percentage(($columns / $grid-columns)); + // Prevent columns from collapsing when empty + min-height: 1px; + // Inner gutter via padding + padding-left: ($gutter / 2); + padding-right: ($gutter / 2); } -// The Grid -@mixin grid-core($gridColumnWidth, $gridGutterWidth) { - .row { - margin-left: $gridGutterWidth * -1; - @include clearfix(); - } +// Generate the small columns +@mixin make-sm-column($columns, $gutter: $grid-gutter-width) { + position: relative; + // Prevent columns from collapsing when empty + min-height: 1px; + // Inner gutter via padding + padding-left: ($gutter / 2); + padding-right: ($gutter / 2); - [class*="span"] { + // Calculate width based on number of columns available + @media (min-width: $screen-sm-min) { float: left; - min-height: 1px; // prevent collapsing columns - margin-left: $gridGutterWidth; - } - - // Set the container width, and override it for fixed navbars in media queries - .container, - .navbar-static-top .container, - .navbar-fixed-top .container, - .navbar-fixed-bottom .container { - @include grid-core-span($gridColumns, $gridColumnWidth, $gridGutterWidth); - } - - // generate .spanX and .offsetX - @include grid-core-span-x($gridColumns, $gridColumnWidth, $gridGutterWidth); - @include grid-core-offset-x($gridColumns, $gridColumnWidth, $gridGutterWidth); -} - -@mixin grid-core-span-x($gridColumns, $gridColumnWidth, $gridGutterWidth) { - @while $gridColumns > 0 { - .span#{$gridColumns} { @include grid-core-span($gridColumns, $gridColumnWidth, $gridGutterWidth); } - $gridColumns: $gridColumns - 1; + width: percentage(($columns / $grid-columns)); } } -@mixin grid-core-offset-x($gridColumns, $gridColumnWidth, $gridGutterWidth) { - @while $gridColumns > 0 { - .offset#{$gridColumns} { @include grid-core-offset($gridColumns, $gridColumnWidth, $gridGutterWidth); } - $gridColumns: $gridColumns - 1; +// Generate the small column offsets +@mixin make-sm-column-offset($columns) { + @media (min-width: $screen-sm-min) { + margin-left: percentage(($columns / $grid-columns)); + } +} +@mixin make-sm-column-push($columns) { + @media (min-width: $screen-sm-min) { + left: percentage(($columns / $grid-columns)); + } +} +@mixin make-sm-column-pull($columns) { + @media (min-width: $screen-sm-min) { + right: percentage(($columns / $grid-columns)); } } -@mixin grid-core-span($columns, $gridColumnWidth, $gridGutterWidth) { - width: ($gridColumnWidth * $columns) + ($gridGutterWidth * ($columns - 1)); +// Generate the medium columns +@mixin make-md-column($columns, $gutter: $grid-gutter-width) { + position: relative; + // Prevent columns from collapsing when empty + min-height: 1px; + // Inner gutter via padding + padding-left: ($gutter / 2); + padding-right: ($gutter / 2); + + // Calculate width based on number of columns available + @media (min-width: $screen-md-min) { + float: left; + width: percentage(($columns / $grid-columns)); + } } -@mixin grid-core-offset($columns, $gridColumnWidth, $gridGutterWidth) { - margin-left: ($gridColumnWidth * $columns) + ($gridGutterWidth * ($columns + 1)); +// Generate the medium column offsets +@mixin make-md-column-offset($columns) { + @media (min-width: $screen-md-min) { + margin-left: percentage(($columns / $grid-columns)); + } +} +@mixin make-md-column-push($columns) { + @media (min-width: $screen-md) { + left: percentage(($columns / $grid-columns)); + } +} +@mixin make-md-column-pull($columns) { + @media (min-width: $screen-md-min) { + right: percentage(($columns / $grid-columns)); + } +} + +// Generate the large columns +@mixin make-lg-column($columns, $gutter: $grid-gutter-width) { + position: relative; + // Prevent columns from collapsing when empty + min-height: 1px; + // Inner gutter via padding + padding-left: ($gutter / 2); + padding-right: ($gutter / 2); + + // Calculate width based on number of columns available + @media (min-width: $screen-lg-min) { + float: left; + width: percentage(($columns / $grid-columns)); + } +} + +// Generate the large column offsets +@mixin make-lg-column-offset($columns) { + @media (min-width: $screen-lg-min) { + margin-left: percentage(($columns / $grid-columns)); + } +} +@mixin make-lg-column-push($columns) { + @media (min-width: $screen-lg-min) { + left: percentage(($columns / $grid-columns)); + } +} +@mixin make-lg-column-pull($columns) { + @media (min-width: $screen-lg-min) { + right: percentage(($columns / $grid-columns)); + } } +// Framework grid generation +// +// Used only by Bootstrap to generate the correct number of grid classes given +// any value of `$grid-columns`. -@mixin grid-fluid($fluidGridColumnWidth, $fluidGridGutterWidth) { - .row-fluid { - width: 100%; - @include clearfix(); - [class*="span"] { - @include input-block-level(); - float: left; - margin-left: $fluidGridGutterWidth; - *margin-left: $fluidGridGutterWidth - (.5 / $gridRowWidth * 100px * 1%); +// [converter] Grid converted to use SASS cycles (LESS uses recursive nested mixin defs not supported by SASS) +@mixin make-grid-columns() { + $list: ''; + $i: 1; + $list: ".col-xs-#{$i}, .col-sm-#{$i}, .col-md-#{$i}, .col-lg-#{$i}"; + @for $i from 2 through $grid-columns { + $list: ".col-xs-#{$i}, .col-sm-#{$i}, .col-md-#{$i}, .col-lg-#{$i}, #{$list}"; + } + #{$list} { + position: relative; + // Prevent columns from collapsing when empty + min-height: 1px; + // Inner gutter via padding + padding-left: ($grid-gutter-width / 2); + padding-right: ($grid-gutter-width / 2); + } +} + + +// [converter] Grid converted to use SASS cycles (LESS uses recursive nested mixin defs not supported by SASS) +@mixin make-grid-columns-float($class) { + $list: ''; + $i: 1; + $list: ".col-#{$class}-#{$i}"; + @for $i from 2 through $grid-columns { + $list: ".col-#{$class}-#{$i}, #{$list}"; + } + #{$list} { + float: left; + } +} + + +@mixin calc-grid($index, $class, $type) { + @if ($type == width) and ($index > 0) { + .col-#{$class}-#{$index} { + width: percentage(($index / $grid-columns)); } - [class*="span"]:first-child { - margin-left: 0; + } + @if ($type == push) { + .col-#{$class}-push-#{$index} { + left: percentage(($index / $grid-columns)); } - - // Space grid-sized controls properly if multiple per line - .controls-row [class*="span"] + [class*="span"] { - margin-left: $fluidGridGutterWidth; + } + @if ($type == pull) { + .col-#{$class}-pull-#{$index} { + right: percentage(($index / $grid-columns)); } - - // generate .spanX and .offsetX - @include grid-fluid-span-x($gridColumns, $fluidGridColumnWidth, $fluidGridGutterWidth); - @include grid-fluid-offset-x($gridColumns, $fluidGridColumnWidth, $fluidGridGutterWidth); } -} - -@mixin grid-fluid-span-x($gridColumns, $fluidGridColumnWidth, $fluidGridGutterWidth) { - @while $gridColumns > 0 { - .span#{$gridColumns} { @include grid-fluid-span($gridColumns, $fluidGridColumnWidth, $fluidGridGutterWidth); } - $gridColumns: $gridColumns - 1; - } -} - -@mixin grid-fluid-offset-x($gridColumns, $fluidGridColumnWidth, $fluidGridGutterWidth) { - @while $gridColumns > 0 { - .offset#{$gridColumns} { @include grid-fluid-offset($gridColumns, $fluidGridColumnWidth, $fluidGridGutterWidth); } - .offset#{$gridColumns}:first-child { @include grid-fluid-offset-first-child($gridColumns, $fluidGridColumnWidth, $fluidGridGutterWidth); } - $gridColumns: $gridColumns - 1; - } -} - -@mixin grid-fluid-span($columns, $fluidGridColumnWidth, $fluidGridGutterWidth) { - width: ($fluidGridColumnWidth * $columns) + ($fluidGridGutterWidth * ($columns - 1)); - *width: ($fluidGridColumnWidth * $columns) + ($fluidGridGutterWidth * ($columns - 1)) - (.5 / $gridRowWidth * 100px * 1%); -} - -@mixin grid-fluid-offset($columns, $fluidGridColumnWidth, $fluidGridGutterWidth) { - margin-left: ($fluidGridColumnWidth * $columns) + ($fluidGridGutterWidth * ($columns - 1)) + ($fluidGridGutterWidth * 2); - *margin-left: ($fluidGridColumnWidth * $columns) + ($fluidGridGutterWidth * ($columns - 1)) - (.5 / $gridRowWidth * 100px * 1%) + ($fluidGridGutterWidth * 2) - (.5 / $gridRowWidth * 100px * 1%); -} - -@mixin grid-fluid-offset-first-child($columns, $fluidGridColumnWidth, $fluidGridGutterWidth) { - margin-left: ($fluidGridColumnWidth * $columns) + ($fluidGridGutterWidth * ($columns - 1)) + ($fluidGridGutterWidth); - *margin-left: ($fluidGridColumnWidth * $columns) + ($fluidGridGutterWidth * ($columns - 1)) - (.5 / $gridRowWidth * 100px * 1%) + $fluidGridGutterWidth - (.5 / $gridRowWidth * 100px * 1%); -} - - - -@mixin grid-input($gridColumnWidth, $gridGutterWidth) { - input, - textarea, - .uneditable-input { - margin-left: 0; // override margin-left from core grid system - } - - // Space grid-sized controls properly if multiple per line - .controls-row [class*="span"] + [class*="span"] { - margin-left: $gridGutterWidth; - } - - // generate .spanX - @include grid-input-span-x($gridColumns, $gridColumnWidth, $gridGutterWidth); -} - -@mixin grid-input-span-x($gridColumns, $gridColumnWidth, $gridGutterWidth) { - @while $gridColumns > 0 { - input.span#{$gridColumns}, - textarea.span#{$gridColumns}, - .uneditable-input.span#{$gridColumns} { - @include grid-input-span($gridColumns, $gridColumnWidth, $gridGutterWidth); + @if ($type == offset) { + .col-#{$class}-offset-#{$index} { + margin-left: percentage(($index / $grid-columns)); } - $gridColumns: $gridColumns - 1; } } -@mixin grid-input-span($columns, $gridColumnWidth, $gridGutterWidth) { - width: (($gridColumnWidth) * $columns) + ($gridGutterWidth * ($columns - 1)) - 14; +// [converter] This is defined recursively in LESS, but SASS supports real loops +@mixin make-grid($columns, $class, $type) { + @for $i from 0 through $columns { + @include calc-grid($i, $class, $type); + } +} + + + +// Form validation states +// +// Used in forms.less to generate the form validation CSS for warnings, errors, +// and successes. + +@mixin form-control-validation($text-color: #555, $border-color: #ccc, $background-color: #f5f5f5) { + // Color the label and help text + .help-block, + .control-label, + .radio, + .checkbox, + .radio-inline, + .checkbox-inline { + color: $text-color; + } + // Set the border and box shadow on specific inputs to match + .form-control { + border-color: $border-color; + @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work + &:focus { + border-color: darken($border-color, 10%); + $shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten($border-color, 20%); + @include box-shadow($shadow); + } + } + // Set validation states also for addons + .input-group-addon { + color: $text-color; + border-color: $border-color; + background-color: $background-color; + } +} + +// Form control focus state +// +// Generate a customized focus state and for any input with the specified color, +// which defaults to the `$input-focus-border` variable. +// +// We highly encourage you to not customize the default value, but instead use +// this to tweak colors on an as-needed basis. This aesthetic change is based on +// WebKit's default styles, but applicable to a wider range of browsers. Its +// usability and accessibility should be taken into account with any change. +// +// Example usage: change the default blue border and shadow to white for better +// contrast against a dark gray background. + +@mixin form-control-focus($color: $input-border-focus) { + $color-rgba: rgba(red($color), green($color), blue($color), .6); + &:focus { + border-color: $color; + outline: 0; + @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px $color-rgba); + } +} + +// Form control sizing +// +// Relative text size, padding, and border-radii changes for form controls. For +// horizontal sizing, wrap controls in the predefined grid classes. `