20 |
34 |
21 |
33 |
22 |
32 |
23 |
31 |
24 |
30 |
25 |
29 |
26 | {{{content}}}
27 |
28 | ├── CNAME ├── .gitignore ├── SUMMARY.md ├── images ├── cat.gif ├── awesome.jpg ├── console.gif ├── console.png ├── yarnify.png ├── bash-sleep.png ├── customers1.png ├── customers2.png ├── customers3.png ├── customers4.png ├── customers5.jpg ├── dealwithit.gif ├── times-loop.png ├── underscore.gif ├── array-access.png ├── array-lookup.png ├── console-replace.gif ├── console-replace.png ├── console-strings.gif ├── console-strings.png ├── object-lookup.png ├── substack-cats.png ├── array-push-length.png ├── console-variables.gif ├── console-variables.png ├── underscore-first.png ├── underscore-source.png ├── custom-function-call.gif ├── custom-function-call.png ├── custom-function-manually.gif ├── custom-function-manually.png ├── custom-function-no-return.gif ├── custom-function-no-return.png ├── custom-function-console-log.gif ├── custom-function-console-log.png ├── custom-function-call-variable.gif └── custom-function-call-variable.png ├── cover_jsforcats.psd ├── javascript-for-cats.pdf ├── params.json ├── render.js ├── package.json ├── index.mustache ├── javascripts ├── generic.js ├── javascript.js ├── marked.js └── rainbow.js ├── stylesheets ├── rainbow.github.css └── style.css └── README.md /CNAME: -------------------------------------------------------------------------------- 1 | jsforcats.com -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * The Console 4 | 5 | -------------------------------------------------------------------------------- /images/cat.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/cat.gif -------------------------------------------------------------------------------- /images/awesome.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/awesome.jpg -------------------------------------------------------------------------------- /images/console.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/console.gif -------------------------------------------------------------------------------- /images/console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/console.png -------------------------------------------------------------------------------- /images/yarnify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/yarnify.png -------------------------------------------------------------------------------- /cover_jsforcats.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/cover_jsforcats.psd -------------------------------------------------------------------------------- /images/bash-sleep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/bash-sleep.png -------------------------------------------------------------------------------- /images/customers1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/customers1.png -------------------------------------------------------------------------------- /images/customers2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/customers2.png -------------------------------------------------------------------------------- /images/customers3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/customers3.png -------------------------------------------------------------------------------- /images/customers4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/customers4.png -------------------------------------------------------------------------------- /images/customers5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/customers5.jpg -------------------------------------------------------------------------------- /images/dealwithit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/dealwithit.gif -------------------------------------------------------------------------------- /images/times-loop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/times-loop.png -------------------------------------------------------------------------------- /images/underscore.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/underscore.gif -------------------------------------------------------------------------------- /images/array-access.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/array-access.png -------------------------------------------------------------------------------- /images/array-lookup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/array-lookup.png -------------------------------------------------------------------------------- /javascript-for-cats.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/javascript-for-cats.pdf -------------------------------------------------------------------------------- /images/console-replace.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/console-replace.gif -------------------------------------------------------------------------------- /images/console-replace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/console-replace.png -------------------------------------------------------------------------------- /images/console-strings.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/console-strings.gif -------------------------------------------------------------------------------- /images/console-strings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/console-strings.png -------------------------------------------------------------------------------- /images/object-lookup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/object-lookup.png -------------------------------------------------------------------------------- /images/substack-cats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/substack-cats.png -------------------------------------------------------------------------------- /images/array-push-length.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/array-push-length.png -------------------------------------------------------------------------------- /images/console-variables.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/console-variables.gif -------------------------------------------------------------------------------- /images/console-variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/console-variables.png -------------------------------------------------------------------------------- /images/underscore-first.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/underscore-first.png -------------------------------------------------------------------------------- /images/underscore-source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/underscore-source.png -------------------------------------------------------------------------------- /images/custom-function-call.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/custom-function-call.gif -------------------------------------------------------------------------------- /images/custom-function-call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/custom-function-call.png -------------------------------------------------------------------------------- /images/custom-function-manually.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/custom-function-manually.gif -------------------------------------------------------------------------------- /images/custom-function-manually.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/custom-function-manually.png -------------------------------------------------------------------------------- /images/custom-function-no-return.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/custom-function-no-return.gif -------------------------------------------------------------------------------- /images/custom-function-no-return.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/custom-function-no-return.png -------------------------------------------------------------------------------- /images/custom-function-console-log.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/custom-function-console-log.gif -------------------------------------------------------------------------------- /images/custom-function-console-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/custom-function-console-log.png -------------------------------------------------------------------------------- /images/custom-function-call-variable.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/custom-function-call-variable.gif -------------------------------------------------------------------------------- /images/custom-function-call-variable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/max-mapper/javascript-for-cats/HEAD/images/custom-function-call-variable.png -------------------------------------------------------------------------------- /params.json: -------------------------------------------------------------------------------- 1 | {"tagline":"information about javascript programming","google":"UA-34180924-1","note":"Don't delete this file! It's used internally to help with page regeneration.","body":"###programming in javascript","name":"jsforcats"} -------------------------------------------------------------------------------- /render.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var marked = require('marked') 3 | var mustache = require('mustache') 4 | 5 | var template = fs.readFileSync('./index.mustache').toString() 6 | var readme = fs.readFileSync('./README.md').toString() 7 | fs.writeFileSync('./index.html', mustache.render(template, {content: marked(readme)})) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "javascript-for-cats", 3 | "version": "1.0.0", 4 | "description": "javascript for cats", 5 | "main": "build.js", 6 | "scripts": { 7 | "render": "node render.js", 8 | "deploy": "gh-pages-deploy" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/maxogden/javascript-for-cats.git" 13 | }, 14 | "gh-pages-deploy": { 15 | "prep": [ 16 | "render" 17 | ], 18 | "noprompt": "true" 19 | }, 20 | "author": "max ogden", 21 | "license": "BSD", 22 | "bugs": { 23 | "url": "https://github.com/maxogden/javascript-for-cats/issues" 24 | }, 25 | "homepage": "https://github.com/maxogden/javascript-for-cats", 26 | "dependencies": { 27 | "marked": "^0.3.2", 28 | "mustache": "^1.0.0" 29 | }, 30 | "devDependencies": { 31 | "gh-pages-deploy": "^0.1.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /index.mustache: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |'
459 | + escape(cap[2], true)
460 | + '';
461 | continue;
462 | }
463 |
464 | // br
465 | if (cap = inline.br.exec(src)) {
466 | src = src.substring(cap[0].length);
467 | out += ''
558 | + token.text
559 | + '\n';
560 | }
561 | case 'blockquote_start': {
562 | var body = '';
563 |
564 | while (next().type !== 'blockquote_end') {
565 | body += tok();
566 | }
567 |
568 | return '\n' 569 | + body 570 | + '\n'; 571 | } 572 | case 'list_start': { 573 | var type = token.ordered ? 'ol' : 'ul' 574 | , body = ''; 575 | 576 | while (next().type !== 'list_end') { 577 | body += tok(); 578 | } 579 | 580 | return '<' 581 | + type 582 | + '>\n' 583 | + body 584 | + '' 585 | + type 586 | + '>\n'; 587 | } 588 | case 'list_item_start': { 589 | var body = ''; 590 | 591 | while (next().type !== 'list_item_end') { 592 | body += token.type === 'text' 593 | ? parseText() 594 | : tok(); 595 | } 596 | 597 | return '
' 622 | + inline.lexer(token.text) 623 | + '
\n'; 624 | } 625 | case 'text': { 626 | return '' 627 | + parseText() 628 | + '
\n'; 629 | } 630 | } 631 | } 632 | 633 | function parseText() { 634 | var body = token.text 635 | , top; 636 | 637 | while ((top = tokens[tokens.length-1]) 638 | && top.type === 'text') { 639 | body += '\n' + next().text; 640 | } 641 | 642 | return inline.lexer(body); 643 | } 644 | 645 | function parse(src) { 646 | tokens = src.reverse(); 647 | 648 | var out = ''; 649 | while (next()) { 650 | out += tok(); 651 | } 652 | 653 | tokens = null; 654 | token = null; 655 | 656 | return out; 657 | } 658 | 659 | /** 660 | * Helpers 661 | */ 662 | 663 | function escape(html, encode) { 664 | return html 665 | .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&') 666 | .replace(//g, '>') 668 | .replace(/"/g, '"') 669 | .replace(/'/g, '''); 670 | } 671 | 672 | function mangle(text) { 673 | var out = '' 674 | , l = text.length 675 | , i = 0 676 | , ch; 677 | 678 | for (; i < l; i++) { 679 | ch = text.charCodeAt(i); 680 | if (Math.random() > 0.5) { 681 | ch = 'x' + ch.toString(16); 682 | } 683 | out += '' + ch + ';'; 684 | } 685 | 686 | return out; 687 | } 688 | 689 | function tag() { 690 | var tag = '(?!(?:' 691 | + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code' 692 | + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo' 693 | + '|span|br|wbr|ins|del|img)\\b)\\w+'; 694 | 695 | return tag; 696 | } 697 | 698 | function replace(regex, opt) { 699 | regex = regex.source; 700 | opt = opt || ''; 701 | return function self(name, val) { 702 | if (!name) return new RegExp(regex, opt); 703 | regex = regex.replace(name, val.source || val); 704 | return self; 705 | }; 706 | } 707 | 708 | function noop() {} 709 | noop.exec = noop; 710 | 711 | /** 712 | * Marked 713 | */ 714 | 715 | function marked(src, opt) { 716 | setOptions(opt); 717 | return parse(block.lexer(src)); 718 | } 719 | 720 | /** 721 | * Options 722 | */ 723 | 724 | var options 725 | , defaults; 726 | 727 | function setOptions(opt) { 728 | if (!opt) opt = defaults; 729 | if (options === opt) return; 730 | options = opt; 731 | 732 | if (options.gfm) { 733 | block.fences = block.gfm.fences; 734 | block.paragraph = block.gfm.paragraph; 735 | inline.text = inline.gfm.text; 736 | inline.url = inline.gfm.url; 737 | } else { 738 | block.fences = block.normal.fences; 739 | block.paragraph = block.normal.paragraph; 740 | inline.text = inline.normal.text; 741 | inline.url = inline.normal.url; 742 | } 743 | 744 | if (options.pedantic) { 745 | inline.em = inline.pedantic.em; 746 | inline.strong = inline.pedantic.strong; 747 | } else { 748 | inline.em = inline.normal.em; 749 | inline.strong = inline.normal.strong; 750 | } 751 | } 752 | 753 | marked.options = 754 | marked.setOptions = function(opt) { 755 | defaults = opt; 756 | setOptions(opt); 757 | return marked; 758 | }; 759 | 760 | marked.setOptions({ 761 | gfm: true, 762 | pedantic: false, 763 | sanitize: false, 764 | highlight: null 765 | }); 766 | 767 | /** 768 | * Expose 769 | */ 770 | 771 | marked.parser = function(src, opt) { 772 | setOptions(opt); 773 | return parse(src); 774 | }; 775 | 776 | marked.lexer = function(src, opt) { 777 | setOptions(opt); 778 | return block.lexer(src); 779 | }; 780 | 781 | marked.parse = marked; 782 | 783 | if (typeof module !== 'undefined') { 784 | module.exports = marked; 785 | } else { 786 | this.marked = marked; 787 | } 788 | 789 | }).call(function() { 790 | return this || (typeof window !== 'undefined' ? window : global); 791 | }()); 792 | -------------------------------------------------------------------------------- /javascripts/rainbow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Craig Campbell 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * Rainbow is a simple code syntax highlighter 17 | * 18 | * @preserve @version 1.1.8 19 | * @url rainbowco.de 20 | */ 21 | window['Rainbow'] = (function() { 22 | 23 | /** 24 | * array of replacements to process at the end 25 | * 26 | * @type {Object} 27 | */ 28 | var replacements = {}, 29 | 30 | /** 31 | * an array of start and end positions of blocks to be replaced 32 | * 33 | * @type {Object} 34 | */ 35 | replacement_positions = {}, 36 | 37 | /** 38 | * an array of the language patterns specified for each language 39 | * 40 | * @type {Object} 41 | */ 42 | language_patterns = {}, 43 | 44 | /** 45 | * an array of languages and whether they should bypass the default patterns 46 | * 47 | * @type {Object} 48 | */ 49 | bypass_defaults = {}, 50 | 51 | /** 52 | * processing level 53 | * 54 | * replacements are stored at this level so if there is a sub block of code 55 | * (for example php inside of html) it runs at a different level 56 | * 57 | * @type {number} 58 | */ 59 | CURRENT_LEVEL = 0, 60 | 61 | /** 62 | * constant used to refer to the default language 63 | * 64 | * @type {number} 65 | */ 66 | DEFAULT_LANGUAGE = 0, 67 | 68 | /** 69 | * used as counters so we can selectively call setTimeout 70 | * after processing a certain number of matches/replacements 71 | * 72 | * @type {number} 73 | */ 74 | match_counter = 0, 75 | 76 | /** 77 | * @type {number} 78 | */ 79 | replacement_counter = 0, 80 | 81 | /** 82 | * @type {null|string} 83 | */ 84 | global_class, 85 | 86 | /** 87 | * @type {null|Function} 88 | */ 89 | onHighlight; 90 | 91 | /** 92 | * cross browser get attribute for an element 93 | * 94 | * @see http://stackoverflow.com/questions/3755227/cross-browser-javascript-getattribute-method 95 | * 96 | * @param {Node} el 97 | * @param {string} attr attribute you are trying to get 98 | * @returns {string|number} 99 | */ 100 | function _attr(el, attr, attrs, i) { 101 | var result = (el.getAttribute && el.getAttribute(attr)) || 0; 102 | 103 | if (!result) { 104 | attrs = el.attributes; 105 | 106 | for (i = 0; i < attrs.length; ++i) { 107 | if (attrs[i].nodeName === attr) { 108 | return attrs[i].nodeValue; 109 | } 110 | } 111 | } 112 | 113 | return result; 114 | } 115 | 116 | /** 117 | * adds a class to a given code block 118 | * 119 | * @param {Element} el 120 | * @param {string} class_name class name to add 121 | * @returns void 122 | */ 123 | function _addClass(el, class_name) { 124 | el.className += el.className ? ' ' + class_name : class_name; 125 | } 126 | 127 | /** 128 | * checks if a block has a given class 129 | * 130 | * @param {Element} el 131 | * @param {string} class_name class name to check for 132 | * @returns {boolean} 133 | */ 134 | function _hasClass(el, class_name) { 135 | return (' ' + el.className + ' ').indexOf(' ' + class_name + ' ') > -1; 136 | } 137 | 138 | /** 139 | * gets the language for this block of code 140 | * 141 | * @param {Element} block 142 | * @returns {string|null} 143 | */ 144 | function _getLanguageForBlock(block) { 145 | 146 | // if this doesn't have a language but the parent does then use that 147 | // this means if for example you have:
148 | // with a bunch of blocks inside then you do not have
149 | // to specify the language for each block
150 | var language = _attr(block, 'data-language') || _attr(block.parentNode, 'data-language');
151 |
152 | // this adds support for specifying language via a css class
153 | // you can use the Google Code Prettify style:
154 | // or the HTML5 style:
155 | if (!language) {
156 | var pattern = /\blang(?:uage)?-(\w+)/,
157 | match = block.className.match(pattern) || block.parentNode.className.match(pattern);
158 |
159 | if (match) {
160 | language = match[1];
161 | }
162 | }
163 |
164 | return language;
165 | }
166 |
167 | /**
168 | * makes sure html entities are always used for tags
169 | *
170 | * @param {string} code
171 | * @returns {string}
172 | */
173 | function _htmlEntities(code) {
174 | return code.replace(//g, '>').replace(/&(?![\w\#]+;)/g, '&');
175 | }
176 |
177 | /**
178 | * determines if a new match intersects with an existing one
179 | *
180 | * @param {number} start1 start position of existing match
181 | * @param {number} end1 end position of existing match
182 | * @param {number} start2 start position of new match
183 | * @param {number} end2 end position of new match
184 | * @returns {boolean}
185 | */
186 | function _intersects(start1, end1, start2, end2) {
187 | if (start2 >= start1 && start2 < end1) {
188 | return true;
189 | }
190 |
191 | return end2 > start1 && end2 < end1;
192 | }
193 |
194 | /**
195 | * determines if two different matches have complete overlap with each other
196 | *
197 | * @param {number} start1 start position of existing match
198 | * @param {number} end1 end position of existing match
199 | * @param {number} start2 start position of new match
200 | * @param {number} end2 end position of new match
201 | * @returns {boolean}
202 | */
203 | function _hasCompleteOverlap(start1, end1, start2, end2) {
204 |
205 | // if the starting and end positions are exactly the same
206 | // then the first one should stay and this one should be ignored
207 | if (start2 == start1 && end2 == end1) {
208 | return false;
209 | }
210 |
211 | return start2 <= start1 && end2 >= end1;
212 | }
213 |
214 | /**
215 | * determines if the match passed in falls inside of an existing match
216 | * this prevents a regex pattern from matching inside of a bigger pattern
217 | *
218 | * @param {number} start - start position of new match
219 | * @param {number} end - end position of new match
220 | * @returns {boolean}
221 | */
222 | function _matchIsInsideOtherMatch(start, end) {
223 | for (var key in replacement_positions[CURRENT_LEVEL]) {
224 | key = parseInt(key, 10);
225 |
226 | // if this block completely overlaps with another block
227 | // then we should remove the other block and return false
228 | if (_hasCompleteOverlap(key, replacement_positions[CURRENT_LEVEL][key], start, end)) {
229 | delete replacement_positions[CURRENT_LEVEL][key];
230 | delete replacements[CURRENT_LEVEL][key];
231 | }
232 |
233 | if (_intersects(key, replacement_positions[CURRENT_LEVEL][key], start, end)) {
234 | return true;
235 | }
236 | }
237 |
238 | return false;
239 | }
240 |
241 | /**
242 | * takes a string of code and wraps it in a span tag based on the name
243 | *
244 | * @param {string} name name of the pattern (ie keyword.regex)
245 | * @param {string} code block of code to wrap
246 | * @returns {string}
247 | */
248 | function _wrapCodeInSpan(name, code) {
249 | return '' + code + '';
250 | }
251 |
252 | /**
253 | * finds out the position of group match for a regular expression
254 | *
255 | * @see http://stackoverflow.com/questions/1985594/how-to-find-index-of-groups-in-match
256 | *
257 | * @param {Object} match
258 | * @param {number} group_number
259 | * @returns {number}
260 | */
261 | function _indexOfGroup(match, group_number) {
262 | var index = 0,
263 | i;
264 |
265 | for (i = 1; i < group_number; ++i) {
266 | if (match[i]) {
267 | index += match[i].length;
268 | }
269 | }
270 |
271 | return index;
272 | }
273 |
274 | /**
275 | * matches a regex pattern against a block of code
276 | * finds all matches that should be processed and stores the positions
277 | * of where they should be replaced within the string
278 | *
279 | * this is where pretty much all the work is done but it should not
280 | * be called directly
281 | *
282 | * @param {RegExp} pattern
283 | * @param {string} code
284 | * @returns void
285 | */
286 | function _processPattern(regex, pattern, code, callback)
287 | {
288 | var match = regex.exec(code);
289 |
290 | if (!match) {
291 | return callback();
292 | }
293 |
294 | ++match_counter;
295 |
296 | // treat match 0 the same way as name
297 | if (!pattern['name'] && typeof pattern['matches'][0] == 'string') {
298 | pattern['name'] = pattern['matches'][0];
299 | delete pattern['matches'][0];
300 | }
301 |
302 | var replacement = match[0],
303 | start_pos = match.index,
304 | end_pos = match[0].length + start_pos,
305 |
306 | /**
307 | * callback to process the next match of this pattern
308 | */
309 | processNext = function() {
310 | var nextCall = function() {
311 | _processPattern(regex, pattern, code, callback);
312 | };
313 |
314 | // every 100 items we process let's call set timeout
315 | // to let the ui breathe a little
316 | return match_counter % 100 > 0 ? nextCall() : setTimeout(nextCall, 0);
317 | };
318 |
319 | // if this is not a child match and it falls inside of another
320 | // match that already happened we should skip it and continue processing
321 | if (_matchIsInsideOtherMatch(start_pos, end_pos)) {
322 | return processNext();
323 | }
324 |
325 | /**
326 | * callback for when a match was successfully processed
327 | *
328 | * @param {string} replacement
329 | * @returns void
330 | */
331 | var onMatchSuccess = function(replacement) {
332 | // if this match has a name then wrap it in a span tag
333 | if (pattern['name']) {
334 | replacement = _wrapCodeInSpan(pattern['name'], replacement);
335 | }
336 |
337 | // console.log('LEVEL', CURRENT_LEVEL, 'replace', match[0], 'with', replacement, 'at position', start_pos, 'to', end_pos);
338 |
339 | // store what needs to be replaced with what at this position
340 | if (!replacements[CURRENT_LEVEL]) {
341 | replacements[CURRENT_LEVEL] = {};
342 | replacement_positions[CURRENT_LEVEL] = {};
343 | }
344 |
345 | replacements[CURRENT_LEVEL][start_pos] = {
346 | 'replace': match[0],
347 | 'with': replacement
348 | };
349 |
350 | // store the range of this match so we can use it for comparisons
351 | // with other matches later
352 | replacement_positions[CURRENT_LEVEL][start_pos] = end_pos;
353 |
354 | // process the next match
355 | processNext();
356 | },
357 |
358 | // if this pattern has sub matches for different groups in the regex
359 | // then we should process them one at a time by rerunning them through
360 | // this function to generate the new replacement
361 | //
362 | // we run through them backwards because the match position of earlier
363 | // matches will not change depending on what gets replaced in later
364 | // matches
365 | group_keys = keys(pattern['matches']),
366 |
367 | /**
368 | * callback for processing a sub group
369 | *
370 | * @param {number} i
371 | * @param {Array} group_keys
372 | * @param {Function} callback
373 | */
374 | processGroup = function(i, group_keys, callback) {
375 | if (i >= group_keys.length) {
376 | return callback(replacement);
377 | }
378 |
379 | var processNextGroup = function() {
380 | processGroup(++i, group_keys, callback);
381 | },
382 | block = match[group_keys[i]];
383 |
384 | // if there is no match here then move on
385 | if (!block) {
386 | return processNextGroup();
387 | }
388 |
389 | var group = pattern['matches'][group_keys[i]],
390 | language = group['language'],
391 |
392 | /**
393 | * process group is what group we should use to actually process
394 | * this match group
395 | *
396 | * for example if the subgroup pattern looks like this
397 | * 2: {
398 | * 'name': 'keyword',
399 | * 'pattern': /true/g
400 | * }
401 | *
402 | * then we use that as is, but if it looks like this
403 | *
404 | * 2: {
405 | * 'name': 'keyword',
406 | * 'matches': {
407 | * 'name': 'special',
408 | * 'pattern': /whatever/g
409 | * }
410 | * }
411 | *
412 | * we treat the 'matches' part as the pattern and keep
413 | * the name around to wrap it with later
414 | */
415 | process_group = group['name'] && group['matches'] ? group['matches'] : group,
416 |
417 | /**
418 | * takes the code block matched at this group, replaces it
419 | * with the highlighted block, and optionally wraps it with
420 | * a span with a name
421 | *
422 | * @param {string} block
423 | * @param {string} replace_block
424 | * @param {string|null} match_name
425 | */
426 | _replaceAndContinue = function(block, replace_block, match_name) {
427 | replacement = _replaceAtPosition(_indexOfGroup(match, group_keys[i]), block, match_name ? _wrapCodeInSpan(match_name, replace_block) : replace_block, replacement);
428 | processNextGroup();
429 | };
430 |
431 | // if this is a sublanguage go and process the block using that language
432 | if (language) {
433 | return _highlightBlockForLanguage(block, language, function(code) {
434 | _replaceAndContinue(block, code);
435 | });
436 | }
437 |
438 | // if this is a string then this match is directly mapped to selector
439 | // so all we have to do is wrap it in a span and continue
440 | if (typeof group === 'string') {
441 | return _replaceAndContinue(block, block, group);
442 | }
443 |
444 | // the process group can be a single pattern or an array of patterns
445 | // _processCodeWithPatterns always expects an array so we convert it here
446 | _processCodeWithPatterns(block, process_group.length ? process_group : [process_group], function(code) {
447 | _replaceAndContinue(block, code, group['matches'] ? group['name'] : 0);
448 | });
449 | };
450 |
451 | processGroup(0, group_keys, onMatchSuccess);
452 | }
453 |
454 | /**
455 | * should a language bypass the default patterns?
456 | *
457 | * if you call Rainbow.extend() and pass true as the third argument
458 | * it will bypass the defaults
459 | */
460 | function _bypassDefaultPatterns(language)
461 | {
462 | return bypass_defaults[language];
463 | }
464 |
465 | /**
466 | * returns a list of regex patterns for this language
467 | *
468 | * @param {string} language
469 | * @returns {Array}
470 | */
471 | function _getPatternsForLanguage(language) {
472 | var patterns = language_patterns[language] || [],
473 | default_patterns = language_patterns[DEFAULT_LANGUAGE] || [];
474 |
475 | return _bypassDefaultPatterns(language) ? patterns : patterns.concat(default_patterns);
476 | }
477 |
478 | /**
479 | * substring replace call to replace part of a string at a certain position
480 | *
481 | * @param {number} position the position where the replacement should happen
482 | * @param {string} replace the text we want to replace
483 | * @param {string} replace_with the text we want to replace it with
484 | * @param {string} code the code we are doing the replacing in
485 | * @returns {string}
486 | */
487 | function _replaceAtPosition(position, replace, replace_with, code) {
488 | var sub_string = code.substr(position);
489 | return code.substr(0, position) + sub_string.replace(replace, replace_with);
490 | }
491 |
492 | /**
493 | * sorts an object by index descending
494 | *
495 | * @param {Object} object
496 | * @return {Array}
497 | */
498 | function keys(object) {
499 | var locations = [],
500 | replacement,
501 | pos;
502 |
503 | for(var location in object) {
504 | if (object.hasOwnProperty(location)) {
505 | locations.push(location);
506 | }
507 | }
508 |
509 | // numeric descending
510 | return locations.sort(function(a, b) {
511 | return b - a;
512 | });
513 | }
514 |
515 | /**
516 | * processes a block of code using specified patterns
517 | *
518 | * @param {string} code
519 | * @param {Array} patterns
520 | * @returns void
521 | */
522 | function _processCodeWithPatterns(code, patterns, callback)
523 | {
524 | // we have to increase the level here so that the
525 | // replacements will not conflict with each other when
526 | // processing sub blocks of code
527 | ++CURRENT_LEVEL;
528 |
529 | // patterns are processed one at a time through this function
530 | function _workOnPatterns(patterns, i)
531 | {
532 | // still have patterns to process, keep going
533 | if (i < patterns.length) {
534 | return _processPattern(patterns[i]['pattern'], patterns[i], code, function() {
535 | _workOnPatterns(patterns, ++i);
536 | });
537 | }
538 |
539 | // we are done processing the patterns
540 | // process the replacements and update the DOM
541 | _processReplacements(code, function(code) {
542 |
543 | // when we are done processing replacements
544 | // we are done at this level so we can go back down
545 | delete replacements[CURRENT_LEVEL];
546 | delete replacement_positions[CURRENT_LEVEL];
547 | --CURRENT_LEVEL;
548 | callback(code);
549 | });
550 | }
551 |
552 | _workOnPatterns(patterns, 0);
553 | }
554 |
555 | /**
556 | * process replacements in the string of code to actually update the markup
557 | *
558 | * @param {string} code the code to process replacements in
559 | * @param {Function} onComplete what to do when we are done processing
560 | * @returns void
561 | */
562 | function _processReplacements(code, onComplete) {
563 |
564 | /**
565 | * processes a single replacement
566 | *
567 | * @param {string} code
568 | * @param {Array} positions
569 | * @param {number} i
570 | * @param {Function} onComplete
571 | * @returns void
572 | */
573 | function _processReplacement(code, positions, i, onComplete) {
574 | if (i < positions.length) {
575 | ++replacement_counter;
576 | var pos = positions[i],
577 | replacement = replacements[CURRENT_LEVEL][pos];
578 | code = _replaceAtPosition(pos, replacement['replace'], replacement['with'], code);
579 |
580 | // process next function
581 | var next = function() {
582 | _processReplacement(code, positions, ++i, onComplete);
583 | };
584 |
585 | // use a timeout every 250 to not freeze up the UI
586 | return replacement_counter % 250 > 0 ? next() : setTimeout(next, 0);
587 | }
588 |
589 | onComplete(code);
590 | }
591 |
592 | var string_positions = keys(replacements[CURRENT_LEVEL]);
593 | _processReplacement(code, string_positions, 0, onComplete);
594 | }
595 |
596 | /**
597 | * takes a string of code and highlights it according to the language specified
598 | *
599 | * @param {string} code
600 | * @param {string} language
601 | * @param {Function} onComplete
602 | * @returns void
603 | */
604 | function _highlightBlockForLanguage(code, language, onComplete) {
605 | var patterns = _getPatternsForLanguage(language);
606 | _processCodeWithPatterns(_htmlEntities(code), patterns, onComplete);
607 | }
608 |
609 | /**
610 | * highlight an individual code block
611 | *
612 | * @param {Array} code_blocks
613 | * @param {number} i
614 | * @returns void
615 | */
616 | function _highlightCodeBlock(code_blocks, i, onComplete) {
617 | if (i < code_blocks.length) {
618 | var block = code_blocks[i],
619 | language = _getLanguageForBlock(block);
620 |
621 | if (!_hasClass(block, 'rainbow') && language) {
622 | language = language.toLowerCase();
623 |
624 | _addClass(block, 'rainbow');
625 |
626 | return _highlightBlockForLanguage(block.innerHTML, language, function(code) {
627 | block.innerHTML = code;
628 |
629 | // reset the replacement arrays
630 | replacements = {};
631 | replacement_positions = {};
632 |
633 | // if you have a listener attached tell it that this block is now highlighted
634 | if (onHighlight) {
635 | onHighlight(block, language);
636 | }
637 |
638 | // process the next block
639 | setTimeout(function() {
640 | _highlightCodeBlock(code_blocks, ++i, onComplete);
641 | }, 0);
642 | });
643 | }
644 | return _highlightCodeBlock(code_blocks, ++i, onComplete);
645 | }
646 |
647 | if (onComplete) {
648 | onComplete();
649 | }
650 | }
651 |
652 | /**
653 | * start highlighting all the code blocks
654 | *
655 | * @returns void
656 | */
657 | function _highlight(node, onComplete) {
658 |
659 | // the first argument can be an Event or a DOM Element
660 | // I was originally checking instanceof Event but that makes it break
661 | // when using mootools
662 | //
663 | // @see https://github.com/ccampbell/rainbow/issues/32
664 | //
665 | node = node && typeof node.getElementsByTagName == 'function' ? node : document;
666 |
667 | var pre_blocks = node.getElementsByTagName('pre'),
668 | code_blocks = node.getElementsByTagName('code'),
669 | i,
670 | final_blocks = [];
671 |
672 | // @see http://stackoverflow.com/questions/2735067/how-to-convert-a-dom-node-list-to-an-array-in-javascript
673 | // we are going to process all blocks
674 | for (i = 0; i < code_blocks.length; ++i) {
675 | final_blocks.push(code_blocks[i]);
676 | }
677 |
678 | // loop through the pre blocks to see which ones we should add
679 | for (i = 0; i < pre_blocks.length; ++i) {
680 |
681 | // if the pre block has no code blocks then process it directly
682 | if (!pre_blocks[i].getElementsByTagName('code').length) {
683 | final_blocks.push(pre_blocks[i]);
684 | }
685 | }
686 |
687 | _highlightCodeBlock(final_blocks, 0, onComplete);
688 | }
689 |
690 | /**
691 | * public methods
692 | */
693 | return {
694 |
695 | /**
696 | * extends the language pattern matches
697 | *
698 | * @param {*} language name of language
699 | * @param {*} patterns array of patterns to add on
700 | * @param {boolean|null} bypass if true this will bypass the default language patterns
701 | */
702 | extend: function(language, patterns, bypass) {
703 |
704 | // if there is only one argument then we assume that we want to
705 | // extend the default language rules
706 | if (arguments.length == 1) {
707 | patterns = language;
708 | language = DEFAULT_LANGUAGE;
709 | }
710 |
711 | bypass_defaults[language] = bypass;
712 | language_patterns[language] = patterns.concat(language_patterns[language] || []);
713 | },
714 |
715 | /**
716 | * call back to let you do stuff in your app after a piece of code has been highlighted
717 | *
718 | * @param {Function} callback
719 | */
720 | onHighlight: function(callback) {
721 | onHighlight = callback;
722 | },
723 |
724 | /**
725 | * method to set a global class that will be applied to all spans
726 | *
727 | * @param {string} class_name
728 | */
729 | addClass: function(class_name) {
730 | global_class = class_name;
731 | },
732 |
733 | /**
734 | * starts the magic rainbow
735 | *
736 | * @returns void
737 | */
738 | color: function() {
739 |
740 | // if you want to straight up highlight a string you can pass the string of code,
741 | // the language, and a callback function
742 | if (typeof arguments[0] == 'string') {
743 | return _highlightBlockForLanguage(arguments[0], arguments[1], arguments[2]);
744 | }
745 |
746 | // if you pass a callback function then we rerun the color function
747 | // on all the code and call the callback function on complete
748 | if (typeof arguments[0] == 'function') {
749 | return _highlight(0, arguments[0]);
750 | }
751 |
752 | // otherwise we use whatever node you passed in with an optional
753 | // callback function as the second parameter
754 | _highlight(arguments[0], arguments[1]);
755 | }
756 | };
757 | }) ();
758 |
759 | /**
760 | * adds event listener to start highlighting
761 | */
762 | (function() {
763 | if (window.addEventListener) {
764 | return window.addEventListener('load', Rainbow.color, false);
765 | }
766 | window.attachEvent('onload', Rainbow.color);
767 | }) ();
768 |
769 | // When using Google closure compiler in advanced mode some methods
770 | // get renamed. This keeps a public reference to these methods so they can
771 | // still be referenced from outside this library.
772 | Rainbow["onHighlight"] = Rainbow.onHighlight;
773 | Rainbow["addClass"] = Rainbow.addClass;
774 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | JavaScript For Cats
2 | ## An introduction for new programmers 
3 | ### *So easy your human companion could do it too!*
4 |
5 | JavaScript is a programming language or, in other words, a means by which a computer is instructed to do things. Just the same as one controls humans with hisses and meows, one controls computers with statements written in a programming language. All web browsers understand JavaScript and you can take advantage of that to make web pages do crazy things!
6 |
7 | JavaScript started as a way to make web pages more interactive. Nowadays JavaScript runs in more places than just web browsers — it runs on web servers, phones and even robots! This page will teach you some JavaScript basics so that you can get up and running in no time*.
8 |
9 | \* *Actual time: more than none. Probably an hour or two. Also since you are a cat you are less likely to run and more likely to lay around in the sun*
10 |
11 | JavaScript for Cats is [CC0 Licensed](https://creativecommons.org/publicdomain/zero/1.0/)
12 |
13 | ## Table of contents
14 |
15 | - [The console](#basics)
16 | - [Strings](#strings)
17 | - [Values and variables](#values)
18 | - [Using functions](#functions)
19 | - [Built in JS functions](#standard-library)
20 | - [Download new JS functions](#third-party-javascript)
21 | - [Writing new functions](#writing-functions)
22 | - [Loops](#loops)
23 | - [Arrays](#arrays)
24 | - [Objects](#objects)
25 | - [Callbacks](#callbacks)
26 | - [Recommended reading](#recommended-reading)
27 |
28 | ## Don't be a scaredy-cat
29 |
30 | 
31 |
32 | You will always land on your feet — even when programming! Unlike [pawing over a glass of water](images/dealwithit.gif) on your laptop, _nothing_ in these tutorials will damage your computer in any way, even if you mistype a command or click the wrong button. Like cats, computer programmers make mistakes all time: misspelling things, forgetting quotes or brackets, and being forgetful of how basic functions (and yarn, lasers) work. Programmers care more about making it work _eventually_ rather than trying to make it work the very first time. The best way to learn is by making mistakes!
33 |
34 | So don't be a scaredy-cat! The absolute worst thing that will happen is that you might have to refresh this page in your web browser if you get stuck. Don't worry though, this will happen very rarely.
35 |
36 | ## # The basics
37 |
38 | There is JavaScript running on this page right now. Let's play around with it a little. For the sake of simplicity I'll assume you are using Google Chrome to read this page (if you aren't it's probably easier on both of us if you follow along with Chrome).
39 |
40 | First, right click anywhere on the screen and hit **Inspect Element**, then click on the **Console** tab. You should see a thingy that looks like this:
41 |
42 | 
43 |
44 | This is a console, otherwise known as a "command line" or "terminal". Basically it's a way to type one thing at a time into a computer and immediately get the computers answer back. They are super useful as a learning tool (I still use the console nearly every day that I'm coding).
45 |
46 | The console does some pretty cool stuff. Here I have started to type something and the console is helping me out by giving me a list of all the possible things I could continue to type! Another thing you could do is type `1 + 1` into the console and then hit the `Enter` key and watch what happens.
47 |
48 | Using the console is a very important part of learning JavaScript. If you don't know if something works or what the command is for something, go to the console and figure it out! Here's an example:
49 |
50 | ### # Strings
51 |
52 | Since I am a cat I want to replace every instance of the word `dog` on the Internet with `those blasted dogs`. First go into your console and type in a few sentences that contain the word `dog` at least once. In JavaScript a bunch of letters, numbers, words or anything else is known as a **String** (as in a *string* of characters). Strings have to begin AND end with a quotation mark. Single `'` or double `"` is fine, just make sure you use the same at the beginning as you do at the end.
53 |
54 | 
55 |
56 | See the nasty error message? Don't worry - you didn't break any laws. SyntaxError ILLEGAL is just the way it sounds when robots tell you that your program has a problem. The first two sentences had matching quotation marks at the beginning and end, but when I mixed single and double quotation marks it freaked out on me.
57 |
58 | OK, to fix up one of these sentences (by replacing `dog` with our enhanced version) we have to first save the original sentence so that we can call it up later when we do our replacing magic. Notice how the string gets repeated in red when we type it into the console? This is because we haven't told it to save the sentence anywhere so it just gives it right back (or it gives us an Error back if we messed something up).
59 |
60 | ### # Values and variables
61 |
62 | **Values** are the simplest components in JavaScript. `1` is a value, `true` is a value, `"hello"` is a value, `function() {}` is a value, the list goes on! There are a handful of different **types** of values in JavaScript but we don't need to go over them all right away — you will learn them naturally the more you code!
63 |
64 | To store values we use things called **variables**. The word 'variable' means 'can change' and is used because variables can store many different types of values and can change their value many times. They are pretty much like mailboxes. We put something in a variable, like our sentence, and then give the variable an address that we can use to look up the sentence later. In real life mailboxes have to have PO Box numbers but in JavaScript you usually just use lowercase letters or numbers without any spaces.
65 |
66 | 
67 |
68 | `var` is shorthand for variable and the `=` means *store the thing on the right-hand side in the thing on the left-hand side*. Also as you can see, now that we are storing our sentence in a variable the console doesn't just return our sentence right away, but instead gives us `undefined` which means *there was nothing to return*.
69 |
70 | If you simply type a variable name into the console it will print out the value stored in that variable. A note about variables is that by default they go away when you switch to a different page. If I were to hit the Refresh button in Chrome, for example, my `dogSentence` variable would get wiped and it would be like it never existed. But don't worry about this too much for now — you can just hit the up or down arrows on your keyboard while in the console to go through everything you've entered in recently.
71 |
72 | ### # Functions
73 |
74 | Now that we have our sentence stored in a variable, let's change a word stored in it! We can do this by performing a *function*. *Functions* are a type of value that, well, serve a specific *function* (AKA purpose or action) for us. Calling them "actions" sounded weird I guess so they went with the word "function" instead.
75 |
76 | JavaScript has a function called `replace` that does exactly what we want! Functions take in any number of values in their parentheses (zero, one or many) and return either nothing (`undefined`) or the changed string. The `replace` function is available to use on any strings and takes in two values: the characters to take out and the characters to swap in. It gets confusing to describe these things so here is a visual example:
77 |
78 | 
79 |
80 | Notice how the value of `dogSentence` is the same even after we run `replace` on it? This is because the `replace` function, (and most JavaScript functions for that matter) takes the value we give it and returns a **new value**, without modifying the value we passed in. Since we didn't store the result (there is no `=` on the left side of the replace function) it just printed out the return value in our console.
81 |
82 | ### # The "standard library"
83 |
84 | You might be wondering what other functions are available in JavaScript. The answer: A TON. There are lots **built in, standard libraries** that you can learn about at MDN (A site run by Mozilla that has lotsa nifty information about web technologies). For example [here is the MDN page on JavaScript's Math object](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math).
85 |
86 | ### # Third-party JavaScript
87 |
88 | There is also a lot of JavaScript code available that is **not built in**. JavaScript from third parties is usually referred to as a "library" or "plugin". One of my favorites is called **Underscore.js**. Let's go and grab it and load it into our page! First go to the Underscore site, [http://underscorejs.org/](http://underscorejs.org/), click on the download link (I usually use development versions because they are easier to read but both will give you the same basic functionality), and then copy all the code onto your clipboard (you can use Select All from the Edit menu to select everything). Then paste it into your console and hit enter. Now your browser has a new variable in it: `_`. Underscore gives you a ton of helpful functions to play with. We'll learn more about how to use them later.
89 |
90 | 
91 |
92 | ### # Making new functions
93 |
94 | You aren't limited to using other peoples functions — you can also write them yourself. It's pretty easy! Let's make a function called `makeMoreExciting` that adds a bunch of exclamation points to the end of a string.
95 |
96 | function makeMoreExciting(string) {
97 | return string + '!!!!'
98 | }
99 |
100 | In my head I read it out loud like this: "there's a function called 'make more exciting' that takes in a string and returns a new copy of that string that has a bunch of exclamation points at the end". Here is how we would write this in the console manually if we weren't using a function:
101 |
102 | 
103 |
104 | The expression `string + '!!!!'` returns a new string and our variable called `string` stays the same as before (since we never updated it to anything else with `=`).
105 |
106 | Let's use our function instead of doing it manually. First, paste the function into the console and then **call** the function by **passing in** a string:
107 |
108 | 
109 |
110 | You could also call the same function by passing in a variable that points to a string (in the above example we just typed the string straight in there as a value instead of saving it to a variable first):
111 |
112 | 
113 |
114 | The line `makeMoreExciting(sentence)` is equivalent to saying `sentence + '!!!!'`. What if we wanted to **modify in-place** (aka update) the value of sentence? Simply save the return value of the function back into our `sentence` variable:
115 |
116 | var sentence = "time for a nap"
117 | sentence = makeMoreExciting(sentence)
118 |
119 | Now `sentence` will have the exclamation marks in it! Note that you only have to use `var` when you are **initializing** a variable — the first time you ever use it. After that you shouldn't use `var` unless you want to re-initialize (reset/clear/empty) the variable.
120 |
121 | What would happen if we took out the `return` statement in our function?
122 |
123 | 
124 |
125 | Why is `sentence` empty? Because functions return `undefined` by default! You can choose to return a value by `return`ing something. Functions should take in a value and, if they change the value or create a new value that is supposed to be used later, `return` a value (fun fact: a fancy term for this style is *functional programming*). Here is another function that doesn't return anything but instead uses a different method to show us the output:
126 |
127 | ```js
128 | function yellIt(string) {
129 | string = string.toUpperCase()
130 | string = makeMoreExciting(string)
131 | console.log(string)
132 | }
133 | ```
134 |
135 | This function, `yellIt`, uses our previous function `makeMoreExciting` as well as the built-in String method [toUpperCase](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/toUpperCase). Methods are just a name for a function when it belongs to something — in this case `toUpperCase` is a function that belongs to `String` so we can refer to it as either a method *or* a function. `makeMoreExciting` on the other hand doesn't belong to anyone so it would be technically incorrect to refer to it as a method (confusing, I know).
136 |
137 | The last line of the function is another built-in that simply takes in any values that you give it and prints them out into the console.
138 |
139 | 
140 |
141 | So is there something wrong with the above `yellIt` function? It depends! Here are the two major types of functions:
142 |
143 | - functions that modify or create values and return them
144 | - functions take in values and perform some action that cannot be returned
145 |
146 | `console.log` is an example of the second type of function: it prints things out to your console — an action that you can see with your eyes but that cannot be represented as a JavaScript value. My own rule of thumb is to try to keep the two types of functions separate from each other, so here's how I would rewrite the `yellIt` function:
147 |
148 | ```js
149 | function yellIt(string) {
150 | string = string.toUpperCase()
151 | return makeMoreExciting(string)
152 | }
153 |
154 | console.log(yellIt("i fear no human"))
155 | ```
156 |
157 | This way `yellIt` becomes more **generic**, meaning it only does one or two simple little things and doesn't know anything about printing itself to a console — that part can always be programmed later, outside the function definition.
158 |
159 | ### # Loops
160 |
161 | Now that we have some basic skills under our belt (*Author's note: do cats even wear belts?*) we can start being lazy. What?! Yes, that's right: programming is about being lazy. Larry Wall, inventor of the Perl programming language, called laziness the [most important virtue](http://c2.com/cgi/wiki?LazinessImpatienceHubris) of a good programmer. If computers didn't exist you would have to do all sorts of tedious tasks by hand, but if you learn to program you can lay in the sun all day while a computer somewhere runs your programs for you. It is a glorious lifestyle filled with relaxation!
162 |
163 | Loops are one of the most important ways to harness the power of a computer. Remember `Underscore.js` from earlier? Make sure you have it loaded in the page (remember: you can just hit the up arrow on your keyboard a few times and then hit `Enter` to load it in again if you need to) and try copy/pasting this into your console:
164 |
165 | ```js
166 | function logANumber(someNumber) {
167 | console.log(someNumber)
168 | }
169 | _.times(10, logANumber)
170 | ```
171 |
172 | This code uses the [times](http://underscorejs.org/#times) method of Underscore which takes in 1 number and 1 function and then starts from 0 and for 10 steps counts up by 1, calling the function with the number each step of the way.
173 |
174 | 
175 |
176 | If we were to manually write out what `times` is doing in the above code it would look like this:
177 |
178 | ```js
179 | logANumber(0)
180 | logANumber(1)
181 | logANumber(2)
182 | logANumber(3)
183 | logANumber(4)
184 | logANumber(5)
185 | logANumber(6)
186 | logANumber(7)
187 | logANumber(8)
188 | logANumber(9)
189 | ```
190 |
191 | But cats refuse to do unnecessary manual work like this so we must always ask ourselves, *"am I doing this in the laziest way possible?"*.
192 |
193 | So why is this called looping? Think of it like this: If we were to write out a list of 10 numbers (from 0 to 9) using a JavaScript Array it would look like this:
194 |
195 | ```js
196 | var zeroThroughTen = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
197 | ```
198 |
199 | What `times` really does is visit each number and repeat a task: in the example above the task was to call the `logANumber` function with the current number. Repeating tasks in this way is referred to as *looping over* the Array.
200 |
201 | ### # Arrays
202 |
203 | I've mentioned these a few times but let's spend a minute learning about them. Imagine you need to keep track of all your buddies. Well, an Array will do just fine. Think of an Array like a sorted list that you can keep *tons* of stuff in.
204 |
205 | This is how you make one:
206 |
207 | ```js
208 | var myCatFriends = ["bill", "tabby", "ceiling"]
209 | ```
210 |
211 | Sweet! Now you have a list of your cat buddies.
212 |
213 | Elements (that is what you call a single item in an array) that are stored within arrays start at 0 and count up from there. So `myCatFriends[0]` returns `bill` and `myCatFriends[1]` returns `tabby`... etc etc.
214 |
215 | To get buddies out of your brand new Array you can just access an element directly like so:
216 |
217 | ```js
218 | console.log(myCatFriends[0])
219 | ```
220 |
221 | 
222 |
223 | If you made a brand new cat friend at the hippest cat club the other night and you want to add them to your list it is super simple: `myCatFriends.push("super hip cat")`.
224 |
225 | To check that the new cat made it into your array you can use `.length`:
226 |
227 | 
228 |
229 | Notice how `push` returned the length? Handy! Also take note that arrays will always **preserve ordering** which means they will remember the order in which you added or defined things. Not everything in JavaScript preserves ordering so remember this special property of Arrays!
230 |
231 | ### # Objects
232 |
233 | Arrays are good for lists, but for other tasks they can be hard to work with. Consider our array of cat friends. What if you also wanted to store more than just names?
234 |
235 | ```js
236 | var myCatFriends = ["bill", "tabby", "ceiling"]
237 | var lastNames = ["the cat", "cat", "cat"]
238 | var addresses = ["The Alley", "Grandmas House", "Attic"]
239 | ```
240 |
241 | Sometimes it is nice to have all of the addresses or names in one variable. But sometimes you have a cat in mind, let's say Bill, and you just want to look up that cat's address. With arrays it takes a lot of work because you can't just say 'hey array, give me Bill's address' because 'Bill' is in one array and his address is in a totally different array.
242 |
243 | 
244 |
245 | This can be brittle because if our arrays change and we add a new cat to the beginning we would have to also update our `billsPosition` variable to point to the new location of Bill's information in the arrays! Here is a easier to maintain way to store information like this using objects:
246 |
247 | ```js
248 | var firstCat = { name: "bill", lastName: "the cat", address: "The Alley" }
249 | var secondCat = { name: "tabby", lastName: "cat", address: "Grandmas House" }
250 | var thirdCat = { name: "ceiling", lastName: "cat", address: "Attic" }
251 | ```
252 |
253 | Why would we do it this way? Because now we have a variable for each cat that we can use to get that cats values in a more convenient and readable way.
254 |
255 | 
256 |
257 | You can think of Objects like keys on a keyring. Each one is for a specific door and if you have nice labels on your keys you can open doors very fast. In fact, the things on the left hand side of the `:` are called **keys** (are also known as **properties**) and the things on the right hand side are **values**.
258 |
259 | ```js
260 | // an object with a single key 'name' and single value 'bill'
261 | { name: 'bill' }
262 | ```
263 |
264 | So why would you ever use arrays if you can just put your data in objects? Because objects don't remember the order of the keys that you set. You might enter in an object like this:
265 |
266 | ```js
267 | { date: "10/20/2012", diary: "slept a bit today", name: "Charles" }
268 | ```
269 |
270 | But the computer could give it back to you like this:
271 |
272 | ```js
273 | { diary: "slept a bit today", name: "Charles", date: "10/20/2012" }
274 | ```
275 |
276 | Or like this!
277 |
278 | ```js
279 | { name: "Charles", diary: "slept a bit today", date: "10/20/2012" }
280 | ```
281 |
282 | So you can't ever trust the order of keys in objects. If you wanna get REALLY fancy you can make an array filled with objects, or an object filled with arrays!
283 |
284 | ```js
285 | var moodLog = [
286 | {
287 | date: "10/20/2012",
288 | mood: "catnipped"
289 | },
290 | {
291 | date: "10/21/2012",
292 | mood: "nonplussed"
293 | },
294 | {
295 | date: "10/22/2012",
296 | mood: "purring"
297 | }
298 | ]
299 |
300 | // ordered from least to most favorite
301 | var favorites = {
302 | treats: ["bird sighting", "belly rub", "catnip"],
303 | napSpots: ["couch", "planter box", "human face"]
304 | }
305 | ```
306 |
307 | When you combine different things like this you are making **data structures**, just like legos!
308 |
309 | ### # Callbacks
310 |
311 | Callbacks aren't really a feature of JavaScript like `Object` or `Array`, but instead just a certain way to use functions. To understand why callbacks are useful you first have to learn about asynchronous (often shortened to async) programming. Asynchronous code by definition is code written in a way that is not synchronous. Synchronous code is easy to understand and write. Here is an example to illustrate:
312 |
313 | ```js
314 | var photo = download('http://foo-chan.com/images/sp.jpg')
315 | uploadPhotoTweet(photo, '@maxogden')
316 | ```
317 |
318 | This synchronous [pseudo-code](http://simple.wikipedia.org/wiki/Pseudocode) downloads an adorable cat photo and then uploads the photo to twitter and tweets the photo at `@maxogden`. Pretty straightforward!
319 |
320 | (*Author's note: I @maxogden do happily accept random cat photo tweets*)
321 |
322 | This code is synchronous because in order for photo to get uploaded to the tweet, the photo download must be completed. This means that line 2 cannot run until the task on line 1 is totally finished. If we were to actually implement this pseudo-code we would want to make sure that `download` 'blocked' execution until the download was finished, meaning it would prevent *any* other JavaScript from being executed until it finished, and then when the download completes it would un-block the JavaScript execution and line 2 would execute.
323 |
324 | Synchronous code is fine for things that happen fast, but it's horrible for things that require saving, loading, downloading or uploading. What if the server you're downloading the photo from is slow, or the internet connection you are using is slow, or the computer you are running the code on has too many youtube cat video tabs open and is running slowly? It means that it could potentially take minutes of waiting before line 2 gets around to running. Meanwhile, because all JavaScript on the page is being blocked from being run while the download is happening, the webpage would totally freeze up and become unresponsive until the download is done.
325 |
326 | Blocking execution should be avoided at all costs, especially when doing so makes your program freeze up or become unresponsive. Let's assume the photo above takes one second to download. To illustrate how long one second is to a modern computer, here is a program that tests to see how many tasks JavaScript can process in one second.
327 |
328 | ```js
329 | function measureLoopSpeed() {
330 | var count = 0
331 | function addOne() { count = count + 1 }
332 |
333 | // Date.now() returns a big number representing the number of
334 | // milliseconds that have elapsed since Jan 01 1970
335 | var now = Date.now()
336 |
337 | // Loop until Date.now() is 1000 milliseconds (1 second) or more into
338 | // the future from when we started looping. On each loop, call addOne
339 | while (Date.now() - now < 1000) addOne()
340 |
341 | // Finally it has been >= 1000ms, so let's print out our total count
342 | console.log(count)
343 | }
344 |
345 | measureLoopSpeed()
346 | ```
347 |
348 | Copy-paste the above code into your JavaScript console and after one second it should print out a number. On my computer I got `8527360`, approximately **8.5 million**. In one second JavaScript can call the `addOne` function 8.5 million times! So if you have synchronous code for downloading a photo, and the photo download takes one second, it means you are potentially preventing 8.5 million operations from happening while JavaScript execution is blocked.
349 |
350 | Some languages have a function called `sleep` that blocks execution for some number of seconds. For example here is some [`bash`](http://en.wikipedia.org/wiki/Bash_%28Unix_shell%29) code running in `Terminal.app` on Mac OS that uses `sleep`. When you run the command `sleep 3 && echo 'done sleeping now'` it blocks for 3 seconds before printing out `done sleeping now`.
351 |
352 | 
353 |
354 | JavaScript doesn't have a `sleep` function. Since you are a cat you are probably asking yourself, "Why am I learning a programming language that does not involve sleeping?". But stay with me. Instead of relying on `sleep` to wait for things to happen the design of JavaScript encourages use of functions instead. If you have to wait for task A to finish before doing task B, you put all of the code for task B into a function and you only call that function when A is done.
355 |
356 | For example, this is blocking-style code:
357 |
358 | ```js
359 | a()
360 | b()
361 | ```
362 |
363 | And this is in a non-blocking style:
364 |
365 | ```js
366 | a(b)
367 | ```
368 |
369 | In the non-blocking version `b` is a callback to `a`. In the blocking version `a` and `b` are both called/invoked (they both have `()` after them which executes the functions immediately). In the non-blocking version you will notice that only `a` gets invoked, and `b` is simply passed in to `a` as an argument.
370 |
371 | In the blocking version, there is no explicit relationship between `a` and `b`. In the non-blocking version it becomes `a`'s job to do what it needs to do and then call `b` when it is done. Using functions in this way is called callbacks because your callback function, in this case `b`, gets called later on when `a` is all done.
372 |
373 | Here is a pseudocode implementation of what `a` might look like:
374 |
375 | ```js
376 | function a(done) {
377 | download('https://pbs.twimg.com/media/B4DDWBrCEAA8u4O.jpg:large', function doneDownloading(error, png) {
378 | // handle error if there was one
379 | if (err) console.log('uh-oh!', error)
380 |
381 | // call done when you are all done
382 | done()
383 | })
384 | }
385 | ```
386 |
387 | Think back to our non-blocking example, `a(b)`, where we call `a` and pass in `b` as the first argument. In the function definition for `a` above the `done` argument *is* our `b` function that we pass in. This behavior is something that is hard to wrap your head around at first. When you call a function, the arguments you pass in won't have the same variable names when they are in the function. In this case what we call `b` is called `done` inside the function. But `b` and `done` are just variable names that point to the same underlying function. Usually callback functions are labelled something like `done` or `callback` to make it clear that they are functions that should be called when the current function is done.
388 |
389 | So, as long as `a` does it's job and called `b` when it is done, both `a` and `b` get called in both the non-blocking and blocking versions. The difference is that in the non-blocking version we don't have to halt execution of JavaScript. In general non-blocking style is where you write every function so that it can return as soon as possible, without ever blocking.
390 |
391 | To drive the point home even further: If `a` takes one second to complete, and you use the blocking version, it means you can only do one thing. If you use the non-blocking version (aka use callbacks) you can do *literally millions* of other things in that same second, which means you can finish your work millions of times faster and sleep the rest of the day.
392 |
393 | Remember: programming is all about laziness and you should be the one sleeping, not your computer.
394 |
395 | Hopefully you can see now that callbacks are just functions that call other functions after some asynchronous task. Common examples of asynchronous tasks are things like reading a photo, downloading a song, uploading a picture, talking to a database, waiting for a user to hit a key or click on someone, etc. Anything that takes time. JavaScript is really great at handling asynchronous tasks like these as long as you take the time to learn how to use callbacks and keep your JavaScript from being blocked.
396 |
397 | ## The end!
398 |
399 | This is just the beginning of your relationship with JavaScript! You can't learn it all at once, but you should find what works for you and try to learn all of the concepts here.
400 |
401 | I'd recommend coming back again tomorrow and going through the entire thing again from the beginning! It might take a few times through before you get everything (programming is hard). Just try to avoid reading this page in any rooms that contain shiny objects . . . they can be incredibly distracting.
402 |
403 | Got another topic you wanna see covered? Open an issue for it [on github](http://github.com/maxogden/javascript-for-cats).
404 |
405 | ### # Recommended reading
406 |
407 | JavaScript For Cats skips over lots of details that aren't important for getting started (cats are not known for their attention spans), but if you feel like you need to dive in deeper then check these out:
408 |
409 | - [NodeSchool.io](http://nodeschool.io/) is a community driven, open source educational software that teaches various web development skills in an interactive, self-guided format. I helped make NodeSchool! Sadly it features fewer cats than this page.
410 | - [Eloquent Javascript](http://eloquentjavascript.net/) is a free book that teaches you JavaScript! It's pretty good! Especially the chapter on [values, variables, and control flow](http://eloquentjavascript.net/chapter2.html)
411 | - [Mozilla's JavaScript Guide](https://developer.mozilla.org/en-US/docs/JavaScript/Guide) also has a pretty sweet intro chapter called [values, variables and literals](https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Values,_variables,_and_literals)
412 | - [`standard` JS Style Guide](https://github.com/feross/standard) is a "zero configuration" linter for JS style that I use
413 | - [Let's Write Code by @shama](https://github.com/shama/letswritecode) a great series of YouTube coding tutorials made by a friend of mine
414 |
415 |
416 | ### # Satisfied customers
417 | 
418 | 
419 | 
420 | 
421 | 
422 |
423 | *JSForCats.com is a labor of love and work in progress by [@maxogden](http://twitter.com/maxogden). If you would like to contribute and make this tutorial better there is a Github repo [right over here](http://github.com/maxogden/javascript-for-cats).*
424 | 
425 |
--------------------------------------------------------------------------------
/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------
2 | Typography / Basics
3 | ---------------------------------------------*/
4 | html,body {
5 | color: #57676e;
6 | background: #e7eef2;
7 | -webkit-font-smoothing: antialiased;
8 | height: 100%;
9 | line-height: 1.5em;
10 | }
11 |
12 | body,
13 | textarea,
14 | input {
15 | font: 13px/20px 'OpenSans', sans-serif;
16 | }
17 |
18 | a {
19 | color: #434c50;
20 | text-decoration: none;
21 | -moz-transition: background-color 100ms linear, color 100ms linear;
22 | -o-transition: background-color 100ms linear, color 100ms linear;
23 | -webkit-transition: background-color 100ms linear, color 100ms linear;
24 | transition: background-color 100ms linear, color 100ms linear;
25 | }
26 |
27 | a:hover {
28 | color: #2e3335;
29 | }
30 |
31 | a:focus {
32 | outline: none;
33 | }
34 |
35 | a:active {
36 | outline: none;
37 | }
38 |
39 | p > a {font-weight: 700;}
40 |
41 | h1,h2,h3,h4,h5,h6 {
42 | margin: 0;
43 | line-height: 1.5em;
44 | }
45 |
46 | h1 {
47 | font-size: 24px;
48 | }
49 |
50 | h1 small {
51 | font-size: 13px;
52 | font-weight: 400;
53 | }
54 |
55 | h2 {
56 | font-weight: 400;
57 | font-size: 16px;
58 | padding: 5px 0 5px 30px;
59 | }
60 |
61 | h2 small {
62 | font-size: 16px;
63 | font-weight: 400;
64 | }
65 |
66 | h3 {
67 | font-size: 11px;
68 | text-transform: uppercase;
69 | font-weight: 700;
70 | margin-top: 10px;
71 | }
72 |
73 | h3 small {
74 | font-size: 14px;
75 | font-weight: 400;
76 | }
77 |
78 | h4 {
79 | font-size: 14px;
80 | }
81 |
82 | h5 {
83 | font-size: 13px;
84 | }
85 |
86 | h6 {
87 | font-size: 11px;
88 | font-weight: 400;
89 | }
90 |
91 | p {
92 | font-size: 16px;
93 | line-height: 1.5em;
94 | margin-bottom: 0;
95 | margin-top: 10px;
96 | }
97 |
98 | /* Use border-box box model */
99 |
100 | * {
101 | box-sizing: border-box;
102 | -webkit-box-sizing: border-box;
103 | -moz-box-sizing: border-box;
104 | }
105 |
106 | /* ------------------------------------------
107 | Globals
108 | ---------------------------------------------*/
109 |
110 | h1 img {
111 | position: relative;
112 | top: 15px;
113 | left: 10px;
114 | }
115 |
116 | /* Top Branding/Navigation */
117 |
118 | #header {
119 | position: absolute;
120 | top: 0;
121 | right: 0;
122 | left: 0;
123 | padding: 0 20px;
124 | height: 60px;
125 | background: #e0e7eb;
126 | border-bottom: 1px solid #c3ccd0;
127 | box-shadow: 0 1px 0 rgba(255, 255, 255, 0),0 0 10px rgba(0, 0, 0, 0.1);
128 | overflow: visible;
129 | }
130 |
131 | body.post #header {
132 | box-shadow: none;
133 | border-bottom: none;
134 | }
135 |
136 | #header .navigation a.title {
137 | position: relative;
138 | width: 80px;
139 | background: url('images/sprite.png') 22px -154px no-repeat;
140 | height: 100%;
141 | margin: 0;
142 | -moz-border-radius: 0px;
143 | -webkit-border-radius: 0px;
144 | border-radius: 0px;
145 | }
146 |
147 | #header a.title span {
148 | display: none;
149 | }
150 |
151 | #header .navigation {
152 | width: 960px;
153 | margin: 0 auto;
154 | position: relative;
155 | line-height: 60px;
156 | overflow: visible;
157 | font-size: 12px;
158 | font-weight: 700;
159 | height: 100%;
160 | text-indent: 20px;
161 | }
162 |
163 | #header .navigation > * {
164 | display: block;
165 | position: relative;
166 | padding: 0 20px 0 20px;
167 | margin: 0px;
168 | float: left;
169 | text-indent: 0px;
170 | }
171 |
172 | #header .navigation a:hover {
173 | background-color: #c9d1d6;
174 | }
175 |
176 | #header .user-status {
177 | float: right;
178 | padding: 0;
179 | min-width: 120px;
180 | text-align: right;
181 | text-indent: -40px;
182 | }
183 |
184 | #header .user-status.logged-out a.button {
185 | text-indent: 0;
186 | padding: 0 10px;
187 | display: block;
188 | }
189 |
190 | #header .user-status .logout {
191 | display: block;
192 | float: right;
193 | width: 30px;
194 | text-indent: 3000px;
195 | margin-left: 10px;
196 | overflow: hidden;
197 | background-image: url('images/sprite.png');
198 | background-position: -441px -25px;
199 | background-repeat: no-repeat;
200 | }
201 |
202 | #main {
203 | overflow:auto;
204 | padding-bottom: 60px; /* must be same height as the footer */
205 | }
206 |
207 | #main .loading {
208 | margin: 150px auto;
209 | width: 50px;
210 | font-size: 20px;
211 | text-align: center;
212 | height: 11px;
213 | background: url('images/ajax-loader.gif') no-repeat;
214 | }
215 |
216 | #main .loading span {
217 | display: none;
218 | }
219 |
220 | #post .inner {
221 | position: relative;
222 | }
223 |
224 | /* ------------------------------------------
225 | Footer - a sticky one
226 | ---------------------------------------------*/
227 |
228 | /* must declare 0 margins on everything, also for main layout components use padding, not
229 | vertical margins (top and bottom) to add spacing, else those margins get added to total height
230 | and your footer gets pushed down a bit more, creating vertical scroll bars in the browser */
231 |
232 | #container {
233 | min-height: 100%;
234 | min-width: 960px;
235 | }
236 |
237 | #footer {
238 | position: relative;
239 | margin-top: -60px; /* negative value of footer height */
240 | height: 60px;
241 | overflow: hidden;
242 | line-height: 60px;
243 | background: #e0e7eb;
244 | border-top: 1px solid #c3ccd0;
245 | clear:both;
246 | }
247 |
248 | #footer .footer-content {
249 | width: 960px;
250 | margin: 0 auto;
251 | font-size: 15px;
252 | }
253 |
254 | #footer a, #footer .brand {
255 | font-size: 12px;
256 | font-weight: bold;
257 | font-weight: 700;
258 | }
259 |
260 | #footer a {
261 | margin-right: 20px;
262 | padding-left: 20px;
263 | }
264 |
265 | a.about, a.help {
266 | background-image: url('images/sprite.png');
267 | }
268 |
269 | a.about {
270 | background-position: 0 -959px;
271 | }
272 |
273 | a.help {
274 | background-position: 0 -1049px;
275 | }
276 |
277 | #footer .footer-content p {
278 | margin: 16px 0;
279 | }
280 |
281 | /*Opera Fix*/
282 | body:before {/* thanks to Maleika (Kohoutec)*/
283 | content:"";
284 | height:100%;
285 | float:left;
286 | width:0;
287 | margin-top:-32767px;/* thank you Erik J - negate effect of float*/
288 | }
289 |
290 | /* ------------------------------------------
291 | Startpage
292 | ---------------------------------------------*/
293 |
294 | #start .dialog {
295 | position: relative;
296 | }
297 |
298 | #start h1 {
299 | padding: 20px 0;
300 | }
301 |
302 | #start .organizations {
303 | overflow: auto;
304 | margin-bottom: 30px;
305 | }
306 |
307 | #start .organizations .organization {
308 | display: block;
309 | float: left;
310 | height: 60px;
311 | padding: 4px;
312 | width: 60px;
313 | margin-right: 20px;
314 | border: 1px solid #C3CCD0;
315 | background: #fff;
316 | -moz-border-radius: 5px;
317 | -webkit-border-radius: 5px;
318 | border-radius: 5px;
319 | }
320 |
321 | #start .organizations .organization img {
322 | padding: 0;
323 | margin: 0;
324 | -moz-border-radius: 3px;
325 | -webkit-border-radius: 3px;
326 | border-radius: 3px;
327 | height: 50px;
328 | width: 50px;
329 | }
330 |
331 | #start .splash {
332 | text-align: center;
333 | background: white;
334 | font-weight: 400;
335 | -moz-border-radius: 5px 5px 0 0;
336 | -webkit-border-radius: 5px 5px 0 0;
337 | border-radius: 5px 5px 0 0;
338 | position: relative;
339 | margin: 40px auto 0 auto;
340 | width: 340px;
341 | border: 1px solid #C3CCD0;
342 | box-shadow: 0 1px 0 rgba(255, 255, 255, 0),0 0 10px rgba(0, 0, 0, 0.1);
343 | border-radius: 3px;
344 | }
345 |
346 | #start .splash h2 {
347 | background: url('images/sprite.png') 111px 47px no-repeat;
348 | text-indent: -3000px;
349 | overflow: hidden;
350 | display: block;
351 | height: 200px;
352 | }
353 |
354 | #start .splash p {
355 | margin-bottom: 20px;
356 | }
357 |
358 | .authorize {
359 | border-top: 1px solid #C3CCD0;
360 | -moz-border-radius: 0 0 5px 5px;
361 | -webkit-border-radius: 0 0 5px 5px;
362 | border-radius: 0 0 5px 5px;
363 | padding: 20px ;
364 | }
365 |
366 | .authorize p {
367 | margin-top: 0;
368 | margin-bottom: 20px;
369 | }
370 |
371 | .authorize a.button {
372 | display: block;
373 | background: #516066;
374 | padding: 5px;
375 | -moz-border-radius: 5px;
376 | -webkit-border-radius: 5px;
377 | border-radius: 5px;
378 | font-family:'OpenSans', sans-serif;
379 | text-transform: uppercase;
380 | font-size: 11px;
381 | font-weight: 700;
382 | color: #fff;
383 | }
384 |
385 | .authorize a.button:hover {
386 | background: #3d4548;
387 | }
388 |
389 | /* ------------------------------------------
390 | Profile
391 | ---------------------------------------------*/
392 |
393 | #profile_wrapper {
394 | overflow: auto;
395 | padding: 20px 0;
396 | border-bottom: 1px solid #C3CCD0;
397 | }
398 |
399 | #start .profile-header {
400 | overflow: auto;
401 | }
402 |
403 | #start .profile-header .avatar {
404 | height: 90px;
405 | width: 90px;
406 | padding: 4px;
407 | border: 1px solid #C3CCD0;
408 | background: #fff;
409 | -moz-border-radius: 5px;
410 | -webkit-border-radius: 5px;
411 | border-radius: 5px;
412 | float: left;
413 | }
414 |
415 | #start .profile-header .user {
416 | margin-top: 25px;
417 | margin-left: 30px;
418 | float: left;
419 | }
420 |
421 | #start .profile-header .user .username {
422 | font-size: 26px;
423 | font-weight: bold;
424 | margin-bottom: 5px;
425 | }
426 |
427 | #start .profile-header, #start .profile-details {
428 |
429 | font-size: 14px;
430 | }
431 |
432 | #start .profile-header {
433 | float: left;
434 | }
435 |
436 | #start .profile-details {
437 | float: right;
438 | margin-top: 50px;
439 | margin-left: 100px;
440 | overflow: auto;
441 | }
442 |
443 | #start .profile-details .info {
444 | float: left;
445 | }
446 |
447 | #start .profile-details .info span {
448 | color: #93A8B1;
449 | }
450 |
451 | #start .profile-details .stats {
452 | float: right;
453 | margin-top: 5px;
454 | margin-left: 70px;
455 | }
456 |
457 | #start .profile-details .stats .count {
458 | text-align: center;
459 | font-size: 30px;
460 | font-weight: bold;
461 | }
462 |
463 | #start .profile-details .stats .label {
464 | text-align: center;
465 | color: #777;
466 | }
467 |
468 | /* ------------------------------------------
469 | Repos listing
470 | ---------------------------------------------*/
471 |
472 | #start {
473 | padding-bottom: 20px;
474 | width: 960px;
475 | margin: 20px auto 0 auto;
476 | }
477 |
478 | #start .owner {
479 | font-size: 16px;
480 | padding: 10px;
481 | margin-bottom: 20px;
482 | background: #E0E7EB;
483 | -moz-border-radius: 4px;
484 | -webkit-border-radius: 4px;
485 | border-radius: 4px;
486 | }
487 |
488 | #start .owner::before {
489 | content: "";
490 | background: url('images/sprite.png') 0px -550px no-repeat;
491 | height: 30px;
492 | width: 30px;
493 | float: left;
494 | display: block;
495 | position: relative;
496 | }
497 |
498 | #start .owner .repo-count {
499 | display: block;
500 | float: right;
501 | }
502 |
503 | .repos {
504 | overflow: auto;
505 | padding: 0px 0 20px 0;
506 | }
507 |
508 | .repos > a {
509 | display: block;
510 | float: left;
511 | position: relative;
512 | overflow: hidden;
513 | text-align: center;
514 | width: 140px;
515 | height: 180px;
516 | margin: 0 20px 20px 0;
517 | box-shadow: 0 1px 0 rgba(255, 255, 255, 0),0 0 10px rgba(0, 0, 0, 0.1);
518 | background:url('images/sprite.png') -450px -640px no-repeat;
519 | background-color: #E0E7EB;
520 | -moz-border-radius: 3px 3px 0px 3px;
521 | -webkit-border-radius: 3px 3px 0px 3px;
522 | border-radius: 3px 3px 0px 3px;
523 | }
524 |
525 | .repos > a:before {
526 | content: '';
527 | display: inline-block;
528 | height: 100%;
529 | vertical-align: middle;
530 | margin-right: -0.25em;
531 | }
532 |
533 | .repos > a:hover {
534 | background-color: #f0f5f7;
535 | }
536 |
537 | .repos > a .name {
538 | display: inline-block;
539 | vertical-align: middle;
540 | width: 116px;
541 | font-size: 12px;
542 | text-align: center;
543 | overflow: hidden;
544 | word-wrap: break-word;
545 | color: #526066;
546 | margin: 0 10px;
547 | }
548 |
549 | .repos > a:hover .name {
550 | color: #526066;
551 | }
552 |
553 | .repos a .branches {
554 | position: absolute;
555 | background:url('images/sprite.png') -450px -640px no-repeat;
556 | background-color: #f0f5f7;
557 | -moz-border-radius: 3px 3px 0px 3px;
558 | -webkit-border-radius: 3px 3px 0px 3px;
559 | border-radius: 3px 3px 0px 3px;
560 | font-size: 12px;
561 | text-align: left;
562 | left: 0px;
563 | right: 0px;
564 | bottom: 0px;
565 | top: 0px;
566 | padding: 10px;
567 | overflow: auto;
568 | border-radius: 3px;
569 | }
570 |
571 | .repos a .branches .label {
572 | line-height: 27px;
573 | padding: 0 5px;
574 | }
575 |
576 | .repos a .branches .repo-error {
577 | position: absolute;
578 | top: 0; bottom: 0; left: 0; right: 0;
579 | color: #C52528;
580 | text-align: center;
581 | padding-top: 80px;
582 | padding-top: 45px;
583 | margin: auto;
584 | overflow: hidden;
585 | word-wrap: break-word;
586 | }
587 |
588 |
589 | .repos a .branches .branch {
590 | padding: 2px 5px;
591 | text-align: center;
592 | }
593 |
594 | .repos a .branches a.branch {
595 | display: block;
596 | color: #555;
597 | }
598 |
599 | .loading-branches, .post-listing a.link.folder.loading .filename {
600 | text-indent: -9999px;
601 | overflow: hidden;
602 | position: absolute;
603 | margin: auto;
604 | left: 0; right: 0; top: 0; bottom: 0;
605 | background: url('images/ajax-loader.gif') no-repeat;
606 | height: 11px;
607 | width: 44px;
608 | }
609 |
610 | .loading-branches, .post-listing a.link.folder.loading {
611 | background-color: #F0F5F7;
612 | }
613 |
614 | .repos a .branches a.branch:hover {
615 | background: #E0E7EB;
616 | }
617 |
618 | .start .sites,
619 | .dialog form {
620 | width: 240px;
621 | position: absolute;
622 | left: 50%;
623 | margin-left: -120px;
624 | }
625 |
626 | ul.site li {
627 | position: relative;
628 | }
629 |
630 | ul.site li a {
631 | display: block;
632 | border-bottom: 1px solid #eee;
633 | padding: 4px 0;
634 | }
635 |
636 | ul.site li a:hover {
637 | background: url(images/icons.png) no-repeat 220px -20px;
638 | }
639 |
640 | /* User box */
641 |
642 | #user {
643 | font-size:12px;
644 | position:absolute;
645 | top:0;
646 | right:0;
647 | z-index:2;
648 | padding:5px;
649 | background:#eee;
650 | border-radius:0 0 0 4px;
651 | -moz-border-radius: 0 0 0 4px;
652 | -webkit-border-radius: 0 0 0 4px;
653 | box-shadow:
654 | inset #ccc 0px 1px,
655 | inset #ddd 0px 0px 5px,
656 | #fff 0px 1px,
657 | #f8f8f8 0px 3px 3px;
658 | }
659 |
660 | #user .name,
661 | #user .logout {
662 | display:inline;
663 | padding:0 5px;
664 | }
665 |
666 | #user a {
667 | color:#222;
668 | }
669 |
670 | #user .logout a {
671 | color:#999;
672 | }
673 |
674 | /* Form hint */
675 |
676 | #hint {
677 | position: absolute;
678 | top: -30px;
679 | font-size: 20px;
680 | width: 100%;
681 | text-align: center;
682 | }
683 |
684 | /* ------------------------------------------
685 | New post
686 | ---------------------------------------------*/
687 |
688 | .step {
689 | background: #fff;
690 | padding: 20px 20px 40px;
691 | -moz-border-radius: 4px;
692 | -webkit-border-radius: 4px;
693 | border-radius: 4px;
694 | width: 318px;
695 | margin: 40px auto 0;
696 | border: 1px solid #CCC;
697 | -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.10);
698 | -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.10);
699 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.10);
700 | }
701 |
702 | .step form {
703 | width: 240px;
704 | margin: 0 auto;
705 | }
706 |
707 | /* ------------------------------------------
708 | Posts
709 | ---------------------------------------------*/
710 |
711 | #posts {
712 | padding: 30px 0;
713 | width: 960px;
714 | margin: 0 auto;
715 | }
716 |
717 |
718 | #publish_status {
719 | position: relative;
720 | height: 50px;
721 | }
722 |
723 | #publish_status.active {
724 | background-color: #fff;
725 | border: 1px solid #a0a0a0;
726 | }
727 |
728 | .post-listing a.link {
729 | display: block;
730 | float: left;
731 | position: relative;
732 | overflow: hidden;
733 | width: 140px;
734 | height: 180px;
735 | margin: 0 20px 20px 0;
736 | box-shadow: 0 1px 0 rgba(255, 255, 255, 0),0 0 10px rgba(0, 0, 0, 0.1);
737 | border-radius: 3px 40px 3px 3px;
738 | background-image:url('images/sprite.png') -450px -400px no-repeat;
739 | background-color: #F2F6F8;
740 | }
741 |
742 | .post-listing a.link:hover {
743 | background-color: #fff;
744 | }
745 |
746 | .post-listing a.link:before {
747 | content: '';
748 | display: inline-block;
749 | height: 100%;
750 | vertical-align: middle;
751 | margin-right: -0.25em;
752 | }
753 |
754 | .post-listing a.link .filename {
755 | display: inline-block;
756 | vertical-align: middle;
757 | width: 116px;
758 | font-size: 12px;
759 | text-align: center;
760 | overflow: hidden;
761 | word-wrap: break-word;
762 | color: #526066;
763 | margin: 0 10px;
764 | }
765 |
766 | .post-listing a.link.loading {
767 | background-color: white;
768 | }
769 |
770 | .post-listing a.link.loading .filename {
771 | text-indent: -9999px;
772 | overflow: hidden;
773 | position: absolute;
774 | margin: auto;
775 | left: 0;
776 | right: 0;
777 | top: 0;
778 | bottom: 0;
779 | background-image: url('images/ajax-loader.gif') no-repeat;
780 | height: 11px;
781 | width: 44px;
782 | color: #444;
783 | }
784 |
785 | .post-listing a.link:hover .filename {
786 | color: #526066;
787 | }
788 |
789 | .post-listing a.link:hover {
790 | border-color: #a0a0a0;
791 | color: #404040;
792 | }
793 |
794 | .post-listing a.link:active {
795 | border-color: #526066;
796 | }
797 |
798 | .post-listing a.link.folder {
799 | background-image:url('images/sprite.png') -450px -150px no-repeat;
800 | background-color: #E0E7EB;
801 | border-radius: 3px;
802 | }
803 |
804 | .post-listing a.link.folder:hover {
805 | background-color: #f0f5f7;
806 | }
807 |
808 | .post-listing a.link.new .button {
809 | background: #516066 url('images/sprite.png') -440px -90px no-repeat;
810 | text-indent: 10px;
811 | padding: 5px;
812 | color: #fff;
813 | position: absolute;
814 | width: 100px;
815 | margin: auto;
816 | top: 40%;
817 | left: 0;
818 | right: 0;
819 | -moz-border-radius: 5px;
820 | -webkit-border-radius: 5px;
821 | border-radius: 5px;
822 | text-transform: uppercase;
823 | text-align: center;
824 | font-size: 11px;
825 | font-weight: 700;
826 | }
827 |
828 | .post-listing a.link.new:hover .button {
829 | background: #3d4548 url('images/sprite.png') -440px -90px no-repeat; }
830 |
831 |
832 | /* ------------------------------------------
833 | Post
834 | ---------------------------------------------*/
835 |
836 | .document-menu {
837 | padding: 0 20px;
838 | height: 60px;
839 | background: #667880;
840 | overflow: visible;
841 | line-height: 40px;
842 | z-index: 2000;
843 | }
844 |
845 | #post.sticky-menu .document-menu {
846 | position: fixed;
847 | top: 0px;
848 | left: 0px;
849 | right: 0px;
850 | }
851 |
852 | #post.published .document-menu {
853 | background-color: #90bb74;
854 | }
855 |
856 | #post.published .metadata {
857 | background-color: #73965d;
858 | }
859 |
860 | .document-menu .options {
861 | display: none;
862 | background-color: #667880;
863 | -moz-transition: background 100ms linear;
864 | -o-transition: background 100ms linear;
865 | -webkit-transition: background 100ms linear;
866 | transition: background 100ms linear;
867 | }
868 |
869 | #post.published .document-menu .options {
870 | background-color: #90bb74;
871 | }
872 |
873 | .document-menu-content {
874 | width: 960px;
875 | margin: 0 auto;
876 | color: #E7EEF2;
877 | font-weight: 700;
878 | position: relative;
879 | }
880 |
881 | .document-menu-content .status {
882 | position: absolute;
883 | left: -50px;
884 | width: 50px;
885 | height: 60px;
886 | background-image: url('images/sprite.png');
887 | background-position: -290px -185px;
888 | }
889 |
890 | #post.published .document-menu-content .status {
891 | background-position: -290px -285px;
892 | }
893 |
894 | .document-menu-content .menu-item {
895 | background: rgba(0,0,0, 0.2);
896 | line-height: 40px;
897 | margin: 10px 0;
898 | }
899 |
900 | .document-menu-content .menu-item state {
901 | background: none;
902 | }
903 |
904 | .document-menu-content .menu-item.preview, .document-menu-content .menu-item.cheatsheet, .document-menu-content .menu-item.compose {
905 | text-indent: -9999px;
906 | overflow: hidden;
907 | background-image:url('images/sprite.png');
908 | background-repeat: no-repeat;
909 | width: 40px;
910 | padding: 0;
911 | margin-left: 1px;
912 | border-radius: 0;
913 | }
914 |
915 | .document-menu-content .menu-item.cheatsheet {
916 | background-position: -290px -486px;
917 | -moz-border-radius: 5px 0px 0px 5px;
918 | -webkit-border-radius: 5px 0px 0px 5px;
919 | border-radius: 5px 0px 0px 5px;
920 | }
921 |
922 | .document-menu-content .menu-item.preview {
923 | background-position: -438px 15px;
924 | -moz-border-radius: 0px 5px 5px 0px;
925 | -webkit-border-radius: 0px 5px 5px 0px;
926 | border-radius: 0px 5px 5px 0px;
927 | }
928 |
929 | .document-menu-content .menu-item.compose {
930 | background-position: -288px -538px;
931 | }
932 |
933 | .document-menu-content .menu-item.preview.active, .document-menu-content .menu-item.cheatsheet.active, .document-menu-content .menu-item.compose.active {
934 | background-color: rgba(0,0,0, 0.6);
935 | }
936 |
937 | .document-menu-content .menu-item.meta {
938 | background-image: url('images/sprite.png');
939 | background-position: -288px 14px;
940 | padding-left: 35px;
941 | padding-right: 10px;
942 | }
943 |
944 | .document-menu-content .menu-item.meta.active {
945 | background-color: rgba(0,0,0, 0.6);
946 | }
947 |
948 | .document-menu-content a {
949 | color: #E7EEF2;
950 | }
951 |
952 | .document-menu-content a:active {
953 | -webkit-box-shadow: inset 0px 0px 5px 0px rgba(0, 0, 0, .2);
954 | box-shadow: inset 0px 0px 5px 0px rgba(0, 0, 0, .2);
955 | }
956 |
957 | .menu-item {
958 | -moz-border-radius: 5px;
959 | -webkit-border-radius: 5px;
960 | border-radius: 5px;
961 | }
962 |
963 | .menu-item:hover {
964 | background: rgba(0,0,0, 0.3);
965 | }
966 |
967 | .document-menu-content .menu-item.meta {
968 | margin-left: 20px;
969 | }
970 |
971 | .document-menu-content .filename input {
972 | font-family: Menlo, monospace;
973 | background: transparent;
974 | border: none;
975 | height: 40px;
976 | font-size: 16px;
977 | color: #555;
978 | color: #e7eef2;
979 | width: 400px;
980 | padding: 0 5px;
981 | margin: 10px 0;
982 | -moz-border-radius: 5px;
983 | -webkit-border-radius: 5px;
984 | border-radius: 5px;
985 | }
986 |
987 | .document-menu-content .filename .state {
988 | position: absolute;
989 | left: 420px;
990 | top: 15px;
991 | width: 50px;
992 | height: 30px;
993 | }
994 |
995 | .document-menu-content .filename .state.loading {
996 | background-image: url('images/ajax-loader.gif') center center no-repeat;
997 | }
998 |
999 | .document-menu-content .filename .state.error {
1000 | background-image: url('images/sprite.png');
1001 | background-position: -300px -200px;
1002 | }
1003 |
1004 | .document-menu-content .filename .state.success {
1005 | background-image:url('images/sprite.png');
1006 | background-position: -300px -300px;
1007 | }
1008 |
1009 | .document-menu-content .filename input:hover, .document-menu-content .filename input:focus {
1010 | background-color: rgba(0,0,0, 0.2);
1011 | color: #e7eef2;
1012 | }
1013 |
1014 | .document-menu .options {
1015 | position: absolute;
1016 | top: 60px;
1017 | right: 0px;
1018 | width: 300px;
1019 | z-index: 3000;
1020 | border-radius: 0 0 5px 5px;
1021 | }
1022 |
1023 | .document-menu .options .publish-state {
1024 | padding: 0 20px;
1025 | }
1026 |
1027 | .document-menu .options .actions {
1028 | background: rgba(255, 255, 255, 0.1);
1029 | padding: 20px;
1030 | border-radius: 0 0 5px 5px;
1031 | }
1032 |
1033 | .document-menu .options .actions .button {
1034 | display: block;
1035 | text-align: center;
1036 | background: rgba(0,0,0, 0.2);
1037 | -moz-border-radius: 5px;
1038 | -webkit-border-radius: 5px;
1039 | border-radius: 5px;
1040 | }
1041 |
1042 | .document-menu .options .actions .button:hover {
1043 | background: #DB6F6F;
1044 | }
1045 |
1046 | .document-menu-content .menu-item.save-state {
1047 | background: none;
1048 | }
1049 |
1050 | .document-menu-content .menu-item.save-state:hover {
1051 | background: none;
1052 | }
1053 |
1054 | .document-menu-content .state .button.save {
1055 | background-color: rgba(0,0,0, 0.2);
1056 | width: 180px;
1057 | text-align: center;
1058 | line-height: 40px;
1059 | margin-left: 1px;
1060 | margin: 0px;
1061 | height: 40px;
1062 | border-radius: 0px 4px 4px 0px;
1063 | margin-left: 1px;
1064 | padding: 0;
1065 | }
1066 |
1067 | .document-menu-content .state .button.save:hover {
1068 | background-color: rgba(0,0,0, 0.4);
1069 | }
1070 |
1071 | .document-menu-content .save-state {
1072 | margin-left: 20px;
1073 | }
1074 |
1075 | .document-menu-content .save-state:hover {
1076 | background-color: rgba(0,0,0, 0.2);
1077 | }
1078 |
1079 | .document-menu-content .state .button {
1080 | display: block;
1081 | float:left;
1082 | color: #fff;
1083 | -moz-border-radius: 3px;
1084 | -webkit-border-radius: 3px;
1085 | border-radius: 3px;
1086 | margin: 5px;
1087 | line-height: 30px;
1088 | height: 30px;
1089 | padding: 0 12px;
1090 | }
1091 |
1092 | .document-menu-content .state .button.toggle-options {
1093 | background-image: url('images/sprite.png');
1094 | background-position: -288px -437px;
1095 | width: 50px;
1096 | padding: 0;
1097 | height: 40px;
1098 | margin: 0;
1099 | border-radius: 3px 0 0 3px;
1100 | background-color: rgba(0, 0, 0, .2);
1101 | }
1102 |
1103 | .document-menu-content .state .button:hover {
1104 | background-color: rgba(0, 0, 0, 0.4);
1105 | }
1106 |
1107 | .document-menu-content .state .button.inactive, .document-menu-content .state .button.inactive:hover {
1108 | text-shadow: none;
1109 | background-color: rgba(0, 0, 0, 0.1);
1110 | color: rgba(255, 255, 255, 0.5);
1111 | cursor: default;
1112 | }
1113 |
1114 | .document-menu-content .state .button.error, .document-menu-content .state .button.error:hover {
1115 | background: #DB6F6F;
1116 | }
1117 |
1118 | .document-menu-content .state .button.saving {
1119 | text-indent: -9999px;
1120 | overflow: hidden;
1121 | background-image: url('images/ajax-loader-unpublished.gif');
1122 | background-repeat: no-repeat;
1123 | background-position: 60px 13px;
1124 | }
1125 |
1126 | .published .document-menu-content .state .button.saving {
1127 | text-indent: -9999px;
1128 | overflow: hidden;
1129 | background-image: url('images/ajax-loader-published.gif');
1130 | background-repeat: no-repeat;
1131 | background-position: 60px 13px;
1132 | }
1133 |
1134 | .document-menu-content .state .options {
1135 | background-color: rgba(0,0,0, 0.3);
1136 | color: #fff;
1137 | -moz-border-radius: 5px;
1138 | -webkit-border-radius: 5px;
1139 | border-radius: 5px;
1140 | margin-left: 10px;
1141 | padding: 8px;
1142 | }
1143 |
1144 | .document .metadata {
1145 | overflow: hidden;
1146 | background-color: #526066;
1147 | color: #CCC;
1148 | z-index: 1000;
1149 | -moz-transition: background 100ms linear;
1150 | -o-transition: background 100ms linear;
1151 | -webkit-transition: background 100ms linear;
1152 | transition: background 100ms linear;
1153 | }
1154 |
1155 | .document .metadata-content .CodeMirror {
1156 | color: #F0F0F0;
1157 | }
1158 |
1159 | .document .metadata-content {
1160 | width: 960px;
1161 | margin: 0 auto;
1162 | }
1163 |
1164 | .state p,
1165 | .state .button-padding {
1166 | float: left;
1167 | }
1168 |
1169 | .state p {
1170 | color: #526066;
1171 | font-weight: 400;
1172 | font-size: 11px;
1173 | line-height: 35px;
1174 | margin: 0;
1175 | }
1176 |
1177 | .document {
1178 | min-height: 400px;
1179 | position: relative;
1180 | overflow:hidden;
1181 | }
1182 |
1183 | .document .surface {
1184 | overflow: hidden;
1185 | }
1186 |
1187 | .document .surface .cheatsheet-wrapper { display: none; }
1188 | .document .surface .content-wrapper { display: none; }
1189 | .document .surface .content-preview-wrapper { display: none; }
1190 |
1191 | .document .surface.cheatsheet .cheatsheet-wrapper {
1192 | padding-top: 20px;
1193 | display: block;
1194 | position: relative;
1195 | }
1196 |
1197 | .document .surface.compose .content-wrapper {
1198 | padding-top: 20px;
1199 | display: block;
1200 | position: relative;
1201 | }
1202 |
1203 | .document .surface.preview .content-preview-wrapper {
1204 | position: relative;
1205 | display: block;
1206 | padding-top: 20px;
1207 | word-wrap: break-word;
1208 | }
1209 |
1210 | .document .content-preview, .document .content {
1211 | padding: 20px 0px;
1212 | width: 960px;
1213 | margin: 0 auto;
1214 | }
1215 |
1216 | .document .cheatsheet-wrapper .content {
1217 | width: 960px;
1218 | margin: 0 auto;
1219 | overflow: auto;
1220 | }
1221 |
1222 | .document .cheatsheet-wrapper .content .left {
1223 | float: left;
1224 | width: 450px;
1225 | }
1226 |
1227 | .document .cheatsheet-wrapper .content .right {
1228 | float: right;
1229 | width: 450px;
1230 | }
1231 |
1232 | .document .post-content .right {
1233 | float: right;
1234 | }
1235 |
1236 | .document .cheatsheet-wrapper .content h2 {
1237 | font-weight: 700;
1238 | padding: 5px 0;
1239 | margin: 0;
1240 | }
1241 |
1242 | .document .cheatsheet-wrapper .content pre {
1243 | border: 1px solid #C3CCD0;
1244 | box-shadow: 0 1px 0 rgba(255, 255, 255, 0),0 0 10px rgba(0, 0, 0, 0.1);
1245 | background-color: #fff;
1246 | line-height: 1.5em;
1247 | font-size: 17px;
1248 | padding: 10px;
1249 | font-family: Menlo, monospace !important;
1250 | }
1251 |
1252 | /* ------------------------------------------
1253 | Rendered Markdown
1254 | ---------------------------------------------*/
1255 |
1256 | .post-content {
1257 | position: relative;
1258 | white-space: pre;
1259 | background: #fff;
1260 | padding: 50px 100px;
1261 | font-family: 'OpenSans', sans-serif;
1262 | font-weight: 400;
1263 | border: 1px solid #C3CCD0;
1264 | font-size: 16px;
1265 | box-shadow: 0 1px 0 rgba(255, 255, 255, 0),0 0 10px rgba(0, 0, 0, 0.1);
1266 | }
1267 |
1268 | .post-content * {
1269 | line-height: 1.2em;
1270 | }
1271 |
1272 | .post-content p, .post-content ul, .post-content ol, .post-content li {
1273 | line-height: 1.5em;
1274 | }
1275 |
1276 | .post-content .title {
1277 | font-size: 18px;
1278 | margin-bottom: 20px;
1279 | font-weight: 700;
1280 | border-bottom: 1px solid #d5e0e4;
1281 | padding-bottom: 20px;
1282 | }
1283 |
1284 | .post-content .bigTitle {
1285 | font-size: 85px;
1286 | }
1287 |
1288 | .post-content h1 {
1289 | font-size: 36px;
1290 | margin: 10px 0 20px 0;
1291 | float: left;
1292 | }
1293 |
1294 | .post-content h2 {
1295 | font-size: 24px;
1296 | margin: 10px 0 20px 0;
1297 | font-weight: 700;
1298 | padding: 0;
1299 | clear: both;
1300 | }
1301 |
1302 | .post-content h3, .post-content h4, .post-content h5, .post-content h6 {
1303 | text-transform: none;
1304 | font-size: 18px;
1305 | font-weight: 700;
1306 | margin: 10px 0 5px 0;
1307 | }
1308 |
1309 | .post-content blockquote {
1310 | padding-left: 19px;
1311 | border-left: 1px solid #d5e0e4;
1312 | font-style: italic;
1313 | margin-bottom: 20px;
1314 | }
1315 |
1316 | .post-content ul {
1317 | margin-left: 0px;
1318 | padding-left: 20px;
1319 | list-style: disc;
1320 | }
1321 |
1322 | .post-content ol {
1323 | margin-left: 0px;
1324 | padding-left: 20px;
1325 | list-style: decimal;
1326 | }
1327 |
1328 | .post-content img {
1329 | max-width: 780px;
1330 | }
1331 |
1332 | .post-content .meta {
1333 | margin-top: 30px;
1334 | padding-top: 5px;
1335 | font-size: 12px;
1336 | text-transform: uppercase;
1337 | border-top: 1px solid #d5e0e4;
1338 | }
1339 |
1340 | .post-content a {
1341 | color: #90BB74;
1342 | }
1343 |
1344 | .post-content a:hover {
1345 | color: #73955C;
1346 | }
1347 |
1348 | .post-content p {
1349 | margin-bottom: 20px;
1350 | }
1351 |
1352 | .post-content p:last-child {
1353 | margin-bottom: 20px;
1354 | }
1355 |
1356 | .post-content code {
1357 | font-family: Menlo, monospace;
1358 | padding: 4px;
1359 | margin: 0 2px;
1360 | -moz-border-radius: 3px;
1361 | -webkit-border-radius: 3px;
1362 | border-radius: 3px;
1363 | font-size: 12px;
1364 | border: 1px solid #d5e0e4;
1365 | }
1366 |
1367 | .post-content pre {
1368 | overflow: auto;
1369 | padding: 10px;
1370 | border-radius: 3px;
1371 | border: 1px solid #d5e0e4;
1372 | word-wrap: normal
1373 | }
1374 |
1375 | .post-content pre code {
1376 | border: none;
1377 | margin: 0;
1378 | padding: 0;
1379 | }
1380 |
1381 | .post-content hr {
1382 | margin: 5px 0 19px 0;
1383 | border: 0;
1384 | border-top: 1px solid #d5e0e4;
1385 | -moz-border-radius: 5px;
1386 | -webkit-border-radius: 5px;
1387 | border-radius: 5px;
1388 | }
1389 |
1390 | /* ------------------------------------------
1391 | About
1392 | ---------------------------------------------*/
1393 |
1394 | #container .about {
1395 | width: 960px;
1396 | margin: 30px auto;
1397 | background: white;
1398 | }
1399 |
1400 | /* ------------------------------------------
1401 | Logbook
1402 | ---------------------------------------------*/
1403 |
1404 | .help {
1405 | width: 960px;
1406 | margin: 20px auto;
1407 | }
1408 |
1409 | .help h2 {
1410 | background: url('images/sprite.png') -110px -1042px no-repeat;
1411 | }
1412 |
1413 | .help.post-content h2 { background: none;}
1414 |
1415 | .help .articles {
1416 | overflow: auto;
1417 | }
1418 |
1419 | .help .articles .article {
1420 | -moz-border-radius: 4px;
1421 | -webkit-border-radius: 4px;
1422 | border-radius: 4px
1423 | border: #c3ccd0 1px solid;
1424 | overflow: hidden;
1425 | background-color: #F2F6F8;
1426 | box-shadow: 0 1px 0 rgba(255, 255, 255, 0),0 0 10px rgba(0, 0, 0, 0.1);
1427 | font-size: 16px;
1428 | position: relative;
1429 | margin: 20px 20px 0px 0;
1430 | width: 220px;
1431 | height: 250px;
1432 | color: #444;
1433 | display: block;
1434 | float: left;
1435 | padding: 10px;
1436 | border: 1px solid #C3CCD0;
1437 | }
1438 |
1439 | .help .articles .article:hover {
1440 | background-color: #fff;
1441 | }
1442 |
1443 | .help .articles .article .title {
1444 | padding: 5px 0;
1445 | }
1446 |
1447 | .help .articles .article p {
1448 | font-size: 12px;
1449 | font-weight: 400;
1450 | }
1451 |
1452 | .help-article {
1453 | width: 960px;
1454 | margin: 30px auto;
1455 | }
1456 |
1457 | /* ------------------------------------------
1458 | Notifications
1459 | ---------------------------------------------*/
1460 |
1461 | #notification .notification{
1462 | text-align: center;
1463 | width: 440px;
1464 | margin: 60px auto 0 auto;
1465 | padding: 20px;
1466 | font-size: 24px;
1467 | line-height: 1.5em;
1468 | font-weight: 700;
1469 | }
1470 |
1471 | #notification a {
1472 | background-color: #516066;
1473 | padding: 5px;
1474 | color: white;
1475 | position: relative;
1476 | display: block;
1477 | width: 100px;
1478 | height: 30px;
1479 | margin: 0px auto;
1480 | -moz-border-radius: 5px;
1481 | -webkit-border-radius: 5px;
1482 | border-radius: 5px;
1483 | text-transform: uppercase;
1484 | text-align: center;
1485 | font-size: 11px;
1486 | font-weight: 700;
1487 | }
1488 |
1489 | #notification a:hover {
1490 | background-color: #3d4548;
1491 | }
1492 |
1493 | ul.form li {
1494 | position: relative;
1495 | }
1496 |
1497 | label.error {
1498 | color: #E73C58;
1499 | position: absolute;
1500 | right: 5px;
1501 | top: 23px;
1502 | font-size: 12px;
1503 | }
1504 |
1505 | /* ------------------------------------------
1506 | Class Helpers
1507 | ---------------------------------------------*/
1508 |
1509 | .clearfix:after {
1510 | content: '.';
1511 | display: block;
1512 | height: 0;
1513 | clear: both;
1514 | visibility: hidden;
1515 | }
1516 |
1517 | * html .clearfix { height: 1%; } /* IE6 */
1518 | *:first-child + html .clearfix { min-height: 1%; } /* IE7 */
1519 |
1520 | .icon {
1521 | background: transparent url(images/icons.png) no-repeat 0 0;
1522 | width: 20px;
1523 | height: 20px;
1524 | display: block;
1525 | text-indent: -999em;
1526 | }
1527 |
1528 | .fl { float: left; }
1529 | .fr { float: right; }
1530 | .clear { clear: both; }
1531 |
1532 | .inner { padding: 0px 0px 40px; }
1533 | .hidden { display: none; }
1534 | .centered { text-align: center; }
1535 | .scrolling { overflow: auto; }
1536 | .clipping { overflow: hidden; }
1537 |
1538 | /* ------------------------------------------
1539 | ios and small screen alterations
1540 | ---------------------------------------------*/
1541 |
1542 | @media all and (max-width: 480px) {
1543 |
1544 | .post-content .bigTitle {
1545 | font-size: 30px;
1546 | text-align: center;
1547 | margin: 0 auto;
1548 | width: 100%;
1549 | display: block;
1550 | }
1551 |
1552 | .post-content h2 {
1553 | font-size: 20px;
1554 | }
1555 |
1556 | .header-text {
1557 | display: block;
1558 | margin: -3px 0 8px 0;
1559 | text-align: center;
1560 | }
1561 |
1562 | .post-content h2 img {
1563 | margin-bottom: 10px;
1564 | }
1565 |
1566 | img {
1567 | width: 100%;
1568 | }
1569 |
1570 | #post .inner {
1571 | width: 100%;
1572 | margin: 0;
1573 | padding: 10px 0px;
1574 | }
1575 |
1576 | .toggle-mode {
1577 | right: 0;
1578 | }
1579 |
1580 | .document .content-preview, .document .content {
1581 | width: 100%;
1582 | padding: 0;
1583 | }
1584 |
1585 | .content-preview-wrapper {
1586 | padding-top: 0;
1587 | }
1588 |
1589 | #container {
1590 | min-width: 100%;
1591 | }
1592 |
1593 | .post-content {
1594 | padding: 20px 15px;
1595 | }
1596 | }
1597 |
1598 |
--------------------------------------------------------------------------------