├── .bowerrc ├── .buildpacks ├── .gitignore ├── .travis.yml ├── Gruntfile.js ├── LICENSE ├── Makefile ├── Procfile ├── README.md ├── app.py ├── bower.json ├── configure.py ├── local_settings.py ├── package.json ├── requirements.txt ├── static ├── images │ ├── boston_strong.jpg │ ├── boston_strong.png │ ├── favicon.ico │ ├── screenshot1.png │ ├── twilio_logo_white_311x100.png │ └── twilio_logo_white_73x22.png ├── materialize │ ├── .bower.json │ ├── .gitattributes │ ├── CHANGELOG.md │ ├── LICENSE │ ├── bower.json │ ├── dist │ │ ├── css │ │ │ ├── materialize.css │ │ │ └── materialize.min.css │ │ ├── font │ │ │ ├── material-design-icons │ │ │ │ ├── Material-Design-Icons.eot │ │ │ │ ├── Material-Design-Icons.svg │ │ │ │ ├── Material-Design-Icons.ttf │ │ │ │ ├── Material-Design-Icons.woff │ │ │ │ └── Material-Design-Icons.woff2 │ │ │ └── roboto │ │ │ │ ├── Roboto-Bold.ttf │ │ │ │ ├── Roboto-Bold.woff │ │ │ │ ├── Roboto-Bold.woff2 │ │ │ │ ├── Roboto-Light.ttf │ │ │ │ ├── Roboto-Light.woff │ │ │ │ ├── Roboto-Light.woff2 │ │ │ │ ├── Roboto-Medium.ttf │ │ │ │ ├── Roboto-Medium.woff │ │ │ │ ├── Roboto-Medium.woff2 │ │ │ │ ├── Roboto-Regular.ttf │ │ │ │ ├── Roboto-Regular.woff │ │ │ │ ├── Roboto-Regular.woff2 │ │ │ │ ├── Roboto-Thin.ttf │ │ │ │ ├── Roboto-Thin.woff │ │ │ │ └── Roboto-Thin.woff2 │ │ └── js │ │ │ ├── materialize.js │ │ │ └── materialize.min.js │ ├── font │ │ ├── material-design-icons │ │ │ ├── Material-Design-Icons.eot │ │ │ ├── Material-Design-Icons.svg │ │ │ ├── Material-Design-Icons.ttf │ │ │ ├── Material-Design-Icons.woff │ │ │ └── Material-Design-Icons.woff2 │ │ └── roboto │ │ │ ├── Roboto-Bold.ttf │ │ │ ├── Roboto-Bold.woff │ │ │ ├── Roboto-Bold.woff2 │ │ │ ├── Roboto-Light.ttf │ │ │ ├── Roboto-Light.woff │ │ │ ├── Roboto-Light.woff2 │ │ │ ├── Roboto-Medium.ttf │ │ │ ├── Roboto-Medium.woff │ │ │ ├── Roboto-Medium.woff2 │ │ │ ├── Roboto-Regular.ttf │ │ │ ├── Roboto-Regular.woff │ │ │ ├── Roboto-Regular.woff2 │ │ │ ├── Roboto-Thin.ttf │ │ │ ├── Roboto-Thin.woff │ │ │ └── Roboto-Thin.woff2 │ ├── js │ │ ├── animation.js │ │ ├── buttons.js │ │ ├── cards.js │ │ ├── character_counter.js │ │ ├── collapsible.js │ │ ├── date_picker │ │ │ ├── picker.date.js │ │ │ └── picker.js │ │ ├── dropdown.js │ │ ├── forms.js │ │ ├── global.js │ │ ├── hammer.min.js │ │ ├── jquery.easing.1.3.js │ │ ├── jquery.hammer.js │ │ ├── jquery.timeago.min.js │ │ ├── leanModal.js │ │ ├── materialbox.js │ │ ├── parallax.js │ │ ├── pushpin.js │ │ ├── scrollFire.js │ │ ├── scrollspy.js │ │ ├── sideNav.js │ │ ├── slider.js │ │ ├── tabs.js │ │ ├── toasts.js │ │ ├── tooltip.js │ │ ├── transitions.js │ │ ├── velocity.min.js │ │ └── waves.js │ ├── package.js │ ├── sass │ │ ├── components │ │ │ ├── _buttons.scss │ │ │ ├── _cards.scss │ │ │ ├── _collapsible.scss │ │ │ ├── _color.scss │ │ │ ├── _dropdown.scss │ │ │ ├── _form.scss │ │ │ ├── _global.scss │ │ │ ├── _grid.scss │ │ │ ├── _icons-material-design.scss │ │ │ ├── _materialbox.scss │ │ │ ├── _mixins.scss │ │ │ ├── _modal.scss │ │ │ ├── _navbar.scss │ │ │ ├── _normalize.scss │ │ │ ├── _prefixer.scss │ │ │ ├── _preloader.scss │ │ │ ├── _roboto.scss │ │ │ ├── _sideNav.scss │ │ │ ├── _slider.scss │ │ │ ├── _table_of_contents.scss │ │ │ ├── _tabs.scss │ │ │ ├── _toast.scss │ │ │ ├── _tooltip.scss │ │ │ ├── _typography.scss │ │ │ ├── _variables.scss │ │ │ ├── _waves.scss │ │ │ └── date_picker │ │ │ │ ├── _default.date.scss │ │ │ │ ├── _default.scss │ │ │ │ └── _default.time.scss │ │ └── materialize.scss │ └── templates │ │ ├── masonry-template │ │ ├── LICENSE │ │ ├── background1.jpg │ │ ├── background2.jpg │ │ ├── background3.jpg │ │ ├── css │ │ │ └── style.css │ │ └── js │ │ │ ├── init.js │ │ │ └── masonry.pkgd.min.js │ │ ├── parallax-template │ │ ├── LICENSE │ │ ├── background1.jpg │ │ ├── background2.jpg │ │ ├── background3.jpg │ │ ├── css │ │ │ └── style.css │ │ └── js │ │ │ └── init.js │ │ └── starter-template │ │ ├── LICENSE │ │ ├── css │ │ └── style.css │ │ └── js │ │ └── init.js ├── sounds │ └── inbound.mp3 └── styles │ ├── index.css │ ├── source │ ├── index.scss │ ├── theme_color.scss │ └── theme_variables.scss │ └── theme.css ├── templates ├── base.html ├── index.html └── thankyou.html └── tests ├── __init__.py ├── context.py ├── test_assets ├── bad_git_config └── good_git_config ├── test_configure.py ├── test_twilio.py └── test_web.py /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory" : "static/components" 3 | } 4 | -------------------------------------------------------------------------------- /.buildpacks: -------------------------------------------------------------------------------- 1 | https://github.com/heroku/heroku-buildpack-nodejs 2 | https://github.com/ejholmes/heroku-buildpack-bower 3 | https://github.com/heroku/heroku-buildpack-python.git 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | build 3 | include 4 | lib 5 | node_modules 6 | static/components 7 | .Python 8 | *.pyc 9 | *.project 10 | *.pydevproject 11 | *.pyo 12 | *.swp 13 | *.coverage 14 | npm-debug.log 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.6" 4 | - "2.7" 5 | install: 6 | - pip install -r requirements.txt --use-mirrors 7 | script: nosetests 8 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | var port = grunt.option('port') || 8000; 3 | // Project configuration 4 | grunt.initConfig({ 5 | sass: { 6 | theme: { 7 | files: { 8 | 'static/styles/index.css': 'static/materialize/sass/materialize.scss' 9 | } 10 | } 11 | }, 12 | jshint: { 13 | files: [ 'Gruntfile.js', 'static/jss/*.js'], 14 | options: { 15 | globals: { 16 | jQuery: true, 17 | console: true 18 | } 19 | } 20 | }, 21 | open: { 22 | delayed: { 23 | path: 'http://localhost:5000', 24 | options: { 25 | openOn: 'serverListening' 26 | } 27 | } 28 | }, 29 | watch: { 30 | options: { 31 | livereload: true 32 | }, 33 | js: { 34 | files: [ 'Gruntfile.js', 'static/js/*.js' ], 35 | tasks: 'jshint' 36 | }, 37 | theme: { 38 | files: [ 'static/materialize/sass/components/*.scss' ], 39 | tasks: 'sass' 40 | }, 41 | html: { 42 | files: [ 'templates/*.html'] 43 | } 44 | }, 45 | }); 46 | 47 | grunt.loadNpmTasks( 'grunt-sass' ); 48 | grunt.loadNpmTasks( 'grunt-contrib-watch' ); 49 | grunt.loadNpmTasks( 'grunt-contrib-jshint' ); 50 | grunt.loadNpmTasks( 'grunt-open' ); 51 | grunt.loadNpmTasks( 'grunt-connect' ); 52 | 53 | grunt.registerTask( 'default', [ 'sass', 'jshint' ] ); 54 | 55 | grunt.registerTask('flask', 'Run flask server.', function() { 56 | var spawn = require('child_process').spawn; 57 | grunt.log.writeln('Starting Flask development server.'); 58 | // stdio: 'inherit' let us see flask output in grunt 59 | process.env.FLASK_YEOMAN_DEBUG = 1; 60 | var PIPE = {stdio: 'inherit'}; 61 | spawn('python', ['app.py'], PIPE); 62 | grunt.event.emit('serverListening'); 63 | }); 64 | 65 | grunt.registerTask( 'serve', [ 'open', 'flask', 'watch', 'connect' ] ); 66 | }; 67 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Twilio, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | init: 2 | pip install -r requirements.txt --use-mirrors 3 | 4 | test: 5 | nosetests -v tests 6 | 7 | configure: 8 | python configure.py 9 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn app:app -b 0.0.0.0:$PORT -w 3 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Call Your Family 2 | 3 | A free Twilio app to let Boston residents call their families while phone 4 | coverage is poor. 5 | 6 | Built following the tragic loss of life during the Boston Marathon, 15 April 7 | 2013. 8 | 9 | [![Build 10 | Status](https://secure.travis-ci.org/RobSpectre/Call-Your-Family.png?branch=master)](http://travis-ci.org/RobSpectre/Call-Your-Family) 11 | 12 | ## Summary 13 | 14 | Simple app using [Twilio Client](http://www.twilio.com/client) to let folks 15 | affected by the tragedy at the Boston Marathon to call their family. 16 | 17 | It works like this: 18 | 19 | 1. Put a phone number in the input box on the right. 20 | 1. Click call. 21 | 1. Click "Allow" on the permissions dialog that follows. 22 | 1. Speak into the microphone on your laptop or desktop to talk with your family for 23 | up to ten minutes. 24 | 25 | 26 | ## Usage 27 | 28 | Once you deploy this app, you get a simple web form that asks you to put in your 29 | phone number: 30 | 31 | ![Call Form](https://raw.github.com/RobSpectre/Call-Your-Family/master/static/images/screenshot1.png) 32 | 33 | Call is then placed to the number (if it is valid) using Twilio Client. 34 | 35 | 36 | 37 | ## Installation 38 | 39 | Step-by-step on how to deploy and develop this app. 40 | 41 | ### Deploy 42 | 43 | 1) Grab latest source 44 |
 45 | git clone git://github.com/RobSpectre/Call-Your-Family.git 
 46 | 
47 | 48 | 2) Install dependencies 49 |
 50 | make init
 51 | 
52 | 53 | 3) Navigate to folder and create new Heroku Cedar app 54 |
 55 | heroku create --stack cedar
 56 | 
57 | 58 | 4) Deploy to Heroku 59 |
 60 | git push heroku master
 61 | 
62 | 63 | 5) Scale your dynos 64 |
 65 | heroku scale web=1
 66 | 
67 | 68 | 6) Configure Heroku to use your Twilio credentials. 69 |
 70 | python configure.py --account_sid ACxxxxxx --auth_token yyyyyyy
 71 | 
72 | 73 | 7) Open the app in your browser and get an invite! 74 |
 75 | heroku open
 76 | 
77 | 78 | 79 | ### Development 80 | 81 | Be sure to follow the configuration steps above and use this step-by-step 82 | guide to tweak to your heart's content. 83 | 84 | 1) Install the dependencies. 85 |
 86 | make init
 87 | 
88 | 89 | 2) Launch local development webserver 90 |
 91 | foreman start
 92 | 
