├── .editorconfig ├── .gitignore ├── Gruntfile.js ├── README.md ├── bower.json ├── dev ├── spreadIt.css └── spreadit.js ├── dist ├── spreadIt.css ├── spreadit.js └── spreadit.min.js ├── example ├── index.html ├── sample.csv └── sample.xlsx ├── fonts └── arrows │ ├── select-arrows.svg │ ├── select-arrows.ttf │ └── select-arrows.woff ├── importer-screenshot.png ├── package.json ├── screenshot.png └── src ├── columnManager.html ├── dropzone.html ├── module.js ├── sass ├── _columnManager.scss ├── _dropzone.scss ├── bourbon │ ├── _bourbon-deprecated-upcoming.scss │ ├── _bourbon.scss │ ├── addons │ │ ├── _border-color.scss │ │ ├── _border-radius.scss │ │ ├── _border-style.scss │ │ ├── _border-width.scss │ │ ├── _buttons.scss │ │ ├── _clearfix.scss │ │ ├── _ellipsis.scss │ │ ├── _font-stacks.scss │ │ ├── _hide-text.scss │ │ ├── _margin.scss │ │ ├── _padding.scss │ │ ├── _position.scss │ │ ├── _prefixer.scss │ │ ├── _retina-image.scss │ │ ├── _size.scss │ │ ├── _text-inputs.scss │ │ ├── _timing-functions.scss │ │ ├── _triangle.scss │ │ └── _word-wrap.scss │ ├── css3 │ │ ├── _animation.scss │ │ ├── _appearance.scss │ │ ├── _backface-visibility.scss │ │ ├── _background-image.scss │ │ ├── _background.scss │ │ ├── _border-image.scss │ │ ├── _calc.scss │ │ ├── _columns.scss │ │ ├── _filter.scss │ │ ├── _flex-box.scss │ │ ├── _font-face.scss │ │ ├── _font-feature-settings.scss │ │ ├── _hidpi-media-query.scss │ │ ├── _hyphens.scss │ │ ├── _image-rendering.scss │ │ ├── _keyframes.scss │ │ ├── _linear-gradient.scss │ │ ├── _perspective.scss │ │ ├── _placeholder.scss │ │ ├── _radial-gradient.scss │ │ ├── _selection.scss │ │ ├── _text-decoration.scss │ │ ├── _transform.scss │ │ ├── _transition.scss │ │ └── _user-select.scss │ ├── functions │ │ ├── _assign-inputs.scss │ │ ├── _contains-falsy.scss │ │ ├── _contains.scss │ │ ├── _is-length.scss │ │ ├── _is-light.scss │ │ ├── _is-number.scss │ │ ├── _is-size.scss │ │ ├── _modular-scale.scss │ │ ├── _px-to-em.scss │ │ ├── _px-to-rem.scss │ │ ├── _shade.scss │ │ ├── _strip-units.scss │ │ ├── _tint.scss │ │ ├── _transition-property-name.scss │ │ └── _unpack.scss │ ├── helpers │ │ ├── _convert-units.scss │ │ ├── _directional-values.scss │ │ ├── _font-source-declaration.scss │ │ ├── _gradient-positions-parser.scss │ │ ├── _linear-angle-parser.scss │ │ ├── _linear-gradient-parser.scss │ │ ├── _linear-positions-parser.scss │ │ ├── _linear-side-corner-parser.scss │ │ ├── _radial-arg-parser.scss │ │ ├── _radial-gradient-parser.scss │ │ ├── _radial-positions-parser.scss │ │ ├── _render-gradients.scss │ │ ├── _shape-size-stripper.scss │ │ └── _str-to-num.scss │ └── settings │ │ ├── _asset-pipeline.scss │ │ ├── _prefixer.scss │ │ └── _px-to-em.scss └── spreadIt.scss ├── siColumnManager.directive.js ├── siDropZone.directive.js ├── siTrigger.directive.js └── spreadIt.service.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = false 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Node template 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like istanbul 17 | coverage 18 | 19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 20 | .grunt 21 | 22 | # node-waf configuration 23 | .lock-wscript 24 | 25 | # Compiled binary addons (http://nodejs.org/api/addons.html) 26 | build/Release 27 | 28 | # Dependency directories 29 | node_modules 30 | jspm_packages 31 | 32 | # Optional npm cache directory 33 | .npm 34 | 35 | # Optional REPL history 36 | .node_repl_history 37 | 38 | bower_components/ 39 | .tmp/ 40 | .sass-cache/ 41 | 42 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | // Project configuration. 6 | grunt.initConfig({ 7 | 8 | pkg: grunt.file.readJSON('package.json'), 9 | concurrent: { 10 | example: { 11 | tasks: ['serve', 'watch:dev', 'open:example'], 12 | options: { 13 | logConcurrentOutput: true 14 | } 15 | } 16 | }, 17 | open: { 18 | example: { 19 | url: 'http://localhost:9099/example/index.html' 20 | } 21 | }, 22 | copy: { 23 | dist: { 24 | expand: true, 25 | cwd: 'src', 26 | dest: 'dist', 27 | src: ['images/**/*'] 28 | }, 29 | dev: { 30 | expand: true, 31 | cwd: 'src', 32 | dest: 'dev', 33 | src: ['images/**/*'] 34 | } 35 | }, 36 | ngtemplates: { 37 | all: { 38 | options: { 39 | module: 'bg.spreadit', 40 | prefix: '/', 41 | htmlmin: { 42 | collapseWhitespace: true, 43 | keepClosingSlash: true 44 | } 45 | }, 46 | cwd: 'src', 47 | src: '**/*.html', 48 | dest: '.tmp/spreadit.templates.js' 49 | } 50 | }, 51 | clean: { 52 | dist: ['.tmp', 'dist'], 53 | dev: ['.tmp', 'dev'] 54 | }, 55 | concat: { 56 | dist: { 57 | src: ['src/module.js', 'src/**/*.js', '.tmp/**/*.js'], 58 | dest: 'dist/spreadit.js' 59 | }, 60 | dev: { 61 | src: ['src/module.js', 'src/**/*.js', '.tmp/**/*.js'], 62 | dest: 'dev/spreadit.js' 63 | } 64 | }, 65 | uglify: { 66 | dist: { 67 | files: { 68 | 'dist/spreadit.min.js': ['dist/spreadit.js'] 69 | } 70 | } 71 | }, 72 | sass: { 73 | options: { 74 | style: 'compressed', 75 | sourcemap: 'none' 76 | }, 77 | dist: { 78 | expand: true, 79 | cwd: 'src/sass', 80 | src: ['**/*.scss'], 81 | dest: 'dist', 82 | ext: '.css' 83 | }, 84 | dev: { 85 | expand: true, 86 | cwd: 'src/sass', 87 | src: ['**/*.scss'], 88 | dest: 'dev', 89 | ext: '.css' 90 | } 91 | }, 92 | watch: { 93 | dev: { 94 | files: ['src/**/*', 'example/**/*'], 95 | tasks: 'dev', 96 | options: { 97 | livereload: false 98 | } 99 | } 100 | }, 101 | serve: { 102 | options: { 103 | port: 9099 104 | } 105 | } 106 | }); 107 | 108 | grunt.registerTask('build', [ 109 | 'clean:dist', 110 | 'copy:dist', 111 | 'ngtemplates', 112 | 'concat:dist', 113 | 'uglify', 114 | 'sass:dist' 115 | ]); 116 | 117 | grunt.registerTask('dev', [ 118 | 'clean:dev', 119 | 'copy:dev', 120 | 'ngtemplates', 121 | 'concat:dev', 122 | 'sass:dev' 123 | ]); 124 | 125 | grunt.registerTask('example', [ 126 | 'clean:dev', 127 | 'copy:dev', 128 | 'ngtemplates', 129 | 'concat:dev', 130 | 'sass:dev', 131 | 'concurrent:example' 132 | ]); 133 | 134 | 135 | }; 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spreadit - Spreadsheet data importing simplified and 100% in the browser. 2 | 3 | Spreadit is an angular directive inspired by the guys at [Conference Badge](https://www.conferencebadge.com/). It imports data from Excel or CSV as JSON so it 4 | can be used in the browser or uploaded to the server. It supports header and column detection. Users can also rename and ignore columns before importing the data. 5 | 6 | ![It's A Screenshot!](screenshot.png) 7 | ![It's Another Screenshot!](importer-screenshot.png) 8 | 9 | ## Install It 10 | * **Manual**: download latest from [here](https://github.com/blakgeek/spreadit/releases/latest) 11 | * **Bower**: `bower install spreadit --save` 12 | * **NPM**: `npm install spreadit` 13 | 14 | ## See It In Action 15 | * [Basic Example](https://jsfiddle.net/blakgeek/vumyL0x1/show) 16 | * [Configure Columns](https://jsfiddle.net/blakgeek/q50cLjnz/show) 17 | * [Restrict Columns](https://jsfiddle.net/blakgeek/y2yfqydp/show) 18 | * [Post-process Data](https://jsfiddle.net/blakgeek/L4t7beeo/show) 19 | 20 | ## Code Sample 21 | HTML: 22 | ```html 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 41 | 42 | ``` 43 | Javascript: 44 | ```js 45 | var app = angular.module('superDopeDemo', ['bg.spreadit']); 46 | 47 | app.controller('MyCtrl', ['$scope', function ($scope) { 48 | 49 | $scope.doStuffWithData = function(data, file, type) { 50 | 51 | console.log('file type: %s', type); 52 | console.log(data); 53 | }; 54 | 55 | $scope.columns = [ 56 | // matches becasue of title 57 | { 58 | title: 'Email', 59 | property: 'emailAddress' 60 | }, 61 | // matches because of property 62 | { 63 | title: 'Last Name', 64 | property: 'last_name' 65 | }, 66 | // matches because of alias 67 | { 68 | title: 'First Name', 69 | property: 'firstName', 70 | aliases: ['first_name', 'first'] 71 | } 72 | ]; 73 | 74 | $scope.postProcessors = [ 75 | 76 | // concatenate first and last name to form a full name 77 | function (data) { 78 | if (data.firstName || data.last_name) { 79 | data.fullName = data.firstName + ' ' + data.last_name; 80 | } 81 | return data; 82 | }, 83 | // capitalize full name 84 | function (data) { 85 | if (data.fullName) { 86 | data.fullName = data.fullName.toUpperCase(); 87 | } 88 | return data; 89 | } 90 | ] 91 | }]); 92 | ``` 93 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spreadit", 3 | "description": "Spreadsheet data importing simplified and 100% in the browser.", 4 | "main": [ 5 | "dist/spreadit.js", 6 | "dist/spreadit.css" 7 | ], 8 | "authors": [ 9 | "Carlos \"blakgeek\" Lawton" 10 | ], 11 | "license": "MIT", 12 | "keywords": [ 13 | "spreadsheet", 14 | "angular", 15 | "angularjs", 16 | "javascript", 17 | "import", 18 | "xls", 19 | "xlsx", 20 | "csv", 21 | "tsv" 22 | ], 23 | "homepage": "https://github.com/blakgeek/spreadit", 24 | "ignore": [ 25 | "**/.*", 26 | "node_modules", 27 | "bower_components", 28 | "test", 29 | "tests" 30 | ], 31 | "dependencies": { 32 | "angular": "<2", 33 | "js-xlsx": "^0.8.0", 34 | "papaparse": "^4.1.2", 35 | "lodash": "^4.11.2" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /dev/spreadIt.css: -------------------------------------------------------------------------------- 1 | si-column-manager{position:fixed;top:0;left:0;bottom:0;right:0;visibility:hidden;background-color:rgba(255,255,255,0.95);z-index:2000}si-column-manager ul{list-style:none;margin:0;padding:0}si-column-manager.active{visibility:visible}si-column-manager header{position:absolute;top:0;right:0;left:0;margin:10px auto}si-column-manager footer{position:absolute;bottom:0;right:0;left:0;margin:10px auto}si-column-manager .si-toggle{display:-webkit-box;display:-moz-box;display:box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-moz-box-align:center;box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-ms-flex-align:center;white-space:nowrap}si-column-manager .si-toggle input[type="checkbox"]{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;appearance:none;display:none}si-column-manager .si-toggle input[type="checkbox"]:checked+i{background-color:#52a552}si-column-manager .si-toggle input[type="checkbox"]:checked+i:after{right:0;left:auto}si-column-manager .si-toggle i{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;-webkit-flex:0 0 40px;-moz-flex:0 0 40px;-ms-flex:0 0 40px;flex:0 0 40px;height:25px;position:relative;background-color:#f0f0f0;border-radius:25px;margin-right:8px}si-column-manager .si-toggle i:after{content:'';display:block;background-color:white;border-radius:20px;height:21px;width:21px;margin:2px;position:absolute;left:0;top:0}si-column-manager .si-column-manager-actions{display:-webkit-box;display:-moz-box;display:box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-moz-box-align:center;box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-ms-flex-align:center;width:calc(100% - 40px);max-width:800px}si-column-manager .si-column-manager-actions button{height:40px;padding:0 20px;font-size:inherit;font-family:inherit}si-column-manager .si-column-manager-actions .si-has-header{margin-right:auto}si-column-manager .si-column-manager-actions .si-close{line-height:40px;width:40px;text-align:center;border-radius:4px;font-size:24px;font-weight:bold;cursor:pointer}si-column-manager .si-column-manager-actions .si-close:hover{background-color:rgba(0,0,0,0.05)}si-column-manager .si-column-manager-actions .si-import{background-color:#52a552;color:white;text-shadow:0 1px 1px rgba(0,0,0,0.03);border:1px solid #56944a;border-radius:4px}si-column-manager footer.si-column-manager-actions{-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;-webkit-justify-content:flex-end;-moz-justify-content:flex-end;-ms-justify-content:flex-end;-o-justify-content:flex-end;justify-content:flex-end;-ms-flex-pack:end}si-column-manager .si-column-manager-columns{left:0;right:0;top:0;bottom:0;position:absolute;margin:60px auto 60px;width:calc(100% - 40px);max-width:800px;counter-reset:column-counter;border-bottom:1px solid #ccc;border-top:1px solid #ccc;box-shadow:0 0 20px -4px rgba(0,0,0,0.2);overflow-y:auto;background-color:white}si-column-manager .si-column-manager-columns .si-column-manager-column{display:-webkit-box;display:-moz-box;display:box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;border:1px solid #ccc;border-bottom:none}si-column-manager .si-column-manager-columns .si-column-manager-column.si-column-ignored .si-column-manager-samples{text-decoration:line-through;color:#ccc}si-column-manager .si-column-manager-samples{counter-reset:sample-counter;-webkit-flex-grow:1;-moz-flex-grow:1;flex-grow:1;-ms-flex-positive:1;position:relative}si-column-manager .si-column-manager-samples .si-column-manager-sample-title{font-weight:bold;font-size:20px}si-column-manager .si-column-manager-samples .si-column-manager-sample-title:before{line-height:40px !important}si-column-manager .si-column-manager-samples li:last-of-type{border-bottom:none !important}si-column-manager .si-column-manager-samples .si-column-manager-sample-header{background-color:#e8e8e8;display:-webkit-box;display:-moz-box;display:box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-moz-box-align:center;box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-ms-flex-align:center;border-bottom:1px solid #ccc}si-column-manager .si-column-manager-samples .si-column-manager-sample-header:before{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;-webkit-flex:0 0 30px;-moz-flex:0 0 30px;-ms-flex:0 0 30px;flex:0 0 30px;background-color:#e8e8e8;display:block;line-height:30px;text-align:center;margin-right:10px;content:'\00a0';border-right:1px solid #ccc}si-column-manager .si-column-manager-samples .si-column-manager-sample-header:after{display:block;content:counter(column-counter,upper-alpha);counter-increment:column-counter;text-align:center;-webkit-flex-grow:1;-moz-flex-grow:1;flex-grow:1;-ms-flex-positive:1}si-column-manager .si-column-manager-samples .si-column-manager-sample{display:-webkit-box;display:-moz-box;display:box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-moz-box-align:center;box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-ms-flex-align:center;border-bottom:1px solid #ccc}si-column-manager .si-column-manager-samples .si-column-manager-sample:before{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;-webkit-flex:0 0 30px;-moz-flex:0 0 30px;-ms-flex:0 0 30px;flex:0 0 30px;background-color:#e8e8e8;display:block;line-height:30px;text-align:center;content:counter(sample-counter,decimal);counter-increment:sample-counter;margin-right:10px;border-right:1px solid #ccc;font-size:1rem;font-weight:normal}si-column-manager .si-column-manager-editor{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;-webkit-flex:0 0 300px;-moz-flex:0 0 300px;-ms-flex:0 0 300px;flex:0 0 300px;padding:20px;position:relative}si-column-manager .si-column-manager-editor input{width:100%;font-family:inherit;font-size:inherit;height:40px;padding:12px;box-sizing:border-box}si-column-manager .si-column-manager-editor .select-group{width:100%;box-sizing:border-box;margin-bottom:10px;position:relative;display:-webkit-box;display:-moz-box;display:box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-moz-box-align:center;box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-ms-flex-align:center;padding:0 10px;border:1px solid #ccc;background-color:white;color:black;border-radius:3px;height:40px}si-column-manager .si-column-manager-editor .select-group:after{font-family:Arrows;content:'\e901';margin-left:auto;display:inline-block;-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;-webkit-flex:0 0 auto;-moz-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto}si-column-manager .si-column-manager-editor .select-group select{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;appearance:none;position:absolute;top:0;left:0;width:100%;height:100%;opacity:0}si-column-manager .si-column-manager-editor label{margin-bottom:6px;font-size:20px;font-weight:bold;display:block}si-column-manager .si-column-manager-editor:after{background:linear-gradient(-45deg, #fff 9px, transparent 0),linear-gradient(-135deg, #fff 9px, transparent 0),linear-gradient(-45deg, #ccc 10px, transparent 0),linear-gradient(-135deg, #ccc 10px, transparent 0);background-position:left-bottom;background-repeat:repeat-y;background-size:20px 20px;content:" ";display:block;position:absolute;top:0;left:-20px;width:20px;height:100%;bottom:0}si-dropzone{display:-webkit-box;display:-moz-box;display:box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;-webkit-justify-content:center;-moz-justify-content:center;-ms-justify-content:center;-o-justify-content:center;justify-content:center;-ms-flex-pack:center;-webkit-box-align:center;-moz-box-align:center;box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-ms-flex-align:center;height:160px;border:1px #a0a0a0 dashed;border-radius:5px;width:calc(100% - 40px);max-width:800px;margin:20px auto 30px;box-sizing:border-box;position:relative;cursor:pointer;background-color:white;-webkit-transition:box-shadow 350ms;-moz-transition:box-shadow 350ms;transition:box-shadow 350ms}si-dropzone:hover{border-color:#303030;box-shadow:0 0 20px -4px rgba(0,0,0,0.4)}si-dropzone .si-icon{margin-left:20px;-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;-webkit-flex:0 0 65px;-moz-flex:0 0 65px;-ms-flex:0 0 65px;flex:0 0 65px}si-dropzone .si-icon path{fill:#303030}si-dropzone .message{margin-right:20px;margin-left:10px;color:#303030;font-weight:normal;cursor:inherit}si-dropzone .message h2{font-size:20px;margin:0}si-dropzone .message p{margin:0}si-dropzone input[type="file"]{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;appearance:none;opacity:0;position:absolute;top:0;left:0;width:100% !important;height:100% !important;cursor:inherit}@font-face{font-family:'Arrows';src:url("../fonts/arrows/select-arrows.ttf?lym46w") format("truetype"),url("../fonts/arrows/select-arrows.woff?lym46w") format("woff"),url("../fonts/arrows/select-arrows.svg?lym46w#select-arrows") format("svg");font-weight:normal;font-style:normal} 2 | -------------------------------------------------------------------------------- /dev/spreadit.js: -------------------------------------------------------------------------------- 1 | +function() { 2 | 3 | angular.module('bg.spreadit', []); 4 | }(); 5 | +function () { 6 | 'use strict'; 7 | 8 | angular.module('bg.spreadit').directive("siColumnManager", ['$timeout', '$parse', '$rootScope', directive]); 9 | 10 | function directive($timeout, $parse, $rootScope) { 11 | var supports = { 12 | xls: !!(window.XLSX && XLSX.utils), 13 | csv: !!(window.Papa && Papa.parse) 14 | }; 15 | 16 | return { 17 | restrict: 'E', 18 | scope: { 19 | id: '@?siId', 20 | callback: '&?siChange', 21 | columns: '=?siColumns', 22 | sampleSize: '=?siSampleSize', 23 | excludeUnknownColumns: '=?siExcludeUnknownColumns', 24 | allowRenaming: '=?siAllowRenaming', 25 | // TODO: add support for these flags 26 | unknownColumnsGroupName: '=?siUnknownColumnsGroupName', 27 | groupUnknownColumns: '=?siGroupUnknownColumns', 28 | postProcessors: '=?siPostProcessors' 29 | }, 30 | controller: ['$scope', '$element', '$attrs', controller], 31 | controllerAs: 'vm', 32 | templateUrl: '/columnManager.html' 33 | }; 34 | 35 | function controller($scope, $element, $attrs) { 36 | 37 | _.defaults($scope, { 38 | id: "", 39 | columns: [], 40 | postProcessors: [], 41 | sampleSize: 3, 42 | excludeUnknownColumns: false, 43 | allowCustomRenaming: true, 44 | unknownColumnGroupName: '$extras', 45 | groupUnknownColumns: false, 46 | callback: angular.noop 47 | }); 48 | 49 | var self = this; 50 | var columnMap = $scope.columns.reduce(function (map, entry) { 51 | 52 | var val; 53 | if (angular.isString(entry)) { 54 | val = { 55 | title: entry, 56 | property: entry 57 | }; 58 | } else { 59 | val = entry; 60 | } 61 | 62 | map[String(val.property).trim().toLowerCase()] = val; 63 | map[String(val.title).trim().toLowerCase()] = val; 64 | if (angular.isArray(entry.aliases)) { 65 | entry.aliases.forEach(function (alias) { 66 | map[String(alias).trim().toLowerCase()] = val; 67 | }); 68 | } 69 | return map; 70 | }, {}); 71 | var titles = _.flatten($scope.columns.map(function (v) { 72 | if (angular.isString(v)) { 73 | return v; 74 | } else if (angular.isArray(v.aliases)) { 75 | return v.aliases.concat(v.title); 76 | } else { 77 | return v.title; 78 | } 79 | })).map(function (v) { 80 | return String(v).trim().toLowerCase(); 81 | }); 82 | 83 | var presult; 84 | var $file; 85 | 86 | $scope.$watch('hasHeader', function () { 87 | 88 | if ($file && self.active) { 89 | parseFile($file); 90 | } 91 | }); 92 | 93 | this.remap = function (mapping) { 94 | 95 | remap(mapping); 96 | this.active = false; 97 | $element.removeClass('active'); 98 | }; 99 | 100 | this.cancel = function () { 101 | this.active = false; 102 | $element.removeClass('active'); 103 | }; 104 | 105 | function isHeader(values) { 106 | 107 | var isIt = $scope.hasHeader || values.some(function (value) { 108 | return titles.indexOf(String(value).trim().toLowerCase()) !== -1; 109 | }); 110 | $scope.hasHeader = isIt; 111 | return isIt; 112 | } 113 | 114 | function isExcel(data) { 115 | return [0xD0, 0x09, 0x3C, 0x50].indexOf(data.charCodeAt(0)) !== -1; 116 | } 117 | 118 | function parseFile(file) { 119 | 120 | if (!file) { 121 | return; 122 | } 123 | 124 | var reader = new FileReader(); 125 | 126 | if (reader.readAsBinaryString) { 127 | 128 | reader.onload = function (e) { 129 | preparse(file, e.target.result); 130 | }; 131 | 132 | reader.readAsBinaryString(file); 133 | } else { 134 | 135 | reader.onload = function (e) { 136 | 137 | /* convert data to binary string */ 138 | var data = new Uint8Array(e.target.result); 139 | var buffer = []; 140 | var i; 141 | for (i = 0; i < data.length; i++) { 142 | buffer[i] = String.fromCharCode(data[i]); 143 | } 144 | preparse(file, buffer.join('')); 145 | }; 146 | reader.readAsArrayBuffer(file) 147 | } 148 | } 149 | 150 | function preparse(file, content) { 151 | 152 | if (supports.xls && isExcel(content)) { 153 | preparseExcel(content); 154 | } else if (supports.csv) { 155 | preparseCSV(file); 156 | } 157 | } 158 | 159 | 160 | function preparseExcel(content) { 161 | 162 | var c; 163 | var workbook = XLSX.read(content, { 164 | type: 'binary', 165 | sheetRows: $scope.sampleSize + 1, 166 | cellHTML: false, 167 | cellFormula: false 168 | }); 169 | var sheet = workbook.Sheets[workbook.SheetNames[0]]; 170 | var headerRange = XLSX.utils.decode_range(sheet['!ref']); 171 | var firstRow = []; 172 | var r = headerRange.s.r; 173 | for (c = headerRange.s.c; c < headerRange.e.c; c++) { 174 | var cell = sheet[XLSX.utils.encode_cell({r: r, c: c})]; 175 | firstRow.push(cell ? String(cell.v).toLowerCase() : null); 176 | } 177 | 178 | var headers; 179 | var i = 1; 180 | if (!isHeader(firstRow)) { 181 | headers = []; 182 | for (c = headerRange.s.c; c <= headerRange.e.c; c++) { 183 | headers.push('Column ' + i++); 184 | } 185 | } 186 | var data = XLSX.utils.sheet_to_json(sheet, { 187 | header: headers, 188 | range: 0 189 | }).slice(0, 3); 190 | 191 | if ($scope.debug) { 192 | window.$spreadIt = { 193 | workbook: workbook, 194 | sheet: sheet, 195 | content: content 196 | } 197 | } 198 | preview({ 199 | type: 'excel', 200 | raw: content, 201 | data: data, 202 | headers: headers || Object.keys(data[0]) 203 | }); 204 | } 205 | 206 | function preparseCsvWithHeader(file) { 207 | 208 | Papa.parse(file, { 209 | header: true, 210 | preview: $scope.sampleSize, 211 | complete: function (result) { 212 | 213 | var headers = Object.keys(result.data[0]); 214 | preview({ 215 | type: 'csv', 216 | data: result.data, 217 | raw: file, 218 | headers: headers 219 | }); 220 | } 221 | }); 222 | } 223 | 224 | function preparseCsvSansHeader(file) { 225 | 226 | Papa.parse(file, { 227 | header: false, 228 | preview: $scope.sampleSize, 229 | complete: function (result) { 230 | 231 | var headers = result.data[0].map(function (column, i) { 232 | return 'Column ' + (i + 1); 233 | }); 234 | 235 | var data = result.data.map(function (columns) { 236 | 237 | var obj = {}; 238 | columns.forEach(function (column, i) { 239 | obj['Column ' + (i + 1)] = column; 240 | }); 241 | return obj; 242 | }); 243 | preview({ 244 | type: 'csv', 245 | headers: headers, 246 | data: data, 247 | raw: file 248 | }); 249 | } 250 | }); 251 | } 252 | 253 | function preparseCSV(file) { 254 | Papa.parse(file, { 255 | preview: 1, 256 | complete: function (result) { 257 | var firstRow = result.data[0]; 258 | if (firstRow && isHeader(firstRow)) { 259 | preparseCsvWithHeader(file); 260 | } else { 261 | preparseCsvSansHeader(file); 262 | } 263 | } 264 | }); 265 | } 266 | 267 | function parseExcel(content, headers) { 268 | var c; 269 | var workbook = XLSX.read(content, { 270 | type: 'binary', 271 | cellHTML: false, 272 | cellFormula: false 273 | }); 274 | var sheet = workbook.Sheets[workbook.SheetNames[0]]; 275 | var headerRange = XLSX.utils.decode_range(sheet['!ref']); 276 | var firstRow = []; 277 | var r = headerRange.s.r; 278 | for (c = headerRange.s.c; c < headerRange.e.c; c++) { 279 | var cell = sheet[XLSX.utils.encode_cell({r: r, c: c})]; 280 | firstRow.push(cell ? String(cell.v).toLowerCase() : null); 281 | } 282 | 283 | var data = XLSX.utils.sheet_to_json(sheet, { 284 | header: headers, 285 | range: isHeader(firstRow) ? 1 : 0 286 | }).map(function (result) { 287 | 288 | delete result.$skip$; 289 | return result; 290 | }); 291 | 292 | 293 | $scope.callback({ 294 | $type: 'excel', 295 | $file: $file, 296 | $data: postProcess(data) 297 | }); 298 | } 299 | 300 | function parseCsv(file, headers) { 301 | 302 | Papa.parse(file, { 303 | header: false, 304 | complete: function (result) { 305 | 306 | var firstRow = result.data[0]; 307 | if (isHeader(firstRow)) { 308 | result.data.splice(0, 1); 309 | } 310 | var data = result.data.map(function (columns) { 311 | 312 | var obj = {}; 313 | columns.forEach(function (column, i) { 314 | 315 | if (headers[i] !== '$skip$') { 316 | obj[headers[i]] = column; 317 | } 318 | }); 319 | return obj; 320 | }); 321 | $scope.callback({ 322 | $type: 'csv', 323 | $file: $file, 324 | $data: postProcess(data) 325 | }); 326 | } 327 | }); 328 | } 329 | 330 | function preview(result) { 331 | 332 | $timeout(function () { 333 | 334 | var preview = self.preview = []; 335 | 336 | result.headers.forEach(function (header) { 337 | 338 | var normalizedHeader = header.toLowerCase().trim(); 339 | var mapping; 340 | if (columnMap[normalizedHeader]) { 341 | mapping = columnMap[normalizedHeader]; 342 | } else if ($scope.excludeUnknownColumns) { 343 | mapping = { 344 | title: 'Ignore This Column', 345 | property: '$skip$' 346 | } 347 | } else { 348 | mapping = { 349 | title: 'Keep This Column', 350 | property: false 351 | }; 352 | } 353 | preview.push({ 354 | header: header, 355 | mapping: mapping, 356 | custom: header, 357 | sample: result.data.map(function (v) { 358 | return v[header]; 359 | }) 360 | }); 361 | }); 362 | var titles = []; 363 | if (!$scope.excludeUnknownColumns) { 364 | titles.push({ 365 | title: 'Keep This Column', 366 | property: false 367 | }); 368 | } 369 | 370 | titles.push({ 371 | title: 'Ignore This Column', 372 | property: '$skip$' 373 | }); 374 | 375 | if (!$scope.excludeUnknownColumns && $scope.allowCustomRenaming) { 376 | titles.push({ 377 | title: 'Rename This Column', 378 | property: '$rename$' 379 | }); 380 | } 381 | 382 | self.titles = titles.concat($scope.columns.map(function (column) { 383 | 384 | if (angular.isObject(column)) { 385 | return column; 386 | } 387 | 388 | return { 389 | title: column, 390 | property: column 391 | } 392 | })); 393 | presult = result; 394 | }); 395 | } 396 | 397 | function remap(mapping) { 398 | 399 | var headers = mapping.map(function (column) { 400 | 401 | var mapping = column.mapping; 402 | if (mapping.property === false) { 403 | return column.header; 404 | } else if (mapping.property === '$rename$') { 405 | return column.custom; 406 | } else { 407 | return column.mapping.property; 408 | } 409 | }); 410 | if (presult.type === 'csv') { 411 | parseCsv(presult.raw, headers); 412 | } else { 413 | parseExcel(presult.raw, headers); 414 | } 415 | } 416 | 417 | $rootScope.$on('si.preview', function (e, id, file) { 418 | 419 | if (file && id === $scope.id) { 420 | $file = file; 421 | $scope.hasHeader = false; 422 | parseFile(file); 423 | self.active = true; 424 | $element.addClass('active'); 425 | } 426 | }); 427 | 428 | function postProcess(data) { 429 | 430 | if(!$scope.postProcessors.length) { 431 | return data; 432 | } 433 | 434 | return data.map(function(obj) { 435 | 436 | $scope.postProcessors.forEach(function(fn) { 437 | fn(obj); 438 | }); 439 | return obj; 440 | }) 441 | } 442 | } 443 | } 444 | 445 | }(); 446 | 447 | +function () { 448 | 'use strict'; 449 | 450 | angular.module('bg.spreadit').directive("siDropzone", ['$rootScope', directive]); 451 | angular.module('bg.spreadit').directive("siImporter", ['$rootScope', directive]); 452 | 453 | function directive($rootScope) { 454 | var accepts = []; 455 | 456 | if(!!(window.XLSX && XLSX.utils)) { 457 | accepts.push('.xls', '.xlsx'); 458 | } 459 | 460 | if(!!(window.Papa && Papa.parse)) { 461 | accepts.push('.csv', '.tsv', '.txt'); 462 | } 463 | 464 | return { 465 | restrict: 'E', 466 | scope: { 467 | id: '@siId' 468 | }, 469 | controller: controller, 470 | controllerAs: 'vm', 471 | templateUrl: '/dropzone.html', 472 | link: link 473 | }; 474 | 475 | function controller() { 476 | 477 | } 478 | 479 | function link($scope, $element, $attrs) { 480 | 481 | _.defaults($scope, { 482 | id: "" 483 | }); 484 | 485 | var element = $element[0]; 486 | element.setAttribute('accepts', accepts.join()); 487 | element.querySelector('input[type="file"]').addEventListener('change', function (e) { 488 | $rootScope.$emit('si.preview', $scope.id, e.target.files[0]); 489 | }); 490 | } 491 | } 492 | 493 | }(); 494 | 495 | +function () { 496 | 'use strict'; 497 | 498 | angular.module('bg.spreadit').directive("siFileSelect", ['$rootScope', directive]); 499 | angular.module('bg.spreadit').directive("siTrigger", ['$rootScope', directive]); 500 | 501 | function directive($rootScope) { 502 | var accepts = []; 503 | 504 | if(!!(window.XLSX && XLSX.utils)) { 505 | accepts.push('.xls', '.xlsx'); 506 | } 507 | 508 | if(!!(window.Papa && Papa.parse)) { 509 | accepts.push('.csv', '.tsv', '.txt'); 510 | } 511 | 512 | return { 513 | restrict: 'EA', 514 | scope: { 515 | id: '@?siFileSelect' 516 | }, 517 | link: link 518 | }; 519 | 520 | function link($scope, $element, $attrs) { 521 | 522 | var element = $element[0]; 523 | var fileEl = $element; 524 | var tagName = element.tagName.toLowerCase(); 525 | var isFileInput = tagName === 'input' && $attrs.type && $attrs.type.toLowerCase() === 'file'; 526 | var isLink = tagName === 'a'; 527 | 528 | if(angular.isDefined($attrs.siFileSelect)) { 529 | $scope.id = $attrs.siFileSelect; 530 | } 531 | 532 | if (!isFileInput) { 533 | fileEl = angular.element(''); 534 | var label = angular.element(''); 535 | label.css('visibility', 'hidden').css('position', 'absolute').css('overflow', 'hidden') 536 | .css('width', '0px').css('height', '0px').css('border', 'none') 537 | .css('margin', '0px').css('padding', '0px').attr('tabindex', '-1'); 538 | document.body.appendChild(label.append(fileEl)[0]); 539 | $element.on('click', function(e) { 540 | e.preventDefault(); 541 | fileEl[0].click(); 542 | }); 543 | } 544 | 545 | if(isLink) { 546 | $element.attr('href', 'javascript:'); 547 | } 548 | 549 | fileEl.attr('accepts', accepts.join()); 550 | fileEl.on('change', onChange); 551 | 552 | function onChange(e) { 553 | $rootScope.$emit('si.preview', $scope.id, e.target.files[0]); 554 | } 555 | } 556 | } 557 | 558 | }(); 559 | 560 | +function () { 561 | 'use strict'; 562 | 563 | angular.module('bg.spreadit').service("Spreadit", ['$rootScope', service]); 564 | 565 | function service($rootScope) { 566 | 567 | } 568 | 569 | }(); 570 | 571 | angular.module('bg.spreadit').run(['$templateCache', function($templateCache) { 572 | 'use strict'; 573 | 574 | $templateCache.put('/columnManager.html', 575 | "
×
" 576 | ); 577 | 578 | 579 | $templateCache.put('/dropzone.html', 580 | "

