├── .gitignore ├── project.json ├── app ├── rulesets │ ├── rulesets.json │ └── flexbox.cheats │ │ ├── fx-img │ │ ├── display_flex.svg │ │ ├── align-items_baseline.svg │ │ ├── flex-wrap_nowrap.svg │ │ ├── align-items_center.svg │ │ ├── align-items_stretch.svg │ │ ├── align-items_flex-end.svg │ │ ├── justify-content_center.svg │ │ ├── align-items_flex-start.svg │ │ ├── justify-content_flex-end.svg │ │ ├── justify-content_flex-start.svg │ │ ├── justify-content_space-around.svg │ │ ├── justify-content_space-between.svg │ │ ├── flex-direction_column.svg │ │ ├── flex-direction_column-reverse.svg │ │ ├── flex-direction_row.svg │ │ ├── flex-direction_row-reverse.svg │ │ ├── align-content_center.svg │ │ ├── align-content_flex-end.svg │ │ ├── align-content_stretch.svg │ │ ├── align-content_flex-start.svg │ │ ├── align-content_space-around.svg │ │ ├── align-content_space-between.svg │ │ ├── display_inline-flex.svg │ │ ├── align-self_auto.svg │ │ ├── align-self_flex-end.svg │ │ ├── align-self_flex-start.svg │ │ ├── align-self_stretch.svg │ │ ├── flex-grow_1.svg │ │ ├── align-self_baseline.svg │ │ ├── align-self_center.svg │ │ ├── flex-wrap_wrap.svg │ │ ├── flex-grow_0.svg │ │ ├── flex-wrap_wrap-reverse.svg │ │ ├── flex-shrink_1.svg │ │ ├── flex-shrink_0.svg │ │ └── order_0.svg │ │ └── flexbox.json ├── list.php ├── index.txt ├── _index.html ├── index.php ├── app.php └── assets │ ├── js │ ├── jquery.hotkeys.js │ ├── fragment.js │ ├── yogert.js │ └── string.js │ ├── scss │ └── yogert.scss │ └── css │ └── yogert.css ├── package.json ├── README.md ├── Gruntfile.js └── LICENCE.txt /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | psd 3 | notes 4 | -------------------------------------------------------------------------------- /project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Vocabs" 3 | } 4 | -------------------------------------------------------------------------------- /app/rulesets/rulesets.json: -------------------------------------------------------------------------------- 1 | { 2 | "flexbox": { 3 | "title": "Flexbox cheatsheet", 4 | "help-text": "", 5 | "credits": { 6 | "@sakamies": "http://twitter.com/sakamies" 7 | }, 8 | "specs": { 9 | "CSS-Tricks: A Complete Guide to Flexbox": "http://css-tricks.com/snippets/css/a-guide-to-flexbox/" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Cheatsheets", 3 | "version": "3.0.0", 4 | "description": "Cheatsheets", 5 | "devDependencies": { 6 | "grunt": "^1.0.1", 7 | "grunt-autoprefixer": "^3.0.4", 8 | "grunt-contrib-watch": "^1.0.0", 9 | "grunt-sass": "^1.2.0" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/sakamies/vocabs" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/list.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Flexbox Cheatsheet 6 | 7 | 8 | 9 | 10 |
11 |
12 |

13 | CSS Cheats 14 |

15 |

by @workflower

16 | 17 | 22 | 23 |

Please report any issues at Github

24 |
25 |
26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CSS Cheats 2 | 3 | CSS Cheatsheets with icons for quick copy & paste. 4 | 5 | ---- 6 | 7 | ## Making new cheatsheets 8 | 9 | First off of course, fork the repo. Cheatsheets are JSON files in app/rulesets/cheatsheet_name.cheats. A cheatsheet contains css rules, each with a selector and some declarations. Check out flexbox.cheats/flexbox.json, it's rather simple. After you've made your new something.cheats folder, add some info about your cheatsheet to rulesets.json. Use the flexbox entry as an example. 10 | 11 | For some declarations it makes sense to make a little image to make it easier to remember what the values do. The filename needs to be in the format `{property-name}_{value}.svg`. 12 | 13 | When you're done, send a pull request to get the cheatsheet added to the app. -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | grunt.initConfig({ 4 | pkg: grunt.file.readJSON('package.json'), 5 | sass: { 6 | app: { 7 | files: { 8 | 'app/assets/css/yogert.css': 'app/assets/scss/yogert.scss', 9 | } 10 | }, 11 | }, 12 | autoprefixer: { 13 | app: { 14 | files: { 15 | 'app/assets/css/yogert.css': 'app/assets/css/yogert.css' 16 | } 17 | }, 18 | }, 19 | watch: { 20 | app: { 21 | files: [ 22 | 'app/assets/scss/*.scss', 23 | ], 24 | tasks: ['sass:app', 'autoprefixer:app'], 25 | options: { 26 | livereload: true, 27 | interrupt: true, 28 | } 29 | }, 30 | } 31 | }); 32 | 33 | grunt.loadNpmTasks('grunt-contrib-watch'); 34 | grunt.loadNpmTasks('grunt-sass'); 35 | grunt.loadNpmTasks('grunt-autoprefixer'); 36 | 37 | grunt.registerTask('serve', ['devserver']); 38 | grunt.registerTask('default', ['watch']); 39 | 40 | }; 41 | -------------------------------------------------------------------------------- /LICENCE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Ville Vanninen (@sakamies) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/index.txt: -------------------------------------------------------------------------------- 1 | Title: Flexbox cheatsheet 2 | ---- 3 | Author: Ville V. Vanninen 4 | ---- 5 | Blurb: Make your own css cheats, starting with flexbox 6 | ---- 7 | Text: 8 | You just love making product grids with html & css, right? Didn't think so. Flexbox is a great tool for making nice layouts for lists of things, but configuring it in code is a dog fart and trying to use photoshop and the like to make a grid of items, well forget it. 9 | 10 | Try this: Make a nice looking (flexible) item. Generate a bunch of them with varying data and click around to choose how they behave in the flexbox. Make a nice flexbox layout. Then get the css and use it in your project. 11 | 12 | When you're done, here's the best guide out there to using flexbox properties on your own: [A Complete Guide to Flexbox](http://css-tricks.com/snippets/css/a-guide-to-flexbox/) 13 | 14 | I'm calling this yogert, but Flexbox cheatsheet is a bit more understandable. Part yoga, part yogurt and doesn't smell. 15 | 16 |
17 | 18 | You should be using autoprefixer, so Yogert only generates the flexbox syntax according to the latest specs. Internally Yogert uses prefixfree for browser compatibility, because it works in the browser. You shouldn't use prefixfree for production sites, please use autoprefixer. (Unless you're making a browser based css generator of course.) -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/display_flex.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | display_flex 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/_index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Flexbox Cheatsheet 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 24 | 25 | 34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-items_baseline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-items_baseline 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/flexbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": [ 3 | { 4 | "selector": ".container", 5 | "declarations": [ 6 | [ 7 | {"display": "flex"}, 8 | {"display": "inline-flex"} 9 | ], 10 | [ 11 | {"flex-direction": "row"}, 12 | {"flex-direction": "row-reverse"}, 13 | {"flex-direction": "column"}, 14 | {"flex-direction": "column-reverse"} 15 | ], 16 | [ 17 | {"flex-wrap": "nowrap"}, 18 | {"flex-wrap": "wrap"}, 19 | {"flex-wrap": "wrap-reverse"} 20 | ], 21 | [ 22 | {"justify-content": "flex-start"}, 23 | {"justify-content": "center"}, 24 | {"justify-content": "flex-end"}, 25 | {"justify-content": "space-between"}, 26 | {"justify-content": "space-around"} 27 | ], 28 | [ 29 | {"align-items":"flex-start"}, 30 | {"align-items": "center"}, 31 | {"align-items": "flex-end"}, 32 | {"align-items": "stretch"}, 33 | {"align-items": "baseline"} 34 | ], 35 | [ 36 | {"align-content": "flex-start"}, 37 | {"align-content": "center"}, 38 | {"align-content": "flex-end"}, 39 | {"align-content": "space-between"}, 40 | {"align-content": "space-around"}, 41 | {"align-content": "stretch"} 42 | ] 43 | ] 44 | }, 45 | { 46 | "selector": ".item", 47 | "declarations": [ 48 | [ 49 | {"order": "0"} 50 | ], 51 | [ 52 | {"flex-grow": "0"}, 53 | {"flex-grow": "1"} 54 | ], 55 | [ 56 | {"flex-shrink": "0"}, 57 | {"flex-shrink": "1"} 58 | ], 59 | [ 60 | {"flex-basis": "auto"} 61 | ], 62 | [ 63 | {"align-self": "auto"}, 64 | {"align-self": "flex-start"}, 65 | {"align-self": "center"}, 66 | {"align-self": "flex-end"}, 67 | {"align-self": "baseline"}, 68 | {"align-self": "stretch"} 69 | ] 70 | ] 71 | } 72 | ] 73 | } 74 | 75 | 76 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/flex-wrap_nowrap.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | flex-wrap_nowrap 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/index.php: -------------------------------------------------------------------------------- 1 | $url) { 6 | $links .= ''.$name.' '; 7 | } 8 | return $links; 9 | } 10 | 11 | function specsLinks($links) { 12 | $html = ''; 13 | $html .= ''; 20 | return $html; 21 | } 22 | 23 | // Use ugly urls for local dev 24 | $localhosts = array('localhost', 'cheat.dev'); 25 | $uglyUrls = in_array($_SERVER['HTTP_HOST'], $localhosts); 26 | // Find out if ugly, but say if pretty, lifts the mood 27 | if ($uglyUrls == true) { 28 | $path = '/'; 29 | } else { 30 | $path = 'http://apps.workflower.fi/css-cheats/'; 31 | }; 32 | 33 | $sets = json_decode(file_get_contents('rulesets/rulesets.json'),true); 34 | $github = 'https://github.com/sakamies/css-cheats'; 35 | $appCredits = '@sakamies / @workflower'; 36 | $reportIssue = 'Report an issue'; 37 | $createSet = 'Create a cheatsheet'; 38 | 39 | // If there is no name given, output the index list and die 40 | $setName = filter_input(INPUT_GET, 'name', FILTER_SANITIZE_STRING); 41 | if(isset($setName) == false){ 42 | include('list.php'); 43 | exit(); 44 | } 45 | 46 | // If a name is in the url, make sure it exists in sets.json 47 | // Should be safe to use setName 48 | $setExists = array_key_exists($setName, $sets); 49 | if ($setExists == false) { 50 | header('HTTP/1.0 404 Not Found'); 51 | include('error.php'); 52 | exit(); 53 | } else { 54 | // Ok cool, we have a cheatsheet, time party 55 | // Read page title and stuff from sets.json according to bundle 56 | $set = $sets[$setName]; 57 | $title = $set['title']; 58 | $credits = creditsLinks($set['credits']); 59 | $specs = specsLinks($set['specs']); 60 | $helpText = $set['help-text']; 61 | include('app.php'); 62 | } 63 | 64 | ?> 65 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-items_center.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-items_center 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-items_stretch.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-items_stretch 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-items_flex-end.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-items_flex-end 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/justify-content_center.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | justify-content_center 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-items_flex-start.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-items_flex-start 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/justify-content_flex-end.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | justify-content_flex-end 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/justify-content_flex-start.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | justify-content_flex-start 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/justify-content_space-around.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | justify-content_space-around 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/justify-content_space-between.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | justify-content_space-between 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/flex-direction_column.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | flex-direction_column 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/flex-direction_column-reverse.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | flex-direction_column-reverse 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/flex-direction_row.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | flex-direction_row 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/flex-direction_row-reverse.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | flex-direction_row-reverse 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-content_center.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-content_center 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-content_flex-end.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-content_flex-end 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-content_stretch.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-content_stretch 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-content_flex-start.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-content_flex-start 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-content_space-around.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-content_space-around 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-content_space-between.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-content_space-between 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/display_inline-flex.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | display_inline-flex 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-self_auto.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-self_auto 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/app.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Flexbox Cheatsheet 6 | 7 | 8 | 9 | 10 |
11 |
12 |