93 | 94 | 3) Open browser to [http://localhost:5000](http://localhost:5000). 95 | 96 | 4) Tweak away on `app.py`. 97 | 98 | 99 | ## Testing 100 | 101 | This example app comes with a full testing suite with the same kind of form 102 | validation that you would want to use in production. To run the tests, simply 103 | use `nose` with this shortcut command: 104 | 105 |
106 | make test
107 | 
108 | 109 | 110 | ## Anatomy 111 | 112 | This app does have a little more complexity than our usual examples in an effort 113 | to be production-ready. Here's a quick rundown of all the important files: 114 | 115 | * `local_settings.py` - Contains all the configuration options for the app, 116 | including Twilio credentials and the URIs you want to which you wish to direct 117 | your mobile users. 118 | * `app.py` - The meat of the app. Contains all the logic for rendering the 119 | form, sending the invites, and redirecting mobile users. 120 | * `tests` - Test suite testing the web, Twilio and form validation functionality 121 | of this example. 122 | * `templates` - The gorgeous interface I surreptitiously from 123 | [Andres](http://twitter.com/enborra). 124 | * `static` - Location of the styles for above. 125 | 126 | 127 | ## Meta 128 | 129 | * No warranty expressed or implied. Software is as is. Diggity. 130 | * [MIT License](http://www.opensource.org/licenses/mit-license.html) 131 | * Lovingly crafted by [Twilio](http://www.twilio.com) 132 | 133 | 134 | Call your folks. They'd like to hear from you. 135 | 136 | 137 | [![githalytics.com 138 | alpha](https://cruel-carlota.pagodabox.com/cca4f318e2c039d16cdd82106e3c7c30 139 | "githalytics.com")](http://githalytics.com/RobSpectre/Call-Your-Family) 140 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import os 2 | import signal 3 | 4 | 5 | from flask import Flask 6 | from flask import render_template 7 | from flask import url_for 8 | from flask import request 9 | 10 | from twilio import twiml 11 | from twilio.util import TwilioCapability 12 | 13 | 14 | # Declare and configure application 15 | app = Flask(__name__, static_url_path='/static') 16 | app.config.from_pyfile('local_settings.py') 17 | 18 | 19 | @app.route('/', methods=['GET', 'POST']) 20 | def index(): 21 | # Make sure we have this host configured properly. 22 | config_errors = [] 23 | for option in ['TWILIO_ACCOUNT_SID', 'TWILIO_AUTH_TOKEN']: 24 | if not app.config[option]: 25 | config_errors.append("%s is not configured for this host." 26 | % option) 27 | 28 | # Create capability token 29 | capability = TwilioCapability(app.config.get('TWILIO_ACCOUNT_SID', None), 30 | app.config.get('TWILIO_AUTH_TOKEN', None)) 31 | capability.allow_client_outgoing(app.config.get('TWILIO_APP_SID', None)) 32 | token = capability.generate() 33 | 34 | # Define important links 35 | params = { 36 | 'sms_request_url': url_for('.sms', _external=True), 37 | 'token': token, 38 | 'config_errors': config_errors} 39 | 40 | return render_template('index.html', params=params) 41 | 42 | 43 | @app.route('/voice', methods=['POST']) 44 | def voice(): 45 | response = twiml.Response() 46 | with response.dial(callerId=app.config['TWILIO_CALLER_ID'], 47 | timeLimit="600") as dial: 48 | dial.number(request.form['PhoneNumber']) 49 | return str(response) 50 | 51 | 52 | @app.route('/inbound', methods=['POST']) 53 | def inbound(): 54 | response = twiml.Response() 55 | response.play('/static/sounds/inbound.mp3') 56 | return str(response) 57 | 58 | 59 | @app.route('/sms', methods=['GET', 'POST']) 60 | def sms(): 61 | # Respond to any text inbound text message with a link to the app! 62 | response = twiml.Response() 63 | response.sms("This number belongs to the Twilio Call Your Family app " \ 64 | "for Boston. Please visit " \ 65 | "http://callyourfamily.twilio.ly for more info.") 66 | return str(response) 67 | 68 | 69 | # Handles SIGTERM so that we don't get an error when Heroku wants or needs to 70 | # restart the dyno 71 | def graceful_shutdown(signum, frame): 72 | exit() 73 | 74 | signal.signal(signal.SIGTERM, graceful_shutdown) 75 | 76 | 77 | if __name__ == '__main__': 78 | port = int(os.environ.get("PORT", 5000)) 79 | if port == 5000: 80 | app.debug = True 81 | app.run(host='0.0.0.0', port=port) 82 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twilio-call-your-family", 3 | "version": "1.0.0", 4 | "authors": [ 5 | "Rob Spectre " 6 | ], 7 | "description": "A disaster response app for free phone calls in emergencies", 8 | "main": "index.html", 9 | "license": "MIT", 10 | "homepage": "http://www.brooklynhacker.com", 11 | "private": true, 12 | "ignore": [ 13 | "**/.*", 14 | "node_modules", 15 | "bower_components", 16 | "test", 17 | "tests" 18 | ], 19 | "dependencies": { 20 | "materialize": "~0.96.1", 21 | "jquery": "~2.1.3", 22 | "intl-tel-input": "~5.8.7" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /local_settings.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Configuration Settings 3 | ''' 4 | 5 | ''' Uncomment to configure using the file. 6 | WARNING: Be careful not to post your account credentials on GitHub. 7 | 8 | TWILIO_ACCOUNT_SID = "ACxxxxxxxxxxxxx" 9 | TWILIO_AUTH_TOKEN = "yyyyyyyyyyyyyyyy" 10 | TWILIO_APP_SID = "APzzzzzzzzz" 11 | TWILIO_CALLER_ID = "+17778889999" 12 | IOS_URI = "http://phobos.apple.com/whatever" 13 | ANDROID_URI = "http://market.google.com/somethingsomething" 14 | ''' 15 | 16 | # Begin Heroku configuration - configured through environment variables. 17 | import os 18 | TWILIO_ACCOUNT_SID = os.environ.get('TWILIO_ACCOUNT_SID', None) 19 | TWILIO_AUTH_TOKEN = os.environ.get('TWILIO_AUTH_TOKEN', None) 20 | TWILIO_CALLER_ID = os.environ.get('TWILIO_CALLER_ID', None) 21 | TWILIO_APP_SID = os.environ.get('TWILIO_APP_SID', None) 22 | IOS_URI = os.environ.get('IOS_URI', 23 | 'http://itunes.apple.com/us/app/plants-vs.-zombies/id350642635?mt=8&uo=4') 24 | ANDROID_URI = os.environ.get('ANDROID_URI', 25 | 'http://market.android.com/details?id=com.popcap.pvz_row') 26 | WEB_URI = os.environ.get('WEB_URI', 27 | 'http://www.popcap.com/games/plants-vs-zombies/pc') 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twilio-call-your-family", 3 | "version": "1.0.0", 4 | "engines": { 5 | "node": "0.10.x" 6 | }, 7 | "dependencies": { 8 | "bower": "^1.3.12", 9 | "grunt": "^0.4.5", 10 | "grunt-cli": "^0.1.13", 11 | "grunt-contrib-connect": "^0.9.0", 12 | "grunt-contrib-jshint": "^0.11.0", 13 | "grunt-contrib-watch": "^0.6.1", 14 | "grunt-sass": "^0.18.1" 15 | }, 16 | "devDependencies": { 17 | "grunt-connect": "^0.2.0", 18 | "grunt-open": "^0.2.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==0.9 2 | twilio>=3.4.5 3 | mock==0.8.0 4 | gunicorn==0.14.2 5 | -------------------------------------------------------------------------------- /static/images/boston_strong.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/images/boston_strong.jpg -------------------------------------------------------------------------------- /static/images/boston_strong.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/images/boston_strong.png -------------------------------------------------------------------------------- /static/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/images/favicon.ico -------------------------------------------------------------------------------- /static/images/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/images/screenshot1.png -------------------------------------------------------------------------------- /static/images/twilio_logo_white_311x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/images/twilio_logo_white_311x100.png -------------------------------------------------------------------------------- /static/images/twilio_logo_white_73x22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/images/twilio_logo_white_73x22.png -------------------------------------------------------------------------------- /static/materialize/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Materialize", 3 | "version": "0.96.1", 4 | "description": "A modern responsive front-end framework based on Material Design", 5 | "keywords": [ 6 | "css", 7 | "js", 8 | "sass", 9 | "mobile-first", 10 | "responsive", 11 | "front-end", 12 | "framework", 13 | "ux", 14 | "material", 15 | "design" 16 | ], 17 | "main": [ 18 | "bin/materialize.css", 19 | "bin/materialize.js", 20 | "font/material-design-icons/Material-Design-Icons.eot", 21 | "font/material-design-icons/Material-Design-Icons.svg", 22 | "font/material-design-icons/Material-Design-Icons.ttf", 23 | "font/material-design-icons/Material-Design-Icons.woff", 24 | "font/material-design-icons/Material-Design-Icons.woff2", 25 | "font/roboto/Roboto-Bold.ttf", 26 | "font/roboto/Roboto-Bold.woff", 27 | "font/roboto/Roboto-Bold.woff2", 28 | "font/roboto/Roboto-Light.ttf", 29 | "font/roboto/Roboto-Light.woff", 30 | "font/roboto/Roboto-Light.woff2", 31 | "font/roboto/Roboto-Medium.ttf", 32 | "font/roboto/Roboto-Medium.woff", 33 | "font/roboto/Roboto-Medium.woff2", 34 | "font/roboto/Roboto-Regular.ttf", 35 | "font/roboto/Roboto-Regular.woff", 36 | "font/roboto/Roboto-Regular.woff2", 37 | "font/roboto/Roboto-Thin.ttf", 38 | "font/roboto/Roboto-Thin.woff", 39 | "font/roboto/Roboto-Thin.woff2" 40 | ], 41 | "ignore": [ 42 | "jade/", 43 | ".gitignore", 44 | "CNAME", 45 | "css/", 46 | "bower.json", 47 | "README.md", 48 | "images/", 49 | "js/jquery.timeago.js", 50 | "js/init.js", 51 | "js/prism.js", 52 | "res/", 53 | "sass/style.scss", 54 | "sass/ghpages-materialize.scss", 55 | "**/*.html", 56 | "**/*.zip", 57 | "**/*.txt", 58 | "sitemap.xml", 59 | "package.json", 60 | "Gruntfile.js" 61 | ], 62 | "dependencies": { 63 | "jquery": ">=2.1.1" 64 | }, 65 | "homepage": "https://github.com/Dogfalo/materialize", 66 | "_release": "0.96.1", 67 | "_resolution": { 68 | "type": "version", 69 | "tag": "v0.96.1", 70 | "commit": "7cdf0c8852ed14f81c7ee43eb573d8df8589ad94" 71 | }, 72 | "_source": "git://github.com/Dogfalo/materialize.git", 73 | "_target": "~0.96.1", 74 | "_originalSource": "materialize" 75 | } -------------------------------------------------------------------------------- /static/materialize/.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | **/*.html linguist-documentation 3 | -------------------------------------------------------------------------------- /static/materialize/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | - v0.94.0 (Dec 30, 2014) 2 | - Sidenav supports right edge positioning 3 | - Responsive Embeds 4 | - Image Vertical align classes 5 | - border-box added 6 | - Variable file created 7 | - Pushpin added 8 | - Tooltips support all directions 9 | - Layout helper classes added 10 | - Materialbox Fixes 11 | - Form Element Enhancements 12 | - Navbar supports search bar 13 | - Waves fixes 14 | - Materialbox Captions 15 | - Image Slider Fixes 16 | 17 | - v0.93.1 (Dec 20, 2014) 18 | - Flexbox Sticky Footer removed due to IE incompatibility 19 | 20 | - v0.93.0 (Dec 19, 2014) 21 | - Card Reveal 22 | - Image Slider 23 | - Dynamically loaded forms work correctly 24 | - Badges added 25 | - Circular Image 26 | - Waves Fixes 27 | - Footer Added 28 | - Toast support Custom HTML 29 | - Modals support programmatic opening/closing 30 | - Responsive Image support 31 | 32 | - v0.92.1 (Dec 14, 2014) 33 | - Bower semver fix 34 | - Added new radio button style 35 | 36 | - v0.92.0 (Dec 13, 2014) 37 | - Clicking icon in dropdown in navbar no longer closes dropdown immediately 38 | - Multiple select inputs now work properly 39 | - Mobile navbar no longer extends past screen width 40 | - Parallax improved 41 | - Modal restructured / can be opened programmatically 42 | - Callbacks added to modals 43 | - Added dist folder to repo 44 | - Cards restructured 45 | 46 | 47 | - v0.91 (Dec 3, 2014) 48 | - bug fixes to forms 49 | - added waves color classes 50 | - toast thickened to look better on mobile 51 | - many other bug fixes 52 | 53 | 54 | - v0.9 (Nov 30, 2014) 55 | - Touch interactions added 56 | - tons more... -------------------------------------------------------------------------------- /static/materialize/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2015 Materialize 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /static/materialize/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Materialize", 3 | "version": "0.96.1", 4 | "description": "A modern responsive front-end framework based on Material Design", 5 | "keywords": [ 6 | "css", 7 | "js", 8 | "sass", 9 | "mobile-first", 10 | "responsive", 11 | "front-end", 12 | "framework", 13 | "ux", 14 | "material", 15 | "design" 16 | ], 17 | "main": [ 18 | "bin/materialize.css", 19 | "bin/materialize.js", 20 | "font/material-design-icons/Material-Design-Icons.eot", 21 | "font/material-design-icons/Material-Design-Icons.svg", 22 | "font/material-design-icons/Material-Design-Icons.ttf", 23 | "font/material-design-icons/Material-Design-Icons.woff", 24 | "font/material-design-icons/Material-Design-Icons.woff2", 25 | "font/roboto/Roboto-Bold.ttf", 26 | "font/roboto/Roboto-Bold.woff", 27 | "font/roboto/Roboto-Bold.woff2", 28 | "font/roboto/Roboto-Light.ttf", 29 | "font/roboto/Roboto-Light.woff", 30 | "font/roboto/Roboto-Light.woff2", 31 | "font/roboto/Roboto-Medium.ttf", 32 | "font/roboto/Roboto-Medium.woff", 33 | "font/roboto/Roboto-Medium.woff2", 34 | "font/roboto/Roboto-Regular.ttf", 35 | "font/roboto/Roboto-Regular.woff", 36 | "font/roboto/Roboto-Regular.woff2", 37 | "font/roboto/Roboto-Thin.ttf", 38 | "font/roboto/Roboto-Thin.woff", 39 | "font/roboto/Roboto-Thin.woff2" 40 | ], 41 | "ignore": [ 42 | "jade/", 43 | ".gitignore", 44 | "CNAME", 45 | "css/", 46 | "bower.json", 47 | "README.md", 48 | "images/", 49 | "js/jquery.timeago.js", 50 | "js/init.js", 51 | "js/prism.js", 52 | "res/", 53 | "sass/style.scss", 54 | "sass/ghpages-materialize.scss", 55 | "**/*.html", 56 | "**/*.zip", 57 | "**/*.txt", 58 | "sitemap.xml", 59 | "package.json", 60 | "Gruntfile.js" 61 | 62 | ], 63 | "dependencies": { 64 | "jquery": ">=2.1.1" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /static/materialize/dist/font/material-design-icons/Material-Design-Icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/material-design-icons/Material-Design-Icons.eot -------------------------------------------------------------------------------- /static/materialize/dist/font/material-design-icons/Material-Design-Icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/material-design-icons/Material-Design-Icons.ttf -------------------------------------------------------------------------------- /static/materialize/dist/font/material-design-icons/Material-Design-Icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/material-design-icons/Material-Design-Icons.woff -------------------------------------------------------------------------------- /static/materialize/dist/font/material-design-icons/Material-Design-Icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/material-design-icons/Material-Design-Icons.woff2 -------------------------------------------------------------------------------- /static/materialize/dist/font/roboto/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/roboto/Roboto-Bold.ttf -------------------------------------------------------------------------------- /static/materialize/dist/font/roboto/Roboto-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/roboto/Roboto-Bold.woff -------------------------------------------------------------------------------- /static/materialize/dist/font/roboto/Roboto-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/roboto/Roboto-Bold.woff2 -------------------------------------------------------------------------------- /static/materialize/dist/font/roboto/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/roboto/Roboto-Light.ttf -------------------------------------------------------------------------------- /static/materialize/dist/font/roboto/Roboto-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/roboto/Roboto-Light.woff -------------------------------------------------------------------------------- /static/materialize/dist/font/roboto/Roboto-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/roboto/Roboto-Light.woff2 -------------------------------------------------------------------------------- /static/materialize/dist/font/roboto/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/roboto/Roboto-Medium.ttf -------------------------------------------------------------------------------- /static/materialize/dist/font/roboto/Roboto-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/roboto/Roboto-Medium.woff -------------------------------------------------------------------------------- /static/materialize/dist/font/roboto/Roboto-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/roboto/Roboto-Medium.woff2 -------------------------------------------------------------------------------- /static/materialize/dist/font/roboto/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/roboto/Roboto-Regular.ttf -------------------------------------------------------------------------------- /static/materialize/dist/font/roboto/Roboto-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/roboto/Roboto-Regular.woff -------------------------------------------------------------------------------- /static/materialize/dist/font/roboto/Roboto-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/roboto/Roboto-Regular.woff2 -------------------------------------------------------------------------------- /static/materialize/dist/font/roboto/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/roboto/Roboto-Thin.ttf -------------------------------------------------------------------------------- /static/materialize/dist/font/roboto/Roboto-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/roboto/Roboto-Thin.woff -------------------------------------------------------------------------------- /static/materialize/dist/font/roboto/Roboto-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/dist/font/roboto/Roboto-Thin.woff2 -------------------------------------------------------------------------------- /static/materialize/font/material-design-icons/Material-Design-Icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/material-design-icons/Material-Design-Icons.eot -------------------------------------------------------------------------------- /static/materialize/font/material-design-icons/Material-Design-Icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/material-design-icons/Material-Design-Icons.ttf -------------------------------------------------------------------------------- /static/materialize/font/material-design-icons/Material-Design-Icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/material-design-icons/Material-Design-Icons.woff -------------------------------------------------------------------------------- /static/materialize/font/material-design-icons/Material-Design-Icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/material-design-icons/Material-Design-Icons.woff2 -------------------------------------------------------------------------------- /static/materialize/font/roboto/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/roboto/Roboto-Bold.ttf -------------------------------------------------------------------------------- /static/materialize/font/roboto/Roboto-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/roboto/Roboto-Bold.woff -------------------------------------------------------------------------------- /static/materialize/font/roboto/Roboto-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/roboto/Roboto-Bold.woff2 -------------------------------------------------------------------------------- /static/materialize/font/roboto/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/roboto/Roboto-Light.ttf -------------------------------------------------------------------------------- /static/materialize/font/roboto/Roboto-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/roboto/Roboto-Light.woff -------------------------------------------------------------------------------- /static/materialize/font/roboto/Roboto-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/roboto/Roboto-Light.woff2 -------------------------------------------------------------------------------- /static/materialize/font/roboto/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/roboto/Roboto-Medium.ttf -------------------------------------------------------------------------------- /static/materialize/font/roboto/Roboto-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/roboto/Roboto-Medium.woff -------------------------------------------------------------------------------- /static/materialize/font/roboto/Roboto-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/roboto/Roboto-Medium.woff2 -------------------------------------------------------------------------------- /static/materialize/font/roboto/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/roboto/Roboto-Regular.ttf -------------------------------------------------------------------------------- /static/materialize/font/roboto/Roboto-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/roboto/Roboto-Regular.woff -------------------------------------------------------------------------------- /static/materialize/font/roboto/Roboto-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/roboto/Roboto-Regular.woff2 -------------------------------------------------------------------------------- /static/materialize/font/roboto/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/roboto/Roboto-Thin.ttf -------------------------------------------------------------------------------- /static/materialize/font/roboto/Roboto-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/roboto/Roboto-Thin.woff -------------------------------------------------------------------------------- /static/materialize/font/roboto/Roboto-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/font/roboto/Roboto-Thin.woff2 -------------------------------------------------------------------------------- /static/materialize/js/animation.js: -------------------------------------------------------------------------------- 1 | // Custom Easing 2 | jQuery.extend( jQuery.easing, 3 | { 4 | easeInOutMaterial: function (x, t, b, c, d) { 5 | if ((t/=d/2) < 1) return c/2*t*t + b; 6 | return c/4*((t-=2)*t*t + 2) + b; 7 | } 8 | }); 9 | 10 | -------------------------------------------------------------------------------- /static/materialize/js/buttons.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | $(document).ready(function() { 3 | 4 | // jQuery reverse 5 | $.fn.reverse = [].reverse; 6 | 7 | $(document).on('mouseenter.fixedActionBtn', '.fixed-action-btn', function(e) { 8 | var $this = $(this); 9 | 10 | $this.find('ul .btn-floating').velocity( 11 | { scaleY: ".4", scaleX: ".4", translateY: "40px"}, 12 | { duration: 0 }); 13 | 14 | var time = 0; 15 | $this.find('ul .btn-floating').reverse().each(function () { 16 | $(this).velocity( 17 | { opacity: "1", scaleX: "1", scaleY: "1", translateY: "0"}, 18 | { duration: 80, delay: time }); 19 | time += 40; 20 | }); 21 | 22 | }); 23 | 24 | $(document).on('mouseleave.fixedActionBtn', '.fixed-action-btn', function(e) { 25 | var $this = $(this); 26 | 27 | var time = 0; 28 | $this.find('ul .btn-floating').velocity("stop", true); 29 | $this.find('ul .btn-floating').velocity( 30 | { opacity: "0", scaleX: ".4", scaleY: ".4", translateY: "40px"}, 31 | { duration: 80 }); 32 | }); 33 | 34 | }); 35 | }( jQuery )); 36 | -------------------------------------------------------------------------------- /static/materialize/js/cards.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | $(document).ready(function() { 3 | 4 | $(document).on('click.card', '.card', function (e) { 5 | if ($(this).find('.card-reveal').length) { 6 | if ($(e.target).is($('.card-reveal .card-title')) || $(e.target).is($('.card-reveal .card-title i'))) { 7 | // Make Reveal animate down and display none 8 | $(this).find('.card-reveal').velocity( 9 | {translateY: 0}, { 10 | duration: 225, 11 | queue: false, 12 | easing: 'easeInOutQuad', 13 | complete: function() { $(this).css({ display: 'none'}) } 14 | } 15 | ); 16 | } 17 | else if ($(e.target).is($('.card .activator')) || 18 | $(e.target).is($('.card .activator i')) ) { 19 | $(this).find('.card-reveal').css({ display: 'block'}).velocity("stop", false).velocity({translateY: '-100%'}, {duration: 300, queue: false, easing: 'easeInOutQuad'}); 20 | } 21 | } 22 | 23 | 24 | }); 25 | 26 | }); 27 | }( jQuery )); -------------------------------------------------------------------------------- /static/materialize/js/character_counter.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | 3 | $.fn.characterCounter = function(){ 4 | return this.each(function(){ 5 | 6 | itHasLengthAttribute = $(this).attr('length') != undefined; 7 | 8 | if(itHasLengthAttribute){ 9 | $(this).on('input', updateCounter); 10 | $(this).on('focus', updateCounter); 11 | $(this).on('blur', removeCounterElement); 12 | 13 | addCounterElement($(this)); 14 | } 15 | 16 | }); 17 | }; 18 | 19 | function updateCounter(){ 20 | var maxLength = +$(this).attr('length'), 21 | actualLength = +$(this).val().length, 22 | isValidLength = actualLength <= maxLength; 23 | 24 | $(this).parent().find('span[class="character-counter"]') 25 | .html( actualLength + '/' + maxLength); 26 | 27 | addInputStyle(isValidLength, $(this)); 28 | } 29 | 30 | function addCounterElement($input){ 31 | $counterElement = $('') 32 | .addClass('character-counter') 33 | .css('float','right') 34 | .css('font-size','12px') 35 | .css('height', 1); 36 | 37 | $input.parent().append($counterElement); 38 | } 39 | 40 | function removeCounterElement(){ 41 | $(this).parent().find('span[class="character-counter"]').html(''); 42 | } 43 | 44 | function addInputStyle(isValidLength, $input){ 45 | inputHasInvalidClass = $input.hasClass('invalid'); 46 | if (isValidLength && inputHasInvalidClass) { 47 | $input.removeClass('invalid'); 48 | } 49 | else if(!isValidLength && !inputHasInvalidClass){ 50 | $input.removeClass('valid'); 51 | $input.addClass('invalid'); 52 | } 53 | } 54 | 55 | $(document).ready(function(){ 56 | $('input, textarea').characterCounter(); 57 | }); 58 | 59 | }( jQuery )); 60 | -------------------------------------------------------------------------------- /static/materialize/js/collapsible.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | $.fn.collapsible = function(options) { 3 | var defaults = { 4 | accordion: undefined 5 | }; 6 | 7 | options = $.extend(defaults, options); 8 | 9 | 10 | return this.each(function() { 11 | 12 | var $this = $(this); 13 | 14 | var $panel_headers = $(this).find('> li > .collapsible-header'); 15 | 16 | var collapsible_type = $this.data("collapsible"); 17 | 18 | // Turn off any existing event handlers 19 | $this.off('click.collapse', '.collapsible-header'); 20 | $panel_headers.off('click.collapse'); 21 | 22 | 23 | /**************** 24 | Helper Functions 25 | ****************/ 26 | 27 | // Accordion Open 28 | function accordionOpen(object) { 29 | $panel_headers = $this.find('> li > .collapsible-header'); 30 | if (object.hasClass('active')) { 31 | object.parent().addClass('active'); 32 | } 33 | else { 34 | object.parent().removeClass('active'); 35 | } 36 | if (object.parent().hasClass('active')){ 37 | object.siblings('.collapsible-body').stop(true,false).slideDown({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '')}}); 38 | } 39 | else{ 40 | object.siblings('.collapsible-body').stop(true,false).slideUp({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '')}}); 41 | } 42 | 43 | $panel_headers.not(object).removeClass('active').parent().removeClass('active'); 44 | $panel_headers.not(object).parent().children('.collapsible-body').stop(true,false).slideUp( 45 | { 46 | duration: 350, 47 | easing: "easeOutQuart", 48 | queue: false, 49 | complete: 50 | function() { 51 | $(this).css('height', '') 52 | } 53 | }); 54 | } 55 | 56 | // Expandable Open 57 | function expandableOpen(object) { 58 | if (object.hasClass('active')) { 59 | object.parent().addClass('active'); 60 | } 61 | else { 62 | object.parent().removeClass('active'); 63 | } 64 | if (object.parent().hasClass('active')){ 65 | object.siblings('.collapsible-body').stop(true,false).slideDown({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '')}}); 66 | } 67 | else{ 68 | object.siblings('.collapsible-body').stop(true,false).slideUp({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '')}}); 69 | } 70 | } 71 | 72 | /** 73 | * Check if object is children of panel header 74 | * @param {Object} object Jquery object 75 | * @return {Boolean} true if it is children 76 | */ 77 | function isChildrenOfPanelHeader(object) { 78 | 79 | var panelHeader = getPanelHeader(object); 80 | 81 | return panelHeader.length > 0; 82 | } 83 | 84 | /** 85 | * Get panel header from a children element 86 | * @param {Object} object Jquery object 87 | * @return {Object} panel header object 88 | */ 89 | function getPanelHeader(object) { 90 | 91 | return object.closest('li > .collapsible-header'); 92 | } 93 | 94 | /***** End Helper Functions *****/ 95 | 96 | 97 | 98 | if (options.accordion || collapsible_type == "accordion" || collapsible_type == undefined) { // Handle Accordion 99 | // Add click handler to only direct collapsible header children 100 | $panel_headers = $this.find('> li > .collapsible-header'); 101 | $panel_headers.on('click.collapse', function (e) { 102 | var element = $(e.target); 103 | 104 | if (isChildrenOfPanelHeader(element)) { 105 | element = getPanelHeader(element); 106 | } 107 | 108 | element.toggleClass('active'); 109 | accordionOpen(element); 110 | }); 111 | // Open first active 112 | accordionOpen($panel_headers.filter('.active').first()); 113 | } 114 | else { // Handle Expandables 115 | $panel_headers.each(function () { 116 | // Add click handler to only direct collapsible header children 117 | $(this).on('click.collapse', function (e) { 118 | var element = $(e.target); 119 | if (isChildrenOfPanelHeader(element)) { 120 | element = getPanelHeader(element); 121 | } 122 | element.toggleClass('active'); 123 | expandableOpen(element); 124 | }); 125 | // Open any bodies that have the active class 126 | if ($(this).hasClass('active')) { 127 | expandableOpen($(this)); 128 | } 129 | 130 | }); 131 | } 132 | 133 | }); 134 | }; 135 | 136 | $(document).ready(function(){ 137 | $('.collapsible').collapsible(); 138 | }); 139 | }( jQuery )); -------------------------------------------------------------------------------- /static/materialize/js/dropdown.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | 3 | // Add posibility to scroll to selected option 4 | // usefull for select for example 5 | $.fn.scrollTo = function(elem) { 6 | $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem).offset().top); 7 | return this; 8 | }; 9 | 10 | $.fn.dropdown = function (option) { 11 | var defaults = { 12 | inDuration: 300, 13 | outDuration: 225, 14 | constrain_width: true, // Constrains width of dropdown to the activator 15 | hover: false, 16 | gutter: 0, // Spacing from edge 17 | belowOrigin: false 18 | } 19 | 20 | this.each(function(){ 21 | var origin = $(this); 22 | var options = $.extend({}, defaults, option); 23 | 24 | // Dropdown menu 25 | var activates = $("#"+ origin.attr('data-activates')); 26 | 27 | function updateOptions() { 28 | if (origin.data('induration') != undefined) 29 | options.inDuration = origin.data('inDuration'); 30 | if (origin.data('outduration') != undefined) 31 | options.outDuration = origin.data('outDuration'); 32 | if (origin.data('constrainwidth') != undefined) 33 | options.constrain_width = origin.data('constrainwidth'); 34 | if (origin.data('hover') != undefined) 35 | options.hover = origin.data('hover'); 36 | if (origin.data('gutter') != undefined) 37 | options.gutter = origin.data('gutter'); 38 | if (origin.data('beloworigin') != undefined) 39 | options.belowOrigin = origin.data('beloworigin'); 40 | } 41 | 42 | updateOptions(); 43 | 44 | // Attach dropdown to its activator 45 | origin.after(activates); 46 | 47 | /* 48 | Helper function to position and resize dropdown. 49 | Used in hover and click handler. 50 | */ 51 | function placeDropdown() { 52 | // Check html data attributes 53 | updateOptions(); 54 | 55 | // Set Dropdown state 56 | activates.addClass('active'); 57 | 58 | // Constrain width 59 | if (options.constrain_width == true) { 60 | activates.css('width', origin.outerWidth()); 61 | } 62 | var offset = 0; 63 | if (options.belowOrigin == true) { 64 | offset = origin.height(); 65 | } 66 | 67 | // Handle edge alignment 68 | var offsetLeft = origin.offset().left; 69 | var width_difference = 0; 70 | var gutter_spacing = options.gutter; 71 | 72 | 73 | if (offsetLeft + activates.innerWidth() > $(window).width()) { 74 | width_difference = origin.innerWidth() - activates.innerWidth(); 75 | gutter_spacing = gutter_spacing * -1; 76 | } 77 | 78 | // Position dropdown 79 | activates.css({ 80 | position: 'absolute', 81 | top: origin.position().top + offset, 82 | left: origin.position().left + width_difference + gutter_spacing 83 | }); 84 | 85 | 86 | 87 | // Show dropdown 88 | activates.stop(true, true).css('opacity', 0) 89 | .slideDown({ 90 | queue: false, 91 | duration: options.inDuration, 92 | easing: 'easeOutCubic', 93 | complete: function() { 94 | $(this).css('height', ''); 95 | } 96 | }) 97 | .animate( {opacity: 1}, {queue: false, duration: options.inDuration, easing: 'easeOutSine'}); 98 | } 99 | 100 | function hideDropdown() { 101 | activates.fadeOut(options.outDuration); 102 | activates.removeClass('active'); 103 | } 104 | 105 | // Hover 106 | if (options.hover) { 107 | var open = false; 108 | origin.unbind('click.' + origin.attr('id')); 109 | // Hover handler to show dropdown 110 | origin.on('mouseenter', function(e){ // Mouse over 111 | if (open === false) { 112 | placeDropdown(); 113 | open = true 114 | } 115 | }); 116 | origin.on('mouseleave', function(e){ 117 | // If hover on origin then to something other than dropdown content, then close 118 | if(!$(e.toElement).closest('.dropdown-content').is(activates)) { 119 | activates.stop(true, true); 120 | hideDropdown(); 121 | open = false; 122 | } 123 | }); 124 | 125 | activates.on('mouseleave', function(e){ // Mouse out 126 | if(!$(e.toElement).closest('.dropdown-button').is(origin)) { 127 | activates.stop(true, true); 128 | hideDropdown(); 129 | open = false; 130 | } 131 | }); 132 | 133 | // Click 134 | } else { 135 | 136 | // Click handler to show dropdown 137 | origin.unbind('click.' + origin.attr('id')); 138 | origin.bind('click.'+origin.attr('id'), function(e){ 139 | 140 | if ( origin[0] == e.currentTarget && ($(e.target).closest('.dropdown-content').length === 0) ) { 141 | e.preventDefault(); // Prevents button click from moving window 142 | placeDropdown(); 143 | 144 | } 145 | // If origin is clicked and menu is open, close menu 146 | else { 147 | if (origin.hasClass('active')) { 148 | hideDropdown(); 149 | $(document).unbind('click.' + activates.attr('id')); 150 | } 151 | } 152 | // If menu open, add click close handler to document 153 | if (activates.hasClass('active')) { 154 | $(document).bind('click.'+ activates.attr('id'), function (e) { 155 | if (!activates.is(e.target) && !origin.is(e.target) && (!origin.find(e.target).length > 0) ) { 156 | hideDropdown(); 157 | $(document).unbind('click.' + activates.attr('id')); 158 | } 159 | }); 160 | } 161 | }); 162 | 163 | } // End else 164 | 165 | // Listen to open and close event - useful for select component 166 | origin.on('open', placeDropdown); 167 | origin.on('close', hideDropdown); 168 | 169 | 170 | }); 171 | }; // End dropdown plugin 172 | 173 | $(document).ready(function(){ 174 | $('.dropdown-button').dropdown(); 175 | }); 176 | }( jQuery )); 177 | -------------------------------------------------------------------------------- /static/materialize/js/global.js: -------------------------------------------------------------------------------- 1 | Materialize = {}; 2 | 3 | // Unique ID 4 | Materialize.guid = (function() { 5 | function s4() { 6 | return Math.floor((1 + Math.random()) * 0x10000) 7 | .toString(16) 8 | .substring(1); 9 | } 10 | return function() { 11 | return s4() + s4() + '-' + s4() + '-' + s4() + '-' + 12 | s4() + '-' + s4() + s4() + s4(); 13 | }; 14 | })(); 15 | 16 | Materialize.elementOrParentIsFixed = function(element) { 17 | var $element = $(element); 18 | var $checkElements = $element.add($element.parents()); 19 | var isFixed = false; 20 | $checkElements.each(function(){ 21 | if ($(this).css("position") === "fixed") { 22 | isFixed = true; 23 | return false; 24 | } 25 | }); 26 | return isFixed; 27 | } 28 | 29 | // Velocity has conflicts when loaded with jQuery, this will check for it 30 | var Vel; 31 | if ($) { Vel = $.Velocity } else { Vel = Velocity}; 32 | -------------------------------------------------------------------------------- /static/materialize/js/jquery.easing.1.3.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ 3 | * 4 | * Uses the built in easing capabilities added In jQuery 1.1 5 | * to offer multiple easing options 6 | * 7 | * TERMS OF USE - jQuery Easing 8 | * 9 | * Open source under the BSD License. 10 | * 11 | * Copyright © 2008 George McGinley Smith 12 | * All rights reserved. 13 | * 14 | * Redistribution and use in source and binary forms, with or without modification, 15 | * are permitted provided that the following conditions are met: 16 | * 17 | * Redistributions of source code must retain the above copyright notice, this list of 18 | * conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this list 20 | * of conditions and the following disclaimer in the documentation and/or other materials 21 | * provided with the distribution. 22 | * 23 | * Neither the name of the author nor the names of contributors may be used to endorse 24 | * or promote products derived from this software without specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 27 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 28 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 29 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 30 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 31 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 32 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 34 | * OF THE POSSIBILITY OF SUCH DAMAGE. 35 | * 36 | */ 37 | 38 | // t: current time, b: begInnIng value, c: change In value, d: duration 39 | jQuery.easing['jswing'] = jQuery.easing['swing']; 40 | 41 | jQuery.extend( jQuery.easing, 42 | { 43 | def: 'easeOutQuad', 44 | swing: function (x, t, b, c, d) { 45 | //alert(jQuery.easing.default); 46 | return jQuery.easing[jQuery.easing.def](x, t, b, c, d); 47 | }, 48 | easeInQuad: function (x, t, b, c, d) { 49 | return c*(t/=d)*t + b; 50 | }, 51 | easeOutQuad: function (x, t, b, c, d) { 52 | return -c *(t/=d)*(t-2) + b; 53 | }, 54 | easeInOutQuad: function (x, t, b, c, d) { 55 | if ((t/=d/2) < 1) return c/2*t*t + b; 56 | return -c/2 * ((--t)*(t-2) - 1) + b; 57 | }, 58 | easeInCubic: function (x, t, b, c, d) { 59 | return c*(t/=d)*t*t + b; 60 | }, 61 | easeOutCubic: function (x, t, b, c, d) { 62 | return c*((t=t/d-1)*t*t + 1) + b; 63 | }, 64 | easeInOutCubic: function (x, t, b, c, d) { 65 | if ((t/=d/2) < 1) return c/2*t*t*t + b; 66 | return c/2*((t-=2)*t*t + 2) + b; 67 | }, 68 | easeInQuart: function (x, t, b, c, d) { 69 | return c*(t/=d)*t*t*t + b; 70 | }, 71 | easeOutQuart: function (x, t, b, c, d) { 72 | return -c * ((t=t/d-1)*t*t*t - 1) + b; 73 | }, 74 | easeInOutQuart: function (x, t, b, c, d) { 75 | if ((t/=d/2) < 1) return c/2*t*t*t*t + b; 76 | return -c/2 * ((t-=2)*t*t*t - 2) + b; 77 | }, 78 | easeInQuint: function (x, t, b, c, d) { 79 | return c*(t/=d)*t*t*t*t + b; 80 | }, 81 | easeOutQuint: function (x, t, b, c, d) { 82 | return c*((t=t/d-1)*t*t*t*t + 1) + b; 83 | }, 84 | easeInOutQuint: function (x, t, b, c, d) { 85 | if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; 86 | return c/2*((t-=2)*t*t*t*t + 2) + b; 87 | }, 88 | easeInSine: function (x, t, b, c, d) { 89 | return -c * Math.cos(t/d * (Math.PI/2)) + c + b; 90 | }, 91 | easeOutSine: function (x, t, b, c, d) { 92 | return c * Math.sin(t/d * (Math.PI/2)) + b; 93 | }, 94 | easeInOutSine: function (x, t, b, c, d) { 95 | return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; 96 | }, 97 | easeInExpo: function (x, t, b, c, d) { 98 | return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; 99 | }, 100 | easeOutExpo: function (x, t, b, c, d) { 101 | return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; 102 | }, 103 | easeInOutExpo: function (x, t, b, c, d) { 104 | if (t==0) return b; 105 | if (t==d) return b+c; 106 | if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; 107 | return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; 108 | }, 109 | easeInCirc: function (x, t, b, c, d) { 110 | return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; 111 | }, 112 | easeOutCirc: function (x, t, b, c, d) { 113 | return c * Math.sqrt(1 - (t=t/d-1)*t) + b; 114 | }, 115 | easeInOutCirc: function (x, t, b, c, d) { 116 | if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; 117 | return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; 118 | }, 119 | easeInElastic: function (x, t, b, c, d) { 120 | var s=1.70158;var p=0;var a=c; 121 | if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; 122 | if (a < Math.abs(c)) { a=c; var s=p/4; } 123 | else var s = p/(2*Math.PI) * Math.asin (c/a); 124 | return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; 125 | }, 126 | easeOutElastic: function (x, t, b, c, d) { 127 | var s=1.70158;var p=0;var a=c; 128 | if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; 129 | if (a < Math.abs(c)) { a=c; var s=p/4; } 130 | else var s = p/(2*Math.PI) * Math.asin (c/a); 131 | return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; 132 | }, 133 | easeInOutElastic: function (x, t, b, c, d) { 134 | var s=1.70158;var p=0;var a=c; 135 | if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); 136 | if (a < Math.abs(c)) { a=c; var s=p/4; } 137 | else var s = p/(2*Math.PI) * Math.asin (c/a); 138 | if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; 139 | return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; 140 | }, 141 | easeInBack: function (x, t, b, c, d, s) { 142 | if (s == undefined) s = 1.70158; 143 | return c*(t/=d)*t*((s+1)*t - s) + b; 144 | }, 145 | easeOutBack: function (x, t, b, c, d, s) { 146 | if (s == undefined) s = 1.70158; 147 | return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; 148 | }, 149 | easeInOutBack: function (x, t, b, c, d, s) { 150 | if (s == undefined) s = 1.70158; 151 | if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; 152 | return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; 153 | }, 154 | easeInBounce: function (x, t, b, c, d) { 155 | return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b; 156 | }, 157 | easeOutBounce: function (x, t, b, c, d) { 158 | if ((t/=d) < (1/2.75)) { 159 | return c*(7.5625*t*t) + b; 160 | } else if (t < (2/2.75)) { 161 | return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; 162 | } else if (t < (2.5/2.75)) { 163 | return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; 164 | } else { 165 | return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; 166 | } 167 | }, 168 | easeInOutBounce: function (x, t, b, c, d) { 169 | if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b; 170 | return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b; 171 | } 172 | }); 173 | 174 | /* 175 | * 176 | * TERMS OF USE - EASING EQUATIONS 177 | * 178 | * Open source under the BSD License. 179 | * 180 | * Copyright © 2001 Robert Penner 181 | * All rights reserved. 182 | * 183 | * Redistribution and use in source and binary forms, with or without modification, 184 | * are permitted provided that the following conditions are met: 185 | * 186 | * Redistributions of source code must retain the above copyright notice, this list of 187 | * conditions and the following disclaimer. 188 | * Redistributions in binary form must reproduce the above copyright notice, this list 189 | * of conditions and the following disclaimer in the documentation and/or other materials 190 | * provided with the distribution. 191 | * 192 | * Neither the name of the author nor the names of contributors may be used to endorse 193 | * or promote products derived from this software without specific prior written permission. 194 | * 195 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 196 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 197 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 198 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 199 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 200 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 201 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 202 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 203 | * OF THE POSSIBILITY OF SUCH DAMAGE. 204 | * 205 | */ -------------------------------------------------------------------------------- /static/materialize/js/jquery.hammer.js: -------------------------------------------------------------------------------- 1 | (function(factory) { 2 | if (typeof define === 'function' && define.amd) { 3 | define(['jquery', 'hammerjs'], factory); 4 | } else if (typeof exports === 'object') { 5 | factory(require('jquery'), require('hammerjs')); 6 | } else { 7 | factory(jQuery, Hammer); 8 | } 9 | }(function($, Hammer) { 10 | function hammerify(el, options) { 11 | var $el = $(el); 12 | if(!$el.data("hammer")) { 13 | $el.data("hammer", new Hammer($el[0], options)); 14 | } 15 | } 16 | 17 | $.fn.hammer = function(options) { 18 | return this.each(function() { 19 | hammerify(this, options); 20 | }); 21 | }; 22 | 23 | // extend the emit method to also trigger jQuery events 24 | Hammer.Manager.prototype.emit = (function(originalEmit) { 25 | return function(type, data) { 26 | originalEmit.call(this, type, data); 27 | $(this.element).trigger({ 28 | type: type, 29 | gesture: data 30 | }); 31 | }; 32 | })(Hammer.Manager.prototype.emit); 33 | })); 34 | -------------------------------------------------------------------------------- /static/materialize/js/jquery.timeago.min.js: -------------------------------------------------------------------------------- 1 | !function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(t){function e(){var e=a(this),o=r.settings;return isNaN(e.datetime)||(0==o.cutoff||Math.abs(n(e.datetime))0)||r.isTime(e)&&e.attr("title")||e.attr("title",a)}return e.data("timeago")}function i(t){return r.inWords(n(t))}function n(t){return(new Date).getTime()-t.getTime()}t.timeago=function(e){return i(e instanceof Date?e:"string"==typeof e?t.timeago.parse(e):"number"==typeof e?new Date(e):t.timeago.datetime(e))};var r=t.timeago;t.extend(t.timeago,{settings:{refreshMillis:6e4,allowPast:!0,allowFuture:!1,localeTitle:!1,cutoff:0,strings:{prefixAgo:null,prefixFromNow:null,suffixAgo:"ago",suffixFromNow:"from now",inPast:"any moment now",seconds:"less than a minute",minute:"about a minute",minutes:"%d minutes",hour:"about an hour",hours:"about %d hours",day:"a day",days:"%d days",month:"about a month",months:"%d months",year:"about a year",years:"%d years",wordSeparator:" ",numbers:[]}},inWords:function(e){function a(a,n){var r=t.isFunction(a)?a(n,e):a,o=i.numbers&&i.numbers[n]||n;return r.replace(/%d/i,o)}if(!this.settings.allowPast&&!this.settings.allowFuture)throw"timeago allowPast and allowFuture settings can not both be set to false.";var i=this.settings.strings,n=i.prefixAgo,r=i.suffixAgo;if(this.settings.allowFuture&&0>e&&(n=i.prefixFromNow,r=i.suffixFromNow),!this.settings.allowPast&&e>=0)return this.settings.strings.inPast;var o=Math.abs(e)/1e3,s=o/60,u=s/60,m=u/24,l=m/365,d=45>o&&a(i.seconds,Math.round(o))||90>o&&a(i.minute,1)||45>s&&a(i.minutes,Math.round(s))||90>s&&a(i.hour,1)||24>u&&a(i.hours,Math.round(u))||42>u&&a(i.day,1)||30>m&&a(i.days,Math.round(m))||45>m&&a(i.month,1)||365>m&&a(i.months,Math.round(m/30))||1.5>l&&a(i.year,1)||a(i.years,Math.round(l)),f=i.wordSeparator||"";return void 0===i.wordSeparator&&(f=" "),t.trim([n,d,r].join(f))},parse:function(e){var a=t.trim(e);return a=a.replace(/\.\d+/,""),a=a.replace(/-/,"/").replace(/-/,"/"),a=a.replace(/T/," ").replace(/Z/," UTC"),a=a.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"),a=a.replace(/([\+\-]\d\d)$/," $100"),new Date(a)},datetime:function(e){var a=t(e).attr(r.isTime(e)?"datetime":"title");return r.parse(a)},isTime:function(e){return"time"===t(e).get(0).tagName.toLowerCase()}});var o={init:function(){var a=t.proxy(e,this);a();var i=r.settings;i.refreshMillis>0&&(this._timeagoInterval=setInterval(a,i.refreshMillis))},update:function(a){var i=r.parse(a);t(this).data("timeago",{datetime:i}),r.settings.localeTitle&&t(this).attr("title",i.toLocaleString()),e.apply(this)},updateFromDOM:function(){t(this).data("timeago",{datetime:r.parse(t(this).attr(r.isTime(this)?"datetime":"title"))}),e.apply(this)},dispose:function(){this._timeagoInterval&&(window.clearInterval(this._timeagoInterval),this._timeagoInterval=null)}};t.fn.timeago=function(t,e){var a=t?o[t]:o.init;if(!a)throw new Error("Unknown function name '"+t+"' for timeago");return this.each(function(){a.call(this,e)}),this},document.createElement("abbr"),document.createElement("time")}); -------------------------------------------------------------------------------- /static/materialize/js/leanModal.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | $.fn.extend({ 3 | openModal: function(options) { 4 | var modal = this; 5 | var overlay = $('
'); 6 | $("body").append(overlay); 7 | 8 | var defaults = { 9 | opacity: 0.5, 10 | in_duration: 350, 11 | out_duration: 250, 12 | ready: undefined, 13 | complete: undefined, 14 | dismissible: true 15 | } 16 | 17 | // Override defaults 18 | options = $.extend(defaults, options); 19 | 20 | if (options.dismissible) { 21 | $("#lean-overlay").click(function() { 22 | $(modal).closeModal(options); 23 | }); 24 | // Return on ESC 25 | $(document).on('keyup.leanModal', function(e) { 26 | if (e.keyCode === 27) { // ESC key 27 | $(modal).closeModal(options); 28 | } 29 | }); 30 | } 31 | 32 | $(modal).find(".modal-close").click(function(e) { 33 | $(modal).closeModal(options); 34 | }); 35 | 36 | $("#lean-overlay").css({ display : "block", opacity : 0 }); 37 | 38 | $(modal).css({ 39 | display : "block", 40 | opacity: 0 41 | }); 42 | 43 | $("#lean-overlay").velocity({opacity: options.opacity}, {duration: options.in_duration, queue: false, ease: "easeOutCubic"}); 44 | 45 | 46 | // Define Bottom Sheet animation 47 | if ($(modal).hasClass('bottom-sheet')) { 48 | $(modal).velocity({bottom: "0", opacity: 1}, { 49 | duration: options.in_duration, 50 | queue: false, 51 | ease: "easeOutCubic", 52 | // Handle modal ready callback 53 | complete: function() { 54 | if (typeof(options.ready) === "function") { 55 | options.ready(); 56 | } 57 | } 58 | }); 59 | } 60 | else { 61 | $(modal).css({ top: "4%" }); 62 | $(modal).velocity({top: "10%", opacity: 1}, { 63 | duration: options.in_duration, 64 | queue: false, 65 | ease: "easeOutCubic", 66 | // Handle modal ready callback 67 | complete: function() { 68 | if (typeof(options.ready) === "function") { 69 | options.ready(); 70 | } 71 | } 72 | }); 73 | } 74 | 75 | 76 | } 77 | }); 78 | 79 | $.fn.extend({ 80 | closeModal: function(options) { 81 | var defaults = { 82 | out_duration: 250, 83 | complete: undefined 84 | } 85 | var options = $.extend(defaults, options); 86 | 87 | $('.modal-close').off(); 88 | $(document).off('keyup.leanModal'); 89 | 90 | $("#lean-overlay").velocity( { opacity: 0}, {duration: options.out_duration, queue: false, ease: "easeOutQuart"}); 91 | 92 | 93 | // Define Bottom Sheet animation 94 | if ($(this).hasClass('bottom-sheet')) { 95 | $(this).velocity({bottom: "-100%", opacity: 0}, { 96 | duration: options.out_duration, 97 | queue: false, 98 | ease: "easeOutCubic", 99 | // Handle modal ready callback 100 | complete: function() { 101 | $("#lean-overlay").css({display:"none"}); 102 | 103 | // Call complete callback 104 | if (typeof(options.complete) === "function") { 105 | options.complete(); 106 | } 107 | $('#lean-overlay').remove(); 108 | } 109 | }); 110 | } 111 | else { 112 | $(this).fadeOut(options.out_duration, function() { 113 | $(this).css({ top: 0}); 114 | $("#lean-overlay").css({display:"none"}); 115 | 116 | // Call complete callback 117 | if (typeof(options.complete) === "function") { 118 | options.complete(); 119 | } 120 | $('#lean-overlay').remove(); 121 | }); 122 | } 123 | 124 | } 125 | }) 126 | 127 | $.fn.extend({ 128 | leanModal: function(options) { 129 | return this.each(function() { 130 | // Close Handlers 131 | $(this).click(function(e) { 132 | var modal_id = $(this).attr("href") || '#' + $(this).data('target'); 133 | $(modal_id).openModal(options); 134 | e.preventDefault(); 135 | }); // done set on click 136 | }); // done return 137 | } 138 | }); 139 | })(jQuery); 140 | -------------------------------------------------------------------------------- /static/materialize/js/materialbox.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | 3 | $.fn.materialbox = function () { 4 | 5 | return this.each(function() { 6 | 7 | if ($(this).hasClass('intialized')) { 8 | return; 9 | } 10 | 11 | $(this).addClass('intialized'); 12 | 13 | var overlayActive = false; 14 | var doneAnimating = true; 15 | var inDuration = 275; 16 | var outDuration = 200; 17 | var origin = $(this); 18 | var placeholder = $('
').addClass('material-placeholder'); 19 | var originalWidth = 0; 20 | var originalHeight = 0; 21 | origin.wrap(placeholder); 22 | 23 | 24 | origin.on('click', function(){ 25 | var placeholder = origin.parent('.material-placeholder'); 26 | var windowWidth = window.innerWidth; 27 | var windowHeight = window.innerHeight; 28 | var originalWidth = origin.width(); 29 | var originalHeight = origin.height(); 30 | 31 | 32 | // If already modal, return to original 33 | if (doneAnimating === false) { 34 | returnToOriginal(); 35 | return false; 36 | } 37 | else if (overlayActive && doneAnimating===true) { 38 | returnToOriginal(); 39 | return false; 40 | } 41 | 42 | 43 | // Set states 44 | doneAnimating = false; 45 | origin.addClass('active'); 46 | overlayActive = true; 47 | 48 | // Set positioning for placeholder 49 | 50 | placeholder.css({ 51 | width: placeholder[0].getBoundingClientRect().width, 52 | height: placeholder[0].getBoundingClientRect().height, 53 | position: 'relative', 54 | top: 0, 55 | left: 0 56 | }); 57 | 58 | 59 | 60 | // Set css on origin 61 | origin.css({position: 'absolute', 'z-index': 1000}) 62 | .data('width', originalWidth) 63 | .data('height', originalHeight); 64 | 65 | // Add overlay 66 | var overlay = $('
') 67 | .css({ 68 | opacity: 0 69 | }) 70 | .click(function(){ 71 | if (doneAnimating === true) 72 | returnToOriginal(); 73 | }); 74 | // Animate Overlay 75 | $('body').append(overlay); 76 | overlay.velocity({opacity: 1}, {duration: inDuration, queue: false, easing: 'easeOutQuad'} 77 | ); 78 | 79 | 80 | // Add and animate caption if it exists 81 | if (origin.data('caption') !== "") { 82 | var $photo_caption = $('
'); 83 | $photo_caption.text(origin.data('caption')); 84 | $('body').append($photo_caption); 85 | $photo_caption.css({ "display": "inline" }); 86 | $photo_caption.velocity({opacity: 1}, {duration: inDuration, queue: false, easing: 'easeOutQuad'}) 87 | } 88 | 89 | 90 | 91 | // Resize Image 92 | var ratio = 0; 93 | var widthPercent = originalWidth / windowWidth; 94 | var heightPercent = originalHeight / windowHeight; 95 | var newWidth = 0; 96 | var newHeight = 0; 97 | 98 | if (widthPercent > heightPercent) { 99 | ratio = originalHeight / originalWidth; 100 | newWidth = windowWidth * 0.9; 101 | newHeight = windowWidth * 0.9 * ratio; 102 | } 103 | else { 104 | ratio = originalWidth / originalHeight; 105 | newWidth = (windowHeight * 0.9) * ratio; 106 | newHeight = windowHeight * 0.9; 107 | } 108 | 109 | // Animate image + set z-index 110 | if(origin.hasClass('responsive-img')) { 111 | origin.velocity({'max-width': newWidth, 'width': originalWidth}, {duration: 0, queue: false, 112 | complete: function(){ 113 | origin.css({left: 0, top: 0}) 114 | .velocity( 115 | { 116 | height: newHeight, 117 | width: newWidth, 118 | left: $(document).scrollLeft() + windowWidth/2 - origin.parent('.material-placeholder').offset().left - newWidth/2, 119 | top: $(document).scrollTop() + windowHeight/2 - origin.parent('.material-placeholder').offset().top - newHeight/ 2 120 | }, 121 | { 122 | duration: inDuration, 123 | queue: false, 124 | easing: 'easeOutQuad', 125 | complete: function(){doneAnimating = true;} 126 | } 127 | ); 128 | } // End Complete 129 | }); // End Velocity 130 | } 131 | else { 132 | origin.css('left', 0) 133 | .css('top', 0) 134 | .velocity( 135 | { 136 | height: newHeight, 137 | width: newWidth, 138 | left: $(document).scrollLeft() + windowWidth/2 - origin.parent('.material-placeholder').offset().left - newWidth/2, 139 | top: $(document).scrollTop() + windowHeight/2 - origin.parent('.material-placeholder').offset().top - newHeight/ 2 140 | }, 141 | { 142 | duration: inDuration, 143 | queue: false, 144 | easing: 'easeOutQuad', 145 | complete: function(){doneAnimating = true;} 146 | } 147 | ); // End Velocity 148 | } 149 | 150 | }); // End origin on click 151 | 152 | 153 | // Return on scroll 154 | $(window).scroll(function() { 155 | if (overlayActive ) { 156 | returnToOriginal(); 157 | } 158 | }); 159 | 160 | // Return on ESC 161 | $(document).keyup(function(e) { 162 | 163 | if (e.keyCode === 27 && doneAnimating === true) { // ESC key 164 | if (overlayActive) { 165 | returnToOriginal(); 166 | } 167 | } 168 | }); 169 | 170 | 171 | // This function returns the modaled image to the original spot 172 | function returnToOriginal() { 173 | 174 | doneAnimating = false; 175 | 176 | var placeholder = origin.parent('.material-placeholder'); 177 | var windowWidth = window.innerWidth; 178 | var windowHeight = window.innerHeight; 179 | var originalWidth = origin.data('width'); 180 | var originalHeight = origin.data('height'); 181 | 182 | origin.velocity("stop", true); 183 | $('#materialbox-overlay').velocity("stop", true); 184 | $('.materialbox-caption').velocity("stop", true); 185 | 186 | 187 | $('#materialbox-overlay').velocity({opacity: 0}, { 188 | duration: outDuration, // Delay prevents animation overlapping 189 | queue: false, easing: 'easeOutQuad', 190 | complete: function(){ 191 | // Remove Overlay 192 | overlayActive = false; 193 | $(this).remove(); 194 | } 195 | }); 196 | 197 | // Resize Image 198 | origin.velocity( 199 | { 200 | width: originalWidth, 201 | height: originalHeight, 202 | left: 0, 203 | top: 0 204 | }, 205 | { 206 | duration: outDuration, 207 | queue: false, easing: 'easeOutQuad' 208 | } 209 | ); 210 | 211 | // Remove Caption + reset css settings on image 212 | $('.materialbox-caption').velocity({opacity: 0}, { 213 | duration: outDuration, // Delay prevents animation overlapping 214 | queue: false, easing: 'easeOutQuad', 215 | complete: function(){ 216 | placeholder.css({ 217 | height: '', 218 | width: '', 219 | position: '', 220 | top: '', 221 | left: '' 222 | }); 223 | 224 | origin.css({ 225 | height: '', 226 | top: '', 227 | left: '', 228 | width: '', 229 | 'max-width': '', 230 | position: '', 231 | 'z-index': '' 232 | }); 233 | 234 | // Remove class 235 | origin.removeClass('active'); 236 | doneAnimating = true; 237 | $(this).remove(); 238 | } 239 | }); 240 | 241 | } 242 | }); 243 | }; 244 | 245 | $(document).ready(function(){ 246 | $('.materialboxed').materialbox(); 247 | }); 248 | 249 | }( jQuery )); 250 | -------------------------------------------------------------------------------- /static/materialize/js/parallax.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | 3 | $.fn.parallax = function () { 4 | var window_width = $(window).width(); 5 | // Parallax Scripts 6 | return this.each(function(i) { 7 | var $this = $(this); 8 | $this.addClass('parallax'); 9 | 10 | function updateParallax(initial) { 11 | var container_height; 12 | if (window_width < 601) { 13 | container_height = ($this.height() > 0) ? $this.height() : $this.children("img").height(); 14 | } 15 | else { 16 | container_height = ($this.height() > 0) ? $this.height() : 500; 17 | } 18 | var $img = $this.children("img").first(); 19 | var img_height = $img.height(); 20 | var parallax_dist = img_height - container_height; 21 | var bottom = $this.offset().top + container_height; 22 | var top = $this.offset().top; 23 | var scrollTop = $(window).scrollTop(); 24 | var windowHeight = window.innerHeight; 25 | var windowBottom = scrollTop + windowHeight; 26 | var percentScrolled = (windowBottom - top) / (container_height + windowHeight); 27 | var parallax = Math.round((parallax_dist * percentScrolled)); 28 | 29 | if (initial) { 30 | $img.css('display', 'block'); 31 | } 32 | if ((bottom > scrollTop) && (top < (scrollTop + windowHeight))) { 33 | $img.css('transform', "translate3D(-50%," + parallax + "px, 0)"); 34 | } 35 | 36 | } 37 | 38 | // Wait for image load 39 | $this.children("img").one("load", function() { 40 | updateParallax(true); 41 | }).each(function() { 42 | if(this.complete) $(this).load(); 43 | }); 44 | 45 | $(window).scroll(function() { 46 | window_width = $(window).width(); 47 | updateParallax(false); 48 | }); 49 | 50 | $(window).resize(function() { 51 | window_width = $(window).width(); 52 | updateParallax(false); 53 | }); 54 | 55 | }); 56 | 57 | }; 58 | }( jQuery )); -------------------------------------------------------------------------------- /static/materialize/js/pushpin.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | $(document).ready(function() { 3 | 4 | $.fn.pushpin = function (options) { 5 | 6 | var defaults = { 7 | top: 0, 8 | bottom: Infinity, 9 | offset: 0 10 | } 11 | options = $.extend(defaults, options); 12 | 13 | $index = 0; 14 | return this.each(function() { 15 | var $uniqueId = Materialize.guid(), 16 | $this = $(this), 17 | $original_offset = $(this).offset().top; 18 | 19 | function removePinClasses(object) { 20 | object.removeClass('pin-top'); 21 | object.removeClass('pinned'); 22 | object.removeClass('pin-bottom'); 23 | } 24 | 25 | function updateElements(objects, scrolled) { 26 | objects.each(function () { 27 | // Add position fixed (because its between top and bottom) 28 | if (options.top <= scrolled && options.bottom >= scrolled && !$(this).hasClass('pinned')) { 29 | removePinClasses($(this)); 30 | $(this).css('top', options.offset); 31 | $(this).addClass('pinned'); 32 | } 33 | 34 | // Add pin-top (when scrolled position is above top) 35 | if (scrolled < options.top && !$(this).hasClass('pin-top')) { 36 | removePinClasses($(this)); 37 | $(this).css('top', 0); 38 | $(this).addClass('pin-top'); 39 | } 40 | 41 | // Add pin-bottom (when scrolled position is below bottom) 42 | if (scrolled > options.bottom && !$(this).hasClass('pin-bottom')) { 43 | removePinClasses($(this)); 44 | $(this).addClass('pin-bottom'); 45 | $(this).css('top', options.bottom - $original_offset); 46 | } 47 | }); 48 | } 49 | 50 | updateElements($this, $(window).scrollTop()); 51 | $(window).on('scroll.' + $uniqueId, function () { 52 | var $scrolled = $(window).scrollTop() + options.offset; 53 | updateElements($this, $scrolled); 54 | }); 55 | 56 | }); 57 | 58 | }; 59 | 60 | 61 | }); 62 | }( jQuery )); -------------------------------------------------------------------------------- /static/materialize/js/scrollFire.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 3 | // Input: Array of JSON objects {selector, offset, callback} 4 | 5 | Materialize.scrollFire = function(options) { 6 | 7 | var didScroll = false; 8 | 9 | window.addEventListener("scroll", function() { 10 | didScroll = true; 11 | }); 12 | 13 | // Rate limit to 100ms 14 | setInterval(function() { 15 | if(didScroll) { 16 | didScroll = false; 17 | 18 | var windowScroll = window.pageYOffset + window.innerHeight; 19 | 20 | for (var i = 0 ; i < options.length; i++) { 21 | // Get options from each line 22 | var value = options[i]; 23 | var selector = value.selector, 24 | offset = value.offset, 25 | callback = value.callback; 26 | 27 | var currentElement = document.querySelector(selector); 28 | if ( currentElement !== null) { 29 | var elementOffset = currentElement.getBoundingClientRect().top + document.body.scrollTop; 30 | 31 | if (windowScroll > (elementOffset + offset)) { 32 | if (value.done != true) { 33 | var callbackFunc = new Function(callback); 34 | callbackFunc(); 35 | value.done = true; 36 | } 37 | } 38 | } 39 | }; 40 | } 41 | }, 100); 42 | 43 | 44 | // $(window).scroll(function () { 45 | // var windowScroll = $(window).scrollTop() + $(window).height(); 46 | 47 | // $.each( options, function( i, value ){ 48 | // var selector = value.selector, 49 | // offset = value.offset, 50 | // callback = value.callback; 51 | 52 | // if ($(selector).length != 0) { 53 | // var elementOffset = $(selector).offset().top; 54 | 55 | // if (windowScroll > (elementOffset + offset)) { 56 | // if (value.done != true) { 57 | // var callbackFunc = new Function(callback); 58 | // callbackFunc(); 59 | // value.done = true; 60 | // } 61 | // } 62 | // } 63 | 64 | // }); 65 | // }); 66 | 67 | } 68 | 69 | })(jQuery); -------------------------------------------------------------------------------- /static/materialize/js/scrollspy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Extend jquery with a scrollspy plugin. 3 | * This watches the window scroll and fires events when elements are scrolled into viewport. 4 | * 5 | * throttle() and getTime() taken from Underscore.js 6 | * https://github.com/jashkenas/underscore 7 | * 8 | * @author Copyright 2013 John Smart 9 | * @license https://raw.github.com/thesmart/jquery-scrollspy/master/LICENSE 10 | * @see https://github.com/thesmart 11 | * @version 0.1.2 12 | */ 13 | (function($) { 14 | 15 | var jWindow = $(window); 16 | var elements = []; 17 | var elementsInView = []; 18 | var isSpying = false; 19 | var ticks = 0; 20 | var unique_id = 1; 21 | var offset = { 22 | top : 0, 23 | right : 0, 24 | bottom : 0, 25 | left : 0, 26 | } 27 | 28 | /** 29 | * Find elements that are within the boundary 30 | * @param {number} top 31 | * @param {number} right 32 | * @param {number} bottom 33 | * @param {number} left 34 | * @return {jQuery} A collection of elements 35 | */ 36 | function findElements(top, right, bottom, left) { 37 | var hits = $(); 38 | $.each(elements, function(i, element) { 39 | if (element.height() > 0) { 40 | var elTop = element.offset().top, 41 | elLeft = element.offset().left, 42 | elRight = elLeft + element.width(), 43 | elBottom = elTop + element.height(); 44 | 45 | var isIntersect = !(elLeft > right || 46 | elRight < left || 47 | elTop > bottom || 48 | elBottom < top); 49 | 50 | if (isIntersect) { 51 | hits.push(element); 52 | } 53 | } 54 | }); 55 | 56 | return hits; 57 | } 58 | 59 | 60 | /** 61 | * Called when the user scrolls the window 62 | */ 63 | function onScroll() { 64 | // unique tick id 65 | ++ticks; 66 | 67 | // viewport rectangle 68 | var top = jWindow.scrollTop(), 69 | left = jWindow.scrollLeft(), 70 | right = left + jWindow.width(), 71 | bottom = top + jWindow.height(); 72 | 73 | // determine which elements are in view 74 | // + 60 accounts for fixed nav 75 | var intersections = findElements(top+offset.top + 200, right+offset.right, bottom+offset.bottom, left+offset.left); 76 | $.each(intersections, function(i, element) { 77 | 78 | var lastTick = element.data('scrollSpy:ticks'); 79 | if (typeof lastTick != 'number') { 80 | // entered into view 81 | element.triggerHandler('scrollSpy:enter'); 82 | } 83 | 84 | // update tick id 85 | element.data('scrollSpy:ticks', ticks); 86 | }); 87 | 88 | // determine which elements are no longer in view 89 | $.each(elementsInView, function(i, element) { 90 | var lastTick = element.data('scrollSpy:ticks'); 91 | if (typeof lastTick == 'number' && lastTick !== ticks) { 92 | // exited from view 93 | element.triggerHandler('scrollSpy:exit'); 94 | element.data('scrollSpy:ticks', null); 95 | } 96 | }); 97 | 98 | // remember elements in view for next tick 99 | elementsInView = intersections; 100 | } 101 | 102 | /** 103 | * Called when window is resized 104 | */ 105 | function onWinSize() { 106 | jWindow.trigger('scrollSpy:winSize'); 107 | } 108 | 109 | /** 110 | * Get time in ms 111 | * @license https://raw.github.com/jashkenas/underscore/master/LICENSE 112 | * @type {function} 113 | * @return {number} 114 | */ 115 | var getTime = (Date.now || function () { 116 | return new Date().getTime(); 117 | }); 118 | 119 | /** 120 | * Returns a function, that, when invoked, will only be triggered at most once 121 | * during a given window of time. Normally, the throttled function will run 122 | * as much as it can, without ever going more than once per `wait` duration; 123 | * but if you'd like to disable the execution on the leading edge, pass 124 | * `{leading: false}`. To disable execution on the trailing edge, ditto. 125 | * @license https://raw.github.com/jashkenas/underscore/master/LICENSE 126 | * @param {function} func 127 | * @param {number} wait 128 | * @param {Object=} options 129 | * @returns {Function} 130 | */ 131 | function throttle(func, wait, options) { 132 | var context, args, result; 133 | var timeout = null; 134 | var previous = 0; 135 | options || (options = {}); 136 | var later = function () { 137 | previous = options.leading === false ? 0 : getTime(); 138 | timeout = null; 139 | result = func.apply(context, args); 140 | context = args = null; 141 | }; 142 | return function () { 143 | var now = getTime(); 144 | if (!previous && options.leading === false) previous = now; 145 | var remaining = wait - (now - previous); 146 | context = this; 147 | args = arguments; 148 | if (remaining <= 0) { 149 | clearTimeout(timeout); 150 | timeout = null; 151 | previous = now; 152 | result = func.apply(context, args); 153 | context = args = null; 154 | } else if (!timeout && options.trailing !== false) { 155 | timeout = setTimeout(later, remaining); 156 | } 157 | return result; 158 | }; 159 | }; 160 | 161 | /** 162 | * Enables ScrollSpy using a selector 163 | * @param {jQuery|string} selector The elements collection, or a selector 164 | * @param {Object=} options Optional. 165 | throttle : number -> scrollspy throttling. Default: 100 ms 166 | offsetTop : number -> offset from top. Default: 0 167 | offsetRight : number -> offset from right. Default: 0 168 | offsetBottom : number -> offset from bottom. Default: 0 169 | offsetLeft : number -> offset from left. Default: 0 170 | * @returns {jQuery} 171 | */ 172 | $.scrollSpy = function(selector, options) { 173 | var visible = []; 174 | selector = $(selector); 175 | selector.each(function(i, element) { 176 | elements.push($(element)); 177 | $(element).data("scrollSpy:id", i); 178 | // Smooth scroll to section 179 | $('a[href=#' + $(element).attr('id') + ']').click(function(e) { 180 | e.preventDefault(); 181 | var offset = $(this.hash).offset().top + 1; 182 | 183 | // offset - 200 allows elements near bottom of page to scroll 184 | 185 | $('html, body').animate({ scrollTop: offset - 200 }, {duration: 400, queue: false, easing: 'easeOutCubic'}); 186 | 187 | }); 188 | }); 189 | options = options || { 190 | throttle: 100 191 | }; 192 | 193 | offset.top = options.offsetTop || 0; 194 | offset.right = options.offsetRight || 0; 195 | offset.bottom = options.offsetBottom || 0; 196 | offset.left = options.offsetLeft || 0; 197 | 198 | var throttledScroll = throttle(onScroll, options.throttle || 100); 199 | var readyScroll = function(){ 200 | $(document).ready(throttledScroll); 201 | }; 202 | 203 | if (!isSpying) { 204 | jWindow.on('scroll', readyScroll); 205 | jWindow.on('resize', readyScroll); 206 | isSpying = true; 207 | } 208 | 209 | // perform a scan once, after current execution context, and after dom is ready 210 | setTimeout(readyScroll, 0); 211 | 212 | 213 | selector.on('scrollSpy:enter', function() { 214 | visible = $.grep(visible, function(value) { 215 | return value.height() != 0; 216 | }); 217 | 218 | var $this = $(this); 219 | 220 | if (visible[0]) { 221 | $('a[href=#' + visible[0].attr('id') + ']').removeClass('active'); 222 | if ($this.data('scrollSpy:id') < visible[0].data('scrollSpy:id')) { 223 | visible.unshift($(this)); 224 | } 225 | else { 226 | visible.push($(this)); 227 | } 228 | } 229 | else { 230 | visible.push($(this)); 231 | } 232 | 233 | 234 | $('a[href=#' + visible[0].attr('id') + ']').addClass('active'); 235 | }); 236 | selector.on('scrollSpy:exit', function() { 237 | visible = $.grep(visible, function(value) { 238 | return value.height() != 0; 239 | }); 240 | 241 | if (visible[0]) { 242 | $('a[href=#' + visible[0].attr('id') + ']').removeClass('active'); 243 | var $this = $(this); 244 | visible = $.grep(visible, function(value) { 245 | return value.attr('id') != $this.attr('id'); 246 | }); 247 | if (visible[0]) { // Check if empty 248 | $('a[href=#' + visible[0].attr('id') + ']').addClass('active'); 249 | } 250 | } 251 | }); 252 | 253 | return selector; 254 | }; 255 | 256 | /** 257 | * Listen for window resize events 258 | * @param {Object=} options Optional. Set { throttle: number } to change throttling. Default: 100 ms 259 | * @returns {jQuery} $(window) 260 | */ 261 | $.winSizeSpy = function(options) { 262 | $.winSizeSpy = function() { return jWindow; }; // lock from multiple calls 263 | options = options || { 264 | throttle: 100 265 | }; 266 | return jWindow.on('resize', throttle(onWinSize, options.throttle || 100)); 267 | }; 268 | 269 | /** 270 | * Enables ScrollSpy on a collection of elements 271 | * e.g. $('.scrollSpy').scrollSpy() 272 | * @param {Object=} options Optional. 273 | throttle : number -> scrollspy throttling. Default: 100 ms 274 | offsetTop : number -> offset from top. Default: 0 275 | offsetRight : number -> offset from right. Default: 0 276 | offsetBottom : number -> offset from bottom. Default: 0 277 | offsetLeft : number -> offset from left. Default: 0 278 | * @returns {jQuery} 279 | */ 280 | $.fn.scrollSpy = function(options) { 281 | return $.scrollSpy($(this), options); 282 | }; 283 | 284 | })(jQuery); -------------------------------------------------------------------------------- /static/materialize/js/slider.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | 3 | $.fn.slider = function (options) { 4 | var defaults = { 5 | indicators: true, 6 | height: 400, 7 | transition: 500, 8 | interval: 6000 9 | } 10 | options = $.extend(defaults, options); 11 | 12 | return this.each(function() { 13 | 14 | // For each slider, we want to keep track of 15 | // which slide is active and its associated content 16 | var $this = $(this); 17 | var $slider = $this.find('ul.slides').first(); 18 | var $slides = $slider.find('li'); 19 | var $active_index = $slider.find('.active').index(); 20 | var $active; 21 | if ($active_index != -1) { $active = $slides.eq($active_index); } 22 | 23 | // Transitions the caption depending on alignment 24 | function captionTransition(caption, duration) { 25 | if (caption.hasClass("center-align")) { 26 | caption.velocity({opacity: 0, translateY: -100}, {duration: duration, queue: false}); 27 | } 28 | else if (caption.hasClass("right-align")) { 29 | caption.velocity({opacity: 0, translateX: 100}, {duration: duration, queue: false}); 30 | } 31 | else if (caption.hasClass("left-align")) { 32 | caption.velocity({opacity: 0, translateX: -100}, {duration: duration, queue: false}); 33 | } 34 | } 35 | 36 | // This function will transition the slide to any index of the next slide 37 | function moveToSlide(index) { 38 | if (index >= $slides.length) index = 0; 39 | else if (index < 0) index = $slides.length -1; 40 | 41 | $active_index = $slider.find('.active').index(); 42 | 43 | // Only do if index changes 44 | if ($active_index != index) { 45 | $active = $slides.eq($active_index); 46 | $caption = $active.find('.caption'); 47 | 48 | $active.removeClass('active'); 49 | $active.velocity({opacity: 0}, {duration: options.transition, queue: false, easing: 'easeOutQuad', 50 | complete: function() { 51 | $slides.not('.active').velocity({opacity: 0, translateX: 0, translateY: 0}, {duration: 0, queue: false}); 52 | } }); 53 | captionTransition($caption, options.transition); 54 | 55 | 56 | // Update indicators 57 | if (options.indicators) { 58 | $indicators.eq($active_index).removeClass('active'); 59 | } 60 | 61 | $slides.eq(index).velocity({opacity: 1}, {duration: options.transition, queue: false, easing: 'easeOutQuad'}); 62 | $slides.eq(index).find('.caption').velocity({opacity: 1, translateX: 0, translateY: 0}, {duration: options.transition, delay: options.transition, queue: false, easing: 'easeOutQuad'}); 63 | $slides.eq(index).addClass('active'); 64 | 65 | 66 | // Update indicators 67 | if (options.indicators) { 68 | $indicators.eq(index).addClass('active'); 69 | } 70 | } 71 | } 72 | 73 | // Set height of slider 74 | if (options.height != 400) { 75 | $this.height(options.height + 40); 76 | $slider.height(options.height); 77 | } 78 | 79 | // Set initial positions of captions 80 | $slides.find('.caption').each(function () { 81 | captionTransition($(this), 0); 82 | }); 83 | 84 | // Set initial dimensions of images 85 | // $slides.find('img').each(function () { 86 | // $(this).load(function () { 87 | // if ($(this).width() < $(this).parent().width()) { 88 | // $(this).css({width: '100%', height: 'auto'}); 89 | // } 90 | // }); 91 | // }); 92 | 93 | // Move img src into background-image 94 | $slides.find('img').each(function () { 95 | $(this).css('background-image', 'url(' + $(this).attr('src') + ')' ); 96 | $(this).attr('src', 'data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='); 97 | }); 98 | 99 | // dynamically add indicators 100 | if (options.indicators) { 101 | var $indicators = $('
    '); 102 | $slides.each(function( index ) { 103 | var $indicator = $('
  • '); 104 | 105 | // Handle clicks on indicators 106 | $indicator.click(function () { 107 | var $parent = $slider.parent(); 108 | var curr_index = $parent.find($(this)).index(); 109 | moveToSlide(curr_index); 110 | 111 | // reset interval 112 | clearInterval($interval); 113 | $interval = setInterval( 114 | function(){ 115 | $active_index = $slider.find('.active').index(); 116 | if ($slides.length == $active_index + 1) $active_index = 0; // loop to start 117 | else $active_index += 1; 118 | 119 | moveToSlide($active_index); 120 | 121 | }, options.transition + options.interval 122 | ); 123 | }); 124 | $indicators.append($indicator); 125 | }); 126 | $this.append($indicators); 127 | $indicators = $this.find('ul.indicators').find('li.indicator-item'); 128 | } 129 | 130 | if ($active) { 131 | $active.show(); 132 | } 133 | else { 134 | $slides.first().addClass('active').velocity({opacity: 1}, {duration: options.transition, queue: false, easing: 'easeOutQuad'}); 135 | 136 | $active_index = 0; 137 | $active = $slides.eq($active_index); 138 | 139 | // Update indicators 140 | if (options.indicators) { 141 | $indicators.eq($active_index).addClass('active'); 142 | } 143 | } 144 | 145 | // Adjust height to current slide 146 | $active.find('img').each(function() { 147 | $active.find('.caption').velocity({opacity: 1, translateX: 0, translateY: 0}, {duration: options.transition, queue: false, easing: 'easeOutQuad'}); 148 | }); 149 | 150 | // auto scroll 151 | $interval = setInterval( 152 | function(){ 153 | $active_index = $slider.find('.active').index(); 154 | moveToSlide($active_index + 1); 155 | 156 | }, options.transition + options.interval 157 | ); 158 | 159 | 160 | // HammerJS, Swipe navigation 161 | 162 | // Touch Event 163 | var panning = false; 164 | var swipeLeft = false; 165 | var swipeRight = false; 166 | 167 | $this.hammer({ 168 | prevent_default: false 169 | }).bind('pan', function(e) { 170 | if (e.gesture.pointerType === "touch") { 171 | 172 | // reset interval 173 | clearInterval($interval); 174 | 175 | var direction = e.gesture.direction; 176 | var x = e.gesture.deltaX; 177 | var velocityX = e.gesture.velocityX; 178 | 179 | $curr_slide = $slider.find('.active'); 180 | $curr_slide.velocity({ translateX: x 181 | }, {duration: 50, queue: false, easing: 'easeOutQuad'}); 182 | 183 | // Swipe Left 184 | if (direction === 4 && (x > ($this.innerWidth() / 2) || velocityX < -0.65)) { 185 | swipeRight = true; 186 | } 187 | // Swipe Right 188 | else if (direction === 2 && (x < (-1 * $this.innerWidth() / 2) || velocityX > 0.65)) { 189 | swipeLeft = true; 190 | } 191 | 192 | // Make Slide Behind active slide visible 193 | var next_slide; 194 | if (swipeLeft) { 195 | next_slide = $curr_slide.next(); 196 | if (next_slide.length === 0) { 197 | next_slide = $slides.first(); 198 | } 199 | next_slide.velocity({ opacity: 1 200 | }, {duration: 300, queue: false, easing: 'easeOutQuad'}); 201 | } 202 | if (swipeRight) { 203 | next_slide = $curr_slide.prev(); 204 | if (next_slide.length === 0) { 205 | next_slide = $slides.last(); 206 | } 207 | next_slide.velocity({ opacity: 1 208 | }, {duration: 300, queue: false, easing: 'easeOutQuad'}); 209 | } 210 | 211 | 212 | } 213 | 214 | }).bind('panend', function(e) { 215 | if (e.gesture.pointerType === "touch") { 216 | 217 | $curr_slide = $slider.find('.active'); 218 | panning = false; 219 | curr_index = $slider.find('.active').index(); 220 | 221 | if (!swipeRight && !swipeLeft) { 222 | // Return to original spot 223 | $curr_slide.velocity({ translateX: 0 224 | }, {duration: 300, queue: false, easing: 'easeOutQuad'}); 225 | } 226 | else if (swipeLeft) { 227 | moveToSlide(curr_index + 1); 228 | $curr_slide.velocity({translateX: -1 * $this.innerWidth() }, {duration: 300, queue: false, easing: 'easeOutQuad', 229 | complete: function() { 230 | $curr_slide.velocity({opacity: 0, translateX: 0}, {duration: 0, queue: false}); 231 | } }); 232 | } 233 | else if (swipeRight) { 234 | moveToSlide(curr_index - 1); 235 | $curr_slide.velocity({translateX: $this.innerWidth() }, {duration: 300, queue: false, easing: 'easeOutQuad', 236 | complete: function() { 237 | $curr_slide.velocity({opacity: 0, translateX: 0}, {duration: 0, queue: false}); 238 | } }); 239 | } 240 | swipeLeft = false; 241 | swipeRight = false; 242 | 243 | // Restart interval 244 | clearInterval($interval); 245 | $interval = setInterval( 246 | function(){ 247 | $active_index = $slider.find('.active').index(); 248 | if ($slides.length == $active_index + 1) $active_index = 0; // loop to start 249 | else $active_index += 1; 250 | 251 | moveToSlide($active_index); 252 | 253 | }, options.transition + options.interval 254 | ); 255 | } 256 | }); 257 | 258 | }); 259 | 260 | 261 | 262 | }; 263 | }( jQuery )); 264 | -------------------------------------------------------------------------------- /static/materialize/js/tabs.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | 3 | var methods = { 4 | init : function() { 5 | return this.each(function() { 6 | 7 | // For each set of tabs, we want to keep track of 8 | // which tab is active and its associated content 9 | var $this = $(this), 10 | window_width = $(window).width(); 11 | 12 | $this.width('100%'); 13 | // Set Tab Width for each tab 14 | var $num_tabs = $(this).children('li').length; 15 | $this.children('li').each(function() { 16 | $(this).width((100/$num_tabs)+'%'); 17 | }); 18 | var $active, $content, $links = $this.find('li.tab a'), 19 | $tabs_width = $this.width(), 20 | $tab_width = $this.find('li').first().outerWidth(), 21 | $index = 0; 22 | 23 | // If the location.hash matches one of the links, use that as the active tab. 24 | $active = $($links.filter('[href="'+location.hash+'"]')); 25 | 26 | // If no match is found, use the first link or any with class 'active' as the initial active tab. 27 | if ($active.length === 0) { 28 | $active = $(this).find('li.tab a.active').first(); 29 | } 30 | if ($active.length === 0) { 31 | $active = $(this).find('li.tab a').first(); 32 | } 33 | 34 | $active.addClass('active'); 35 | $index = $links.index($active); 36 | if ($index < 0) { 37 | $index = 0; 38 | } 39 | 40 | $content = $($active[0].hash); 41 | 42 | // append indicator then set indicator width to tab width 43 | $this.append('
    '); 44 | var $indicator = $this.find('.indicator'); 45 | if ($this.is(":visible")) { 46 | $indicator.css({"right": $tabs_width - (($index + 1) * $tab_width)}); 47 | $indicator.css({"left": $index * $tab_width}); 48 | } 49 | $(window).resize(function () { 50 | $tabs_width = $this.width(); 51 | $tab_width = $this.find('li').first().outerWidth(); 52 | if ($index < 0) { 53 | $index = 0; 54 | } 55 | if ($tab_width !== 0 && $tabs_width !== 0) { 56 | $indicator.css({"right": $tabs_width - (($index + 1) * $tab_width)}); 57 | $indicator.css({"left": $index * $tab_width}); 58 | } 59 | }); 60 | 61 | // Hide the remaining content 62 | $links.not($active).each(function () { 63 | $(this.hash).hide(); 64 | }); 65 | 66 | 67 | // Bind the click event handler 68 | $this.on('click', 'a', function(e){ 69 | $tabs_width = $this.width(); 70 | $tab_width = $this.find('li').first().outerWidth(); 71 | 72 | // Make the old tab inactive. 73 | $active.removeClass('active'); 74 | $content.hide(); 75 | 76 | // Update the variables with the new link and content 77 | $active = $(this); 78 | $content = $(this.hash); 79 | $links = $this.find('li.tab a'); 80 | 81 | // Make the tab active. 82 | $active.addClass('active'); 83 | var $prev_index = $index; 84 | $index = $links.index($(this)); 85 | if ($index < 0) { 86 | $index = 0; 87 | } 88 | // Change url to current tab 89 | // window.location.hash = $active.attr('href'); 90 | 91 | $content.show(); 92 | 93 | // Update indicator 94 | if (($index - $prev_index) >= 0) { 95 | $indicator.velocity({"right": $tabs_width - (($index + 1) * $tab_width)}, { duration: 300, queue: false, easing: 'easeOutQuad'}); 96 | $indicator.velocity({"left": $index * $tab_width}, {duration: 300, queue: false, easing: 'easeOutQuad', delay: 90}); 97 | 98 | } 99 | else { 100 | $indicator.velocity({"left": $index * $tab_width}, { duration: 300, queue: false, easing: 'easeOutQuad'}); 101 | $indicator.velocity({"right": $tabs_width - (($index + 1) * $tab_width)}, {duration: 300, queue: false, easing: 'easeOutQuad', delay: 90}); 102 | } 103 | 104 | // Prevent the anchor's default click action 105 | e.preventDefault(); 106 | }); 107 | }); 108 | 109 | }, 110 | select_tab : function( id ) { 111 | this.find('a[href="#' + id + '"]').trigger('click'); 112 | } 113 | }; 114 | 115 | $.fn.tabs = function(methodOrOptions) { 116 | if ( methods[methodOrOptions] ) { 117 | return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); 118 | } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { 119 | // Default to "init" 120 | return methods.init.apply( this, arguments ); 121 | } else { 122 | $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.tooltip' ); 123 | } 124 | }; 125 | 126 | $(document).ready(function(){ 127 | $('ul.tabs').tabs(); 128 | }); 129 | }( jQuery )); 130 | -------------------------------------------------------------------------------- /static/materialize/js/toasts.js: -------------------------------------------------------------------------------- 1 | Materialize.toast = function (message, displayLength, className, completeCallback) { 2 | className = className || ""; 3 | 4 | var container = document.getElementById('toast-container'); 5 | 6 | // Create toast container if it does not exist 7 | if (container === null) { 8 | // create notification container 9 | var container = document.createElement('div'); 10 | container.id = 'toast-container'; 11 | document.body.appendChild(container); 12 | } 13 | 14 | // Select and append toast 15 | var newToast = createToast(message); 16 | container.appendChild(newToast); 17 | 18 | newToast.style.top = '35px'; 19 | newToast.style.opacity = 0; 20 | 21 | // Animate toast in 22 | Vel(newToast, { "top" : "0px", opacity: 1 }, {duration: 300, 23 | easing: 'easeOutCubic', 24 | queue: false}); 25 | 26 | // Allows timer to be pause while being panned 27 | var timeLeft = displayLength; 28 | var counterInterval = setInterval (function(){ 29 | 30 | 31 | if (newToast.parentNode === null) 32 | window.clearInterval(counterInterval); 33 | 34 | // If toast is not being dragged, decrease its time remaining 35 | if (!newToast.classList.contains('panning')) { 36 | timeLeft -= 20; 37 | } 38 | 39 | if (timeLeft <= 0) { 40 | // Animate toast out 41 | Vel(newToast, {"opacity": 0, marginTop: '-40px'}, { duration: 375, 42 | easing: 'easeOutExpo', 43 | queue: false, 44 | complete: function(){ 45 | // Call the optional callback 46 | if(typeof(completeCallback) === "function") 47 | completeCallback(); 48 | // Remove toast after it times out 49 | this[0].parentNode.removeChild(this[0]); 50 | } 51 | }); 52 | window.clearInterval(counterInterval); 53 | } 54 | }, 20); 55 | 56 | 57 | 58 | function createToast(html) { 59 | 60 | // Create toast 61 | var toast = document.createElement('div'); 62 | toast.classList.add('toast'); 63 | if (className) { 64 | var classes = className.split(' '); 65 | 66 | for (var i = 0, count = classes.length; i < count; i++) { 67 | toast.classList.add(classes[i]); 68 | } 69 | } 70 | toast.innerHTML = html; 71 | 72 | // Bind hammer 73 | var hammerHandler = new Hammer(toast, {prevent_default: false}); 74 | hammerHandler.on('pan', function(e) { 75 | var deltaX = e.deltaX; 76 | var activationDistance = 80; 77 | 78 | // Change toast state 79 | if (!toast.classList.contains('panning')){ 80 | toast.classList.add('panning'); 81 | } 82 | 83 | var opacityPercent = 1-Math.abs(deltaX / activationDistance); 84 | if (opacityPercent < 0) 85 | opacityPercent = 0; 86 | 87 | Vel(toast, {left: deltaX, opacity: opacityPercent }, {duration: 50, queue: false, easing: 'easeOutQuad'}); 88 | 89 | }); 90 | 91 | hammerHandler.on('panend', function(e) { 92 | var deltaX = e.deltaX; 93 | var activationDistance = 80; 94 | 95 | // If toast dragged past activation point 96 | if (Math.abs(deltaX) > activationDistance) { 97 | Vel(toast, {marginTop: '-40px'}, { duration: 375, 98 | easing: 'easeOutExpo', 99 | queue: false, 100 | complete: function(){ 101 | if(typeof(completeCallback) === "function") { 102 | completeCallback(); 103 | } 104 | toast.parentNode.removeChild(toast); 105 | } 106 | }); 107 | 108 | } else { 109 | toast.classList.remove('panning'); 110 | // Put toast back into original position 111 | Vel(toast, { left: 0, opacity: 1 }, { duration: 300, 112 | easing: 'easeOutExpo', 113 | queue: false 114 | }); 115 | 116 | } 117 | }); 118 | 119 | return toast; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /static/materialize/js/tooltip.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | $.fn.tooltip = function (options) { 3 | var timeout = null, 4 | counter = null, 5 | started = false, 6 | counterInterval = null, 7 | margin = 5; 8 | 9 | // Defaults 10 | var defaults = { 11 | delay: 350 12 | }; 13 | options = $.extend(defaults, options); 14 | 15 | //Remove previously created html 16 | $('.material-tooltip').remove(); 17 | 18 | return this.each(function(){ 19 | var origin = $(this); 20 | 21 | // Create Text span 22 | var tooltip_text = $('').text(origin.attr('data-tooltip')); 23 | 24 | // Create tooltip 25 | var newTooltip = $('
    '); 26 | newTooltip.addClass('material-tooltip').append(tooltip_text); 27 | newTooltip.appendTo($('body')); 28 | 29 | var backdrop = $('
    ').addClass('backdrop'); 30 | backdrop.appendTo(newTooltip); 31 | backdrop.css({ top: 0, left:0 }); 32 | 33 | 34 | //Destroy previously binded events 35 | $(this).off('mouseenter mouseleave'); 36 | // Mouse In 37 | $(this).on({ 38 | mouseenter: function(e) { 39 | var tooltip_delay = origin.data("delay"); 40 | tooltip_delay = (tooltip_delay == undefined || tooltip_delay == "") ? options.delay : tooltip_delay; 41 | counter = 0; 42 | counterInterval = setInterval(function(){ 43 | counter += 10; 44 | if (counter >= tooltip_delay && started == false) { 45 | started = true 46 | newTooltip.css({ display: 'block', left: '0px', top: '0px' }); 47 | 48 | // Set Tooltip text 49 | newTooltip.children('span').text(origin.attr('data-tooltip')); 50 | 51 | // Tooltip positioning 52 | var originWidth = origin.outerWidth(); 53 | var originHeight = origin.outerHeight(); 54 | var tooltipPosition = origin.attr('data-position'); 55 | var tooltipHeight = newTooltip.outerHeight(); 56 | var tooltipWidth = newTooltip.outerWidth(); 57 | var tooltipVerticalMovement = '0px'; 58 | var tooltipHorizontalMovement = '0px'; 59 | var scale_factor = 8; 60 | 61 | if (tooltipPosition === "top") { 62 | // Top Position 63 | newTooltip.css({ 64 | top: origin.offset().top - tooltipHeight - margin, 65 | left: origin.offset().left + originWidth/2 - tooltipWidth/2 66 | }); 67 | tooltipVerticalMovement = '-10px'; 68 | backdrop.css({ 69 | borderRadius: '14px 14px 0 0', 70 | transformOrigin: '50% 90%', 71 | marginTop: tooltipHeight, 72 | marginLeft: (tooltipWidth/2) - (backdrop.width()/2) 73 | 74 | }); 75 | } 76 | // Left Position 77 | else if (tooltipPosition === "left") { 78 | newTooltip.css({ 79 | top: origin.offset().top + originHeight/2 - tooltipHeight/2, 80 | left: origin.offset().left - tooltipWidth - margin 81 | }); 82 | tooltipHorizontalMovement = '-10px'; 83 | backdrop.css({ 84 | width: '14px', 85 | height: '14px', 86 | borderRadius: '14px 0 0 14px', 87 | transformOrigin: '95% 50%', 88 | marginTop: tooltipHeight/2, 89 | marginLeft: tooltipWidth 90 | }); 91 | } 92 | // Right Position 93 | else if (tooltipPosition === "right") { 94 | newTooltip.css({ 95 | top: origin.offset().top + originHeight/2 - tooltipHeight/2, 96 | left: origin.offset().left + originWidth + margin 97 | }); 98 | tooltipHorizontalMovement = '+10px'; 99 | backdrop.css({ 100 | width: '14px', 101 | height: '14px', 102 | borderRadius: '0 14px 14px 0', 103 | transformOrigin: '5% 50%', 104 | marginTop: tooltipHeight/2, 105 | marginLeft: '0px' 106 | }); 107 | } 108 | else { 109 | // Bottom Position 110 | newTooltip.css({ 111 | top: origin.offset().top + origin.outerHeight() + margin, 112 | left: origin.offset().left + originWidth/2 - tooltipWidth/2 113 | }); 114 | tooltipVerticalMovement = '+10px'; 115 | backdrop.css({ 116 | marginLeft: (tooltipWidth/2) - (backdrop.width()/2) 117 | }); 118 | } 119 | 120 | // Calculate Scale to fill 121 | scale_factor = tooltipWidth / 8; 122 | if (scale_factor < 8) { 123 | scale_factor = 8; 124 | } 125 | if (tooltipPosition === "right" || tooltipPosition === "left") { 126 | scale_factor = tooltipWidth / 10; 127 | if (scale_factor < 6) 128 | scale_factor = 6; 129 | } 130 | 131 | newTooltip.velocity({ opacity: 1, marginTop: tooltipVerticalMovement, marginLeft: tooltipHorizontalMovement}, { duration: 350, queue: false }); 132 | backdrop.css({ display: 'block' }) 133 | .velocity({opacity:1},{duration: 55, delay: 0, queue: false}) 134 | .velocity({scale: scale_factor}, {duration: 300, delay: 0, queue: false, easing: 'easeInOutQuad'}); 135 | 136 | } 137 | }, 10); // End Interval 138 | 139 | // Mouse Out 140 | }, 141 | mouseleave: function(){ 142 | // Reset State 143 | clearInterval(counterInterval); 144 | counter = 0; 145 | 146 | // Animate back 147 | newTooltip.velocity({ 148 | opacity: 0, marginTop: 0, marginLeft: 0}, { duration: 225, queue: false, delay: 275 } 149 | ); 150 | backdrop.velocity({opacity: 0, scale: 1}, { 151 | duration:225, 152 | delay: 275, queue: false, 153 | complete: function(){ 154 | backdrop.css('display', 'none'); 155 | newTooltip.css('display', 'none'); 156 | started = false;} 157 | }); 158 | } 159 | }); 160 | }); 161 | }; 162 | 163 | $(document).ready(function(){ 164 | $('.tooltipped').tooltip(); 165 | }); 166 | }( jQuery )); 167 | -------------------------------------------------------------------------------- /static/materialize/js/transitions.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | // Image transition function 3 | Materialize.fadeInImage = function(selector){ 4 | var element = $(selector); 5 | element.css({opacity: 0}); 6 | $(element).velocity({opacity: 1}, { 7 | duration: 650, 8 | queue: false, 9 | easing: 'easeOutSine' 10 | }); 11 | $(element).velocity({opacity: 1}, { 12 | duration: 1300, 13 | queue: false, 14 | easing: 'swing', 15 | step: function(now, fx) { 16 | fx.start = 100; 17 | var grayscale_setting = now/100; 18 | var brightness_setting = 150 - (100 - now)/1.75; 19 | 20 | if (brightness_setting < 100) { 21 | brightness_setting = 100; 22 | } 23 | if (now >= 0) { 24 | $(this).css({ 25 | "-webkit-filter": "grayscale("+grayscale_setting+")" + "brightness("+brightness_setting+"%)", 26 | "filter": "grayscale("+grayscale_setting+")" + "brightness("+brightness_setting+"%)" 27 | }); 28 | } 29 | } 30 | }); 31 | }; 32 | 33 | // Horizontal staggered list 34 | Materialize.showStaggeredList = function(selector) { 35 | var time = 0; 36 | $(selector).find('li').velocity( 37 | { translateX: "-100px"}, 38 | { duration: 0 }); 39 | 40 | $(selector).find('li').each(function() { 41 | $(this).velocity( 42 | { opacity: "1", translateX: "0"}, 43 | { duration: 800, delay: time, easing: [60, 10] }); 44 | time += 120; 45 | }); 46 | }; 47 | 48 | 49 | $(document).ready(function() { 50 | // Hardcoded .staggered-list scrollFire 51 | // var staggeredListOptions = []; 52 | // $('ul.staggered-list').each(function (i) { 53 | 54 | // var label = 'scrollFire-' + i; 55 | // $(this).addClass(label); 56 | // staggeredListOptions.push( 57 | // {selector: 'ul.staggered-list.' + label, 58 | // offset: 200, 59 | // callback: 'showStaggeredList("ul.staggered-list.' + label + '")'}); 60 | // }); 61 | // scrollFire(staggeredListOptions); 62 | 63 | // HammerJS, Swipe navigation 64 | 65 | // Touch Event 66 | var swipeLeft = false; 67 | var swipeRight = false; 68 | 69 | $('.dismissable').each(function() { 70 | $(this).hammer({ 71 | prevent_default: false 72 | }).bind('pan', function(e) { 73 | if (e.gesture.pointerType === "touch") { 74 | var $this = $(this); 75 | var direction = e.gesture.direction; 76 | var x = e.gesture.deltaX; 77 | var velocityX = e.gesture.velocityX; 78 | 79 | $this.velocity({ translateX: x 80 | }, {duration: 50, queue: false, easing: 'easeOutQuad'}); 81 | 82 | // Swipe Left 83 | if (direction === 4 && (x > ($this.innerWidth() / 2) || velocityX < -0.75)) { 84 | swipeLeft = true; 85 | } 86 | // Swipe Right 87 | else if (direction === 2 && (x < (-1 * $this.innerWidth() / 2) || velocityX > 0.75)) { 88 | swipeRight = true; 89 | } 90 | } 91 | }).bind('panend', function(e) { 92 | if (e.gesture.pointerType === "touch") { 93 | var $this = $(this); 94 | if (swipeLeft || swipeRight) { 95 | var fullWidth; 96 | if (swipeLeft) { fullWidth = $this.innerWidth() } 97 | else { fullWidth = -1 * $this.innerWidth() } 98 | 99 | $this.velocity({ translateX: fullWidth, 100 | }, {duration: 100, queue: false, easing: 'easeOutQuad', complete: 101 | function() { 102 | $this.css('border', 'none'); 103 | $this.velocity({ height: 0, padding: 0, 104 | }, {duration: 200, queue: false, easing: 'easeOutQuad', complete: 105 | function() { $this.remove(); } 106 | }); 107 | } 108 | }); 109 | } 110 | else { 111 | $this.velocity({ translateX: 0, 112 | }, {duration: 100, queue: false, easing: 'easeOutQuad'}); 113 | } 114 | swipeLeft = false; 115 | swipeRight = false; 116 | } 117 | }); 118 | 119 | }); 120 | 121 | 122 | // time = 0 123 | // // Vertical Staggered list 124 | // $('ul.staggered-list.vertical li').velocity( 125 | // { translateY: "100px"}, 126 | // { duration: 0 }); 127 | 128 | // $('ul.staggered-list.vertical li').each(function() { 129 | // $(this).velocity( 130 | // { opacity: "1", translateY: "0"}, 131 | // { duration: 800, delay: time, easing: [60, 25] }); 132 | // time += 120; 133 | // }); 134 | 135 | // // Fade in and Scale 136 | // $('.fade-in.scale').velocity( 137 | // { scaleX: .4, scaleY: .4, translateX: -600}, 138 | // { duration: 0}); 139 | // $('.fade-in').each(function() { 140 | // $(this).velocity( 141 | // { opacity: "1", scaleX: 1, scaleY: 1, translateX: 0}, 142 | // { duration: 800, easing: [60, 10] }); 143 | // }); 144 | }); 145 | }( jQuery )); 146 | -------------------------------------------------------------------------------- /static/materialize/package.js: -------------------------------------------------------------------------------- 1 | // package metadata file for Meteor.js 2 | 3 | Package.describe({ 4 | name: 'materialize:materialize', // http://atmospherejs.com/materialize/materialize 5 | summary: 'Materialize (official): A modern responsive front-end framework based on Material Design', 6 | version: '0.96.1', 7 | git: 'https://github.com/Dogfalo/materialize.git' 8 | }); 9 | 10 | Package.onUse(function (api) { 11 | api.versionsFrom('METEOR@1.0'); 12 | 13 | api.use('jquery', 'client'); 14 | 15 | api.export('Materialize', 'client'); 16 | 17 | api.addFiles([ 18 | 'font/material-design-icons/Material-Design-Icons.eot', 19 | 'font/material-design-icons/Material-Design-Icons.svg', 20 | 'font/material-design-icons/Material-Design-Icons.ttf', 21 | 'font/material-design-icons/Material-Design-Icons.woff', 22 | 'font/material-design-icons/Material-Design-Icons.woff2', 23 | 'font/roboto/Roboto-Bold.ttf', 24 | 'font/roboto/Roboto-Bold.woff', 25 | 'font/roboto/Roboto-Bold.woff2', 26 | 'font/roboto/Roboto-Light.ttf', 27 | 'font/roboto/Roboto-Light.woff', 28 | 'font/roboto/Roboto-Light.woff2', 29 | 'font/roboto/Roboto-Medium.ttf', 30 | 'font/roboto/Roboto-Medium.woff', 31 | 'font/roboto/Roboto-Medium.woff2', 32 | 'font/roboto/Roboto-Regular.ttf', 33 | 'font/roboto/Roboto-Regular.woff', 34 | 'font/roboto/Roboto-Regular.woff2', 35 | 'font/roboto/Roboto-Thin.ttf', 36 | 'font/roboto/Roboto-Thin.woff', 37 | 'font/roboto/Roboto-Thin.woff2', 38 | 'bin/materialize.css', 39 | 'bin/materialize.js', 40 | ], 'client'); 41 | }); 42 | -------------------------------------------------------------------------------- /static/materialize/sass/components/_buttons.scss: -------------------------------------------------------------------------------- 1 | // shared styles 2 | .btn, .btn-flat { 3 | border: none; 4 | border-radius: 2px; 5 | display: inline-block; 6 | height: $button-height; 7 | line-height: $button-line-height; 8 | // margin-bottom: 15px; 9 | outline: 0; 10 | padding: 0 2rem; 11 | text-transform: uppercase; 12 | vertical-align: middle; 13 | // Gets rid of tap active state 14 | -webkit-tap-highlight-color: transparent; 15 | } 16 | // Disabled shared style 17 | .btn.disabled, .btn-floating.disabled, .btn-large.disabled, .btn:disabled, .btn-large:disabled, .btn-floating:disabled { 18 | background-color: $button-bg-color-disabled; 19 | box-shadow: none; 20 | color: $button-color-disabled; 21 | cursor: default; 22 | * { 23 | pointer-events: none; 24 | } 25 | 26 | &:hover { 27 | background-color: $button-bg-color-disabled; 28 | color: $button-color-disabled; 29 | } 30 | } 31 | // Shared icon styles 32 | .btn, .btn-floating, .btn-large, .btn-flat { 33 | i { 34 | font-size: $button-font-size-shared; 35 | line-height: inherit; 36 | } 37 | } 38 | 39 | // Raised Button 40 | .btn { 41 | text-decoration:none; 42 | color: $button-color-raised; 43 | background-color: $button-color; 44 | text-align: center; 45 | letter-spacing: .5px; 46 | @extend .z-depth-1; 47 | @include transition(.2s ease-out); 48 | cursor: pointer; 49 | 50 | &:hover { 51 | background-color: lighten($button-color, 5%); 52 | @extend .z-depth-1-half; 53 | } 54 | } 55 | 56 | // Floating button 57 | .btn-floating { 58 | display: inline-block; 59 | color: $button-color-raised; 60 | position: relative; 61 | overflow: hidden; 62 | z-index: 1; 63 | width: $button-floating-size; 64 | height: $button-floating-size; 65 | line-height: $button-floating-size; 66 | padding: 0; 67 | background-color: $button-color; 68 | border-radius: 50%; 69 | @extend .z-depth-1; 70 | transition: .3s; 71 | cursor: pointer; 72 | vertical-align: middle; 73 | 74 | i { 75 | width: inherit; 76 | display: inline-block; 77 | text-align: center; 78 | color: $button-color-raised; 79 | font-size: 1.6rem; 80 | line-height: $button-floating-size; 81 | } 82 | 83 | &:hover { 84 | @extend .z-depth-1-half; 85 | } 86 | &:before { 87 | border-radius: 0; 88 | } 89 | &.btn-large { 90 | width: $button-floating-size * 1.5; 91 | height: $button-floating-size * 1.5; 92 | i{ 93 | line-height: $button-floating-size * 1.5; 94 | } 95 | } 96 | 97 | } 98 | // button fix 99 | button.btn-floating { 100 | border: none; 101 | } 102 | 103 | // Fixed Action Button 104 | .fixed-action-btn { 105 | position: fixed; 106 | right: 23px; 107 | bottom: 23px; 108 | padding-top: 15px; 109 | margin-bottom: 0; 110 | z-index: 998; 111 | 112 | ul { 113 | left: 0; 114 | right: 0; 115 | text-align: center; 116 | position: absolute; 117 | bottom: 64px; 118 | 119 | li { 120 | margin-bottom: 15px; 121 | } 122 | 123 | a.btn-floating { 124 | opacity: 0; 125 | } 126 | } 127 | } 128 | 129 | // Flat button 130 | .btn-flat { 131 | box-shadow: none; 132 | background-color: transparent; 133 | color: $button-color-flat; 134 | cursor: pointer; 135 | 136 | &.disabled { 137 | color: lighten(#999, 10%); 138 | cursor: default; 139 | } 140 | } 141 | 142 | // Large button 143 | .btn-large { 144 | @extend .btn; 145 | height: $button-height * 1.5; 146 | line-height: 56px; 147 | 148 | i { 149 | font-size: 1.6rem; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /static/materialize/sass/components/_cards.scss: -------------------------------------------------------------------------------- 1 | 2 | 3 | .card-panel { 4 | padding: $card-padding; 5 | margin: $element-top-margin 0 $element-bottom-margin 0; 6 | border-radius: 2px; 7 | @extend .z-depth-1; 8 | background-color: $card-bg-color; 9 | } 10 | 11 | .card { 12 | position: relative; 13 | overflow: hidden; 14 | margin: $element-top-margin 0 $element-bottom-margin 0; 15 | background-color: $card-bg-color; 16 | border-radius: 2px; 17 | @extend .z-depth-1; 18 | 19 | 20 | .card-title { 21 | color: #fff; 22 | font-size: 24px; 23 | font-weight: 300; 24 | &.activator { 25 | cursor: pointer; 26 | } 27 | } 28 | 29 | // Card Sizes 30 | &.small, &.medium, &.large { 31 | position: relative; 32 | 33 | .card-image { 34 | overflow: hidden; 35 | } 36 | .card-content { 37 | overflow: hidden; 38 | } 39 | .card-action { 40 | position: absolute; 41 | bottom: 0; 42 | left: 0; 43 | right: 0; 44 | } 45 | } 46 | 47 | &.small { 48 | height: 300px; 49 | 50 | .card-image { 51 | height: 150px; 52 | } 53 | .card-content { 54 | height: 150px; 55 | } 56 | 57 | } 58 | 59 | &.medium { 60 | height: 400px; 61 | 62 | .card-image { 63 | height: 250px; 64 | } 65 | .card-content { 66 | height: 150px; 67 | } 68 | } 69 | 70 | &.large { 71 | height: 500px; 72 | 73 | .card-image { 74 | height: 330px; 75 | } 76 | .card-content { 77 | height: 170px; 78 | } 79 | } 80 | 81 | 82 | .card-image { 83 | position: relative; 84 | 85 | // Image background for content 86 | img { 87 | border-radius: 2px 2px 0 0; 88 | position: relative; 89 | left: 0; 90 | right: 0; 91 | top: 0; 92 | bottom: 0; 93 | width: 100%; 94 | } 95 | 96 | .card-title { 97 | position: absolute; 98 | bottom: 0; 99 | left: 0; 100 | padding: $card-padding; 101 | } 102 | 103 | } 104 | 105 | .card-content { 106 | padding: $card-padding; 107 | border-radius: 0 0 2px 2px; 108 | 109 | 110 | p { 111 | margin: 0; 112 | color: inherit; 113 | } 114 | .card-title { 115 | line-height: 48px; 116 | } 117 | } 118 | 119 | .card-action { 120 | border-top: 1px solid rgba(160,160,160,.2); 121 | padding: $card-padding; 122 | 123 | a { 124 | color: color("orange", "accent-2"); 125 | margin-right: $card-padding; 126 | @include transition(color .3s ease); 127 | text-transform: uppercase; 128 | 129 | &:hover { color: lighten(color("orange", "accent-2"), 20%); } 130 | } 131 | } 132 | 133 | .card-reveal { 134 | padding: $card-padding; 135 | position: absolute; 136 | background-color: #FFF; 137 | width: 100%; 138 | overflow-y: auto; 139 | top: 100%; 140 | height: 100%; 141 | z-index: 1; 142 | display: none; 143 | 144 | .card-title { 145 | cursor: pointer; 146 | display: block; 147 | } 148 | 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /static/materialize/sass/components/_collapsible.scss: -------------------------------------------------------------------------------- 1 | .collapsible { 2 | border-top: 1px solid $collapsible-border-color; 3 | border-right: 1px solid $collapsible-border-color; 4 | border-left: 1px solid $collapsible-border-color; 5 | margin: $element-top-margin 0 $element-bottom-margin 0; 6 | @extend .z-depth-1; 7 | } 8 | 9 | .collapsible-header { 10 | display: block; 11 | cursor: pointer; 12 | height: $collapsible-height; 13 | line-height: $collapsible-height; 14 | padding: 0 1rem; 15 | background-color: $collapsible-header-color; 16 | border-bottom: 1px solid $collapsible-border-color; 17 | 18 | i { 19 | width: 2rem; 20 | font-size: 1.6rem; 21 | line-height: $collapsible-height; 22 | display: block; 23 | float: left; 24 | text-align: center; 25 | margin-right: 1rem; 26 | } 27 | } 28 | 29 | .collapsible-body { 30 | overflow: hidden; 31 | display: none; 32 | border-bottom: 1px solid $collapsible-border-color; 33 | @include box-sizing(border-box); 34 | 35 | p { 36 | margin: 0; 37 | padding: 2rem; 38 | } 39 | } 40 | 41 | // sideNav collapsible styling 42 | .side-nav { 43 | 44 | .collapsible { 45 | border: none; 46 | box-shadow: none; 47 | 48 | li { padding: 0; } 49 | } 50 | 51 | .collapsible-header { 52 | background-color: transparent; 53 | border: none; 54 | line-height: inherit; 55 | height: inherit; 56 | margin: 0 1rem; 57 | 58 | i { line-height: inherit; } 59 | } 60 | 61 | .collapsible-body { 62 | border: 0; 63 | background-color: #FFF; 64 | 65 | li a { margin: 0 1rem 0 2rem; } 66 | } 67 | 68 | } 69 | 70 | // Popout Collapsible 71 | 72 | .collapsible.popout { 73 | border: none; 74 | box-shadow: none; 75 | > li { 76 | &:hover { 77 | will-change: margin, transform; 78 | } 79 | box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12); 80 | transform: scaleX(.92) translate3d(0,0,0); 81 | transition: margin .35s cubic-bezier(0.250, 0.460, 0.450, 0.940), transform .35s cubic-bezier(0.250, 0.460, 0.450, 0.940); 82 | } 83 | > li.active { 84 | box-shadow: 0 5px 11px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15); 85 | margin: 16px 0; 86 | transform: scaleX(1) translate3d(0,0,0); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /static/materialize/sass/components/_dropdown.scss: -------------------------------------------------------------------------------- 1 | .dropdown-content { 2 | @extend .z-depth-1; 3 | background-color: #FFFFFF; 4 | margin: 0; 5 | display: none; 6 | min-width: 100px; 7 | max-height: 650px; 8 | overflow-y: auto; 9 | opacity: 0; 10 | position: absolute; 11 | white-space: nowrap; // Force one line 12 | z-index: 1; 13 | will-change: width, height; 14 | 15 | li { 16 | clear: both; 17 | color: $off-black; 18 | cursor: pointer; 19 | line-height: 1.5rem; 20 | width: 100%; 21 | text-align: left; 22 | text-transform: none; 23 | 24 | &:hover, &.active { 25 | background-color: #eee; 26 | } 27 | 28 | & > a, & > span { 29 | font-size: 1.2rem; 30 | color: $dropdown-color; 31 | display: block; 32 | padding: 1rem 1rem; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /static/materialize/sass/components/_grid.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 0 $gutter-width; 3 | margin: 0 auto; 4 | max-width: 1280px; 5 | width: 90%; 6 | } 7 | @media #{$medium-and-up} { 8 | .container { 9 | width: 85%; 10 | } 11 | } 12 | @media #{$large-and-up} { 13 | .container { 14 | width: 70%; 15 | } 16 | } 17 | .container .row { 18 | margin-left: (-1 * $gutter-width / 2); 19 | margin-right: (-1 * $gutter-width / 2); 20 | } 21 | 22 | .section { 23 | padding-top: 1rem; 24 | padding-bottom: 1rem; 25 | 26 | &.no-pad { 27 | padding: 0; 28 | } 29 | &.no-pad-bot { 30 | padding-bottom: 0; 31 | } 32 | &.no-pad-top { 33 | padding-top: 0; 34 | } 35 | } 36 | 37 | 38 | .row { 39 | margin-left: auto; 40 | margin-right: auto; 41 | margin-bottom: 20px; 42 | 43 | // Clear floating children 44 | &:after { 45 | content: ""; 46 | display: table; 47 | clear: both; 48 | } 49 | 50 | .col { 51 | float: left; 52 | @include box-sizing(border-box); 53 | padding: 0 $gutter-width / 2; 54 | 55 | $i: 1; 56 | @while $i <= $num-cols { 57 | $perc: unquote((100 / ($num-cols / $i)) + "%"); 58 | &.s#{$i} { 59 | width: $perc; 60 | margin-left: 0; 61 | } 62 | $i: $i + 1; 63 | } 64 | $i: 1; 65 | @while $i <= $num-cols { 66 | $perc: unquote((100 / ($num-cols / $i)) + "%"); 67 | &.offset-s#{$i} { 68 | margin-left: $perc; 69 | } 70 | $i: $i + 1; 71 | } 72 | 73 | @media #{$medium-and-up} { 74 | 75 | $i: 1; 76 | @while $i <= $num-cols { 77 | $perc: unquote((100 / ($num-cols / $i)) + "%"); 78 | &.m#{$i} { 79 | width: $perc; 80 | margin-left: 0; 81 | } 82 | $i: $i + 1; 83 | } 84 | $i: 1; 85 | @while $i <= $num-cols { 86 | $perc: unquote((100 / ($num-cols / $i)) + "%"); 87 | &.offset-m#{$i} { 88 | margin-left: $perc; 89 | } 90 | $i: $i + 1; 91 | } 92 | 93 | } 94 | 95 | @media #{$large-and-up} { 96 | 97 | $i: 1; 98 | @while $i <= $num-cols { 99 | $perc: unquote((100 / ($num-cols / $i)) + "%"); 100 | &.l#{$i} { 101 | width: $perc; 102 | margin-left: 0; 103 | } 104 | $i: $i + 1; 105 | } 106 | $i: 1; 107 | @while $i <= $num-cols { 108 | $perc: unquote((100 / ($num-cols / $i)) + "%"); 109 | &.offset-l#{$i} { 110 | margin-left: $perc; 111 | } 112 | $i: $i + 1; 113 | } 114 | 115 | } 116 | 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /static/materialize/sass/components/_materialbox.scss: -------------------------------------------------------------------------------- 1 | .materialboxed { 2 | cursor: zoom-in; 3 | position: relative; 4 | @include transition(opacity .4s); 5 | 6 | &:hover { 7 | &:not(.active) { 8 | opacity: .8; 9 | } 10 | will-change: left, top, width, height; 11 | } 12 | } 13 | 14 | .materialboxed.active { 15 | cursor: zoom-out; 16 | } 17 | 18 | #materialbox-overlay { 19 | position:fixed; 20 | top:0; 21 | left:0; 22 | right: 0; 23 | bottom: 0; 24 | background-color: #292929; 25 | z-index: 999; 26 | 27 | will-change: opacity; 28 | } 29 | .materialbox-caption { 30 | position: fixed; 31 | display: none; 32 | color: #fff; 33 | line-height: 50px; 34 | bottom: 0; 35 | width: 100%; 36 | text-align: center; 37 | padding: 0% 15%; 38 | height: 50px; 39 | z-index: 1000; 40 | -webkit-font-smoothing: antialiased; 41 | } -------------------------------------------------------------------------------- /static/materialize/sass/components/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin box-shadow-2($args1, $args2) { 2 | -webkit-box-shadow: $args1, $args2; 3 | -moz-box-shadow: $args1, $args2; 4 | box-shadow: $args1, $args2; 5 | } -------------------------------------------------------------------------------- /static/materialize/sass/components/_modal.scss: -------------------------------------------------------------------------------- 1 | .modal { 2 | @extend .z-depth-4; 3 | 4 | display: none; 5 | position: fixed; 6 | left: 0; 7 | right: 0; 8 | background-color: #fafafa; 9 | padding: 0; 10 | max-height: 70%; 11 | width: 55%; 12 | margin: auto; 13 | overflow-y: auto; 14 | z-index: 1000; 15 | 16 | border-radius: 2px; 17 | @include transform(translate(0)); 18 | will-change: top, opacity; 19 | 20 | @media #{$medium-and-down} { 21 | width: 80%; 22 | } 23 | 24 | h1,h2,h3,h4 { 25 | margin-top: 0; 26 | } 27 | 28 | .modal-content { 29 | padding: 24px; 30 | } 31 | 32 | .modal-footer { 33 | border-radius: 0 0 2px 2px; 34 | background-color: #fafafa; 35 | padding: 4px 6px; 36 | height: 56px; 37 | width: 100%; 38 | 39 | .btn, .btn-flat { 40 | float: right; 41 | margin: 6px 0; 42 | } 43 | } 44 | } 45 | #lean-overlay { 46 | position: fixed; 47 | z-index:999; 48 | top: 0; 49 | left: 0; 50 | bottom: 0; 51 | right: 0; 52 | height: 115%; 53 | width: 100%; 54 | background: #000; 55 | display: none; 56 | 57 | will-change: opacity; 58 | } 59 | 60 | // Modal with fixed action footer 61 | .modal.modal-fixed-footer { 62 | padding: 0; 63 | height: 70%; 64 | 65 | .modal-content { 66 | position: fixed; 67 | max-height: 100%; 68 | padding-bottom: 64px; 69 | width: 100%; 70 | overflow-y: auto; 71 | } 72 | 73 | .modal-footer { 74 | border-top: 1px solid rgba(0,0,0,.1); 75 | position: fixed; 76 | bottom: 0; 77 | } 78 | } 79 | 80 | // Modal Bottom Sheet Style 81 | .modal.bottom-sheet { 82 | top: auto; 83 | bottom: -100%; 84 | margin: 0; 85 | width: 100%; 86 | max-height: 45%; 87 | border-radius: 0; 88 | will-change: bottom, opacity; 89 | } -------------------------------------------------------------------------------- /static/materialize/sass/components/_navbar.scss: -------------------------------------------------------------------------------- 1 | nav { 2 | color: #fff; 3 | @extend .z-depth-1; 4 | background-color: $primary-color; 5 | width: 100%; 6 | height: $navbar-height-mobile; 7 | line-height: $navbar-height-mobile; 8 | 9 | a { color: #fff; } 10 | 11 | .nav-wrapper { 12 | position: relative; 13 | height: 100%; 14 | 15 | i { 16 | display: block; 17 | font-size: 2rem; 18 | } 19 | } 20 | 21 | @media #{$large-and-up} { 22 | a.button-collapse { display: none; } 23 | } 24 | 25 | 26 | // Collapse button 27 | .button-collapse { 28 | float: left; 29 | position: relative; 30 | z-index: 1; 31 | height: $navbar-height-mobile; 32 | 33 | i { 34 | font-size: 2.7rem; 35 | height: $navbar-height-mobile; 36 | line-height: $navbar-height-mobile; 37 | } 38 | } 39 | 40 | 41 | // Logo 42 | .brand-logo { 43 | position: absolute; 44 | color: #fff; 45 | display: inline-block; 46 | font-size: 2.1rem; 47 | padding: 0; 48 | 49 | &.center { 50 | left: 50%; 51 | @include transform(translateX(-50%)); 52 | } 53 | 54 | @media #{$medium-and-down} { 55 | left: 50%; 56 | @include transform(translateX(-50%)); 57 | } 58 | 59 | &.right { 60 | right: 0.5rem; 61 | padding: 0; 62 | } 63 | } 64 | 65 | 66 | // Navbar Links 67 | ul { 68 | margin: 0; 69 | 70 | li { 71 | @include transition(background-color .3s); 72 | float: left; 73 | padding: 0; 74 | 75 | &:hover, &.active { 76 | background-color: rgba(0,0,0,.1); 77 | } 78 | } 79 | a { 80 | font-size: 1rem; 81 | color: #fff; 82 | display: block; 83 | padding: 0 15px; 84 | } 85 | 86 | &.left { 87 | float: left; 88 | } 89 | } 90 | 91 | // Navbar Search Form 92 | .input-field { 93 | margin: 0; 94 | 95 | input { 96 | height: 100%; 97 | font-size: 1.2rem; 98 | border: none; 99 | padding-left: 2rem; 100 | 101 | &:focus, &[type=text]:valid, &[type=password]:valid, 102 | &[type=email]:valid, &[type=url]:valid, &[type=date]:valid { 103 | border: none; 104 | box-shadow: none; 105 | } 106 | } 107 | label { 108 | top: 0; 109 | left: 0; 110 | 111 | i { 112 | color: rgba(255,255,255,.7); 113 | @include transition(color .3s); 114 | } 115 | &.active i { color: #fff; } 116 | &.active { 117 | @include transform(translateY(0)); 118 | } 119 | } 120 | 121 | } 122 | 123 | } 124 | 125 | // Fixed Navbar 126 | .navbar-fixed { 127 | position: relative; 128 | height: $navbar-height-mobile; 129 | z-index: 998; 130 | 131 | nav { 132 | position: fixed; 133 | } 134 | } 135 | @media #{$medium-and-up} { 136 | nav, nav .nav-wrapper i, nav a.button-collapse, nav a.button-collapse i { 137 | height: $navbar-height; 138 | line-height: $navbar-height; 139 | } 140 | .navbar-fixed { 141 | height: $navbar-height; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /static/materialize/sass/components/_normalize.scss: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS text size adjust after orientation change, without disabling 6 | * user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -ms-text-size-adjust: 100%; /* 2 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | * and Firefox. 30 | * Correct `block` display not defined for `main` in IE 11. 31 | */ 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | /** 50 | * 1. Correct `inline-block` display not defined in IE 8/9. 51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | */ 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; /* 1 */ 59 | vertical-align: baseline; /* 2 */ 60 | } 61 | 62 | /** 63 | * Prevent modern browsers from displaying `audio` without controls. 64 | * Remove excess height in iOS 5 devices. 65 | */ 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | /** 73 | * Address `[hidden]` styling not present in IE 8/9/10. 74 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. 75 | */ 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | /* Links 83 | ========================================================================== */ 84 | 85 | /** 86 | * Remove the gray background color from active links in IE 10. 87 | */ 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | /** 94 | * Improve readability when focused and also mouse hovered in all browsers. 95 | */ 96 | 97 | a:active, 98 | a:hover { 99 | outline: 0; 100 | } 101 | 102 | /* Text-level semantics 103 | ========================================================================== */ 104 | 105 | /** 106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 107 | */ 108 | 109 | abbr[title] { 110 | border-bottom: 1px dotted; 111 | } 112 | 113 | /** 114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 115 | */ 116 | 117 | b, 118 | strong { 119 | font-weight: bold; 120 | } 121 | 122 | /** 123 | * Address styling not present in Safari and Chrome. 124 | */ 125 | 126 | dfn { 127 | font-style: italic; 128 | } 129 | 130 | /** 131 | * Address variable `h1` font-size and margin within `section` and `article` 132 | * contexts in Firefox 4+, Safari, and Chrome. 133 | */ 134 | 135 | h1 { 136 | font-size: 2em; 137 | margin: 0.67em 0; 138 | } 139 | 140 | /** 141 | * Address styling not present in IE 8/9. 142 | */ 143 | 144 | mark { 145 | background: #ff0; 146 | color: #000; 147 | } 148 | 149 | /** 150 | * Address inconsistent and variable font size in all browsers. 151 | */ 152 | 153 | small { 154 | font-size: 80%; 155 | } 156 | 157 | /** 158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 159 | */ 160 | 161 | sub, 162 | sup { 163 | font-size: 75%; 164 | line-height: 0; 165 | position: relative; 166 | vertical-align: baseline; 167 | } 168 | 169 | sup { 170 | top: -0.5em; 171 | } 172 | 173 | sub { 174 | bottom: -0.25em; 175 | } 176 | 177 | /* Embedded content 178 | ========================================================================== */ 179 | 180 | /** 181 | * Remove border when inside `a` element in IE 8/9/10. 182 | */ 183 | 184 | img { 185 | border: 0; 186 | } 187 | 188 | /** 189 | * Correct overflow not hidden in IE 9/10/11. 190 | */ 191 | 192 | svg:not(:root) { 193 | overflow: hidden; 194 | } 195 | 196 | /* Grouping content 197 | ========================================================================== */ 198 | 199 | /** 200 | * Address margin not present in IE 8/9 and Safari. 201 | */ 202 | 203 | figure { 204 | margin: 1em 40px; 205 | } 206 | 207 | /** 208 | * Address differences between Firefox and other browsers. 209 | */ 210 | 211 | hr { 212 | -moz-box-sizing: content-box; 213 | box-sizing: content-box; 214 | height: 0; 215 | } 216 | 217 | /** 218 | * Contain overflow in all browsers. 219 | */ 220 | 221 | pre { 222 | overflow: auto; 223 | } 224 | 225 | /** 226 | * Address odd `em`-unit font size rendering in all browsers. 227 | */ 228 | 229 | code, 230 | kbd, 231 | pre, 232 | samp { 233 | font-family: monospace, monospace; 234 | font-size: 1em; 235 | } 236 | 237 | /* Forms 238 | ========================================================================== */ 239 | 240 | /** 241 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 242 | * styling of `select`, unless a `border` property is set. 243 | */ 244 | 245 | /** 246 | * 1. Correct color not being inherited. 247 | * Known issue: affects color of disabled elements. 248 | * 2. Correct font properties not being inherited. 249 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 | */ 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | color: inherit; /* 1 */ 258 | font: inherit; /* 2 */ 259 | margin: 0; /* 3 */ 260 | } 261 | 262 | /** 263 | * Address `overflow` set to `hidden` in IE 8/9/10/11. 264 | */ 265 | 266 | button { 267 | overflow: visible; 268 | } 269 | 270 | /** 271 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 272 | * All other form control elements do not inherit `text-transform` values. 273 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 | * Correct `select` style inheritance in Firefox. 275 | */ 276 | 277 | button, 278 | select { 279 | text-transform: none; 280 | } 281 | 282 | /** 283 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 | * and `video` controls. 285 | * 2. Correct inability to style clickable `input` types in iOS. 286 | * 3. Improve usability and consistency of cursor style between image-type 287 | * `input` and others. 288 | */ 289 | 290 | /* 1 */ html input[type="button"], 291 | button, 292 | input[type="reset"], 293 | input[type="submit"] { 294 | -webkit-appearance: button; /* 2 */ 295 | cursor: pointer; /* 3 */ 296 | } 297 | 298 | /** 299 | * Re-set default cursor for disabled elements. 300 | */ 301 | 302 | button[disabled], 303 | html input[disabled] { 304 | cursor: default; 305 | } 306 | 307 | /** 308 | * Remove inner padding and border in Firefox 4+. 309 | */ 310 | 311 | button::-moz-focus-inner, 312 | input::-moz-focus-inner { 313 | border: 0; 314 | padding: 0; 315 | } 316 | 317 | /** 318 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 | * the UA stylesheet. 320 | */ 321 | 322 | input { 323 | line-height: normal; 324 | } 325 | 326 | /** 327 | * It's recommended that you don't attempt to style these elements. 328 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 329 | * 330 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 331 | * 2. Remove excess padding in IE 8/9/10. 332 | */ 333 | 334 | input[type="checkbox"], 335 | input[type="radio"] { 336 | box-sizing: border-box; /* 1 */ 337 | padding: 0; /* 2 */ 338 | } 339 | 340 | /** 341 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 | * `font-size` values of the `input`, it causes the cursor style of the 343 | * decrement button to change from `default` to `text`. 344 | */ 345 | 346 | input[type="number"]::-webkit-inner-spin-button, 347 | input[type="number"]::-webkit-outer-spin-button { 348 | height: auto; 349 | } 350 | 351 | /** 352 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome 354 | * (include `-moz` to future-proof). 355 | */ 356 | 357 | input[type="search"] { 358 | -webkit-appearance: textfield; /* 1 */ 359 | -moz-box-sizing: content-box; 360 | -webkit-box-sizing: content-box; /* 2 */ 361 | box-sizing: content-box; 362 | } 363 | 364 | /** 365 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 366 | * Safari (but not Chrome) clips the cancel button when the search input has 367 | * padding (and `textfield` appearance). 368 | */ 369 | 370 | input[type="search"]::-webkit-search-cancel-button, 371 | input[type="search"]::-webkit-search-decoration { 372 | -webkit-appearance: none; 373 | } 374 | 375 | /** 376 | * Define consistent border, margin, and padding. 377 | */ 378 | 379 | fieldset { 380 | border: 1px solid #c0c0c0; 381 | margin: 0 2px; 382 | padding: 0.35em 0.625em 0.75em; 383 | } 384 | 385 | /** 386 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 387 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 388 | */ 389 | 390 | legend { 391 | border: 0; /* 1 */ 392 | padding: 0; /* 2 */ 393 | } 394 | 395 | /** 396 | * Remove default vertical scrollbar in IE 8/9/10/11. 397 | */ 398 | 399 | textarea { 400 | overflow: auto; 401 | } 402 | 403 | /** 404 | * Don't inherit the `font-weight` (applied by a rule above). 405 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 406 | */ 407 | 408 | optgroup { 409 | font-weight: bold; 410 | } 411 | 412 | /* Tables 413 | ========================================================================== */ 414 | 415 | /** 416 | * Remove most spacing between table cells. 417 | */ 418 | 419 | table { 420 | border-collapse: collapse; 421 | border-spacing: 0; 422 | } 423 | 424 | td, 425 | th { 426 | padding: 0; 427 | } 428 | -------------------------------------------------------------------------------- /static/materialize/sass/components/_roboto.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Roboto"; 3 | src: url("#{$roboto-font-path}Roboto-Thin.woff2") format("woff2"), 4 | url("#{$roboto-font-path}Roboto-Thin.woff") format("woff"), 5 | url("#{$roboto-font-path}Roboto-Thin.ttf") format("truetype"); 6 | font-weight: 200; 7 | } 8 | @font-face { 9 | font-family: "Roboto"; 10 | src: url("#{$roboto-font-path}Roboto-Light.woff2") format("woff2"), 11 | url("#{$roboto-font-path}Roboto-Light.woff") format("woff"), 12 | url("#{$roboto-font-path}Roboto-Light.ttf") format("truetype"); 13 | font-weight: 300; 14 | } 15 | 16 | @font-face { 17 | font-family: "Roboto"; 18 | src: url("#{$roboto-font-path}Roboto-Regular.woff2") format("woff2"), 19 | url("#{$roboto-font-path}Roboto-Regular.woff") format("woff"), 20 | url("#{$roboto-font-path}Roboto-Regular.ttf") format("truetype"); 21 | font-weight: 400; 22 | } 23 | 24 | @font-face { 25 | font-family: "Roboto"; 26 | src: url("#{$roboto-font-path}Roboto-Medium.woff2") format("woff2"), 27 | url("#{$roboto-font-path}Roboto-Medium.woff") format("woff"), 28 | url("#{$roboto-font-path}Roboto-Medium.ttf") format("truetype"); 29 | font-weight: 500; 30 | } 31 | 32 | @font-face { 33 | font-family: "Roboto"; 34 | src: url("#{$roboto-font-path}Roboto-Bold.woff2") format("woff2"), 35 | url("#{$roboto-font-path}Roboto-Bold.woff") format("woff"), 36 | url("#{$roboto-font-path}Roboto-Bold.ttf") format("truetype"); 37 | font-weight: 700; 38 | } -------------------------------------------------------------------------------- /static/materialize/sass/components/_sideNav.scss: -------------------------------------------------------------------------------- 1 | .side-nav { 2 | position: fixed; 3 | width: 240px; 4 | left: -105%; 5 | top: 0; 6 | margin: 0; 7 | height: 100%; 8 | height: calc(100% + 60px); 9 | height: -moz-calc(100%); //Temporary Firefox Fix 10 | padding-bottom: 60px; 11 | background-color: #FFF; 12 | z-index: 999; 13 | overflow-y: auto; 14 | 15 | @extend .z-depth-1; 16 | will-change: left; 17 | 18 | // Right Align 19 | &.right-aligned { 20 | will-change: right; 21 | right: -105%; 22 | left: auto; 23 | } 24 | 25 | .collapsible{ 26 | margin: 0; 27 | } 28 | 29 | 30 | li { 31 | float: none; 32 | padding: 0 15px; 33 | &:hover, &.active { background-color: #ddd; } 34 | } 35 | a { 36 | color: #444; 37 | display: block; 38 | font-size: 1rem; 39 | height: 64px; 40 | line-height: 64px; 41 | padding: 0 15px; 42 | } 43 | } 44 | 45 | 46 | // Touch interaction 47 | .drag-target { 48 | height: 100%; 49 | width: 10px; 50 | position: fixed; 51 | top: 0; 52 | z-index: 998; 53 | } 54 | 55 | 56 | // Hidden side-nav for all sizes 57 | .side-nav.fixed { 58 | a { 59 | display: block; 60 | padding: 0 15px; 61 | color: #444; 62 | } 63 | } 64 | 65 | 66 | // Fixed side-nav shown 67 | .side-nav.fixed { 68 | left: 0; 69 | position: fixed; 70 | 71 | // Right Align 72 | &.right-aligned { 73 | right: 0; 74 | left: auto; 75 | } 76 | } 77 | 78 | // Fixed sideNav hide on smaller 79 | @media #{$medium-and-down} { 80 | .side-nav.fixed { 81 | left: -105%; 82 | 83 | &.right-aligned { 84 | right: -105%; 85 | left: auto; 86 | } 87 | } 88 | } 89 | 90 | 91 | .side-nav .collapsible-body li.active, 92 | .side-nav.fixed .collapsible-body li.active { 93 | background-color: $primary-color; 94 | a { 95 | color: #fff; 96 | } 97 | } 98 | 99 | 100 | #sidenav-overlay { 101 | position: fixed; 102 | top: 0; 103 | left: 0; 104 | right: 0; 105 | 106 | height: 120vh; 107 | background-color: rgba(0,0,0,.5); 108 | z-index: 997; 109 | 110 | will-change: opacity; 111 | } 112 | -------------------------------------------------------------------------------- /static/materialize/sass/components/_slider.scss: -------------------------------------------------------------------------------- 1 | .slider { 2 | position: relative; 3 | height: 440px; 4 | width: 100%; 5 | 6 | // Fullscreen slider 7 | &.fullscreen { 8 | height: 100%; 9 | width: 100%; 10 | position: absolute; 11 | top: 0; 12 | left: 0; 13 | right: 0; 14 | bottom: 0; 15 | 16 | ul.slides { 17 | height: 100%; 18 | } 19 | 20 | ul.indicators { 21 | z-index: 2; 22 | bottom: 30px; 23 | } 24 | } 25 | 26 | .slides { 27 | background-color: color('grey', 'base'); 28 | margin: 0; 29 | height: 400px; 30 | 31 | li { 32 | opacity: 0; 33 | position: absolute; 34 | top: 0; 35 | left: 0; 36 | z-index: 1; 37 | width: 100%; 38 | height: inherit; 39 | overflow: hidden; 40 | 41 | img { 42 | height: 100%; 43 | width: 100%; 44 | background-size: cover; 45 | background-position: center; 46 | } 47 | 48 | .caption { 49 | color: #fff; 50 | position: absolute; 51 | top: 15%; 52 | left: 15%; 53 | width: 70%; 54 | opacity: 0; 55 | 56 | p { color: color('grey', 'lighten-2'); } 57 | } 58 | 59 | &.active { 60 | z-index: 2; 61 | } 62 | } 63 | } 64 | 65 | 66 | .indicators { 67 | position: absolute; 68 | text-align: center; 69 | left: 0; 70 | right: 0; 71 | bottom: 0; 72 | margin: 0; 73 | 74 | .indicator-item { 75 | display: inline-block; 76 | position: relative; 77 | cursor: pointer; 78 | height: 16px; 79 | width: 16px; 80 | margin: 0 12px; 81 | background-color: color('grey', 'lighten-2'); 82 | 83 | @include transition(background-color .3s); 84 | border-radius: 50%; 85 | 86 | &.active { 87 | background-color: color('green', 'base'); 88 | } 89 | } 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /static/materialize/sass/components/_table_of_contents.scss: -------------------------------------------------------------------------------- 1 | /*************** 2 | Nav List 3 | ***************/ 4 | .table-of-contents { 5 | &.fixed { 6 | position: fixed; 7 | } 8 | 9 | li { 10 | padding: 2px 0; 11 | } 12 | a { 13 | display: inline-block; 14 | font-weight: 300; 15 | color: #757575; 16 | padding-left: 20px; 17 | height: 1.5rem; 18 | line-height: 1.5rem; 19 | letter-spacing: .4; 20 | display: inline-block; 21 | 22 | &:hover { 23 | color: lighten(#757575, 20%); 24 | padding-left: 19px; 25 | border-left: 1px solid lighten(color("materialize-red", "base"),10%); 26 | } 27 | &.active { 28 | font-weight: 500; 29 | padding-left: 18px; 30 | border-left: 2px solid lighten(color("materialize-red", "base"),10%); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /static/materialize/sass/components/_tabs.scss: -------------------------------------------------------------------------------- 1 | .tabs { 2 | position: relative; 3 | height: 48px; 4 | background-color: $tabs-bg-color; 5 | margin: 0 auto; 6 | width: 100%; 7 | white-space: nowrap; 8 | 9 | .tab { 10 | display: block; 11 | float: left; 12 | text-align: center; 13 | line-height: 48px; 14 | height: 48px; 15 | padding: 0 20px; 16 | margin: 0; 17 | text-transform: uppercase; 18 | letter-spacing: .8px; 19 | width: 15%; 20 | 21 | a { 22 | color: $tabs-text-color; 23 | display: block; 24 | width: 100%; 25 | height: 100%; 26 | @include transition( color .28s ease); 27 | &:hover { 28 | color: lighten($tabs-text-color, 20%); 29 | } 30 | } 31 | } 32 | .indicator { 33 | position: absolute; 34 | bottom: 0; 35 | height: 2px; 36 | background-color: $tabs-underline-color; 37 | will-change: left, right; 38 | } 39 | } 40 | 41 | .tabs .tab { padding: 0; } 42 | 43 | -------------------------------------------------------------------------------- /static/materialize/sass/components/_toast.scss: -------------------------------------------------------------------------------- 1 | #toast-container { 2 | display:block; 3 | position: fixed; 4 | z-index: 1001; 5 | 6 | @media #{$small-and-down} { 7 | min-width: 100%; 8 | bottom: 0%; 9 | } 10 | @media #{$medium-only} { 11 | min-width: 30%; 12 | left: 5%; 13 | bottom: 7%; 14 | } 15 | @media #{$large-and-up} { 16 | min-width: 8%; 17 | top: 10%; 18 | right: 7%; 19 | } 20 | } 21 | 22 | .toast { 23 | @extend .z-depth-1; 24 | border-radius: 2px; 25 | top: 0; 26 | width: auto; 27 | clear: both; 28 | margin-top: 10px; 29 | position: relative; 30 | max-width:100%; 31 | height: $toast-height; 32 | line-height: $toast-height; 33 | background-color: $toast-color; 34 | padding: 0 25px; 35 | font-size: 1.1rem; 36 | font-weight: 300; 37 | color: $toast-text-color; 38 | 39 | @include flexbox(); 40 | @include align(center); 41 | @include justify-content(space-between); 42 | 43 | .btn, .btn-flat { 44 | margin: 0; 45 | margin-left: 3rem; 46 | } 47 | 48 | &.rounded{ 49 | border-radius: 24px; 50 | } 51 | 52 | @media #{$small-and-down} { 53 | width:100%; 54 | border-radius: 0; 55 | } 56 | @media #{$medium-only} { 57 | float: left; 58 | } 59 | @media #{$large-and-up} { 60 | float: right; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /static/materialize/sass/components/_tooltip.scss: -------------------------------------------------------------------------------- 1 | .material-tooltip { 2 | padding: 10px 8px; 3 | font-size: 1rem; 4 | z-index: 1000; 5 | background-color: transparent; 6 | border-radius: 2px; 7 | color: #fff; 8 | min-height: 36px; 9 | line-height: 1rem; 10 | // max-width: 350px; 11 | opacity: 0; 12 | display: none; 13 | position: absolute; 14 | text-align: center; 15 | overflow: hidden; 16 | left:0; 17 | top:0; 18 | 19 | will-change: top, left; 20 | } 21 | 22 | .backdrop { 23 | position: absolute; 24 | opacity: 0; 25 | display: none; 26 | height: 7px; 27 | width: 14px; 28 | border-radius: 0 0 14px 14px; 29 | background-color: #323232; 30 | z-index: -1; 31 | @include transform-origin( 50% 10%); 32 | 33 | will-change: transform, opacity; 34 | } 35 | -------------------------------------------------------------------------------- /static/materialize/sass/components/_typography.scss: -------------------------------------------------------------------------------- 1 | a { 2 | text-decoration: none; 3 | } 4 | 5 | html{ 6 | line-height: 1.5; 7 | 8 | @media only screen and (min-width: 0) { 9 | font-size: 14px; 10 | } 11 | 12 | @media only screen and (min-width: $medium-screen) { 13 | font-size: 14.5px; 14 | } 15 | 16 | @media only screen and (min-width: $large-screen) { 17 | font-size: 15px; 18 | } 19 | 20 | font-family: "Roboto", sans-serif; 21 | font-weight: normal; 22 | color: $off-black; 23 | } 24 | h1, h2, h3, h4, h5, h6 { 25 | font-weight: 400; 26 | } 27 | 28 | // Header Styles 29 | h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { font-weight: inherit; } 30 | h1 { font-size: $h1-fontsize; line-height: 1.1*$h1-fontsize; margin: ($h1-fontsize / 2) 0 ($h1-fontsize / 2.5) 0;} 31 | h2 { font-size: $h2-fontsize; line-height: 1.1*$h2-fontsize; margin: ($h2-fontsize / 2) 0 ($h2-fontsize / 2.5) 0;} 32 | h3 { font-size: $h3-fontsize; line-height: 1.1*$h3-fontsize; margin: ($h3-fontsize / 2) 0 ($h3-fontsize / 2.5) 0;} 33 | h4 { font-size: $h4-fontsize; line-height: 1.1*$h4-fontsize; margin: ($h4-fontsize / 2) 0 ($h4-fontsize / 2.5) 0;} 34 | h5 { font-size: $h5-fontsize; line-height: 1.1*$h5-fontsize; margin: ($h5-fontsize / 2) 0 ($h5-fontsize / 2.5) 0;} 35 | h6 { font-size: $h6-fontsize; line-height: 1.1*$h6-fontsize; margin: ($h6-fontsize / 2) 0 ($h6-fontsize / 2.5) 0;} 36 | 37 | // Text Styles 38 | em { font-style: italic; } 39 | strong { font-weight: 500; } 40 | small { font-size: 75%; } 41 | .light { font-weight: 300; } 42 | .thin { font-weight: 200; } 43 | 44 | .flow-text{ 45 | font-weight: 300; 46 | $i: 0; 47 | @while $i <= $intervals { 48 | @media only screen and (min-width : 360 + ($i * $interval-size)) { 49 | font-size: 1.2rem * (1 + (.02 * $i)); 50 | } 51 | @media only screen and (min-width : 0 + ($i * $interval-size)) { 52 | line-height: .8rem * (1 + (.13 * $i)); 53 | } 54 | $i: $i + 1; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /static/materialize/sass/components/_variables.scss: -------------------------------------------------------------------------------- 1 | /*** Colors ***/ 2 | $primary-color: color("materialize-red", "lighten-2") !default; 3 | $primary-color-light: lighten($primary-color, 15%) !default; 4 | $primary-color-dark: darken($primary-color, 15%) !default; 5 | 6 | $secondary-color: color("teal", "lighten-1") !default; 7 | $success-color: color("green", "base") !default; 8 | $error-color: color("red", "base") !default; 9 | $link-color: color("blue", "base") !default; 10 | 11 | /*** Badges ***/ 12 | $badge-bg-color: $secondary-color !default; 13 | 14 | /*** Buttons ***/ 15 | $button-bg-color-disabled: #DFDFDF !default; 16 | $button-color: $secondary-color !default; 17 | $button-color-disabled: #9F9F9F !default; 18 | $button-color-flat: #343434 !default; 19 | $button-color-raised: #FFF !default; 20 | $button-floating-size: 37px !default; 21 | $button-height: 36px !default; 22 | $button-font-size-shared: 1.3rem !default; 23 | $button-line-height: 36px !default; 24 | 25 | 26 | /*** Cards ***/ 27 | $card-padding: 20px !default; 28 | $card-bg-color: #fff !default; 29 | 30 | /*** Collapsible ***/ 31 | $collapsible-height: 3rem !default; 32 | $collapsible-header-color: #fff !default; 33 | $collapsible-border-color: #ddd !default; 34 | 35 | 36 | /*** Dropdown ***/ 37 | $dropdown-color: $secondary-color !default; 38 | 39 | /*** Fonts ***/ 40 | $roboto-font-path: "../materialize/font/roboto/" !default; 41 | $icons-font-path: "../materialize/font/material-design-icons/" !default; 42 | 43 | /*** Forms ***/ 44 | // Text Inputs + Textarea 45 | $input-border-color: color("grey", "base") !default; 46 | $input-error-color: $error-color !default; 47 | $input-success-color: $success-color !default; 48 | $input-focus-color: $secondary-color !default; 49 | $label-font-size: .8rem !default; 50 | $input-disabled-color: rgba(0,0,0, .26) !default; 51 | $input-disabled-solid-color: #BDBDBD !default; 52 | 53 | 54 | // Radio Buttons 55 | $radio-fill-color: $secondary-color !default; 56 | $radio-empty-color: #5a5a5a !default; 57 | 58 | // Switches 59 | $switch-bg-color: $secondary-color !default; 60 | $switch-checked-lever-bg: desaturate(lighten($secondary-color, 25%), 25%) !default; 61 | $switch-unchecked-bg: #F1F1F1 !default; 62 | $switch-unchecked-lever-bg: #818181 !default; 63 | 64 | // Date Picker 65 | $datepicker-weekday-bg: darken($secondary_color, 7%) !default; 66 | $datepicker-date-bg: $secondary_color !default; 67 | $datepicker-year: rgba(255, 255, 255, .4) !default; 68 | $datepicker-focus: rgba(0,0,0, .05) !default; 69 | $datepicker-selected: $secondary-color !default; 70 | $datepicker-selected-outfocus: desaturate(lighten($secondary-color, 35%), 15%) !default; 71 | 72 | 73 | /*** Global ***/ 74 | // Media Query Ranges 75 | $small-screen-up: 601px !default; 76 | $medium-screen-up: 993px !default; 77 | $large-screen-up: 1201px !default; 78 | $small-screen: 600px !default; 79 | $medium-screen: 992px !default; 80 | $large-screen: 1200px !default; 81 | 82 | $medium-and-up: "only screen and (min-width : #{$small-screen-up})" !default; 83 | $large-and-up: "only screen and (min-width : #{$medium-screen-up})" !default; 84 | $small-and-down: "only screen and (max-width : #{$small-screen})" !default; 85 | $medium-and-down: "only screen and (max-width : #{$medium-screen})" !default; 86 | $medium-only: "only screen and (min-width : #{$small-screen-up}) and (max-width : #{$medium-screen})" !default; 87 | 88 | // Grid Variables 89 | $num-cols: 12 !default; 90 | $gutter-width: 1.5rem !default; 91 | $element-top-margin: $gutter-width/3 !default; 92 | $element-bottom-margin: ($gutter-width*2)/3 !default; 93 | 94 | /*** Navbar ***/ 95 | $navbar-height: 64px !default; 96 | $navbar-height-mobile: 56px !default; 97 | 98 | 99 | /*** SideNav ***/ 100 | 101 | 102 | 103 | /*** Tabs ***/ 104 | $tabs-underline-color: $primary-color-light !default; 105 | $tabs-text-color: $primary-color !default; 106 | $tabs-bg-color: #fff !default; 107 | 108 | /*** Tables ***/ 109 | $table-border-color: #d0d0d0 !default; 110 | $table-striped-color: #f2f2f2 !default; 111 | 112 | /*** Toasts ***/ 113 | $toast-height: 48px !default; 114 | $toast-color: #323232 !default; 115 | $toast-text-color: #fff !default; 116 | 117 | /*** Typography ***/ 118 | $off-black: rgba(0, 0, 0, 0.87) !default; 119 | // Header Styles 120 | $h1-fontsize: 4.2rem !default; 121 | $h2-fontsize: 3.56rem !default; 122 | $h3-fontsize: 2.92rem !default; 123 | $h4-fontsize: 2.28rem !default; 124 | $h5-fontsize: 1.64rem !default; 125 | $h6-fontsize: 1rem !default; 126 | 127 | // Footer 128 | $footer-bg-color: $primary-color !default; 129 | 130 | // Flowtext 131 | $range : $large-screen - $small-screen !default; 132 | $intervals: 20 !default; 133 | $interval-size: $range / $intervals !default; 134 | 135 | /*** Collections ***/ 136 | $collection-border-color: #e0e0e0 !default; 137 | $collection-bg-color: #fff !default; 138 | $collection-active-bg-color: $secondary-color !default; 139 | $collection-active-color: lighten($secondary-color, 55%) !default; 140 | $collection-hover-bg-color: #ddd !default; 141 | 142 | /* Progress Bar */ 143 | $progress-bar-color: $secondary-color !default; 144 | -------------------------------------------------------------------------------- /static/materialize/sass/components/_waves.scss: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | * Waves v0.6.0 4 | * http://fian.my.id/Waves 5 | * 6 | * Copyright 2014 Alfiana E. Sibuea and other contributors 7 | * Released under the MIT license 8 | * https://github.com/fians/Waves/blob/master/LICENSE 9 | */ 10 | 11 | 12 | .waves-effect { 13 | position: relative; 14 | cursor: pointer; 15 | display: inline-block; 16 | overflow: hidden; 17 | -webkit-user-select: none; 18 | -moz-user-select: none; 19 | -ms-user-select: none; 20 | user-select: none; 21 | -webkit-tap-highlight-color: transparent; 22 | // white-space: nowrap; 23 | // outline: 0; 24 | 25 | vertical-align: middle; 26 | // cursor: pointer; 27 | // border: none; 28 | // outline: none; 29 | // color: inherit; 30 | // background-color: rgba(0, 0, 0, 0); 31 | // font-size: 1em; 32 | // line-height:1em; 33 | // text-align: center; 34 | // text-decoration: none; 35 | z-index: 1; 36 | will-change: opacity, transform; 37 | @include transition(all .3s ease-out); 38 | 39 | .waves-ripple { 40 | position: absolute; 41 | border-radius: 50%; 42 | width: 20px; 43 | height: 20px; 44 | margin-top:-10px; 45 | margin-left:-10px; 46 | opacity: 0; 47 | 48 | background: rgba(0,0,0,0.2); 49 | // $gradient: rgba(0,0,0,0.2) 0,rgba(0,0,0,.3) 40%,rgba(0,0,0,.4) 50%,rgba(0,0,0,.5) 60%,rgba(255,255,255,0) 70%; 50 | // background: -webkit-radial-gradient($gradient); 51 | // background: -o-radial-gradient($gradient); 52 | // background: -moz-radial-gradient($gradient); 53 | // background: radial-gradient($gradient); 54 | @include transition(all 0.7s ease-out); 55 | -webkit-transition-property: -webkit-transform, opacity; 56 | -moz-transition-property: -moz-transform, opacity; 57 | -o-transition-property: -o-transform, opacity; 58 | transition-property: transform, opacity; 59 | @include transform(scale(0)); 60 | pointer-events: none; 61 | } 62 | 63 | // Waves Colors 64 | &.waves-light .waves-ripple { 65 | background-color: rgba(255, 255, 255, 0.45); 66 | } 67 | 68 | &.waves-red .waves-ripple { 69 | background-color: rgba(244, 67, 54, .70); 70 | } 71 | &.waves-yellow .waves-ripple { 72 | background-color: rgba(255, 235, 59, .70); 73 | } 74 | &.waves-orange .waves-ripple { 75 | background-color: rgba(255, 152, 0, .70); 76 | } 77 | &.waves-purple .waves-ripple { 78 | background-color: rgba(156, 39, 176, 0.70); 79 | } 80 | &.waves-green .waves-ripple { 81 | background-color: rgba(76, 175, 80, 0.70); 82 | } 83 | &.waves-teal .waves-ripple { 84 | background-color: rgba(0, 150, 136, 0.70); 85 | } 86 | 87 | } 88 | 89 | .waves-notransition { 90 | @include transition(none #{"!important"}); 91 | } 92 | 93 | .waves-circle { 94 | @include transform(translateZ(0)); 95 | -webkit-mask-image: -webkit-radial-gradient(circle, white 100%, black 100%); 96 | } 97 | 98 | // .waves-button, 99 | // .waves-button:hover, 100 | // .waves-button:visited, 101 | // .waves-button-input { 102 | // white-space: nowrap; 103 | // vertical-align: middle; 104 | // cursor: pointer; 105 | // border: none; 106 | // outline: none; 107 | // color: inherit; 108 | // background-color: rgba(0, 0, 0, 0); 109 | // font-size: 1em; 110 | // line-height:1em; 111 | // text-align: center; 112 | // text-decoration: none; 113 | // z-index: 1; 114 | // } 115 | 116 | // .waves-button { 117 | // padding: 0.85em 1.1em; 118 | // border-radius: 0.2em; 119 | // } 120 | 121 | // .waves-button-input { 122 | // margin: 0; 123 | // padding: 0.85em 1.1em; 124 | // } 125 | 126 | .waves-input-wrapper { 127 | border-radius: 0.2em; 128 | vertical-align: bottom; 129 | 130 | // &.waves-button { 131 | // padding: 0; 132 | // } 133 | 134 | .waves-button-input { 135 | position: relative; 136 | top: 0; 137 | left: 0; 138 | z-index: 1; 139 | } 140 | } 141 | 142 | .waves-circle { 143 | text-align: center; 144 | width: 2.5em; 145 | height: 2.5em; 146 | line-height: 2.5em; 147 | border-radius: 50%; 148 | -webkit-mask-image: none; 149 | } 150 | 151 | // .waves-float { 152 | // -webkit-mask-image: none; 153 | // @include box-shadow(0px 1px 1.5px 1px rgba(0, 0, 0, 0.12)); 154 | 155 | // &:active { 156 | // @include box-shadow(0px 8px 20px 1px rgba(0, 0, 0, 0.30)); 157 | // } 158 | // } 159 | 160 | .waves-block { 161 | display: block; 162 | } 163 | 164 | /* Firefox Bug: link not triggered */ 165 | a.waves-effect .waves-ripple { 166 | z-index: -1; 167 | } -------------------------------------------------------------------------------- /static/materialize/sass/components/date_picker/_default.scss: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | $BASE-PICKER 3 | ========================================================================== */ 4 | /** 5 | * Note: the root picker element should *NOT* be styled more than what's here. 6 | */ 7 | .picker { 8 | font-size: 16px; 9 | text-align: left; 10 | line-height: 1.2; 11 | color: #000000; 12 | position: absolute; 13 | z-index: 10000; 14 | -webkit-user-select: none; 15 | -moz-user-select: none; 16 | -ms-user-select: none; 17 | user-select: none; 18 | } 19 | /** 20 | * The picker input element. 21 | */ 22 | .picker__input { 23 | cursor: default; 24 | } 25 | /** 26 | * When the picker is opened, the input element is "activated". 27 | */ 28 | .picker__input.picker__input--active { 29 | border-color: #0089ec; 30 | } 31 | /** 32 | * The holder is the only "scrollable" top-level container element. 33 | */ 34 | .picker__holder { 35 | width: 100%; 36 | overflow-y: auto; 37 | -webkit-overflow-scrolling: touch; 38 | } 39 | 40 | /*! 41 | * Default mobile-first, responsive styling for pickadate.js 42 | * Demo: http://amsul.github.io/pickadate.js 43 | */ 44 | /** 45 | * Note: the root picker element should *NOT* be styled more than what's here. 46 | */ 47 | /** 48 | * Make the holder and frame fullscreen. 49 | */ 50 | .picker__holder, 51 | .picker__frame { 52 | bottom: 0; 53 | left: 0; 54 | right: 0; 55 | top: 100%; 56 | } 57 | /** 58 | * The holder should overlay the entire screen. 59 | */ 60 | .picker__holder { 61 | position: fixed; 62 | -webkit-transition: background 0.15s ease-out, top 0s 0.15s; 63 | -moz-transition: background 0.15s ease-out, top 0s 0.15s; 64 | transition: background 0.15s ease-out, top 0s 0.15s; 65 | -webkit-backface-visibility: hidden; 66 | } 67 | /** 68 | * The frame that bounds the box contents of the picker. 69 | */ 70 | .picker__frame { 71 | position: absolute; 72 | margin: 0 auto; 73 | min-width: 256px; 74 | 75 | // picker width 76 | max-width: 300px; 77 | max-height: 350px; 78 | 79 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; 80 | filter: alpha(opacity=0); 81 | -moz-opacity: 0; 82 | opacity: 0; 83 | -webkit-transition: all 0.15s ease-out; 84 | -moz-transition: all 0.15s ease-out; 85 | transition: all 0.15s ease-out; 86 | } 87 | @media (min-height: 28.875em) { 88 | .picker__frame { 89 | overflow: visible; 90 | top: auto; 91 | bottom: -100%; 92 | max-height: 80%; 93 | } 94 | } 95 | @media (min-height: 40.125em) { 96 | .picker__frame { 97 | margin-bottom: 7.5%; 98 | } 99 | } 100 | /** 101 | * The wrapper sets the stage to vertically align the box contents. 102 | */ 103 | .picker__wrap { 104 | display: table; 105 | width: 100%; 106 | height: 100%; 107 | } 108 | @media (min-height: 28.875em) { 109 | .picker__wrap { 110 | display: block; 111 | } 112 | } 113 | /** 114 | * The box contains all the picker contents. 115 | */ 116 | .picker__box { 117 | background: #ffffff; 118 | display: table-cell; 119 | vertical-align: middle; 120 | } 121 | //@media (min-height: 26.5em) { 122 | // .picker__box { 123 | //// font-size: 1.25em; 124 | // } 125 | //} 126 | @media (min-height: 28.875em) { 127 | .picker__box { 128 | display: block; 129 | 130 | // picker header font-size 131 | // font-size: 1rem; 132 | 133 | border: 1px solid #777777; 134 | border-top-color: #898989; 135 | border-bottom-width: 0; 136 | -webkit-border-radius: 5px 5px 0 0; 137 | -moz-border-radius: 5px 5px 0 0; 138 | border-radius: 5px 5px 0 0; 139 | -webkit-box-shadow: 0 12px 36px 16px rgba(0, 0, 0, 0.24); 140 | -moz-box-shadow: 0 12px 36px 16px rgba(0, 0, 0, 0.24); 141 | box-shadow: 0 12px 36px 16px rgba(0, 0, 0, 0.24); 142 | } 143 | } 144 | //@media (min-height: 40.125em) { 145 | // .picker__box { 146 | // font-size: 1.1rem; 147 | // border-bottom-width: 1px; 148 | // -webkit-border-radius: 5px; 149 | // -moz-border-radius: 5px; 150 | // border-radius: 5px; 151 | // } 152 | //} 153 | /** 154 | * When the picker opens... 155 | */ 156 | .picker--opened .picker__holder { 157 | top: 0; 158 | background: transparent; 159 | -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E000000,endColorstr=#1E000000)"; 160 | zoom: 1; 161 | background: rgba(0, 0, 0, 0.32); 162 | -webkit-transition: background 0.15s ease-out; 163 | -moz-transition: background 0.15s ease-out; 164 | transition: background 0.15s ease-out; 165 | } 166 | .picker--opened .picker__frame { 167 | top: 0; 168 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; 169 | filter: alpha(opacity=100); 170 | -moz-opacity: 1; 171 | opacity: 1; 172 | } 173 | @media (min-height: 35.875em) { 174 | .picker--opened .picker__frame { 175 | top: 10%; 176 | bottom: 20%auto; 177 | } 178 | } 179 | /** 180 | * For `large` screens, transform into an inline picker. 181 | */ 182 | 183 | /* ========================================================================== 184 | CUSTOM MATERIALIZE STYLES 185 | ========================================================================== */ 186 | 187 | .picker__input.picker__input--active { 188 | border-color: color("blue", "lighten-5"); 189 | } 190 | 191 | .picker__frame { 192 | margin: 0 auto; 193 | max-width: 325px; 194 | } 195 | 196 | @media (min-height: 38.875em) { 197 | .picker--opened .picker__frame { 198 | top: 10%; 199 | bottom: auto; 200 | } 201 | } -------------------------------------------------------------------------------- /static/materialize/sass/components/date_picker/_default.time.scss: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | $BASE-TIME-PICKER 3 | ========================================================================== */ 4 | /** 5 | * The list of times. 6 | */ 7 | .picker__list { 8 | list-style: none; 9 | padding: 0.75em 0 4.2em; 10 | margin: 0; 11 | } 12 | /** 13 | * The times on the clock. 14 | */ 15 | .picker__list-item { 16 | border-bottom: 1px solid #dddddd; 17 | border-top: 1px solid #dddddd; 18 | margin-bottom: -1px; 19 | position: relative; 20 | background: #ffffff; 21 | padding: .75em 1.25em; 22 | } 23 | @media (min-height: 46.75em) { 24 | .picker__list-item { 25 | padding: .5em 1em; 26 | } 27 | } 28 | /* Hovered time */ 29 | .picker__list-item:hover { 30 | cursor: pointer; 31 | color: #000000; 32 | background: #b1dcfb; 33 | border-color: #0089ec; 34 | z-index: 10; 35 | } 36 | /* Highlighted and hovered/focused time */ 37 | .picker__list-item--highlighted { 38 | border-color: #0089ec; 39 | z-index: 10; 40 | } 41 | .picker__list-item--highlighted:hover, 42 | .picker--focused .picker__list-item--highlighted { 43 | cursor: pointer; 44 | color: #000000; 45 | background: #b1dcfb; 46 | } 47 | /* Selected and hovered/focused time */ 48 | .picker__list-item--selected, 49 | .picker__list-item--selected:hover, 50 | .picker--focused .picker__list-item--selected { 51 | background: #0089ec; 52 | color: #ffffff; 53 | z-index: 10; 54 | } 55 | /* Disabled time */ 56 | .picker__list-item--disabled, 57 | .picker__list-item--disabled:hover, 58 | .picker--focused .picker__list-item--disabled { 59 | background: #f5f5f5; 60 | border-color: #f5f5f5; 61 | color: #dddddd; 62 | cursor: default; 63 | border-color: #dddddd; 64 | z-index: auto; 65 | } 66 | /** 67 | * The clear button 68 | */ 69 | .picker--time .picker__button--clear { 70 | display: block; 71 | width: 80%; 72 | margin: 1em auto 0; 73 | padding: 1em 1.25em; 74 | background: none; 75 | border: 0; 76 | font-weight: 500; 77 | font-size: .67em; 78 | text-align: center; 79 | text-transform: uppercase; 80 | color: #666; 81 | } 82 | .picker--time .picker__button--clear:hover, 83 | .picker--time .picker__button--clear:focus { 84 | color: #000000; 85 | background: #b1dcfb; 86 | background: #ee2200; 87 | border-color: #ee2200; 88 | cursor: pointer; 89 | color: #ffffff; 90 | outline: none; 91 | } 92 | .picker--time .picker__button--clear:before { 93 | top: -0.25em; 94 | color: #666; 95 | font-size: 1.25em; 96 | font-weight: bold; 97 | } 98 | .picker--time .picker__button--clear:hover:before, 99 | .picker--time .picker__button--clear:focus:before { 100 | color: #ffffff; 101 | } 102 | 103 | /* ========================================================================== 104 | $DEFAULT-TIME-PICKER 105 | ========================================================================== */ 106 | /** 107 | * The frame the bounds the time picker. 108 | */ 109 | .picker--time .picker__frame { 110 | min-width: 256px; 111 | max-width: 320px; 112 | } 113 | /** 114 | * The picker box. 115 | */ 116 | .picker--time .picker__box { 117 | font-size: 1em; 118 | background: #f2f2f2; 119 | padding: 0; 120 | } 121 | @media (min-height: 40.125em) { 122 | .picker--time .picker__box { 123 | margin-bottom: 5em; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /static/materialize/sass/materialize.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | // Mixins 4 | @import "components/prefixer"; 5 | @import "components/mixins"; 6 | @import "components/color"; 7 | 8 | // Variables; 9 | @import "components/variables"; 10 | 11 | // Reset 12 | @import "components/normalize"; 13 | 14 | // components 15 | @import "components/global"; 16 | @import "components/icons-material-design"; 17 | @import "components/grid"; 18 | @import "components/navbar"; 19 | @import "components/roboto"; 20 | @import "components/typography"; 21 | @import "components/cards"; 22 | @import "components/toast"; 23 | @import "components/tabs"; 24 | @import "components/tooltip"; 25 | @import "components/buttons"; 26 | @import "components/dropdown"; 27 | @import "components/waves"; 28 | @import "components/modal"; 29 | @import "components/collapsible"; 30 | @import "components/materialbox"; 31 | @import "components/form"; 32 | @import "components/table_of_contents"; 33 | @import "components/sideNav"; 34 | @import "components/preloader"; 35 | @import "components/slider"; 36 | @import "components/date_picker/default.scss"; 37 | @import "components/date_picker/default.date.scss"; 38 | @import "components/date_picker/default.time.scss"; -------------------------------------------------------------------------------- /static/materialize/templates/masonry-template/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Materialize 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /static/materialize/templates/masonry-template/background1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/templates/masonry-template/background1.jpg -------------------------------------------------------------------------------- /static/materialize/templates/masonry-template/background2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/templates/masonry-template/background2.jpg -------------------------------------------------------------------------------- /static/materialize/templates/masonry-template/background3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/templates/masonry-template/background3.jpg -------------------------------------------------------------------------------- /static/materialize/templates/masonry-template/css/style.css: -------------------------------------------------------------------------------- 1 | /* Custom Stylesheet */ 2 | /** 3 | * Use this file to override Materialize files so you can update 4 | * the core Materialize files in the future 5 | * 6 | * Made By MaterializeCSS.com 7 | */ 8 | 9 | nav ul a, 10 | nav .brand-logo { 11 | color: #444; 12 | } 13 | 14 | p { 15 | line-height: 2rem; 16 | } 17 | 18 | .button-collapse { 19 | color: #26a69a; 20 | } 21 | 22 | .parallax-container { 23 | min-height: 380px; 24 | line-height: 0; 25 | height: auto; 26 | color: rgba(255,255,255,.9); 27 | } 28 | .parallax-container .section { 29 | width: 100%; 30 | } 31 | 32 | @media only screen and (max-width : 992px) { 33 | .parallax-container .section { 34 | position: absolute; 35 | top: 40%; 36 | } 37 | #index-banner .section { 38 | top: 10%; 39 | } 40 | } 41 | 42 | @media only screen and (max-width : 600px) { 43 | #index-banner .section { 44 | top: 0; 45 | } 46 | } 47 | 48 | 49 | .icon-block { 50 | padding: 0 15px; 51 | } 52 | 53 | footer.page-footer { 54 | margin: 0; 55 | } -------------------------------------------------------------------------------- /static/materialize/templates/masonry-template/js/init.js: -------------------------------------------------------------------------------- 1 | (function($){ 2 | $(function(){ 3 | 4 | $('.button-collapse').sideNav(); 5 | 6 | 7 | var $container = $('#masonry-grid'); 8 | // initialize 9 | $container.masonry({ 10 | columnWidth: '.col', 11 | itemSelector: '.col', 12 | }); 13 | 14 | 15 | }); // end of document ready 16 | })(jQuery); // end of jQuery name space -------------------------------------------------------------------------------- /static/materialize/templates/parallax-template/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Materialize 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /static/materialize/templates/parallax-template/background1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/templates/parallax-template/background1.jpg -------------------------------------------------------------------------------- /static/materialize/templates/parallax-template/background2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/templates/parallax-template/background2.jpg -------------------------------------------------------------------------------- /static/materialize/templates/parallax-template/background3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/materialize/templates/parallax-template/background3.jpg -------------------------------------------------------------------------------- /static/materialize/templates/parallax-template/css/style.css: -------------------------------------------------------------------------------- 1 | /* Custom Stylesheet */ 2 | /** 3 | * Use this file to override Materialize files so you can update 4 | * the core Materialize files in the future 5 | * 6 | * Made By MaterializeCSS.com 7 | */ 8 | 9 | nav ul a, 10 | nav .brand-logo { 11 | color: #444; 12 | } 13 | 14 | p { 15 | line-height: 2rem; 16 | } 17 | 18 | .button-collapse { 19 | color: #26a69a; 20 | } 21 | 22 | .parallax-container { 23 | min-height: 380px; 24 | line-height: 0; 25 | height: auto; 26 | color: rgba(255,255,255,.9); 27 | } 28 | .parallax-container .section { 29 | width: 100%; 30 | } 31 | 32 | @media only screen and (max-width : 992px) { 33 | .parallax-container .section { 34 | position: absolute; 35 | top: 40%; 36 | } 37 | #index-banner .section { 38 | top: 10%; 39 | } 40 | } 41 | 42 | @media only screen and (max-width : 600px) { 43 | #index-banner .section { 44 | top: 0; 45 | } 46 | } 47 | 48 | 49 | .icon-block { 50 | padding: 0 15px; 51 | } 52 | 53 | footer.page-footer { 54 | margin: 0; 55 | } -------------------------------------------------------------------------------- /static/materialize/templates/parallax-template/js/init.js: -------------------------------------------------------------------------------- 1 | (function($){ 2 | $(function(){ 3 | 4 | $('.button-collapse').sideNav(); 5 | $('.parallax').parallax(); 6 | 7 | }); // end of document ready 8 | })(jQuery); // end of jQuery name space -------------------------------------------------------------------------------- /static/materialize/templates/starter-template/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Materialize 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /static/materialize/templates/starter-template/css/style.css: -------------------------------------------------------------------------------- 1 | /* Custom Stylesheet */ 2 | /** 3 | * Use this file to override Materialize files so you can update 4 | * the core Materialize files in the future 5 | * 6 | * Made By MaterializeCSS.com 7 | */ 8 | 9 | .icon-block { 10 | padding: 0 15px; 11 | } -------------------------------------------------------------------------------- /static/materialize/templates/starter-template/js/init.js: -------------------------------------------------------------------------------- 1 | (function($){ 2 | $(function(){ 3 | 4 | $('.button-collapse').sideNav(); 5 | 6 | }); // end of document ready 7 | })(jQuery); // end of jQuery name space -------------------------------------------------------------------------------- /static/sounds/inbound.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/sounds/inbound.mp3 -------------------------------------------------------------------------------- /static/styles/source/index.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | // Mixins 4 | @import "../../components/materialize/sass/components/prefixer"; 5 | @import "../../components/materialize/sass/components/mixins"; 6 | @import "../../components/materialize/sass/components/color"; 7 | @import "theme_color"; 8 | 9 | // Variables; 10 | @import "../../components/materialize/sass/components/variables"; 11 | @import "theme_variables"; 12 | 13 | // Reset 14 | @import "../../components/materialize/sass/components/normalize"; 15 | 16 | // components 17 | @import "../../components/materialize/sass/components/global"; 18 | @import "../../components/materialize/sass/components/icons-material-design"; 19 | @import "../../components/materialize/sass/components/grid"; 20 | @import "../../components/materialize/sass/components/navbar"; 21 | @import "../../components/materialize/sass/components/roboto"; 22 | @import "../../components/materialize/sass/components/typography"; 23 | @import "../../components/materialize/sass/components/cards"; 24 | @import "../../components/materialize/sass/components/toast"; 25 | @import "../../components/materialize/sass/components/tabs"; 26 | @import "../../components/materialize/sass/components/tooltip"; 27 | @import "../../components/materialize/sass/components/buttons"; 28 | @import "../../components/materialize/sass/components/dropdown"; 29 | @import "../../components/materialize/sass/components/waves"; 30 | @import "../../components/materialize/sass/components/modal"; 31 | @import "../../components/materialize/sass/components/collapsible"; 32 | @import "../../components/materialize/sass/components/materialbox"; 33 | @import "../../components/materialize/sass/components/form"; 34 | @import "../../components/materialize/sass/components/table_of_contents"; 35 | @import "../../components/materialize/sass/components/sideNav"; 36 | @import "../../components/materialize/sass/components/preloader"; 37 | @import "../../components/materialize/sass/components/slider"; 38 | @import "../../components/materialize/sass/components/date_picker/default.scss"; 39 | @import "../../components/materialize/sass/components/date_picker/default.date.scss"; 40 | @import "../../components/materialize/sass/components/date_picker/default.time.scss"; 41 | -------------------------------------------------------------------------------- /static/styles/source/theme_color.scss: -------------------------------------------------------------------------------- 1 | // Twilio Colors 2 | $red: ( 3 | ); 4 | 5 | $twilioMaroon: ( 6 | "base": #971d1f, 7 | ); 8 | 9 | $twilioGray: ( 10 | "base": #2c2c2a, 11 | ); 12 | 13 | $twilioBlack: ( 14 | "base": #231f20, 15 | ); 16 | 17 | $twilioBrown: ( 18 | "base": #b1aca0, 19 | ); 20 | 21 | $twilioBeige: ( 22 | "base": #dbddd7, 23 | ); 24 | 25 | $twilioBlue: ( 26 | "base": #54c3c2, 27 | ); 28 | 29 | // Theme colors 30 | $colors: ( 31 | "materialize-red": $twilioRed, 32 | "red": $twilioRed, 33 | "blue": $twilioBlue, 34 | "grey": $twilioGray, 35 | ) !default; 36 | -------------------------------------------------------------------------------- /static/styles/source/theme_variables.scss: -------------------------------------------------------------------------------- 1 | $primary-color: color("purple") !default; 2 | $link-color: color("teal", "darken-1") !default; 3 | -------------------------------------------------------------------------------- /static/styles/theme.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/static/styles/theme.css -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% block title %}{% endblock %} 5 | 6 | 7 | 9 | {% block head %}{% endblock %} 10 | 11 | 12 | {% block content %}{% endblock %} 13 | 15 | 17 | 26 | 27 | 28 | {% block javascript %}{% endblock %} 29 | 30 | 31 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Call Your Family - Nepal Earthquake{% endblock %} 4 | 5 | {% block head %} 6 | 8 | 9 | {% endblock %} 10 | 11 | {% block content %} 12 | 24 |
    25 |
    26 |

    27 | {% if params['config_errors'] %} 28 |

    Configuration Error!

    29 | {% else %} 30 |

    Call Your Family

    31 | {% endif %} 32 |
    33 |
    Free 10 minute call to a loved one affected by the Nepalese earthquake.
    34 |
    35 |

    36 |
    37 |
    38 |
    39 |
    40 |
    41 |

    42 | {% if params['config_errors'] %} 43 |
    There was an error configuring this app.
    44 | {% for error in params['config_errors'] %} 45 |

    {{ error }}

    46 | {% endfor %} 47 | {% else %} 48 |
    Powered By Twilio
    49 |

    1. Select the country you wish to call.

    50 |

    2. Input the number.

    51 |

    3. Press Call button.

    52 |

    4. Click "Allow" in your browser or dialog.

    53 |

    5. Talk through your browser for ten minutes.

    54 | {% endif %} 55 |
    56 |
    57 |
    58 |
    59 |

    60 | {% if not params['config_errors'] %} 61 |
    Input the phone number to call below:
    62 |
    63 | 64 | 66 | ✓ Valid 67 | Invalid number 68 |
    69 | {% endif %} 70 |
    71 |
    72 |
    73 |
    74 |
    75 |
    76 |
    77 |
    78 |
    Powered by Twilio.org
    79 |

    Calls are free for you and the party you call. Calls last ten minutes.

    80 |
    81 |
    82 | 93 |
    94 | 104 | 105 | {% endblock %} 106 | 107 | {% block javascript %} 108 | 110 | 194 | {% endblock %} 195 | -------------------------------------------------------------------------------- /templates/thankyou.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Call Your Family - Boston Marathon{% endblock %} 4 | 5 | {% block head %} 6 | 8 | 10 | {% endblock %} 11 | 12 | {% block content %} 13 |
    14 |
    15 | 22 |
    23 |
    24 |
    25 | {% if params['config_errors'] %} 26 |

    We just need to set a few more 27 | configuration options.

    28 |

    Check your local_settings.py to set these missing 29 | options:

    30 |
    31 | {% for error in params['config_errors'] %} 32 |
    Error
    33 |
    {{ error }}
    34 | {% endfor %} 35 |
    36 | {% else %} 37 |

    Our hearts and heads are with 38 | Boston.

    39 |
    40 | {% endif %} 41 |
    42 |
    43 | 55 |
    56 | {% endblock %} 57 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobSpectre/Call-Your-Family/9f41bda1fab9368b32332c678874f27c943311ff/tests/__init__.py -------------------------------------------------------------------------------- /tests/context.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | sys.path.insert(0, os.path.abspath('..')) 4 | 5 | import configure 6 | from app import app 7 | -------------------------------------------------------------------------------- /tests/test_assets/bad_git_config: -------------------------------------------------------------------------------- 1 | [core] 2 | repositoryformatversion = 0 3 | filemode = true 4 | bare = false 5 | logallrefupdates = true 6 | -------------------------------------------------------------------------------- /tests/test_assets/good_git_config: -------------------------------------------------------------------------------- 1 | [core] 2 | repositoryformatversion = 0 3 | filemode = true 4 | bare = false 5 | logallrefupdates = true 6 | [remote "heroku"] 7 | url = git@heroku.com:look-here-snacky-11211.git 8 | fetch = +refs/heads/*:refs/remotes/heroku/* 9 | -------------------------------------------------------------------------------- /tests/test_twilio.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from .context import app 3 | 4 | 5 | class TwiMLTest(unittest.TestCase): 6 | def setUp(self): 7 | self.app = app.test_client() 8 | 9 | def assertTwiML(self, response): 10 | self.assertTrue("" in response.data, "Did not find " \ 11 | ": %s" % response.data) 12 | self.assertTrue("" in response.data, "Did not find " \ 13 | ": %s" % response.data) 14 | self.assertEqual("200 OK", response.status) 15 | 16 | def sms(self, body, path='/sms', number='+15555555555'): 17 | params = { 18 | 'SmsSid': 'SMtesting', 19 | 'AccountSid': 'ACtesting', 20 | 'From': number, 21 | 'To': '+16666666666', 22 | 'Body': body, 23 | 'ApiVersion': '2010-04-01', 24 | 'Direction': 'inbound'} 25 | return self.app.post(path, data=params) 26 | 27 | def call(self, path='/voice', caller_id='+15555555555', digits=None, 28 | phone_number=None): 29 | params = { 30 | 'CallSid': 'CAtesting', 31 | 'AccountSid': 'ACtesting', 32 | 'From': caller_id, 33 | 'To': '+16666666666', 34 | 'CallStatus': 'ringing', 35 | 'ApiVersion': '2010-04-01', 36 | 'Direction': 'inbound'} 37 | if digits: 38 | params['Digits'] = digits 39 | if phone_number: 40 | params['PhoneNumber'] = phone_number 41 | return self.app.post(path, data=params) 42 | 43 | 44 | class TwilioTests(TwiMLTest): 45 | def test_voice(self): 46 | response = self.call(phone_number="+15557778888") 47 | self.assertTwiML(response) 48 | 49 | def test_inbound(self): 50 | response = self.call(path='/inbound') 51 | self.assertTwiML(response) 52 | 53 | def test_sms(self): 54 | response = self.sms("Test") 55 | self.assertTwiML(response) 56 | -------------------------------------------------------------------------------- /tests/test_web.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from .context import app 4 | 5 | app.config['TWILIO_ACCOUNT_SID'] = 'ACxxxxxx' 6 | app.config['TWILIO_AUTH_TOKEN'] = 'yyyyyyyyy' 7 | app.config['TWILIO_CALLER_ID'] = '+15558675309' 8 | app.config['IOS_URI'] = \ 9 | 'http://itunes.apple.com/us/app/plants-vs.-zombies/id350642635?mt=8&uo=4' 10 | app.config['ANDROID_URI'] = \ 11 | 'http://market.android.com/details?id=com.popcap.pvz_row' 12 | app.config['WEB_URI'] = 'http://www.popcap.com/games/plants-vs-zombies/pc' 13 | 14 | 15 | class WebTest(unittest.TestCase): 16 | def setUp(self): 17 | self.app = app.test_client() 18 | 19 | 20 | class IndexTests(WebTest): 21 | def test_index(self): 22 | response = self.app.get('/') 23 | self.assertEqual("200 OK", response.status) 24 | --------------------------------------------------------------------------------