Wanna Import a spreadsheet (Excel or CSV)?

Click here or drag and drop your file like it's hot.

" 586 | ); 587 | 588 | }]); 589 | -------------------------------------------------------------------------------- /dist/spreadIt.css: -------------------------------------------------------------------------------- 1 | si-column-manager{position:fixed;top:0;left:0;bottom:0;right:0;visibility:hidden;background-color:rgba(255,255,255,0.95);z-index:2000}si-column-manager ul{list-style:none;margin:0;padding:0}si-column-manager.active{visibility:visible}si-column-manager header{position:absolute;top:0;right:0;left:0;margin:10px auto}si-column-manager footer{position:absolute;bottom:0;right:0;left:0;margin:10px auto}si-column-manager .si-toggle{display:-webkit-box;display:-moz-box;display:box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-moz-box-align:center;box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-ms-flex-align:center;white-space:nowrap}si-column-manager .si-toggle input[type="checkbox"]{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;appearance:none;display:none}si-column-manager .si-toggle input[type="checkbox"]:checked+i{background-color:#52a552}si-column-manager .si-toggle input[type="checkbox"]:checked+i:after{right:0;left:auto}si-column-manager .si-toggle i{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;-webkit-flex:0 0 40px;-moz-flex:0 0 40px;-ms-flex:0 0 40px;flex:0 0 40px;height:25px;position:relative;background-color:#f0f0f0;border-radius:25px;margin-right:8px}si-column-manager .si-toggle i:after{content:'';display:block;background-color:white;border-radius:20px;height:21px;width:21px;margin:2px;position:absolute;left:0;top:0}si-column-manager .si-column-manager-actions{display:-webkit-box;display:-moz-box;display:box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-moz-box-align:center;box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-ms-flex-align:center;width:calc(100% - 40px);max-width:800px}si-column-manager .si-column-manager-actions button{height:40px;padding:0 20px;font-size:inherit;font-family:inherit}si-column-manager .si-column-manager-actions .si-has-header{margin-right:auto}si-column-manager .si-column-manager-actions .si-close{line-height:40px;width:40px;text-align:center;border-radius:4px;font-size:24px;font-weight:bold;cursor:pointer}si-column-manager .si-column-manager-actions .si-close:hover{background-color:rgba(0,0,0,0.05)}si-column-manager .si-column-manager-actions .si-import{background-color:#52a552;color:white;text-shadow:0 1px 1px rgba(0,0,0,0.03);border:1px solid #56944a;border-radius:4px}si-column-manager footer.si-column-manager-actions{-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;-webkit-justify-content:flex-end;-moz-justify-content:flex-end;-ms-justify-content:flex-end;-o-justify-content:flex-end;justify-content:flex-end;-ms-flex-pack:end}si-column-manager .si-column-manager-columns{left:0;right:0;top:0;bottom:0;position:absolute;margin:60px auto 60px;width:calc(100% - 40px);max-width:800px;counter-reset:column-counter;border-bottom:1px solid #ccc;border-top:1px solid #ccc;box-shadow:0 0 20px -4px rgba(0,0,0,0.2);overflow-y:auto;background-color:white}si-column-manager .si-column-manager-columns .si-column-manager-column{display:-webkit-box;display:-moz-box;display:box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;border:1px solid #ccc;border-bottom:none}si-column-manager .si-column-manager-columns .si-column-manager-column.si-column-ignored .si-column-manager-samples{text-decoration:line-through;color:#ccc}si-column-manager .si-column-manager-samples{counter-reset:sample-counter;-webkit-flex-grow:1;-moz-flex-grow:1;flex-grow:1;-ms-flex-positive:1;position:relative}si-column-manager .si-column-manager-samples .si-column-manager-sample-title{font-weight:bold;font-size:20px}si-column-manager .si-column-manager-samples .si-column-manager-sample-title:before{line-height:40px !important}si-column-manager .si-column-manager-samples li:last-of-type{border-bottom:none !important}si-column-manager .si-column-manager-samples .si-column-manager-sample-header{background-color:#e8e8e8;display:-webkit-box;display:-moz-box;display:box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-moz-box-align:center;box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-ms-flex-align:center;border-bottom:1px solid #ccc}si-column-manager .si-column-manager-samples .si-column-manager-sample-header:before{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;-webkit-flex:0 0 30px;-moz-flex:0 0 30px;-ms-flex:0 0 30px;flex:0 0 30px;background-color:#e8e8e8;display:block;line-height:30px;text-align:center;margin-right:10px;content:'\00a0';border-right:1px solid #ccc}si-column-manager .si-column-manager-samples .si-column-manager-sample-header:after{display:block;content:counter(column-counter,upper-alpha);counter-increment:column-counter;text-align:center;-webkit-flex-grow:1;-moz-flex-grow:1;flex-grow:1;-ms-flex-positive:1}si-column-manager .si-column-manager-samples .si-column-manager-sample{display:-webkit-box;display:-moz-box;display:box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-moz-box-align:center;box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-ms-flex-align:center;border-bottom:1px solid #ccc}si-column-manager .si-column-manager-samples .si-column-manager-sample:before{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;-webkit-flex:0 0 30px;-moz-flex:0 0 30px;-ms-flex:0 0 30px;flex:0 0 30px;background-color:#e8e8e8;display:block;line-height:30px;text-align:center;content:counter(sample-counter,decimal);counter-increment:sample-counter;margin-right:10px;border-right:1px solid #ccc;font-size:1rem;font-weight:normal}si-column-manager .si-column-manager-editor{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;-webkit-flex:0 0 300px;-moz-flex:0 0 300px;-ms-flex:0 0 300px;flex:0 0 300px;padding:20px;position:relative}si-column-manager .si-column-manager-editor input{width:100%;font-family:inherit;font-size:inherit;height:40px;padding:12px;box-sizing:border-box}si-column-manager .si-column-manager-editor .select-group{width:100%;box-sizing:border-box;margin-bottom:10px;position:relative;display:-webkit-box;display:-moz-box;display:box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-moz-box-align:center;box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-ms-flex-align:center;padding:0 10px;border:1px solid #ccc;background-color:white;color:black;border-radius:3px;height:40px}si-column-manager .si-column-manager-editor .select-group:after{font-family:Arrows;content:'\e901';margin-left:auto;display:inline-block;-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;-webkit-flex:0 0 auto;-moz-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto}si-column-manager .si-column-manager-editor .select-group select{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;appearance:none;position:absolute;top:0;left:0;width:100%;height:100%;opacity:0}si-column-manager .si-column-manager-editor label{margin-bottom:6px;font-size:20px;font-weight:bold;display:block}si-column-manager .si-column-manager-editor:after{background:linear-gradient(-45deg, #fff 9px, transparent 0),linear-gradient(-135deg, #fff 9px, transparent 0),linear-gradient(-45deg, #ccc 10px, transparent 0),linear-gradient(-135deg, #ccc 10px, transparent 0);background-position:left-bottom;background-repeat:repeat-y;background-size:20px 20px;content:" ";display:block;position:absolute;top:0;left:-20px;width:20px;height:100%;bottom:0}si-dropzone{display:-webkit-box;display:-moz-box;display:box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;-webkit-justify-content:center;-moz-justify-content:center;-ms-justify-content:center;-o-justify-content:center;justify-content:center;-ms-flex-pack:center;-webkit-box-align:center;-moz-box-align:center;box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-ms-flex-align:center;height:160px;border:1px #a0a0a0 dashed;border-radius:5px;width:calc(100% - 40px);max-width:800px;margin:20px auto 30px;box-sizing:border-box;position:relative;cursor:pointer;background-color:white;-webkit-transition:box-shadow 350ms;-moz-transition:box-shadow 350ms;transition:box-shadow 350ms}si-dropzone:hover{border-color:#303030;box-shadow:0 0 20px -4px rgba(0,0,0,0.4)}si-dropzone .si-icon{margin-left:20px;-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;-webkit-flex:0 0 65px;-moz-flex:0 0 65px;-ms-flex:0 0 65px;flex:0 0 65px}si-dropzone .si-icon path{fill:#303030}si-dropzone .message{margin-right:20px;margin-left:10px;color:#303030;font-weight:normal;cursor:inherit}si-dropzone .message h2{font-size:20px;margin:0}si-dropzone .message p{margin:0}si-dropzone input[type="file"]{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;appearance:none;opacity:0;position:absolute;top:0;left:0;width:100% !important;height:100% !important;cursor:inherit}@font-face{font-family:'Arrows';src:url("../fonts/arrows/select-arrows.ttf?lym46w") format("truetype"),url("../fonts/arrows/select-arrows.woff?lym46w") format("woff"),url("../fonts/arrows/select-arrows.svg?lym46w#select-arrows") format("svg");font-weight:normal;font-style:normal} 2 | -------------------------------------------------------------------------------- /dist/spreadit.min.js: -------------------------------------------------------------------------------- 1 | +function(){angular.module("bg.spreadit",[])}(),+function(){"use strict";function a(a,b,c){function d(b,d,f){function g(a){var c=b.hasHeader||a.some(function(a){return-1!==x.indexOf(String(a).trim().toLowerCase())});return b.hasHeader=c,c}function h(a){return-1!==[208,9,60,80].indexOf(a.charCodeAt(0))}function i(a){if(a){var b=new FileReader;b.readAsBinaryString?(b.onload=function(b){j(a,b.target.result)},b.readAsBinaryString(a)):(b.onload=function(b){var c,d=new Uint8Array(b.target.result),e=[];for(c=0;c');var l=angular.element("");l.css("visibility","hidden").css("position","absolute").css("overflow","hidden").css("width","0px").css("height","0px").css("border","none").css("margin","0px").css("padding","0px").attr("tabindex","-1"),document.body.appendChild(l.append(h)[0]),d.on("click",function(a){a.preventDefault(),h[0].click()})}k&&d.attr("href","javascript:"),h.attr("accepts",c.join()),h.on("change",f)}var c=[];return window.XLSX&&XLSX.utils&&c.push(".xls",".xlsx"),window.Papa&&Papa.parse&&c.push(".csv",".tsv",".txt"),{restrict:"EA",scope:{id:"@?siFileSelect"},link:b}}angular.module("bg.spreadit").directive("siFileSelect",["$rootScope",a]),angular.module("bg.spreadit").directive("siTrigger",["$rootScope",a])}(),+function(){"use strict";function a(a){}angular.module("bg.spreadit").service("Spreadit",["$rootScope",a])}(),angular.module("bg.spreadit").run(["$templateCache",function(a){"use strict";a.put("/columnManager.html",'
×
'),a.put("/dropzone.html",'