13 | Flexbox cheatsheet 14 |

15 |

16 | by @sakamies 17 |

18 |
19 |

20 | Click a property or value to select its text. Makes it really fast to copy declarations. 21 |

22 |

23 | The means you selected something. (Click it to unselect.) 24 |

25 |

26 | Click a selector to get the whole rule set with your selections. (Click outside the textarea or copy the text to clipboard to dismiss.) 27 |

28 |

29 | Use tab, space, ↑↓←→ keys and copy/paste for quick keyboard action. 30 |

31 |
32 |

33 | CSS Cheats 34 | by @workflower 35 |

36 |

Please report any issues at Github

37 |
38 | 42 | 43 |
44 | { 45 | 46 |
47 | 48 | $value): ?> 49 |
50 | 51 | : 52 | ; 53 | 59 |
60 | 61 | 62 |
63 | 64 | } 65 | 66 |
67 | 68 |
69 | 70 |
71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-self_flex-end.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-self_flex-end 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-self_flex-start.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-self_flex-start 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-self_stretch.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-self_stretch 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/flex-grow_1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | flex-grow_1 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-self_baseline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-self_baseline 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/align-self_center.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | align-self_center 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/flex-wrap_wrap.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | flex-wrap_wrap 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/flex-grow_0.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | flex-grow_0 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/flex-wrap_wrap-reverse.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | flex-wrap_wrap-reverse 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/flex-shrink_1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | flex-shrink_1 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/flex-shrink_0.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | flex-shrink_0 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/rulesets/flexbox.cheats/fx-img/order_0.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | order_0 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/assets/js/jquery.hotkeys.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Hotkeys Plugin 3 | * Copyright 2010, John Resig 4 | * Dual licensed under the MIT or GPL Version 2 licenses. 5 | * 6 | * Based upon the plugin by Tzury Bar Yochay: 7 | * http://github.com/tzuryby/hotkeys 8 | * 9 | * Original idea by: 10 | * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/ 11 | */ 12 | 13 | /* 14 | * One small change is: now keys are passed by object { keys: '...' } 15 | * Might be useful, when you want to pass some other data to your handler 16 | */ 17 | 18 | (function(jQuery){ 19 | 20 | jQuery.hotkeys = { 21 | version: "0.8", 22 | 23 | specialKeys: { 24 | 8: "backspace", 9: "tab", 10: "return", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause", 25 | 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home", 26 | 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del", 59: ";", 61: "=", 27 | 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7", 28 | 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/", 29 | 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8", 30 | 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 173: "-", 186: ";", 187: "=", 31 | 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 221: "]", 222: "'" 32 | }, 33 | 34 | shiftNums: { 35 | "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&", 36 | "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<", 37 | ".": ">", "/": "?", "\\": "|" 38 | }, 39 | 40 | // excludes: button, checkbox, file, hidden, image, password, radio, reset, search, submit, url 41 | textAcceptingInputTypes: [ 42 | "text", "password", "number", "email", "url", "range", "date", "month", "week", "time", "datetime", 43 | "datetime-local", "search", "color", "tel"], 44 | 45 | options: { 46 | filterTextInputs: true 47 | } 48 | }; 49 | 50 | function keyHandler( handleObj ) { 51 | if ( typeof handleObj.data === "string" ) { 52 | handleObj.data = { keys: handleObj.data }; 53 | } 54 | 55 | // Only care when a possible input has been specified 56 | if ( !handleObj.data || !handleObj.data.keys || typeof handleObj.data.keys !== "string" ) { 57 | return; 58 | } 59 | 60 | var origHandler = handleObj.handler, 61 | keys = handleObj.data.keys.toLowerCase().split(" "); 62 | 63 | handleObj.handler = function( event ) { 64 | // Don't fire in text-accepting inputs that we didn't directly bind to 65 | if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) || 66 | ( jQuery.hotkeys.options.filterTextInputs && 67 | jQuery.inArray(event.target.type, jQuery.hotkeys.textAcceptingInputTypes) > -1 ) ) ) { 68 | return; 69 | } 70 | 71 | var special = jQuery.hotkeys.specialKeys[ event.keyCode ], 72 | character = String.fromCharCode( event.which ).toLowerCase(), 73 | modif = "", possible = {}; 74 | 75 | jQuery.each([ "alt", "ctrl", "meta", "shift" ], function(index, specialKey) { 76 | if (event[specialKey + 'Key'] && special !== specialKey) { 77 | modif += specialKey + '+'; 78 | } 79 | }); 80 | 81 | 82 | modif = modif.replace('alt+ctrl+meta+shift', 'hyper'); 83 | 84 | if ( special ) { 85 | possible[ modif + special ] = true; 86 | } 87 | 88 | if ( character ) { 89 | possible[ modif + character ] = true; 90 | possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true; 91 | 92 | // "$" can be triggered as "Shift+4" or "Shift+$" or just "$" 93 | if ( modif === "shift+" ) { 94 | possible[ jQuery.hotkeys.shiftNums[ character ] ] = true; 95 | } 96 | } 97 | 98 | for ( var i = 0, l = keys.length; i < l; i++ ) { 99 | if ( possible[ keys[i] ] ) { 100 | return origHandler.apply( this, arguments ); 101 | } 102 | } 103 | }; 104 | } 105 | 106 | jQuery.each([ "keydown", "keyup", "keypress" ], function() { 107 | jQuery.event.special[ this ] = { add: keyHandler }; 108 | }); 109 | 110 | })( this.jQuery ); 111 | -------------------------------------------------------------------------------- /app/assets/scss/yogert.scss: -------------------------------------------------------------------------------- 1 | //Monokai colors: 2 | 3 | $dark: #272822; 4 | $light: #f8f8f2; 5 | $gray: #75715e; 6 | $red: #f92772; 7 | $purple: #be84ff; 8 | $green: #a6e22d; 9 | $yellow: #e6db74; 10 | $orange: #f6aa10; 11 | $blue: #66d9ef; 12 | 13 | 14 | *, 15 | *::before, 16 | *::after { 17 | box-sizing: border-box; 18 | } 19 | 20 | body { 21 | font-size: 16px; 22 | line-height: 25px; 23 | font-family: monospace; 24 | -webkit-font-smoothing: antialiased; 25 | margin: 0; 26 | padding: 0; 27 | color: $light; 28 | background: $gray; 29 | background: $dark; 30 | } 31 | body::after { 32 | content: ''; 33 | display: table; 34 | clear: both; 35 | } 36 | a { 37 | color: $orange; 38 | } 39 | img, 40 | svg { 41 | vertical-align: middle; 42 | } 43 | h1 { 44 | font-size: 32px; 45 | line-height: 35px; 46 | margin: 25px 0 25px 0; 47 | } 48 | h2 { 49 | font-size: 24px; 50 | line-height: 25px; 51 | margin: 0 0 25px 0; 52 | } 53 | h1 + h2 { 54 | margin-top: -25px; 55 | } 56 | h3 { 57 | font-size: inherit; 58 | font-weight: bold; 59 | margin: 0 0 0px 0; 60 | } 61 | p { 62 | margin: 0px 0 12px 0; 63 | } 64 | ul { 65 | margin: 0 0 12px 0; 66 | padding: 0; 67 | list-style: none; 68 | list-style-position: outside; 69 | } 70 | li { 71 | margin: 0; 72 | padding: 0; 73 | } 74 | 75 | textarea { 76 | font-family: inherit; 77 | font-weight: inherit; 78 | font-size: inherit; 79 | line-height: inherit; 80 | -webkit-font-smoothing: inherit; 81 | } 82 | button { 83 | display: inline-block; 84 | vertical-align: middle; 85 | height: 25px; 86 | width: 25px; 87 | border-radius: 3px; 88 | border: none; 89 | color: $light; 90 | background: transparent; 91 | border: 1px solid; 92 | -webkit-font-smoothing: inherit; 93 | } 94 | 95 | $selfg: #fffff8; 96 | $selbg: rgba(lighten(#9D550F, 10%), .65); 97 | $selbg: $orange; 98 | ::selection { 99 | color: $selfg; 100 | background: $selbg; 101 | } 102 | ::-moz-selection { 103 | color: $selfg; 104 | background: $selbg; 105 | } 106 | $selfg: $dark; 107 | $selbg: rgba(desaturate(darken($blue, 20%), 10%), .35); 108 | textarea::selection { 109 | color: $selfg; 110 | background: $selbg; 111 | } 112 | textarea::-moz-selection { 113 | color: $selfg; 114 | background: $selbg; 115 | } 116 | 117 | :focus { 118 | outline: none; 119 | } 120 | .hide { 121 | display: none; 122 | } 123 | 124 | .layout { 125 | min-height: 100vh; 126 | display: flex; 127 | flex-direction: row; 128 | flex-wrap: wrap; 129 | align-items: flex-start; 130 | justify-content: flex-start; 131 | } 132 | 133 | .header { 134 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 135 | flex-shrink: 1; 136 | order: 99; 137 | width: 400px; 138 | align-self: stretch; 139 | padding: 0 25px 25px 25px; 140 | margin-left: auto; 141 | color: rgba($light, .7); 142 | border: 1px solid rgba($light, .2); 143 | border-width: 0px 0px 0px 1px; 144 | } 145 | @media (max-width: 1227px) { 146 | .header { 147 | order: 99; 148 | width: 100%; 149 | align-self: auto; 150 | border-width: 1px 0px 0px 0px; 151 | } 152 | } 153 | .help { 154 | margin: 25px 0 50px 0; 155 | } 156 | 157 | .rule { 158 | position: relative; 159 | flex-shrink: 0; 160 | max-width: 520px; 161 | padding: 25px 13px 25px 12px; 162 | margin: 0 12px; 163 | background: $dark; 164 | border-radius: 4px; 165 | } 166 | .selector { 167 | color: $green; 168 | cursor: pointer; 169 | } 170 | .row-group { 171 | } 172 | .row-group::after { 173 | content: ''; 174 | display: block; 175 | margin-left: 20px; 176 | padding-bottom: 3px; 177 | border-bottom: 1px dotted rgba(255,255,255,.1); 178 | margin-bottom: 3px; 179 | } 180 | .row-group:last-child::after { 181 | /*display: none;*/ 182 | } 183 | .declaration { 184 | line-height: 25px; 185 | white-space: nowrap; 186 | display: block; 187 | position: relative; 188 | padding-right: 66px; 189 | } 190 | .declaration.active { 191 | background: rgba(117, 113, 94, .2); 192 | border-radius: 2px; 193 | } 194 | .marker { 195 | color: $red; 196 | } 197 | .marker::before { 198 | position: absolute; 199 | top: 0; 200 | right: 100%; 201 | margin-right: -14px; 202 | white-space: pre; 203 | display: block; 204 | } 205 | .active .marker::before { 206 | display: inline-block; 207 | content: '●'; 208 | } 209 | .property { 210 | color: $blue; 211 | } 212 | .property::before { 213 | white-space: pre; 214 | content: ' '; 215 | } 216 | .value { 217 | color: $blue; 218 | } 219 | 220 | .declaration svg { 221 | position: absolute; 222 | right: 2px; 223 | top: 50%; 224 | margin-top: -11px; 225 | opacity: .8; 226 | } 227 | .declaration.active svg { 228 | opacity: 1; 229 | } 230 | .declaration:not(.active) svg #selector { 231 | //fill: $light; 232 | } 233 | 234 | .copyboard { 235 | display: none; 236 | position: absolute; 237 | top: 13px; 238 | left: 0; 239 | right: 0; 240 | bottom: 12px; 241 | width: 100%; 242 | height: 100%; 243 | margin: 0; 244 | padding: 12px 13px 13px 12px; 245 | color: $dark; 246 | background: $light; 247 | border: none; 248 | border-radius: 3px; 249 | } 250 | .overlay { 251 | display: none; 252 | position: fixed; 253 | top: 0; 254 | left: 0; 255 | right: 0; 256 | bottom: 0; 257 | } 258 | -------------------------------------------------------------------------------- /app/assets/css/yogert.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | *, 3 | *::before, 4 | *::after { 5 | box-sizing: border-box; } 6 | 7 | body { 8 | font-size: 16px; 9 | line-height: 25px; 10 | font-family: monospace; 11 | -webkit-font-smoothing: antialiased; 12 | margin: 0; 13 | padding: 0; 14 | color: #f8f8f2; 15 | background: #75715e; 16 | background: #272822; } 17 | 18 | body::after { 19 | content: ''; 20 | display: table; 21 | clear: both; } 22 | 23 | a { 24 | color: #f6aa10; } 25 | 26 | img, 27 | svg { 28 | vertical-align: middle; } 29 | 30 | h1 { 31 | font-size: 32px; 32 | line-height: 35px; 33 | margin: 25px 0 25px 0; } 34 | 35 | h2 { 36 | font-size: 24px; 37 | line-height: 25px; 38 | margin: 0 0 25px 0; } 39 | 40 | h1 + h2 { 41 | margin-top: -25px; } 42 | 43 | h3 { 44 | font-size: inherit; 45 | font-weight: bold; 46 | margin: 0 0 0px 0; } 47 | 48 | p { 49 | margin: 0px 0 12px 0; } 50 | 51 | ul { 52 | margin: 0 0 12px 0; 53 | padding: 0; 54 | list-style: none; 55 | list-style-position: outside; } 56 | 57 | li { 58 | margin: 0; 59 | padding: 0; } 60 | 61 | textarea { 62 | font-family: inherit; 63 | font-weight: inherit; 64 | font-size: inherit; 65 | line-height: inherit; 66 | -webkit-font-smoothing: inherit; } 67 | 68 | button { 69 | display: inline-block; 70 | vertical-align: middle; 71 | height: 25px; 72 | width: 25px; 73 | border-radius: 3px; 74 | border: none; 75 | color: #f8f8f2; 76 | background: transparent; 77 | border: 1px solid; 78 | -webkit-font-smoothing: inherit; } 79 | 80 | ::-moz-selection { 81 | color: #fffff8; 82 | background: #f6aa10; } 83 | 84 | ::selection { 85 | color: #fffff8; 86 | background: #f6aa10; } 87 | 88 | ::-moz-selection { 89 | color: #fffff8; 90 | background: #f6aa10; } 91 | 92 | textarea::-moz-selection { 93 | color: #272822; 94 | background: rgba(35, 177, 204, 0.35); } 95 | 96 | textarea::selection { 97 | color: #272822; 98 | background: rgba(35, 177, 204, 0.35); } 99 | 100 | textarea::-moz-selection { 101 | color: #272822; 102 | background: rgba(35, 177, 204, 0.35); } 103 | 104 | :focus { 105 | outline: none; } 106 | 107 | .hide { 108 | display: none; } 109 | 110 | .layout { 111 | min-height: 100vh; 112 | display: -webkit-box; 113 | display: -ms-flexbox; 114 | display: flex; 115 | -webkit-box-orient: horizontal; 116 | -webkit-box-direction: normal; 117 | -ms-flex-direction: row; 118 | flex-direction: row; 119 | -ms-flex-wrap: wrap; 120 | flex-wrap: wrap; 121 | -webkit-box-align: start; 122 | -ms-flex-align: start; 123 | align-items: flex-start; 124 | -webkit-box-pack: start; 125 | -ms-flex-pack: start; 126 | justify-content: flex-start; } 127 | 128 | .header { 129 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 130 | -ms-flex-negative: 1; 131 | flex-shrink: 1; 132 | -webkit-box-ordinal-group: 100; 133 | -ms-flex-order: 99; 134 | order: 99; 135 | width: 400px; 136 | -ms-flex-item-align: stretch; 137 | align-self: stretch; 138 | padding: 0 25px 25px 25px; 139 | margin-left: auto; 140 | color: rgba(248, 248, 242, 0.7); 141 | border: 1px solid rgba(248, 248, 242, 0.2); 142 | border-width: 0px 0px 0px 1px; } 143 | 144 | @media (max-width: 1227px) { 145 | .header { 146 | -webkit-box-ordinal-group: 100; 147 | -ms-flex-order: 99; 148 | order: 99; 149 | width: 100%; 150 | -ms-flex-item-align: auto; 151 | align-self: auto; 152 | border-width: 1px 0px 0px 0px; } } 153 | 154 | .help { 155 | margin: 25px 0 50px 0; } 156 | 157 | .rule { 158 | position: relative; 159 | -ms-flex-negative: 0; 160 | flex-shrink: 0; 161 | max-width: 520px; 162 | padding: 25px 13px 25px 12px; 163 | margin: 0 12px; 164 | background: #272822; 165 | border-radius: 4px; } 166 | 167 | .selector { 168 | color: #a6e22d; 169 | cursor: pointer; } 170 | 171 | .row-group::after { 172 | content: ''; 173 | display: block; 174 | margin-left: 20px; 175 | padding-bottom: 3px; 176 | border-bottom: 1px dotted rgba(255, 255, 255, 0.1); 177 | margin-bottom: 3px; } 178 | 179 | .row-group:last-child::after { 180 | /*display: none;*/ } 181 | 182 | .declaration { 183 | line-height: 25px; 184 | white-space: nowrap; 185 | display: block; 186 | position: relative; 187 | padding-right: 66px; } 188 | 189 | .declaration.active { 190 | background: rgba(117, 113, 94, 0.2); 191 | border-radius: 2px; } 192 | 193 | .marker { 194 | color: #f92772; } 195 | 196 | .marker::before { 197 | position: absolute; 198 | top: 0; 199 | right: 100%; 200 | margin-right: -14px; 201 | white-space: pre; 202 | display: block; } 203 | 204 | .active .marker::before { 205 | display: inline-block; 206 | content: '●'; } 207 | 208 | .property { 209 | color: #66d9ef; } 210 | 211 | .property::before { 212 | white-space: pre; 213 | content: ' '; } 214 | 215 | .value { 216 | color: #66d9ef; } 217 | 218 | .declaration svg { 219 | position: absolute; 220 | right: 2px; 221 | top: 50%; 222 | margin-top: -11px; 223 | opacity: .8; } 224 | 225 | .declaration.active svg { 226 | opacity: 1; } 227 | 228 | .copyboard { 229 | display: none; 230 | position: absolute; 231 | top: 13px; 232 | left: 0; 233 | right: 0; 234 | bottom: 12px; 235 | width: 100%; 236 | height: 100%; 237 | margin: 0; 238 | padding: 12px 13px 13px 12px; 239 | color: #272822; 240 | background: #f8f8f2; 241 | border: none; 242 | border-radius: 3px; } 243 | 244 | .overlay { 245 | display: none; 246 | position: fixed; 247 | top: 0; 248 | left: 0; 249 | right: 0; 250 | bottom: 0; } 251 | -------------------------------------------------------------------------------- /app/assets/js/fragment.js: -------------------------------------------------------------------------------- 1 | ;(function(win, doc) { 2 | 3 | // Gets either a string, which it will just return, or a {html, json} pair which 4 | // it will try to render with Mustache, Handlebars and Underscore. 5 | // If that fails, it just returns the html. 6 | var render = function(html, json) { 7 | if (typeof json === "undefined") { 8 | return html; 9 | } 10 | 11 | if (typeof win.Mustache !== "undefined" && 12 | typeof win.Mustache.render !== "undefined") { 13 | return Mustache.render(html, json); 14 | } else if (typeof win.Handlebars !== "undefined" && 15 | typeof win.Handlebars.compile !== "undefined") { 16 | return Handlebars.compile(html)(json); 17 | } else if (typeof win._ !== "undefined" && 18 | typeof win._.template !== "undefined") { 19 | return output = _.template(html, json); 20 | } 21 | 22 | return html; 23 | }; 24 | 25 | // Helper function to load ajax data 26 | var load_xhr = function(url, callback) { 27 | var request = new XMLHttpRequest(); 28 | request.open('GET', url); 29 | request.send(); 30 | request.onload = function() { 31 | callback(this.response); 32 | }; 33 | }; 34 | 35 | // Helper function to load jsonp data 36 | var load_jsonp = function(url, callback, url_parser) { 37 | var script = doc.createElement('script'); 38 | script.src = url + (parser.search == '' ? '?' : '&') + 39 | fragment.jsonp + '=JSONPCallback'; 40 | 41 | win.JSONPCallback = function(data) { 42 | // The callback function expects a string 43 | callback(JSON.stringify(data)); 44 | win.JSONPCallback = null; 45 | // Clean up DOM by removing the JSONP script element 46 | var parent = script.parentNode; 47 | if (parent) { 48 | parent.removeChild(script); 49 | } 50 | script = null; 51 | } 52 | doc.getElementsByTagName('head')[0].appendChild(script); 53 | }; 54 | 55 | var load = function(url, callback) { 56 | // We'll need something that can easily parse urls 57 | var url_parser = doc.createElement('a'); 58 | url_parser.href = url; 59 | 60 | // If the resource is located at the same hostname, assume ajax 61 | if (url_parser.hostname == win.location.hostname) { 62 | load_xhr(url, callback); 63 | } 64 | // If the resource is located at a different hostname, assume jsonp 65 | else { 66 | load_jsonp(url, callback, url_parser); 67 | } 68 | }; 69 | 70 | var render_template = function(element, html, json) { 71 | var context = extend(JSON.parse(json), context); 72 | element.innerHTML = fragment.render(html, context); 73 | evaluate(element, context); 74 | }; 75 | 76 | var render_html = function(element, html) { 77 | var context = this.context; 78 | 79 | // If the innerHTML is nonempty: the context is interpreted as the 80 | // combination of the JSONified innerHTML and the existing context. 81 | // The JSONified innerHTML has a higher precedence over the existing context. 82 | if (element.innerHTML != "") { 83 | context = extend(JSON.parse(element.innerHTML), context); 84 | } 85 | 86 | element.innerHTML = fragment.render(html, context); 87 | evaluate(element, context); 88 | }; 89 | 90 | var render_json = function(element, json) { 91 | var context = extend(JSON.parse(json), context); 92 | element.innerHTML = fragment.render(element.innerHTML, context); 93 | evaluate(element, this.context); 94 | }; 95 | 96 | // Handle an individual fragment 97 | var render_fragment = function(fragment_type, element) { 98 | var html_url = element.getAttribute('data-'+fragment.html); 99 | var json_url = element.getAttribute('data-'+fragment.json); 100 | var media = element.getAttribute('data-fragment-media'); 101 | 102 | // Don't load anything if the media query doesn't match 103 | if ( media && win.matchMedia && !win.matchMedia(media).matches ) return; 104 | 105 | // Update the num_fragments and deligate rendering to a submethod 106 | var resource_loaded = function(render_handler) { 107 | render_handler(); 108 | update_num_fragments(-1); 109 | }; 110 | 111 | update_num_fragments(1); 112 | 113 | if (fragment_type.html && fragment_type.json) { 114 | load(html_url, function(html) { 115 | load(json_url, function(json) { 116 | resource_loaded(render_template.bind(this, element, html, json)); 117 | }); 118 | }); 119 | } 120 | else if (fragment_type.html) { 121 | load(html_url, function(html) { 122 | resource_loaded(render_html.bind(this, element, html)); 123 | }); 124 | } 125 | else if (fragment_type.json) { 126 | load(json_url, function(json) { 127 | resource_loaded(render_json.bind(this, element, json)); 128 | }); 129 | } 130 | }; 131 | 132 | var evaluate = function(parent, context) { 133 | if (typeof parent === "undefined" || !("querySelectorAll" in parent)) { 134 | parent = doc; 135 | } 136 | 137 | // Scope contains information for recursively rendering fragments 138 | var scope = { parent: parent, context: context }; 139 | var fragments = parent.querySelectorAll('[data-'+fragment.html+'][data-'+fragment.json+']'); 140 | Array.prototype.forEach.call(fragments, render_fragment.bind(scope, { json: true, html: true })); 141 | 142 | var fragments = parent.querySelectorAll('[data-'+fragment.html+']:not([data-'+fragment.json+'])'); 143 | Array.prototype.forEach.call(fragments, render_fragment.bind(scope, { json: false, html: true })); 144 | 145 | var fragments = parent.querySelectorAll('[data-'+fragment.json+']:not([data-'+fragment.html+'])'); 146 | Array.prototype.forEach.call(fragments, render_fragment.bind(scope, { json: true, html: false })); 147 | }; 148 | 149 | var extend = function(obj, defaults) { 150 | if (typeof obj === "undefined") obj = {}; 151 | for (var element in defaults) { 152 | if (!obj.hasOwnProperty(element)) { 153 | obj[element] = defaults[element]; 154 | } 155 | } 156 | return obj; 157 | }; 158 | 159 | var num_fragments = 0; 160 | var max_fragments = 0; 161 | var update_num_fragments = function(diff) { 162 | num_fragments += diff; 163 | 164 | if (num_fragments > max_fragments) { 165 | max_fragments = num_fragments; 166 | } 167 | if (num_fragments == 0) { 168 | fragment.ready(max_fragments); 169 | } 170 | }; 171 | 172 | // Extend fragment with defaults 173 | var fragment = extend(win.fragment, { 174 | html: 'fragment', 175 | json: 'fragment-json', 176 | jsonp: 'callback', 177 | manual: false, 178 | render: render, 179 | evaluate: evaluate, 180 | ready: function(){} 181 | }); 182 | 183 | // Autoload 184 | if (!fragment.manual) { 185 | doc.addEventListener('DOMContentLoaded', function() { 186 | fragment.evaluate(); 187 | }); 188 | } 189 | 190 | // Just overwrite any existing "fragment" property 191 | win.fragment = fragment; 192 | 193 | })(window, window.document); 194 | -------------------------------------------------------------------------------- /app/assets/js/yogert.js: -------------------------------------------------------------------------------- 1 | fragment = { 2 | ready: function() { 3 | $(document).trigger('ready.fragment'); 4 | } 5 | }; 6 | 7 | jQuery.fn.selectText = function(){ 8 | var doc = document; 9 | var element = this[0]; 10 | var range, selection; 11 | 12 | if (doc.body.createTextRange) { 13 | range = document.body.createTextRange(); 14 | range.moveToElementText(element); 15 | range.select(); 16 | } else if (window.getSelection) { 17 | selection = window.getSelection(); 18 | range = document.createRange(); 19 | range.selectNodeContents(element); 20 | selection.removeAllRanges(); 21 | selection.addRange(range); 22 | } 23 | }; 24 | 25 | 26 | $(document).on('ready.fragment', function(event) { 27 | 28 | console.log('fragments loaded'); 29 | 30 | //TODO: Ohh screw timeout, why wont the fragments loaded work? 31 | setTimeout(function () { 32 | 33 | 34 | var selectable = '.declaration, .value'; 35 | $(selectable).attr('tabindex', '1'); 36 | 37 | $(selectable).on('focus', function(event) { 38 | var decl = $(this).closest('.declaration'); 39 | 40 | decl.addClass('active'); 41 | decl.siblings().removeClass('active'); 42 | 43 | $('.focus').removeClass('focus'); 44 | $(this).addClass('focus'); 45 | setTimeout(function () { 46 | $('.focus').selectText(); 47 | }, 0); 48 | }); 49 | $(selectable).on('mouseup click', function(event) { 50 | event.preventDefault(); 51 | event.stopPropagation(); 52 | }); 53 | $(selectable).on('mousedown', function(event) { 54 | event.preventDefault(); 55 | event.stopPropagation(); 56 | $(this).focus(); 57 | }); 58 | 59 | $('.marker').on('click', function(event) { 60 | event.preventDefault(); 61 | event.stopPropagation(); 62 | $(this).closest('.declaration').removeClass('active'); 63 | $(this).selectText(); 64 | }); 65 | 66 | $('.selector').on('click', function(event) { 67 | event.preventDefault(); 68 | var rule = $(this).closest('.rule'); 69 | var copyboard = rule.find('.copyboard'); 70 | var selector = rule.find('.selector'); 71 | var declarations = rule.find('.declaration.active'); 72 | var cssText = ''; 73 | 74 | declarations = declarations.clone(); 75 | declarations.find('svg').remove(); 76 | console.log(declarations); 77 | cssText = selector.text() + ' {'; 78 | cssText += declarations.text(); 79 | cssText += '}'; 80 | cssText = S(cssText); 81 | cssText = cssText 82 | .replaceAll(' ', '') 83 | .replaceAll('\n', '') 84 | .replaceAll('{', ' {\n ') 85 | .replaceAll(':', ': ') 86 | .replaceAll(';', ';\n ') 87 | .replaceAll(' }', '}'); 88 | copyboard.val(cssText.s).addClass('show').show().select(); 89 | $('.overlay').show(); 90 | }); 91 | 92 | 93 | $('.declaration').bind('keydown', 'up', function(event) { 94 | event.preventDefault(); 95 | event.stopPropagation(); 96 | var $this = $(this); 97 | var prev = $this.prev(); 98 | if (prev.length === 0) { return; } 99 | $this.removeClass('active'); 100 | prev.focus(); 101 | }); 102 | $('.value').bind('keydown', 'up', function(event) { 103 | event.preventDefault(); 104 | event.stopPropagation(); 105 | var $this = $(this); 106 | var decl = $this.closest('.declaration'); 107 | var prev = decl.prev(); 108 | if (prev.length === 0) { return; } 109 | var prevValue = prev.find('.value'); 110 | prev.removeClass('active'); 111 | prevValue.focus(); 112 | }); 113 | $('.declaration').bind('keydown', 'down', function(event) { 114 | event.preventDefault(); 115 | event.stopPropagation(); 116 | var $this = $(this); 117 | var next = $this.next(); 118 | if (next.length === 0) { return; } 119 | $this.removeClass('active'); 120 | next.focus(); 121 | }); 122 | $('.value').bind('keydown', 'down', function(event) { 123 | event.preventDefault(); 124 | event.stopPropagation(); 125 | var $this = $(this); 126 | var decl = $this.closest('.declaration'); 127 | var next = decl.next(); 128 | if (next.length === 0) { return; } 129 | var nextValue = next.find('.value'); 130 | next.removeClass('active'); 131 | nextValue.focus(); 132 | }); 133 | $('.declaration').bind('keydown', 'right', function(event) { 134 | event.preventDefault(); 135 | event.stopPropagation(); 136 | $(this).find('.value').focus(); 137 | }); 138 | $('.value').bind('keydown', 'left', function(event) { 139 | event.preventDefault(); 140 | event.stopPropagation(); 141 | $(this).closest('.declaration').focus(); 142 | }); 143 | $('.declaration, .value').bind('keydown', 'tab space', function(event) { 144 | event.preventDefault(); 145 | event.stopPropagation(); 146 | 147 | var nextGroup; 148 | var next; 149 | 150 | var spaceKey = event.which === 32; 151 | if (spaceKey) { 152 | $(this).closest('.declaration').removeClass('active'); 153 | } 154 | 155 | nextGroup = $(this).closest('.row-group').next('.row-group'); 156 | if (nextGroup.length === 0) { 157 | nextGroup = $(this).closest('.rule').next('.rule').find('.row-group:first'); 158 | } 159 | if (nextGroup.length === 0) { 160 | nextGroup = $(this).closest('.rules').find('.rule:first .row-group:first'); 161 | } 162 | 163 | next = nextGroup.find('.active:first'); 164 | if (next.length === 0) { 165 | nextGroup.find('.declaration:first').focus(); 166 | } else { 167 | next.focus(); 168 | } 169 | }); 170 | $('.declaration, .value').bind('keydown', 'shift+tab', function(event) { 171 | event.preventDefault(); 172 | event.stopPropagation(); 173 | 174 | var prevGroup; 175 | var prev; 176 | 177 | prevGroup = $(this).closest('.row-group').prev('.row-group'); 178 | console.log('1',prevGroup[0]); 179 | if (prevGroup.length === 0) { 180 | console.log($(this).closest('.rule')); 181 | prevGroup = $(this).closest('.rule').prev('.rule').find('.row-group:last'); 182 | } 183 | if (prevGroup.length === 0) { 184 | prevGroup = $(this).closest('.rules').find('.rule:last .row-group:last'); 185 | } 186 | 187 | prev = prevGroup.find('.active:first'); 188 | if (prev.length === 0) { 189 | prevGroup.find('.declaration:first').focus(); 190 | } else { 191 | prev.focus(); 192 | } 193 | }); 194 | 195 | $('.copyboard').on('copy', function(event) { 196 | setTimeout(function () { 197 | $('.copyboard.show').removeClass('show').hide(); 198 | }, 0); 199 | }); 200 | $('.copyboard').on('keydown', 'esc', function(event) { 201 | event.preventDefault(); 202 | $(this).hide(); 203 | }); 204 | $('.overlay').on('click', function(event) { 205 | event.preventDefault(); 206 | $('.overlay, .copyboard.show').removeClass('show').hide(); 207 | }); 208 | 209 | }, 500); 210 | 211 | }); 212 | -------------------------------------------------------------------------------- /app/assets/js/string.js: -------------------------------------------------------------------------------- 1 | /* 2 | string.js - Copyright (C) 2012-2014, JP Richardson 3 | */ 4 | 5 | !(function() { 6 | "use strict"; 7 | 8 | var VERSION = '1.9.0'; 9 | 10 | var ENTITIES = {}; 11 | 12 | //****************************************************************************** 13 | // Added an initialize function which is essentially the code from the S 14 | // constructor. Now, the S constructor calls this and a new method named 15 | // setValue calls it as well. The setValue function allows constructors for 16 | // modules that extend string.js to set the initial value of an object without 17 | // knowing the internal workings of string.js. 18 | // 19 | // Also, all methods which return a new S object now call: 20 | // 21 | // return new this.constructor(s); 22 | // 23 | // instead of: 24 | // 25 | // return new S(s); 26 | // 27 | // This allows extended objects to keep their proper instanceOf and constructor. 28 | //****************************************************************************** 29 | 30 | function initialize (object, s) { 31 | if (s !== null && s !== undefined) { 32 | if (typeof s === 'string') 33 | object.s = s; 34 | else 35 | object.s = s.toString(); 36 | } else { 37 | object.s = s; //null or undefined 38 | } 39 | 40 | object.orig = s; //original object, currently only used by toCSV() and toBoolean() 41 | 42 | if (s !== null && s !== undefined) { 43 | if (object.__defineGetter__) { 44 | object.__defineGetter__('length', function() { 45 | return object.s.length; 46 | }) 47 | } else { 48 | object.length = s.length; 49 | } 50 | } else { 51 | object.length = -1; 52 | } 53 | } 54 | 55 | function S(s) { 56 | initialize(this, s); 57 | } 58 | 59 | var __nsp = String.prototype; 60 | var __sp = S.prototype = { 61 | 62 | between: function(left, right) { 63 | var s = this.s; 64 | var startPos = s.indexOf(left); 65 | var endPos = s.indexOf(right, startPos + left.length); 66 | if (endPos == -1 && right != null) 67 | return new this.constructor('') 68 | else if (endPos == -1 && right == null) 69 | return new this.constructor(s.substring(startPos + left.length)) 70 | else 71 | return new this.constructor(s.slice(startPos + left.length, endPos)); 72 | }, 73 | 74 | //# modified slightly from https://github.com/epeli/underscore.string 75 | camelize: function() { 76 | var s = this.trim().s.replace(/(\-|_|\s)+(.)?/g, function(mathc, sep, c) { 77 | return (c ? c.toUpperCase() : ''); 78 | }); 79 | return new this.constructor(s); 80 | }, 81 | 82 | capitalize: function() { 83 | return new this.constructor(this.s.substr(0, 1).toUpperCase() + this.s.substring(1).toLowerCase()); 84 | }, 85 | 86 | charAt: function(index) { 87 | return this.s.charAt(index); 88 | }, 89 | 90 | chompLeft: function(prefix) { 91 | var s = this.s; 92 | if (s.indexOf(prefix) === 0) { 93 | s = s.slice(prefix.length); 94 | return new this.constructor(s); 95 | } else { 96 | return this; 97 | } 98 | }, 99 | 100 | chompRight: function(suffix) { 101 | if (this.endsWith(suffix)) { 102 | var s = this.s; 103 | s = s.slice(0, s.length - suffix.length); 104 | return new this.constructor(s); 105 | } else { 106 | return this; 107 | } 108 | }, 109 | 110 | //#thanks Google 111 | collapseWhitespace: function() { 112 | var s = this.s.replace(/[\s\xa0]+/g, ' ').replace(/^\s+|\s+$/g, ''); 113 | return new this.constructor(s); 114 | }, 115 | 116 | contains: function(ss) { 117 | return this.s.indexOf(ss) >= 0; 118 | }, 119 | 120 | count: function(ss) { 121 | var count = 0 122 | , pos = this.s.indexOf(ss) 123 | 124 | while (pos >= 0) { 125 | count += 1 126 | pos = this.s.indexOf(ss, pos + 1) 127 | } 128 | 129 | return count 130 | }, 131 | 132 | //#modified from https://github.com/epeli/underscore.string 133 | dasherize: function() { 134 | var s = this.trim().s.replace(/[_\s]+/g, '-').replace(/([A-Z])/g, '-$1').replace(/-+/g, '-').toLowerCase(); 135 | return new this.constructor(s); 136 | }, 137 | 138 | decodeHtmlEntities: function() { //https://github.com/substack/node-ent/blob/master/index.js 139 | var s = this.s; 140 | s = s.replace(/&#(\d+);?/g, function (_, code) { 141 | return String.fromCharCode(code); 142 | }) 143 | .replace(/&#[xX]([A-Fa-f0-9]+);?/g, function (_, hex) { 144 | return String.fromCharCode(parseInt(hex, 16)); 145 | }) 146 | .replace(/&([^;\W]+;?)/g, function (m, e) { 147 | var ee = e.replace(/;$/, ''); 148 | var target = ENTITIES[e] || (e.match(/;$/) && ENTITIES[ee]); 149 | 150 | if (typeof target === 'number') { 151 | return String.fromCharCode(target); 152 | } 153 | else if (typeof target === 'string') { 154 | return target; 155 | } 156 | else { 157 | return m; 158 | } 159 | }) 160 | 161 | return new this.constructor(s); 162 | }, 163 | 164 | endsWith: function(suffix) { 165 | var l = this.s.length - suffix.length; 166 | return l >= 0 && this.s.indexOf(suffix, l) === l; 167 | }, 168 | 169 | escapeHTML: function() { //from underscore.string 170 | return new this.constructor(this.s.replace(/[&<>"']/g, function(m){ return '&' + reversedEscapeChars[m] + ';'; })); 171 | }, 172 | 173 | ensureLeft: function(prefix) { 174 | var s = this.s; 175 | if (s.indexOf(prefix) === 0) { 176 | return this; 177 | } else { 178 | return new this.constructor(prefix + s); 179 | } 180 | }, 181 | 182 | ensureRight: function(suffix) { 183 | var s = this.s; 184 | if (this.endsWith(suffix)) { 185 | return this; 186 | } else { 187 | return new this.constructor(s + suffix); 188 | } 189 | }, 190 | 191 | humanize: function() { //modified from underscore.string 192 | if (this.s === null || this.s === undefined) 193 | return new this.constructor('') 194 | var s = this.underscore().replace(/_id$/,'').replace(/_/g, ' ').trim().capitalize() 195 | return new this.constructor(s) 196 | }, 197 | 198 | isAlpha: function() { 199 | return !/[^a-z\xDF-\xFF]/.test(this.s.toLowerCase()); 200 | }, 201 | 202 | isAlphaNumeric: function() { 203 | return !/[^0-9a-z\xDF-\xFF]/.test(this.s.toLowerCase()); 204 | }, 205 | 206 | isEmpty: function() { 207 | return this.s === null || this.s === undefined ? true : /^[\s\xa0]*$/.test(this.s); 208 | }, 209 | 210 | isLower: function() { 211 | return this.isAlpha() && this.s.toLowerCase() === this.s; 212 | }, 213 | 214 | isNumeric: function() { 215 | return !/[^0-9]/.test(this.s); 216 | }, 217 | 218 | isUpper: function() { 219 | return this.isAlpha() && this.s.toUpperCase() === this.s; 220 | }, 221 | 222 | left: function(N) { 223 | if (N >= 0) { 224 | var s = this.s.substr(0, N); 225 | return new this.constructor(s); 226 | } else { 227 | return this.right(-N); 228 | } 229 | }, 230 | 231 | lines: function() { //convert windows newlines to unix newlines then convert to an Array of lines 232 | return this.replaceAll('\r\n', '\n').s.split('\n'); 233 | }, 234 | 235 | pad: function(len, ch) { //https://github.com/component/pad 236 | if (ch == null) ch = ' '; 237 | if (this.s.length >= len) return new this.constructor(this.s); 238 | len = len - this.s.length; 239 | var left = Array(Math.ceil(len / 2) + 1).join(ch); 240 | var right = Array(Math.floor(len / 2) + 1).join(ch); 241 | return new this.constructor(left + this.s + right); 242 | }, 243 | 244 | padLeft: function(len, ch) { //https://github.com/component/pad 245 | if (ch == null) ch = ' '; 246 | if (this.s.length >= len) return new this.constructor(this.s); 247 | return new this.constructor(Array(len - this.s.length + 1).join(ch) + this.s); 248 | }, 249 | 250 | padRight: function(len, ch) { //https://github.com/component/pad 251 | if (ch == null) ch = ' '; 252 | if (this.s.length >= len) return new this.constructor(this.s); 253 | return new this.constructor(this.s + Array(len - this.s.length + 1).join(ch)); 254 | }, 255 | 256 | parseCSV: function(delimiter, qualifier, escape, lineDelimiter) { //try to parse no matter what 257 | delimiter = delimiter || ','; 258 | escape = escape || '\\' 259 | if (typeof qualifier == 'undefined') 260 | qualifier = '"'; 261 | 262 | var i = 0, fieldBuffer = [], fields = [], len = this.s.length, inField = false, inUnqualifiedString = false, self = this; 263 | var ca = function(i){return self.s.charAt(i)}; 264 | if (typeof lineDelimiter !== 'undefined') var rows = []; 265 | 266 | if (!qualifier) 267 | inField = true; 268 | 269 | while (i < len) { 270 | var current = ca(i); 271 | switch (current) { 272 | case escape: 273 | //fix for issues #32 and #35 274 | if (inField && ((escape !== qualifier) || ca(i+1) === qualifier)) { 275 | i += 1; 276 | fieldBuffer.push(ca(i)); 277 | break; 278 | } 279 | if (escape !== qualifier) break; 280 | case qualifier: 281 | inField = !inField; 282 | break; 283 | case delimiter: 284 | if(inUnqualifiedString) { 285 | inField=false; 286 | inUnqualifiedString=false; 287 | } 288 | if (inField && qualifier) 289 | fieldBuffer.push(current); 290 | else { 291 | fields.push(fieldBuffer.join('')) 292 | fieldBuffer.length = 0; 293 | } 294 | break; 295 | case lineDelimiter: 296 | if(inUnqualifiedString) { 297 | inField=false; 298 | inUnqualifiedString=false; 299 | fields.push(fieldBuffer.join('')) 300 | rows.push(fields); 301 | fields = []; 302 | fieldBuffer.length = 0; 303 | } 304 | else if (inField) { 305 | fieldBuffer.push(current); 306 | } else { 307 | if (rows) { 308 | fields.push(fieldBuffer.join('')) 309 | rows.push(fields); 310 | fields = []; 311 | fieldBuffer.length = 0; 312 | } 313 | } 314 | break; 315 | case ' ': 316 | if (inField) 317 | fieldBuffer.push(current); 318 | break; 319 | default: 320 | if (inField) 321 | fieldBuffer.push(current); 322 | else if(current!==qualifier) { 323 | fieldBuffer.push(current); 324 | inField=true; 325 | inUnqualifiedString=true; 326 | } 327 | break; 328 | } 329 | i += 1; 330 | } 331 | 332 | fields.push(fieldBuffer.join('')); 333 | if (rows) { 334 | rows.push(fields); 335 | return rows; 336 | } 337 | return fields; 338 | }, 339 | 340 | replaceAll: function(ss, r) { 341 | //var s = this.s.replace(new RegExp(ss, 'g'), r); 342 | var s = this.s.split(ss).join(r) 343 | return new this.constructor(s); 344 | }, 345 | 346 | right: function(N) { 347 | if (N >= 0) { 348 | var s = this.s.substr(this.s.length - N, N); 349 | return new this.constructor(s); 350 | } else { 351 | return this.left(-N); 352 | } 353 | }, 354 | 355 | setValue: function (s) { 356 | initialize(this, s); 357 | return this; 358 | }, 359 | 360 | slugify: function() { 361 | var sl = (new S(this.s.replace(/[^\w\s-]/g, '').toLowerCase())).dasherize().s; 362 | if (sl.charAt(0) === '-') 363 | sl = sl.substr(1); 364 | return new this.constructor(sl); 365 | }, 366 | 367 | startsWith: function(prefix) { 368 | return this.s.lastIndexOf(prefix, 0) === 0; 369 | }, 370 | 371 | stripPunctuation: function() { 372 | //return new this.constructor(this.s.replace(/[\.,-\/#!$%\^&\*;:{}=\-_`~()]/g,"")); 373 | return new this.constructor(this.s.replace(/[^\w\s]|_/g, "").replace(/\s+/g, " ")); 374 | }, 375 | 376 | stripTags: function() { //from sugar.js 377 | var s = this.s, args = arguments.length > 0 ? arguments : ['']; 378 | multiArgs(args, function(tag) { 379 | s = s.replace(RegExp('<\/?' + tag + '[^<>]*>', 'gi'), ''); 380 | }); 381 | return new this.constructor(s); 382 | }, 383 | 384 | template: function(values, opening, closing) { 385 | var s = this.s 386 | var opening = opening || Export.TMPL_OPEN 387 | var closing = closing || Export.TMPL_CLOSE 388 | 389 | var open = opening.replace(/[-[\]()*\s]/g, "\\$&").replace(/\$/g, '\\$') 390 | var close = closing.replace(/[-[\]()*\s]/g, "\\$&").replace(/\$/g, '\\$') 391 | var r = new RegExp(open + '(.+?)' + close, 'g') 392 | //, r = /\{\{(.+?)\}\}/g 393 | var matches = s.match(r) || []; 394 | 395 | matches.forEach(function(match) { 396 | var key = match.substring(opening.length, match.length - closing.length);//chop {{ and }} 397 | if (typeof values[key] != 'undefined') 398 | s = s.replace(match, values[key]); 399 | }); 400 | return new this.constructor(s); 401 | }, 402 | 403 | times: function(n) { 404 | return new this.constructor(new Array(n + 1).join(this.s)); 405 | }, 406 | 407 | toBoolean: function() { 408 | if (typeof this.orig === 'string') { 409 | var s = this.s.toLowerCase(); 410 | return s === 'true' || s === 'yes' || s === 'on' || s === '1'; 411 | } else 412 | return this.orig === true || this.orig === 1; 413 | }, 414 | 415 | toFloat: function(precision) { 416 | var num = parseFloat(this.s) 417 | if (precision) 418 | return parseFloat(num.toFixed(precision)) 419 | else 420 | return num 421 | }, 422 | 423 | toInt: function() { //thanks Google 424 | // If the string starts with '0x' or '-0x', parse as hex. 425 | return /^\s*-?0x/i.test(this.s) ? parseInt(this.s, 16) : parseInt(this.s, 10) 426 | }, 427 | 428 | trim: function() { 429 | var s; 430 | if (typeof __nsp.trim === 'undefined') 431 | s = this.s.replace(/(^\s*|\s*$)/g, '') 432 | else 433 | s = this.s.trim() 434 | return new this.constructor(s); 435 | }, 436 | 437 | trimLeft: function() { 438 | var s; 439 | if (__nsp.trimLeft) 440 | s = this.s.trimLeft(); 441 | else 442 | s = this.s.replace(/(^\s*)/g, ''); 443 | return new this.constructor(s); 444 | }, 445 | 446 | trimRight: function() { 447 | var s; 448 | if (__nsp.trimRight) 449 | s = this.s.trimRight(); 450 | else 451 | s = this.s.replace(/\s+$/, ''); 452 | return new this.constructor(s); 453 | }, 454 | 455 | truncate: function(length, pruneStr) { //from underscore.string, author: github.com/rwz 456 | var str = this.s; 457 | 458 | length = ~~length; 459 | pruneStr = pruneStr || '...'; 460 | 461 | if (str.length <= length) return new this.constructor(str); 462 | 463 | var tmpl = function(c){ return c.toUpperCase() !== c.toLowerCase() ? 'A' : ' '; }, 464 | template = str.slice(0, length+1).replace(/.(?=\W*\w*$)/g, tmpl); // 'Hello, world' -> 'HellAA AAAAA' 465 | 466 | if (template.slice(template.length-2).match(/\w\w/)) 467 | template = template.replace(/\s*\S+$/, ''); 468 | else 469 | template = new S(template.slice(0, template.length-1)).trimRight().s; 470 | 471 | return (template+pruneStr).length > str.length ? new S(str) : new S(str.slice(0, template.length)+pruneStr); 472 | }, 473 | 474 | toCSV: function() { 475 | var delim = ',', qualifier = '"', escape = '\\', encloseNumbers = true, keys = false; 476 | var dataArray = []; 477 | 478 | function hasVal(it) { 479 | return it !== null && it !== ''; 480 | } 481 | 482 | if (typeof arguments[0] === 'object') { 483 | delim = arguments[0].delimiter || delim; 484 | delim = arguments[0].separator || delim; 485 | qualifier = arguments[0].qualifier || qualifier; 486 | encloseNumbers = !!arguments[0].encloseNumbers; 487 | escape = arguments[0].escape || escape; 488 | keys = !!arguments[0].keys; 489 | } else if (typeof arguments[0] === 'string') { 490 | delim = arguments[0]; 491 | } 492 | 493 | if (typeof arguments[1] === 'string') 494 | qualifier = arguments[1]; 495 | 496 | if (arguments[1] === null) 497 | qualifier = null; 498 | 499 | if (this.orig instanceof Array) 500 | dataArray = this.orig; 501 | else { //object 502 | for (var key in this.orig) 503 | if (this.orig.hasOwnProperty(key)) 504 | if (keys) 505 | dataArray.push(key); 506 | else 507 | dataArray.push(this.orig[key]); 508 | } 509 | 510 | var rep = escape + qualifier; 511 | var buildString = []; 512 | for (var i = 0; i < dataArray.length; ++i) { 513 | var shouldQualify = hasVal(qualifier) 514 | if (typeof dataArray[i] == 'number') 515 | shouldQualify &= encloseNumbers; 516 | 517 | if (shouldQualify) 518 | buildString.push(qualifier); 519 | 520 | if (dataArray[i] !== null && dataArray[i] !== undefined) { 521 | var d = new S(dataArray[i]).replaceAll(qualifier, rep).s; 522 | buildString.push(d); 523 | } else 524 | buildString.push('') 525 | 526 | if (shouldQualify) 527 | buildString.push(qualifier); 528 | 529 | if (delim) 530 | buildString.push(delim); 531 | } 532 | 533 | //chop last delim 534 | //console.log(buildString.length) 535 | buildString.length = buildString.length - 1; 536 | return new this.constructor(buildString.join('')); 537 | }, 538 | 539 | toString: function() { 540 | return this.s; 541 | }, 542 | 543 | //#modified from https://github.com/epeli/underscore.string 544 | underscore: function() { 545 | var s = this.trim().s.replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/[-\s]+/g, '_').toLowerCase(); 546 | if ((new S(this.s.charAt(0))).isUpper()) { 547 | s = '_' + s; 548 | } 549 | return new this.constructor(s); 550 | }, 551 | 552 | unescapeHTML: function() { //from underscore.string 553 | return new this.constructor(this.s.replace(/\&([^;]+);/g, function(entity, entityCode){ 554 | var match; 555 | 556 | if (entityCode in escapeChars) { 557 | return escapeChars[entityCode]; 558 | } else if (match = entityCode.match(/^#x([\da-fA-F]+)$/)) { 559 | return String.fromCharCode(parseInt(match[1], 16)); 560 | } else if (match = entityCode.match(/^#(\d+)$/)) { 561 | return String.fromCharCode(~~match[1]); 562 | } else { 563 | return entity; 564 | } 565 | })); 566 | }, 567 | 568 | valueOf: function() { 569 | return this.s.valueOf(); 570 | }, 571 | 572 | //#Added a New Function called wrapHTML. 573 | wrapHTML: function (tagName, tagAttrs) { 574 | var s = this.s, el = (tagName == null) ? 'span' : tagName, elAttr = '', wrapped = ''; 575 | if(typeof tagAttrs == 'object') for(var prop in tagAttrs) elAttr += ' ' + prop + '="' +(new this.constructor(tagAttrs[prop])).escapeHTML() + '"'; 576 | s = wrapped.concat('<', el, elAttr, '>', this, ''); 577 | return new this.constructor(s); 578 | } 579 | } 580 | 581 | var methodsAdded = []; 582 | function extendPrototype() { 583 | for (var name in __sp) { 584 | (function(name){ 585 | var func = __sp[name]; 586 | if (!__nsp.hasOwnProperty(name)) { 587 | methodsAdded.push(name); 588 | __nsp[name] = function() { 589 | String.prototype.s = this; 590 | return func.apply(this, arguments); 591 | } 592 | } 593 | })(name); 594 | } 595 | } 596 | 597 | function restorePrototype() { 598 | for (var i = 0; i < methodsAdded.length; ++i) 599 | delete String.prototype[methodsAdded[i]]; 600 | methodsAdded.length = 0; 601 | } 602 | 603 | 604 | /************************************* 605 | /* Attach Native JavaScript String Properties 606 | /*************************************/ 607 | 608 | var nativeProperties = getNativeStringProperties(); 609 | for (var name in nativeProperties) { 610 | (function(name) { 611 | var stringProp = __nsp[name]; 612 | if (typeof stringProp == 'function') { 613 | //console.log(stringProp) 614 | if (!__sp[name]) { 615 | if (nativeProperties[name] === 'string') { 616 | __sp[name] = function() { 617 | //console.log(name) 618 | return new this.constructor(stringProp.apply(this, arguments)); 619 | } 620 | } else { 621 | __sp[name] = stringProp; 622 | } 623 | } 624 | } 625 | })(name); 626 | } 627 | 628 | 629 | /************************************* 630 | /* Function Aliases 631 | /*************************************/ 632 | 633 | __sp.repeat = __sp.times; 634 | __sp.include = __sp.contains; 635 | __sp.toInteger = __sp.toInt; 636 | __sp.toBool = __sp.toBoolean; 637 | __sp.decodeHTMLEntities = __sp.decodeHtmlEntities //ensure consistent casing scheme of 'HTML' 638 | 639 | 640 | //****************************************************************************** 641 | // Set the constructor. Without this, string.js objects are instances of 642 | // Object instead of S. 643 | //****************************************************************************** 644 | 645 | __sp.constructor = S; 646 | 647 | 648 | /************************************* 649 | /* Private Functions 650 | /*************************************/ 651 | 652 | function getNativeStringProperties() { 653 | var names = getNativeStringPropertyNames(); 654 | var retObj = {}; 655 | 656 | for (var i = 0; i < names.length; ++i) { 657 | var name = names[i]; 658 | var func = __nsp[name]; 659 | try { 660 | var type = typeof func.apply('teststring', []); 661 | retObj[name] = type; 662 | } catch (e) {} 663 | } 664 | return retObj; 665 | } 666 | 667 | function getNativeStringPropertyNames() { 668 | var results = []; 669 | if (Object.getOwnPropertyNames) { 670 | results = Object.getOwnPropertyNames(__nsp); 671 | results.splice(results.indexOf('valueOf'), 1); 672 | results.splice(results.indexOf('toString'), 1); 673 | return results; 674 | } else { //meant for legacy cruft, this could probably be made more efficient 675 | var stringNames = {}; 676 | var objectNames = []; 677 | for (var name in String.prototype) 678 | stringNames[name] = name; 679 | 680 | for (var name in Object.prototype) 681 | delete stringNames[name]; 682 | 683 | //stringNames['toString'] = 'toString'; //this was deleted with the rest of the object names 684 | for (var name in stringNames) { 685 | results.push(name); 686 | } 687 | return results; 688 | } 689 | } 690 | 691 | function Export(str) { 692 | return new S(str); 693 | }; 694 | 695 | //attach exports to StringJSWrapper 696 | Export.extendPrototype = extendPrototype; 697 | Export.restorePrototype = restorePrototype; 698 | Export.VERSION = VERSION; 699 | Export.TMPL_OPEN = '{{'; 700 | Export.TMPL_CLOSE = '}}'; 701 | Export.ENTITIES = ENTITIES; 702 | 703 | 704 | 705 | /************************************* 706 | /* Exports 707 | /*************************************/ 708 | 709 | if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { 710 | module.exports = Export; 711 | 712 | } else { 713 | 714 | if(typeof define === "function" && define.amd) { 715 | define([], function() { 716 | return Export; 717 | }); 718 | } else { 719 | window.S = Export; 720 | } 721 | } 722 | 723 | 724 | /************************************* 725 | /* 3rd Party Private Functions 726 | /*************************************/ 727 | 728 | //from sugar.js 729 | function multiArgs(args, fn) { 730 | var result = [], i; 731 | for(i = 0; i < args.length; i++) { 732 | result.push(args[i]); 733 | if(fn) fn.call(args, args[i], i); 734 | } 735 | return result; 736 | } 737 | 738 | //from underscore.string 739 | var escapeChars = { 740 | lt: '<', 741 | gt: '>', 742 | quot: '"', 743 | apos: "'", 744 | amp: '&' 745 | }; 746 | 747 | //from underscore.string 748 | var reversedEscapeChars = {}; 749 | for(var key in escapeChars){ reversedEscapeChars[escapeChars[key]] = key; } 750 | 751 | ENTITIES = { 752 | "amp" : "&", 753 | "gt" : ">", 754 | "lt" : "<", 755 | "quot" : "\"", 756 | "apos" : "'", 757 | "AElig" : 198, 758 | "Aacute" : 193, 759 | "Acirc" : 194, 760 | "Agrave" : 192, 761 | "Aring" : 197, 762 | "Atilde" : 195, 763 | "Auml" : 196, 764 | "Ccedil" : 199, 765 | "ETH" : 208, 766 | "Eacute" : 201, 767 | "Ecirc" : 202, 768 | "Egrave" : 200, 769 | "Euml" : 203, 770 | "Iacute" : 205, 771 | "Icirc" : 206, 772 | "Igrave" : 204, 773 | "Iuml" : 207, 774 | "Ntilde" : 209, 775 | "Oacute" : 211, 776 | "Ocirc" : 212, 777 | "Ograve" : 210, 778 | "Oslash" : 216, 779 | "Otilde" : 213, 780 | "Ouml" : 214, 781 | "THORN" : 222, 782 | "Uacute" : 218, 783 | "Ucirc" : 219, 784 | "Ugrave" : 217, 785 | "Uuml" : 220, 786 | "Yacute" : 221, 787 | "aacute" : 225, 788 | "acirc" : 226, 789 | "aelig" : 230, 790 | "agrave" : 224, 791 | "aring" : 229, 792 | "atilde" : 227, 793 | "auml" : 228, 794 | "ccedil" : 231, 795 | "eacute" : 233, 796 | "ecirc" : 234, 797 | "egrave" : 232, 798 | "eth" : 240, 799 | "euml" : 235, 800 | "iacute" : 237, 801 | "icirc" : 238, 802 | "igrave" : 236, 803 | "iuml" : 239, 804 | "ntilde" : 241, 805 | "oacute" : 243, 806 | "ocirc" : 244, 807 | "ograve" : 242, 808 | "oslash" : 248, 809 | "otilde" : 245, 810 | "ouml" : 246, 811 | "szlig" : 223, 812 | "thorn" : 254, 813 | "uacute" : 250, 814 | "ucirc" : 251, 815 | "ugrave" : 249, 816 | "uuml" : 252, 817 | "yacute" : 253, 818 | "yuml" : 255, 819 | "copy" : 169, 820 | "reg" : 174, 821 | "nbsp" : 160, 822 | "iexcl" : 161, 823 | "cent" : 162, 824 | "pound" : 163, 825 | "curren" : 164, 826 | "yen" : 165, 827 | "brvbar" : 166, 828 | "sect" : 167, 829 | "uml" : 168, 830 | "ordf" : 170, 831 | "laquo" : 171, 832 | "not" : 172, 833 | "shy" : 173, 834 | "macr" : 175, 835 | "deg" : 176, 836 | "plusmn" : 177, 837 | "sup1" : 185, 838 | "sup2" : 178, 839 | "sup3" : 179, 840 | "acute" : 180, 841 | "micro" : 181, 842 | "para" : 182, 843 | "middot" : 183, 844 | "cedil" : 184, 845 | "ordm" : 186, 846 | "raquo" : 187, 847 | "frac14" : 188, 848 | "frac12" : 189, 849 | "frac34" : 190, 850 | "iquest" : 191, 851 | "times" : 215, 852 | "divide" : 247, 853 | "OElig;" : 338, 854 | "oelig;" : 339, 855 | "Scaron;" : 352, 856 | "scaron;" : 353, 857 | "Yuml;" : 376, 858 | "fnof;" : 402, 859 | "circ;" : 710, 860 | "tilde;" : 732, 861 | "Alpha;" : 913, 862 | "Beta;" : 914, 863 | "Gamma;" : 915, 864 | "Delta;" : 916, 865 | "Epsilon;" : 917, 866 | "Zeta;" : 918, 867 | "Eta;" : 919, 868 | "Theta;" : 920, 869 | "Iota;" : 921, 870 | "Kappa;" : 922, 871 | "Lambda;" : 923, 872 | "Mu;" : 924, 873 | "Nu;" : 925, 874 | "Xi;" : 926, 875 | "Omicron;" : 927, 876 | "Pi;" : 928, 877 | "Rho;" : 929, 878 | "Sigma;" : 931, 879 | "Tau;" : 932, 880 | "Upsilon;" : 933, 881 | "Phi;" : 934, 882 | "Chi;" : 935, 883 | "Psi;" : 936, 884 | "Omega;" : 937, 885 | "alpha;" : 945, 886 | "beta;" : 946, 887 | "gamma;" : 947, 888 | "delta;" : 948, 889 | "epsilon;" : 949, 890 | "zeta;" : 950, 891 | "eta;" : 951, 892 | "theta;" : 952, 893 | "iota;" : 953, 894 | "kappa;" : 954, 895 | "lambda;" : 955, 896 | "mu;" : 956, 897 | "nu;" : 957, 898 | "xi;" : 958, 899 | "omicron;" : 959, 900 | "pi;" : 960, 901 | "rho;" : 961, 902 | "sigmaf;" : 962, 903 | "sigma;" : 963, 904 | "tau;" : 964, 905 | "upsilon;" : 965, 906 | "phi;" : 966, 907 | "chi;" : 967, 908 | "psi;" : 968, 909 | "omega;" : 969, 910 | "thetasym;" : 977, 911 | "upsih;" : 978, 912 | "piv;" : 982, 913 | "ensp;" : 8194, 914 | "emsp;" : 8195, 915 | "thinsp;" : 8201, 916 | "zwnj;" : 8204, 917 | "zwj;" : 8205, 918 | "lrm;" : 8206, 919 | "rlm;" : 8207, 920 | "ndash;" : 8211, 921 | "mdash;" : 8212, 922 | "lsquo;" : 8216, 923 | "rsquo;" : 8217, 924 | "sbquo;" : 8218, 925 | "ldquo;" : 8220, 926 | "rdquo;" : 8221, 927 | "bdquo;" : 8222, 928 | "dagger;" : 8224, 929 | "Dagger;" : 8225, 930 | "bull;" : 8226, 931 | "hellip;" : 8230, 932 | "permil;" : 8240, 933 | "prime;" : 8242, 934 | "Prime;" : 8243, 935 | "lsaquo;" : 8249, 936 | "rsaquo;" : 8250, 937 | "oline;" : 8254, 938 | "frasl;" : 8260, 939 | "euro;" : 8364, 940 | "image;" : 8465, 941 | "weierp;" : 8472, 942 | "real;" : 8476, 943 | "trade;" : 8482, 944 | "alefsym;" : 8501, 945 | "larr;" : 8592, 946 | "uarr;" : 8593, 947 | "rarr;" : 8594, 948 | "darr;" : 8595, 949 | "harr;" : 8596, 950 | "crarr;" : 8629, 951 | "lArr;" : 8656, 952 | "uArr;" : 8657, 953 | "rArr;" : 8658, 954 | "dArr;" : 8659, 955 | "hArr;" : 8660, 956 | "forall;" : 8704, 957 | "part;" : 8706, 958 | "exist;" : 8707, 959 | "empty;" : 8709, 960 | "nabla;" : 8711, 961 | "isin;" : 8712, 962 | "notin;" : 8713, 963 | "ni;" : 8715, 964 | "prod;" : 8719, 965 | "sum;" : 8721, 966 | "minus;" : 8722, 967 | "lowast;" : 8727, 968 | "radic;" : 8730, 969 | "prop;" : 8733, 970 | "infin;" : 8734, 971 | "ang;" : 8736, 972 | "and;" : 8743, 973 | "or;" : 8744, 974 | "cap;" : 8745, 975 | "cup;" : 8746, 976 | "int;" : 8747, 977 | "there4;" : 8756, 978 | "sim;" : 8764, 979 | "cong;" : 8773, 980 | "asymp;" : 8776, 981 | "ne;" : 8800, 982 | "equiv;" : 8801, 983 | "le;" : 8804, 984 | "ge;" : 8805, 985 | "sub;" : 8834, 986 | "sup;" : 8835, 987 | "nsub;" : 8836, 988 | "sube;" : 8838, 989 | "supe;" : 8839, 990 | "oplus;" : 8853, 991 | "otimes;" : 8855, 992 | "perp;" : 8869, 993 | "sdot;" : 8901, 994 | "lceil;" : 8968, 995 | "rceil;" : 8969, 996 | "lfloor;" : 8970, 997 | "rfloor;" : 8971, 998 | "lang;" : 9001, 999 | "rang;" : 9002, 1000 | "loz;" : 9674, 1001 | "spades;" : 9824, 1002 | "clubs;" : 9827, 1003 | "hearts;" : 9829, 1004 | "diams;" : 9830 1005 | } 1006 | 1007 | 1008 | }).call(this); 1009 | --------------------------------------------------------------------------------