Wanna Import a spreadsheet (Excel or CSV)?

Click here or drag and drop your file like it\'s hot.

')}]); -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Spreadit Demo 6 | 7 | 8 | 54 | 55 | 56 |
57 | 58 | 59 | 60 | 61 | 62 | 63 |
64 | 65 | 68 | 69 | 70 | 73 | 74 | 78 | 79 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 134 | 135 | -------------------------------------------------------------------------------- /example/sample.csv: -------------------------------------------------------------------------------- 1 | id,first_name,last_name,email,gender,ip_address 2 | 1,Robin,Parker,rparker0@adobe.com,Female,57.233.108.210 3 | 2,Joyce,Reynolds,jreynolds1@hugedomains.com,Female,129.125.90.145 4 | 3,Pamela,Freeman,pfreeman2@163.com,Female,58.29.172.21 5 | 4,Angela,Nichols,anichols3@huffingtonpost.com,Female,94.19.251.40 6 | 5,Lawrence,Spencer,lspencer4@bizjournals.com,Male,50.107.175.59 7 | 6,Julia,Montgomery,jmontgomery5@globo.com,Female,79.244.198.237 8 | 7,Gloria,Greene,ggreene6@parallels.com,Female,209.45.239.143 9 | 8,Daniel,Miller,dmiller7@dion.ne.jp,Male,7.236.23.77 10 | 9,Terry,Nguyen,tnguyen8@de.vu,Male,60.16.127.120 11 | 10,Rose,Jones,rjones9@geocities.jp,Female,149.90.190.214 12 | 11,Albert,Gray,agraya@gizmodo.com,Male,172.158.251.68 13 | 12,Douglas,Burns,dburnsb@netlog.com,Male,18.243.232.149 14 | 13,Ruby,Hansen,rhansenc@tinypic.com,Female,55.158.112.244 15 | 14,Elizabeth,Thomas,ethomasd@google.es,Female,212.201.231.20 16 | 15,Ashley,Carpenter,acarpentere@cornell.edu,Female,136.249.115.187 17 | 16,Sharon,Fox,sfoxf@feedburner.com,Female,15.102.110.182 18 | 17,Kimberly,Jackson,kjacksong@businesswire.com,Female,76.35.79.37 19 | 18,Mary,Little,mlittleh@mtv.com,Female,217.46.149.59 20 | 19,Henry,Garcia,hgarciai@e-recht24.de,Male,88.59.59.30 21 | 20,Joshua,Owens,jowensj@is.gd,Male,91.227.198.91 22 | 21,Evelyn,Wright,ewrightk@ustream.tv,Female,241.101.137.232 23 | 22,Barbara,Smith,bsmithl@guardian.co.uk,Female,42.26.163.120 24 | 23,Henry,Gonzales,hgonzalesm@mac.com,Male,37.35.170.253 25 | 24,Larry,Vasquez,lvasquezn@gnu.org,Male,80.30.235.250 26 | 25,Janet,Welch,jwelcho@hud.gov,Female,182.66.31.193 27 | 26,Frances,Fowler,ffowlerp@redcross.org,Female,154.92.7.21 28 | 27,Angela,Cox,acoxq@si.edu,Female,167.223.205.252 29 | 28,Henry,Andrews,handrewsr@sun.com,Male,34.105.213.72 30 | 29,Walter,Frazier,wfraziers@123-reg.co.uk,Male,121.207.248.168 31 | 30,Joyce,Kelly,jkellyt@scientificamerican.com,Female,57.168.0.55 32 | 31,Terry,Stephens,tstephensu@clickbank.net,Male,204.56.114.219 33 | 32,Russell,Edwards,redwardsv@cbsnews.com,Male,45.134.23.179 34 | 33,Helen,Boyd,hboydw@ameblo.jp,Female,31.248.43.237 35 | 34,Susan,Ferguson,sfergusonx@uiuc.edu,Female,34.177.104.172 36 | 35,Kenneth,Ortiz,kortizy@google.co.jp,Male,209.233.114.78 37 | 36,Bonnie,Day,bdayz@archive.org,Female,97.151.182.199 38 | 37,Russell,Allen,rallen10@rambler.ru,Male,88.159.60.139 39 | 38,Lillian,Cruz,lcruz11@house.gov,Female,216.221.154.192 40 | 39,Wayne,Ferguson,wferguson12@hostgator.com,Male,2.228.83.166 41 | 40,Catherine,Tucker,ctucker13@last.fm,Female,136.16.207.52 42 | 41,Johnny,Collins,jcollins14@wordpress.com,Male,59.240.137.66 43 | 42,Elizabeth,Weaver,eweaver15@usatoday.com,Female,243.43.50.232 44 | 43,Victor,Diaz,vdiaz16@comsenz.com,Male,250.207.218.12 45 | 44,Patrick,Taylor,ptaylor17@aboutads.info,Male,31.78.183.53 46 | 45,Ruth,Garza,rgarza18@cloudflare.com,Female,193.35.7.241 47 | 46,Eric,Green,egreen19@un.org,Male,208.115.114.15 48 | 47,Sharon,Fields,sfields1a@walmart.com,Female,201.84.150.113 49 | 48,Lisa,Montgomery,lmontgomery1b@ifeng.com,Female,236.120.118.122 50 | 49,Kathy,Reynolds,kreynolds1c@apache.org,Female,54.244.56.244 51 | 50,Louise,Stewart,lstewart1d@liveinternet.ru,Female,111.123.66.30 52 | 51,Jonathan,Rivera,jrivera1e@cocolog-nifty.com,Male,54.245.153.221 53 | 52,Paul,Price,pprice1f@storify.com,Male,186.10.142.95 54 | 53,Amanda,Bishop,abishop1g@disqus.com,Female,153.191.108.49 55 | 54,Ruth,Mills,rmills1h@macromedia.com,Female,0.23.187.193 56 | 55,Donald,Patterson,dpatterson1i@dot.gov,Male,173.146.245.86 57 | 56,Shawn,Taylor,staylor1j@nhs.uk,Male,68.60.201.240 58 | 57,Heather,Stevens,hstevens1k@disqus.com,Female,138.20.167.31 59 | 58,Carolyn,Alexander,calexander1l@bing.com,Female,155.15.224.206 60 | 59,Sean,Welch,swelch1m@exblog.jp,Male,217.194.90.192 61 | 60,Carl,Bishop,cbishop1n@census.gov,Male,18.167.146.150 62 | 61,Sandra,Johnston,sjohnston1o@europa.eu,Female,57.159.14.77 63 | 62,Rebecca,Daniels,rdaniels1p@google.ru,Female,107.115.158.160 64 | 63,Howard,Morris,hmorris1q@tamu.edu,Male,226.74.252.243 65 | 64,Rachel,Welch,rwelch1r@imgur.com,Female,139.125.3.150 66 | 65,Russell,Torres,rtorres1s@hibu.com,Male,25.233.48.44 67 | 66,Andrew,James,ajames1t@surveymonkey.com,Male,209.213.136.2 68 | 67,Helen,Jordan,hjordan1u@mysql.com,Female,155.90.57.202 69 | 68,Paula,Willis,pwillis1v@xinhuanet.com,Female,182.235.216.133 70 | 69,Jason,Gardner,jgardner1w@nifty.com,Male,159.254.244.49 71 | 70,Douglas,Graham,dgraham1x@seesaa.net,Male,180.75.190.237 72 | 71,Stephanie,Rivera,srivera1y@sourceforge.net,Female,232.57.216.204 73 | 72,Wayne,Morales,wmorales1z@alexa.com,Male,69.75.5.47 74 | 73,Christopher,Kelly,ckelly20@arizona.edu,Male,187.107.178.37 75 | 74,Nancy,Gordon,ngordon21@multiply.com,Female,163.149.194.248 76 | 75,Judy,Franklin,jfranklin22@google.de,Female,253.113.100.51 77 | 76,Laura,Nelson,lnelson23@statcounter.com,Female,32.200.227.150 78 | 77,Judy,Banks,jbanks24@reference.com,Female,160.94.78.104 79 | 78,Jimmy,Arnold,jarnold25@linkedin.com,Male,189.153.8.124 80 | 79,Janet,Myers,jmyers26@jimdo.com,Female,53.81.202.3 81 | 80,Rebecca,Bishop,rbishop27@statcounter.com,Female,235.207.8.133 82 | 81,Fred,Black,fblack28@newyorker.com,Male,36.175.7.244 83 | 82,Harry,Harrison,hharrison29@ehow.com,Male,161.107.17.226 84 | 83,Diana,Flores,dflores2a@spiegel.de,Female,52.134.213.82 85 | 84,Katherine,Edwards,kedwards2b@bloglines.com,Female,78.73.183.8 86 | 85,Diane,Howell,dhowell2c@salon.com,Female,158.172.24.102 87 | 86,Harold,Welch,hwelch2d@ning.com,Male,135.17.58.249 88 | 87,Jean,Franklin,jfranklin2e@free.fr,Female,169.163.147.254 89 | 88,Tammy,Hall,thall2f@unesco.org,Female,126.40.80.22 90 | 89,Julie,Matthews,jmatthews2g@seesaa.net,Female,94.53.71.164 91 | 90,Ann,Boyd,aboyd2h@washington.edu,Female,214.103.149.43 92 | 91,Evelyn,Fox,efox2i@taobao.com,Female,14.12.173.215 93 | 92,Amy,Moore,amoore2j@ask.com,Female,56.196.98.125 94 | 93,Anne,Gray,agray2k@printfriendly.com,Female,231.245.141.184 95 | 94,Diane,Martin,dmartin2l@bizjournals.com,Female,127.225.182.49 96 | 95,Rose,Alvarez,ralvarez2m@wired.com,Female,240.8.61.170 97 | 96,Martha,Ellis,mellis2n@usnews.com,Female,18.230.235.105 98 | 97,Sandra,Ryan,sryan2o@a8.net,Female,65.161.158.156 99 | 98,Irene,Gray,igray2p@berkeley.edu,Female,126.224.255.223 100 | 99,Stephen,Garrett,sgarrett2q@rakuten.co.jp,Male,79.232.241.175 101 | 100,Carolyn,Garza,cgarza2r@cnet.com,Female,242.154.162.54 102 | -------------------------------------------------------------------------------- /example/sample.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakgeek/spreadit/9d600a5f20031b719838cef4b33bcf9a57c015c5/example/sample.xlsx -------------------------------------------------------------------------------- /fonts/arrows/select-arrows.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /fonts/arrows/select-arrows.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakgeek/spreadit/9d600a5f20031b719838cef4b33bcf9a57c015c5/fonts/arrows/select-arrows.ttf -------------------------------------------------------------------------------- /fonts/arrows/select-arrows.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakgeek/spreadit/9d600a5f20031b719838cef4b33bcf9a57c015c5/fonts/arrows/select-arrows.woff -------------------------------------------------------------------------------- /importer-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakgeek/spreadit/9d600a5f20031b719838cef4b33bcf9a57c015c5/importer-screenshot.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spreadit", 3 | "version": "1.0.5", 4 | "description": "Spreadsheet data importing simplified and 100% in the browser", 5 | "main": "Gruntfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/blakgeek/spreadit.git" 12 | }, 13 | "keywords": [ 14 | "spreadsheet", 15 | "angular", 16 | "angularjs", 17 | "javascript", 18 | "import", 19 | "xls", 20 | "xlsx", 21 | "csv", 22 | "tsv" 23 | ], 24 | "author": "Carlos \"blakgeek\" Lawton", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/blakgeek/spreadit/issues" 28 | }, 29 | "homepage": "https://github.com/blakgeek/spreadit#readme", 30 | "devDependencies": { 31 | "grunt": "^0.4.5", 32 | "grunt-angular-templates": "^1.0.3", 33 | "grunt-bower-concat": "^1.0.0", 34 | "grunt-concurrent": "^2.3.0", 35 | "grunt-contrib-clean": "^1.0.0", 36 | "grunt-contrib-concat": "^1.0.1", 37 | "grunt-contrib-copy": "^1.0.0", 38 | "grunt-contrib-sass": "^1.0.0", 39 | "grunt-contrib-uglify": "^1.0.1", 40 | "grunt-contrib-watch": "^1.0.0", 41 | "grunt-open": "^0.2.3", 42 | "grunt-serve": "^0.1.6", 43 | "load-grunt-tasks": "^3.5.0" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakgeek/spreadit/9d600a5f20031b719838cef4b33bcf9a57c015c5/screenshot.png -------------------------------------------------------------------------------- /src/columnManager.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | × 4 |
5 | 28 | -------------------------------------------------------------------------------- /src/dropzone.html: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 |
10 |

Wanna Import a spreadsheet (Excel or CSV)?

11 |

Click here or drag and drop your file like it's hot.

12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /src/module.js: -------------------------------------------------------------------------------- 1 | +function() { 2 | 3 | angular.module('bg.spreadit', []); 4 | }(); -------------------------------------------------------------------------------- /src/sass/_columnManager.scss: -------------------------------------------------------------------------------- 1 | $siPositiveColor: #52a552 !default; 2 | $siPositiveBorder: darken(adjust-hue($siPositiveColor, -10), 5%) !default; 3 | 4 | si-column-manager { 5 | 6 | ul { 7 | list-style: none; 8 | margin: 0; 9 | padding: 0; 10 | } 11 | 12 | position: fixed; 13 | top: 0; 14 | left: 0; 15 | bottom: 0; 16 | right: 0; 17 | visibility: hidden; 18 | background-color: rgba(white, .95); 19 | z-index: 2000; 20 | 21 | &.active { 22 | visibility: visible; 23 | } 24 | 25 | header { 26 | 27 | position: absolute; 28 | top: 0; 29 | right: 0; 30 | left: 0; 31 | margin: 10px auto; 32 | } 33 | 34 | footer { 35 | 36 | position: absolute; 37 | bottom: 0; 38 | right: 0; 39 | left: 0; 40 | margin: 10px auto; 41 | } 42 | 43 | .si-toggle { 44 | @include display(flex); 45 | @include align-items(center); 46 | white-space: nowrap; 47 | 48 | input[type="checkbox"] { 49 | @include appearance(none); 50 | display: none; 51 | 52 | &:checked + i { 53 | background-color: $siPositiveColor; 54 | &:after { 55 | right: 0; 56 | left: auto; 57 | } 58 | } 59 | } 60 | 61 | i { 62 | @include flex(0 0 40px); 63 | height: 25px; 64 | position: relative; 65 | background-color: #f0f0f0; 66 | border-radius: 25px; 67 | margin-right: 8px; 68 | 69 | &:after { 70 | content: ''; 71 | display: block; 72 | background-color: white; 73 | border-radius: 20px; 74 | height: 21px; 75 | width: 21px; 76 | margin: 2px; 77 | position: absolute; 78 | left: 0; 79 | top: 0; 80 | } 81 | } 82 | } 83 | 84 | .si-column-manager-actions { 85 | 86 | @include display(flex); 87 | @include align-items(center); 88 | width: calc(100% - 40px); 89 | max-width: 800px; 90 | 91 | 92 | button { 93 | height: 40px; 94 | padding: 0 20px; 95 | font-size: inherit; 96 | font-family: inherit; 97 | } 98 | 99 | .si-has-header { 100 | margin-right: auto; 101 | } 102 | 103 | .si-close { 104 | 105 | line-height: 40px; 106 | width: 40px; 107 | text-align: center; 108 | border-radius: 4px; 109 | font-size: 24px; 110 | font-weight: bold; 111 | cursor: pointer; 112 | 113 | &:hover { 114 | background-color: rgba(black, .05); 115 | } 116 | } 117 | 118 | .si-import { 119 | 120 | background-color: $siPositiveColor; 121 | color: white; 122 | text-shadow: 0 1px 1px rgba(black, .03); 123 | border: 1px solid $siPositiveBorder; 124 | border-radius: 4px; 125 | } 126 | 127 | } 128 | 129 | header.si-column-manager-actions { 130 | 131 | 132 | } 133 | 134 | footer.si-column-manager-actions { 135 | 136 | @include justify-content(flex-end); 137 | } 138 | 139 | .si-column-manager-columns { 140 | 141 | left: 0; 142 | right: 0; 143 | top: 0; 144 | bottom: 0; 145 | position: absolute; 146 | margin: 60px auto 60px; 147 | width: calc(100% - 40px); 148 | max-width: 800px; 149 | counter-reset: column-counter; 150 | border-bottom: 1px solid #ccc; 151 | border-top: 1px solid #ccc; 152 | box-shadow: 0 0 20px -4px rgba(0,0,0,.2); 153 | overflow-y: auto; 154 | background-color: white; 155 | 156 | .si-column-manager-column { 157 | @include display(flex); 158 | border: 1px solid #ccc; 159 | border-bottom: none; 160 | //margin-bottom: 20px; 161 | 162 | &.si-column-ignored { 163 | 164 | .si-column-manager-samples { 165 | text-decoration: line-through; 166 | color: #ccc; 167 | } 168 | } 169 | } 170 | } 171 | 172 | .si-column-manager-samples { 173 | 174 | counter-reset: sample-counter; 175 | @include flex-grow(1); 176 | position: relative; 177 | 178 | .si-column-manager-sample-title { 179 | font-weight: bold; 180 | font-size: 20px; 181 | 182 | &:before { 183 | line-height: 40px !important; 184 | } 185 | } 186 | 187 | li:last-of-type { 188 | border-bottom: none !important; 189 | } 190 | 191 | .si-column-manager-sample-header { 192 | 193 | background-color: #e8e8e8; 194 | @include display(flex); 195 | @include align-items(center); 196 | border-bottom: 1px solid #ccc; 197 | 198 | &:before { 199 | @include flex(0 0 30px); 200 | background-color: #e8e8e8; 201 | display: block; 202 | line-height: 30px; 203 | text-align: center; 204 | margin-right: 10px; 205 | content: '\00a0'; 206 | border-right: 1px solid #ccc; 207 | } 208 | &:after { 209 | display: block; 210 | content: counter(column-counter, upper-alpha); 211 | counter-increment: column-counter; 212 | text-align: center; 213 | @include flex-grow(1); 214 | } 215 | } 216 | 217 | 218 | .si-column-manager-sample { 219 | @include display(flex); 220 | @include align-items(center); 221 | border-bottom: 1px solid #ccc; 222 | 223 | &:before { 224 | @include flex(0 0 30px); 225 | background-color: #e8e8e8; 226 | display: block; 227 | line-height: 30px; 228 | text-align: center; 229 | content: counter(sample-counter, decimal); 230 | counter-increment: sample-counter; 231 | margin-right: 10px; 232 | border-right: 1px solid #ccc; 233 | font-size: 1rem; 234 | font-weight: normal; 235 | } 236 | } 237 | } 238 | 239 | .si-column-manager-editor { 240 | @include flex(0 0 300px); 241 | padding: 20px; 242 | position: relative; 243 | 244 | input { 245 | width: 100%; 246 | font-family: inherit; 247 | font-size: inherit; 248 | height: 40px; 249 | padding: 12px; 250 | box-sizing: border-box; 251 | } 252 | 253 | .select-group { 254 | width: 100%; 255 | box-sizing: border-box; 256 | margin-bottom: 10px; 257 | position: relative; 258 | @include display(flex); 259 | @include align-items(center); 260 | padding: 0 10px; 261 | border: 1px solid #ccc; 262 | background-color: white; 263 | color: black; 264 | border-radius: 3px; 265 | height: 40px; 266 | 267 | &:after { 268 | font-family: Arrows; 269 | content: '\e901'; 270 | margin-left: auto; 271 | display: inline-block; 272 | @include flex(0 0 auto); 273 | } 274 | 275 | select { 276 | @include appearance(none); 277 | position: absolute; 278 | top: 0; 279 | left: 0; 280 | width: 100%; 281 | height: 100%; 282 | opacity: 0; 283 | } 284 | } 285 | 286 | label { 287 | margin-bottom: 6px; 288 | font-size: 20px; 289 | font-weight: bold; 290 | display: block; 291 | } 292 | 293 | &:after { 294 | background: linear-gradient(-45deg, white 9px, transparent 0), linear-gradient(-135deg, white 9px, transparent 0), 295 | linear-gradient(-45deg, #ccc 10px, transparent 0), linear-gradient(-135deg, #ccc 10px, transparent 0); 296 | background-position: left-bottom; 297 | background-repeat: repeat-y; 298 | background-size: 20px 20px; 299 | content: " "; 300 | display: block; 301 | position: absolute; 302 | top: 0; 303 | left: -20px; 304 | width: 20px; 305 | height: 100%; 306 | bottom: 0; 307 | } 308 | } 309 | } -------------------------------------------------------------------------------- /src/sass/_dropzone.scss: -------------------------------------------------------------------------------- 1 | si-dropzone { 2 | @include display(flex); 3 | @include justify-content(center); 4 | @include align-items(center); 5 | height: 160px; 6 | border: 1px #a0a0a0 dashed; 7 | border-radius: 5px; 8 | width: calc(100% - 40px); 9 | max-width: 800px; 10 | margin: 20px auto 30px; 11 | box-sizing: border-box; 12 | position: relative; 13 | cursor: pointer; 14 | background-color: white; 15 | @include transition(box-shadow 350ms); 16 | 17 | &:hover { 18 | border-color: #303030; 19 | box-shadow: 0 0 20px -4px rgba(0,0,0,.4); 20 | } 21 | 22 | .si-icon { 23 | margin-left: 20px; 24 | @include flex(0 0 65px); 25 | 26 | path { 27 | fill: #303030; 28 | } 29 | } 30 | 31 | .message { 32 | 33 | margin-right: 20px; 34 | margin-left: 10px; 35 | color: #303030; 36 | font-weight: normal; 37 | cursor: inherit; 38 | 39 | h2 { 40 | font-size: 20px; 41 | margin: 0; 42 | } 43 | 44 | p { 45 | margin: 0; 46 | } 47 | } 48 | 49 | input[type="file"] { 50 | @include appearance(none); 51 | opacity: 0; 52 | position: absolute; 53 | top: 0; 54 | left: 0; 55 | width: 100% !important; 56 | height: 100% !important; 57 | cursor: inherit; 58 | } 59 | } -------------------------------------------------------------------------------- /src/sass/bourbon/_bourbon-deprecated-upcoming.scss: -------------------------------------------------------------------------------- 1 | // The following features have been deprecated and will be removed in the next MAJOR version release 2 | 3 | @mixin inline-block { 4 | display: inline-block; 5 | 6 | @warn "The inline-block mixin is deprecated and will be removed in the next major version release"; 7 | } 8 | 9 | @mixin button ($style: simple, $base-color: #4294f0, $text-size: inherit, $padding: 7px 18px) { 10 | 11 | @if type-of($style) == string and type-of($base-color) == color { 12 | @include buttonstyle($style, $base-color, $text-size, $padding); 13 | } 14 | 15 | @if type-of($style) == string and type-of($base-color) == number { 16 | $padding: $text-size; 17 | $text-size: $base-color; 18 | $base-color: #4294f0; 19 | 20 | @if $padding == inherit { 21 | $padding: 7px 18px; 22 | } 23 | 24 | @include buttonstyle($style, $base-color, $text-size, $padding); 25 | } 26 | 27 | @if type-of($style) == color and type-of($base-color) == color { 28 | $base-color: $style; 29 | $style: simple; 30 | @include buttonstyle($style, $base-color, $text-size, $padding); 31 | } 32 | 33 | @if type-of($style) == color and type-of($base-color) == number { 34 | $padding: $text-size; 35 | $text-size: $base-color; 36 | $base-color: $style; 37 | $style: simple; 38 | 39 | @if $padding == inherit { 40 | $padding: 7px 18px; 41 | } 42 | 43 | @include buttonstyle($style, $base-color, $text-size, $padding); 44 | } 45 | 46 | @if type-of($style) == number { 47 | $padding: $base-color; 48 | $text-size: $style; 49 | $base-color: #4294f0; 50 | $style: simple; 51 | 52 | @if $padding == #4294f0 { 53 | $padding: 7px 18px; 54 | } 55 | 56 | @include buttonstyle($style, $base-color, $text-size, $padding); 57 | } 58 | 59 | &:disabled { 60 | cursor: not-allowed; 61 | opacity: 0.5; 62 | } 63 | 64 | @warn "The button mixin is deprecated and will be removed in the next major version release"; 65 | } 66 | 67 | // Selector Style Button 68 | @mixin buttonstyle($type, $b-color, $t-size, $pad) { 69 | // Grayscale button 70 | @if $type == simple and $b-color == grayscale($b-color) { 71 | @include simple($b-color, true, $t-size, $pad); 72 | } 73 | 74 | @if $type == shiny and $b-color == grayscale($b-color) { 75 | @include shiny($b-color, true, $t-size, $pad); 76 | } 77 | 78 | @if $type == pill and $b-color == grayscale($b-color) { 79 | @include pill($b-color, true, $t-size, $pad); 80 | } 81 | 82 | @if $type == flat and $b-color == grayscale($b-color) { 83 | @include flat($b-color, true, $t-size, $pad); 84 | } 85 | 86 | // Colored button 87 | @if $type == simple { 88 | @include simple($b-color, false, $t-size, $pad); 89 | } 90 | 91 | @else if $type == shiny { 92 | @include shiny($b-color, false, $t-size, $pad); 93 | } 94 | 95 | @else if $type == pill { 96 | @include pill($b-color, false, $t-size, $pad); 97 | } 98 | 99 | @else if $type == flat { 100 | @include flat($b-color, false, $t-size, $pad); 101 | } 102 | } 103 | 104 | // Simple Button 105 | @mixin simple($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) { 106 | $color: hsl(0, 0, 100%); 107 | $border: adjust-color($base-color, $saturation: 9%, $lightness: -14%); 108 | $inset-shadow: adjust-color($base-color, $saturation: -8%, $lightness: 15%); 109 | $stop-gradient: adjust-color($base-color, $saturation: 9%, $lightness: -11%); 110 | $text-shadow: adjust-color($base-color, $saturation: 15%, $lightness: -18%); 111 | 112 | @if is-light($base-color) { 113 | $color: hsl(0, 0, 20%); 114 | $text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%); 115 | } 116 | 117 | @if $grayscale == true { 118 | $border: grayscale($border); 119 | $inset-shadow: grayscale($inset-shadow); 120 | $stop-gradient: grayscale($stop-gradient); 121 | $text-shadow: grayscale($text-shadow); 122 | } 123 | 124 | border: 1px solid $border; 125 | border-radius: 3px; 126 | box-shadow: inset 0 1px 0 0 $inset-shadow; 127 | color: $color; 128 | display: inline-block; 129 | font-size: $textsize; 130 | font-weight: bold; 131 | @include linear-gradient ($base-color, $stop-gradient); 132 | padding: $padding; 133 | text-decoration: none; 134 | text-shadow: 0 1px 0 $text-shadow; 135 | background-clip: padding-box; 136 | 137 | &:hover:not(:disabled) { 138 | $base-color-hover: adjust-color($base-color, $saturation: -4%, $lightness: -5%); 139 | $inset-shadow-hover: adjust-color($base-color, $saturation: -7%, $lightness: 5%); 140 | $stop-gradient-hover: adjust-color($base-color, $saturation: 8%, $lightness: -14%); 141 | 142 | @if $grayscale == true { 143 | $base-color-hover: grayscale($base-color-hover); 144 | $inset-shadow-hover: grayscale($inset-shadow-hover); 145 | $stop-gradient-hover: grayscale($stop-gradient-hover); 146 | } 147 | 148 | @include linear-gradient ($base-color-hover, $stop-gradient-hover); 149 | 150 | box-shadow: inset 0 1px 0 0 $inset-shadow-hover; 151 | cursor: pointer; 152 | } 153 | 154 | &:active:not(:disabled), 155 | &:focus:not(:disabled) { 156 | $border-active: adjust-color($base-color, $saturation: 9%, $lightness: -14%); 157 | $inset-shadow-active: adjust-color($base-color, $saturation: 7%, $lightness: -17%); 158 | 159 | @if $grayscale == true { 160 | $border-active: grayscale($border-active); 161 | $inset-shadow-active: grayscale($inset-shadow-active); 162 | } 163 | 164 | border: 1px solid $border-active; 165 | box-shadow: inset 0 0 8px 4px $inset-shadow-active, inset 0 0 8px 4px $inset-shadow-active; 166 | } 167 | } 168 | 169 | // Shiny Button 170 | @mixin shiny($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) { 171 | $color: hsl(0, 0, 100%); 172 | $border: adjust-color($base-color, $red: -117, $green: -111, $blue: -81); 173 | $border-bottom: adjust-color($base-color, $red: -126, $green: -127, $blue: -122); 174 | $fourth-stop: adjust-color($base-color, $red: -79, $green: -70, $blue: -46); 175 | $inset-shadow: adjust-color($base-color, $red: 37, $green: 29, $blue: 12); 176 | $second-stop: adjust-color($base-color, $red: -56, $green: -50, $blue: -33); 177 | $text-shadow: adjust-color($base-color, $red: -140, $green: -141, $blue: -114); 178 | $third-stop: adjust-color($base-color, $red: -86, $green: -75, $blue: -48); 179 | 180 | @if is-light($base-color) { 181 | $color: hsl(0, 0, 20%); 182 | $text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%); 183 | } 184 | 185 | @if $grayscale == true { 186 | $border: grayscale($border); 187 | $border-bottom: grayscale($border-bottom); 188 | $fourth-stop: grayscale($fourth-stop); 189 | $inset-shadow: grayscale($inset-shadow); 190 | $second-stop: grayscale($second-stop); 191 | $text-shadow: grayscale($text-shadow); 192 | $third-stop: grayscale($third-stop); 193 | } 194 | 195 | @include linear-gradient(top, $base-color 0%, $second-stop 50%, $third-stop 50%, $fourth-stop 100%); 196 | 197 | border: 1px solid $border; 198 | border-bottom: 1px solid $border-bottom; 199 | border-radius: 5px; 200 | box-shadow: inset 0 1px 0 0 $inset-shadow; 201 | color: $color; 202 | display: inline-block; 203 | font-size: $textsize; 204 | font-weight: bold; 205 | padding: $padding; 206 | text-align: center; 207 | text-decoration: none; 208 | text-shadow: 0 -1px 1px $text-shadow; 209 | 210 | &:hover:not(:disabled) { 211 | $first-stop-hover: adjust-color($base-color, $red: -13, $green: -15, $blue: -18); 212 | $second-stop-hover: adjust-color($base-color, $red: -66, $green: -62, $blue: -51); 213 | $third-stop-hover: adjust-color($base-color, $red: -93, $green: -85, $blue: -66); 214 | $fourth-stop-hover: adjust-color($base-color, $red: -86, $green: -80, $blue: -63); 215 | 216 | @if $grayscale == true { 217 | $first-stop-hover: grayscale($first-stop-hover); 218 | $second-stop-hover: grayscale($second-stop-hover); 219 | $third-stop-hover: grayscale($third-stop-hover); 220 | $fourth-stop-hover: grayscale($fourth-stop-hover); 221 | } 222 | 223 | @include linear-gradient(top, $first-stop-hover 0%, 224 | $second-stop-hover 50%, 225 | $third-stop-hover 50%, 226 | $fourth-stop-hover 100%); 227 | cursor: pointer; 228 | } 229 | 230 | &:active:not(:disabled), 231 | &:focus:not(:disabled) { 232 | $inset-shadow-active: adjust-color($base-color, $red: -111, $green: -116, $blue: -122); 233 | 234 | @if $grayscale == true { 235 | $inset-shadow-active: grayscale($inset-shadow-active); 236 | } 237 | 238 | box-shadow: inset 0 0 20px 0 $inset-shadow-active; 239 | } 240 | } 241 | 242 | // Pill Button 243 | @mixin pill($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) { 244 | $color: hsl(0, 0, 100%); 245 | $border-bottom: adjust-color($base-color, $hue: 8, $saturation: -11%, $lightness: -26%); 246 | $border-sides: adjust-color($base-color, $hue: 4, $saturation: -21%, $lightness: -21%); 247 | $border-top: adjust-color($base-color, $hue: -1, $saturation: -30%, $lightness: -15%); 248 | $inset-shadow: adjust-color($base-color, $hue: -1, $saturation: -1%, $lightness: 7%); 249 | $stop-gradient: adjust-color($base-color, $hue: 8, $saturation: 14%, $lightness: -10%); 250 | $text-shadow: adjust-color($base-color, $hue: 5, $saturation: -19%, $lightness: -15%); 251 | 252 | @if is-light($base-color) { 253 | $color: hsl(0, 0, 20%); 254 | $text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%); 255 | } 256 | 257 | @if $grayscale == true { 258 | $border-bottom: grayscale($border-bottom); 259 | $border-sides: grayscale($border-sides); 260 | $border-top: grayscale($border-top); 261 | $inset-shadow: grayscale($inset-shadow); 262 | $stop-gradient: grayscale($stop-gradient); 263 | $text-shadow: grayscale($text-shadow); 264 | } 265 | 266 | border: 1px solid $border-top; 267 | border-color: $border-top $border-sides $border-bottom; 268 | border-radius: 16px; 269 | box-shadow: inset 0 1px 0 0 $inset-shadow; 270 | color: $color; 271 | display: inline-block; 272 | font-size: $textsize; 273 | font-weight: normal; 274 | line-height: 1; 275 | @include linear-gradient ($base-color, $stop-gradient); 276 | padding: $padding; 277 | text-align: center; 278 | text-decoration: none; 279 | text-shadow: 0 -1px 1px $text-shadow; 280 | background-clip: padding-box; 281 | 282 | &:hover:not(:disabled) { 283 | $base-color-hover: adjust-color($base-color, $lightness: -4.5%); 284 | $border-bottom: adjust-color($base-color, $hue: 8, $saturation: 13.5%, $lightness: -32%); 285 | $border-sides: adjust-color($base-color, $hue: 4, $saturation: -2%, $lightness: -27%); 286 | $border-top: adjust-color($base-color, $hue: -1, $saturation: -17%, $lightness: -21%); 287 | $inset-shadow-hover: adjust-color($base-color, $saturation: -1%, $lightness: 3%); 288 | $stop-gradient-hover: adjust-color($base-color, $hue: 8, $saturation: -4%, $lightness: -15.5%); 289 | $text-shadow-hover: adjust-color($base-color, $hue: 5, $saturation: -5%, $lightness: -22%); 290 | 291 | @if $grayscale == true { 292 | $base-color-hover: grayscale($base-color-hover); 293 | $border-bottom: grayscale($border-bottom); 294 | $border-sides: grayscale($border-sides); 295 | $border-top: grayscale($border-top); 296 | $inset-shadow-hover: grayscale($inset-shadow-hover); 297 | $stop-gradient-hover: grayscale($stop-gradient-hover); 298 | $text-shadow-hover: grayscale($text-shadow-hover); 299 | } 300 | 301 | @include linear-gradient ($base-color-hover, $stop-gradient-hover); 302 | 303 | background-clip: padding-box; 304 | border: 1px solid $border-top; 305 | border-color: $border-top $border-sides $border-bottom; 306 | box-shadow: inset 0 1px 0 0 $inset-shadow-hover; 307 | cursor: pointer; 308 | text-shadow: 0 -1px 1px $text-shadow-hover; 309 | } 310 | 311 | &:active:not(:disabled), 312 | &:focus:not(:disabled) { 313 | $active-color: adjust-color($base-color, $hue: 4, $saturation: -12%, $lightness: -10%); 314 | $border-active: adjust-color($base-color, $hue: 6, $saturation: -2.5%, $lightness: -30%); 315 | $border-bottom-active: adjust-color($base-color, $hue: 11, $saturation: 6%, $lightness: -31%); 316 | $inset-shadow-active: adjust-color($base-color, $hue: 9, $saturation: 2%, $lightness: -21.5%); 317 | $text-shadow-active: adjust-color($base-color, $hue: 5, $saturation: -12%, $lightness: -21.5%); 318 | 319 | @if $grayscale == true { 320 | $active-color: grayscale($active-color); 321 | $border-active: grayscale($border-active); 322 | $border-bottom-active: grayscale($border-bottom-active); 323 | $inset-shadow-active: grayscale($inset-shadow-active); 324 | $text-shadow-active: grayscale($text-shadow-active); 325 | } 326 | 327 | background: $active-color; 328 | border: 1px solid $border-active; 329 | border-bottom: 1px solid $border-bottom-active; 330 | box-shadow: inset 0 0 6px 3px $inset-shadow-active; 331 | text-shadow: 0 -1px 1px $text-shadow-active; 332 | } 333 | } 334 | 335 | // Flat Button 336 | @mixin flat($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) { 337 | $color: hsl(0, 0, 100%); 338 | 339 | @if is-light($base-color) { 340 | $color: hsl(0, 0, 20%); 341 | } 342 | 343 | background-color: $base-color; 344 | border-radius: 3px; 345 | border: 0; 346 | color: $color; 347 | display: inline-block; 348 | font-size: $textsize; 349 | font-weight: bold; 350 | padding: $padding; 351 | text-decoration: none; 352 | background-clip: padding-box; 353 | 354 | &:hover:not(:disabled){ 355 | $base-color-hover: adjust-color($base-color, $saturation: 4%, $lightness: 5%); 356 | 357 | @if $grayscale == true { 358 | $base-color-hover: grayscale($base-color-hover); 359 | } 360 | 361 | background-color: $base-color-hover; 362 | cursor: pointer; 363 | } 364 | 365 | &:active:not(:disabled), 366 | &:focus:not(:disabled) { 367 | $base-color-active: adjust-color($base-color, $saturation: -4%, $lightness: -5%); 368 | 369 | @if $grayscale == true { 370 | $base-color-active: grayscale($base-color-active); 371 | } 372 | 373 | background-color: $base-color-active; 374 | cursor: pointer; 375 | } 376 | } 377 | 378 | // Flexible grid 379 | @function flex-grid($columns, $container-columns: $fg-max-columns) { 380 | $width: $columns * $fg-column + ($columns - 1) * $fg-gutter; 381 | $container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter; 382 | @return percentage($width / $container-width); 383 | 384 | @warn "The flex-grid function is deprecated and will be removed in the next major version release"; 385 | } 386 | 387 | // Flexible gutter 388 | @function flex-gutter($container-columns: $fg-max-columns, $gutter: $fg-gutter) { 389 | $container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter; 390 | @return percentage($gutter / $container-width); 391 | 392 | @warn "The flex-gutter function is deprecated and will be removed in the next major version release"; 393 | } 394 | 395 | @function grid-width($n) { 396 | @return $n * $gw-column + ($n - 1) * $gw-gutter; 397 | 398 | @warn "The grid-width function is deprecated and will be removed in the next major version release"; 399 | } 400 | 401 | @function golden-ratio($value, $increment) { 402 | @return modular-scale($increment, $value, $ratio: $golden); 403 | 404 | @warn "The golden-ratio function is deprecated and will be removed in the next major version release. Please use the modular-scale function, instead."; 405 | } 406 | 407 | @mixin box-sizing($box) { 408 | @include prefixer(box-sizing, $box, webkit moz spec); 409 | 410 | @warn "The box-sizing mixin is deprecated and will be removed in the next major version release. This property can now be used un-prefixed."; 411 | } 412 | -------------------------------------------------------------------------------- /src/sass/bourbon/_bourbon.scss: -------------------------------------------------------------------------------- 1 | // Bourbon 4.2.6 2 | // http://bourbon.io 3 | // Copyright 2011-2015 thoughtbot, inc. 4 | // MIT License 5 | 6 | @import "settings/prefixer"; 7 | @import "settings/px-to-em"; 8 | @import "settings/asset-pipeline"; 9 | 10 | @import "functions/assign-inputs"; 11 | @import "functions/contains"; 12 | @import "functions/contains-falsy"; 13 | @import "functions/is-length"; 14 | @import "functions/is-light"; 15 | @import "functions/is-number"; 16 | @import "functions/is-size"; 17 | @import "functions/px-to-em"; 18 | @import "functions/px-to-rem"; 19 | @import "functions/shade"; 20 | @import "functions/strip-units"; 21 | @import "functions/tint"; 22 | @import "functions/transition-property-name"; 23 | @import "functions/unpack"; 24 | @import "functions/modular-scale"; 25 | 26 | @import "helpers/convert-units"; 27 | @import "helpers/directional-values"; 28 | @import "helpers/font-source-declaration"; 29 | @import "helpers/gradient-positions-parser"; 30 | @import "helpers/linear-angle-parser"; 31 | @import "helpers/linear-gradient-parser"; 32 | @import "helpers/linear-positions-parser"; 33 | @import "helpers/linear-side-corner-parser"; 34 | @import "helpers/radial-arg-parser"; 35 | @import "helpers/radial-positions-parser"; 36 | @import "helpers/radial-gradient-parser"; 37 | @import "helpers/render-gradients"; 38 | @import "helpers/shape-size-stripper"; 39 | @import "helpers/str-to-num"; 40 | 41 | @import "css3/animation"; 42 | @import "css3/appearance"; 43 | @import "css3/backface-visibility"; 44 | @import "css3/background"; 45 | @import "css3/background-image"; 46 | @import "css3/border-image"; 47 | @import "css3/calc"; 48 | @import "css3/columns"; 49 | @import "css3/filter"; 50 | @import "css3/flex-box"; 51 | @import "css3/font-face"; 52 | @import "css3/font-feature-settings"; 53 | @import "css3/hidpi-media-query"; 54 | @import "css3/hyphens"; 55 | @import "css3/image-rendering"; 56 | @import "css3/keyframes"; 57 | @import "css3/linear-gradient"; 58 | @import "css3/perspective"; 59 | @import "css3/placeholder"; 60 | @import "css3/radial-gradient"; 61 | @import "css3/selection"; 62 | @import "css3/text-decoration"; 63 | @import "css3/transform"; 64 | @import "css3/transition"; 65 | @import "css3/user-select"; 66 | 67 | @import "addons/border-color"; 68 | @import "addons/border-radius"; 69 | @import "addons/border-style"; 70 | @import "addons/border-width"; 71 | @import "addons/buttons"; 72 | @import "addons/clearfix"; 73 | @import "addons/ellipsis"; 74 | @import "addons/font-stacks"; 75 | @import "addons/hide-text"; 76 | @import "addons/margin"; 77 | @import "addons/padding"; 78 | @import "addons/position"; 79 | @import "addons/prefixer"; 80 | @import "addons/retina-image"; 81 | @import "addons/size"; 82 | @import "addons/text-inputs"; 83 | @import "addons/timing-functions"; 84 | @import "addons/triangle"; 85 | @import "addons/word-wrap"; 86 | 87 | @import "bourbon-deprecated-upcoming"; 88 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_border-color.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a quick method for targeting `border-color` on specific sides of a box. Use a `null` value to “skip” a side. 4 | /// 5 | /// @param {Arglist} $vals 6 | /// List of arguments 7 | /// 8 | /// @example scss - Usage 9 | /// .element { 10 | /// @include border-color(#a60b55 #76cd9c null #e8ae1a); 11 | /// } 12 | /// 13 | /// @example css - CSS Output 14 | /// .element { 15 | /// border-left-color: #e8ae1a; 16 | /// border-right-color: #76cd9c; 17 | /// border-top-color: #a60b55; 18 | /// } 19 | /// 20 | /// @require {mixin} directional-property 21 | /// 22 | /// @output `border-color` 23 | 24 | @mixin border-color($vals...) { 25 | @include directional-property(border, color, $vals...); 26 | } 27 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_border-radius.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a quick method for targeting `border-radius` on both corners on the side of a box. 4 | /// 5 | /// @param {Number} $radii 6 | /// List of arguments 7 | /// 8 | /// @example scss - Usage 9 | /// .element-one { 10 | /// @include border-top-radius(5px); 11 | /// } 12 | /// 13 | /// .element-two { 14 | /// @include border-left-radius(3px); 15 | /// } 16 | /// 17 | /// @example css - CSS Output 18 | /// .element-one { 19 | /// border-top-left-radius: 5px; 20 | /// border-top-right-radius: 5px; 21 | /// } 22 | /// 23 | /// .element-two { 24 | /// border-bottom-left-radius: 3px; 25 | /// border-top-left-radius: 3px; 26 | /// } 27 | /// 28 | /// @output `border-radius` 29 | 30 | @mixin border-top-radius($radii) { 31 | border-top-left-radius: $radii; 32 | border-top-right-radius: $radii; 33 | } 34 | 35 | @mixin border-right-radius($radii) { 36 | border-bottom-right-radius: $radii; 37 | border-top-right-radius: $radii; 38 | } 39 | 40 | @mixin border-bottom-radius($radii) { 41 | border-bottom-left-radius: $radii; 42 | border-bottom-right-radius: $radii; 43 | } 44 | 45 | @mixin border-left-radius($radii) { 46 | border-bottom-left-radius: $radii; 47 | border-top-left-radius: $radii; 48 | } 49 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_border-style.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a quick method for targeting `border-style` on specific sides of a box. Use a `null` value to “skip” a side. 4 | /// 5 | /// @param {Arglist} $vals 6 | /// List of arguments 7 | /// 8 | /// @example scss - Usage 9 | /// .element { 10 | /// @include border-style(dashed null solid); 11 | /// } 12 | /// 13 | /// @example css - CSS Output 14 | /// .element { 15 | /// border-bottom-style: solid; 16 | /// border-top-style: dashed; 17 | /// } 18 | /// 19 | /// @require {mixin} directional-property 20 | /// 21 | /// @output `border-style` 22 | 23 | @mixin border-style($vals...) { 24 | @include directional-property(border, style, $vals...); 25 | } 26 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_border-width.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a quick method for targeting `border-width` on specific sides of a box. Use a `null` value to “skip” a side. 4 | /// 5 | /// @param {Arglist} $vals 6 | /// List of arguments 7 | /// 8 | /// @example scss - Usage 9 | /// .element { 10 | /// @include border-width(1em null 20px); 11 | /// } 12 | /// 13 | /// @example css - CSS Output 14 | /// .element { 15 | /// border-bottom-width: 20px; 16 | /// border-top-width: 1em; 17 | /// } 18 | /// 19 | /// @require {mixin} directional-property 20 | /// 21 | /// @output `border-width` 22 | 23 | @mixin border-width($vals...) { 24 | @include directional-property(border, width, $vals...); 25 | } 26 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_buttons.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Generates variables for all buttons. Please note that you must use interpolation on the variable: `#{$all-buttons}`. 4 | /// 5 | /// @example scss - Usage 6 | /// #{$all-buttons} { 7 | /// background-color: #f00; 8 | /// } 9 | /// 10 | /// #{$all-buttons-focus}, 11 | /// #{$all-buttons-hover} { 12 | /// background-color: #0f0; 13 | /// } 14 | /// 15 | /// #{$all-buttons-active} { 16 | /// background-color: #00f; 17 | /// } 18 | /// 19 | /// @example css - CSS Output 20 | /// button, 21 | /// input[type="button"], 22 | /// input[type="reset"], 23 | /// input[type="submit"] { 24 | /// background-color: #f00; 25 | /// } 26 | /// 27 | /// button:focus, 28 | /// input[type="button"]:focus, 29 | /// input[type="reset"]:focus, 30 | /// input[type="submit"]:focus, 31 | /// button:hover, 32 | /// input[type="button"]:hover, 33 | /// input[type="reset"]:hover, 34 | /// input[type="submit"]:hover { 35 | /// background-color: #0f0; 36 | /// } 37 | /// 38 | /// button:active, 39 | /// input[type="button"]:active, 40 | /// input[type="reset"]:active, 41 | /// input[type="submit"]:active { 42 | /// background-color: #00f; 43 | /// } 44 | /// 45 | /// @require assign-inputs 46 | /// 47 | /// @type List 48 | /// 49 | /// @todo Remove double assigned variables (Lines 59–62) in v5.0.0 50 | 51 | $buttons-list: 'button', 52 | 'input[type="button"]', 53 | 'input[type="reset"]', 54 | 'input[type="submit"]'; 55 | 56 | $all-buttons: assign-inputs($buttons-list); 57 | $all-buttons-active: assign-inputs($buttons-list, active); 58 | $all-buttons-focus: assign-inputs($buttons-list, focus); 59 | $all-buttons-hover: assign-inputs($buttons-list, hover); 60 | 61 | $all-button-inputs: $all-buttons; 62 | $all-button-inputs-active: $all-buttons-active; 63 | $all-button-inputs-focus: $all-buttons-focus; 64 | $all-button-inputs-hover: $all-buttons-hover; 65 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_clearfix.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides an easy way to include a clearfix for containing floats. 4 | /// 5 | /// @link http://cssmojo.com/latest_new_clearfix_so_far/ 6 | /// 7 | /// @example scss - Usage 8 | /// .element { 9 | /// @include clearfix; 10 | /// } 11 | /// 12 | /// @example css - CSS Output 13 | /// .element::after { 14 | /// clear: both; 15 | /// content: ""; 16 | /// display: table; 17 | /// } 18 | 19 | @mixin clearfix { 20 | &::after { 21 | clear: both; 22 | content: ""; 23 | display: table; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_ellipsis.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Truncates text and adds an ellipsis to represent overflow. 4 | /// 5 | /// @param {Number} $width [100%] 6 | /// Max-width for the string to respect before being truncated 7 | /// 8 | /// @example scss - Usage 9 | /// .element { 10 | /// @include ellipsis; 11 | /// } 12 | /// 13 | /// @example css - CSS Output 14 | /// .element { 15 | /// display: inline-block; 16 | /// max-width: 100%; 17 | /// overflow: hidden; 18 | /// text-overflow: ellipsis; 19 | /// white-space: nowrap; 20 | /// word-wrap: normal; 21 | /// } 22 | 23 | @mixin ellipsis($width: 100%) { 24 | display: inline-block; 25 | max-width: $width; 26 | overflow: hidden; 27 | text-overflow: ellipsis; 28 | white-space: nowrap; 29 | word-wrap: normal; 30 | } 31 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_font-stacks.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Georgia font stack. 4 | /// 5 | /// @type List 6 | 7 | $georgia: "Georgia", "Cambria", "Times New Roman", "Times", serif; 8 | 9 | /// Helvetica font stack. 10 | /// 11 | /// @type List 12 | 13 | $helvetica: "Helvetica Neue", "Helvetica", "Roboto", "Arial", sans-serif; 14 | 15 | /// Lucida Grande font stack. 16 | /// 17 | /// @type List 18 | 19 | $lucida-grande: "Lucida Grande", "Tahoma", "Verdana", "Arial", sans-serif; 20 | 21 | /// Monospace font stack. 22 | /// 23 | /// @type List 24 | 25 | $monospace: "Bitstream Vera Sans Mono", "Consolas", "Courier", monospace; 26 | 27 | /// Verdana font stack. 28 | /// 29 | /// @type List 30 | 31 | $verdana: "Verdana", "Geneva", sans-serif; 32 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_hide-text.scss: -------------------------------------------------------------------------------- 1 | /// Hides the text in an element, commonly used to show an image. Some elements will need block-level styles applied. 2 | /// 3 | /// @link http://zeldman.com/2012/03/01/replacing-the-9999px-hack-new-image-replacement 4 | /// 5 | /// @example scss - Usage 6 | /// .element { 7 | /// @include hide-text; 8 | /// } 9 | /// 10 | /// @example css - CSS Output 11 | /// .element { 12 | /// overflow: hidden; 13 | /// text-indent: 101%; 14 | /// white-space: nowrap; 15 | /// } 16 | /// 17 | /// @todo Remove height argument in v5.0.0 18 | 19 | @mixin hide-text($height: null) { 20 | overflow: hidden; 21 | text-indent: 101%; 22 | white-space: nowrap; 23 | 24 | @if $height { 25 | @warn "The `hide-text` mixin has changed and no longer requires a height. The height argument will no longer be accepted in v5.0.0"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_margin.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a quick method for targeting `margin` on specific sides of a box. Use a `null` value to “skip” a side. 4 | /// 5 | /// @param {Arglist} $vals 6 | /// List of arguments 7 | /// 8 | /// @example scss - Usage 9 | /// .element { 10 | /// @include margin(null 10px 3em 20vh); 11 | /// } 12 | /// 13 | /// @example css - CSS Output 14 | /// .element { 15 | /// margin-bottom: 3em; 16 | /// margin-left: 20vh; 17 | /// margin-right: 10px; 18 | /// } 19 | /// 20 | /// @require {mixin} directional-property 21 | /// 22 | /// @output `margin` 23 | 24 | @mixin margin($vals...) { 25 | @include directional-property(margin, false, $vals...); 26 | } 27 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_padding.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a quick method for targeting `padding` on specific sides of a box. Use a `null` value to “skip” a side. 4 | /// 5 | /// @param {Arglist} $vals 6 | /// List of arguments 7 | /// 8 | /// @example scss - Usage 9 | /// .element { 10 | /// @include padding(12vh null 10px 5%); 11 | /// } 12 | /// 13 | /// @example css - CSS Output 14 | /// .element { 15 | /// padding-bottom: 10px; 16 | /// padding-left: 5%; 17 | /// padding-top: 12vh; 18 | /// } 19 | /// 20 | /// @require {mixin} directional-property 21 | /// 22 | /// @output `padding` 23 | 24 | @mixin padding($vals...) { 25 | @include directional-property(padding, false, $vals...); 26 | } 27 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_position.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a quick method for setting an element’s position. Use a `null` value to “skip” a side. 4 | /// 5 | /// @param {Position} $position [relative] 6 | /// A CSS position value 7 | /// 8 | /// @param {Arglist} $coordinates [null null null null] 9 | /// List of values that correspond to the 4-value syntax for the edges of a box 10 | /// 11 | /// @example scss - Usage 12 | /// .element { 13 | /// @include position(absolute, 0 null null 10em); 14 | /// } 15 | /// 16 | /// @example css - CSS Output 17 | /// .element { 18 | /// left: 10em; 19 | /// position: absolute; 20 | /// top: 0; 21 | /// } 22 | /// 23 | /// @require {function} is-length 24 | /// @require {function} unpack 25 | 26 | @mixin position($position: relative, $coordinates: null null null null) { 27 | @if type-of($position) == list { 28 | $coordinates: $position; 29 | $position: relative; 30 | } 31 | 32 | $coordinates: unpack($coordinates); 33 | 34 | $offsets: ( 35 | top: nth($coordinates, 1), 36 | right: nth($coordinates, 2), 37 | bottom: nth($coordinates, 3), 38 | left: nth($coordinates, 4) 39 | ); 40 | 41 | position: $position; 42 | 43 | @each $offset, $value in $offsets { 44 | @if is-length($value) { 45 | #{$offset}: $value; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_prefixer.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// A mixin for generating vendor prefixes on non-standardized properties. 4 | /// 5 | /// @param {String} $property 6 | /// Property to prefix 7 | /// 8 | /// @param {*} $value 9 | /// Value to use 10 | /// 11 | /// @param {List} $prefixes 12 | /// Prefixes to define 13 | /// 14 | /// @example scss - Usage 15 | /// .element { 16 | /// @include prefixer(border-radius, 10px, webkit ms spec); 17 | /// } 18 | /// 19 | /// @example css - CSS Output 20 | /// .element { 21 | /// -webkit-border-radius: 10px; 22 | /// -moz-border-radius: 10px; 23 | /// border-radius: 10px; 24 | /// } 25 | /// 26 | /// @require {variable} $prefix-for-webkit 27 | /// @require {variable} $prefix-for-mozilla 28 | /// @require {variable} $prefix-for-microsoft 29 | /// @require {variable} $prefix-for-opera 30 | /// @require {variable} $prefix-for-spec 31 | 32 | @mixin prefixer($property, $value, $prefixes) { 33 | @each $prefix in $prefixes { 34 | @if $prefix == webkit { 35 | @if $prefix-for-webkit { 36 | -webkit-#{$property}: $value; 37 | } 38 | } @else if $prefix == moz { 39 | @if $prefix-for-mozilla { 40 | -moz-#{$property}: $value; 41 | } 42 | } @else if $prefix == ms { 43 | @if $prefix-for-microsoft { 44 | -ms-#{$property}: $value; 45 | } 46 | } @else if $prefix == o { 47 | @if $prefix-for-opera { 48 | -o-#{$property}: $value; 49 | } 50 | } @else if $prefix == spec { 51 | @if $prefix-for-spec { 52 | #{$property}: $value; 53 | } 54 | } @else { 55 | @warn "Unrecognized prefix: #{$prefix}"; 56 | } 57 | } 58 | } 59 | 60 | @mixin disable-prefix-for-all() { 61 | $prefix-for-webkit: false !global; 62 | $prefix-for-mozilla: false !global; 63 | $prefix-for-microsoft: false !global; 64 | $prefix-for-opera: false !global; 65 | $prefix-for-spec: false !global; 66 | } 67 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_retina-image.scss: -------------------------------------------------------------------------------- 1 | @mixin retina-image($filename, $background-size, $extension: png, $retina-filename: null, $retina-suffix: _2x, $asset-pipeline: $asset-pipeline) { 2 | @if $asset-pipeline { 3 | background-image: image-url("#{$filename}.#{$extension}"); 4 | } @else { 5 | background-image: url("#{$filename}.#{$extension}"); 6 | } 7 | 8 | @include hidpi { 9 | @if $asset-pipeline { 10 | @if $retina-filename { 11 | background-image: image-url("#{$retina-filename}.#{$extension}"); 12 | } @else { 13 | background-image: image-url("#{$filename}#{$retina-suffix}.#{$extension}"); 14 | } 15 | } @else { 16 | @if $retina-filename { 17 | background-image: url("#{$retina-filename}.#{$extension}"); 18 | } @else { 19 | background-image: url("#{$filename}#{$retina-suffix}.#{$extension}"); 20 | } 21 | } 22 | 23 | background-size: $background-size; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_size.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Sets the `width` and `height` of the element. 4 | /// 5 | /// @param {List} $size 6 | /// A list of at most 2 size values. 7 | /// 8 | /// If there is only a single value in `$size` it is used for both width and height. All units are supported. 9 | /// 10 | /// @example scss - Usage 11 | /// .first-element { 12 | /// @include size(2em); 13 | /// } 14 | /// 15 | /// .second-element { 16 | /// @include size(auto 10em); 17 | /// } 18 | /// 19 | /// @example css - CSS Output 20 | /// .first-element { 21 | /// width: 2em; 22 | /// height: 2em; 23 | /// } 24 | /// 25 | /// .second-element { 26 | /// width: auto; 27 | /// height: 10em; 28 | /// } 29 | /// 30 | /// @todo Refactor in 5.0.0 to use a comma-separated argument 31 | 32 | @mixin size($value) { 33 | $width: nth($value, 1); 34 | $height: $width; 35 | 36 | @if length($value) > 1 { 37 | $height: nth($value, 2); 38 | } 39 | 40 | @if is-size($height) { 41 | height: $height; 42 | } @else { 43 | @warn "`#{$height}` is not a valid length for the `$height` parameter in the `size` mixin."; 44 | } 45 | 46 | @if is-size($width) { 47 | width: $width; 48 | } @else { 49 | @warn "`#{$width}` is not a valid length for the `$width` parameter in the `size` mixin."; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_text-inputs.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Generates variables for all text-based inputs. Please note that you must use interpolation on the variable: `#{$all-text-inputs}`. 4 | /// 5 | /// @example scss - Usage 6 | /// #{$all-text-inputs} { 7 | /// border: 1px solid #f00; 8 | /// } 9 | /// 10 | /// #{$all-text-inputs-focus}, 11 | /// #{$all-text-inputs-hover} { 12 | /// border: 1px solid #0f0; 13 | /// } 14 | /// 15 | /// #{$all-text-inputs-active} { 16 | /// border: 1px solid #00f; 17 | /// } 18 | /// 19 | /// @example css - CSS Output 20 | /// input[type="color"], 21 | /// input[type="date"], 22 | /// input[type="datetime"], 23 | /// input[type="datetime-local"], 24 | /// input[type="email"], 25 | /// input[type="month"], 26 | /// input[type="number"], 27 | /// input[type="password"], 28 | /// input[type="search"], 29 | /// input[type="tel"], 30 | /// input[type="text"], 31 | /// input[type="time"], 32 | /// input[type="url"], 33 | /// input[type="week"], 34 | /// textarea { 35 | /// border: 1px solid #f00; 36 | /// } 37 | /// 38 | /// input[type="color"]:focus, 39 | /// input[type="date"]:focus, 40 | /// input[type="datetime"]:focus, 41 | /// input[type="datetime-local"]:focus, 42 | /// input[type="email"]:focus, 43 | /// input[type="month"]:focus, 44 | /// input[type="number"]:focus, 45 | /// input[type="password"]:focus, 46 | /// input[type="search"]:focus, 47 | /// input[type="tel"]:focus, 48 | /// input[type="text"]:focus, 49 | /// input[type="time"]:focus, 50 | /// input[type="url"]:focus, 51 | /// input[type="week"]:focus, 52 | /// textarea:focus, 53 | /// input[type="color"]:hover, 54 | /// input[type="date"]:hover, 55 | /// input[type="datetime"]:hover, 56 | /// input[type="datetime-local"]:hover, 57 | /// input[type="email"]:hover, 58 | /// input[type="month"]:hover, 59 | /// input[type="number"]:hover, 60 | /// input[type="password"]:hover, 61 | /// input[type="search"]:hover, 62 | /// input[type="tel"]:hover, 63 | /// input[type="text"]:hover, 64 | /// input[type="time"]:hover, 65 | /// input[type="url"]:hover, 66 | /// input[type="week"]:hover, 67 | /// textarea:hover { 68 | /// border: 1px solid #0f0; 69 | /// } 70 | /// 71 | /// input[type="color"]:active, 72 | /// input[type="date"]:active, 73 | /// input[type="datetime"]:active, 74 | /// input[type="datetime-local"]:active, 75 | /// input[type="email"]:active, 76 | /// input[type="month"]:active, 77 | /// input[type="number"]:active, 78 | /// input[type="password"]:active, 79 | /// input[type="search"]:active, 80 | /// input[type="tel"]:active, 81 | /// input[type="text"]:active, 82 | /// input[type="time"]:active, 83 | /// input[type="url"]:active, 84 | /// input[type="week"]:active, 85 | /// textarea:active { 86 | /// border: 1px solid #00f; 87 | /// } 88 | /// 89 | /// @require assign-inputs 90 | /// 91 | /// @type List 92 | 93 | $text-inputs-list: 'input[type="color"]', 94 | 'input[type="date"]', 95 | 'input[type="datetime"]', 96 | 'input[type="datetime-local"]', 97 | 'input[type="email"]', 98 | 'input[type="month"]', 99 | 'input[type="number"]', 100 | 'input[type="password"]', 101 | 'input[type="search"]', 102 | 'input[type="tel"]', 103 | 'input[type="text"]', 104 | 'input[type="time"]', 105 | 'input[type="url"]', 106 | 'input[type="week"]', 107 | 'input:not([type])', 108 | 'textarea'; 109 | 110 | $all-text-inputs: assign-inputs($text-inputs-list); 111 | $all-text-inputs-active: assign-inputs($text-inputs-list, active); 112 | $all-text-inputs-focus: assign-inputs($text-inputs-list, focus); 113 | $all-text-inputs-hover: assign-inputs($text-inputs-list, hover); 114 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_timing-functions.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// CSS cubic-bezier timing functions. Timing functions courtesy of jquery.easie (github.com/jaukia/easie) 4 | /// 5 | /// Timing functions are the same as demoed here: http://jqueryui.com/resources/demos/effect/easing.html 6 | /// 7 | /// @type cubic-bezier 8 | 9 | $ease-in-quad: cubic-bezier(0.550, 0.085, 0.680, 0.530); 10 | $ease-in-cubic: cubic-bezier(0.550, 0.055, 0.675, 0.190); 11 | $ease-in-quart: cubic-bezier(0.895, 0.030, 0.685, 0.220); 12 | $ease-in-quint: cubic-bezier(0.755, 0.050, 0.855, 0.060); 13 | $ease-in-sine: cubic-bezier(0.470, 0.000, 0.745, 0.715); 14 | $ease-in-expo: cubic-bezier(0.950, 0.050, 0.795, 0.035); 15 | $ease-in-circ: cubic-bezier(0.600, 0.040, 0.980, 0.335); 16 | $ease-in-back: cubic-bezier(0.600, -0.280, 0.735, 0.045); 17 | 18 | $ease-out-quad: cubic-bezier(0.250, 0.460, 0.450, 0.940); 19 | $ease-out-cubic: cubic-bezier(0.215, 0.610, 0.355, 1.000); 20 | $ease-out-quart: cubic-bezier(0.165, 0.840, 0.440, 1.000); 21 | $ease-out-quint: cubic-bezier(0.230, 1.000, 0.320, 1.000); 22 | $ease-out-sine: cubic-bezier(0.390, 0.575, 0.565, 1.000); 23 | $ease-out-expo: cubic-bezier(0.190, 1.000, 0.220, 1.000); 24 | $ease-out-circ: cubic-bezier(0.075, 0.820, 0.165, 1.000); 25 | $ease-out-back: cubic-bezier(0.175, 0.885, 0.320, 1.275); 26 | 27 | $ease-in-out-quad: cubic-bezier(0.455, 0.030, 0.515, 0.955); 28 | $ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1.000); 29 | $ease-in-out-quart: cubic-bezier(0.770, 0.000, 0.175, 1.000); 30 | $ease-in-out-quint: cubic-bezier(0.860, 0.000, 0.070, 1.000); 31 | $ease-in-out-sine: cubic-bezier(0.445, 0.050, 0.550, 0.950); 32 | $ease-in-out-expo: cubic-bezier(1.000, 0.000, 0.000, 1.000); 33 | $ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.150, 0.860); 34 | $ease-in-out-back: cubic-bezier(0.680, -0.550, 0.265, 1.550); 35 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_triangle.scss: -------------------------------------------------------------------------------- 1 | @mixin triangle($size, $color, $direction) { 2 | $width: nth($size, 1); 3 | $height: nth($size, length($size)); 4 | $foreground-color: nth($color, 1); 5 | $background-color: if(length($color) == 2, nth($color, 2), transparent); 6 | height: 0; 7 | width: 0; 8 | 9 | @if ($direction == up) or ($direction == down) or ($direction == right) or ($direction == left) { 10 | $width: $width / 2; 11 | $height: if(length($size) > 1, $height, $height/2); 12 | 13 | @if $direction == up { 14 | border-bottom: $height solid $foreground-color; 15 | border-left: $width solid $background-color; 16 | border-right: $width solid $background-color; 17 | } @else if $direction == right { 18 | border-bottom: $width solid $background-color; 19 | border-left: $height solid $foreground-color; 20 | border-top: $width solid $background-color; 21 | } @else if $direction == down { 22 | border-left: $width solid $background-color; 23 | border-right: $width solid $background-color; 24 | border-top: $height solid $foreground-color; 25 | } @else if $direction == left { 26 | border-bottom: $width solid $background-color; 27 | border-right: $height solid $foreground-color; 28 | border-top: $width solid $background-color; 29 | } 30 | } @else if ($direction == up-right) or ($direction == up-left) { 31 | border-top: $height solid $foreground-color; 32 | 33 | @if $direction == up-right { 34 | border-left: $width solid $background-color; 35 | } @else if $direction == up-left { 36 | border-right: $width solid $background-color; 37 | } 38 | } @else if ($direction == down-right) or ($direction == down-left) { 39 | border-bottom: $height solid $foreground-color; 40 | 41 | @if $direction == down-right { 42 | border-left: $width solid $background-color; 43 | } @else if $direction == down-left { 44 | border-right: $width solid $background-color; 45 | } 46 | } @else if ($direction == inset-up) { 47 | border-color: $background-color $background-color $foreground-color; 48 | border-style: solid; 49 | border-width: $height $width; 50 | } @else if ($direction == inset-down) { 51 | border-color: $foreground-color $background-color $background-color; 52 | border-style: solid; 53 | border-width: $height $width; 54 | } @else if ($direction == inset-right) { 55 | border-color: $background-color $background-color $background-color $foreground-color; 56 | border-style: solid; 57 | border-width: $width $height; 58 | } @else if ($direction == inset-left) { 59 | border-color: $background-color $foreground-color $background-color $background-color; 60 | border-style: solid; 61 | border-width: $width $height; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/sass/bourbon/addons/_word-wrap.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides an easy way to change the `word-wrap` property. 4 | /// 5 | /// @param {String} $wrap [break-word] 6 | /// Value for the `word-break` property. 7 | /// 8 | /// @example scss - Usage 9 | /// .wrapper { 10 | /// @include word-wrap(break-word); 11 | /// } 12 | /// 13 | /// @example css - CSS Output 14 | /// .wrapper { 15 | /// overflow-wrap: break-word; 16 | /// word-break: break-all; 17 | /// word-wrap: break-word; 18 | /// } 19 | 20 | @mixin word-wrap($wrap: break-word) { 21 | overflow-wrap: $wrap; 22 | word-wrap: $wrap; 23 | 24 | @if $wrap == break-word { 25 | word-break: break-all; 26 | } @else { 27 | word-break: $wrap; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/sass/bourbon/css3/_animation.scss: -------------------------------------------------------------------------------- 1 | // http://www.w3.org/TR/css3-animations/#the-animation-name-property- 2 | // Each of these mixins support comma separated lists of values, which allows different transitions for individual properties to be described in a single style rule. Each value in the list corresponds to the value at that same position in the other properties. 3 | 4 | @mixin animation($animations...) { 5 | @include prefixer(animation, $animations, webkit moz spec); 6 | } 7 | 8 | @mixin animation-name($names...) { 9 | @include prefixer(animation-name, $names, webkit moz spec); 10 | } 11 | 12 | @mixin animation-duration($times...) { 13 | @include prefixer(animation-duration, $times, webkit moz spec); 14 | } 15 | 16 | @mixin animation-timing-function($motions...) { 17 | // ease | linear | ease-in | ease-out | ease-in-out 18 | @include prefixer(animation-timing-function, $motions, webkit moz spec); 19 | } 20 | 21 | @mixin animation-iteration-count($values...) { 22 | // infinite | 23 | @include prefixer(animation-iteration-count, $values, webkit moz spec); 24 | } 25 | 26 | @mixin animation-direction($directions...) { 27 | // normal | alternate 28 | @include prefixer(animation-direction, $directions, webkit moz spec); 29 | } 30 | 31 | @mixin animation-play-state($states...) { 32 | // running | paused 33 | @include prefixer(animation-play-state, $states, webkit moz spec); 34 | } 35 | 36 | @mixin animation-delay($times...) { 37 | @include prefixer(animation-delay, $times, webkit moz spec); 38 | } 39 | 40 | @mixin animation-fill-mode($modes...) { 41 | // none | forwards | backwards | both 42 | @include prefixer(animation-fill-mode, $modes, webkit moz spec); 43 | } 44 | -------------------------------------------------------------------------------- /src/sass/bourbon/css3/_appearance.scss: -------------------------------------------------------------------------------- 1 | @mixin appearance($value) { 2 | @include prefixer(appearance, $value, webkit moz ms o spec); 3 | } 4 | -------------------------------------------------------------------------------- /src/sass/bourbon/css3/_backface-visibility.scss: -------------------------------------------------------------------------------- 1 | @mixin backface-visibility($visibility) { 2 | @include prefixer(backface-visibility, $visibility, webkit spec); 3 | } 4 | -------------------------------------------------------------------------------- /src/sass/bourbon/css3/_background-image.scss: -------------------------------------------------------------------------------- 1 | //************************************************************************// 2 | // Background-image property for adding multiple background images with 3 | // gradients, or for stringing multiple gradients together. 4 | //************************************************************************// 5 | 6 | @mixin background-image($images...) { 7 | $webkit-images: (); 8 | $spec-images: (); 9 | 10 | @each $image in $images { 11 | $webkit-image: (); 12 | $spec-image: (); 13 | 14 | @if (type-of($image) == string) { 15 | $url-str: str-slice($image, 1, 3); 16 | $gradient-type: str-slice($image, 1, 6); 17 | 18 | @if $url-str == "url" { 19 | $webkit-image: $image; 20 | $spec-image: $image; 21 | } 22 | 23 | @else if $gradient-type == "linear" { 24 | $gradients: _linear-gradient-parser($image); 25 | $webkit-image: map-get($gradients, webkit-image); 26 | $spec-image: map-get($gradients, spec-image); 27 | } 28 | 29 | @else if $gradient-type == "radial" { 30 | $gradients: _radial-gradient-parser($image); 31 | $webkit-image: map-get($gradients, webkit-image); 32 | $spec-image: map-get($gradients, spec-image); 33 | } 34 | } 35 | 36 | $webkit-images: append($webkit-images, $webkit-image, comma); 37 | $spec-images: append($spec-images, $spec-image, comma); 38 | } 39 | 40 | background-image: $webkit-images; 41 | background-image: $spec-images; 42 | } 43 | -------------------------------------------------------------------------------- /src/sass/bourbon/css3/_background.scss: -------------------------------------------------------------------------------- 1 | //************************************************************************// 2 | // Background property for adding multiple backgrounds using shorthand 3 | // notation. 4 | //************************************************************************// 5 | 6 | @mixin background($backgrounds...) { 7 | $webkit-backgrounds: (); 8 | $spec-backgrounds: (); 9 | 10 | @each $background in $backgrounds { 11 | $webkit-background: (); 12 | $spec-background: (); 13 | $background-type: type-of($background); 14 | 15 | @if $background-type == string or $background-type == list { 16 | $background-str: if($background-type == list, nth($background, 1), $background); 17 | 18 | $url-str: str-slice($background-str, 1, 3); 19 | $gradient-type: str-slice($background-str, 1, 6); 20 | 21 | @if $url-str == "url" { 22 | $webkit-background: $background; 23 | $spec-background: $background; 24 | } 25 | 26 | @else if $gradient-type == "linear" { 27 | $gradients: _linear-gradient-parser("#{$background}"); 28 | $webkit-background: map-get($gradients, webkit-image); 29 | $spec-background: map-get($gradients, spec-image); 30 | } 31 | 32 | @else if $gradient-type == "radial" { 33 | $gradients: _radial-gradient-parser("#{$background}"); 34 | $webkit-background: map-get($gradients, webkit-image); 35 | $spec-background: map-get($gradients, spec-image); 36 | } 37 | 38 | @else { 39 | $webkit-background: $background; 40 | $spec-background: $background; 41 | } 42 | } 43 | 44 | @else { 45 | $webkit-background: $background; 46 | $spec-background: $background; 47 | } 48 | 49 | $webkit-backgrounds: append($webkit-backgrounds, $webkit-background, comma); 50 | $spec-backgrounds: append($spec-backgrounds, $spec-background, comma); 51 | } 52 | 53 | background: $webkit-backgrounds; 54 | background: $spec-backgrounds; 55 | } 56 | -------------------------------------------------------------------------------- /src/sass/bourbon/css3/_border-image.scss: -------------------------------------------------------------------------------- 1 | @mixin border-image($borders...) { 2 | $webkit-borders: (); 3 | $spec-borders: (); 4 | 5 | @each $border in $borders { 6 | $webkit-border: (); 7 | $spec-border: (); 8 | $border-type: type-of($border); 9 | 10 | @if $border-type == string or list { 11 | $border-str: if($border-type == list, nth($border, 1), $border); 12 | 13 | $url-str: str-slice($border-str, 1, 3); 14 | $gradient-type: str-slice($border-str, 1, 6); 15 | 16 | @if $url-str == "url" { 17 | $webkit-border: $border; 18 | $spec-border: $border; 19 | } 20 | 21 | @else if $gradient-type == "linear" { 22 | $gradients: _linear-gradient-parser("#{$border}"); 23 | $webkit-border: map-get($gradients, webkit-image); 24 | $spec-border: map-get($gradients, spec-image); 25 | } 26 | 27 | @else if $gradient-type == "radial" { 28 | $gradients: _radial-gradient-parser("#{$border}"); 29 | $webkit-border: map-get($gradients, webkit-image); 30 | $spec-border: map-get($gradients, spec-image); 31 | } 32 | 33 | @else { 34 | $webkit-border: $border; 35 | $spec-border: $border; 36 | } 37 | } 38 | 39 | @else { 40 | $webkit-border: $border; 41 | $spec-border: $border; 42 | } 43 | 44 | $webkit-borders: append($webkit-borders, $webkit-border, comma); 45 | $spec-borders: append($spec-borders, $spec-border, comma); 46 | } 47 | 48 | -webkit-border-image: $webkit-borders; 49 | border-image: $spec-borders; 50 | border-style: solid; 51 | } 52 | 53 | //Examples: 54 | // @include border-image(url("image.png")); 55 | // @include border-image(url("image.png") 20 stretch); 56 | // @include border-image(linear-gradient(45deg, orange, yellow)); 57 | // @include border-image(linear-gradient(45deg, orange, yellow) stretch); 58 | // @include border-image(linear-gradient(45deg, orange, yellow) 20 30 40 50 stretch round); 59 | // @include border-image(radial-gradient(top, cover, orange, yellow, orange)); 60 | -------------------------------------------------------------------------------- /src/sass/bourbon/css3/_calc.scss: -------------------------------------------------------------------------------- 1 | @mixin calc($property, $value) { 2 | #{$property}: -webkit-calc(#{$value}); 3 | #{$property}: calc(#{$value}); 4 | } 5 | -------------------------------------------------------------------------------- /src/sass/bourbon/css3/_columns.scss: -------------------------------------------------------------------------------- 1 | @mixin columns($arg: auto) { 2 | // || 3 | @include prefixer(columns, $arg, webkit moz spec); 4 | } 5 | 6 | @mixin column-count($int: auto) { 7 | // auto || integer 8 | @include prefixer(column-count, $int, webkit moz spec); 9 | } 10 | 11 | @mixin column-gap($length: normal) { 12 | // normal || length 13 | @include prefixer(column-gap, $length, webkit moz spec); 14 | } 15 | 16 | @mixin column-fill($arg: auto) { 17 | // auto || length 18 | @include prefixer(column-fill, $arg, webkit moz spec); 19 | } 20 | 21 | @mixin column-rule($arg) { 22 | // || || 23 | @include prefixer(column-rule, $arg, webkit moz spec); 24 | } 25 | 26 | @mixin column-rule-color($color) { 27 | @include prefixer(column-rule-color, $color, webkit moz spec); 28 | } 29 | 30 | @mixin column-rule-style($style: none) { 31 | // none | hidden | dashed | dotted | double | groove | inset | inset | outset | ridge | solid 32 | @include prefixer(column-rule-style, $style, webkit moz spec); 33 | } 34 | 35 | @mixin column-rule-width ($width: none) { 36 | @include prefixer(column-rule-width, $width, webkit moz spec); 37 | } 38 | 39 | @mixin column-span($arg: none) { 40 | // none || all 41 | @include prefixer(column-span, $arg, webkit moz spec); 42 | } 43 | 44 | @mixin column-width($length: auto) { 45 | // auto || length 46 | @include prefixer(column-width, $length, webkit moz spec); 47 | } 48 | -------------------------------------------------------------------------------- /src/sass/bourbon/css3/_filter.scss: -------------------------------------------------------------------------------- 1 | @mixin filter($function: none) { 2 | // [ 3 | @include prefixer(perspective, $depth, webkit moz spec); 4 | } 5 | 6 | @mixin perspective-origin($value: 50% 50%) { 7 | @include prefixer(perspective-origin, $value, webkit moz spec); 8 | } 9 | -------------------------------------------------------------------------------- /src/sass/bourbon/css3/_placeholder.scss: -------------------------------------------------------------------------------- 1 | @mixin placeholder { 2 | $placeholders: ":-webkit-input" ":-moz" "-moz" "-ms-input"; 3 | @each $placeholder in $placeholders { 4 | &:#{$placeholder}-placeholder { 5 | @content; 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/sass/bourbon/css3/_radial-gradient.scss: -------------------------------------------------------------------------------- 1 | // Requires Sass 3.1+ 2 | @mixin radial-gradient($g1, $g2, 3 | $g3: null, $g4: null, 4 | $g5: null, $g6: null, 5 | $g7: null, $g8: null, 6 | $g9: null, $g10: null, 7 | $pos: null, 8 | $shape-size: null, 9 | $fallback: null) { 10 | 11 | $data: _radial-arg-parser($g1, $g2, $pos, $shape-size); 12 | $g1: nth($data, 1); 13 | $g2: nth($data, 2); 14 | $pos: nth($data, 3); 15 | $shape-size: nth($data, 4); 16 | 17 | $full: $g1, $g2, $g3, $g4, $g5, $g6, $g7, $g8, $g9, $g10; 18 | 19 | // Strip deprecated cover/contain for spec 20 | $shape-size-spec: _shape-size-stripper($shape-size); 21 | 22 | // Set $g1 as the default fallback color 23 | $first-color: nth($full, 1); 24 | $fallback-color: nth($first-color, 1); 25 | 26 | @if (type-of($fallback) == color) or ($fallback == "transparent") { 27 | $fallback-color: $fallback; 28 | } 29 | 30 | // Add Commas and spaces 31 | $shape-size: if($shape-size, "#{$shape-size}, ", null); 32 | $pos: if($pos, "#{$pos}, ", null); 33 | $pos-spec: if($pos, "at #{$pos}", null); 34 | $shape-size-spec: if(($shape-size-spec != " ") and ($pos == null), "#{$shape-size-spec}, ", "#{$shape-size-spec} "); 35 | 36 | background-color: $fallback-color; 37 | background-image: -webkit-radial-gradient(unquote(#{$pos}#{$shape-size}#{$full})); 38 | background-image: unquote("radial-gradient(#{$shape-size-spec}#{$pos-spec}#{$full})"); 39 | } 40 | -------------------------------------------------------------------------------- /src/sass/bourbon/css3/_selection.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Outputs the spec and prefixed versions of the `::selection` pseudo-element. 4 | /// 5 | /// @param {Bool} $current-selector [false] 6 | /// If set to `true`, it takes the current element into consideration. 7 | /// 8 | /// @example scss - Usage 9 | /// .element { 10 | /// @include selection(true) { 11 | /// background-color: #ffbb52; 12 | /// } 13 | /// } 14 | /// 15 | /// @example css - CSS Output 16 | /// .element::-moz-selection { 17 | /// background-color: #ffbb52; 18 | /// } 19 | /// 20 | /// .element::selection { 21 | /// background-color: #ffbb52; 22 | /// } 23 | 24 | @mixin selection($current-selector: false) { 25 | @if $current-selector { 26 | &::-moz-selection { 27 | @content; 28 | } 29 | 30 | &::selection { 31 | @content; 32 | } 33 | } @else { 34 | ::-moz-selection { 35 | @content; 36 | } 37 | 38 | ::selection { 39 | @content; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/sass/bourbon/css3/_text-decoration.scss: -------------------------------------------------------------------------------- 1 | @mixin text-decoration($value) { 2 | // || || 3 | @include prefixer(text-decoration, $value, moz); 4 | } 5 | 6 | @mixin text-decoration-line($line: none) { 7 | // none || underline || overline || line-through 8 | @include prefixer(text-decoration-line, $line, moz); 9 | } 10 | 11 | @mixin text-decoration-style($style: solid) { 12 | // solid || double || dotted || dashed || wavy 13 | @include prefixer(text-decoration-style, $style, moz webkit); 14 | } 15 | 16 | @mixin text-decoration-color($color: currentColor) { 17 | // currentColor || 18 | @include prefixer(text-decoration-color, $color, moz); 19 | } 20 | -------------------------------------------------------------------------------- /src/sass/bourbon/css3/_transform.scss: -------------------------------------------------------------------------------- 1 | @mixin transform($property: none) { 2 | // none | 3 | @include prefixer(transform, $property, webkit moz ms o spec); 4 | } 5 | 6 | @mixin transform-origin($axes: 50%) { 7 | // x-axis - left | center | right | length | % 8 | // y-axis - top | center | bottom | length | % 9 | // z-axis - length 10 | @include prefixer(transform-origin, $axes, webkit moz ms o spec); 11 | } 12 | 13 | @mixin transform-style($style: flat) { 14 | @include prefixer(transform-style, $style, webkit moz ms o spec); 15 | } 16 | -------------------------------------------------------------------------------- /src/sass/bourbon/css3/_transition.scss: -------------------------------------------------------------------------------- 1 | // Shorthand mixin. Supports multiple parentheses-deliminated values for each variable. 2 | // Example: @include transition (all 2s ease-in-out); 3 | // @include transition (opacity 1s ease-in 2s, width 2s ease-out); 4 | // @include transition-property (transform, opacity); 5 | 6 | @mixin transition($properties...) { 7 | // Fix for vendor-prefix transform property 8 | $needs-prefixes: false; 9 | $webkit: (); 10 | $moz: (); 11 | $spec: (); 12 | 13 | // Create lists for vendor-prefixed transform 14 | @each $list in $properties { 15 | @if nth($list, 1) == "transform" { 16 | $needs-prefixes: true; 17 | $list1: -webkit-transform; 18 | $list2: -moz-transform; 19 | $list3: (); 20 | 21 | @each $var in $list { 22 | $list3: join($list3, $var); 23 | 24 | @if $var != "transform" { 25 | $list1: join($list1, $var); 26 | $list2: join($list2, $var); 27 | } 28 | } 29 | 30 | $webkit: append($webkit, $list1); 31 | $moz: append($moz, $list2); 32 | $spec: append($spec, $list3); 33 | } @else { 34 | $webkit: append($webkit, $list, comma); 35 | $moz: append($moz, $list, comma); 36 | $spec: append($spec, $list, comma); 37 | } 38 | } 39 | 40 | @if $needs-prefixes { 41 | -webkit-transition: $webkit; 42 | -moz-transition: $moz; 43 | transition: $spec; 44 | } @else { 45 | @if length($properties) >= 1 { 46 | @include prefixer(transition, $properties, webkit moz spec); 47 | } @else { 48 | $properties: all 0.15s ease-out 0s; 49 | @include prefixer(transition, $properties, webkit moz spec); 50 | } 51 | } 52 | } 53 | 54 | @mixin transition-property($properties...) { 55 | -webkit-transition-property: transition-property-names($properties, "webkit"); 56 | -moz-transition-property: transition-property-names($properties, "moz"); 57 | transition-property: transition-property-names($properties, false); 58 | } 59 | 60 | @mixin transition-duration($times...) { 61 | @include prefixer(transition-duration, $times, webkit moz spec); 62 | } 63 | 64 | @mixin transition-timing-function($motions...) { 65 | // ease | linear | ease-in | ease-out | ease-in-out | cubic-bezier() 66 | @include prefixer(transition-timing-function, $motions, webkit moz spec); 67 | } 68 | 69 | @mixin transition-delay($times...) { 70 | @include prefixer(transition-delay, $times, webkit moz spec); 71 | } 72 | -------------------------------------------------------------------------------- /src/sass/bourbon/css3/_user-select.scss: -------------------------------------------------------------------------------- 1 | @mixin user-select($value: none) { 2 | @include prefixer(user-select, $value, webkit moz ms spec); 3 | } 4 | -------------------------------------------------------------------------------- /src/sass/bourbon/functions/_assign-inputs.scss: -------------------------------------------------------------------------------- 1 | @function assign-inputs($inputs, $pseudo: null) { 2 | $list: (); 3 | 4 | @each $input in $inputs { 5 | $input: unquote($input); 6 | $input: if($pseudo, $input + ":" + $pseudo, $input); 7 | $list: append($list, $input, comma); 8 | } 9 | 10 | @return $list; 11 | } 12 | -------------------------------------------------------------------------------- /src/sass/bourbon/functions/_contains-falsy.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks if a list does not contains a value. 4 | /// 5 | /// @access private 6 | /// 7 | /// @param {List} $list 8 | /// The list to check against. 9 | /// 10 | /// @return {Bool} 11 | 12 | @function contains-falsy($list) { 13 | @each $item in $list { 14 | @if not $item { 15 | @return true; 16 | } 17 | } 18 | 19 | @return false; 20 | } 21 | -------------------------------------------------------------------------------- /src/sass/bourbon/functions/_contains.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks if a list contains a value(s). 4 | /// 5 | /// @access private 6 | /// 7 | /// @param {List} $list 8 | /// The list to check against. 9 | /// 10 | /// @param {List} $values 11 | /// A single value or list of values to check for. 12 | /// 13 | /// @example scss - Usage 14 | /// contains($list, $value) 15 | /// 16 | /// @return {Bool} 17 | 18 | @function contains($list, $values...) { 19 | @each $value in $values { 20 | @if type-of(index($list, $value)) != "number" { 21 | @return false; 22 | } 23 | } 24 | 25 | @return true; 26 | } 27 | -------------------------------------------------------------------------------- /src/sass/bourbon/functions/_is-length.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks for a valid CSS length. 4 | /// 5 | /// @param {String} $value 6 | 7 | @function is-length($value) { 8 | @return type-of($value) != "null" and (str-slice($value + "", 1, 4) == "calc" 9 | or index(auto inherit initial 0, $value) 10 | or (type-of($value) == "number" and not(unitless($value)))); 11 | } 12 | -------------------------------------------------------------------------------- /src/sass/bourbon/functions/_is-light.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Programatically determines whether a color is light or dark. 4 | /// 5 | /// @link http://robots.thoughtbot.com/closer-look-color-lightness 6 | /// 7 | /// @param {Color (Hex)} $color 8 | /// 9 | /// @example scss - Usage 10 | /// is-light($color) 11 | /// 12 | /// @return {Bool} 13 | 14 | @function is-light($hex-color) { 15 | $-local-red: red(rgba($hex-color, 1)); 16 | $-local-green: green(rgba($hex-color, 1)); 17 | $-local-blue: blue(rgba($hex-color, 1)); 18 | $-local-lightness: ($-local-red * 0.2126 + $-local-green * 0.7152 + $-local-blue * 0.0722) / 255; 19 | 20 | @return $-local-lightness > 0.6; 21 | } 22 | -------------------------------------------------------------------------------- /src/sass/bourbon/functions/_is-number.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks for a valid number. 4 | /// 5 | /// @param {Number} $value 6 | /// 7 | /// @require {function} contains 8 | 9 | @function is-number($value) { 10 | @return contains("0" "1" "2" "3" "4" "5" "6" "7" "8" "9" 0 1 2 3 4 5 6 7 8 9, $value); 11 | } 12 | -------------------------------------------------------------------------------- /src/sass/bourbon/functions/_is-size.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks for a valid CSS size. 4 | /// 5 | /// @param {String} $value 6 | /// 7 | /// @require {function} contains 8 | /// @require {function} is-length 9 | 10 | @function is-size($value) { 11 | @return is-length($value) 12 | or contains("fill" "fit-content" "min-content" "max-content", $value); 13 | } 14 | -------------------------------------------------------------------------------- /src/sass/bourbon/functions/_modular-scale.scss: -------------------------------------------------------------------------------- 1 | // Scaling Variables 2 | $golden: 1.618; 3 | $minor-second: 1.067; 4 | $major-second: 1.125; 5 | $minor-third: 1.2; 6 | $major-third: 1.25; 7 | $perfect-fourth: 1.333; 8 | $augmented-fourth: 1.414; 9 | $perfect-fifth: 1.5; 10 | $minor-sixth: 1.6; 11 | $major-sixth: 1.667; 12 | $minor-seventh: 1.778; 13 | $major-seventh: 1.875; 14 | $octave: 2; 15 | $major-tenth: 2.5; 16 | $major-eleventh: 2.667; 17 | $major-twelfth: 3; 18 | $double-octave: 4; 19 | 20 | $modular-scale-ratio: $perfect-fourth !default; 21 | $modular-scale-base: em($em-base) !default; 22 | 23 | @function modular-scale($increment, $value: $modular-scale-base, $ratio: $modular-scale-ratio) { 24 | $v1: nth($value, 1); 25 | $v2: nth($value, length($value)); 26 | $value: $v1; 27 | 28 | // scale $v2 to just above $v1 29 | @while $v2 > $v1 { 30 | $v2: ($v2 / $ratio); // will be off-by-1 31 | } 32 | @while $v2 < $v1 { 33 | $v2: ($v2 * $ratio); // will fix off-by-1 34 | } 35 | 36 | // check AFTER scaling $v2 to prevent double-counting corner-case 37 | $double-stranded: $v2 > $v1; 38 | 39 | @if $increment > 0 { 40 | @for $i from 1 through $increment { 41 | @if $double-stranded and ($v1 * $ratio) > $v2 { 42 | $value: $v2; 43 | $v2: ($v2 * $ratio); 44 | } @else { 45 | $v1: ($v1 * $ratio); 46 | $value: $v1; 47 | } 48 | } 49 | } 50 | 51 | @if $increment < 0 { 52 | // adjust $v2 to just below $v1 53 | @if $double-stranded { 54 | $v2: ($v2 / $ratio); 55 | } 56 | 57 | @for $i from $increment through -1 { 58 | @if $double-stranded and ($v1 / $ratio) < $v2 { 59 | $value: $v2; 60 | $v2: ($v2 / $ratio); 61 | } @else { 62 | $v1: ($v1 / $ratio); 63 | $value: $v1; 64 | } 65 | } 66 | } 67 | 68 | @return $value; 69 | } 70 | -------------------------------------------------------------------------------- /src/sass/bourbon/functions/_px-to-em.scss: -------------------------------------------------------------------------------- 1 | // Convert pixels to ems 2 | // eg. for a relational value of 12px write em(12) when the parent is 16px 3 | // if the parent is another value say 24px write em(12, 24) 4 | 5 | @function em($pxval, $base: $em-base) { 6 | @if not unitless($pxval) { 7 | $pxval: strip-units($pxval); 8 | } 9 | @if not unitless($base) { 10 | $base: strip-units($base); 11 | } 12 | @return ($pxval / $base) * 1em; 13 | } 14 | -------------------------------------------------------------------------------- /src/sass/bourbon/functions/_px-to-rem.scss: -------------------------------------------------------------------------------- 1 | // Convert pixels to rems 2 | // eg. for a relational value of 12px write rem(12) 3 | // Assumes $em-base is the font-size of 4 | 5 | @function rem($pxval) { 6 | @if not unitless($pxval) { 7 | $pxval: strip-units($pxval); 8 | } 9 | 10 | $base: $em-base; 11 | @if not unitless($base) { 12 | $base: strip-units($base); 13 | } 14 | @return ($pxval / $base) * 1rem; 15 | } 16 | -------------------------------------------------------------------------------- /src/sass/bourbon/functions/_shade.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Mixes a color with black. 4 | /// 5 | /// @param {Color} $color 6 | /// 7 | /// @param {Number (Percentage)} $percent 8 | /// The amount of black to be mixed in. 9 | /// 10 | /// @example scss - Usage 11 | /// .element { 12 | /// background-color: shade(#ffbb52, 60%); 13 | /// } 14 | /// 15 | /// @example css - CSS Output 16 | /// .element { 17 | /// background-color: #664a20; 18 | /// } 19 | /// 20 | /// @return {Color} 21 | 22 | @function shade($color, $percent) { 23 | @return mix(#000, $color, $percent); 24 | } 25 | -------------------------------------------------------------------------------- /src/sass/bourbon/functions/_strip-units.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Strips the unit from a number. 4 | /// 5 | /// @param {Number (With Unit)} $value 6 | /// 7 | /// @example scss - Usage 8 | /// $dimension: strip-units(10em); 9 | /// 10 | /// @example css - CSS Output 11 | /// $dimension: 10; 12 | /// 13 | /// @return {Number (Unitless)} 14 | 15 | @function strip-units($value) { 16 | @return ($value / ($value * 0 + 1)); 17 | } 18 | -------------------------------------------------------------------------------- /src/sass/bourbon/functions/_tint.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Mixes a color with white. 4 | /// 5 | /// @param {Color} $color 6 | /// 7 | /// @param {Number (Percentage)} $percent 8 | /// The amount of white to be mixed in. 9 | /// 10 | /// @example scss - Usage 11 | /// .element { 12 | /// background-color: tint(#6ecaa6, 40%); 13 | /// } 14 | /// 15 | /// @example css - CSS Output 16 | /// .element { 17 | /// background-color: #a8dfc9; 18 | /// } 19 | /// 20 | /// @return {Color} 21 | 22 | @function tint($color, $percent) { 23 | @return mix(#fff, $color, $percent); 24 | } 25 | -------------------------------------------------------------------------------- /src/sass/bourbon/functions/_transition-property-name.scss: -------------------------------------------------------------------------------- 1 | // Return vendor-prefixed property names if appropriate 2 | // Example: transition-property-names((transform, color, background), moz) -> -moz-transform, color, background 3 | //************************************************************************// 4 | @function transition-property-names($props, $vendor: false) { 5 | $new-props: (); 6 | 7 | @each $prop in $props { 8 | $new-props: append($new-props, transition-property-name($prop, $vendor), comma); 9 | } 10 | 11 | @return $new-props; 12 | } 13 | 14 | @function transition-property-name($prop, $vendor: false) { 15 | // put other properties that need to be prefixed here aswell 16 | @if $vendor and $prop == transform { 17 | @return unquote('-'+$vendor+'-'+$prop); 18 | } 19 | @else { 20 | @return $prop; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/sass/bourbon/functions/_unpack.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Converts shorthand to the 4-value syntax. 4 | /// 5 | /// @param {List} $shorthand 6 | /// 7 | /// @example scss - Usage 8 | /// .element { 9 | /// margin: unpack(1em 2em); 10 | /// } 11 | /// 12 | /// @example css - CSS Output 13 | /// .element { 14 | /// margin: 1em 2em 1em 2em; 15 | /// } 16 | 17 | @function unpack($shorthand) { 18 | @if length($shorthand) == 1 { 19 | @return nth($shorthand, 1) nth($shorthand, 1) nth($shorthand, 1) nth($shorthand, 1); 20 | } @else if length($shorthand) == 2 { 21 | @return nth($shorthand, 1) nth($shorthand, 2) nth($shorthand, 1) nth($shorthand, 2); 22 | } @else if length($shorthand) == 3 { 23 | @return nth($shorthand, 1) nth($shorthand, 2) nth($shorthand, 3) nth($shorthand, 2); 24 | } @else { 25 | @return $shorthand; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/sass/bourbon/helpers/_convert-units.scss: -------------------------------------------------------------------------------- 1 | //************************************************************************// 2 | // Helper function for str-to-num fn. 3 | // Source: http://sassmeister.com/gist/9647408 4 | //************************************************************************// 5 | @function _convert-units($number, $unit) { 6 | $strings: "px", "cm", "mm", "%", "ch", "pica", "in", "em", "rem", "pt", "pc", "ex", "vw", "vh", "vmin", "vmax", "deg", "rad", "grad", "turn"; 7 | $units: 1px, 1cm, 1mm, 1%, 1ch, 1pica, 1in, 1em, 1rem, 1pt, 1pc, 1ex, 1vw, 1vh, 1vmin, 1vmax, 1deg, 1rad, 1grad, 1turn; 8 | $index: index($strings, $unit); 9 | 10 | @if not $index { 11 | @warn "Unknown unit `#{$unit}`."; 12 | @return false; 13 | } 14 | 15 | @if type-of($number) != "number" { 16 | @warn "`#{$number} is not a number`"; 17 | @return false; 18 | } 19 | 20 | @return $number * nth($units, $index); 21 | } 22 | -------------------------------------------------------------------------------- /src/sass/bourbon/helpers/_directional-values.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Directional-property mixins are shorthands for writing properties like the following 4 | /// 5 | /// @ignore You can also use `false` instead of `null`. 6 | /// 7 | /// @param {List} $vals 8 | /// List of directional values 9 | /// 10 | /// @example scss - Usage 11 | /// .element { 12 | /// @include border-style(dotted null); 13 | /// @include margin(null 0 10px); 14 | /// } 15 | /// 16 | /// @example css - CSS Output 17 | /// .element { 18 | /// border-bottom-style: dotted; 19 | /// border-top-style: dotted; 20 | /// margin-bottom: 10px; 21 | /// margin-left: 0; 22 | /// margin-right: 0; 23 | /// } 24 | /// 25 | /// @require {function} contains-falsy 26 | /// 27 | /// @return {List} 28 | 29 | @function collapse-directionals($vals) { 30 | $output: null; 31 | 32 | $a: nth($vals, 1); 33 | $b: if(length($vals) < 2, $a, nth($vals, 2)); 34 | $c: if(length($vals) < 3, $a, nth($vals, 3)); 35 | $d: if(length($vals) < 2, $a, nth($vals, if(length($vals) < 4, 2, 4))); 36 | 37 | @if $a == 0 { $a: 0; } 38 | @if $b == 0 { $b: 0; } 39 | @if $c == 0 { $c: 0; } 40 | @if $d == 0 { $d: 0; } 41 | 42 | @if $a == $b and $a == $c and $a == $d { $output: $a; } 43 | @else if $a == $c and $b == $d { $output: $a $b; } 44 | @else if $b == $d { $output: $a $b $c; } 45 | @else { $output: $a $b $c $d; } 46 | 47 | @return $output; 48 | } 49 | 50 | /// Output directional properties, for instance `margin`. 51 | /// 52 | /// @access private 53 | /// 54 | /// @param {String} $pre 55 | /// Prefix to use 56 | /// @param {String} $suf 57 | /// Suffix to use 58 | /// @param {List} $vals 59 | /// List of values 60 | /// 61 | /// @require {function} collapse-directionals 62 | /// @require {function} contains-falsy 63 | 64 | @mixin directional-property($pre, $suf, $vals) { 65 | // Property Names 66 | $top: $pre + "-top" + if($suf, "-#{$suf}", ""); 67 | $bottom: $pre + "-bottom" + if($suf, "-#{$suf}", ""); 68 | $left: $pre + "-left" + if($suf, "-#{$suf}", ""); 69 | $right: $pre + "-right" + if($suf, "-#{$suf}", ""); 70 | $all: $pre + if($suf, "-#{$suf}", ""); 71 | 72 | $vals: collapse-directionals($vals); 73 | 74 | @if contains-falsy($vals) { 75 | @if nth($vals, 1) { #{$top}: nth($vals, 1); } 76 | 77 | @if length($vals) == 1 { 78 | @if nth($vals, 1) { #{$right}: nth($vals, 1); } 79 | } @else { 80 | @if nth($vals, 2) { #{$right}: nth($vals, 2); } 81 | } 82 | 83 | @if length($vals) == 2 { 84 | @if nth($vals, 1) { #{$bottom}: nth($vals, 1); } 85 | @if nth($vals, 2) { #{$left}: nth($vals, 2); } 86 | } @else if length($vals) == 3 { 87 | @if nth($vals, 3) { #{$bottom}: nth($vals, 3); } 88 | @if nth($vals, 2) { #{$left}: nth($vals, 2); } 89 | } @else if length($vals) == 4 { 90 | @if nth($vals, 3) { #{$bottom}: nth($vals, 3); } 91 | @if nth($vals, 4) { #{$left}: nth($vals, 4); } 92 | } 93 | } @else { 94 | #{$all}: $vals; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/sass/bourbon/helpers/_font-source-declaration.scss: -------------------------------------------------------------------------------- 1 | // Used for creating the source string for fonts using @font-face 2 | // Reference: http://goo.gl/Ru1bKP 3 | 4 | @function font-url-prefixer($asset-pipeline) { 5 | @if $asset-pipeline == true { 6 | @return font-url; 7 | } @else { 8 | @return url; 9 | } 10 | } 11 | 12 | @function font-source-declaration( 13 | $font-family, 14 | $file-path, 15 | $asset-pipeline, 16 | $file-formats, 17 | $font-url) { 18 | 19 | $src: (); 20 | 21 | $formats-map: ( 22 | eot: "#{$file-path}.eot?#iefix" format("embedded-opentype"), 23 | woff2: "#{$file-path}.woff2" format("woff2"), 24 | woff: "#{$file-path}.woff" format("woff"), 25 | ttf: "#{$file-path}.ttf" format("truetype"), 26 | svg: "#{$file-path}.svg##{$font-family}" format("svg") 27 | ); 28 | 29 | @each $key, $values in $formats-map { 30 | @if contains($file-formats, $key) { 31 | $file-path: nth($values, 1); 32 | $font-format: nth($values, 2); 33 | 34 | @if $asset-pipeline == true { 35 | $src: append($src, font-url($file-path) $font-format, comma); 36 | } @else { 37 | $src: append($src, url($file-path) $font-format, comma); 38 | } 39 | } 40 | } 41 | 42 | @return $src; 43 | } 44 | -------------------------------------------------------------------------------- /src/sass/bourbon/helpers/_gradient-positions-parser.scss: -------------------------------------------------------------------------------- 1 | @function _gradient-positions-parser($gradient-type, $gradient-positions) { 2 | @if $gradient-positions 3 | and ($gradient-type == linear) 4 | and (type-of($gradient-positions) != color) { 5 | $gradient-positions: _linear-positions-parser($gradient-positions); 6 | } 7 | @else if $gradient-positions 8 | and ($gradient-type == radial) 9 | and (type-of($gradient-positions) != color) { 10 | $gradient-positions: _radial-positions-parser($gradient-positions); 11 | } 12 | @return $gradient-positions; 13 | } 14 | -------------------------------------------------------------------------------- /src/sass/bourbon/helpers/_linear-angle-parser.scss: -------------------------------------------------------------------------------- 1 | // Private function for linear-gradient-parser 2 | @function _linear-angle-parser($image, $first-val, $prefix, $suffix) { 3 | $offset: null; 4 | $unit-short: str-slice($first-val, str-length($first-val) - 2, str-length($first-val)); 5 | $unit-long: str-slice($first-val, str-length($first-val) - 3, str-length($first-val)); 6 | 7 | @if ($unit-long == "grad") or 8 | ($unit-long == "turn") { 9 | $offset: if($unit-long == "grad", -100grad * 3, -0.75turn); 10 | } 11 | 12 | @else if ($unit-short == "deg") or 13 | ($unit-short == "rad") { 14 | $offset: if($unit-short == "deg", -90 * 3, 1.6rad); 15 | } 16 | 17 | @if $offset { 18 | $num: _str-to-num($first-val); 19 | 20 | @return ( 21 | webkit-image: -webkit- + $prefix + ($offset - $num) + $suffix, 22 | spec-image: $image 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/sass/bourbon/helpers/_linear-gradient-parser.scss: -------------------------------------------------------------------------------- 1 | @function _linear-gradient-parser($image) { 2 | $image: unquote($image); 3 | $gradients: (); 4 | $start: str-index($image, "("); 5 | $end: str-index($image, ","); 6 | $first-val: str-slice($image, $start + 1, $end - 1); 7 | 8 | $prefix: str-slice($image, 1, $start); 9 | $suffix: str-slice($image, $end, str-length($image)); 10 | 11 | $has-multiple-vals: str-index($first-val, " "); 12 | $has-single-position: unquote(_position-flipper($first-val) + ""); 13 | $has-angle: is-number(str-slice($first-val, 1, 1)); 14 | 15 | @if $has-multiple-vals { 16 | $gradients: _linear-side-corner-parser($image, $first-val, $prefix, $suffix, $has-multiple-vals); 17 | } 18 | 19 | @else if $has-single-position != "" { 20 | $pos: unquote($has-single-position + ""); 21 | 22 | $gradients: ( 23 | webkit-image: -webkit- + $image, 24 | spec-image: $prefix + "to " + $pos + $suffix 25 | ); 26 | } 27 | 28 | @else if $has-angle { 29 | // Rotate degree for webkit 30 | $gradients: _linear-angle-parser($image, $first-val, $prefix, $suffix); 31 | } 32 | 33 | @else { 34 | $gradients: ( 35 | webkit-image: -webkit- + $image, 36 | spec-image: $image 37 | ); 38 | } 39 | 40 | @return $gradients; 41 | } 42 | -------------------------------------------------------------------------------- /src/sass/bourbon/helpers/_linear-positions-parser.scss: -------------------------------------------------------------------------------- 1 | @function _linear-positions-parser($pos) { 2 | $type: type-of(nth($pos, 1)); 3 | $spec: null; 4 | $degree: null; 5 | $side: null; 6 | $corner: null; 7 | $length: length($pos); 8 | // Parse Side and corner positions 9 | @if ($length > 1) { 10 | @if nth($pos, 1) == "to" { // Newer syntax 11 | $side: nth($pos, 2); 12 | 13 | @if $length == 2 { // eg. to top 14 | // Swap for backwards compatibility 15 | $degree: _position-flipper(nth($pos, 2)); 16 | } 17 | @else if $length == 3 { // eg. to top left 18 | $corner: nth($pos, 3); 19 | } 20 | } 21 | @else if $length == 2 { // Older syntax ("top left") 22 | $side: _position-flipper(nth($pos, 1)); 23 | $corner: _position-flipper(nth($pos, 2)); 24 | } 25 | 26 | @if ("#{$side} #{$corner}" == "left top") or ("#{$side} #{$corner}" == "top left") { 27 | $degree: _position-flipper(#{$side}) _position-flipper(#{$corner}); 28 | } 29 | @else if ("#{$side} #{$corner}" == "right top") or ("#{$side} #{$corner}" == "top right") { 30 | $degree: _position-flipper(#{$side}) _position-flipper(#{$corner}); 31 | } 32 | @else if ("#{$side} #{$corner}" == "right bottom") or ("#{$side} #{$corner}" == "bottom right") { 33 | $degree: _position-flipper(#{$side}) _position-flipper(#{$corner}); 34 | } 35 | @else if ("#{$side} #{$corner}" == "left bottom") or ("#{$side} #{$corner}" == "bottom left") { 36 | $degree: _position-flipper(#{$side}) _position-flipper(#{$corner}); 37 | } 38 | $spec: to $side $corner; 39 | } 40 | @else if $length == 1 { 41 | // Swap for backwards compatibility 42 | @if $type == string { 43 | $degree: $pos; 44 | $spec: to _position-flipper($pos); 45 | } 46 | @else { 47 | $degree: -270 - $pos; //rotate the gradient opposite from spec 48 | $spec: $pos; 49 | } 50 | } 51 | $degree: unquote($degree + ","); 52 | $spec: unquote($spec + ","); 53 | @return $degree $spec; 54 | } 55 | 56 | @function _position-flipper($pos) { 57 | @return if($pos == left, right, null) 58 | if($pos == right, left, null) 59 | if($pos == top, bottom, null) 60 | if($pos == bottom, top, null); 61 | } 62 | -------------------------------------------------------------------------------- /src/sass/bourbon/helpers/_linear-side-corner-parser.scss: -------------------------------------------------------------------------------- 1 | // Private function for linear-gradient-parser 2 | @function _linear-side-corner-parser($image, $first-val, $prefix, $suffix, $has-multiple-vals) { 3 | $val-1: str-slice($first-val, 1, $has-multiple-vals - 1); 4 | $val-2: str-slice($first-val, $has-multiple-vals + 1, str-length($first-val)); 5 | $val-3: null; 6 | $has-val-3: str-index($val-2, " "); 7 | 8 | @if $has-val-3 { 9 | $val-3: str-slice($val-2, $has-val-3 + 1, str-length($val-2)); 10 | $val-2: str-slice($val-2, 1, $has-val-3 - 1); 11 | } 12 | 13 | $pos: _position-flipper($val-1) _position-flipper($val-2) _position-flipper($val-3); 14 | $pos: unquote($pos + ""); 15 | 16 | // Use old spec for webkit 17 | @if $val-1 == "to" { 18 | @return ( 19 | webkit-image: -webkit- + $prefix + $pos + $suffix, 20 | spec-image: $image 21 | ); 22 | } 23 | 24 | // Bring the code up to spec 25 | @else { 26 | @return ( 27 | webkit-image: -webkit- + $image, 28 | spec-image: $prefix + "to " + $pos + $suffix 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/sass/bourbon/helpers/_radial-arg-parser.scss: -------------------------------------------------------------------------------- 1 | @function _radial-arg-parser($g1, $g2, $pos, $shape-size) { 2 | @each $value in $g1, $g2 { 3 | $first-val: nth($value, 1); 4 | $pos-type: type-of($first-val); 5 | $spec-at-index: null; 6 | 7 | // Determine if spec was passed to mixin 8 | @if type-of($value) == list { 9 | $spec-at-index: if(index($value, at), index($value, at), false); 10 | } 11 | @if $spec-at-index { 12 | @if $spec-at-index > 1 { 13 | @for $i from 1 through ($spec-at-index - 1) { 14 | $shape-size: $shape-size nth($value, $i); 15 | } 16 | @for $i from ($spec-at-index + 1) through length($value) { 17 | $pos: $pos nth($value, $i); 18 | } 19 | } 20 | @else if $spec-at-index == 1 { 21 | @for $i from ($spec-at-index + 1) through length($value) { 22 | $pos: $pos nth($value, $i); 23 | } 24 | } 25 | $g1: null; 26 | } 27 | 28 | // If not spec calculate correct values 29 | @else { 30 | @if ($pos-type != color) or ($first-val != "transparent") { 31 | @if ($pos-type == number) 32 | or ($first-val == "center") 33 | or ($first-val == "top") 34 | or ($first-val == "right") 35 | or ($first-val == "bottom") 36 | or ($first-val == "left") { 37 | 38 | $pos: $value; 39 | 40 | @if $pos == $g1 { 41 | $g1: null; 42 | } 43 | } 44 | 45 | @else if 46 | ($first-val == "ellipse") 47 | or ($first-val == "circle") 48 | or ($first-val == "closest-side") 49 | or ($first-val == "closest-corner") 50 | or ($first-val == "farthest-side") 51 | or ($first-val == "farthest-corner") 52 | or ($first-val == "contain") 53 | or ($first-val == "cover") { 54 | 55 | $shape-size: $value; 56 | 57 | @if $value == $g1 { 58 | $g1: null; 59 | } 60 | 61 | @else if $value == $g2 { 62 | $g2: null; 63 | } 64 | } 65 | } 66 | } 67 | } 68 | @return $g1, $g2, $pos, $shape-size; 69 | } 70 | -------------------------------------------------------------------------------- /src/sass/bourbon/helpers/_radial-gradient-parser.scss: -------------------------------------------------------------------------------- 1 | @function _radial-gradient-parser($image) { 2 | $image: unquote($image); 3 | $gradients: (); 4 | $start: str-index($image, "("); 5 | $end: str-index($image, ","); 6 | $first-val: str-slice($image, $start + 1, $end - 1); 7 | 8 | $prefix: str-slice($image, 1, $start); 9 | $suffix: str-slice($image, $end, str-length($image)); 10 | 11 | $is-spec-syntax: str-index($first-val, "at"); 12 | 13 | @if $is-spec-syntax and $is-spec-syntax > 1 { 14 | $keyword: str-slice($first-val, 1, $is-spec-syntax - 2); 15 | $pos: str-slice($first-val, $is-spec-syntax + 3, str-length($first-val)); 16 | $pos: append($pos, $keyword, comma); 17 | 18 | $gradients: ( 19 | webkit-image: -webkit- + $prefix + $pos + $suffix, 20 | spec-image: $image 21 | ); 22 | } 23 | 24 | @else if $is-spec-syntax == 1 { 25 | $pos: str-slice($first-val, $is-spec-syntax + 3, str-length($first-val)); 26 | 27 | $gradients: ( 28 | webkit-image: -webkit- + $prefix + $pos + $suffix, 29 | spec-image: $image 30 | ); 31 | } 32 | 33 | @else if str-index($image, "cover") or str-index($image, "contain") { 34 | @warn "Radial-gradient needs to be updated to conform to latest spec."; 35 | 36 | $gradients: ( 37 | webkit-image: null, 38 | spec-image: $image 39 | ); 40 | } 41 | 42 | @else { 43 | $gradients: ( 44 | webkit-image: -webkit- + $image, 45 | spec-image: $image 46 | ); 47 | } 48 | 49 | @return $gradients; 50 | } 51 | -------------------------------------------------------------------------------- /src/sass/bourbon/helpers/_radial-positions-parser.scss: -------------------------------------------------------------------------------- 1 | @function _radial-positions-parser($gradient-pos) { 2 | $shape-size: nth($gradient-pos, 1); 3 | $pos: nth($gradient-pos, 2); 4 | $shape-size-spec: _shape-size-stripper($shape-size); 5 | 6 | $pre-spec: unquote(if($pos, "#{$pos}, ", null)) 7 | unquote(if($shape-size, "#{$shape-size},", null)); 8 | $pos-spec: if($pos, "at #{$pos}", null); 9 | 10 | $spec: "#{$shape-size-spec} #{$pos-spec}"; 11 | 12 | // Add comma 13 | @if ($spec != " ") { 14 | $spec: "#{$spec},"; 15 | } 16 | 17 | @return $pre-spec $spec; 18 | } 19 | -------------------------------------------------------------------------------- /src/sass/bourbon/helpers/_render-gradients.scss: -------------------------------------------------------------------------------- 1 | // User for linear and radial gradients within background-image or border-image properties 2 | 3 | @function _render-gradients($gradient-positions, $gradients, $gradient-type, $vendor: false) { 4 | $pre-spec: null; 5 | $spec: null; 6 | $vendor-gradients: null; 7 | @if $gradient-type == linear { 8 | @if $gradient-positions { 9 | $pre-spec: nth($gradient-positions, 1); 10 | $spec: nth($gradient-positions, 2); 11 | } 12 | } 13 | @else if $gradient-type == radial { 14 | $pre-spec: nth($gradient-positions, 1); 15 | $spec: nth($gradient-positions, 2); 16 | } 17 | 18 | @if $vendor { 19 | $vendor-gradients: -#{$vendor}-#{$gradient-type}-gradient(#{$pre-spec} $gradients); 20 | } 21 | @else if $vendor == false { 22 | $vendor-gradients: "#{$gradient-type}-gradient(#{$spec} #{$gradients})"; 23 | $vendor-gradients: unquote($vendor-gradients); 24 | } 25 | @return $vendor-gradients; 26 | } 27 | -------------------------------------------------------------------------------- /src/sass/bourbon/helpers/_shape-size-stripper.scss: -------------------------------------------------------------------------------- 1 | @function _shape-size-stripper($shape-size) { 2 | $shape-size-spec: null; 3 | @each $value in $shape-size { 4 | @if ($value == "cover") or ($value == "contain") { 5 | $value: null; 6 | } 7 | $shape-size-spec: "#{$shape-size-spec} #{$value}"; 8 | } 9 | @return $shape-size-spec; 10 | } 11 | -------------------------------------------------------------------------------- /src/sass/bourbon/helpers/_str-to-num.scss: -------------------------------------------------------------------------------- 1 | //************************************************************************// 2 | // Helper function for linear/radial-gradient-parsers. 3 | // Source: http://sassmeister.com/gist/9647408 4 | //************************************************************************// 5 | @function _str-to-num($string) { 6 | // Matrices 7 | $strings: "0" "1" "2" "3" "4" "5" "6" "7" "8" "9"; 8 | $numbers: 0 1 2 3 4 5 6 7 8 9; 9 | 10 | // Result 11 | $result: 0; 12 | $divider: 0; 13 | $minus: false; 14 | 15 | // Looping through all characters 16 | @for $i from 1 through str-length($string) { 17 | $character: str-slice($string, $i, $i); 18 | $index: index($strings, $character); 19 | 20 | @if $character == "-" { 21 | $minus: true; 22 | } 23 | 24 | @else if $character == "." { 25 | $divider: 1; 26 | } 27 | 28 | @else { 29 | @if not $index { 30 | $result: if($minus, $result * -1, $result); 31 | @return _convert-units($result, str-slice($string, $i)); 32 | } 33 | 34 | $number: nth($numbers, $index); 35 | 36 | @if $divider == 0 { 37 | $result: $result * 10; 38 | } 39 | 40 | @else { 41 | // Move the decimal dot to the left 42 | $divider: $divider * 10; 43 | $number: $number / $divider; 44 | } 45 | 46 | $result: $result + $number; 47 | } 48 | } 49 | @return if($minus, $result * -1, $result); 50 | } 51 | -------------------------------------------------------------------------------- /src/sass/bourbon/settings/_asset-pipeline.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// A global setting to enable or disable the `$asset-pipeline` variable for all functions that accept it. 4 | /// 5 | /// @type Bool 6 | 7 | $asset-pipeline: false !default; 8 | -------------------------------------------------------------------------------- /src/sass/bourbon/settings/_prefixer.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Global variables to enable or disable vendor prefixes 4 | 5 | $prefix-for-webkit: true !default; 6 | $prefix-for-mozilla: true !default; 7 | $prefix-for-microsoft: true !default; 8 | $prefix-for-opera: true !default; 9 | $prefix-for-spec: true !default; 10 | -------------------------------------------------------------------------------- /src/sass/bourbon/settings/_px-to-em.scss: -------------------------------------------------------------------------------- 1 | $em-base: 16px !default; 2 | -------------------------------------------------------------------------------- /src/sass/spreadIt.scss: -------------------------------------------------------------------------------- 1 | @import 'bourbon/bourbon'; 2 | @import 'columnManager'; 3 | @import 'dropzone'; 4 | 5 | $arrowFontsDir: '../fonts/arrows' !default; 6 | 7 | @font-face { 8 | font-family: 'Arrows'; 9 | src: 10 | url($arrowFontsDir + '/select-arrows.ttf?lym46w') format('truetype'), 11 | url($arrowFontsDir + '/select-arrows.woff?lym46w') format('woff'), 12 | url($arrowFontsDir + '/select-arrows.svg?lym46w#select-arrows') format('svg'); 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/siColumnManager.directive.js: -------------------------------------------------------------------------------- 1 | +function () { 2 | 'use strict'; 3 | 4 | angular.module('bg.spreadit').directive("siColumnManager", ['$timeout', '$parse', '$rootScope', directive]); 5 | 6 | function directive($timeout, $parse, $rootScope) { 7 | var supports = { 8 | xls: !!(window.XLSX && XLSX.utils), 9 | csv: !!(window.Papa && Papa.parse) 10 | }; 11 | 12 | return { 13 | restrict: 'E', 14 | scope: { 15 | id: '@?siId', 16 | callback: '&?siChange', 17 | columns: '=?siColumns', 18 | sampleSize: '=?siSampleSize', 19 | excludeUnknownColumns: '=?siExcludeUnknownColumns', 20 | allowRenaming: '=?siAllowRenaming', 21 | // TODO: add support for these flags 22 | unknownColumnsGroupName: '=?siUnknownColumnsGroupName', 23 | groupUnknownColumns: '=?siGroupUnknownColumns', 24 | postProcessors: '=?siPostProcessors' 25 | }, 26 | controller: ['$scope', '$element', '$attrs', controller], 27 | controllerAs: 'vm', 28 | templateUrl: '/columnManager.html' 29 | }; 30 | 31 | function controller($scope, $element, $attrs) { 32 | 33 | _.defaults($scope, { 34 | id: "", 35 | columns: [], 36 | postProcessors: [], 37 | sampleSize: 3, 38 | excludeUnknownColumns: false, 39 | allowCustomRenaming: true, 40 | unknownColumnGroupName: '$extras', 41 | groupUnknownColumns: false, 42 | callback: angular.noop 43 | }); 44 | 45 | var self = this; 46 | var columnMap = $scope.columns.reduce(function (map, entry) { 47 | 48 | var val; 49 | if (angular.isString(entry)) { 50 | val = { 51 | title: entry, 52 | property: entry 53 | }; 54 | } else { 55 | val = entry; 56 | } 57 | 58 | map[String(val.property).trim().toLowerCase()] = val; 59 | map[String(val.title).trim().toLowerCase()] = val; 60 | if (angular.isArray(entry.aliases)) { 61 | entry.aliases.forEach(function (alias) { 62 | map[String(alias).trim().toLowerCase()] = val; 63 | }); 64 | } 65 | return map; 66 | }, {}); 67 | var titles = _.flatten($scope.columns.map(function (v) { 68 | if (angular.isString(v)) { 69 | return v; 70 | } else if (angular.isArray(v.aliases)) { 71 | return v.aliases.concat(v.title); 72 | } else { 73 | return v.title; 74 | } 75 | })).map(function (v) { 76 | return String(v).trim().toLowerCase(); 77 | }); 78 | 79 | var presult; 80 | var $file; 81 | 82 | $scope.$watch('hasHeader', function () { 83 | 84 | if ($file && self.active) { 85 | parseFile($file); 86 | } 87 | }); 88 | 89 | this.remap = function (mapping) { 90 | 91 | remap(mapping); 92 | this.active = false; 93 | $element.removeClass('active'); 94 | }; 95 | 96 | this.cancel = function () { 97 | this.active = false; 98 | $element.removeClass('active'); 99 | }; 100 | 101 | function isHeader(values) { 102 | 103 | var isIt = $scope.hasHeader || values.some(function (value) { 104 | return titles.indexOf(String(value).trim().toLowerCase()) !== -1; 105 | }); 106 | $scope.hasHeader = isIt; 107 | return isIt; 108 | } 109 | 110 | function isExcel(data) { 111 | return [0xD0, 0x09, 0x3C, 0x50].indexOf(data.charCodeAt(0)) !== -1; 112 | } 113 | 114 | function parseFile(file) { 115 | 116 | if (!file) { 117 | return; 118 | } 119 | 120 | var reader = new FileReader(); 121 | 122 | if (reader.readAsBinaryString) { 123 | 124 | reader.onload = function (e) { 125 | preparse(file, e.target.result); 126 | }; 127 | 128 | reader.readAsBinaryString(file); 129 | } else { 130 | 131 | reader.onload = function (e) { 132 | 133 | /* convert data to binary string */ 134 | var data = new Uint8Array(e.target.result); 135 | var buffer = []; 136 | var i; 137 | for (i = 0; i < data.length; i++) { 138 | buffer[i] = String.fromCharCode(data[i]); 139 | } 140 | preparse(file, buffer.join('')); 141 | }; 142 | reader.readAsArrayBuffer(file) 143 | } 144 | } 145 | 146 | function preparse(file, content) { 147 | 148 | if (supports.xls && isExcel(content)) { 149 | preparseExcel(content); 150 | } else if (supports.csv) { 151 | preparseCSV(file); 152 | } 153 | } 154 | 155 | 156 | function preparseExcel(content) { 157 | 158 | var c; 159 | var workbook = XLSX.read(content, { 160 | type: 'binary', 161 | sheetRows: $scope.sampleSize + 1, 162 | cellHTML: false, 163 | cellFormula: false 164 | }); 165 | var sheet = workbook.Sheets[workbook.SheetNames[0]]; 166 | var headerRange = XLSX.utils.decode_range(sheet['!ref']); 167 | var firstRow = []; 168 | var r = headerRange.s.r; 169 | for (c = headerRange.s.c; c < headerRange.e.c; c++) { 170 | var cell = sheet[XLSX.utils.encode_cell({r: r, c: c})]; 171 | firstRow.push(cell ? String(cell.v).toLowerCase() : null); 172 | } 173 | 174 | var headers; 175 | var i = 1; 176 | if (!isHeader(firstRow)) { 177 | headers = []; 178 | for (c = headerRange.s.c; c <= headerRange.e.c; c++) { 179 | headers.push('Column ' + i++); 180 | } 181 | } 182 | var data = XLSX.utils.sheet_to_json(sheet, { 183 | header: headers, 184 | range: 0 185 | }).slice(0, 3); 186 | 187 | if ($scope.debug) { 188 | window.$spreadIt = { 189 | workbook: workbook, 190 | sheet: sheet, 191 | content: content 192 | } 193 | } 194 | preview({ 195 | type: 'excel', 196 | raw: content, 197 | data: data, 198 | headers: headers || Object.keys(data[0]) 199 | }); 200 | } 201 | 202 | function preparseCsvWithHeader(file) { 203 | 204 | Papa.parse(file, { 205 | header: true, 206 | preview: $scope.sampleSize, 207 | complete: function (result) { 208 | 209 | var headers = Object.keys(result.data[0]); 210 | preview({ 211 | type: 'csv', 212 | data: result.data, 213 | raw: file, 214 | headers: headers 215 | }); 216 | } 217 | }); 218 | } 219 | 220 | function preparseCsvSansHeader(file) { 221 | 222 | Papa.parse(file, { 223 | header: false, 224 | preview: $scope.sampleSize, 225 | complete: function (result) { 226 | 227 | var headers = result.data[0].map(function (column, i) { 228 | return 'Column ' + (i + 1); 229 | }); 230 | 231 | var data = result.data.map(function (columns) { 232 | 233 | var obj = {}; 234 | columns.forEach(function (column, i) { 235 | obj['Column ' + (i + 1)] = column; 236 | }); 237 | return obj; 238 | }); 239 | preview({ 240 | type: 'csv', 241 | headers: headers, 242 | data: data, 243 | raw: file 244 | }); 245 | } 246 | }); 247 | } 248 | 249 | function preparseCSV(file) { 250 | Papa.parse(file, { 251 | preview: 1, 252 | complete: function (result) { 253 | var firstRow = result.data[0]; 254 | if (firstRow && isHeader(firstRow)) { 255 | preparseCsvWithHeader(file); 256 | } else { 257 | preparseCsvSansHeader(file); 258 | } 259 | } 260 | }); 261 | } 262 | 263 | function parseExcel(content, headers) { 264 | var c; 265 | var workbook = XLSX.read(content, { 266 | type: 'binary', 267 | cellHTML: false, 268 | cellFormula: false 269 | }); 270 | var sheet = workbook.Sheets[workbook.SheetNames[0]]; 271 | var headerRange = XLSX.utils.decode_range(sheet['!ref']); 272 | var firstRow = []; 273 | var r = headerRange.s.r; 274 | for (c = headerRange.s.c; c < headerRange.e.c; c++) { 275 | var cell = sheet[XLSX.utils.encode_cell({r: r, c: c})]; 276 | firstRow.push(cell ? String(cell.v).toLowerCase() : null); 277 | } 278 | 279 | var data = XLSX.utils.sheet_to_json(sheet, { 280 | header: headers, 281 | range: isHeader(firstRow) ? 1 : 0 282 | }).map(function (result) { 283 | 284 | delete result.$skip$; 285 | return result; 286 | }); 287 | 288 | 289 | $scope.callback({ 290 | $type: 'excel', 291 | $file: $file, 292 | $data: postProcess(data) 293 | }); 294 | } 295 | 296 | function parseCsv(file, headers) { 297 | 298 | Papa.parse(file, { 299 | header: false, 300 | complete: function (result) { 301 | 302 | var firstRow = result.data[0]; 303 | if (isHeader(firstRow)) { 304 | result.data.splice(0, 1); 305 | } 306 | var data = result.data.map(function (columns) { 307 | 308 | var obj = {}; 309 | columns.forEach(function (column, i) { 310 | 311 | if (headers[i] !== '$skip$') { 312 | obj[headers[i]] = column; 313 | } 314 | }); 315 | return obj; 316 | }); 317 | $scope.callback({ 318 | $type: 'csv', 319 | $file: $file, 320 | $data: postProcess(data) 321 | }); 322 | } 323 | }); 324 | } 325 | 326 | function preview(result) { 327 | 328 | $timeout(function () { 329 | 330 | var preview = self.preview = []; 331 | 332 | result.headers.forEach(function (header) { 333 | 334 | var normalizedHeader = header.toLowerCase().trim(); 335 | var mapping; 336 | if (columnMap[normalizedHeader]) { 337 | mapping = columnMap[normalizedHeader]; 338 | } else if ($scope.excludeUnknownColumns) { 339 | mapping = { 340 | title: 'Ignore This Column', 341 | property: '$skip$' 342 | } 343 | } else { 344 | mapping = { 345 | title: 'Keep This Column', 346 | property: false 347 | }; 348 | } 349 | preview.push({ 350 | header: header, 351 | mapping: mapping, 352 | custom: header, 353 | sample: result.data.map(function (v) { 354 | return v[header]; 355 | }) 356 | }); 357 | }); 358 | var titles = []; 359 | if (!$scope.excludeUnknownColumns) { 360 | titles.push({ 361 | title: 'Keep This Column', 362 | property: false 363 | }); 364 | } 365 | 366 | titles.push({ 367 | title: 'Ignore This Column', 368 | property: '$skip$' 369 | }); 370 | 371 | if (!$scope.excludeUnknownColumns && $scope.allowCustomRenaming) { 372 | titles.push({ 373 | title: 'Rename This Column', 374 | property: '$rename$' 375 | }); 376 | } 377 | 378 | self.titles = titles.concat($scope.columns.map(function (column) { 379 | 380 | if (angular.isObject(column)) { 381 | return column; 382 | } 383 | 384 | return { 385 | title: column, 386 | property: column 387 | } 388 | })); 389 | presult = result; 390 | }); 391 | } 392 | 393 | function remap(mapping) { 394 | 395 | var headers = mapping.map(function (column) { 396 | 397 | var mapping = column.mapping; 398 | if (mapping.property === false) { 399 | return column.header; 400 | } else if (mapping.property === '$rename$') { 401 | return column.custom; 402 | } else { 403 | return column.mapping.property; 404 | } 405 | }); 406 | if (presult.type === 'csv') { 407 | parseCsv(presult.raw, headers); 408 | } else { 409 | parseExcel(presult.raw, headers); 410 | } 411 | } 412 | 413 | $rootScope.$on('si.preview', function (e, id, file) { 414 | 415 | if (file && id === $scope.id) { 416 | $file = file; 417 | $scope.hasHeader = false; 418 | parseFile(file); 419 | self.active = true; 420 | $element.addClass('active'); 421 | } 422 | }); 423 | 424 | function postProcess(data) { 425 | 426 | if(!$scope.postProcessors.length) { 427 | return data; 428 | } 429 | 430 | return data.map(function(obj) { 431 | 432 | $scope.postProcessors.forEach(function(fn) { 433 | fn(obj); 434 | }); 435 | return obj; 436 | }) 437 | } 438 | } 439 | } 440 | 441 | }(); 442 | -------------------------------------------------------------------------------- /src/siDropZone.directive.js: -------------------------------------------------------------------------------- 1 | +function () { 2 | 'use strict'; 3 | 4 | angular.module('bg.spreadit').directive("siDropzone", ['$rootScope', directive]); 5 | angular.module('bg.spreadit').directive("siImporter", ['$rootScope', directive]); 6 | 7 | function directive($rootScope) { 8 | var accepts = []; 9 | 10 | if(!!(window.XLSX && XLSX.utils)) { 11 | accepts.push('.xls', '.xlsx'); 12 | } 13 | 14 | if(!!(window.Papa && Papa.parse)) { 15 | accepts.push('.csv', '.tsv', '.txt'); 16 | } 17 | 18 | return { 19 | restrict: 'E', 20 | scope: { 21 | id: '@siId' 22 | }, 23 | controller: controller, 24 | controllerAs: 'vm', 25 | templateUrl: '/dropzone.html', 26 | link: link 27 | }; 28 | 29 | function controller() { 30 | 31 | } 32 | 33 | function link($scope, $element, $attrs) { 34 | 35 | _.defaults($scope, { 36 | id: "" 37 | }); 38 | 39 | var element = $element[0]; 40 | element.setAttribute('accepts', accepts.join()); 41 | element.querySelector('input[type="file"]').addEventListener('change', function (e) { 42 | $rootScope.$emit('si.preview', $scope.id, e.target.files[0]); 43 | }); 44 | } 45 | } 46 | 47 | }(); 48 | -------------------------------------------------------------------------------- /src/siTrigger.directive.js: -------------------------------------------------------------------------------- 1 | +function () { 2 | 'use strict'; 3 | 4 | angular.module('bg.spreadit').directive("siFileSelect", ['$rootScope', directive]); 5 | angular.module('bg.spreadit').directive("siTrigger", ['$rootScope', directive]); 6 | 7 | function directive($rootScope) { 8 | var accepts = []; 9 | 10 | if(!!(window.XLSX && XLSX.utils)) { 11 | accepts.push('.xls', '.xlsx'); 12 | } 13 | 14 | if(!!(window.Papa && Papa.parse)) { 15 | accepts.push('.csv', '.tsv', '.txt'); 16 | } 17 | 18 | return { 19 | restrict: 'EA', 20 | scope: { 21 | id: '@?siFileSelect' 22 | }, 23 | link: link 24 | }; 25 | 26 | function link($scope, $element, $attrs) { 27 | 28 | var element = $element[0]; 29 | var fileEl = $element; 30 | var tagName = element.tagName.toLowerCase(); 31 | var isFileInput = tagName === 'input' && $attrs.type && $attrs.type.toLowerCase() === 'file'; 32 | var isLink = tagName === 'a'; 33 | 34 | if(angular.isDefined($attrs.siFileSelect)) { 35 | $scope.id = $attrs.siFileSelect; 36 | } 37 | 38 | if (!isFileInput) { 39 | fileEl = angular.element(''); 40 | var label = angular.element(''); 41 | label.css('visibility', 'hidden').css('position', 'absolute').css('overflow', 'hidden') 42 | .css('width', '0px').css('height', '0px').css('border', 'none') 43 | .css('margin', '0px').css('padding', '0px').attr('tabindex', '-1'); 44 | document.body.appendChild(label.append(fileEl)[0]); 45 | $element.on('click', function(e) { 46 | e.preventDefault(); 47 | fileEl[0].click(); 48 | }); 49 | } 50 | 51 | if(isLink) { 52 | $element.attr('href', 'javascript:'); 53 | } 54 | 55 | fileEl.attr('accepts', accepts.join()); 56 | fileEl.on('change', onChange); 57 | 58 | function onChange(e) { 59 | $rootScope.$emit('si.preview', $scope.id, e.target.files[0]); 60 | } 61 | } 62 | } 63 | 64 | }(); 65 | -------------------------------------------------------------------------------- /src/spreadIt.service.js: -------------------------------------------------------------------------------- 1 | +function () { 2 | 'use strict'; 3 | 4 | angular.module('bg.spreadit').service("Spreadit", ['$rootScope', service]); 5 | 6 | function service($rootScope) { 7 | 8 | } 9 | 10 | }(); 11 | --------------------------------------------------------------------------------