Release 0.1.0 (CaptainCore is born)

This commit is contained in:
Austin Ginder 2018-02-04 13:54:24 -05:00
commit 2fe82e661a
139 changed files with 48597 additions and 0 deletions

7
.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
*~
.DS_Store
.svn
.cvs
*.bak
*.swp
Thumbs.db

339
LICENSE.txt Executable file
View file

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

39
README.txt Executable file
View file

@ -0,0 +1,39 @@
=== CaptainCore ===
Author URI: https://anchor.host
Plugin URI: https://captaincore.io
Contributors: austinginder
Tags: hosting, dns, wp hosting, web host, website management, web host business
Requires at least: 3.0.1
Tested up to: 3.4
Stable tag: 4.3
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Toolkit for running your own WordPress hosting business
== Description ==
CaptainCore is an open sourced toolkit made and used by [Anchor Hosting](https://anchor.host). If your a geek take a look on Github and help contribute! If you just want to pay someone to setup and run CaptainCore for your business then check out [CaptainCore.io](https://captaincore.io). We'll handle getting your business and hosting customers moved over.
== Installation ==
This section describes how to install the plugin and get it working.
e.g.
1. Upload `/captaincore/` to the `/wp-content/plugins/` directory
1. Activate the plugin through the 'Plugins' menu in WordPress
1. CaptainCore requires access to a remote server running CaptainCore CLI. (TODO: add instructions for adding keys to wp-config.php)
== Frequently Asked Questions ==
TODO
== Screenshots ==
TODO
== Changelog ==
= 0.1.0: February 4, 2018 =
CaptainCore is born.

103
admin/class-captaincore-admin.php Executable file
View file

@ -0,0 +1,103 @@
<?php
/**
* The admin-specific functionality of the plugin.
*
* @link https://anchor.host
* @since 0.1.0
*
* @package Captaincore
* @subpackage Captaincore/admin
*/
/**
* The admin-specific functionality of the plugin.
*
* Defines the plugin name, version, and two examples hooks for how to
* enqueue the admin-specific stylesheet and JavaScript.
*
* @package Captaincore
* @subpackage Captaincore/admin
* @author Anchor Hosting <support@anchor.host>
*/
class Captaincore_Admin {
/**
* The ID of this plugin.
*
* @since 0.1.0
* @access private
* @var string $plugin_name The ID of this plugin.
*/
private $plugin_name;
/**
* The version of this plugin.
*
* @since 0.1.0
* @access private
* @var string $version The current version of this plugin.
*/
private $version;
/**
* Initialize the class and set its properties.
*
* @since 0.1.0
* @param string $plugin_name The name of this plugin.
* @param string $version The version of this plugin.
*/
public function __construct( $plugin_name, $version ) {
$this->plugin_name = $plugin_name;
$this->version = $version;
}
/**
* Register the stylesheets for the admin area.
*
* @since 0.1.0
*/
public function enqueue_styles() {
/**
* This function is provided for demonstration purposes only.
*
* An instance of this class should be passed to the run() function
* defined in Captaincore_Loader as all of the hooks are defined
* in that particular class.
*
* The Captaincore_Loader will then create the relationship
* between the defined hooks and the functions defined in this
* class.
*/
wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/captaincore-admin.css', array(), $this->version, 'all' );
}
/**
* Register the JavaScript for the admin area.
*
* @since 0.1.0
*/
public function enqueue_scripts() {
/**
* This function is provided for demonstration purposes only.
*
* An instance of this class should be passed to the run() function
* defined in Captaincore_Loader as all of the hooks are defined
* in that particular class.
*
* The Captaincore_Loader will then create the relationship
* between the defined hooks and the functions defined in this
* class.
*/
wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/captaincore-admin.js', array( 'jquery' ), $this->version, false );
}
}

View file

@ -0,0 +1,4 @@
/**
* All of the CSS for your admin-specific functionality should be
* included in this file.
*/

1
admin/index.php Executable file
View file

@ -0,0 +1 @@
<?php // Silence is golden

32
admin/js/captaincore-admin.js Executable file
View file

@ -0,0 +1,32 @@
(function( $ ) {
'use strict';
/**
* All of the code for your admin-facing JavaScript source
* should reside in this file.
*
* Note: It has been assumed you will write jQuery code here, so the
* $ function reference has been prepared for usage within the scope
* of this function.
*
* This enables you to define handlers, for when the DOM is ready:
*
* $(function() {
*
* });
*
* When the window is loaded:
*
* $( window ).load(function() {
*
* });
*
* ...and/or other possibilities.
*
* Ideally, it is not considered best practise to attach more than a
* single DOM-ready or window-load handler for a particular page.
* Although scripts in the WordPress core, Plugins and Themes may be
* practising this, we should strive to set a better example in our own work.
*/
})( jQuery );

View file

@ -0,0 +1,16 @@
<?php
/**
* Provide a admin area view for the plugin
*
* This file is used to markup the admin-facing aspects of the plugin.
*
* @link https://anchor.host
* @since 0.1.0
*
* @package Captaincore
* @subpackage Captaincore/admin/partials
*/
?>
<!-- This file should primarily consist of HTML with a little bit of PHP. -->

3317
captaincore.php Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,175 @@
<?php
/**
* This plugin allows you to include templates with your plugin so that they can
* be added with any theme.
*
* @package Page Template Example
* @version 0.1.0
* @since 0.1.0
*/
class Page_Template_Plugin {
/**
* Plugin version, used for cache-busting of style and script file references.
*
* @since 0.1.0
*
* @var string
*/
const VERSION = '0.1.0';
/**
* Unique identifier for the plugin.
*
* The variable name is used as the text domain when internationalizing strings
* of text.
*
* @since 0.1.0
*
* @var string
*/
protected $plugin_slug;
/**
* A reference to an instance of this class.
*
* @since 0.1.0
*
* @var Page_Template_Plugin
*/
private static $instance;
/**
* The array of templates that this plugin tracks.
*
* @var array
*/
protected $templates;
/**
* Returns an instance of this class. An implementation of the singleton design pattern.
*
* @return Page_Templae_Example A reference to an instance of this class.
* @since 0.1.0
*/
public static function get_instance() {
if( null == self::$instance ) {
self::$instance = new Page_Template_Plugin();
} // end if
return self::$instance;
} // end getInstance
/**
* Initializes the plugin by setting localization, filters, and administration functions.
*
* @version 0.1.0
* @since 0.1.0
*/
private function __construct() {
$this->templates = array();
$this->plugin_locale = 'pte';
// Grab the translations for the plugin
add_action( 'init', array( $this, 'load_plugin_textdomain' ) );
// Add a filter to the page attributes metabox to inject our template into the page template cache.
add_filter('page_attributes_dropdown_pages_args', array( $this, 'register_project_templates' ) );
// Add a filter to the save post in order to inject out template into the page cache
add_filter('wp_insert_post_data', array( $this, 'register_project_templates' ) );
// Add a filter to the template include in order to determine if the page has our template assigned and return it's path
add_filter('template_include', array( $this, 'view_project_template') );
// Register hooks that are fired when the plugin is activated, deactivated, and uninstalled, respectively.
register_deactivation_hook( __FILE__, array( $this, 'deactivate' ) );
// Add your templates to this array.
$this->templates = array(
'page-company-handbook.php' => __( 'Company Handbook', $this->plugin_slug ),
'page-anchor-api.php' => __( 'Anchor API', $this->plugin_slug ),
);
// adding support for theme templates to be merged and shown in dropdown
$templates = wp_get_theme()->get_page_templates();
$templates = array_merge( $templates, $this->templates );
} // end constructor
/**
* Load the plugin text domain for translation.
*
* @since 0.1.0
*/
public function load_plugin_textdomain() {
$domain = $this->plugin_slug;
$locale = apply_filters( 'plugin_locale', get_locale(), $domain );
load_textdomain( $domain, trailingslashit( WP_LANG_DIR ) . $domain . '/' . $domain . '-' . $locale . '.mo' );
load_plugin_textdomain( $domain, FALSE, basename( dirname( __FILE__ ) ) . '/languages/' );
} // end load_plugin_textdomain
/**
* Adds our template to the pages cache in order to trick WordPress
* into thinking the template file exists where it doens't really exist.
*
* @param array $atts The attributes for the page attributes dropdown
* @return array $atts The attributes for the page attributes dropdown
* @verison 0.1.0
* @since 0.1.0
*/
public function register_project_templates( $atts ) {
// Create the key used for the themes cache
$cache_key = 'page_templates-' . md5( get_theme_root() . '/' . get_stylesheet() );
// Retrieve the cache list. If it doesn't exist, or it's empty prepare an array
$templates = wp_cache_get( $cache_key, 'themes' );
if ( empty( $templates ) ) {
$templates = array();
} // end if
// Since we've updated the cache, we need to delete the old cache
wp_cache_delete( $cache_key , 'themes');
// Now add our template to the list of templates by merging our templates
// with the existing templates array from the cache.
$templates = array_merge( $templates, $this->templates );
// Add the modified cache to allow WordPress to pick it up for listing
// available templates
wp_cache_add( $cache_key, $templates, 'themes', 1800 );
return $atts;
} // end register_project_templates
/**
* Checks if the template is assigned to the page
*
* @version 0.1.0
* @since 0.1.0
*/
public function view_project_template( $template ) {
global $post;
// If no posts found, return to
// avoid "Trying to get property of non-object" error
if ( !isset( $post ) ) return $template;
if ( ! isset( $this->templates[ get_post_meta( $post->ID, '_wp_page_template', true ) ] ) ) {
return $template;
} // end if
$file = plugin_dir_path( __FILE__ ) . 'templates/' . get_post_meta( $post->ID, '_wp_page_template', true );
// Just to be safe, we check if the file exist first
if( file_exists( $file ) ) {
return $file;
} // end if
return $template;
} // end view_project_template
/*--------------------------------------------*
* deactivate the plugin
*---------------------------------------------*/
static function deactivate( $network_wide ) {
foreach($this as $value) {
page-template-example::delete_template( $value );
}
} // end deactivate
/*--------------------------------------------*
* Delete Templates from Theme
*---------------------------------------------*/
public function delete_template( $filename ){
$theme_path = get_template_directory();
$template_path = $theme_path . '/' . $filename;
if( file_exists( $template_path ) ) {
unlink( $template_path );
}
// we should probably delete the old cache
wp_cache_delete( $cache_key , 'themes');
}
/**
* Retrieves and returns the slug of this plugin. This function should be called on an instance
* of the plugin outside of this class.
*
* @return string The plugin's slug used in the locale.
* @version 0.1.0
* @since 0.1.0
*/
public function get_locale() {
return $this->plugin_slug;
} // end get_locale
} // end class

View file

@ -0,0 +1,210 @@
<style>
.heading {
margin-top: 2em;
font-weight: bold;
font-size: 1.4em;
}
.total {
font-weight: bold;
padding: 10px 0px;
display: block;
}
</style>
<div class="wrap"><div id="icon-tools" class="icon32"></div>
<h2>Customer Report</h2>
<?php
$next_month = $date = date('m', strtotime('+1 month'));
$next_year = $date = date('Y', strtotime('+1 year'));
// WP_Query arguments
$args = array (
'post_type' => array( 'customer' ),
'posts_per_page' => '-1',
);
// The Query
$query = new WP_Query( $args );
$posts = $query->get_posts();
// The Loop
if ( $query->have_posts() ) {
echo "<div class='websites'>";
while ( $query->have_posts() ) {
$query->the_post();
$month = date('m', strtotime(get_field('billing_date')));
if ($month < $next_month) {
$monthyear = $next_year . $month;
} else {
$monthyear = date('Y') . $month;
}
?>
<div class="website" data-renewal="<?php echo $monthyear; ?>" data-price="<?php the_field('total_price'); ?>" data-terms="<?php the_field('billing_terms'); ?>">
<?php the_title(); ?> - $<?php the_field('total_price'); ?> <?php the_field('billing_terms'); ?>
</div>
<?php
}
echo "</div>";
} else {
// no posts found
}
// Restore original Post Data
wp_reset_postdata();
?>
</div>
<div id="result"></div>
<script>
var today = new Date();
// current year
year = today.getFullYear();
// next month
month = ("0" + (today.getMonth() + 1)).slice(-2);
var renewals = {},
renewal;
// loop through and build renewals object to store upcoming months
for (var i = 1; i < 13; i++) {
loop_month = ("0" + (i)).slice(-2);;
next_year = year + 1;
if (parseInt(month) < i) {
renewals[year + loop_month] = 0;
} else {
renewals[next_year + loop_month] = 0;
}
}
// Totals up the renewals
jQuery('.websites .website[data-renewal]').each(function(i, el){
renewal = jQuery(el).data('renewal');
price = jQuery(el).data('price');
if (renewals.hasOwnProperty(renewal)) {
renewals[renewal] += 1;
}
else {
renewals[renewal] = 1;
}
});
/*! jquery-dateFormat 18-05-2015 */
var DateFormat={};!function(a){var b=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],c=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],d=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],e=["January","February","March","April","May","June","July","August","September","October","November","December"],f={Jan:"01",Feb:"02",Mar:"03",Apr:"04",May:"05",Jun:"06",Jul:"07",Aug:"08",Sep:"09",Oct:"10",Nov:"11",Dec:"12"},g=/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.?\d{0,3}[Z\-+]?(\d{2}:?\d{2})?/;a.format=function(){function a(a){return b[parseInt(a,10)]||a}function h(a){return c[parseInt(a,10)]||a}function i(a){var b=parseInt(a,10)-1;return d[b]||a}function j(a){var b=parseInt(a,10)-1;return e[b]||a}function k(a){return f[a]||a}function l(a){var b,c,d,e,f,g=a,h="";return-1!==g.indexOf(".")&&(e=g.split("."),g=e[0],h=e[e.length-1]),f=g.split(":"),3===f.length?(b=f[0],c=f[1],d=f[2].replace(/\s.+/,"").replace(/[a-z]/gi,""),g=g.replace(/\s.+/,"").replace(/[a-z]/gi,""),{time:g,hour:b,minute:c,second:d,millis:h}):{time:"",hour:"",minute:"",second:"",millis:""}}function m(a,b){for(var c=b-String(a).length,d=0;c>d;d++)a="0"+a;return a}return{parseDate:function(a){var b,c,d={date:null,year:null,month:null,dayOfMonth:null,dayOfWeek:null,time:null};if("number"==typeof a)return this.parseDate(new Date(a));if("function"==typeof a.getFullYear)d.year=String(a.getFullYear()),d.month=String(a.getMonth()+1),d.dayOfMonth=String(a.getDate()),d.time=l(a.toTimeString()+"."+a.getMilliseconds());else if(-1!=a.search(g))b=a.split(/[T\+-]/),d.year=b[0],d.month=b[1],d.dayOfMonth=b[2],d.time=l(b[3].split(".")[0]);else switch(b=a.split(" "),6===b.length&&isNaN(b[5])&&(b[b.length]="()"),b.length){case 6:d.year=b[5],d.month=k(b[1]),d.dayOfMonth=b[2],d.time=l(b[3]);break;case 2:c=b[0].split("-"),d.year=c[0],d.month=c[1],d.dayOfMonth=c[2],d.time=l(b[1]);break;case 7:case 9:case 10:d.year=b[3],d.month=k(b[1]),d.dayOfMonth=b[2],d.time=l(b[4]);break;case 1:c=b[0].split(""),d.year=c[0]+c[1]+c[2]+c[3],d.month=c[5]+c[6],d.dayOfMonth=c[8]+c[9],d.time=l(c[13]+c[14]+c[15]+c[16]+c[17]+c[18]+c[19]+c[20]);break;default:return null}return d.date=d.time?new Date(d.year,d.month-1,d.dayOfMonth,d.time.hour,d.time.minute,d.time.second,d.time.millis):new Date(d.year,d.month-1,d.dayOfMonth),d.dayOfWeek=String(d.date.getDay()),d},date:function(b,c){try{var d=this.parseDate(b);if(null===d)return b;for(var e,f=d.year,g=d.month,k=d.dayOfMonth,l=d.dayOfWeek,n=d.time,o="",p="",q="",r=!1,s=0;s<c.length;s++){var t=c.charAt(s),u=c.charAt(s+1);if(r)"'"==t?(p+=""===o?"'":o,o="",r=!1):o+=t;else switch(o+=t,q="",o){case"ddd":p+=a(l),o="";break;case"dd":if("d"===u)break;p+=m(k,2),o="";break;case"d":if("d"===u)break;p+=parseInt(k,10),o="";break;case"D":k=1==k||21==k||31==k?parseInt(k,10)+"st":2==k||22==k?parseInt(k,10)+"nd":3==k||23==k?parseInt(k,10)+"rd":parseInt(k,10)+"th",p+=k,o="";break;case"MMMM":p+=j(g),o="";break;case"MMM":if("M"===u)break;p+=i(g),o="";break;case"MM":if("M"===u)break;p+=m(g,2),o="";break;case"M":if("M"===u)break;p+=parseInt(g,10),o="";break;case"y":case"yyy":if("y"===u)break;p+=o,o="";break;case"yy":if("y"===u)break;p+=String(f).slice(-2),o="";break;case"yyyy":p+=f,o="";break;case"HH":p+=m(n.hour,2),o="";break;case"H":if("H"===u)break;p+=parseInt(n.hour,10),o="";break;case"hh":e=0===parseInt(n.hour,10)?12:n.hour<13?n.hour:n.hour-12,p+=m(e,2),o="";break;case"h":if("h"===u)break;e=0===parseInt(n.hour,10)?12:n.hour<13?n.hour:n.hour-12,p+=parseInt(e,10),o="";break;case"mm":p+=m(n.minute,2),o="";break;case"m":if("m"===u)break;p+=n.minute,o="";break;case"ss":p+=m(n.second.substring(0,2),2),o="";break;case"s":if("s"===u)break;p+=n.second,o="";break;case"S":case"SS":if("S"===u)break;p+=o,o="";break;case"SSS":var v="000"+n.millis.substring(0,3);p+=v.substring(v.length-3),o="";break;case"a":p+=n.hour>=12?"PM":"AM",o="";break;case"p":p+=n.hour>=12?"p.m.":"a.m.",o="";break;case"E":p+=h(l),o="";break;case"'":o="",r=!0;break;default:p+=t,o=""}}return p+=q}catch(w){return console&&console.log&&console.log(w),b}},prettyDate:function(a){var b,c,d;return("string"==typeof a||"number"==typeof a)&&(b=new Date(a)),"object"==typeof a&&(b=new Date(a.toString())),c=((new Date).getTime()-b.getTime())/1e3,d=Math.floor(c/86400),isNaN(d)||0>d?void 0:60>c?"just now":120>c?"1 minute ago":3600>c?Math.floor(c/60)+" minutes ago":7200>c?"1 hour ago":86400>c?Math.floor(c/3600)+" hours ago":1===d?"Yesterday":7>d?d+" days ago":31>d?Math.ceil(d/7)+" weeks ago":d>=31?"more than 5 weeks ago":void 0},toBrowserTimeZone:function(a,b){return this.date(new Date(a),b||"MM/dd/yyyy HH:mm:ss")}}}()}(DateFormat),function(a){a.format=DateFormat.format}(jQuery);
// Loop through all monthlys terms and attach to the other groupings
jQuery('.websites .website[data-terms=month]').each(function(){
renewal = jQuery(this).data('renewal');
// gather months/years
months = Object.keys(renewals);
// loop through each month/years
for (i in months) {
// create new website element for each month
new_cloned_website = jQuery(this).clone();
// assign new month/year
jQuery(new_cloned_website).attr('data-renewal', months[i]);
current_month = months[i];
if (renewal != current_month) {
jQuery('.websites .website[data-renewal='+ months[i] +']:last').after(new_cloned_website);
}
}
});
// Loop through all quarterly terms and attach to the other groupings
jQuery('.websites .website[data-terms=quarter]').each(function(){
renewal = jQuery(this).data('renewal');
renewal_year = parseInt(renewal.toString().substring(0, 4));
renewal_month = parseInt(renewal.toString().substring(4, 6));
// form list of months which it will renew
// gather months
var renewal_months = []
for (var i = 0; i < 4; i++) {
calculated_month = renewal_month + (i * 3);
if (calculated_month > 12) {
renewal_months.push(renewal_month + (i * 3) - 12);
} else {
renewal_months.push(renewal_month + (i * 3));
}
}
var renewal_months = [201512, 201603, 201606, 201609];
// gather months/years
months = [201512, 201603, 201606, 201609];
// loop through each month/years
for (i in months) {
// create new website element for each month
new_cloned_website = jQuery(this).clone();
// assign new month/year
jQuery(new_cloned_website).attr('data-renewal', months[i]);
// lookup renewal
found_renewal = jQuery.inArray(months[i], renewal_months);
current_month = months[i];
if (renewal != current_month) {
jQuery('.websites').append(new_cloned_website);
}
}
});
jQuery(".website").sort(sort_li) // sort elements
.appendTo('.websites'); // append again to the list
// sort function callback
function sort_li(a, b){
return (jQuery(b).data('renewal')) < (jQuery(a).data('renewal')) ? 1 : -1;
}
// print results
for(var key in renewals){
var total_price = 0;
jQuery('.websites .website[data-renewal='+ key +']').each(function() {
price = jQuery(this).data('price');
if (isNaN(price)) {
price = 0;
}
if(typeof price === 'undefined'){
price = 0;
};
if (price) {
total_price = total_price + price;
}
});
var date = new Date(key.substring(0, 4), key.substring(4, 6) - 1, 1, 1, 1, 1, 1),
timestamp = date.getTime();
var parsedDate = jQuery.format.date(timestamp, "MMM yyyy");
jQuery('.websites .website[data-renewal='+ key +']:first').prepend('<div class="heading">'+ parsedDate + ' (' + renewals[key] + ')</div>');
jQuery('.websites .website[data-renewal='+ key +']:last').after('<div class="total" data-total="'+total_price+'">Total: $'+ total_price +'</div>');
}
var yearly_total = 0;
jQuery('.total').each(function() {
yearly_total = yearly_total + jQuery(this).data('total');
});
jQuery('#result').html("$"+yearly_total);
</script>

View file

@ -0,0 +1,208 @@
<style>
.heading {
margin-top: 2em;
font-weight: bold;
font-size: 1.4em;
}
.total {
font-weight: bold;
padding: 10px 0px;
display: block;
}
.websites li {
margin-bottom: 0px;
}
.websites ul {
margin-left: 10px;
}
.websites li p {
line-height: 1em;
}
</style>
<div class="wrap"><div id="icon-tools" class="icon32"></div>
<h2>Partners Install Report</h2>
<?php
// WP_Query arguments
$args = array (
'post_type' => array( 'customer' ),
'posts_per_page' => '-1',
'meta_query' => array(
array(
'key' => 'partner', // name of custom field
'value' => true, // matches exaclty "123", not just 123. This prevents a match for "1234"
'compare' => 'LIKE'
)
)
);
// The Query
$query = new WP_Query( $args );
$posts = $query->get_posts();
// The Loop
if ( $query->have_posts() ) {
echo "<div class='websites'>";
while ( $query->have_posts() ) {
$query->the_post();
$id = get_the_ID();
?>
<div class="partner">
<?php the_title(); ?> - ID# <?php echo get_the_ID(); ?>
<?php
/*
* Query posts for a relationship value.
* This method uses the meta_query LIKE to match the string "123" to the database value a:1:{i:0;s:3:"123";} (serialized array)
*/
$websites = get_posts(array(
'post_type' => 'website',
'posts_per_page' => '-1',
'meta_query' => array(
'relation' => 'AND', // Optional, defaults to "AND"
array(
'key' => 'partner', // name of custom field
'value' => '"' . $id . '"', // matches exaclty "123", not just 123. This prevents a match for "1234"
'compare' => 'LIKE'
),
array(
'key' => 'status', // name of custom field
'value' => 'active', // matches exaclty "123", not just 123. This prevents a match for "1234"
'compare' => 'LIKE'
),
)
));
$customer_count = 0;
?>
<?php if( $websites ): ?>
<?php
// New array to collect customers IDs
$customer_ids = array();
// Loop through websites
echo "<ul class='website-list'><li>";
foreach( $websites as $website ):
$domain = get_the_title( $website->ID );
$customer_id = get_field('customer', $website->ID);
if (get_field('install',$website->ID)) {
the_field('install', $website->ID ); ?> <?php
}
endforeach;
echo "</li></ul>";
echo "[";
$i = 1;
foreach( $websites as $website ):
if (get_field('install',$website->ID)) {
if ($i < count($websites)) {
echo '"'.get_the_title($website->ID).'",';
} else {
echo '"'.get_the_title($website->ID).'"';
}
}
$i++;
endforeach;
echo "]<p></p>";
echo "<pre>";
foreach( $websites as $website ):
if (get_field('install',$website->ID)) {
$install = get_field('install',$website->ID);
$domain = get_the_title($website->ID);
$address = get_field('address',$website->ID);
$username = get_field('username',$website->ID);
$password = get_field('password',$website->ID);
$protocol = get_field('protocol',$website->ID);
$port = get_field('port',$website->ID);
$token = "***REMOVED***";
echo "php Sites/backup.anchor.host/api/new.php install=$install domain=$domain username=$username password=".rawurlencode(base64_encode($password))." address=$address protocol=$protocol port=$port preloadusers=$preloadusers token=$token skip=true
";
}
endforeach;
echo "</pre>";
// End partner loop
endif; ?>
</div>
<?php
}
echo "</div>";
} else {
// no posts found
}
// Restore original Post Data
wp_reset_postdata();
?>
</div>
<div id="result"></div>
<script>
var today = new Date();
// current year
year = today.getFullYear();
// next month
month = ("0" + (today.getMonth() + 1)).slice(-2);
var renewals = {},
renewal;
// loop through and build renewals object to store upcoming months
for (var i = 1; i < 13; i++) {
loop_month = ("0" + (i)).slice(-2);;
next_year = year + 1;
if (parseInt(month) < i) {
renewals[year + loop_month] = 0;
} else {
renewals[next_year + loop_month] = 0;
}
}
// Totals up the renewals
jQuery('.websites .website[data-renewal]').each(function(i, el){
renewal = jQuery(el).data('renewal');
price = jQuery(el).data('price');
if (renewals.hasOwnProperty(renewal)) {
renewals[renewal] += 1;
}
else {
renewals[renewal] = 1;
}
});
/*! jquery-dateFormat 18-05-2015 */
var DateFormat={};!function(a){var b=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],c=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],d=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],e=["January","February","March","April","May","June","July","August","September","October","November","December"],f={Jan:"01",Feb:"02",Mar:"03",Apr:"04",May:"05",Jun:"06",Jul:"07",Aug:"08",Sep:"09",Oct:"10",Nov:"11",Dec:"12"},g=/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.?\d{0,3}[Z\-+]?(\d{2}:?\d{2})?/;a.format=function(){function a(a){return b[parseInt(a,10)]||a}function h(a){return c[parseInt(a,10)]||a}function i(a){var b=parseInt(a,10)-1;return d[b]||a}function j(a){var b=parseInt(a,10)-1;return e[b]||a}function k(a){return f[a]||a}function l(a){var b,c,d,e,f,g=a,h="";return-1!==g.indexOf(".")&&(e=g.split("."),g=e[0],h=e[e.length-1]),f=g.split(":"),3===f.length?(b=f[0],c=f[1],d=f[2].replace(/\s.+/,"").replace(/[a-z]/gi,""),g=g.replace(/\s.+/,"").replace(/[a-z]/gi,""),{time:g,hour:b,minute:c,second:d,millis:h}):{time:"",hour:"",minute:"",second:"",millis:""}}function m(a,b){for(var c=b-String(a).length,d=0;c>d;d++)a="0"+a;return a}return{parseDate:function(a){var b,c,d={date:null,year:null,month:null,dayOfMonth:null,dayOfWeek:null,time:null};if("number"==typeof a)return this.parseDate(new Date(a));if("function"==typeof a.getFullYear)d.year=String(a.getFullYear()),d.month=String(a.getMonth()+1),d.dayOfMonth=String(a.getDate()),d.time=l(a.toTimeString()+"."+a.getMilliseconds());else if(-1!=a.search(g))b=a.split(/[T\+-]/),d.year=b[0],d.month=b[1],d.dayOfMonth=b[2],d.time=l(b[3].split(".")[0]);else switch(b=a.split(" "),6===b.length&&isNaN(b[5])&&(b[b.length]="()"),b.length){case 6:d.year=b[5],d.month=k(b[1]),d.dayOfMonth=b[2],d.time=l(b[3]);break;case 2:c=b[0].split("-"),d.year=c[0],d.month=c[1],d.dayOfMonth=c[2],d.time=l(b[1]);break;case 7:case 9:case 10:d.year=b[3],d.month=k(b[1]),d.dayOfMonth=b[2],d.time=l(b[4]);break;case 1:c=b[0].split(""),d.year=c[0]+c[1]+c[2]+c[3],d.month=c[5]+c[6],d.dayOfMonth=c[8]+c[9],d.time=l(c[13]+c[14]+c[15]+c[16]+c[17]+c[18]+c[19]+c[20]);break;default:return null}return d.date=d.time?new Date(d.year,d.month-1,d.dayOfMonth,d.time.hour,d.time.minute,d.time.second,d.time.millis):new Date(d.year,d.month-1,d.dayOfMonth),d.dayOfWeek=String(d.date.getDay()),d},date:function(b,c){try{var d=this.parseDate(b);if(null===d)return b;for(var e,f=d.year,g=d.month,k=d.dayOfMonth,l=d.dayOfWeek,n=d.time,o="",p="",q="",r=!1,s=0;s<c.length;s++){var t=c.charAt(s),u=c.charAt(s+1);if(r)"'"==t?(p+=""===o?"'":o,o="",r=!1):o+=t;else switch(o+=t,q="",o){case"ddd":p+=a(l),o="";break;case"dd":if("d"===u)break;p+=m(k,2),o="";break;case"d":if("d"===u)break;p+=parseInt(k,10),o="";break;case"D":k=1==k||21==k||31==k?parseInt(k,10)+"st":2==k||22==k?parseInt(k,10)+"nd":3==k||23==k?parseInt(k,10)+"rd":parseInt(k,10)+"th",p+=k,o="";break;case"MMMM":p+=j(g),o="";break;case"MMM":if("M"===u)break;p+=i(g),o="";break;case"MM":if("M"===u)break;p+=m(g,2),o="";break;case"M":if("M"===u)break;p+=parseInt(g,10),o="";break;case"y":case"yyy":if("y"===u)break;p+=o,o="";break;case"yy":if("y"===u)break;p+=String(f).slice(-2),o="";break;case"yyyy":p+=f,o="";break;case"HH":p+=m(n.hour,2),o="";break;case"H":if("H"===u)break;p+=parseInt(n.hour,10),o="";break;case"hh":e=0===parseInt(n.hour,10)?12:n.hour<13?n.hour:n.hour-12,p+=m(e,2),o="";break;case"h":if("h"===u)break;e=0===parseInt(n.hour,10)?12:n.hour<13?n.hour:n.hour-12,p+=parseInt(e,10),o="";break;case"mm":p+=m(n.minute,2),o="";break;case"m":if("m"===u)break;p+=n.minute,o="";break;case"ss":p+=m(n.second.substring(0,2),2),o="";break;case"s":if("s"===u)break;p+=n.second,o="";break;case"S":case"SS":if("S"===u)break;p+=o,o="";break;case"SSS":var v="000"+n.millis.substring(0,3);p+=v.substring(v.length-3),o="";break;case"a":p+=n.hour>=12?"PM":"AM",o="";break;case"p":p+=n.hour>=12?"p.m.":"a.m.",o="";break;case"E":p+=h(l),o="";break;case"'":o="",r=!0;break;default:p+=t,o=""}}return p+=q}catch(w){return console&&console.log&&console.log(w),b}},prettyDate:function(a){var b,c,d;return("string"==typeof a||"number"==typeof a)&&(b=new Date(a)),"object"==typeof a&&(b=new Date(a.toString())),c=((new Date).getTime()-b.getTime())/1e3,d=Math.floor(c/86400),isNaN(d)||0>d?void 0:60>c?"just now":120>c?"1 minute ago":3600>c?Math.floor(c/60)+" minutes ago":7200>c?"1 hour ago":86400>c?Math.floor(c/3600)+" hours ago":1===d?"Yesterday":7>d?d+" days ago":31>d?Math.ceil(d/7)+" weeks ago":d>=31?"more than 5 weeks ago":void 0},toBrowserTimeZone:function(a,b){return this.date(new Date(a),b||"MM/dd/yyyy HH:mm:ss")}}}()}(DateFormat),function(a){a.format=DateFormat.format}(jQuery);
jQuery(".website").sort(sort_li) // sort elements
.appendTo('.websites'); // append again to the list
// sort function callback
function sort_li(a, b){
return (jQuery(b).data('renewal')) < (jQuery(a).data('renewal')) ? 1 : -1;
}
</script>

660
inc/admin-kpi-report.php Normal file
View file

@ -0,0 +1,660 @@
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<link rel='stylesheet' id='font-awesome-css' href='https://anchor.host/wp-content/themes/swell-anchorhost/css/font-awesome.min.css' type='text/css' media='all' />
<style>
.heading {
margin-right: 1em;
}
.process-star {
display:inline-block;
position: relative;
}
.process-star .info p {
line-height: 1em;
padding: 8px 0px;
}
.process-star .desc {
line-height: 1em;
padding: 8px 0px;
}
.process-star hr {
margin: 10px 0px;
padding: 0px;
opacity: 0.5;
}
.process-star a {
-webkit-transition: 0.0s ease;
-moz-transition: 0.0s ease;
-o-transition: 0.0s ease;
transition: 0.0s ease;
}
.total {
font-weight: bold;
padding: 10px 0px;
display: block;
}
.websites li {
margin-bottom: 0px;
}
.websites ul {
margin-left: 10px;
}
.websites li p {
line-height: 1em;
}
.process-icons i {
margin-left: 20px;
}
.process-icons i:first-child {
margin-left: 0px;
}
.process-stars {
position: relative;
padding-right: 122px;
border-bottom: 1px solid #ccc;
margin: 1em 0;
padding-bottom: 1em;
line-height: 1em;
}
.process-stars:last-child {
border-bottom: 0px;
}
.process-stars .heading {
text-align: left;
margin-bottom: .5em;
}
.process-stars .heading span {
font-size: .6em;
background-color: rgba(39, 195, 243, 0.79);
border-radius: 4px;
color: #fff;
position: relative;
top: -3px;
margin: 0 0 0 5px;
display: inline-block;
text-align: center;
padding: 3px 3px;
line-height: 1em;
}
.process-stars .heading span.site-count {
color: #888;
background: none;
}
.process-role-manager {
display: inline;
font-size: 13px;
}
.process-description {
font-size: 0.8em;
line-height: 1.2em;
margin-bottom: 1em;
}
.process-log-update {
max-width: 980px;
margin: auto;
position: absolute;
z-index: 10;
left: 0;
right: 0;
background-color: #fff;
padding: 1em 1em 0 1em;
margin-top: 1em;
border-radius: 4px;
border: 1px solid rgba(74, 74, 74, 0.8);
border-style: solid;
}
.process-log-update .acf-relationship .filters {
background: #f7f7f7;
}
.process-log-update .acf-relationship .filters .filter {
line-height: auto;
height: auto;
padding: 5px;
}
.process-log-update .acf-relationship .list .acf-rel-label,
.process-log-update .acf-relationship .list .acf-rel-item,
.process-log-update .acf-relationship .list p {
padding: 0px 7px;
margin: 0;
display: block;
position: relative;
min-height: 12px;
font-size: 0.85em;
line-height: 1.8em;
}
.process-log-update .acf-field textarea {
height: 64px;
}
.process-log-update .acf-field.acf-field-select.acf-field-588bb7bd3cab6 label {
display: none;
}
.activity-log i span {
display: block;
visibility: hidden;
opacity: 0;
transition: visibility 0s, opacity 0.5s ease-in-out;
position: absolute;
background: #000;
border-radius: 10px;
color: #fff;
padding: 8.5px 12px;
font-size: 13px;
left: -10px;
top: 23px;
width: 230px;
z-index: 1;
font-family: "proxima-nova-soft",sans-serif;
font-style: normal;
font-weight: 400;
}
#plans i span:before,
.block i span:before {
content: " ";
width: 0;
height: 0;
border-top: 11px solid transparent;
border-bottom: 11px solid transparent;
border-right: 11px solid #000;
top: 4px;
left: -9px;
position: absolute;
}
.activity-log i span:before {
content: " ";
width: 0;
height: 0;
border-left: 11px solid transparent;
border-bottom: 11px solid #000;
border-right: 11px solid transparent;
top: -10px;
left: 6px;
position: absolute;
}
#plans i:hover span,
.block i:hover span,
.activity-log i:hover span {
visibility: visible;
opacity: 1;
display: block;
-webkit-transition: all 0.2s ease-in-out;
-moz-transition: all 0.2s ease-in-out;
-ms-transition: all 0.2s ease-in-out;
-o-transition: all 0.2s ease-in-out;
transition: all 0.2s ease-in-out;
}
.activity-log .process-stars {
float: left;
}
.results > div {
float: left;
margin-right: 10px;
display: none;
}
.results > div:nth-last-child(-n+5) {
display: block;
}
.results .activity-log-kpi-1:after {
content: " New Customers";
}
.results .activity-log-kpi-2:after {
content: " Support Requests";
}
.results .activity-log-kpi-3:after {
content: " Product Development";
}
.results .heading {
margin-top: 1em;
margin-bottom: .2em;
font-size: 1.2em;
font-weight: bold;
}
</style>
<script>
/*! jquery-dateFormat 18-05-2015 */
var DateFormat={};!function(a){var b=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],c=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],d=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],e=["January","February","March","April","May","June","July","August","September","October","November","December"],f={Jan:"01",Feb:"02",Mar:"03",Apr:"04",May:"05",Jun:"06",Jul:"07",Aug:"08",Sep:"09",Oct:"10",Nov:"11",Dec:"12"},g=/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.?\d{0,3}[Z\-+]?(\d{2}:?\d{2})?/;a.format=function(){function a(a){return b[parseInt(a,10)]||a}function h(a){return c[parseInt(a,10)]||a}function i(a){var b=parseInt(a,10)-1;return d[b]||a}function j(a){var b=parseInt(a,10)-1;return e[b]||a}function k(a){return f[a]||a}function l(a){var b,c,d,e,f,g=a,h="";return-1!==g.indexOf(".")&&(e=g.split("."),g=e[0],h=e[e.length-1]),f=g.split(":"),3===f.length?(b=f[0],c=f[1],d=f[2].replace(/\s.+/,"").replace(/[a-z]/gi,""),g=g.replace(/\s.+/,"").replace(/[a-z]/gi,""),{time:g,hour:b,minute:c,second:d,millis:h}):{time:"",hour:"",minute:"",second:"",millis:""}}function m(a,b){for(var c=b-String(a).length,d=0;c>d;d++)a="0"+a;return a}return{parseDate:function(a){var b,c,d={date:null,year:null,month:null,dayOfMonth:null,dayOfWeek:null,time:null};if("number"==typeof a)return this.parseDate(new Date(a));if("function"==typeof a.getFullYear)d.year=String(a.getFullYear()),d.month=String(a.getMonth()+1),d.dayOfMonth=String(a.getDate()),d.time=l(a.toTimeString()+"."+a.getMilliseconds());else if(-1!=a.search(g))b=a.split(/[T\+-]/),d.year=b[0],d.month=b[1],d.dayOfMonth=b[2],d.time=l(b[3].split(".")[0]);else switch(b=a.split(" "),6===b.length&&isNaN(b[5])&&(b[b.length]="()"),b.length){case 6:d.year=b[5],d.month=k(b[1]),d.dayOfMonth=b[2],d.time=l(b[3]);break;case 2:c=b[0].split("-"),d.year=c[0],d.month=c[1],d.dayOfMonth=c[2],d.time=l(b[1]);break;case 7:case 9:case 10:d.year=b[3],d.month=k(b[1]),d.dayOfMonth=b[2],d.time=l(b[4]);break;case 1:c=b[0].split(""),d.year=c[0]+c[1]+c[2]+c[3],d.month=c[5]+c[6],d.dayOfMonth=c[8]+c[9],d.time=l(c[13]+c[14]+c[15]+c[16]+c[17]+c[18]+c[19]+c[20]);break;default:return null}return d.date=d.time?new Date(d.year,d.month-1,d.dayOfMonth,d.time.hour,d.time.minute,d.time.second,d.time.millis):new Date(d.year,d.month-1,d.dayOfMonth),d.dayOfWeek=String(d.date.getDay()),d},date:function(b,c){try{var d=this.parseDate(b);if(null===d)return b;for(var e,f=d.year,g=d.month,k=d.dayOfMonth,l=d.dayOfWeek,n=d.time,o="",p="",q="",r=!1,s=0;s<c.length;s++){var t=c.charAt(s),u=c.charAt(s+1);if(r)"'"==t?(p+=""===o?"'":o,o="",r=!1):o+=t;else switch(o+=t,q="",o){case"ddd":p+=a(l),o="";break;case"dd":if("d"===u)break;p+=m(k,2),o="";break;case"d":if("d"===u)break;p+=parseInt(k,10),o="";break;case"D":k=1==k||21==k||31==k?parseInt(k,10)+"st":2==k||22==k?parseInt(k,10)+"nd":3==k||23==k?parseInt(k,10)+"rd":parseInt(k,10)+"th",p+=k,o="";break;case"MMMM":p+=j(g),o="";break;case"MMM":if("M"===u)break;p+=i(g),o="";break;case"MM":if("M"===u)break;p+=m(g,2),o="";break;case"M":if("M"===u)break;p+=parseInt(g,10),o="";break;case"y":case"yyy":if("y"===u)break;p+=o,o="";break;case"yy":if("y"===u)break;p+=String(f).slice(-2),o="";break;case"yyyy":p+=f,o="";break;case"HH":p+=m(n.hour,2),o="";break;case"H":if("H"===u)break;p+=parseInt(n.hour,10),o="";break;case"hh":e=0===parseInt(n.hour,10)?12:n.hour<13?n.hour:n.hour-12,p+=m(e,2),o="";break;case"h":if("h"===u)break;e=0===parseInt(n.hour,10)?12:n.hour<13?n.hour:n.hour-12,p+=parseInt(e,10),o="";break;case"mm":p+=m(n.minute,2),o="";break;case"m":if("m"===u)break;p+=n.minute,o="";break;case"ss":p+=m(n.second.substring(0,2),2),o="";break;case"s":if("s"===u)break;p+=n.second,o="";break;case"S":case"SS":if("S"===u)break;p+=o,o="";break;case"SSS":var v="000"+n.millis.substring(0,3);p+=v.substring(v.length-3),o="";break;case"a":p+=n.hour>=12?"PM":"AM",o="";break;case"p":p+=n.hour>=12?"p.m.":"a.m.",o="";break;case"E":p+=h(l),o="";break;case"'":o="",r=!0;break;default:p+=t,o=""}}return p+=q}catch(w){return console&&console.log&&console.log(w),b}},prettyDate:function(a){var b,c,d;return("string"==typeof a||"number"==typeof a)&&(b=new Date(a)),"object"==typeof a&&(b=new Date(a.toString())),c=((new Date).getTime()-b.getTime())/1e3,d=Math.floor(c/86400),isNaN(d)||0>d?void 0:60>c?"just now":120>c?"1 minute ago":3600>c?Math.floor(c/60)+" minutes ago":7200>c?"1 hour ago":86400>c?Math.floor(c/3600)+" hours ago":1===d?"Yesterday":7>d?d+" days ago":31>d?Math.ceil(d/7)+" weeks ago":d>=31?"more than 5 weeks ago":void 0},toBrowserTimeZone:function(a,b){return this.date(new Date(a),b||"MM/dd/yyyy HH:mm:ss")}}}()}(DateFormat),function(a){a.format=DateFormat.format}(jQuery);
var months_1 = {};
var months_2 = {};
var months_3 = {};
// Adds pad function for adding zero's to single digital months. Example 3 becomes 03.
Number.prototype.pad = function(size) {
var s = String(this);
while (s.length < (size || 2)) {s = "0" + s;}
return s;
}
jQuery( document ).ready( function () {
jQuery('.activity-log-kpi-1 .process-star').each(function() {
udate = jQuery(this).data("log-date");
month = new Date(udate * 1000).getUTCMonth() + 1;
year = new Date(udate * 1000).getUTCFullYear();
yearmonth = [year] + [month.pad("2")];
jQuery(this).attr('data-yearmonth', yearmonth);
if (months_1.hasOwnProperty(yearmonth)) {
months_1[yearmonth] += 1;
}
else {
months_1[yearmonth] = 1;
}
});
// print results
for(var key in months_1){
var date = new Date(key.substring(0, 4), key.substring(4, 6) - 1, 1, 1, 1, 1, 1),
timestamp = date.getTime();
var parsedDate = jQuery.format.date(timestamp, "MMM yyyy");
jQuery('.activity-log-kpi-1 .process-star[data-yearmonth='+ key +']:first').before('<div id="result-'+key+'" class="process-stars">');
items = jQuery('.activity-log-kpi-1 .process-star[data-yearmonth='+ key +']').detach();
items.appendTo( ".activity-log-kpi-1 #result-"+key );
jQuery(".activity-log-kpi-1 #result-"+key).prepend('<div class="heading">'+ parsedDate + ' <span>' + months_1[key] + '</span></div>');
if ( jQuery(".results #result-"+key+" .activity-log-kpi-1").length == 0 ) {
jQuery('.results').append("<div id='result-"+key+"'><div class='activity-log-kpi-1'>");
jQuery(".results #result-"+key+" .activity-log-kpi-1").html( months_1[key] );
}
if ( jQuery(".results #result-"+key+" .heading").length == 0 ) {
jQuery(".results #result-"+key).prepend('<div class="heading">'+ parsedDate + '</div>');
}
}
jQuery('.activity-log-kpi-2 .process-star').each(function() {
udate = jQuery(this).data("log-date");
month = new Date(udate * 1000).getUTCMonth() + 1;
year = new Date(udate * 1000).getUTCFullYear();
yearmonth = [year] + [month.pad("2")];
jQuery(this).attr('data-yearmonth', yearmonth);
if (months_2.hasOwnProperty(yearmonth)) {
months_2[yearmonth] += 1;
}
else {
months_2[yearmonth] = 1;
}
});
// print results
for(var key in months_2){
var date = new Date(key.substring(0, 4), key.substring(4, 6) - 1, 1, 1, 1, 1, 1),
timestamp = date.getTime();
var parsedDate = jQuery.format.date(timestamp, "MMM yyyy");
jQuery('.activity-log-kpi-2 .process-star[data-yearmonth='+ key +']:first').before('<div id="result-'+key+'" class="process-stars">');
items = jQuery('.activity-log-kpi-2 .process-star[data-yearmonth='+ key +']').detach();
items.appendTo( ".activity-log-kpi-2 #result-"+key );
jQuery(".activity-log-kpi-2 #result-"+key).prepend('<div class="heading">'+ parsedDate + ' <span>' + months_2[key] + '</span></div>');
if ( jQuery(".results #result-"+key).length == 0 ) {
jQuery('.results').append("<div id='result-"+key+"'><div class='activity-log-kpi-2'>");
jQuery(".results #result-"+key+" .activity-log-kpi-2").html( months_2[key] );
} else if ( jQuery(".results #result-"+key+" .activity-log-kpi-2").length == 0 ) {
jQuery('.results #result-'+key).append("<div class='activity-log-kpi-2'>");
jQuery(".results #result-"+key+" .activity-log-kpi-2").html( months_2[key] );
}
if ( jQuery(".results #result-"+key+" .heading").length == 0 ) {
jQuery(".results #result-"+key).prepend('<div class="heading">'+ parsedDate + '</div>');
}
}
jQuery('.activity-log-kpi-3 .process-star').each(function() {
udate = jQuery(this).data("log-date");
month = new Date(udate * 1000).getUTCMonth() + 1;
year = new Date(udate * 1000).getUTCFullYear();
yearmonth = [year] + [month.pad("2")];
jQuery(this).attr('data-yearmonth', yearmonth);
if (months_3.hasOwnProperty(yearmonth)) {
months_3[yearmonth] += 1;
}
else {
months_3[yearmonth] = 1;
}
});
// print results
for(var key in months_3){
var date = new Date(key.substring(0, 4), key.substring(4, 6) - 1, 1, 1, 1, 1, 1),
timestamp = date.getTime();
var parsedDate = jQuery.format.date(timestamp, "MMM yyyy");
jQuery('.activity-log-kpi-3 .process-star[data-yearmonth='+ key +']:first').before('<div id="result-'+key+'" class="process-stars">');
items = jQuery('.activity-log-kpi-3 .process-star[data-yearmonth='+ key +']').detach();
items.appendTo( ".activity-log-kpi-3 #result-"+key );
jQuery(".activity-log-kpi-3 #result-"+key).prepend('<div class="heading">'+ parsedDate + ' <span>' + months_3[key] + '</span></div>');
if ( jQuery(".results #result-"+key).length == 0 ) {
jQuery('.results').append("<div id='result-"+key+"'><div class='activity-log-kpi-3'>");
jQuery(".results #result-"+key+" .activity-log-kpi-3").html( months_3[key] );
} else if ( jQuery(".results #result-"+key+" .activity-log-kpi-3").length == 0 ) {
jQuery('.results #result-'+key).append("<div class='activity-log-kpi-3'>");
jQuery(".results #result-"+key+" .activity-log-kpi-3").html( months_3[key] );
}
if ( jQuery(".results #result-"+key+" .heading").length == 0 ) {
jQuery(".results #result-"+key).prepend('<div class="heading">'+ parsedDate + '</div>');
}
}
// calculate and print site count
jQuery('.activity-log-kpi-1 .process-stars').each(function() {
site_count = jQuery(this).find('.process-star span.info a.website').length;
heading = jQuery(this).find('.heading');
if (site_count > 0) {
jQuery( '<span class="site-count">' + site_count + ' sites</span>' ).appendTo( heading );
}
});
// calculate and print site count
jQuery('.activity-log-kpi-2 .process-stars').each(function() {
site_count = jQuery(this).find('.process-star span.info a.website').length;
heading = jQuery(this).find('.heading');
if (site_count > 0) {
jQuery( '<span class="site-count">' + site_count + ' sites</span>' ).appendTo( heading );
}
});
// calculate and print site count
jQuery('.activity-log-kpi-3 .process-stars').each(function() {
site_count = jQuery(this).find('.process-star span.info a.website').length;
heading = jQuery(this).find('.heading');
if (site_count > 0) {
jQuery( '<span class="site-count">' + site_count + ' sites</span>' ).appendTo( heading );
}
});
// Sort results in order by date
$results = jQuery('.results > div');
$results.sort(function(a, b) {
var nameA = jQuery(a).attr("id");
var nameB = jQuery(b).attr("id");
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
// names must be equal
return 0;
});
jQuery('.results > div').remove(); // Remove current results
jQuery('.results').append($results); // Adds sorted results
google.charts.load('current', {'packages':['bar']});
google.charts.setOnLoadCallback(drawChart);
});
// Draws chart using Google Chart library: https://developers.google.com/chart/interactive/docs/gallery/barchart
function drawChart() {
// Create data array for chart to use
result_data = [['Year', 'New Customers', 'Support Requests', 'Product Development']];
jQuery('.results > div').each(function() {
title = jQuery(this).find(".heading").text();
kpi_1 = jQuery(this).find(".activity-log-kpi-1").text();
kpi_2 = jQuery(this).find(".activity-log-kpi-2").text();
kpi_3 = jQuery(this).find(".activity-log-kpi-3").text();
result_data.push([title,parseInt(kpi_1),parseInt(kpi_2),parseInt(kpi_3)]);
});
var data = google.visualization.arrayToDataTable(result_data);
var options = {
chart: {
title: '',
subtitle: '',
},
width: 1200,
height: 400,
legend: { position: 'none' },
};
var chart = new google.charts.Bar(document.getElementById('columnchart_material'));
chart.draw(data, google.charts.Bar.convertOptions(options));
}
</script>
<div class="wrap"><div id="icon-tools" class="icon32"></div>
<h2>KPI Report</h2>
<div id="columnchart_material" style="width: 1200px; height: 400px;"></div>
<div class="activity-log">
<?php
$today = date('Ymd');
// WP_Query arguments
$process_id = get_field('kpi_new_customers', 'option');
if ($process_id) { $process_id = $process_id[0]; }
$process_logs = get_posts(array(
'post_type' => 'process_log',
'posts_per_page' => '-1',
'meta_query' => array(
array(
'key' => 'process', // name of custom field
'value' => '"' . $process_id . '"', // matches exaclty "123", not just 123. This prevents a match for "1234"
'compare' => 'LIKE'
)
)
)); ?>
<h4>KPI New Customers <small>(Process - <?php echo get_the_title($process_id); ?>)</small></h4>
<?php
if( $process_logs ): ?>
<div class="activity-log-kpi-1">
<?php foreach( $process_logs as $process_log ):
$desc = get_field('description', $process_log->ID); ?>
<div class="process-star" data-log-date="<?php echo get_the_date( "U", $process_log->ID ); ?>">
<i class="fa fa-star" aria-hidden="true">
<span class="info">
<a href="<?php echo get_edit_post_link( $process_log->ID ); ?>" class="alignright"><i class="fa fa-pencil-square-o" aria-hidden="true"></i></a>
<?php echo get_the_author_meta("first_name", $process_log->post_author); ?> completed <br />
<?php if ($desc) { ?>
<div class="desc">
<?php echo WPCom_Markdown::get_instance()->transform( $desc, array('id'=>false,'unslash'=>false)); ?>
</div>
<?php } ?>
<?php if (get_field('website', $process_log->ID)) {
$website = get_field('website', $process_log->ID);
foreach( $website as $p ): // variable must NOT be called $post (IMPORTANT) ?>
<i class="fa fa-link" aria-hidden="true"></i> <a href="<?php echo get_edit_post_link( $p ); ?>" class="website"><?php echo get_the_title( $p ); ?></a><br />
<?php endforeach;
} ?>
<hr />
<i class="fa fa-calendar" aria-hidden="true"></i>
<?php echo get_the_date( "M j | g:ia", $process_log->ID ); ?>
</span></i>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<?php
$process_role_support_requests_id = get_field('kpi_support_requests', 'option');
$process_role_support_requests = get_term($process_role_support_requests_id);
$process_ids = get_posts( array (
'post_type' => array( 'process' ),
'posts_per_page' => '-1',
'taxonomy' => 'process_role',
'term' => $process_role_support_requests->slug,
'order' => 'ASC',
'orderby' => 'title',
'fields' => 'ids', // Only get post IDs
));
foreach ($process_ids as $process_id) {
$processRelations[] = array(
'key' => 'process',
'value' => '"'. $process_id. '"',
'compare' => 'LIKE'
);
}
// The Query
$process_logs_support_requests = get_posts(array(
'post_type' => 'process_log',
'posts_per_page' => '-1',
'meta_query' => array(
array_merge(array('relation' => 'OR'), $processRelations)
)
));
?>
<div class="clear"></div>
<h4>KPI Support Requests <small>(Role - <?php echo $process_role_support_requests->name; ?>)</small></h4>
<div class="activity-log-kpi-2">
<?php
if( $process_logs_support_requests ): ?>
<?php foreach( $process_logs_support_requests as $process_log_support_requests ):
$desc = get_field('description', $process_log_support_requests->ID); ?>
<div class="process-star" data-log-date="<?php echo get_the_date( "U", $process_log_support_requests->ID ); ?>">
<i class="fa fa-star" aria-hidden="true">
<span class="info">
<a href="<?php echo get_edit_post_link( $process_log_support_requests->ID ); ?>" class="alignright"><i class="fa fa-pencil-square-o" aria-hidden="true"></i></a>
<?php echo get_the_author_meta("first_name", $process_log_support_requests->post_author); ?> completed <br />
<?php if ($desc) { ?>
<div class="desc">
<?php echo WPCom_Markdown::get_instance()->transform( $desc, array('id'=>false,'unslash'=>false)); ?>
</div>
<?php } ?>
<?php if (get_field('website', $process_log_support_requests->ID)) {
$website = get_field('website', $process_log_support_requests->ID);
foreach( $website as $p ): // variable must NOT be called $post (IMPORTANT) ?>
<i class="fa fa-link" aria-hidden="true"></i> <a href="<?php echo get_edit_post_link( $p ); ?>" class="website"><?php echo get_the_title( $p ); ?></a><br />
<?php endforeach;
} ?>
<hr />
<i class="fa fa-calendar" aria-hidden="true"></i>
<?php echo get_the_date( "M j | g:ia", $process_log_support_requests->ID ); ?>
</span></i>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<?php
$process_role_product_development_id = get_field('kpi_product_development', 'option');
$process_role_product_development = get_term($process_role_product_development_id);
$process_ids = get_posts( array (
'post_type' => array( 'process' ),
'posts_per_page' => '-1',
'taxonomy' => 'process_role',
'term' => $process_role_product_development->slug,
'order' => 'ASC',
'orderby' => 'title',
'fields' => 'ids', // Only get post IDs
));
$processRelations = [];
foreach ($process_ids as $process_id) {
$processRelations[] = array(
'key' => 'process',
'value' => '"'. $process_id. '"',
'compare' => 'LIKE'
);
}
// The Query
$process_logs_product_development = get_posts(array(
'post_type' => 'process_log',
'posts_per_page' => '-1',
'meta_query' => array(
array_merge(array('relation' => 'OR'), $processRelations)
)
));
?>
<div class="clear"></div>
<h4>KPI Product Development <small>(Role - <?php echo $process_role_product_development->name; ?>)</small></h4>
<div class="activity-log-kpi-3">
<?php
if( $process_logs_product_development ): ?>
<?php foreach( $process_logs_product_development as $process_log_product_development ):
$desc = get_field('description', $process_log_product_development->ID); ?>
<div class="process-star" data-log-date="<?php echo get_the_date( "U", $process_log_product_development->ID ); ?>">
<i class="fa fa-star" aria-hidden="true">
<span class="info">
<a href="<?php echo get_edit_post_link( $process_log_product_development->ID ); ?>" class="alignright"><i class="fa fa-pencil-square-o" aria-hidden="true"></i></a>
<?php echo get_the_author_meta("first_name", $process_log_product_development->post_author); ?> completed <br />
<?php if ($desc) { ?>
<div class="desc">
<?php echo WPCom_Markdown::get_instance()->transform( $desc, array('id'=>false,'unslash'=>false)); ?>
</div>
<?php } ?>
<?php if (get_field('website', $process_log_product_development->ID)) {
$website = get_field('website', $process_log_product_development->ID);
foreach( $website as $p ): // variable must NOT be called $post (IMPORTANT) ?>
<i class="fa fa-link" aria-hidden="true"></i> <a href="<?php echo get_edit_post_link( $p ); ?>" class="website"><?php echo get_the_title( $p ); ?></a><br />
<?php endforeach;
} ?>
<hr />
<i class="fa fa-calendar" aria-hidden="true"></i>
<?php echo get_the_date( "M j | g:ia", $process_log_product_development->ID ); ?>
</span></i>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<?php
// Restore original Post Data
wp_reset_postdata();
?>
</div>
</div>
<div class="results clear">
<h3>Totals</h3>
</div>

View file

@ -0,0 +1,230 @@
<style>
.heading {
margin-top: 2em;
font-weight: bold;
font-size: 1.4em;
}
.total {
font-weight: bold;
padding: 10px 0px;
display: block;
}
.websites li {
margin-bottom: 0px;
}
.websites ul {
margin-left: 10px;
}
.websites li p {
line-height: 1em;
}
</style>
<div class="wrap"><div id="icon-tools" class="icon32"></div>
<h2>Partners Report</h2>
<?php
// WP_Query arguments
$args = array (
'post_type' => array( 'customer' ),
'posts_per_page' => '-1',
'meta_query' => array(
array(
'key' => 'partner', // name of custom field
'value' => true, // matches exaclty "123", not just 123. This prevents a match for "1234"
'compare' => 'LIKE'
)
)
);
// The Query
$query = new WP_Query( $args );
$posts = $query->get_posts();
// The Loop
if ( $query->have_posts() ) {
echo "<div class='websites'>";
while ( $query->have_posts() ) {
$query->the_post();
$id = get_the_ID();
?>
<div class="partner">
<?php the_title(); ?> - ID# <?php echo get_the_ID(); ?>
<?php
/*
* Query posts for a relationship value.
* This method uses the meta_query LIKE to match the string "123" to the database value a:1:{i:0;s:3:"123";} (serialized array)
*/
$websites = get_posts(array(
'post_type' => 'website',
'posts_per_page' => '-1',
'meta_query' => array(
array(
'key' => 'partner', // name of custom field
'value' => '"' . $id . '"', // matches exaclty "123", not just 123. This prevents a match for "1234"
'compare' => 'LIKE'
)
)
));
$customer_count = 0;
?>
<?php if( $websites ): ?>
<?php
// New array to collect customers IDs
$customer_ids = array();
// Loop through websites
echo "<ul class='website-list'>";
foreach( $websites as $website ):
$domain = get_the_title( $website->ID );
$customer_id = get_field('customer', $website->ID);
?>
<li>
<?php edit_post_link(get_the_title($website->ID), '', '', $website->ID ); ?>
</li>
<?php
// add customer if not already added
if (!in_array($customer_id, $customer_ids)) {
//$customer_ids[] = $customer_id[0];
array_push( $customer_ids, $customer_id[0]);
}
endforeach;
echo "</ul>";
if( $customer_ids ): ?>
<ul class="customer-list" style="display:none;">
<?php
// WP_Query arguments
$args = array (
'post__in' => $customer_ids,
'post_type' => 'customer'
);
// The Query
$customer_query = new WP_Query( $args );
// The Loop
if ( $customer_query->have_posts() ) {
while ( $customer_query->have_posts() ) {
$customer_query->the_post(); ?>
<li data-price="<?php the_field('hosting_price'); ?>" data-terms="<?php the_field('billing_terms'); ?>">
<a href="<?php echo get_permalink(); ?>"><?php the_title(); ?></a>
</li>
<?php
}
} else {
// no posts found
}
// Restore original Post Data
//wp_reset_postdata();
?>
</ul>
<?php endif; ?>
<?php
// End partner loop
endif; ?>
</div>
<?php
}
echo "</div>";
} else {
// no posts found
}
// Restore original Post Data
wp_reset_postdata();
?>
</div>
<div id="result"></div>
<script>
var today = new Date();
// current year
year = today.getFullYear();
// next month
month = ("0" + (today.getMonth() + 1)).slice(-2);
var renewals = {},
renewal;
// loop through and build renewals object to store upcoming months
for (var i = 1; i < 13; i++) {
loop_month = ("0" + (i)).slice(-2);;
next_year = year + 1;
if (parseInt(month) < i) {
renewals[year + loop_month] = 0;
} else {
renewals[next_year + loop_month] = 0;
}
}
// Totals up the renewals
jQuery('.websites .website[data-renewal]').each(function(i, el){
renewal = jQuery(el).data('renewal');
price = jQuery(el).data('price');
if (renewals.hasOwnProperty(renewal)) {
renewals[renewal] += 1;
}
else {
renewals[renewal] = 1;
}
});
/*! jquery-dateFormat 18-05-2015 */
var DateFormat={};!function(a){var b=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],c=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],d=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],e=["January","February","March","April","May","June","July","August","September","October","November","December"],f={Jan:"01",Feb:"02",Mar:"03",Apr:"04",May:"05",Jun:"06",Jul:"07",Aug:"08",Sep:"09",Oct:"10",Nov:"11",Dec:"12"},g=/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.?\d{0,3}[Z\-+]?(\d{2}:?\d{2})?/;a.format=function(){function a(a){return b[parseInt(a,10)]||a}function h(a){return c[parseInt(a,10)]||a}function i(a){var b=parseInt(a,10)-1;return d[b]||a}function j(a){var b=parseInt(a,10)-1;return e[b]||a}function k(a){return f[a]||a}function l(a){var b,c,d,e,f,g=a,h="";return-1!==g.indexOf(".")&&(e=g.split("."),g=e[0],h=e[e.length-1]),f=g.split(":"),3===f.length?(b=f[0],c=f[1],d=f[2].replace(/\s.+/,"").replace(/[a-z]/gi,""),g=g.replace(/\s.+/,"").replace(/[a-z]/gi,""),{time:g,hour:b,minute:c,second:d,millis:h}):{time:"",hour:"",minute:"",second:"",millis:""}}function m(a,b){for(var c=b-String(a).length,d=0;c>d;d++)a="0"+a;return a}return{parseDate:function(a){var b,c,d={date:null,year:null,month:null,dayOfMonth:null,dayOfWeek:null,time:null};if("number"==typeof a)return this.parseDate(new Date(a));if("function"==typeof a.getFullYear)d.year=String(a.getFullYear()),d.month=String(a.getMonth()+1),d.dayOfMonth=String(a.getDate()),d.time=l(a.toTimeString()+"."+a.getMilliseconds());else if(-1!=a.search(g))b=a.split(/[T\+-]/),d.year=b[0],d.month=b[1],d.dayOfMonth=b[2],d.time=l(b[3].split(".")[0]);else switch(b=a.split(" "),6===b.length&&isNaN(b[5])&&(b[b.length]="()"),b.length){case 6:d.year=b[5],d.month=k(b[1]),d.dayOfMonth=b[2],d.time=l(b[3]);break;case 2:c=b[0].split("-"),d.year=c[0],d.month=c[1],d.dayOfMonth=c[2],d.time=l(b[1]);break;case 7:case 9:case 10:d.year=b[3],d.month=k(b[1]),d.dayOfMonth=b[2],d.time=l(b[4]);break;case 1:c=b[0].split(""),d.year=c[0]+c[1]+c[2]+c[3],d.month=c[5]+c[6],d.dayOfMonth=c[8]+c[9],d.time=l(c[13]+c[14]+c[15]+c[16]+c[17]+c[18]+c[19]+c[20]);break;default:return null}return d.date=d.time?new Date(d.year,d.month-1,d.dayOfMonth,d.time.hour,d.time.minute,d.time.second,d.time.millis):new Date(d.year,d.month-1,d.dayOfMonth),d.dayOfWeek=String(d.date.getDay()),d},date:function(b,c){try{var d=this.parseDate(b);if(null===d)return b;for(var e,f=d.year,g=d.month,k=d.dayOfMonth,l=d.dayOfWeek,n=d.time,o="",p="",q="",r=!1,s=0;s<c.length;s++){var t=c.charAt(s),u=c.charAt(s+1);if(r)"'"==t?(p+=""===o?"'":o,o="",r=!1):o+=t;else switch(o+=t,q="",o){case"ddd":p+=a(l),o="";break;case"dd":if("d"===u)break;p+=m(k,2),o="";break;case"d":if("d"===u)break;p+=parseInt(k,10),o="";break;case"D":k=1==k||21==k||31==k?parseInt(k,10)+"st":2==k||22==k?parseInt(k,10)+"nd":3==k||23==k?parseInt(k,10)+"rd":parseInt(k,10)+"th",p+=k,o="";break;case"MMMM":p+=j(g),o="";break;case"MMM":if("M"===u)break;p+=i(g),o="";break;case"MM":if("M"===u)break;p+=m(g,2),o="";break;case"M":if("M"===u)break;p+=parseInt(g,10),o="";break;case"y":case"yyy":if("y"===u)break;p+=o,o="";break;case"yy":if("y"===u)break;p+=String(f).slice(-2),o="";break;case"yyyy":p+=f,o="";break;case"HH":p+=m(n.hour,2),o="";break;case"H":if("H"===u)break;p+=parseInt(n.hour,10),o="";break;case"hh":e=0===parseInt(n.hour,10)?12:n.hour<13?n.hour:n.hour-12,p+=m(e,2),o="";break;case"h":if("h"===u)break;e=0===parseInt(n.hour,10)?12:n.hour<13?n.hour:n.hour-12,p+=parseInt(e,10),o="";break;case"mm":p+=m(n.minute,2),o="";break;case"m":if("m"===u)break;p+=n.minute,o="";break;case"ss":p+=m(n.second.substring(0,2),2),o="";break;case"s":if("s"===u)break;p+=n.second,o="";break;case"S":case"SS":if("S"===u)break;p+=o,o="";break;case"SSS":var v="000"+n.millis.substring(0,3);p+=v.substring(v.length-3),o="";break;case"a":p+=n.hour>=12?"PM":"AM",o="";break;case"p":p+=n.hour>=12?"p.m.":"a.m.",o="";break;case"E":p+=h(l),o="";break;case"'":o="",r=!0;break;default:p+=t,o=""}}return p+=q}catch(w){return console&&console.log&&console.log(w),b}},prettyDate:function(a){var b,c,d;return("string"==typeof a||"number"==typeof a)&&(b=new Date(a)),"object"==typeof a&&(b=new Date(a.toString())),c=((new Date).getTime()-b.getTime())/1e3,d=Math.floor(c/86400),isNaN(d)||0>d?void 0:60>c?"just now":120>c?"1 minute ago":3600>c?Math.floor(c/60)+" minutes ago":7200>c?"1 hour ago":86400>c?Math.floor(c/3600)+" hours ago":1===d?"Yesterday":7>d?d+" days ago":31>d?Math.ceil(d/7)+" weeks ago":d>=31?"more than 5 weeks ago":void 0},toBrowserTimeZone:function(a,b){return this.date(new Date(a),b||"MM/dd/yyyy HH:mm:ss")}}}()}(DateFormat),function(a){a.format=DateFormat.format}(jQuery);
jQuery(".website").sort(sort_li) // sort elements
.appendTo('.websites'); // append again to the list
// sort function callback
function sort_li(a, b){
return (jQuery(b).data('renewal')) < (jQuery(a).data('renewal')) ? 1 : -1;
}
jQuery('.partner').each(function() {
// Loop through each partner and generate totals
var total_price = 0;
jQuery(this).find('li').each(function() {
price = jQuery(this).data('price');
term = jQuery(this).data('terms');
if (isNaN(price)) {
price = 0;
}
if(typeof price === 'undefined'){
price = 0;
};
if (price) {
if (term == "quarterly") {
price = price * 4;
}
if (term == "month") {
price = price * 12;
}
total_price = total_price + price;
}
});
// Add total price as data attribute
jQuery(this).attr("data-total", total_price);
// Display total price
jQuery(this).children("ul").append("<li>Total Price: $"+total_price+ "</li>");
});
</script>

View file

@ -0,0 +1,219 @@
<style>
.heading {
margin-top: 2em;
font-weight: bold;
font-size: 1.4em;
}
.total {
font-weight: bold;
padding: 10px 0px;
display: block;
}
.websites li {
margin-bottom: 0px;
}
.websites ul {
margin-left: 10px;
}
.websites li p {
line-height: 1em;
}
</style>
<script>
var chart_data = [];
var chart_data_formatted = [];
var chart_data_year = [];
var chart_data_year_formatted = [];
jQuery( document ).ready( function () {
// Generate array to build monthly chart
jQuery('.websites .customer').each(function() {
var start_date = new Date( jQuery(this).data('start') );
var end_date = new Date( jQuery(this).data('end') );
var year = start_date.getFullYear();
var month = ('0' + (start_date.getMonth()+1)).slice(-2);
var key = year+"-"+month;
if ( start_date != "Invalid Date" ) {
if ( chart_data[key] == undefined ) {
chart_data[key] = 0;
} else {
chart_data[key] = chart_data[key] + 1;
}
}
if ( end_date != "Invalid Date") {
if ( chart_data[key] == undefined ) {
chart_data[key] = -1;
} else {
chart_data[key] = chart_data[key] - 1;
}
}
});
chart_data_keys = Object.keys( chart_data ).sort();
// Loop through key
for (var key in chart_data_keys) {
var count = 0;
var previous_count = chart_data[ chart_data_keys[key - 1 ] ];
if (isNaN(previous_count) ) {
} else {
count = chart_data[ chart_data_keys[key] ] + parseInt( previous_count );
chart_data[ chart_data_keys[key] ] = chart_data[ chart_data_keys[key] ] + parseInt(previous_count);
}
chart_data_formatted.push( [ new Date( chart_data_keys[key] ), count ] );
}
// Generate array to build yearly chart
jQuery('.websites .customer').each(function() {
var start_date = new Date( jQuery(this).data('start') );
var end_date = new Date( jQuery(this).data('end') );
var year = start_date.getFullYear();
var month = ('0' + (start_date.getMonth()+1)).slice(-2);
var key = year;
if ( start_date != "Invalid Date" ) {
if ( chart_data_year[key] == undefined ) {
//chart_data_year[key] = 0;
} else {
chart_data_year[key] = chart_data_year[key] + 1;
}
}
if ( end_date != "Invalid Date") {
if ( chart_data_year[key] == undefined ) {
chart_data_year[key] = -1;
} else {
chart_data_year[key] = chart_data_year[key] - 1;
}
}
});
chart_data_year_keys = Object.keys( chart_data_year ).sort();
// Loop through key
for (var key in chart_data_year_keys) {
var count = 0;
var previous_count = chart_data_year[ chart_data_year_keys[key - 1 ] ];
if (isNaN(previous_count) ) {
} else {
count = chart_data_year[ chart_data_year_keys[key] ] + parseInt( previous_count );
chart_data_year[ chart_data_year_keys[key] ] = chart_data_year[ chart_data_year_keys[key] ] + parseInt(previous_count);
}
chart_data_year_formatted.push( [ new Date( chart_data_year_keys[key], 0, 1 ), chart_data_year_keys[key], count ] );
}
google.charts.load('current', {'packages':['bar']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('date', 'Time of Day');
data.addColumn('number', 'Customers');
data.addRows(chart_data_formatted);
var data_year = new google.visualization.DataTable();
data_year.addColumn('date', 'Year');
data_year.addColumn({type: 'string', role: 'tooltip'});
data_year.addColumn('number', 'Customers');
data_year.addRows(chart_data_year_formatted);
var options = {
title: '',
height: 450,
legend: false
};
var chart = new google.charts.Bar(document.getElementById('chart_div'));
var chart_year = new google.charts.Bar(document.getElementById('chart_div_year'));
chart.draw(data, google.charts.Bar.convertOptions(options));
chart_year.draw(data_year, google.charts.Bar.convertOptions(options));
}
});
</script>
<div class="wrap"><div id="icon-tools" class="icon32"></div>
<h2>Customer Timeline</h2>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
<div id="result"></div>
<div id="chart_div_year"></div>
<div id="result_year"></div>
<?php
$today = date('Ymd');
// WP_Query arguments
$args = array (
'post_type' => array( 'customer' ),
'posts_per_page' => '-1',
'meta_query' => array(
array(
'key' => 'billing_date',
'compare' => '<=',
'value' => $today,
),
array(
'key' => 'total_price',
'compare' => '>',
'value' => "0",
)
),
);
// The Query
$query = new WP_Query( $args );
$posts = $query->get_posts();
// The Loop
if ( $query->have_posts() ) {
echo "<div class='websites'>";
while ( $query->have_posts() ) {
$query->the_post();
$id = get_the_ID();
$status = get_field('status');
if ($status == "cancelled") {
// Guess close date based on related websites
$close_date = get_the_modified_date('m/d/y');
} else {
$close_date = "";
}
?>
<div class="customer" data-start="<?php the_field('billing_date'); ?>" data-end="<?php echo $close_date; ?>" data-status="<?php the_field('status'); ?>">
<?php the_title(); ?> - ID# <?php echo get_the_ID(); ?>
</div>
<?php
}
echo "</div>";
} else {
// no posts found
}
// Restore original Post Data
wp_reset_postdata();
?>
</div>

158
inc/bulk-actions.php Normal file
View file

@ -0,0 +1,158 @@
<?php
if (!class_exists('FRS_Custom_Bulk_Action')) {
class FRS_Custom_Bulk_Action {
public function __construct() {
if(is_admin()) {
// admin actions/filters
add_action('admin_footer-edit.php', array(&$this, 'custom_bulk_admin_footer'));
add_action('load-edit.php', array(&$this, 'custom_bulk_action'));
add_action('admin_notices', array(&$this, 'custom_bulk_admin_notices'));
}
}
/**
* Step 1: add the custom Bulk Action to the select menus
*/
function custom_bulk_admin_footer() {
global $post_type;
if($post_type == 'website') {
?>
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery('<option>').val('generate').text('<?php _e('Generate Customer')?>').appendTo("select[name='action']");
jQuery('<option>').val('generate').text('<?php _e('Generate Customer')?>').appendTo("select[name='action2']");
jQuery('<option>').val('partner').text('<?php _e('Add Partner')?>').appendTo("select[name='action']");
jQuery('<option>').val('partner').text('<?php _e('Add Partner')?>').appendTo("select[name='action2']");
jQuery('<input type="text" name="new_partner" id="new_partner">').insertBefore('#doaction');
});
</script>
<?php
}
}
/**
* Step 2: handle the custom Bulk Action
*
* Based on the post http://wordpress.stackexchange.com/questions/29822/custom-bulk-action
*/
function custom_bulk_action() {
global $typenow;
$post_type = $typenow;
if($post_type == 'website') {
// get the action
$wp_list_table = _get_list_table('WP_Posts_List_Table'); // depending on your resource type this could be WP_Users_List_Table, WP_Comments_List_Table, etc
$action = $wp_list_table->current_action();
$allowed_actions = array("generate",'partner');
if(!in_array($action, $allowed_actions)) return;
// security check
check_admin_referer('bulk-posts');
// make sure ids are submitted. depending on the resource type, this may be 'media' or 'ids'
if(isset($_REQUEST['post'])) {
$post_ids = array_map('intval', $_REQUEST['post']);
}
$partner_id = $_REQUEST['new_partner'];
if(empty($post_ids)) return;
// this is based on wp-admin/edit.php
$sendback = remove_query_arg( array('exported', 'untrashed', 'deleted', 'ids'), wp_get_referer() );
if ( ! $sendback )
$sendback = admin_url( "edit.php?post_type=$post_type" );
$pagenum = $wp_list_table->get_pagenum();
$sendback = add_query_arg( 'paged', $pagenum, $sendback );
switch($action) {
case 'generate':
// if we set up user permissions/capabilities, the code might look like:
//if ( !current_user_can($post_type_object->cap->export_post, $post_id) )
// wp_die( __('You are not allowed to export this post.') );
$exported = 0;
foreach( $post_ids as $post_id ) {
if ( !$this->perform_export($post_id) )
wp_die( __('Error exporting post.') );
$exported++;
}
$sendback = add_query_arg( array('exported' => $exported, 'ids' => join(',', $post_ids) ), $sendback );
break;
case 'partner':
// if we set up user permissions/capabilities, the code might look like:
//if ( !current_user_can($post_type_object->cap->export_post, $post_id) )
// wp_die( __('You are not allowed to export this post.') );
$partner_added = 0;
foreach( $post_ids as $post_id ) {
if ( !$this->assign_partner($post_id, $partner_id) )
wp_die( __('Error exporting post.') );
$partner_added++;
}
$sendback = add_query_arg( array('partner_added' => $partner_added, 'ids' => join(',', $post_ids) ), $sendback );
break;
default: return;
}
$sendback = remove_query_arg( array('action', 'action2', 'tags_input', 'post_author', 'comment_status', 'ping_status', '_status', 'post', 'bulk_edit', 'post_view'), $sendback );
wp_redirect($sendback);
exit();
}
}
/**
* Step 3: display an admin notice on the Posts page after exporting
*/
function custom_bulk_admin_notices() {
global $post_type, $pagenow;
if($pagenow == 'edit.php' && $post_type == 'website' && isset($_REQUEST['exported']) && (int) $_REQUEST['exported']) {
$message = sprintf( _n( 'Customers generated.', '%s customers generated.', $_REQUEST['exported'] ), number_format_i18n( $_REQUEST['exported'] ) );
echo "<div class=\"updated\"><p>{$message}</p></div>";
}
if($pagenow == 'edit.php' && $post_type == 'website' && isset($_REQUEST['partner_added']) && (int) $_REQUEST['partner_added']) {
$message = sprintf( _n( 'Partner assigned.', '%s partners assigned.', $_REQUEST['partner_added'] ), number_format_i18n( $_REQUEST['partner_added'] ) );
echo "<div class=\"updated\"><p>{$message}</p></div>";
}
}
function perform_export($post_id) {
// do whatever work needs to be done
// Update the post into the database
anchor_acf_save_post_after($post_id);
return true;
}
function assign_partner($post_id, $partner_id) {
// do whatever work needs to be done
// Assign the partners from the bulk edit
update_field( "field_56181a38cf6e3", $partner_id, $post_id);
return true;
}
}
}
new FRS_Custom_Bulk_Action();

1
inc/constellix-api Submodule

@ -0,0 +1 @@
Subproject commit 0da24895049f47d3dea5fd4f4716c99bd091cbff

View file

@ -0,0 +1,159 @@
<?php
class Anchor_My_Account_Licenses_Endpoint {
/**
* Custom endpoint name.
*
* @var string
*/
public static $endpoint = 'licenses';
/**
* Plugin actions.
*/
public function __construct() {
$user = wp_get_current_user();
$role_check = in_array( 'partner', $user->roles ) + in_array( 'administrator', $user->roles );
if ($role_check) {
// Actions used to insert a new endpoint in the WordPress.
add_action( 'init', array( $this, 'add_endpoints' ) );
add_filter( 'query_vars', array( $this, 'add_query_vars' ), 0 );
// Change the My Accout page title.
add_filter( 'the_title', array( $this, 'endpoint_title' ) );
// Insering your new tab/page into the My Account page.
add_filter( 'woocommerce_account_menu_items', array( $this, 'new_menu_items' ) );
add_action( 'woocommerce_account_' . self::$endpoint . '_endpoint', array( $this, 'endpoint_content' ) );
}
}
/**
* Register new endpoint to use inside My Account page.
*
* @see https://developer.wordpress.org/reference/functions/add_rewrite_endpoint/
*/
public function add_endpoints() {
add_rewrite_endpoint( self::$endpoint, EP_ROOT | EP_PAGES );
}
/**
* Add new query var.
*
* @param array $vars
* @return array
*/
public function add_query_vars( $vars ) {
$vars[] = self::$endpoint;
return $vars;
}
/**
* Set endpoint title.
*
* @param string $title
* @return string
*/
public function endpoint_title( $title ) {
global $wp_query;
$is_endpoint = isset( $wp_query->query_vars[ self::$endpoint ] );
if ( $is_endpoint && ! is_admin() && is_main_query() && in_the_loop() && is_account_page() ) {
// New page title.
$title = __( 'Licenses', 'woocommerce' );
remove_filter( 'the_title', array( $this, 'endpoint_title' ) );
}
return $title;
}
/**
* Insert the new endpoint into the My Account menu.
*
* @param array $items
* @return array
*/
public function new_menu_items( $items ) {
// Remove the logout menu item.
$logout = $items['customer-logout'];
unset( $items['customer-logout'] );
// Insert your custom endpoint.
$items[ self::$endpoint ] = __( 'Licenses', 'woocommerce' );
// Insert back the logout item.
$items['customer-logout'] = $logout;
return $items;
}
/**
* Endpoint HTML content.
*/
public function endpoint_content() {
?>
<script>
jQuery(document).ready(function() {
jQuery('.license input').click(function() {
jQuery(this).focus().select();
});
});
</script>
<h3>WordPress Licenses</h3>
<?php if( have_rows('licenses') ): ?>
<div class="license">
<?php while( have_rows('licenses') ): the_row();
// vars
$name = get_sub_field('name');
$type = get_sub_field('type');
$link = get_sub_field('link');
$key = get_sub_field('key');
$username = get_sub_field('username');
$password = get_sub_field('password');
$account_link = get_sub_field('account_link');
?>
<div class="link" href="http://cmdshiftdesign.com/">
<?php if ($account_link) { ?>
<div class="login">
<span class="username"><?php echo $username; ?></span>
<span class="password"><?php echo $password; ?></span>
<a href="<?php echo $account_link; ?>" target="_blank">Account Login</a>
</div>
<?php } ?>
<span class="name"><?php echo $name; ?></span>
<span class="website"><input type="input" value="<?php echo $key; ?>"></span>
<span class="tag"><?php echo $type; ?></span>
</div>
<?php endwhile; ?>
</ul>
<?php endif; ?>
<?php }
/**
* Plugin install action.
* Flush rewrite rules to make our custom endpoint available.
*/
public static function install() {
flush_rewrite_rules();
}
}
new Anchor_My_Account_Licenses_Endpoint();
// Flush rewrite rules on plugin activation.
register_activation_hook( __FILE__, array( 'Anchor_My_Account_Licenses_Endpoint', 'install' ) );

File diff suppressed because it is too large Load diff

202
inc/mailgun-api.php Normal file
View file

@ -0,0 +1,202 @@
<?php
function mailgun_setup( $domain ) {
// Prep to handle remote responses
$responses = '';
// Load Mailgun API client
include_once ABSPATH . '/vendor/autoload.php';
$mgClient = new \Mailgun\Mailgun( MAILGUN_API_KEY );
// Prep Mailgun domain variable
$mailgun_subdomain = "mg.$domain";
// Fetch all domains from Mailgun
$results = $mgClient->get( 'domains' );
foreach ( $results->http_response_body->items as $result ) {
if ( $result->name == $mailgun_subdomain ) {
$mailgun_domain_found = $mailgun_subdomain;
if ( $result->state == 'unverified' ) {
$mailgun_domain_unverified = true;
}
}
}
// If Mailgun domain already exists then exit
if ( $mailgun_domain_found && ! $mailgun_domain_unverified ) {
return "Mailgun domain $mailgun_domain_found already entered and verified";
}
if ( $mailgun_domain_found ) {
// Fetch domain from Mailgun
$result = $mgClient->get( "domains/$mailgun_subdomain" );
} else {
// Create domain in Mailgun
$result = $mgClient->post(
'domains', array(
'name' => $mailgun_subdomain,
)
);
}
$mailgun_receiving_dns_records = $result->http_response_body->receiving_dns_records;
$mailgun_sending_dns_records = $result->http_response_body->sending_dns_records;
// Load Constellix domains from transient
$constellix_all_domains = get_transient( 'constellix_all_domains' );
// If empty then update transient with large remote call
if ( empty( $constellix_all_domains ) ) {
// Fetch Constellix domains
$constellix_all_domains = constellix_api_get( 'domains' );
// Save the API response so we don't have to call again until tomorrow.
set_transient( 'constellix_all_domains', $constellix_all_domains, HOUR_IN_SECONDS );
}
// Check Consellix for domain
foreach ( $constellix_all_domains as $constellix_domain ) {
// Search API for domain ID
if ( $domain == $constellix_domain->name ) {
$domain_id = $constellix_domain->id;
}
}
// Found domain ID from Consellix so add Mailgun dns records
if ( $domain_id ) {
// Loop through Mailgun's API new receiving records and prep for Constellix
$mx_records = [];
foreach ( $mailgun_receiving_dns_records as $record ) {
if ( $record->record_type == 'MX' and $record->valid != 'valid' ) {
$mx_records[] = array(
'value' => $record->value . '.',
'level' => $record->priority,
'disableFlag' => false,
);
}
}
// Prep new Constellix records
$record_type = 'mx';
$post = array(
'recordOption' => 'roundRobin',
'name' => 'mg',
'ttl' => '1800',
'roundRobin' => $mx_records,
);
// Post to new MX records to Constellix
$response = constellix_api_post( "domains/$domain_id/records/$record_type", $post );
// Capture responses
foreach ( $response as $result ) {
if ( is_array( $result ) ) {
$result['errors'] = $result[0];
$responses = $responses . json_encode( $result ) . ',';
} else {
$responses = $responses . json_encode( $result ) . ',';
}
}
// Loop through Mailgun's API new receiving records and prep for Constellix
foreach ( $mailgun_sending_dns_records as $record ) {
if ( $record->record_type == 'TXT' and $record->valid != 'valid' ) {
$record_name_without_domain = str_replace( '.' . $domain, '', $record->name );
$post = array(
'recordOption' => 'roundRobin',
'name' => $record_name_without_domain,
'ttl' => '1800',
'roundRobin' => array(
array(
'value' => $record->value,
'disableFlag' => false,
),
),
);
$response = constellix_api_post( "domains/$domain_id/records/txt", $post );
foreach ( $response as $result ) {
if ( is_array( $result ) ) {
$result['errors'] = $result[0];
$responses = $responses . json_encode( $result ) . ',';
} else {
$responses = $responses . json_encode( $result ) . ',';
}
}
}
if ( $record->record_type == 'CNAME' and $record->valid != 'valid' ) {
$record_name_without_domain = str_replace( '.' . $domain, '', $record->name );
$post = array(
'name' => $record_name_without_domain,
'host' => "$record->value.",
'ttl' => 1800,
);
$response = constellix_api_post( "domains/$domain_id/records/cname", $post );
foreach ( $response as $result ) {
if ( is_array( $result ) ) {
$result['errors'] = $result[0];
$responses = $responses . json_encode( $result ) . ',';
} else {
$responses = $responses . json_encode( $result ) . ',';
}
}
}
}
}
// Valid Mailgun domains
$result = $mgClient->put(
"domains/$mailgun_subdomain/verify", array(
'domain' => "$mailgun_subdomain",
)
);
// In 1 minute run Mailgun verify domain
wp_schedule_single_event( time() + 60, 'schedule_mailgun_verify', array( $domain ) );
if ( $responses ) {
return $responses;
}
}
// Hook to run mailgun_verify() at a later time
add_action( 'schedule_mailgun_verify', 'mailgun_verify', 10, 3 );
function mailgun_verify( $domain ) {
// Load Mailgun API client
include_once ABSPATH . '/vendor/autoload.php';
$mgClient = new \Mailgun\Mailgun( MAILGUN_API_KEY );
// Prep Mailgun domain variable
$mailgun_subdomain = "mg.$domain";
// Valid Mailgun domains
$result = $mgClient->put(
"domains/$mailgun_subdomain/verify", array(
'domain' => "$mailgun_subdomain",
)
);
// Check if records are valid. If not need to flag the domain
// (TO DO: add place to flag domain with automattic retry schedule. 60sec, 3 minutes, 6 minutes, 1hr, 24hrs)
$mailgun_receiving_dns_records = $result->http_response_body->receiving_dns_records;
$mailgun_sending_dns_records = $result->http_response_body->sending_dns_records;
return $result->http_response_body->domain->state;
}

View file

@ -0,0 +1,40 @@
<?php
add_action( 'woocommerce_edit_account_form', 'anchor_woocommerce_edit_account_form' );
function anchor_woocommerce_edit_account_form() {
$user_id = get_current_user_id();
$user = get_userdata( $user_id );
if ( !$user )
return;
?>
<fieldset>
<p class="woocommerce-form-row woocommerce-form-row--wide form-row form-row-wide">
<label for="anchor_password_1"><?php _e( 'New password (leave blank to leave unchanged)', 'woocommerce' ); ?></label>
<input type="password" class="woocommerce-Input woocommerce-Input--password input-text" name="anchor_password_1" id="anchor_password_1" />
</p>
<p class="woocommerce-form-row woocommerce-form-row--wide form-row form-row-wide">
<label for="anchor_password_2"><?php _e( 'Confirm new password', 'woocommerce' ); ?></label>
<input type="password" class="woocommerce-Input woocommerce-Input--password input-text" name="anchor_password_2" id="anchor_password_2" />
</p>
</fieldset>
<?php
}
add_action( 'woocommerce_save_account_details', 'anchor_woocommerce_save_account_details' );
function anchor_woocommerce_save_account_details( $user_id ) {
if ( ( ! empty( $_POST['anchor_password_1'] ) && ! empty( $_POST['anchor_password_2']) ) && $_POST['anchor_password_1'] == $_POST['anchor_password_2'] ) {
$user = wp_update_user( array( 'ID' => $user_id, 'user_pass' => $_POST['anchor_password_1'] ) );
}
}
add_action( 'woocommerce_save_account_details_errors','anchor_woocommerce_validate_custom_field', 10,2 );
function anchor_woocommerce_validate_custom_field(&$args, &$user) {
if ( $_POST['anchor_password_1'] != $_POST['anchor_password_2']) {
wc_add_notice( __( 'New passwords do not match.', 'woocommerce' ), 'error' );
}
}

View file

@ -0,0 +1,36 @@
<?php
/**
* Fired during plugin activation
*
* @link https://anchor.host
* @since 0.1.0
*
* @package Captaincore
* @subpackage Captaincore/includes
*/
/**
* Fired during plugin activation.
*
* This class defines all code necessary to run during the plugin's activation.
*
* @since 0.1.0
* @package Captaincore
* @subpackage Captaincore/includes
* @author Anchor Hosting <support@anchor.host>
*/
class Captaincore_Activator {
/**
* Short Description. (use period)
*
* Long Description.
*
* @since 0.1.0
*/
public static function activate() {
}
}

View file

@ -0,0 +1,36 @@
<?php
/**
* Fired during plugin deactivation
*
* @link https://anchor.host
* @since 0.1.0
*
* @package Captaincore
* @subpackage Captaincore/includes
*/
/**
* Fired during plugin deactivation.
*
* This class defines all code necessary to run during the plugin's deactivation.
*
* @since 0.1.0
* @package Captaincore
* @subpackage Captaincore/includes
* @author Anchor Hosting <support@anchor.host>
*/
class Captaincore_Deactivator {
/**
* Short Description. (use period)
*
* Long Description.
*
* @since 0.1.0
*/
public static function deactivate() {
}
}

View file

@ -0,0 +1,47 @@
<?php
/**
* Define the internationalization functionality
*
* Loads and defines the internationalization files for this plugin
* so that it is ready for translation.
*
* @link https://anchor.host
* @since 0.1.0
*
* @package Captaincore
* @subpackage Captaincore/includes
*/
/**
* Define the internationalization functionality.
*
* Loads and defines the internationalization files for this plugin
* so that it is ready for translation.
*
* @since 0.1.0
* @package Captaincore
* @subpackage Captaincore/includes
* @author Anchor Hosting <support@anchor.host>
*/
class Captaincore_i18n {
/**
* Load the plugin text domain for translation.
*
* @since 0.1.0
*/
public function load_plugin_textdomain() {
load_plugin_textdomain(
'captaincore',
false,
dirname( dirname( plugin_basename( __FILE__ ) ) ) . '/languages/'
);
}
}

View file

@ -0,0 +1,129 @@
<?php
/**
* Register all actions and filters for the plugin
*
* @link https://anchor.host
* @since 0.1.0
*
* @package Captaincore
* @subpackage Captaincore/includes
*/
/**
* Register all actions and filters for the plugin.
*
* Maintain a list of all hooks that are registered throughout
* the plugin, and register them with the WordPress API. Call the
* run function to execute the list of actions and filters.
*
* @package Captaincore
* @subpackage Captaincore/includes
* @author Anchor Hosting <support@anchor.host>
*/
class Captaincore_Loader {
/**
* The array of actions registered with WordPress.
*
* @since 0.1.0
* @access protected
* @var array $actions The actions registered with WordPress to fire when the plugin loads.
*/
protected $actions;
/**
* The array of filters registered with WordPress.
*
* @since 0.1.0
* @access protected
* @var array $filters The filters registered with WordPress to fire when the plugin loads.
*/
protected $filters;
/**
* Initialize the collections used to maintain the actions and filters.
*
* @since 0.1.0
*/
public function __construct() {
$this->actions = array();
$this->filters = array();
}
/**
* Add a new action to the collection to be registered with WordPress.
*
* @since 0.1.0
* @param string $hook The name of the WordPress action that is being registered.
* @param object $component A reference to the instance of the object on which the action is defined.
* @param string $callback The name of the function definition on the $component.
* @param int $priority Optional. The priority at which the function should be fired. Default is 10.
* @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1.
*/
public function add_action( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) {
$this->actions = $this->add( $this->actions, $hook, $component, $callback, $priority, $accepted_args );
}
/**
* Add a new filter to the collection to be registered with WordPress.
*
* @since 0.1.0
* @param string $hook The name of the WordPress filter that is being registered.
* @param object $component A reference to the instance of the object on which the filter is defined.
* @param string $callback The name of the function definition on the $component.
* @param int $priority Optional. The priority at which the function should be fired. Default is 10.
* @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1
*/
public function add_filter( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) {
$this->filters = $this->add( $this->filters, $hook, $component, $callback, $priority, $accepted_args );
}
/**
* A utility function that is used to register the actions and hooks into a single
* collection.
*
* @since 0.1.0
* @access private
* @param array $hooks The collection of hooks that is being registered (that is, actions or filters).
* @param string $hook The name of the WordPress filter that is being registered.
* @param object $component A reference to the instance of the object on which the filter is defined.
* @param string $callback The name of the function definition on the $component.
* @param int $priority The priority at which the function should be fired.
* @param int $accepted_args The number of arguments that should be passed to the $callback.
* @return array The collection of actions and filters registered with WordPress.
*/
private function add( $hooks, $hook, $component, $callback, $priority, $accepted_args ) {
$hooks[] = array(
'hook' => $hook,
'component' => $component,
'callback' => $callback,
'priority' => $priority,
'accepted_args' => $accepted_args
);
return $hooks;
}
/**
* Register the filters and actions with WordPress.
*
* @since 0.1.0
*/
public function run() {
foreach ( $this->filters as $hook ) {
add_filter( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] );
}
foreach ( $this->actions as $hook ) {
add_action( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] );
}
}
}

218
includes/class-captaincore.php Executable file
View file

@ -0,0 +1,218 @@
<?php
/**
* The file that defines the core plugin class
*
* A class definition that includes attributes and functions used across both the
* public-facing side of the site and the admin area.
*
* @link https://anchor.host
* @since 0.1.0
*
* @package Captaincore
* @subpackage Captaincore/includes
*/
/**
* The core plugin class.
*
* This is used to define internationalization, admin-specific hooks, and
* public-facing site hooks.
*
* Also maintains the unique identifier of this plugin as well as the current
* version of the plugin.
*
* @since 0.1.0
* @package Captaincore
* @subpackage Captaincore/includes
* @author Anchor Hosting <support@anchor.host>
*/
class Captaincore {
/**
* The loader that's responsible for maintaining and registering all hooks that power
* the plugin.
*
* @since 0.1.0
* @access protected
* @var Captaincore_Loader $loader Maintains and registers all hooks for the plugin.
*/
protected $loader;
/**
* The unique identifier of this plugin.
*
* @since 0.1.0
* @access protected
* @var string $plugin_name The string used to uniquely identify this plugin.
*/
protected $plugin_name;
/**
* The current version of the plugin.
*
* @since 0.1.0
* @access protected
* @var string $version The current version of the plugin.
*/
protected $version;
/**
* Define the core functionality of the plugin.
*
* Set the plugin name and the plugin version that can be used throughout the plugin.
* Load the dependencies, define the locale, and set the hooks for the admin area and
* the public-facing side of the site.
*
* @since 0.1.0
*/
public function __construct() {
if ( defined( 'PLUGIN_NAME_VERSION' ) ) {
$this->version = PLUGIN_NAME_VERSION;
} else {
$this->version = '0.1.0';
}
$this->plugin_name = 'captaincore';
$this->load_dependencies();
$this->set_locale();
$this->define_admin_hooks();
$this->define_public_hooks();
}
/**
* Load the required dependencies for this plugin.
*
* Include the following files that make up the plugin:
*
* - Captaincore_Loader. Orchestrates the hooks of the plugin.
* - Captaincore_i18n. Defines internationalization functionality.
* - Captaincore_Admin. Defines all hooks for the admin area.
* - Captaincore_Public. Defines all hooks for the public side of the site.
*
* Create an instance of the loader which will be used to register the hooks
* with WordPress.
*
* @since 0.1.0
* @access private
*/
private function load_dependencies() {
/**
* The class responsible for orchestrating the actions and filters of the
* core plugin.
*/
require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-captaincore-loader.php';
/**
* The class responsible for defining internationalization functionality
* of the plugin.
*/
require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-captaincore-i18n.php';
/**
* The class responsible for defining all actions that occur in the admin area.
*/
require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-captaincore-admin.php';
/**
* The class responsible for defining all actions that occur in the public-facing
* side of the site.
*/
require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-captaincore-public.php';
$this->loader = new Captaincore_Loader();
}
/**
* Define the locale for this plugin for internationalization.
*
* Uses the Captaincore_i18n class in order to set the domain and to register the hook
* with WordPress.
*
* @since 0.1.0
* @access private
*/
private function set_locale() {
$plugin_i18n = new Captaincore_i18n();
$this->loader->add_action( 'plugins_loaded', $plugin_i18n, 'load_plugin_textdomain' );
}
/**
* Register all of the hooks related to the admin area functionality
* of the plugin.
*
* @since 0.1.0
* @access private
*/
private function define_admin_hooks() {
$plugin_admin = new Captaincore_Admin( $this->get_plugin_name(), $this->get_version() );
$this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
$this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
}
/**
* Register all of the hooks related to the public-facing functionality
* of the plugin.
*
* @since 0.1.0
* @access private
*/
private function define_public_hooks() {
$plugin_public = new Captaincore_Public( $this->get_plugin_name(), $this->get_version() );
$this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_styles' );
$this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' );
}
/**
* Run the loader to execute all of the hooks with WordPress.
*
* @since 0.1.0
*/
public function run() {
$this->loader->run();
}
/**
* The name of the plugin used to uniquely identify it within the context of
* WordPress and to define internationalization functionality.
*
* @since 0.1.0
* @return string The name of the plugin.
*/
public function get_plugin_name() {
return $this->plugin_name;
}
/**
* The reference to the class that orchestrates the hooks with the plugin.
*
* @since 0.1.0
* @return Captaincore_Loader Orchestrates the hooks of the plugin.
*/
public function get_loader() {
return $this->loader;
}
/**
* Retrieve the version number of the plugin.
*
* @since 0.1.0
* @return string The version number of the plugin.
*/
public function get_version() {
return $this->version;
}
}

1
includes/index.php Executable file
View file

@ -0,0 +1 @@
<?php // Silence is golden

1
index.php Executable file
View file

@ -0,0 +1 @@
<?php // Silence is golden

0
languages/captaincore.pot Executable file
View file

View file

@ -0,0 +1,107 @@
<?php
/**
* The public-facing functionality of the plugin.
*
* @link https://anchor.host
* @since 0.1.0
*
* @package Captaincore
* @subpackage Captaincore/public
*/
/**
* The public-facing functionality of the plugin.
*
* Defines the plugin name, version, and two examples hooks for how to
* enqueue the public-facing stylesheet and JavaScript.
*
* @package Captaincore
* @subpackage Captaincore/public
* @author Anchor Hosting <support@anchor.host>
*/
class Captaincore_Public {
/**
* The ID of this plugin.
*
* @since 0.1.0
* @access private
* @var string $plugin_name The ID of this plugin.
*/
private $plugin_name;
/**
* The version of this plugin.
*
* @since 0.1.0
* @access private
* @var string $version The current version of this plugin.
*/
private $version;
/**
* Initialize the class and set its properties.
*
* @since 0.1.0
* @param string $plugin_name The name of the plugin.
* @param string $version The version of this plugin.
*/
public function __construct( $plugin_name, $version ) {
$this->plugin_name = $plugin_name;
$this->version = $version;
}
/**
* Register the stylesheets for the public-facing side of the site.
*
* @since 0.1.0
*/
public function enqueue_styles() {
/**
* This function is provided for demonstration purposes only.
*
* An instance of this class should be passed to the run() function
* defined in Captaincore_Loader as all of the hooks are defined
* in that particular class.
*
* The Captaincore_Loader will then create the relationship
* between the defined hooks and the functions defined in this
* class.
*/
wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/captaincore-public.css', array(), $this->version, 'all' );
wp_enqueue_style( 'google-material-icons', "https://fonts.googleapis.com/icon?family=Material+Icons", array(), '2017-09-03' );
wp_enqueue_style( 'materialize', plugin_dir_url( __FILE__ ) . "css/materialize-src/materialize.css", array(), '2017-09-08' );
wp_enqueue_script( 'materialize', plugin_dir_url( __FILE__ ) . 'css/materialize-src/js/bin/materialize.js', array(), '2016-12-30', true );
}
/**
* Register the JavaScript for the public-facing side of the site.
*
* @since 0.1.0
*/
public function enqueue_scripts() {
/**
* This function is provided for demonstration purposes only.
*
* An instance of this class should be passed to the run() function
* defined in Captaincore_Loader as all of the hooks are defined
* in that particular class.
*
* The Captaincore_Loader will then create the relationship
* between the defined hooks and the functions defined in this
* class.
*/
wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/captaincore-public.js', array( 'jquery' ), $this->version, false );
}
}

View file

@ -0,0 +1,4 @@
/**
* All of the CSS for your public-facing functionality should be
* included in this file.
*/

View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014-2017 Materialize
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,90 @@
<p align="center">
<a href="http://materializecss.com/">
<img src="http://materializecss.com/res/materialize.svg" width="150">
</a>
<h3 align="center">MaterializeCSS</h3>
<p align="center">
Materialize, a CSS Framework based on material design.
<br>
<a href="http://materializecss.com/"><strong>-- Browse the docs --</strong></a>
<br>
<br>
<a href="https://travis-ci.org/Dogfalo/materialize">
<img src="https://travis-ci.org/Dogfalo/materialize.svg?branch=master" alt="Travis CI badge">
</a>
<a href="https://badge.fury.io/js/materialize-css">
<img src="https://badge.fury.io/js/materialize-css.svg" alt="npm version badge">
</a>
<a href="https://cdnjs.com/libraries/materialize">
<img src="https://img.shields.io/cdnjs/v/materialize.svg" alt="CDNJS version badge">
</a>
<a href="https://david-dm.org/Dogfalo/materialize">
<img src="https://david-dm.org/Dogfalo/materialize/status.svg" alt="dependencies Status badge">
</a>
<a href="https://david-dm.org/Dogfalo/materialize#info=devDependencies">
<img src="https://david-dm.org/Dogfalo/materialize/dev-status.svg" alt="devDependency Status badge">
</a>
<a href="https://gitter.im/Dogfalo/materialize">
<img src="https://badges.gitter.im/Join%20Chat.svg" alt="Gitter badge">
</a>
</p>
## Table of Contents
- [Quickstart](#quickstart)
- [Documentation](#documentation)
- [Supported Browsers](#supported-browsers)
- [Changelog](#changelog)
- [Testing](#testing)
- [Contributing](#contributing)
- [Copyright and license](#copyright-and-license)
## Quickstart:
Read the [getting started guide](http://materializecss.com/getting-started.html) for more information on how to use materialize.
- [Download the latest release](https://github.com/Dogfalo/materialize/releases/latest) of materialize directly from GitHub.
- Clone the repo: `git clone https://github.com/Dogfalo/materialize.git`
- Include the files via [cdnjs](https://cdnjs.com/libraries/materialize). More [here](http://materializecss.com/getting-started.html).
- Install with [npm](https://www.npmjs.com): `npm install materialize-css`
- Install with [Bower](https://bower.io): `bower install materialize`
- Install with [Atmosphere](https://atmospherejs.com): `meteor add materialize:materialize`
## Documentation
The documentation can be found at <http://materializecss.com>. To run the documentation locally on your machine, you need [Node.js](https://nodejs.org/en/) installed on your computer.
### Running documentation locally
Run these commands to set up the documentation:
```bash
git clone https://github.com/Dogfalo/materialize
cd materialize
npm install
```
Then run `grunt monitor` to compile the documentation. When it finishes, open a new browser window and navigate to `localhost:8000`. We use [BrowserSync](https://www.browsersync.io/) to display the documentation.
### Documentation for previous releases
Previous releases and their documentation are available for [download](https://github.com/Dogfalo/materialize/releases).
## Supported Browsers:
Materialize is compatible with:
- Chrome 35+
- Firefox 31+
- Safari 7+
- Opera
- Edge
- IE 10+
## Changelog
For changelogs, check out [the Releases section of materialize](https://github.com/Dogfalo/materialize/releases) or the [CHANGELOG.md](CHANGELOG.md).
## Testing
We use Jasmine as our testing framework and we're trying to write a robust test suite for our components. If you want to help, [here's a starting guide on how to write tests in Jasmine](CONTRIBUTING.md#jasmine-testing-guide).
## Contributing
Check out the [CONTRIBUTING document](CONTRIBUTING.md) in the root of the repository to learn how you can contribute. You can also browse the [help-wanted](https://github.com/Dogfalo/materialize/labels/help-wanted) tag in our issue tracker to find things to do.
## Copyright and license
Code copyright 2017 Materialize. Code released under the MIT license.

View file

@ -0,0 +1,8 @@
// Custom Easing
jQuery.extend( jQuery.easing,
{
easeInOutMaterial: function (x, t, b, c, d) {
if ((t/=d/2) < 1) return c/2*t*t + b;
return c/4*((t-=2)*t*t + 2) + b;
}
});

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,267 @@
(function ($) {
$(document).ready(function() {
// jQuery reverse
$.fn.reverse = [].reverse;
// Hover behaviour: make sure this doesn't work on .click-to-toggle FABs!
$(document).on('mouseenter.fixedActionBtn', '.fixed-action-btn:not(.click-to-toggle):not(.toolbar)', function(e) {
var $this = $(this);
openFABMenu($this);
});
$(document).on('mouseleave.fixedActionBtn', '.fixed-action-btn:not(.click-to-toggle):not(.toolbar)', function(e) {
var $this = $(this);
closeFABMenu($this);
});
// Toggle-on-click behaviour.
$(document).on('click.fabClickToggle', '.fixed-action-btn.click-to-toggle > a', function(e) {
var $this = $(this);
var $menu = $this.parent();
if ($menu.hasClass('active')) {
closeFABMenu($menu);
} else {
openFABMenu($menu);
}
});
// Toolbar transition behaviour.
$(document).on('click.fabToolbar', '.fixed-action-btn.toolbar > a', function(e) {
var $this = $(this);
var $menu = $this.parent();
FABtoToolbar($menu);
});
});
$.fn.extend({
openFAB: function() {
openFABMenu($(this));
},
closeFAB: function() {
closeFABMenu($(this));
},
openToolbar: function() {
FABtoToolbar($(this));
},
closeToolbar: function() {
toolbarToFAB($(this));
}
});
var openFABMenu = function (btn) {
var $this = btn;
if ($this.hasClass('active') === false) {
// Get direction option
var horizontal = $this.hasClass('horizontal');
var offsetY, offsetX;
if (horizontal === true) {
offsetX = 40;
} else {
offsetY = 40;
}
$this.addClass('active');
$this.find('ul .btn-floating').velocity(
{ scaleY: ".4", scaleX: ".4", translateY: offsetY + 'px', translateX: offsetX + 'px'},
{ duration: 0 });
var time = 0;
$this.find('ul .btn-floating').reverse().each( function () {
$(this).velocity(
{ opacity: "1", scaleX: "1", scaleY: "1", translateY: "0", translateX: '0'},
{ duration: 80, delay: time });
time += 40;
});
}
};
var closeFABMenu = function (btn) {
var $this = btn;
// Get direction option
var horizontal = $this.hasClass('horizontal');
var offsetY, offsetX;
if (horizontal === true) {
offsetX = 40;
} else {
offsetY = 40;
}
$this.removeClass('active');
var time = 0;
$this.find('ul .btn-floating').velocity("stop", true);
$this.find('ul .btn-floating').velocity(
{ opacity: "0", scaleX: ".4", scaleY: ".4", translateY: offsetY + 'px', translateX: offsetX + 'px'},
{ duration: 80 }
);
};
/**
* Transform FAB into toolbar
* @param {Object} object jQuery object
*/
var FABtoToolbar = function(btn) {
if (btn.attr('data-open') === "true") {
return;
}
var offsetX, offsetY, scaleFactor;
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var btnRect = btn[0].getBoundingClientRect();
var anchor = btn.find('> a').first();
var menu = btn.find('> ul').first();
var backdrop = $('<div class="fab-backdrop"></div>');
var fabColor = anchor.css('background-color');
anchor.append(backdrop);
offsetX = btnRect.left - (windowWidth / 2) + (btnRect.width / 2);
offsetY = windowHeight - btnRect.bottom;
scaleFactor = windowWidth / backdrop.width();
btn.attr('data-origin-bottom', btnRect.bottom);
btn.attr('data-origin-left', btnRect.left);
btn.attr('data-origin-width', btnRect.width);
// Set initial state
btn.addClass('active');
btn.attr('data-open', true);
btn.css({
'text-align': 'center',
width: '100%',
bottom: 0,
left: 0,
transform: 'translateX(' + offsetX + 'px)',
transition: 'none'
});
anchor.css({
transform: 'translateY(' + -offsetY + 'px)',
transition: 'none'
});
backdrop.css({
'background-color': fabColor
});
setTimeout(function() {
btn.css({
transform: '',
transition: 'transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s'
});
anchor.css({
overflow: 'visible',
transform: '',
transition: 'transform .2s'
});
setTimeout(function() {
btn.css({
overflow: 'hidden',
'background-color': fabColor
});
backdrop.css({
transform: 'scale(' + scaleFactor + ')',
transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)'
});
menu.find('> li > a').css({
opacity: 1
});
// Scroll to close.
$(window).on('scroll.fabToolbarClose', function() {
toolbarToFAB(btn);
$(window).off('scroll.fabToolbarClose');
$(document).off('click.fabToolbarClose');
});
$(document).on('click.fabToolbarClose', function(e) {
if (!$(e.target).closest(menu).length) {
toolbarToFAB(btn);
$(window).off('scroll.fabToolbarClose');
$(document).off('click.fabToolbarClose');
}
});
}, 100);
}, 0);
};
/**
* Transform toolbar back into FAB
* @param {Object} object jQuery object
*/
var toolbarToFAB = function(btn) {
if (btn.attr('data-open') !== "true") {
return;
}
var offsetX, offsetY, scaleFactor;
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var btnWidth = btn.attr('data-origin-width');
var btnBottom = btn.attr('data-origin-bottom');
var btnLeft = btn.attr('data-origin-left');
var anchor = btn.find('> .btn-floating').first();
var menu = btn.find('> ul').first();
var backdrop = btn.find('.fab-backdrop');
var fabColor = anchor.css('background-color');
offsetX = btnLeft - (windowWidth / 2) + (btnWidth / 2);
offsetY = windowHeight - btnBottom;
scaleFactor = windowWidth / backdrop.width();
// Hide backdrop
btn.removeClass('active');
btn.attr('data-open', false);
btn.css({
'background-color': 'transparent',
transition: 'none'
});
anchor.css({
transition: 'none'
});
backdrop.css({
transform: 'scale(0)',
'background-color': fabColor
});
menu.find('> li > a').css({
opacity: ''
});
setTimeout(function() {
backdrop.remove();
// Set initial state.
btn.css({
'text-align': '',
width: '',
bottom: '',
left: '',
overflow: '',
'background-color': '',
transform: 'translate3d(' + -offsetX + 'px,0,0)'
});
anchor.css({
overflow: '',
transform: 'translate3d(0,' + offsetY + 'px,0)'
});
setTimeout(function() {
btn.css({
transform: 'translate3d(0,0,0)',
transition: 'transform .2s'
});
anchor.css({
transform: 'translate3d(0,0,0)',
transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)'
});
}, 20);
}, 200);
};
}( jQuery ));

View file

@ -0,0 +1,36 @@
(function ($) {
$(document).ready(function() {
$(document).on('click.card', '.card', function (e) {
if ($(this).find('> .card-reveal').length) {
var $card = $(e.target).closest('.card');
if ($card.data('initialOverflow') === undefined) {
$card.data(
'initialOverflow',
$card.css('overflow') === undefined ? '' : $card.css('overflow')
);
}
if ($(e.target).is($('.card-reveal .card-title')) || $(e.target).is($('.card-reveal .card-title i'))) {
// Make Reveal animate down and display none
$(this).find('.card-reveal').velocity(
{translateY: 0}, {
duration: 225,
queue: false,
easing: 'easeInOutQuad',
complete: function() {
$(this).css({ display: 'none'});
$card.css('overflow', $card.data('initialOverflow'));
}
}
);
}
else if ($(e.target).is($('.card .activator')) ||
$(e.target).is($('.card .activator i')) ) {
$card.css('overflow', 'hidden');
$(this).find('.card-reveal').css({ display: 'block'}).velocity("stop", false).velocity({translateY: '-100%'}, {duration: 300, queue: false, easing: 'easeInOutQuad'});
}
}
});
});
}( jQuery ));

View file

@ -0,0 +1,565 @@
(function ($) {
var methods = {
init : function(options) {
var defaults = {
duration: 200, // ms
dist: -100, // zoom scale TODO: make this more intuitive as an option
shift: 0, // spacing for center image
padding: 0, // Padding between non center items
fullWidth: false, // Change to full width styles
indicators: false, // Toggle indicators
noWrap: false, // Don't wrap around and cycle through items.
onCycleTo: null // Callback for when a new slide is cycled to.
};
options = $.extend(defaults, options);
var namespace = Materialize.objectSelectorString($(this));
return this.each(function(i) {
var images, item_width, item_height, offset, center, pressed, dim, count,
reference, referenceY, amplitude, target, velocity, scrolling,
xform, frame, timestamp, ticker, dragged, vertical_dragged;
var $indicators = $('<ul class="indicators"></ul>');
var scrollingTimeout = null;
var oneTimeCallback = null;
// Initialize
var view = $(this);
var hasMultipleSlides = view.find('.carousel-item').length > 1;
var showIndicators = (view.attr('data-indicators') || options.indicators) && hasMultipleSlides;
var noWrap = (view.attr('data-no-wrap') || options.noWrap) || !hasMultipleSlides;
var uniqueNamespace = view.attr('data-namespace') || namespace+i;
view.attr('data-namespace', uniqueNamespace);
// Options
var setCarouselHeight = function(imageOnly) {
var firstSlide = view.find('.carousel-item.active').length ? view.find('.carousel-item.active').first() : view.find('.carousel-item').first();
var firstImage = firstSlide.find('img').first();
if (firstImage.length) {
if (firstImage[0].complete) {
// If image won't trigger the load event
var imageHeight = firstImage.height();
if (imageHeight > 0) {
view.css('height', firstImage.height());
} else {
// If image still has no height, use the natural dimensions to calculate
var naturalWidth = firstImage[0].naturalWidth;
var naturalHeight = firstImage[0].naturalHeight;
var adjustedHeight = (view.width() / naturalWidth) * naturalHeight;
view.css('height', adjustedHeight);
}
} else {
// Get height when image is loaded normally
firstImage.on('load', function(){
view.css('height', $(this).height());
});
}
} else if (!imageOnly) {
var slideHeight = firstSlide.height();
view.css('height', slideHeight);
}
};
if (options.fullWidth) {
options.dist = 0;
setCarouselHeight();
// Offset fixed items when indicators.
if (showIndicators) {
view.find('.carousel-fixed-item').addClass('with-indicators');
}
}
// Don't double initialize.
if (view.hasClass('initialized')) {
// Recalculate variables
$(window).trigger('resize');
// Redraw carousel.
view.trigger('carouselNext', [0.000001]);
return true;
}
view.addClass('initialized');
pressed = false;
offset = target = 0;
images = [];
item_width = view.find('.carousel-item').first().innerWidth();
item_height = view.find('.carousel-item').first().innerHeight();
dim = item_width * 2 + options.padding;
view.find('.carousel-item').each(function (i) {
images.push($(this)[0]);
if (showIndicators) {
var $indicator = $('<li class="indicator-item"></li>');
// Add active to first by default.
if (i === 0) {
$indicator.addClass('active');
}
// Handle clicks on indicators.
$indicator.click(function (e) {
e.stopPropagation();
var index = $(this).index();
cycleTo(index);
});
$indicators.append($indicator);
}
});
if (showIndicators) {
view.append($indicators);
}
count = images.length;
function setupEvents() {
if (typeof window.ontouchstart !== 'undefined') {
view.on('touchstart.carousel', tap);
view.on('touchmove.carousel', drag);
view.on('touchend.carousel', release);
}
view.on('mousedown.carousel', tap);
view.on('mousemove.carousel', drag);
view.on('mouseup.carousel', release);
view.on('mouseleave.carousel', release);
view.on('click.carousel', click);
}
function xpos(e) {
// touch event
if (e.targetTouches && (e.targetTouches.length >= 1)) {
return e.targetTouches[0].clientX;
}
// mouse event
return e.clientX;
}
function ypos(e) {
// touch event
if (e.targetTouches && (e.targetTouches.length >= 1)) {
return e.targetTouches[0].clientY;
}
// mouse event
return e.clientY;
}
function wrap(x) {
return (x >= count) ? (x % count) : (x < 0) ? wrap(count + (x % count)) : x;
}
function scroll(x) {
// Track scrolling state
scrolling = true;
if (!view.hasClass('scrolling')) {
view.addClass('scrolling');
}
if (scrollingTimeout != null) {
window.clearTimeout(scrollingTimeout);
}
scrollingTimeout = window.setTimeout(function() {
scrolling = false;
view.removeClass('scrolling');
}, options.duration);
// Start actual scroll
var i, half, delta, dir, tween, el, alignment, xTranslation;
var lastCenter = center;
offset = (typeof x === 'number') ? x : offset;
center = Math.floor((offset + dim / 2) / dim);
delta = offset - center * dim;
dir = (delta < 0) ? 1 : -1;
tween = -dir * delta * 2 / dim;
half = count >> 1;
if (!options.fullWidth) {
alignment = 'translateX(' + (view[0].clientWidth - item_width) / 2 + 'px) ';
alignment += 'translateY(' + (view[0].clientHeight - item_height) / 2 + 'px)';
} else {
alignment = 'translateX(0)';
}
// Set indicator active
if (showIndicators) {
var diff = (center % count);
var activeIndicator = $indicators.find('.indicator-item.active');
if (activeIndicator.index() !== diff) {
activeIndicator.removeClass('active');
$indicators.find('.indicator-item').eq(diff).addClass('active');
}
}
// center
// Don't show wrapped items.
if (!noWrap || (center >= 0 && center < count)) {
el = images[wrap(center)];
// Add active class to center item.
if (!$(el).hasClass('active')) {
view.find('.carousel-item').removeClass('active');
$(el).addClass('active');
}
el.style[xform] = alignment +
' translateX(' + (-delta / 2) + 'px)' +
' translateX(' + (dir * options.shift * tween * i) + 'px)' +
' translateZ(' + (options.dist * tween) + 'px)';
el.style.zIndex = 0;
if (options.fullWidth) { tweenedOpacity = 1; }
else { tweenedOpacity = 1 - 0.2 * tween; }
el.style.opacity = tweenedOpacity;
el.style.display = 'block';
}
for (i = 1; i <= half; ++i) {
// right side
if (options.fullWidth) {
zTranslation = options.dist;
tweenedOpacity = (i === half && delta < 0) ? 1 - tween : 1;
} else {
zTranslation = options.dist * (i * 2 + tween * dir);
tweenedOpacity = 1 - 0.2 * (i * 2 + tween * dir);
}
// Don't show wrapped items.
if (!noWrap || center + i < count) {
el = images[wrap(center + i)];
el.style[xform] = alignment +
' translateX(' + (options.shift + (dim * i - delta) / 2) + 'px)' +
' translateZ(' + zTranslation + 'px)';
el.style.zIndex = -i;
el.style.opacity = tweenedOpacity;
el.style.display = 'block';
}
// left side
if (options.fullWidth) {
zTranslation = options.dist;
tweenedOpacity = (i === half && delta > 0) ? 1 - tween : 1;
} else {
zTranslation = options.dist * (i * 2 - tween * dir);
tweenedOpacity = 1 - 0.2 * (i * 2 - tween * dir);
}
// Don't show wrapped items.
if (!noWrap || center - i >= 0) {
el = images[wrap(center - i)];
el.style[xform] = alignment +
' translateX(' + (-options.shift + (-dim * i - delta) / 2) + 'px)' +
' translateZ(' + zTranslation + 'px)';
el.style.zIndex = -i;
el.style.opacity = tweenedOpacity;
el.style.display = 'block';
}
}
// center
// Don't show wrapped items.
if (!noWrap || (center >= 0 && center < count)) {
el = images[wrap(center)];
el.style[xform] = alignment +
' translateX(' + (-delta / 2) + 'px)' +
' translateX(' + (dir * options.shift * tween) + 'px)' +
' translateZ(' + (options.dist * tween) + 'px)';
el.style.zIndex = 0;
if (options.fullWidth) { tweenedOpacity = 1; }
else { tweenedOpacity = 1 - 0.2 * tween; }
el.style.opacity = tweenedOpacity;
el.style.display = 'block';
}
// onCycleTo callback
if (lastCenter !== center &&
typeof(options.onCycleTo) === "function") {
var $curr_item = view.find('.carousel-item').eq(wrap(center));
options.onCycleTo.call(this, $curr_item, dragged);
}
// One time callback
if (typeof(oneTimeCallback) === "function") {
oneTimeCallback.call(this, $curr_item, dragged);
oneTimeCallback = null;
}
}
function track() {
var now, elapsed, delta, v;
now = Date.now();
elapsed = now - timestamp;
timestamp = now;
delta = offset - frame;
frame = offset;
v = 1000 * delta / (1 + elapsed);
velocity = 0.8 * v + 0.2 * velocity;
}
function autoScroll() {
var elapsed, delta;
if (amplitude) {
elapsed = Date.now() - timestamp;
delta = amplitude * Math.exp(-elapsed / options.duration);
if (delta > 2 || delta < -2) {
scroll(target - delta);
requestAnimationFrame(autoScroll);
} else {
scroll(target);
}
}
}
function click(e) {
// Disable clicks if carousel was dragged.
if (dragged) {
e.preventDefault();
e.stopPropagation();
return false;
} else if (!options.fullWidth) {
var clickedIndex = $(e.target).closest('.carousel-item').index();
var diff = wrap(center) - clickedIndex;
// Disable clicks if carousel was shifted by click
if (diff !== 0) {
e.preventDefault();
e.stopPropagation();
}
cycleTo(clickedIndex);
}
}
function cycleTo(n) {
var diff = (center % count) - n;
// Account for wraparound.
if (!noWrap) {
if (diff < 0) {
if (Math.abs(diff + count) < Math.abs(diff)) { diff += count; }
} else if (diff > 0) {
if (Math.abs(diff - count) < diff) { diff -= count; }
}
}
// Call prev or next accordingly.
if (diff < 0) {
view.trigger('carouselNext', [Math.abs(diff)]);
} else if (diff > 0) {
view.trigger('carouselPrev', [diff]);
}
}
function tap(e) {
// Fixes firefox draggable image bug
if (e.type === 'mousedown' && $(e.target).is('img')) {
e.preventDefault();
}
pressed = true;
dragged = false;
vertical_dragged = false;
reference = xpos(e);
referenceY = ypos(e);
velocity = amplitude = 0;
frame = offset;
timestamp = Date.now();
clearInterval(ticker);
ticker = setInterval(track, 100);
}
function drag(e) {
var x, delta, deltaY;
if (pressed) {
x = xpos(e);
y = ypos(e);
delta = reference - x;
deltaY = Math.abs(referenceY - y);
if (deltaY < 30 && !vertical_dragged) {
// If vertical scrolling don't allow dragging.
if (delta > 2 || delta < -2) {
dragged = true;
reference = x;
scroll(offset + delta);
}
} else if (dragged) {
// If dragging don't allow vertical scroll.
e.preventDefault();
e.stopPropagation();
return false;
} else {
// Vertical scrolling.
vertical_dragged = true;
}
}
if (dragged) {
// If dragging don't allow vertical scroll.
e.preventDefault();
e.stopPropagation();
return false;
}
}
function release(e) {
if (pressed) {
pressed = false;
} else {
return;
}
clearInterval(ticker);
target = offset;
if (velocity > 10 || velocity < -10) {
amplitude = 0.9 * velocity;
target = offset + amplitude;
}
target = Math.round(target / dim) * dim;
// No wrap of items.
if (noWrap) {
if (target >= dim * (count - 1)) {
target = dim * (count - 1);
} else if (target < 0) {
target = 0;
}
}
amplitude = target - offset;
timestamp = Date.now();
requestAnimationFrame(autoScroll);
if (dragged) {
e.preventDefault();
e.stopPropagation();
}
return false;
}
xform = 'transform';
['webkit', 'Moz', 'O', 'ms'].every(function (prefix) {
var e = prefix + 'Transform';
if (typeof document.body.style[e] !== 'undefined') {
xform = e;
return false;
}
return true;
});
var throttledResize = Materialize.throttle(function() {
if (options.fullWidth) {
item_width = view.find('.carousel-item').first().innerWidth();
var imageHeight = view.find('.carousel-item.active').height();
dim = item_width * 2 + options.padding;
offset = center * 2 * item_width;
target = offset;
setCarouselHeight(true);
} else {
scroll();
}
}, 200);
$(window)
.off('resize.carousel-'+uniqueNamespace)
.on('resize.carousel-'+uniqueNamespace, throttledResize);
setupEvents();
scroll(offset);
$(this).on('carouselNext', function(e, n, callback) {
if (n === undefined) {
n = 1;
}
if (typeof(callback) === "function") {
oneTimeCallback = callback;
}
target = (dim * Math.round(offset / dim)) + (dim * n);
if (offset !== target) {
amplitude = target - offset;
timestamp = Date.now();
requestAnimationFrame(autoScroll);
}
});
$(this).on('carouselPrev', function(e, n, callback) {
if (n === undefined) {
n = 1;
}
if (typeof(callback) === "function") {
oneTimeCallback = callback;
}
target = (dim * Math.round(offset / dim)) - (dim * n);
if (offset !== target) {
amplitude = target - offset;
timestamp = Date.now();
requestAnimationFrame(autoScroll);
}
});
$(this).on('carouselSet', function(e, n, callback) {
if (n === undefined) {
n = 0;
}
if (typeof(callback) === "function") {
oneTimeCallback = callback;
}
cycleTo(n);
});
});
},
next : function(n, callback) {
$(this).trigger('carouselNext', [n, callback]);
},
prev : function(n, callback) {
$(this).trigger('carouselPrev', [n, callback]);
},
set : function(n, callback) {
$(this).trigger('carouselSet', [n, callback]);
},
destroy : function() {
var uniqueNamespace = $(this).attr('data-namespace');
$(this).removeAttr('data-namespace');
$(this).removeClass('initialized');
$(this).find('.indicators').remove();
// Remove event handlers
$(this).off('carouselNext carouselPrev carouselSet');
$(window).off('resize.carousel-'+uniqueNamespace);
if (typeof window.ontouchstart !== 'undefined') {
$(this).off('touchstart.carousel touchmove.carousel touchend.carousel');
}
$(this).off('mousedown.carousel mousemove.carousel mouseup.carousel mouseleave.carousel click.carousel');
}
};
$.fn.carousel = function(methodOrOptions) {
if ( methods[methodOrOptions] ) {
return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
// Default to "init"
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.carousel' );
}
}; // Plugin end
}( jQuery ));

View file

@ -0,0 +1,72 @@
(function ($) {
$.fn.characterCounter = function(){
return this.each(function(){
var $input = $(this);
var $counterElement = $input.parent().find('span[class="character-counter"]');
// character counter has already been added appended to the parent container
if ($counterElement.length) {
return;
}
var itHasLengthAttribute = $input.attr('data-length') !== undefined;
if(itHasLengthAttribute){
$input.on('input', updateCounter);
$input.on('focus', updateCounter);
$input.on('blur', removeCounterElement);
addCounterElement($input);
}
});
};
function updateCounter(){
var maxLength = +$(this).attr('data-length'),
actualLength = +$(this).val().length,
isValidLength = actualLength <= maxLength;
$(this).parent().find('span[class="character-counter"]')
.html( actualLength + '/' + maxLength);
addInputStyle(isValidLength, $(this));
}
function addCounterElement($input) {
var $counterElement = $input.parent().find('span[class="character-counter"]');
if ($counterElement.length) {
return;
}
$counterElement = $('<span/>')
.addClass('character-counter')
.css('float','right')
.css('font-size','12px')
.css('height', 1);
$input.parent().append($counterElement);
}
function removeCounterElement(){
$(this).parent().find('span[class="character-counter"]').html('');
}
function addInputStyle(isValidLength, $input){
var inputHasInvalidClass = $input.hasClass('invalid');
if (isValidLength && inputHasInvalidClass) {
$input.removeClass('invalid');
}
else if(!isValidLength && !inputHasInvalidClass){
$input.removeClass('valid');
$input.addClass('invalid');
}
}
$(document).ready(function(){
$('input, textarea').characterCounter();
});
}( jQuery ));

View file

@ -0,0 +1,318 @@
(function ($) {
var materialChipsDefaults = {
data: [],
placeholder: '',
secondaryPlaceholder: '',
autocompleteOptions: {},
};
$(document).ready(function() {
// Handle removal of static chips.
$(document).on('click', '.chip .close', function(e){
var $chips = $(this).closest('.chips');
if ($chips.attr('data-initialized')) {
return;
}
$(this).closest('.chip').remove();
});
});
$.fn.material_chip = function (options) {
var self = this;
this.$el = $(this);
this.$document = $(document);
this.SELS = {
CHIPS: '.chips',
CHIP: '.chip',
INPUT: 'input',
DELETE: '.material-icons',
SELECTED_CHIP: '.selected',
};
if ('data' === options) {
return this.$el.data('chips');
}
var curr_options = $.extend({}, materialChipsDefaults, options);
self.hasAutocomplete = !$.isEmptyObject(curr_options.autocompleteOptions.data);
// Initialize
this.init = function() {
var i = 0;
var chips;
self.$el.each(function(){
var $chips = $(this);
var chipId = Materialize.guid();
self.chipId = chipId;
if (!curr_options.data || !(curr_options.data instanceof Array)) {
curr_options.data = [];
}
$chips.data('chips', curr_options.data);
$chips.attr('data-index', i);
$chips.attr('data-initialized', true);
if (!$chips.hasClass(self.SELS.CHIPS)) {
$chips.addClass('chips');
}
self.chips($chips, chipId);
i++;
});
};
this.handleEvents = function() {
var SELS = self.SELS;
self.$document.off('click.chips-focus', SELS.CHIPS).on('click.chips-focus', SELS.CHIPS, function(e){
$(e.target).find(SELS.INPUT).focus();
});
self.$document.off('click.chips-select', SELS.CHIP).on('click.chips-select', SELS.CHIP, function(e){
var $chip = $(e.target);
if ($chip.length) {
var wasSelected = $chip.hasClass('selected');
var $chips = $chip.closest(SELS.CHIPS);
$(SELS.CHIP).removeClass('selected');
if (!wasSelected) {
self.selectChip($chip.index(), $chips);
}
}
});
self.$document.off('keydown.chips').on('keydown.chips', function(e){
if ($(e.target).is('input, textarea')) {
return;
}
// delete
var $chip = self.$document.find(SELS.CHIP + SELS.SELECTED_CHIP);
var $chips = $chip.closest(SELS.CHIPS);
var length = $chip.siblings(SELS.CHIP).length;
var index;
if (!$chip.length) {
return;
}
if (e.which === 8 || e.which === 46) {
e.preventDefault();
index = $chip.index();
self.deleteChip(index, $chips);
var selectIndex = null;
if ((index + 1) < length) {
selectIndex = index;
} else if (index === length || (index + 1) === length) {
selectIndex = length - 1;
}
if (selectIndex < 0) selectIndex = null;
if (null !== selectIndex) {
self.selectChip(selectIndex, $chips);
}
if (!length) $chips.find('input').focus();
// left
} else if (e.which === 37) {
index = $chip.index() - 1;
if (index < 0) {
return;
}
$(SELS.CHIP).removeClass('selected');
self.selectChip(index, $chips);
// right
} else if (e.which === 39) {
index = $chip.index() + 1;
$(SELS.CHIP).removeClass('selected');
if (index > length) {
$chips.find('input').focus();
return;
}
self.selectChip(index, $chips);
}
});
self.$document.off('focusin.chips', SELS.CHIPS + ' ' + SELS.INPUT).on('focusin.chips', SELS.CHIPS + ' ' + SELS.INPUT, function(e){
var $currChips = $(e.target).closest(SELS.CHIPS);
$currChips.addClass('focus');
$currChips.siblings('label, .prefix').addClass('active');
$(SELS.CHIP).removeClass('selected');
});
self.$document.off('focusout.chips', SELS.CHIPS + ' ' + SELS.INPUT).on('focusout.chips', SELS.CHIPS + ' ' + SELS.INPUT, function(e){
var $currChips = $(e.target).closest(SELS.CHIPS);
$currChips.removeClass('focus');
// Remove active if empty
if ($currChips.data('chips') === undefined || !$currChips.data('chips').length) {
$currChips.siblings('label').removeClass('active');
}
$currChips.siblings('.prefix').removeClass('active');
});
self.$document.off('keydown.chips-add', SELS.CHIPS + ' ' + SELS.INPUT).on('keydown.chips-add', SELS.CHIPS + ' ' + SELS.INPUT, function(e){
var $target = $(e.target);
var $chips = $target.closest(SELS.CHIPS);
var chipsLength = $chips.children(SELS.CHIP).length;
// enter
if (13 === e.which) {
// Override enter if autocompleting.
if (self.hasAutocomplete &&
$chips.find('.autocomplete-content.dropdown-content').length &&
$chips.find('.autocomplete-content.dropdown-content').children().length) {
return;
}
e.preventDefault();
self.addChip({tag: $target.val()}, $chips);
$target.val('');
return;
}
// delete or left
if ((8 === e.keyCode || 37 === e.keyCode) && '' === $target.val() && chipsLength) {
e.preventDefault();
self.selectChip(chipsLength - 1, $chips);
$target.blur();
return;
}
});
// Click on delete icon in chip.
self.$document.off('click.chips-delete', SELS.CHIPS + ' ' + SELS.DELETE).on('click.chips-delete', SELS.CHIPS + ' ' + SELS.DELETE, function(e) {
var $target = $(e.target);
var $chips = $target.closest(SELS.CHIPS);
var $chip = $target.closest(SELS.CHIP);
e.stopPropagation();
self.deleteChip($chip.index(), $chips);
$chips.find('input').focus();
});
};
this.chips = function($chips, chipId) {
$chips.empty();
$chips.data('chips').forEach(function(elem){
$chips.append(self.renderChip(elem));
});
$chips.append($('<input id="' + chipId +'" class="input" placeholder="">'));
self.setPlaceholder($chips);
// Set for attribute for label
var label = $chips.next('label');
if (label.length) {
label.attr('for', chipId);
if ($chips.data('chips')!== undefined && $chips.data('chips').length) {
label.addClass('active');
}
}
// Setup autocomplete if needed.
var input = $('#' + chipId);
if (self.hasAutocomplete) {
curr_options.autocompleteOptions.onAutocomplete = function(val) {
self.addChip({tag: val}, $chips);
input.val('');
input.focus();
}
input.autocomplete(curr_options.autocompleteOptions);
}
};
/**
* Render chip jQuery element.
* @param {Object} elem
* @return {jQuery}
*/
this.renderChip = function(elem) {
if (!elem.tag) return;
var $renderedChip = $('<div class="chip"></div>');
$renderedChip.text(elem.tag);
if (elem.image) {
$renderedChip.prepend($('<img />').attr('src', elem.image))
}
$renderedChip.append($('<i class="material-icons close">close</i>'));
return $renderedChip;
};
this.setPlaceholder = function($chips) {
if (($chips.data('chips') !== undefined && !$chips.data('chips').length) && curr_options.placeholder) {
$chips.find('input').prop('placeholder', curr_options.placeholder);
} else if (($chips.data('chips') === undefined || !!$chips.data('chips').length) && curr_options.secondaryPlaceholder) {
$chips.find('input').prop('placeholder', curr_options.secondaryPlaceholder);
}
};
this.isValid = function($chips, elem) {
var chips = $chips.data('chips');
var exists = false;
for (var i=0; i < chips.length; i++) {
if (chips[i].tag === elem.tag) {
exists = true;
return;
}
}
return '' !== elem.tag && !exists;
};
this.addChip = function(elem, $chips) {
if (!self.isValid($chips, elem)) {
return;
}
var $renderedChip = self.renderChip(elem);
var newData = [];
var oldData = $chips.data('chips');
for (var i = 0; i < oldData.length; i++) {
newData.push(oldData[i]);
}
newData.push(elem);
$chips.data('chips', newData);
$renderedChip.insertBefore($chips.find('input'));
$chips.trigger('chip.add', elem);
self.setPlaceholder($chips);
};
this.deleteChip = function(chipIndex, $chips) {
var chip = $chips.data('chips')[chipIndex];
$chips.find('.chip').eq(chipIndex).remove();
var newData = [];
var oldData = $chips.data('chips');
for (var i = 0; i < oldData.length; i++) {
if (i !== chipIndex) {
newData.push(oldData[i]);
}
}
$chips.data('chips', newData);
$chips.trigger('chip.delete', chip);
self.setPlaceholder($chips);
};
this.selectChip = function(chipIndex, $chips) {
var $chip = $chips.find('.chip').eq(chipIndex);
if ($chip && false === $chip.hasClass('selected')) {
$chip.addClass('selected');
$chips.trigger('chip.select', $chips.data('chips')[chipIndex]);
}
};
this.getChipsElement = function(index, $chips) {
return $chips.eq(index);
};
// init
this.init();
this.handleEvents();
};
}( jQuery ));

View file

@ -0,0 +1,183 @@
(function ($) {
$.fn.collapsible = function(options, methodParam) {
var defaults = {
accordion: undefined,
onOpen: undefined,
onClose: undefined
};
var methodName = options;
options = $.extend(defaults, options);
return this.each(function() {
var $this = $(this);
var $panel_headers = $(this).find('> li > .collapsible-header');
var collapsible_type = $this.data("collapsible");
/****************
Helper Functions
****************/
// Accordion Open
function accordionOpen(object) {
$panel_headers = $this.find('> li > .collapsible-header');
if (object.hasClass('active')) {
object.parent().addClass('active');
}
else {
object.parent().removeClass('active');
}
if (object.parent().hasClass('active')){
object.siblings('.collapsible-body').stop(true,false).slideDown({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}});
}
else{
object.siblings('.collapsible-body').stop(true,false).slideUp({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}});
}
$panel_headers.not(object).removeClass('active').parent().removeClass('active');
// Close previously open accordion elements.
$panel_headers.not(object).parent().children('.collapsible-body').stop(true,false).each(function() {
if ($(this).is(':visible')) {
$(this).slideUp({
duration: 350,
easing: "easeOutQuart",
queue: false,
complete:
function() {
$(this).css('height', '');
execCallbacks($(this).siblings('.collapsible-header'));
}
});
}
});
}
// Expandable Open
function expandableOpen(object) {
if (object.hasClass('active')) {
object.parent().addClass('active');
}
else {
object.parent().removeClass('active');
}
if (object.parent().hasClass('active')){
object.siblings('.collapsible-body').stop(true,false).slideDown({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}});
}
else {
object.siblings('.collapsible-body').stop(true,false).slideUp({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}});
}
}
// Open collapsible. object: .collapsible-header
function collapsibleOpen(object, noToggle) {
if (!noToggle) {
object.toggleClass('active');
}
if (options.accordion || collapsible_type === "accordion" || collapsible_type === undefined) { // Handle Accordion
accordionOpen(object);
} else { // Handle Expandables
expandableOpen(object);
}
execCallbacks(object);
}
// Handle callbacks
function execCallbacks(object) {
if (object.hasClass('active')) {
if (typeof(options.onOpen) === "function") {
options.onOpen.call(this, object.parent());
}
} else {
if (typeof(options.onClose) === "function") {
options.onClose.call(this, object.parent());
}
}
}
/**
* Check if object is children of panel header
* @param {Object} object Jquery object
* @return {Boolean} true if it is children
*/
function isChildrenOfPanelHeader(object) {
var panelHeader = getPanelHeader(object);
return panelHeader.length > 0;
}
/**
* Get panel header from a children element
* @param {Object} object Jquery object
* @return {Object} panel header object
*/
function getPanelHeader(object) {
return object.closest('li > .collapsible-header');
}
// Turn off any existing event handlers
function removeEventHandlers() {
$this.off('click.collapse', '> li > .collapsible-header');
}
/***** End Helper Functions *****/
// Methods
if (methodName === 'destroy') {
removeEventHandlers();
return;
} else if (methodParam >= 0 &&
methodParam < $panel_headers.length) {
var $curr_header = $panel_headers.eq(methodParam);
if ($curr_header.length &&
(methodName === 'open' ||
(methodName === 'close' &&
$curr_header.hasClass('active')))) {
collapsibleOpen($curr_header);
}
return;
}
removeEventHandlers();
// Add click handler to only direct collapsible header children
$this.on('click.collapse', '> li > .collapsible-header', function(e) {
var element = $(e.target);
if (isChildrenOfPanelHeader(element)) {
element = getPanelHeader(element);
}
collapsibleOpen(element);
});
// Open first active
if (options.accordion || collapsible_type === "accordion" || collapsible_type === undefined) { // Handle Accordion
collapsibleOpen($panel_headers.filter('.active').first(), true);
} else { // Handle Expandables
$panel_headers.filter('.active').each(function() {
collapsibleOpen($(this), true);
});
}
});
};
$(document).ready(function(){
$('.collapsible').collapsible();
});
}( jQuery ));

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,695 @@
/*!
* ClockPicker v0.0.7 (http://weareoutman.github.io/clockpicker/)
* Copyright 2014 Wang Shenwei.
* Licensed under MIT (https://github.com/weareoutman/clockpicker/blob/gh-pages/LICENSE)
*
* Further modified
* Copyright 2015 Ching Yaw Hao.
*/
(function($){
var $win = $(window),
$doc = $(document);
// Can I use inline svg ?
var svgNS = 'http://www.w3.org/2000/svg',
svgSupported = 'SVGAngle' in window && (function() {
var supported,
el = document.createElement('div');
el.innerHTML = '<svg/>';
supported = (el.firstChild && el.firstChild.namespaceURI) == svgNS;
el.innerHTML = '';
return supported;
})();
// Can I use transition ?
var transitionSupported = (function() {
var style = document.createElement('div').style;
return 'transition' in style ||
'WebkitTransition' in style ||
'MozTransition' in style ||
'msTransition' in style ||
'OTransition' in style;
})();
// Listen touch events in touch screen device, instead of mouse events in desktop.
var touchSupported = 'ontouchstart' in window,
mousedownEvent = 'mousedown' + ( touchSupported ? ' touchstart' : ''),
mousemoveEvent = 'mousemove.clockpicker' + ( touchSupported ? ' touchmove.clockpicker' : ''),
mouseupEvent = 'mouseup.clockpicker' + ( touchSupported ? ' touchend.clockpicker' : '');
// Vibrate the device if supported
var vibrate = navigator.vibrate ? 'vibrate' : navigator.webkitVibrate ? 'webkitVibrate' : null;
function createSvgElement(name) {
return document.createElementNS(svgNS, name);
}
function leadingZero(num) {
return (num < 10 ? '0' : '') + num;
}
// Get a unique id
var idCounter = 0;
function uniqueId(prefix) {
var id = ++idCounter + '';
return prefix ? prefix + id : id;
}
// Clock size
var dialRadius = 135,
outerRadius = 105,
// innerRadius = 80 on 12 hour clock
innerRadius = 70,
tickRadius = 20,
diameter = dialRadius * 2,
duration = transitionSupported ? 350 : 1;
// Popover template
var tpl = [
'<div class="clockpicker picker">',
'<div class="picker__holder">',
'<div class="picker__frame">',
'<div class="picker__wrap">',
'<div class="picker__box">',
'<div class="picker__date-display">',
'<div class="clockpicker-display">',
'<div class="clockpicker-display-column">',
'<span class="clockpicker-span-hours text-primary"></span>',
':',
'<span class="clockpicker-span-minutes"></span>',
'</div>',
'<div class="clockpicker-display-column clockpicker-display-am-pm">',
'<div class="clockpicker-span-am-pm"></div>',
'</div>',
'</div>',
'</div>',
'<div class="picker__container__wrapper">',
'<div class="picker__calendar-container">',
'<div class="clockpicker-plate">',
'<div class="clockpicker-canvas"></div>',
'<div class="clockpicker-dial clockpicker-hours"></div>',
'<div class="clockpicker-dial clockpicker-minutes clockpicker-dial-out"></div>',
'</div>',
'<div class="clockpicker-am-pm-block">',
'</div>',
'</div>',
'<div class="picker__footer">',
'</div>',
'</div>',
'</div>',
'</div>',
'</div>',
'</div>',
'</div>'
].join('');
// ClockPicker
function ClockPicker(element, options) {
var popover = $(tpl),
plate = popover.find('.clockpicker-plate'),
holder = popover.find('.picker__holder'),
hoursView = popover.find('.clockpicker-hours'),
minutesView = popover.find('.clockpicker-minutes'),
amPmBlock = popover.find('.clockpicker-am-pm-block'),
isInput = element.prop('tagName') === 'INPUT',
input = isInput ? element : element.find('input'),
label = $("label[for=" + input.attr("id") + "]"),
self = this;
this.id = uniqueId('cp');
this.element = element;
this.holder = holder;
this.options = options;
this.isAppended = false;
this.isShown = false;
this.currentView = 'hours';
this.isInput = isInput;
this.input = input;
this.label = label;
this.popover = popover;
this.plate = plate;
this.hoursView = hoursView;
this.minutesView = minutesView;
this.amPmBlock = amPmBlock;
this.spanHours = popover.find('.clockpicker-span-hours');
this.spanMinutes = popover.find('.clockpicker-span-minutes');
this.spanAmPm = popover.find('.clockpicker-span-am-pm');
this.footer = popover.find('.picker__footer');
this.amOrPm = "PM";
// Setup for for 12 hour clock if option is selected
if (options.twelvehour) {
if (!options.ampmclickable) {
this.spanAmPm.empty();
$('<div id="click-am">AM</div>').appendTo(this.spanAmPm);
$('<div id="click-pm">PM</div>').appendTo(this.spanAmPm);
}
else {
this.spanAmPm.empty();
$('<div id="click-am">AM</div>').on("click", function() {
self.spanAmPm.children('#click-am').addClass("text-primary");
self.spanAmPm.children('#click-pm').removeClass("text-primary");
self.amOrPm = "AM";
}).appendTo(this.spanAmPm);
$('<div id="click-pm">PM</div>').on("click", function() {
self.spanAmPm.children('#click-pm').addClass("text-primary");
self.spanAmPm.children('#click-am').removeClass("text-primary");
self.amOrPm = 'PM';
}).appendTo(this.spanAmPm);
}
}
// Add buttons to footer
$('<button type="button" class="btn-flat picker__clear" tabindex="' + (options.twelvehour? '3' : '1') + '">' + options.cleartext + '</button>').click($.proxy(this.clear, this)).appendTo(this.footer);
$('<button type="button" class="btn-flat picker__close" tabindex="' + (options.twelvehour? '3' : '1') + '">' + options.canceltext + '</button>').click($.proxy(this.hide, this)).appendTo(this.footer);
$('<button type="button" class="btn-flat picker__close" tabindex="' + (options.twelvehour? '3' : '1') + '">' + options.donetext + '</button>').click($.proxy(this.done, this)).appendTo(this.footer);
this.spanHours.click($.proxy(this.toggleView, this, 'hours'));
this.spanMinutes.click($.proxy(this.toggleView, this, 'minutes'));
// Show or toggle
input.on('focus.clockpicker click.clockpicker', $.proxy(this.show, this));
// Build ticks
var tickTpl = $('<div class="clockpicker-tick"></div>'),
i, tick, radian, radius;
// Hours view
if (options.twelvehour) {
for (i = 1; i < 13; i += 1) {
tick = tickTpl.clone();
radian = i / 6 * Math.PI;
radius = outerRadius;
tick.css({
left: dialRadius + Math.sin(radian) * radius - tickRadius,
top: dialRadius - Math.cos(radian) * radius - tickRadius
});
tick.html(i === 0 ? '00' : i);
hoursView.append(tick);
tick.on(mousedownEvent, mousedown);
}
} else {
for (i = 0; i < 24; i += 1) {
tick = tickTpl.clone();
radian = i / 6 * Math.PI;
var inner = i > 0 && i < 13;
radius = inner ? innerRadius : outerRadius;
tick.css({
left: dialRadius + Math.sin(radian) * radius - tickRadius,
top: dialRadius - Math.cos(radian) * radius - tickRadius
});
tick.html(i === 0 ? '00' : i);
hoursView.append(tick);
tick.on(mousedownEvent, mousedown);
}
}
// Minutes view
for (i = 0; i < 60; i += 5) {
tick = tickTpl.clone();
radian = i / 30 * Math.PI;
tick.css({
left: dialRadius + Math.sin(radian) * outerRadius - tickRadius,
top: dialRadius - Math.cos(radian) * outerRadius - tickRadius
});
tick.html(leadingZero(i));
minutesView.append(tick);
tick.on(mousedownEvent, mousedown);
}
// Clicking on minutes view space
plate.on(mousedownEvent, function(e) {
if ($(e.target).closest('.clockpicker-tick').length === 0) {
mousedown(e, true);
}
});
// Mousedown or touchstart
function mousedown(e, space) {
var offset = plate.offset(),
isTouch = /^touch/.test(e.type),
x0 = offset.left + dialRadius,
y0 = offset.top + dialRadius,
dx = (isTouch ? e.originalEvent.touches[0] : e).pageX - x0,
dy = (isTouch ? e.originalEvent.touches[0] : e).pageY - y0,
z = Math.sqrt(dx * dx + dy * dy),
moved = false;
// When clicking on minutes view space, check the mouse position
if (space && (z < outerRadius - tickRadius || z > outerRadius + tickRadius)) {
return;
}
e.preventDefault();
// Set cursor style of body after 200ms
var movingTimer = setTimeout(function(){
self.popover.addClass('clockpicker-moving');
}, 200);
// Clock
self.setHand(dx, dy, !space, true);
// Mousemove on document
$doc.off(mousemoveEvent).on(mousemoveEvent, function(e){
e.preventDefault();
var isTouch = /^touch/.test(e.type),
x = (isTouch ? e.originalEvent.touches[0] : e).pageX - x0,
y = (isTouch ? e.originalEvent.touches[0] : e).pageY - y0;
if (! moved && x === dx && y === dy) {
// Clicking in chrome on windows will trigger a mousemove event
return;
}
moved = true;
self.setHand(x, y, false, true);
});
// Mouseup on document
$doc.off(mouseupEvent).on(mouseupEvent, function(e) {
$doc.off(mouseupEvent);
e.preventDefault();
var isTouch = /^touch/.test(e.type),
x = (isTouch ? e.originalEvent.changedTouches[0] : e).pageX - x0,
y = (isTouch ? e.originalEvent.changedTouches[0] : e).pageY - y0;
if ((space || moved) && x === dx && y === dy) {
self.setHand(x, y);
}
if (self.currentView === 'hours') {
self.toggleView('minutes', duration / 2);
} else if (options.autoclose) {
self.minutesView.addClass('clockpicker-dial-out');
setTimeout(function(){
self.done();
}, duration / 2);
}
plate.prepend(canvas);
// Reset cursor style of body
clearTimeout(movingTimer);
self.popover.removeClass('clockpicker-moving');
// Unbind mousemove event
$doc.off(mousemoveEvent);
});
}
if (svgSupported) {
// Draw clock hands and others
var canvas = popover.find('.clockpicker-canvas'),
svg = createSvgElement('svg');
svg.setAttribute('class', 'clockpicker-svg');
svg.setAttribute('width', diameter);
svg.setAttribute('height', diameter);
var g = createSvgElement('g');
g.setAttribute('transform', 'translate(' + dialRadius + ',' + dialRadius + ')');
var bearing = createSvgElement('circle');
bearing.setAttribute('class', 'clockpicker-canvas-bearing');
bearing.setAttribute('cx', 0);
bearing.setAttribute('cy', 0);
bearing.setAttribute('r', 4);
var hand = createSvgElement('line');
hand.setAttribute('x1', 0);
hand.setAttribute('y1', 0);
var bg = createSvgElement('circle');
bg.setAttribute('class', 'clockpicker-canvas-bg');
bg.setAttribute('r', tickRadius);
g.appendChild(hand);
g.appendChild(bg);
g.appendChild(bearing);
svg.appendChild(g);
canvas.append(svg);
this.hand = hand;
this.bg = bg;
this.bearing = bearing;
this.g = g;
this.canvas = canvas;
}
raiseCallback(this.options.init);
}
function raiseCallback(callbackFunction) {
if (callbackFunction && typeof callbackFunction === "function")
callbackFunction();
}
// Default options
ClockPicker.DEFAULTS = {
'default': '', // default time, 'now' or '13:14' e.g.
fromnow: 0, // set default time to * milliseconds from now (using with default = 'now')
donetext: 'Ok', // done button text
cleartext: 'Clear',
canceltext: 'Cancel',
autoclose: false, // auto close when minute is selected
ampmclickable: true, // set am/pm button on itself
darktheme: false, // set to dark theme
twelvehour: true, // change to 12 hour AM/PM clock from 24 hour
vibrate: true // vibrate the device when dragging clock hand
};
// Show or hide popover
ClockPicker.prototype.toggle = function() {
this[this.isShown ? 'hide' : 'show']();
};
// Set popover position
ClockPicker.prototype.locate = function() {
var element = this.element,
popover = this.popover,
offset = element.offset(),
width = element.outerWidth(),
height = element.outerHeight(),
align = this.options.align,
self = this;
popover.show();
};
// Show popover
ClockPicker.prototype.show = function(e){
// Not show again
if (this.isShown) {
return;
}
raiseCallback(this.options.beforeShow);
$(':input').each(function() {
$(this).attr('tabindex', -1);
})
var self = this;
// Initialize
this.input.blur();
this.popover.addClass('picker--opened');
this.input.addClass('picker__input picker__input--active');
$(document.body).css('overflow', 'hidden');
// Get the time
var value = ((this.input.prop('value') || this.options['default'] || '') + '').split(':');
if (this.options.twelvehour && !(typeof value[1] === 'undefined')) {
if (value[1].indexOf("AM") > 0){
this.amOrPm = 'AM';
} else {
this.amOrPm = 'PM';
}
value[1] = value[1].replace("AM", "").replace("PM", "");
}
if (value[0] === 'now') {
var now = new Date(+ new Date() + this.options.fromnow);
value = [
now.getHours(),
now.getMinutes()
];
if (this.options.twelvehour) {
this.amOrPm = value[0] >= 12 && value[0] < 24 ? 'PM' : 'AM';
}
}
this.hours = + value[0] || 0;
this.minutes = + value[1] || 0;
this.spanHours.html(this.hours);
this.spanMinutes.html(leadingZero(this.minutes));
if (!this.isAppended) {
// Append popover to input by default
var containerEl = document.querySelector(this.options.container);
if (this.options.container && containerEl) {
containerEl.appendChild(this.popover[0]);
} else {
this.popover.insertAfter(this.input);
}
if (this.options.twelvehour) {
if (this.amOrPm === 'PM'){
this.spanAmPm.children('#click-pm').addClass("text-primary");
this.spanAmPm.children('#click-am').removeClass("text-primary");
} else {
this.spanAmPm.children('#click-am').addClass("text-primary");
this.spanAmPm.children('#click-pm').removeClass("text-primary");
}
}
// Reset position when resize
$win.on('resize.clockpicker' + this.id, function() {
if (self.isShown) {
self.locate();
}
});
this.isAppended = true;
}
// Toggle to hours view
this.toggleView('hours');
// Set position
this.locate();
this.isShown = true;
// Hide when clicking or tabbing on any element except the clock and input
$doc.on('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id, function(e) {
var target = $(e.target);
if (target.closest(self.popover.find('.picker__wrap')).length === 0 && target.closest(self.input).length === 0) {
self.hide();
}
});
// Hide when ESC is pressed
$doc.on('keyup.clockpicker.' + this.id, function(e){
if (e.keyCode === 27) {
self.hide();
}
});
raiseCallback(this.options.afterShow);
};
// Hide popover
ClockPicker.prototype.hide = function() {
raiseCallback(this.options.beforeHide);
this.input.removeClass('picker__input picker__input--active');
this.popover.removeClass('picker--opened');
$(document.body).css('overflow', 'visible');
this.isShown = false;
$(':input').each(function(index) {
$(this).attr('tabindex', index + 1);
});
// Unbinding events on document
$doc.off('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id);
$doc.off('keyup.clockpicker.' + this.id);
this.popover.hide();
raiseCallback(this.options.afterHide);
};
// Toggle to hours or minutes view
ClockPicker.prototype.toggleView = function(view, delay) {
var raiseAfterHourSelect = false;
if (view === 'minutes' && $(this.hoursView).css("visibility") === "visible") {
raiseCallback(this.options.beforeHourSelect);
raiseAfterHourSelect = true;
}
var isHours = view === 'hours',
nextView = isHours ? this.hoursView : this.minutesView,
hideView = isHours ? this.minutesView : this.hoursView;
this.currentView = view;
this.spanHours.toggleClass('text-primary', isHours);
this.spanMinutes.toggleClass('text-primary', ! isHours);
// Let's make transitions
hideView.addClass('clockpicker-dial-out');
nextView.css('visibility', 'visible').removeClass('clockpicker-dial-out');
// Reset clock hand
this.resetClock(delay);
// After transitions ended
clearTimeout(this.toggleViewTimer);
this.toggleViewTimer = setTimeout(function() {
hideView.css('visibility', 'hidden');
}, duration);
if (raiseAfterHourSelect) {
raiseCallback(this.options.afterHourSelect);
}
};
// Reset clock hand
ClockPicker.prototype.resetClock = function(delay) {
var view = this.currentView,
value = this[view],
isHours = view === 'hours',
unit = Math.PI / (isHours ? 6 : 30),
radian = value * unit,
radius = isHours && value > 0 && value < 13 ? innerRadius : outerRadius,
x = Math.sin(radian) * radius,
y = - Math.cos(radian) * radius,
self = this;
if (svgSupported && delay) {
self.canvas.addClass('clockpicker-canvas-out');
setTimeout(function(){
self.canvas.removeClass('clockpicker-canvas-out');
self.setHand(x, y);
}, delay);
} else
this.setHand(x, y);
};
// Set clock hand to (x, y)
ClockPicker.prototype.setHand = function(x, y, roundBy5, dragging) {
var radian = Math.atan2(x, - y),
isHours = this.currentView === 'hours',
unit = Math.PI / (isHours || roundBy5? 6 : 30),
z = Math.sqrt(x * x + y * y),
options = this.options,
inner = isHours && z < (outerRadius + innerRadius) / 2,
radius = inner ? innerRadius : outerRadius,
value;
if (options.twelvehour) {
radius = outerRadius;
}
// Radian should in range [0, 2PI]
if (radian < 0) {
radian = Math.PI * 2 + radian;
}
// Get the round value
value = Math.round(radian / unit);
// Get the round radian
radian = value * unit;
// Correct the hours or minutes
if (options.twelvehour) {
if (isHours) {
if (value === 0)
value = 12;
} else {
if (roundBy5)
value *= 5;
if (value === 60)
value = 0;
}
} else {
if (isHours) {
if (value === 12)
value = 0;
value = inner ? (value === 0 ? 12 : value) : value === 0 ? 0 : value + 12;
} else {
if (roundBy5)
value *= 5;
if (value === 60)
value = 0;
}
}
// Once hours or minutes changed, vibrate the device
if (this[this.currentView] !== value) {
if (vibrate && this.options.vibrate) {
// Do not vibrate too frequently
if (!this.vibrateTimer) {
navigator[vibrate](10);
this.vibrateTimer = setTimeout($.proxy(function(){
this.vibrateTimer = null;
}, this), 100);
}
}
}
this[this.currentView] = value;
if (isHours) {
this['spanHours'].html(value);
} else {
this['spanMinutes'].html(leadingZero(value));
}
// If svg is not supported, just add an active class to the tick
if (!svgSupported) {
this[isHours ? 'hoursView' : 'minutesView'].find('.clockpicker-tick').each(function(){
var tick = $(this);
tick.toggleClass('active', value === + tick.html());
});
return;
}
// Set clock hand and others' position
var cx1 = Math.sin(radian) * (radius - tickRadius),
cy1 = - Math.cos(radian) * (radius - tickRadius),
cx2 = Math.sin(radian) * radius,
cy2 = - Math.cos(radian) * radius;
this.hand.setAttribute('x2', cx1);
this.hand.setAttribute('y2', cy1);
this.bg.setAttribute('cx', cx2);
this.bg.setAttribute('cy', cy2);
};
// Hours and minutes are selected
ClockPicker.prototype.done = function() {
raiseCallback(this.options.beforeDone);
this.hide();
this.label.addClass('active');
var last = this.input.prop('value'),
value = leadingZero(this.hours) + ':' + leadingZero(this.minutes);
if (this.options.twelvehour) {
value = value + this.amOrPm;
}
this.input.prop('value', value);
if (value !== last) {
this.input.triggerHandler('change');
if (!this.isInput) {
this.element.trigger('change');
}
}
if (this.options.autoclose)
this.input.trigger('blur');
raiseCallback(this.options.afterDone);
};
// Clear input field
ClockPicker.prototype.clear = function() {
this.hide();
this.label.removeClass('active');
var last = this.input.prop('value'),
value = '';
this.input.prop('value', value);
if (value !== last) {
this.input.triggerHandler('change');
if (! this.isInput) {
this.element.trigger('change');
}
}
if (this.options.autoclose) {
this.input.trigger('blur');
}
};
// Remove clockpicker from input
ClockPicker.prototype.remove = function() {
this.element.removeData('clockpicker');
this.input.off('focus.clockpicker click.clockpicker');
if (this.isShown) {
this.hide();
}
if (this.isAppended) {
$win.off('resize.clockpicker' + this.id);
this.popover.remove();
}
};
// Extends $.fn.clockpicker
$.fn.pickatime = function(option){
var args = Array.prototype.slice.call(arguments, 1);
return this.each(function(){
var $this = $(this),
data = $this.data('clockpicker');
if (!data) {
var options = $.extend({}, ClockPicker.DEFAULTS, $this.data(), typeof option == 'object' && option);
$this.data('clockpicker', new ClockPicker($this, options));
} else {
// Manual operatsions. show, hide, remove, e.g.
if (typeof data[option] === 'function') {
data[option].apply(data, args);
}
}
});
};
})(jQuery);

View file

@ -0,0 +1,274 @@
(function ($) {
// Add posibility to scroll to selected option
// usefull for select for example
$.fn.scrollTo = function(elem) {
$(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem).offset().top);
return this;
};
$.fn.dropdown = function (options) {
var defaults = {
inDuration: 300,
outDuration: 225,
constrainWidth: true, // Constrains width of dropdown to the activator
hover: false,
gutter: 0, // Spacing from edge
belowOrigin: false,
alignment: 'left',
stopPropagation: false
};
// Open dropdown.
if (options === "open") {
this.each(function() {
$(this).trigger('open');
});
return false;
}
// Close dropdown.
if (options === "close") {
this.each(function() {
$(this).trigger('close');
});
return false;
}
this.each(function(){
var origin = $(this);
var curr_options = $.extend({}, defaults, options);
var isFocused = false;
// Dropdown menu
var activates = $("#"+ origin.attr('data-activates'));
function updateOptions() {
if (origin.data('induration') !== undefined)
curr_options.inDuration = origin.data('induration');
if (origin.data('outduration') !== undefined)
curr_options.outDuration = origin.data('outduration');
if (origin.data('constrainwidth') !== undefined)
curr_options.constrainWidth = origin.data('constrainwidth');
if (origin.data('hover') !== undefined)
curr_options.hover = origin.data('hover');
if (origin.data('gutter') !== undefined)
curr_options.gutter = origin.data('gutter');
if (origin.data('beloworigin') !== undefined)
curr_options.belowOrigin = origin.data('beloworigin');
if (origin.data('alignment') !== undefined)
curr_options.alignment = origin.data('alignment');
if (origin.data('stoppropagation') !== undefined)
curr_options.stopPropagation = origin.data('stoppropagation');
}
updateOptions();
// Attach dropdown to its activator
origin.after(activates);
/*
Helper function to position and resize dropdown.
Used in hover and click handler.
*/
function placeDropdown(eventType) {
// Check for simultaneous focus and click events.
if (eventType === 'focus') {
isFocused = true;
}
// Check html data attributes
updateOptions();
// Set Dropdown state
activates.addClass('active');
origin.addClass('active');
var originWidth = origin[0].getBoundingClientRect().width;
// Constrain width
if (curr_options.constrainWidth === true) {
activates.css('width', originWidth);
} else {
activates.css('white-space', 'nowrap');
}
// Offscreen detection
var windowHeight = window.innerHeight;
var originHeight = origin.innerHeight();
var offsetLeft = origin.offset().left;
var offsetTop = origin.offset().top - $(window).scrollTop();
var currAlignment = curr_options.alignment;
var gutterSpacing = 0;
var leftPosition = 0;
// Below Origin
var verticalOffset = 0;
if (curr_options.belowOrigin === true) {
verticalOffset = originHeight;
}
// Check for scrolling positioned container.
var scrollYOffset = 0;
var scrollXOffset = 0;
var wrapper = origin.parent();
if (!wrapper.is('body')) {
if (wrapper[0].scrollHeight > wrapper[0].clientHeight) {
scrollYOffset = wrapper[0].scrollTop;
}
if (wrapper[0].scrollWidth > wrapper[0].clientWidth) {
scrollXOffset = wrapper[0].scrollLeft;
}
}
if (offsetLeft + activates.innerWidth() > $(window).width()) {
// Dropdown goes past screen on right, force right alignment
currAlignment = 'right';
} else if (offsetLeft - activates.innerWidth() + origin.innerWidth() < 0) {
// Dropdown goes past screen on left, force left alignment
currAlignment = 'left';
}
// Vertical bottom offscreen detection
if (offsetTop + activates.innerHeight() > windowHeight) {
// If going upwards still goes offscreen, just crop height of dropdown.
if (offsetTop + originHeight - activates.innerHeight() < 0) {
var adjustedHeight = windowHeight - offsetTop - verticalOffset;
activates.css('max-height', adjustedHeight);
} else {
// Flow upwards.
if (!verticalOffset) {
verticalOffset += originHeight;
}
verticalOffset -= activates.innerHeight();
}
}
// Handle edge alignment
if (currAlignment === 'left') {
gutterSpacing = curr_options.gutter;
leftPosition = origin.position().left + gutterSpacing;
}
else if (currAlignment === 'right') {
// Material icons fix
activates
.stop(true, true)
.css({
opacity: 0,
left: 0
})
var offsetRight = origin.position().left + originWidth - activates.width();
gutterSpacing = -curr_options.gutter;
leftPosition = offsetRight + gutterSpacing;
}
// Position dropdown
activates.css({
position: 'absolute',
top: origin.position().top + verticalOffset + scrollYOffset,
left: leftPosition + scrollXOffset
});
// Show dropdown
activates
.slideDown({
queue: false,
duration: curr_options.inDuration,
easing: 'easeOutCubic',
complete: function() {
$(this).css('height', '');
}
})
.animate( {opacity: 1}, {queue: false, duration: curr_options.inDuration, easing: 'easeOutSine'});
// Add click close handler to document
setTimeout(function() {
$(document).on('click.'+ activates.attr('id'), function (e) {
hideDropdown();
$(document).off('click.'+ activates.attr('id'));
});
}, 0);
}
function hideDropdown() {
// Check for simultaneous focus and click events.
isFocused = false;
activates.fadeOut(curr_options.outDuration);
activates.removeClass('active');
origin.removeClass('active');
$(document).off('click.'+ activates.attr('id'));
setTimeout(function() { activates.css('max-height', ''); }, curr_options.outDuration);
}
// Hover
if (curr_options.hover) {
var open = false;
origin.off('click.' + origin.attr('id'));
// Hover handler to show dropdown
origin.on('mouseenter', function(e){ // Mouse over
if (open === false) {
placeDropdown();
open = true;
}
});
origin.on('mouseleave', function(e){
// If hover on origin then to something other than dropdown content, then close
var toEl = e.toElement || e.relatedTarget; // added browser compatibility for target element
if(!$(toEl).closest('.dropdown-content').is(activates)) {
activates.stop(true, true);
hideDropdown();
open = false;
}
});
activates.on('mouseleave', function(e){ // Mouse out
var toEl = e.toElement || e.relatedTarget;
if(!$(toEl).closest('.dropdown-button').is(origin)) {
activates.stop(true, true);
hideDropdown();
open = false;
}
});
// Click
} else {
// Click handler to show dropdown
origin.off('click.' + origin.attr('id'));
origin.on('click.'+origin.attr('id'), function(e){
if (!isFocused) {
if ( origin[0] == e.currentTarget &&
!origin.hasClass('active') &&
($(e.target).closest('.dropdown-content').length === 0)) {
e.preventDefault(); // Prevents button click from moving window
if (curr_options.stopPropagation) {
e.stopPropagation();
}
placeDropdown('click');
}
// If origin is clicked and menu is open, close menu
else if (origin.hasClass('active')) {
hideDropdown();
$(document).off('click.'+ activates.attr('id'));
}
}
});
} // End else
// Listen to open and close event - useful for select component
origin.on('open', function(e, eventType) {
placeDropdown(eventType);
});
origin.on('close', hideDropdown);
});
}; // End dropdown plugin
$(document).ready(function(){
$('.dropdown-button').dropdown();
});
}( jQuery ));

View file

@ -0,0 +1,811 @@
(function ($) {
$(document).ready(function() {
// Function to update labels of text fields
Materialize.updateTextFields = function() {
var input_selector = 'input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], textarea';
$(input_selector).each(function(index, element) {
var $this = $(this);
if ($(element).val().length > 0 || $(element).is(':focus') || element.autofocus || $this.attr('placeholder') !== undefined) {
$this.siblings('label').addClass('active');
} else if ($(element)[0].validity) {
$this.siblings('label').toggleClass('active', $(element)[0].validity.badInput === true);
} else {
$this.siblings('label').removeClass('active');
}
});
};
// Text based inputs
var input_selector = 'input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], textarea';
// Add active if form auto complete
$(document).on('change', input_selector, function () {
if($(this).val().length !== 0 || $(this).attr('placeholder') !== undefined) {
$(this).siblings('label').addClass('active');
}
validate_field($(this));
});
// Add active if input element has been pre-populated on document ready
$(document).ready(function() {
Materialize.updateTextFields();
});
// HTML DOM FORM RESET handling
$(document).on('reset', function(e) {
var formReset = $(e.target);
if (formReset.is('form')) {
formReset.find(input_selector).removeClass('valid').removeClass('invalid');
formReset.find(input_selector).each(function () {
if ($(this).attr('value') === '') {
$(this).siblings('label').removeClass('active');
}
});
// Reset select
formReset.find('select.initialized').each(function () {
var reset_text = formReset.find('option[selected]').text();
formReset.siblings('input.select-dropdown').val(reset_text);
});
}
});
// Add active when element has focus
$(document).on('focus', input_selector, function () {
$(this).siblings('label, .prefix').addClass('active');
});
$(document).on('blur', input_selector, function () {
var $inputElement = $(this);
var selector = ".prefix";
if ($inputElement.val().length === 0 && $inputElement[0].validity.badInput !== true && $inputElement.attr('placeholder') === undefined) {
selector += ", label";
}
$inputElement.siblings(selector).removeClass('active');
validate_field($inputElement);
});
window.validate_field = function(object) {
var hasLength = object.attr('data-length') !== undefined;
var lenAttr = parseInt(object.attr('data-length'));
var len = object.val().length;
if (object.val().length === 0 && object[0].validity.badInput === false && !object.is(':required')) {
if (object.hasClass('validate')) {
object.removeClass('valid');
object.removeClass('invalid');
}
}
else {
if (object.hasClass('validate')) {
// Check for character counter attributes
if ((object.is(':valid') && hasLength && (len <= lenAttr)) || (object.is(':valid') && !hasLength)) {
object.removeClass('invalid');
object.addClass('valid');
}
else {
object.removeClass('valid');
object.addClass('invalid');
}
}
}
};
// Radio and Checkbox focus class
var radio_checkbox = 'input[type=radio], input[type=checkbox]';
$(document).on('keyup.radio', radio_checkbox, function(e) {
// TAB, check if tabbing to radio or checkbox.
if (e.which === 9) {
$(this).addClass('tabbed');
var $this = $(this);
$this.one('blur', function(e) {
$(this).removeClass('tabbed');
});
return;
}
});
// Textarea Auto Resize
var hiddenDiv = $('.hiddendiv').first();
if (!hiddenDiv.length) {
hiddenDiv = $('<div class="hiddendiv common"></div>');
$('body').append(hiddenDiv);
}
var text_area_selector = '.materialize-textarea';
function textareaAutoResize($textarea) {
// Set font properties of hiddenDiv
var fontFamily = $textarea.css('font-family');
var fontSize = $textarea.css('font-size');
var lineHeight = $textarea.css('line-height');
var padding = $textarea.css('padding');
if (fontSize) { hiddenDiv.css('font-size', fontSize); }
if (fontFamily) { hiddenDiv.css('font-family', fontFamily); }
if (lineHeight) { hiddenDiv.css('line-height', lineHeight); }
if (padding) { hiddenDiv.css('padding', padding); }
// Set original-height, if none
if (!$textarea.data('original-height')) {
$textarea.data('original-height', $textarea.height());
}
if ($textarea.attr('wrap') === 'off') {
hiddenDiv.css('overflow-wrap', 'normal')
.css('white-space', 'pre');
}
hiddenDiv.text($textarea.val() + '\n');
var content = hiddenDiv.html().replace(/\n/g, '<br>');
hiddenDiv.html(content);
// When textarea is hidden, width goes crazy.
// Approximate with half of window size
if ($textarea.is(':visible')) {
hiddenDiv.css('width', $textarea.width());
}
else {
hiddenDiv.css('width', $(window).width()/2);
}
/**
* Resize if the new height is greater than the
* original height of the textarea
*/
if ($textarea.data('original-height') <= hiddenDiv.height()) {
$textarea.css('height', hiddenDiv.height());
} else if ($textarea.val().length < $textarea.data('previous-length')) {
/**
* In case the new height is less than original height, it
* means the textarea has less text than before
* So we set the height to the original one
*/
$textarea.css('height', $textarea.data('original-height'));
}
$textarea.data('previous-length', $textarea.val().length);
}
$(text_area_selector).each(function () {
var $textarea = $(this);
/**
* Instead of resizing textarea on document load,
* store the original height and the original length
*/
$textarea.data('original-height', $textarea.height());
$textarea.data('previous-length', $textarea.val().length);
});
$('body').on('keyup keydown autoresize', text_area_selector, function () {
textareaAutoResize($(this));
});
// File Input Path
$(document).on('change', '.file-field input[type="file"]', function () {
var file_field = $(this).closest('.file-field');
var path_input = file_field.find('input.file-path');
var files = $(this)[0].files;
var file_names = [];
for (var i = 0; i < files.length; i++) {
file_names.push(files[i].name);
}
path_input.val(file_names.join(", "));
path_input.trigger('change');
});
/****************
* Range Input *
****************/
var range_type = 'input[type=range]';
var range_mousedown = false;
var left;
$(range_type).each(function () {
var thumb = $('<span class="thumb"><span class="value"></span></span>');
$(this).after(thumb);
});
var showRangeBubble = function(thumb) {
var paddingLeft = parseInt(thumb.parent().css('padding-left'));
var marginLeft = (-7 + paddingLeft) + 'px';
thumb.velocity({ height: "30px", width: "30px", top: "-30px", marginLeft: marginLeft}, { duration: 300, easing: 'easeOutExpo' });
};
var calcRangeOffset = function(range) {
var width = range.width() - 15;
var max = parseFloat(range.attr('max'));
var min = parseFloat(range.attr('min'));
var percent = (parseFloat(range.val()) - min) / (max - min);
return percent * width;
}
var range_wrapper = '.range-field';
$(document).on('change', range_type, function(e) {
var thumb = $(this).siblings('.thumb');
thumb.find('.value').html($(this).val());
if (!thumb.hasClass('active')) {
showRangeBubble(thumb);
}
var offsetLeft = calcRangeOffset($(this));
thumb.addClass('active').css('left', offsetLeft);
});
$(document).on('mousedown touchstart', range_type, function(e) {
var thumb = $(this).siblings('.thumb');
// If thumb indicator does not exist yet, create it
if (thumb.length <= 0) {
thumb = $('<span class="thumb"><span class="value"></span></span>');
$(this).after(thumb);
}
// Set indicator value
thumb.find('.value').html($(this).val());
range_mousedown = true;
$(this).addClass('active');
if (!thumb.hasClass('active')) {
showRangeBubble(thumb);
}
if (e.type !== 'input') {
var offsetLeft = calcRangeOffset($(this));
thumb.addClass('active').css('left', offsetLeft);
}
});
$(document).on('mouseup touchend', range_wrapper, function() {
range_mousedown = false;
$(this).removeClass('active');
});
$(document).on('input mousemove touchmove', range_wrapper, function(e) {
var thumb = $(this).children('.thumb');
var left;
var input = $(this).find(range_type);
if (range_mousedown) {
if (!thumb.hasClass('active')) {
showRangeBubble(thumb);
}
var offsetLeft = calcRangeOffset(input);
thumb.addClass('active').css('left', offsetLeft);
thumb.find('.value').html(thumb.siblings(range_type).val());
}
});
$(document).on('mouseout touchleave', range_wrapper, function() {
if (!range_mousedown) {
var thumb = $(this).children('.thumb');
var paddingLeft = parseInt($(this).css('padding-left'));
var marginLeft = (7 + paddingLeft) + 'px';
if (thumb.hasClass('active')) {
thumb.velocity({ height: '0', width: '0', top: '10px', marginLeft: marginLeft}, { duration: 100 });
}
thumb.removeClass('active');
}
});
/**************************
* Auto complete plugin *
*************************/
$.fn.autocomplete = function (options) {
// Defaults
var defaults = {
data: {},
limit: Infinity,
onAutocomplete: null,
minLength: 1
};
options = $.extend(defaults, options);
return this.each(function() {
var $input = $(this);
var data = options.data,
count = 0,
activeIndex = -1,
oldVal,
$inputDiv = $input.closest('.input-field'); // Div to append on
// Check if data isn't empty
if (!$.isEmptyObject(data)) {
var $autocomplete = $('<ul class="autocomplete-content dropdown-content"></ul>');
var $oldAutocomplete;
// Append autocomplete element.
// Prevent double structure init.
if ($inputDiv.length) {
$oldAutocomplete = $inputDiv.children('.autocomplete-content.dropdown-content').first();
if (!$oldAutocomplete.length) {
$inputDiv.append($autocomplete); // Set ul in body
}
} else {
$oldAutocomplete = $input.next('.autocomplete-content.dropdown-content');
if (!$oldAutocomplete.length) {
$input.after($autocomplete);
}
}
if ($oldAutocomplete.length) {
$autocomplete = $oldAutocomplete;
}
// Highlight partial match.
var highlight = function(string, $el) {
var img = $el.find('img');
var matchStart = $el.text().toLowerCase().indexOf("" + string.toLowerCase() + ""),
matchEnd = matchStart + string.length - 1,
beforeMatch = $el.text().slice(0, matchStart),
matchText = $el.text().slice(matchStart, matchEnd + 1),
afterMatch = $el.text().slice(matchEnd + 1);
$el.html("<span>" + beforeMatch + "<span class='highlight'>" + matchText + "</span>" + afterMatch + "</span>");
if (img.length) {
$el.prepend(img);
}
};
// Reset current element position
var resetCurrentElement = function() {
activeIndex = -1;
$autocomplete.find('.active').removeClass('active');
}
// Remove autocomplete elements
var removeAutocomplete = function() {
$autocomplete.empty();
resetCurrentElement();
oldVal = undefined;
};
$input.off('blur.autocomplete').on('blur.autocomplete', function() {
removeAutocomplete();
});
// Perform search
$input.off('keyup.autocomplete focus.autocomplete').on('keyup.autocomplete focus.autocomplete', function (e) {
// Reset count.
count = 0;
var val = $input.val().toLowerCase();
// Don't capture enter or arrow key usage.
if (e.which === 13 ||
e.which === 38 ||
e.which === 40) {
return;
}
// Check if the input isn't empty
if (oldVal !== val) {
removeAutocomplete();
if (val.length >= options.minLength) {
for(var key in data) {
if (data.hasOwnProperty(key) &&
key.toLowerCase().indexOf(val) !== -1) {
// Break if past limit
if (count >= options.limit) {
break;
}
var autocompleteOption = $('<li></li>');
if (!!data[key]) {
autocompleteOption.append('<img src="'+ data[key] +'" class="right circle"><span>'+ key +'</span>');
} else {
autocompleteOption.append('<span>'+ key +'</span>');
}
$autocomplete.append(autocompleteOption);
highlight(val, autocompleteOption);
count++;
}
}
}
}
// Update oldVal
oldVal = val;
});
$input.off('keydown.autocomplete').on('keydown.autocomplete', function (e) {
// Arrow keys and enter key usage
var keyCode = e.which,
liElement,
numItems = $autocomplete.children('li').length,
$active = $autocomplete.children('.active').first();
// select element on Enter
if (keyCode === 13 && activeIndex >= 0) {
liElement = $autocomplete.children('li').eq(activeIndex);
if (liElement.length) {
liElement.trigger('mousedown.autocomplete');
e.preventDefault();
}
return;
}
// Capture up and down key
if ( keyCode === 38 || keyCode === 40 ) {
e.preventDefault();
if (keyCode === 38 &&
activeIndex > 0) {
activeIndex--;
}
if (keyCode === 40 &&
activeIndex < (numItems - 1)) {
activeIndex++;
}
$active.removeClass('active');
if (activeIndex >= 0) {
$autocomplete.children('li').eq(activeIndex).addClass('active');
}
}
});
// Set input value
$autocomplete.off('mousedown.autocomplete touchstart.autocomplete').on('mousedown.autocomplete touchstart.autocomplete', 'li', function () {
var text = $(this).text().trim();
$input.val(text);
$input.trigger('change');
removeAutocomplete();
// Handle onAutocomplete callback.
if (typeof(options.onAutocomplete) === "function") {
options.onAutocomplete.call(this, text);
}
});
// Empty data
} else {
$input.off('keyup.autocomplete focus.autocomplete');
}
});
};
}); // End of $(document).ready
/*******************
* Select Plugin *
******************/
$.fn.material_select = function (callback) {
$(this).each(function(){
var $select = $(this);
if ($select.hasClass('browser-default')) {
return; // Continue to next (return false breaks out of entire loop)
}
var multiple = $select.attr('multiple') ? true : false,
lastID = $select.attr('data-select-id'); // Tear down structure if Select needs to be rebuilt
if (lastID) {
$select.parent().find('span.caret').remove();
$select.parent().find('input').remove();
$select.unwrap();
$('ul#select-options-'+lastID).remove();
}
// If destroying the select, remove the selelct-id and reset it to it's uninitialized state.
if(callback === 'destroy') {
$select.removeAttr('data-select-id').removeClass('initialized');
$(window).off('click.select');
return;
}
var uniqueID = Materialize.guid();
$select.attr('data-select-id', uniqueID);
var wrapper = $('<div class="select-wrapper"></div>');
wrapper.addClass($select.attr('class'));
if ($select.is(':disabled'))
wrapper.addClass('disabled');
var options = $('<ul id="select-options-' + uniqueID +'" class="dropdown-content select-dropdown ' + (multiple ? 'multiple-select-dropdown' : '') + '"></ul>'),
selectChildren = $select.children('option, optgroup'),
valuesSelected = [],
optionsHover = false;
var label = $select.find('option:selected').html() || $select.find('option:first').html() || "";
// Function that renders and appends the option taking into
// account type and possible image icon.
var appendOptionWithIcon = function(select, option, type) {
// Add disabled attr if disabled
var disabledClass = (option.is(':disabled')) ? 'disabled ' : '';
var optgroupClass = (type === 'optgroup-option') ? 'optgroup-option ' : '';
var multipleCheckbox = multiple ? '<input type="checkbox"' + disabledClass + '/><label></label>' : '';
// add icons
var icon_url = option.data('icon');
var classes = option.attr('class');
if (!!icon_url) {
var classString = '';
if (!!classes) classString = ' class="' + classes + '"';
// Check for multiple type.
options.append($('<li class="' + disabledClass + optgroupClass + '"><img alt="" src="' + icon_url + '"' + classString + '><span>' + multipleCheckbox + option.html() + '</span></li>'));
return true;
}
// Check for multiple type.
options.append($('<li class="' + disabledClass + optgroupClass + '"><span>' + multipleCheckbox + option.html() + '</span></li>'));
};
/* Create dropdown structure. */
if (selectChildren.length) {
selectChildren.each(function() {
if ($(this).is('option')) {
// Direct descendant option.
if (multiple) {
appendOptionWithIcon($select, $(this), 'multiple');
} else {
appendOptionWithIcon($select, $(this));
}
} else if ($(this).is('optgroup')) {
// Optgroup.
var selectOptions = $(this).children('option');
options.append($('<li class="optgroup"><span>' + $(this).attr('label') + '</span></li>'));
selectOptions.each(function() {
appendOptionWithIcon($select, $(this), 'optgroup-option');
});
}
});
}
options.find('li:not(.optgroup)').each(function (i) {
$(this).click(function (e) {
// Check if option element is disabled
if (!$(this).hasClass('disabled') && !$(this).hasClass('optgroup')) {
var selected = true;
if (multiple) {
$('input[type="checkbox"]', this).prop('checked', function(i, v) { return !v; });
selected = toggleEntryFromArray(valuesSelected, i, $select);
$newSelect.trigger('focus');
} else {
options.find('li').removeClass('active');
$(this).toggleClass('active');
$newSelect.val($(this).text());
}
activateOption(options, $(this));
$select.find('option').eq(i).prop('selected', selected);
// Trigger onchange() event
$select.trigger('change');
if (typeof callback !== 'undefined') callback();
}
e.stopPropagation();
});
});
// Wrap Elements
$select.wrap(wrapper);
// Add Select Display Element
var dropdownIcon = $('<span class="caret">&#9660;</span>');
// escape double quotes
var sanitizedLabelHtml = label.replace(/"/g, '&quot;');
var $newSelect = $('<input type="text" class="select-dropdown" readonly="true" ' + (($select.is(':disabled')) ? 'disabled' : '') + ' data-activates="select-options-' + uniqueID +'" value="'+ sanitizedLabelHtml +'"/>');
$select.before($newSelect);
$newSelect.before(dropdownIcon);
$newSelect.after(options);
// Check if section element is disabled
if (!$select.is(':disabled')) {
$newSelect.dropdown({'hover': false});
}
// Copy tabindex
if ($select.attr('tabindex')) {
$($newSelect[0]).attr('tabindex', $select.attr('tabindex'));
}
$select.addClass('initialized');
$newSelect.on({
'focus': function (){
if ($('ul.select-dropdown').not(options[0]).is(':visible')) {
$('input.select-dropdown').trigger('close');
$(window).off('click.select');
}
if (!options.is(':visible')) {
$(this).trigger('open', ['focus']);
var label = $(this).val();
if (multiple && label.indexOf(',') >= 0) {
label = label.split(',')[0];
}
var selectedOption = options.find('li').filter(function() {
return $(this).text().toLowerCase() === label.toLowerCase();
})[0];
activateOption(options, selectedOption, true);
$(window).off('click.select').on('click.select', function () {
multiple && (optionsHover || $newSelect.trigger('close'));
$(window).off('click.select');
});
}
},
'click': function (e){
e.stopPropagation();
}
});
$newSelect.on('blur', function() {
if (!multiple) {
$(this).trigger('close');
$(window).off('click.select');
}
options.find('li.selected').removeClass('selected');
});
options.hover(function() {
optionsHover = true;
}, function () {
optionsHover = false;
});
// Add initial multiple selections.
if (multiple) {
$select.find("option:selected:not(:disabled)").each(function () {
var index = this.index;
toggleEntryFromArray(valuesSelected, index, $select);
options.find("li:not(.optgroup)").eq(index).find(":checkbox").prop("checked", true);
});
}
/**
* Make option as selected and scroll to selected position
* @param {jQuery} collection Select options jQuery element
* @param {Element} newOption element of the new option
* @param {Boolean} firstActivation If on first activation of select
*/
var activateOption = function(collection, newOption, firstActivation) {
if (newOption) {
collection.find('li.selected').removeClass('selected');
var option = $(newOption);
option.addClass('selected');
if (!multiple || !!firstActivation) {
options.scrollTo(option);
}
}
};
// Allow user to search by typing
// this array is cleared after 1 second
var filterQuery = [],
onKeyDown = function(e){
// TAB - switch to another input
if(e.which == 9){
$newSelect.trigger('close');
return;
}
// ARROW DOWN WHEN SELECT IS CLOSED - open select options
if(e.which == 40 && !options.is(':visible')){
$newSelect.trigger('open');
return;
}
// ENTER WHEN SELECT IS CLOSED - submit form
if(e.which == 13 && !options.is(':visible')){
return;
}
e.preventDefault();
// CASE WHEN USER TYPE LETTERS
var letter = String.fromCharCode(e.which).toLowerCase(),
nonLetters = [9,13,27,38,40];
if (letter && (nonLetters.indexOf(e.which) === -1)) {
filterQuery.push(letter);
var string = filterQuery.join(''),
newOption = options.find('li').filter(function() {
return $(this).text().toLowerCase().indexOf(string) === 0;
})[0];
if (newOption) {
activateOption(options, newOption);
}
}
// ENTER - select option and close when select options are opened
if (e.which == 13) {
var activeOption = options.find('li.selected:not(.disabled)')[0];
if(activeOption){
$(activeOption).trigger('click');
if (!multiple) {
$newSelect.trigger('close');
}
}
}
// ARROW DOWN - move to next not disabled option
if (e.which == 40) {
if (options.find('li.selected').length) {
newOption = options.find('li.selected').next('li:not(.disabled)')[0];
} else {
newOption = options.find('li:not(.disabled)')[0];
}
activateOption(options, newOption);
}
// ESC - close options
if (e.which == 27) {
$newSelect.trigger('close');
}
// ARROW UP - move to previous not disabled option
if (e.which == 38) {
newOption = options.find('li.selected').prev('li:not(.disabled)')[0];
if(newOption)
activateOption(options, newOption);
}
// Automaticaly clean filter query so user can search again by starting letters
setTimeout(function(){ filterQuery = []; }, 1000);
};
$newSelect.on('keydown', onKeyDown);
});
function toggleEntryFromArray(entriesArray, entryIndex, select) {
var index = entriesArray.indexOf(entryIndex),
notAdded = index === -1;
if (notAdded) {
entriesArray.push(entryIndex);
} else {
entriesArray.splice(index, 1);
}
select.siblings('ul.dropdown-content').find('li:not(.optgroup)').eq(entryIndex).toggleClass('active');
// use notAdded instead of true (to detect if the option is selected or not)
select.find('option').eq(entryIndex).prop('selected', notAdded);
setValueToInput(entriesArray, select);
return notAdded;
}
function setValueToInput(entriesArray, select) {
var value = '';
for (var i = 0, count = entriesArray.length; i < count; i++) {
var text = select.find('option').eq(entriesArray[i]).text();
i === 0 ? value += text : value += ', ' + text;
}
if (value === '') {
value = select.find('option:disabled').eq(0).text();
}
select.siblings('input.select-dropdown').val(value);
}
};
}( jQuery ));

View file

@ -0,0 +1,177 @@
// Required for Meteor package, the use of window prevents export by Meteor
(function(window){
if(window.Package){
Materialize = {};
} else {
window.Materialize = {};
}
})(window);
if (typeof exports !== 'undefined' && !exports.nodeType) {
if (typeof module !== 'undefined' && !module.nodeType && module.exports) {
exports = module.exports = Materialize;
}
exports.default = Materialize;
}
/*
* raf.js
* https://github.com/ngryman/raf.js
*
* original requestAnimationFrame polyfill by Erik Möller
* inspired from paul_irish gist and post
*
* Copyright (c) 2013 ngryman
* Licensed under the MIT license.
*/
(function(window) {
var lastTime = 0,
vendors = ['webkit', 'moz'],
requestAnimationFrame = window.requestAnimationFrame,
cancelAnimationFrame = window.cancelAnimationFrame,
i = vendors.length;
// try to un-prefix existing raf
while (--i >= 0 && !requestAnimationFrame) {
requestAnimationFrame = window[vendors[i] + 'RequestAnimationFrame'];
cancelAnimationFrame = window[vendors[i] + 'CancelRequestAnimationFrame'];
}
// polyfill with setTimeout fallback
// heavily inspired from @darius gist mod: https://gist.github.com/paulirish/1579671#comment-837945
if (!requestAnimationFrame || !cancelAnimationFrame) {
requestAnimationFrame = function(callback) {
var now = +Date.now(),
nextTime = Math.max(lastTime + 16, now);
return setTimeout(function() {
callback(lastTime = nextTime);
}, nextTime - now);
};
cancelAnimationFrame = clearTimeout;
}
// export to window
window.requestAnimationFrame = requestAnimationFrame;
window.cancelAnimationFrame = cancelAnimationFrame;
}(window));
/**
* Generate approximated selector string for a jQuery object
* @param {jQuery} obj jQuery object to be parsed
* @returns {string}
*/
Materialize.objectSelectorString = function(obj) {
var tagStr = obj.prop('tagName') || '';
var idStr = obj.attr('id') || '';
var classStr = obj.attr('class') || '';
return (tagStr + idStr + classStr).replace(/\s/g,'');
};
// Unique Random ID
Materialize.guid = (function() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return function() {
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
};
})();
/**
* Escapes hash from special characters
* @param {string} hash String returned from this.hash
* @returns {string}
*/
Materialize.escapeHash = function(hash) {
return hash.replace( /(:|\.|\[|\]|,|=)/g, "\\$1" );
};
Materialize.elementOrParentIsFixed = function(element) {
var $element = $(element);
var $checkElements = $element.add($element.parents());
var isFixed = false;
$checkElements.each(function(){
if ($(this).css("position") === "fixed") {
isFixed = true;
return false;
}
});
return isFixed;
};
/**
* Get time in ms
* @license https://raw.github.com/jashkenas/underscore/master/LICENSE
* @type {function}
* @return {number}
*/
var getTime = (Date.now || function () {
return new Date().getTime();
});
/**
* Returns a function, that, when invoked, will only be triggered at most once
* during a given window of time. Normally, the throttled function will run
* as much as it can, without ever going more than once per `wait` duration;
* but if you'd like to disable the execution on the leading edge, pass
* `{leading: false}`. To disable execution on the trailing edge, ditto.
* @license https://raw.github.com/jashkenas/underscore/master/LICENSE
* @param {function} func
* @param {number} wait
* @param {Object=} options
* @returns {Function}
*/
Materialize.throttle = function(func, wait, options) {
var context, args, result;
var timeout = null;
var previous = 0;
options || (options = {});
var later = function () {
previous = options.leading === false ? 0 : getTime();
timeout = null;
result = func.apply(context, args);
context = args = null;
};
return function () {
var now = getTime();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0) {
clearTimeout(timeout);
timeout = null;
previous = now;
result = func.apply(context, args);
context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
};
// Velocity has conflicts when loaded with jQuery, this will check for it
// First, check if in noConflict mode
var Vel;
if (jQuery) {
Vel = jQuery.Velocity;
} else if ($) {
Vel = $.Velocity;
} else {
Vel = Velocity;
}
if (Vel) {
Materialize.Vel = Vel;
} else {
Materialize.Vel = Velocity;
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,10 @@
// Check for jQuery.
if (typeof(jQuery) === 'undefined') {
// Check if require is a defined function.
if (typeof(require) === 'function') {
jQuery = $ = require('jquery');
// Else use the dollar sign alias.
} else {
jQuery = $;
}
}

View file

@ -0,0 +1,166 @@
/*
* jQuery Easing v1.4.0 - http://gsgd.co.uk/sandbox/jquery/easing/
* Open source under the BSD License.
* Copyright © 2008 George McGinley Smith
* All rights reserved.
* https://raw.github.com/gdsmith/jquery-easing/master/LICENSE
*/
(function (factory) {
if (typeof define === "function" && define.amd) {
define(['jquery'], function ($) {
return factory($);
});
} else if (typeof module === "object" && typeof module.exports === "object") {
exports = factory(require('jquery'));
} else {
factory(jQuery);
}
})(function($){
// Preserve the original jQuery "swing" easing as "jswing"
$.easing['jswing'] = $.easing['swing'];
var pow = Math.pow,
sqrt = Math.sqrt,
sin = Math.sin,
cos = Math.cos,
PI = Math.PI,
c1 = 1.70158,
c2 = c1 * 1.525,
c3 = c1 + 1,
c4 = ( 2 * PI ) / 3,
c5 = ( 2 * PI ) / 4.5;
// x is the fraction of animation progress, in the range 0..1
function bounceOut(x) {
var n1 = 7.5625,
d1 = 2.75;
if ( x < 1/d1 ) {
return n1*x*x;
} else if ( x < 2/d1 ) {
return n1*(x-=(1.5/d1))*x + .75;
} else if ( x < 2.5/d1 ) {
return n1*(x-=(2.25/d1))*x + .9375;
} else {
return n1*(x-=(2.625/d1))*x + .984375;
}
}
$.extend( $.easing,
{
def: 'easeOutQuad',
swing: function (x) {
return $.easing[$.easing.def](x);
},
easeInQuad: function (x) {
return x * x;
},
easeOutQuad: function (x) {
return 1 - ( 1 - x ) * ( 1 - x );
},
easeInOutQuad: function (x) {
return x < 0.5 ?
2 * x * x :
1 - pow( -2 * x + 2, 2 ) / 2;
},
easeInCubic: function (x) {
return x * x * x;
},
easeOutCubic: function (x) {
return 1 - pow( 1 - x, 3 );
},
easeInOutCubic: function (x) {
return x < 0.5 ?
4 * x * x * x :
1 - pow( -2 * x + 2, 3 ) / 2;
},
easeInQuart: function (x) {
return x * x * x * x;
},
easeOutQuart: function (x) {
return 1 - pow( 1 - x, 4 );
},
easeInOutQuart: function (x) {
return x < 0.5 ?
8 * x * x * x * x :
1 - pow( -2 * x + 2, 4 ) / 2;
},
easeInQuint: function (x) {
return x * x * x * x * x;
},
easeOutQuint: function (x) {
return 1 - pow( 1 - x, 5 );
},
easeInOutQuint: function (x) {
return x < 0.5 ?
16 * x * x * x * x * x :
1 - pow( -2 * x + 2, 5 ) / 2;
},
easeInSine: function (x) {
return 1 - cos( x * PI/2 );
},
easeOutSine: function (x) {
return sin( x * PI/2 );
},
easeInOutSine: function (x) {
return -( cos( PI * x ) - 1 ) / 2;
},
easeInExpo: function (x) {
return x === 0 ? 0 : pow( 2, 10 * x - 10 );
},
easeOutExpo: function (x) {
return x === 1 ? 1 : 1 - pow( 2, -10 * x );
},
easeInOutExpo: function (x) {
return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ?
pow( 2, 20 * x - 10 ) / 2 :
( 2 - pow( 2, -20 * x + 10 ) ) / 2;
},
easeInCirc: function (x) {
return 1 - sqrt( 1 - pow( x, 2 ) );
},
easeOutCirc: function (x) {
return sqrt( 1 - pow( x - 1, 2 ) );
},
easeInOutCirc: function (x) {
return x < 0.5 ?
( 1 - sqrt( 1 - pow( 2 * x, 2 ) ) ) / 2 :
( sqrt( 1 - pow( -2 * x + 2, 2 ) ) + 1 ) / 2;
},
easeInElastic: function (x) {
return x === 0 ? 0 : x === 1 ? 1 :
-pow( 2, 10 * x - 10 ) * sin( ( x * 10 - 10.75 ) * c4 );
},
easeOutElastic: function (x) {
return x === 0 ? 0 : x === 1 ? 1 :
pow( 2, -10 * x ) * sin( ( x * 10 - 0.75 ) * c4 ) + 1;
},
easeInOutElastic: function (x) {
return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ?
-( pow( 2, 20 * x - 10 ) * sin( ( 20 * x - 11.125 ) * c5 )) / 2 :
pow( 2, -20 * x + 10 ) * sin( ( 20 * x - 11.125 ) * c5 ) / 2 + 1;
},
easeInBack: function (x) {
return c3 * x * x * x - c1 * x * x;
},
easeOutBack: function (x) {
return 1 + c3 * pow( x - 1, 3 ) + c1 * pow( x - 1, 2 );
},
easeInOutBack: function (x) {
return x < 0.5 ?
( pow( 2 * x, 2 ) * ( ( c2 + 1 ) * 2 * x - c2 ) ) / 2 :
( pow( 2 * x - 2, 2 ) *( ( c2 + 1 ) * ( x * 2 - 2 ) + c2 ) + 2 ) / 2;
},
easeInBounce: function (x) {
return 1 - bounceOut( 1 - x );
},
easeOutBounce: bounceOut,
easeInOutBounce: function (x) {
return x < 0.5 ?
( 1 - bounceOut( 1 - 2 * x ) ) / 2 :
( 1 + bounceOut( 2 * x - 1 ) ) / 2;
}
});
});

View file

@ -0,0 +1,33 @@
(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery', 'hammerjs'], factory);
} else if (typeof exports === 'object') {
factory(require('jquery'), require('hammerjs'));
} else {
factory(jQuery, Hammer);
}
}(function($, Hammer) {
function hammerify(el, options) {
var $el = $(el);
if(!$el.data("hammer")) {
$el.data("hammer", new Hammer($el[0], options));
}
}
$.fn.hammer = function(options) {
return this.each(function() {
hammerify(this, options);
});
};
// extend the emit method to also trigger jQuery events
Hammer.Manager.prototype.emit = (function(originalEmit) {
return function(type, data) {
originalEmit.call(this, type, data);
$(this.element).trigger({
type: type,
gesture: data
});
};
})(Hammer.Manager.prototype.emit);
}));

View file

@ -0,0 +1,289 @@
(function ($) {
$.fn.materialbox = function () {
return this.each(function() {
if ($(this).hasClass('initialized')) {
return;
}
$(this).addClass('initialized');
var overlayActive = false;
var doneAnimating = true;
var inDuration = 275;
var outDuration = 200;
var origin = $(this);
var placeholder = $('<div></div>').addClass('material-placeholder');
var originalWidth = 0;
var originalHeight = 0;
var ancestorsChanged;
var ancestor;
var originInlineStyles = origin.attr('style');
origin.wrap(placeholder);
// Start click handler
origin.on('click', function() {
var placeholder = origin.parent('.material-placeholder');
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var originalWidth = origin.width();
var originalHeight = origin.height();
// If already modal, return to original
if (doneAnimating === false) {
returnToOriginal();
return false;
}
else if (overlayActive && doneAnimating===true) {
returnToOriginal();
return false;
}
// Set states
doneAnimating = false;
origin.addClass('active');
overlayActive = true;
// Set positioning for placeholder
placeholder.css({
width: placeholder[0].getBoundingClientRect().width,
height: placeholder[0].getBoundingClientRect().height,
position: 'relative',
top: 0,
left: 0
});
// Find ancestor with overflow: hidden; and remove it
ancestorsChanged = undefined;
ancestor = placeholder[0].parentNode;
var count = 0;
while (ancestor !== null && !$(ancestor).is(document)) {
var curr = $(ancestor);
if (curr.css('overflow') !== 'visible') {
curr.css('overflow', 'visible');
if (ancestorsChanged === undefined) {
ancestorsChanged = curr;
}
else {
ancestorsChanged = ancestorsChanged.add(curr);
}
}
ancestor = ancestor.parentNode;
}
// Set css on origin
origin.css({
position: 'absolute',
'z-index': 1000,
'will-change': 'left, top, width, height'
})
.data('width', originalWidth)
.data('height', originalHeight);
// Add overlay
var overlay = $('<div id="materialbox-overlay"></div>')
.css({
opacity: 0
})
.click(function(){
if (doneAnimating === true)
returnToOriginal();
});
// Put before in origin image to preserve z-index layering.
origin.before(overlay);
// Set dimensions if needed
var overlayOffset = overlay[0].getBoundingClientRect();
overlay.css({
width: windowWidth,
height: windowHeight,
left: -1 * overlayOffset.left,
top: -1 * overlayOffset.top
})
// Animate Overlay
overlay.velocity({opacity: 1},
{duration: inDuration, queue: false, easing: 'easeOutQuad'} );
// Add and animate caption if it exists
if (origin.data('caption') !== "") {
var $photo_caption = $('<div class="materialbox-caption"></div>');
$photo_caption.text(origin.data('caption'));
$('body').append($photo_caption);
$photo_caption.css({ "display": "inline" });
$photo_caption.velocity({opacity: 1}, {duration: inDuration, queue: false, easing: 'easeOutQuad'});
}
// Resize Image
var ratio = 0;
var widthPercent = originalWidth / windowWidth;
var heightPercent = originalHeight / windowHeight;
var newWidth = 0;
var newHeight = 0;
if (widthPercent > heightPercent) {
ratio = originalHeight / originalWidth;
newWidth = windowWidth * 0.9;
newHeight = windowWidth * 0.9 * ratio;
}
else {
ratio = originalWidth / originalHeight;
newWidth = (windowHeight * 0.9) * ratio;
newHeight = windowHeight * 0.9;
}
// Animate image + set z-index
if(origin.hasClass('responsive-img')) {
origin.velocity({'max-width': newWidth, 'width': originalWidth}, {duration: 0, queue: false,
complete: function(){
origin.css({left: 0, top: 0})
.velocity(
{
height: newHeight,
width: newWidth,
left: $(document).scrollLeft() + windowWidth/2 - origin.parent('.material-placeholder').offset().left - newWidth/2,
top: $(document).scrollTop() + windowHeight/2 - origin.parent('.material-placeholder').offset().top - newHeight/ 2
},
{
duration: inDuration,
queue: false,
easing: 'easeOutQuad',
complete: function(){doneAnimating = true;}
}
);
} // End Complete
}); // End Velocity
}
else {
origin.css('left', 0)
.css('top', 0)
.velocity(
{
height: newHeight,
width: newWidth,
left: $(document).scrollLeft() + windowWidth/2 - origin.parent('.material-placeholder').offset().left - newWidth/2,
top: $(document).scrollTop() + windowHeight/2 - origin.parent('.material-placeholder').offset().top - newHeight/ 2
},
{
duration: inDuration,
queue: false,
easing: 'easeOutQuad',
complete: function(){doneAnimating = true;}
}
); // End Velocity
}
// Handle Exit triggers
$(window).on('scroll.materialbox', function() {
if (overlayActive) {
returnToOriginal();
}
});
$(window).on('resize.materialbox', function() {
if (overlayActive) {
returnToOriginal();
}
});
$(document).on('keyup.materialbox', function(e) {
// ESC key
if (e.keyCode === 27 &&
doneAnimating === true &&
overlayActive) {
returnToOriginal();
}
});
}); // End click handler
// This function returns the modaled image to the original spot
function returnToOriginal() {
doneAnimating = false;
var placeholder = origin.parent('.material-placeholder');
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var originalWidth = origin.data('width');
var originalHeight = origin.data('height');
origin.velocity("stop", true);
$('#materialbox-overlay').velocity("stop", true);
$('.materialbox-caption').velocity("stop", true);
// disable exit handlers
$(window).off('scroll.materialbox');
$(document).off('keyup.materialbox');
$(window).off('resize.materialbox');
$('#materialbox-overlay').velocity({opacity: 0}, {
duration: outDuration, // Delay prevents animation overlapping
queue: false, easing: 'easeOutQuad',
complete: function(){
// Remove Overlay
overlayActive = false;
$(this).remove();
}
});
// Resize Image
origin.velocity(
{
width: originalWidth,
height: originalHeight,
left: 0,
top: 0
},
{
duration: outDuration,
queue: false, easing: 'easeOutQuad',
complete: function() {
placeholder.css({
height: '',
width: '',
position: '',
top: '',
left: ''
});
origin.removeAttr('style');
origin.attr('style', originInlineStyles);
// Remove class
origin.removeClass('active');
doneAnimating = true;
// Remove overflow overrides on ancestors
if (ancestorsChanged) {
ancestorsChanged.css('overflow', '');
}
}
}
);
// Remove Caption + reset css settings on image
$('.materialbox-caption').velocity({opacity: 0}, {
duration: outDuration, // Delay prevents animation overlapping
queue: false, easing: 'easeOutQuad',
complete: function(){
$(this).remove();
}
});
}
});
};
$(document).ready(function(){
$('.materialboxed').materialbox();
});
}( jQuery ));

View file

@ -0,0 +1,371 @@
(function($, Vel) {
'use strict';
let _defaults = {
opacity: 0.5,
inDuration: 250,
outDuration: 250,
ready: undefined,
complete: undefined,
dismissible: true,
startingTop: '4%',
endingTop: '10%'
};
/**
* @class
*
*/
class Modal {
/**
* Construct Modal instance and set up overlay
* @constructor
* @param {jQuery} $el
* @param {Object} options
*/
constructor($el, options) {
// If exists, destroy and reinitialize
if (!!$el[0].M_Modal) {
$el[0].M_Modal.destroy();
}
/**
* The jQuery element
* @type {jQuery}
*/
this.$el = $el;
/**
* Options for the modal
* @member Modal#options
* @prop {Number} [opacity=0.5] - Opacity of the modal overlay
* @prop {Number} [inDuration=250] - Length in ms of enter transition
* @prop {Number} [outDuration=250] - Length in ms of exit transition
* @prop {Function} ready - Callback function called when modal is finished entering
* @prop {Function} complete - Callback function called when modal is finished exiting
* @prop {Boolean} [dismissible=true] - Allow modal to be dismissed by keyboard or overlay click
* @prop {String} [startingTop='4%'] - startingTop
* @prop {String} [endingTop='10%'] - endingTop
*/
this.options = $.extend({}, Modal.defaults, options);
/**
* Describes open/close state of modal
* @type {Boolean}
*/
this.isOpen = false;
this.$el[0].M_Modal = this;
this.id = $el.attr('id');
this.openingTrigger = undefined;
this.$overlay = $('<div class="modal-overlay"></div>');
Modal._increment++;
Modal._count++;
this.$overlay[0].style.zIndex = 1000 + Modal._increment * 2;
this.$el[0].style.zIndex = 1000 + Modal._increment * 2 + 1;
this.setupEventHandlers();
}
static get defaults() {
return _defaults;
}
static init($els, options) {
let arr = [];
$els.each(function() {
arr.push(new Modal($(this), options));
});
return arr;
}
/**
* Get Instance
*/
getInstance() {
return this;
}
/**
* Teardown component
*/
destroy() {
this.removeEventHandlers();
this.$el[0].removeAttribute('style')
if (!!this.$overlay[0].parentNode) {
this.$overlay[0].parentNode.removeChild(this.$overlay[0]);
}
this.$el[0].M_Modal = undefined;
Modal._count--;
}
/**
* Setup Event Handlers
*/
setupEventHandlers() {
this.handleOverlayClickBound = this.handleOverlayClick.bind(this);
this.handleModalCloseClickBound = this.handleModalCloseClick.bind(this);
if (Modal._count === 1) {
document.body.addEventListener('click', this.handleTriggerClick);
}
this.$overlay[0].addEventListener('click', this.handleOverlayClickBound);
this.$el[0].addEventListener('click', this.handleModalCloseClickBound);
}
/**
* Remove Event Handlers
*/
removeEventHandlers() {
if (Modal._count === 0) {
document.body.removeEventListener('click', this.handleTriggerClick);
}
this.$overlay[0].removeEventListener('click', this.handleOverlayClickBound);
this.$el[0].removeEventListener('click', this.handleModalCloseClickBound);
}
/**
* Handle Trigger Click
* @param {Event} e
*/
handleTriggerClick(e) {
let $trigger = $(e.target).closest('.modal-trigger');
if (e.target && $trigger.length) {
let modalId = $trigger[0].getAttribute('href');
if (modalId) {
modalId = modalId.slice(1);
} else {
modalId = $trigger[0].getAttribute('data-target');
}
let modalInstance = document.getElementById(modalId).M_Modal;
if (modalInstance) {
modalInstance.open($trigger);
}
e.preventDefault();
}
}
/**
* Handle Overlay Click
*/
handleOverlayClick() {
if (this.options.dismissible) {
this.close();
}
}
/**
* Handle Modal Close Click
* @param {Event} e
*/
handleModalCloseClick(e) {
let $closeTrigger = $(e.target).closest('.modal-close');
if (e.target && $closeTrigger.length) {
this.close();
}
}
/**
* Handle Keydown
* @param {Event} e
*/
handleKeydown(e) {
// ESC key
if (e.keyCode === 27 && this.options.dismissible) {
this.close();
}
}
/**
* Animate in modal
*/
animateIn() {
// Set initial styles
$.extend(this.$el[0].style, {
display: 'block',
opacity: 0
});
$.extend(this.$overlay[0].style, {
display: 'block',
opacity: 0
});
// Animate overlay
Vel(
this.$overlay[0],
{opacity: this.options.opacity},
{duration: this.options.inDuration, queue: false, ease: 'easeOutCubic'}
);
// Define modal animation options
let enterVelocityOptions = {
duration: this.options.inDuration,
queue: false,
ease: 'easeOutCubic',
// Handle modal ready callback
complete: () => {
if (typeof(this.options.ready) === 'function') {
this.options.ready.call(this, this.$el, this.openingTrigger);
}
}
};
// Bottom sheet animation
if (this.$el[0].classList.contains('bottom-sheet')) {
Vel(
this.$el[0],
{bottom: 0, opacity: 1},
enterVelocityOptions);
// Normal modal animation
} else {
Vel.hook(this.$el[0], 'scaleX', 0.7);
this.$el[0].style.top = this.options.startingTop;
Vel(
this.$el[0],
{top: this.options.endingTop, opacity: 1, scaleX: 1},
enterVelocityOptions
);
}
}
/**
* Animate out modal
*/
animateOut() {
// Animate overlay
Vel(
this.$overlay[0],
{ opacity: 0},
{duration: this.options.outDuration, queue: false, ease: 'easeOutQuart'}
);
// Define modal animation options
var exitVelocityOptions = {
duration: this.options.outDuration,
queue: false,
ease: 'easeOutCubic',
// Handle modal ready callback
complete: () => {
this.$el[0].style.display = 'none';
// Call complete callback
if (typeof(this.options.complete) === 'function') {
this.options.complete.call(this, this.$el);
}
this.$overlay[0].parentNode.removeChild(this.$overlay[0]);
}
};
// Bottom sheet animation
if (this.$el[0].classList.contains('bottom-sheet')) {
Vel(
this.$el[0],
{bottom: '-100%', opacity: 0},
exitVelocityOptions
);
// Normal modal animation
} else {
Vel(
this.$el[0],
{top: this.options.startingTop, opacity: 0, scaleX: 0.7},
exitVelocityOptions
);
}
}
/**
* Open Modal
* @param {jQuery} [$trigger]
*/
open($trigger) {
if (this.isOpen) {
return;
}
this.isOpen = true;
let body = document.body;
body.style.overflow = 'hidden';
this.$el[0].classList.add('open');
body.appendChild(this.$overlay[0]);
// Set opening trigger, undefined indicates modal was opened by javascript
this.openingTrigger = !!$trigger ? $trigger : undefined;
if (this.options.dismissible) {
this.handleKeydownBound = this.handleKeydown.bind(this);
document.addEventListener('keydown', this.handleKeydownBound);
}
this.animateIn();
return this;
}
/**
* Close Modal
*/
close() {
if (!this.isOpen) {
return;
}
this.isOpen = false;
this.$el[0].classList.remove('open');
document.body.style.overflow = '';
if (this.options.dismissible) {
document.removeEventListener('keydown', this.handleKeydownBound);
}
this.animateOut();
return this;
}
}
/**
* @static
* @memberof Modal
*/
Modal._increment = 0;
/**
* @static
* @memberof Modal
*/
Modal._count = 0;
Materialize.Modal = Modal;
$.fn.modal = function(methodOrOptions) {
// Call plugin method if valid method name is passed in
if (Modal.prototype[methodOrOptions]) {
// Getter methods
if (methodOrOptions.slice(0,3) === 'get') {
return this.first()[0].M_Modal[methodOrOptions]();
// Void methods
} else {
return this.each(function() {
this.M_Modal[methodOrOptions]();
});
}
// Initialize plugin if options or no argument is passed in
} else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
Modal.init(this, arguments[0]);
return this;
// Return error if an unrecognized method name is passed in
} else {
$.error(`Method ${methodOrOptions} does not exist on jQuery.modal`);
}
};
})(jQuery, Materialize.Vel);

View file

@ -0,0 +1,58 @@
(function ($) {
$.fn.parallax = function () {
var window_width = $(window).width();
// Parallax Scripts
return this.each(function(i) {
var $this = $(this);
$this.addClass('parallax');
function updateParallax(initial) {
var container_height;
if (window_width < 601) {
container_height = ($this.height() > 0) ? $this.height() : $this.children("img").height();
}
else {
container_height = ($this.height() > 0) ? $this.height() : 500;
}
var $img = $this.children("img").first();
var img_height = $img.height();
var parallax_dist = img_height - container_height;
var bottom = $this.offset().top + container_height;
var top = $this.offset().top;
var scrollTop = $(window).scrollTop();
var windowHeight = window.innerHeight;
var windowBottom = scrollTop + windowHeight;
var percentScrolled = (windowBottom - top) / (container_height + windowHeight);
var parallax = Math.round((parallax_dist * percentScrolled));
if (initial) {
$img.css('display', 'block');
}
if ((bottom > scrollTop) && (top < (scrollTop + windowHeight))) {
$img.css('transform', "translate3D(-50%," + parallax + "px, 0)");
}
}
// Wait for image load
$this.children("img").one("load", function() {
updateParallax(true);
}).each(function() {
if (this.complete) $(this).trigger("load");
});
$(window).scroll(function() {
window_width = $(window).width();
updateParallax(false);
});
$(window).resize(function() {
window_width = $(window).width();
updateParallax(false);
});
});
};
}( jQuery ));

View file

@ -0,0 +1,71 @@
(function ($) {
$.fn.pushpin = function (options) {
// Defaults
var defaults = {
top: 0,
bottom: Infinity,
offset: 0
};
// Remove pushpin event and classes
if (options === "remove") {
this.each(function () {
if (id = $(this).data('pushpin-id')) {
$(window).off('scroll.' + id);
$(this).removeData('pushpin-id').removeClass('pin-top pinned pin-bottom').removeAttr('style');
}
});
return false;
}
options = $.extend(defaults, options);
$index = 0;
return this.each(function() {
var $uniqueId = Materialize.guid(),
$this = $(this),
$original_offset = $(this).offset().top;
function removePinClasses(object) {
object.removeClass('pin-top');
object.removeClass('pinned');
object.removeClass('pin-bottom');
}
function updateElements(objects, scrolled) {
objects.each(function () {
// Add position fixed (because its between top and bottom)
if (options.top <= scrolled && options.bottom >= scrolled && !$(this).hasClass('pinned')) {
removePinClasses($(this));
$(this).css('top', options.offset);
$(this).addClass('pinned');
}
// Add pin-top (when scrolled position is above top)
if (scrolled < options.top && !$(this).hasClass('pin-top')) {
removePinClasses($(this));
$(this).css('top', 0);
$(this).addClass('pin-top');
}
// Add pin-bottom (when scrolled position is below bottom)
if (scrolled > options.bottom && !$(this).hasClass('pin-bottom')) {
removePinClasses($(this));
$(this).addClass('pin-bottom');
$(this).css('top', options.bottom - $original_offset);
}
});
}
$(this).data('pushpin-id', $uniqueId);
updateElements($this, $(window).scrollTop());
$(window).on('scroll.' + $uniqueId, function () {
var $scrolled = $(window).scrollTop() + options.offset;
updateElements($this, $scrolled);
});
});
};
}( jQuery ));

View file

@ -0,0 +1,51 @@
(function($) {
var scrollFireEventsHandled = false;
// Input: Array of JSON objects {selector, offset, callback}
Materialize.scrollFire = function(options) {
var onScroll = function() {
var windowScroll = window.pageYOffset + window.innerHeight;
for (var i = 0 ; i < options.length; i++) {
// Get options from each line
var value = options[i];
var selector = value.selector,
offset = value.offset,
callback = value.callback;
var currentElement = document.querySelector(selector);
if ( currentElement !== null) {
var elementOffset = currentElement.getBoundingClientRect().top + window.pageYOffset;
if (windowScroll > (elementOffset + offset)) {
if (value.done !== true) {
if (typeof(callback) === 'function') {
callback.call(this, currentElement);
} else if (typeof(callback) === 'string') {
var callbackFunc = new Function(callback);
callbackFunc(currentElement);
}
value.done = true;
}
}
}
}
};
var throttledScroll = Materialize.throttle(function() {
onScroll();
}, options.throttle || 100);
if (!scrollFireEventsHandled) {
window.addEventListener("scroll", throttledScroll);
window.addEventListener("resize", throttledScroll);
scrollFireEventsHandled = true;
}
// perform a scan once, after current execution context, and after dom is ready
setTimeout(throttledScroll, 0);
};
})(jQuery);

View file

@ -0,0 +1,238 @@
/**
* Extend jquery with a scrollspy plugin.
* This watches the window scroll and fires events when elements are scrolled into viewport.
*
* throttle() and getTime() taken from Underscore.js
* https://github.com/jashkenas/underscore
*
* @author Copyright 2013 John Smart
* @license https://raw.github.com/thesmart/jquery-scrollspy/master/LICENSE
* @see https://github.com/thesmart
* @version 0.1.2
*/
(function($) {
var jWindow = $(window);
var elements = [];
var elementsInView = [];
var isSpying = false;
var ticks = 0;
var unique_id = 1;
var offset = {
top : 0,
right : 0,
bottom : 0,
left : 0,
}
/**
* Find elements that are within the boundary
* @param {number} top
* @param {number} right
* @param {number} bottom
* @param {number} left
* @return {jQuery} A collection of elements
*/
function findElements(top, right, bottom, left) {
var hits = $();
$.each(elements, function(i, element) {
if (element.height() > 0) {
var elTop = element.offset().top,
elLeft = element.offset().left,
elRight = elLeft + element.width(),
elBottom = elTop + element.height();
var isIntersect = !(elLeft > right ||
elRight < left ||
elTop > bottom ||
elBottom < top);
if (isIntersect) {
hits.push(element);
}
}
});
return hits;
}
/**
* Called when the user scrolls the window
*/
function onScroll(scrollOffset) {
// unique tick id
++ticks;
// viewport rectangle
var top = jWindow.scrollTop(),
left = jWindow.scrollLeft(),
right = left + jWindow.width(),
bottom = top + jWindow.height();
// determine which elements are in view
var intersections = findElements(top+offset.top + scrollOffset || 200, right+offset.right, bottom+offset.bottom, left+offset.left);
$.each(intersections, function(i, element) {
var lastTick = element.data('scrollSpy:ticks');
if (typeof lastTick != 'number') {
// entered into view
element.triggerHandler('scrollSpy:enter');
}
// update tick id
element.data('scrollSpy:ticks', ticks);
});
// determine which elements are no longer in view
$.each(elementsInView, function(i, element) {
var lastTick = element.data('scrollSpy:ticks');
if (typeof lastTick == 'number' && lastTick !== ticks) {
// exited from view
element.triggerHandler('scrollSpy:exit');
element.data('scrollSpy:ticks', null);
}
});
// remember elements in view for next tick
elementsInView = intersections;
}
/**
* Called when window is resized
*/
function onWinSize() {
jWindow.trigger('scrollSpy:winSize');
}
/**
* Enables ScrollSpy using a selector
* @param {jQuery|string} selector The elements collection, or a selector
* @param {Object=} options Optional.
throttle : number -> scrollspy throttling. Default: 100 ms
offsetTop : number -> offset from top. Default: 0
offsetRight : number -> offset from right. Default: 0
offsetBottom : number -> offset from bottom. Default: 0
offsetLeft : number -> offset from left. Default: 0
activeClass : string -> Class name to be added to the active link. Default: active
* @returns {jQuery}
*/
$.scrollSpy = function(selector, options) {
var defaults = {
throttle: 100,
scrollOffset: 200, // offset - 200 allows elements near bottom of page to scroll
activeClass: 'active',
getActiveElement: function(id) {
return 'a[href="#' + id + '"]';
}
};
options = $.extend(defaults, options);
var visible = [];
selector = $(selector);
selector.each(function(i, element) {
elements.push($(element));
$(element).data("scrollSpy:id", i);
// Smooth scroll to section
$('a[href="#' + $(element).attr('id') + '"]').click(function(e) {
e.preventDefault();
var offset = $(Materialize.escapeHash(this.hash)).offset().top + 1;
$('html, body').animate({ scrollTop: offset - options.scrollOffset }, {duration: 400, queue: false, easing: 'easeOutCubic'});
});
});
offset.top = options.offsetTop || 0;
offset.right = options.offsetRight || 0;
offset.bottom = options.offsetBottom || 0;
offset.left = options.offsetLeft || 0;
var throttledScroll = Materialize.throttle(function() {
onScroll(options.scrollOffset);
}, options.throttle || 100);
var readyScroll = function(){
$(document).ready(throttledScroll);
};
if (!isSpying) {
jWindow.on('scroll', readyScroll);
jWindow.on('resize', readyScroll);
isSpying = true;
}
// perform a scan once, after current execution context, and after dom is ready
setTimeout(readyScroll, 0);
selector.on('scrollSpy:enter', function() {
visible = $.grep(visible, function(value) {
return value.height() != 0;
});
var $this = $(this);
if (visible[0]) {
$(options.getActiveElement(visible[0].attr('id'))).removeClass(options.activeClass);
if ($this.data('scrollSpy:id') < visible[0].data('scrollSpy:id')) {
visible.unshift($(this));
}
else {
visible.push($(this));
}
}
else {
visible.push($(this));
}
$(options.getActiveElement(visible[0].attr('id'))).addClass(options.activeClass);
});
selector.on('scrollSpy:exit', function() {
visible = $.grep(visible, function(value) {
return value.height() != 0;
});
if (visible[0]) {
$(options.getActiveElement(visible[0].attr('id'))).removeClass(options.activeClass);
var $this = $(this);
visible = $.grep(visible, function(value) {
return value.attr('id') != $this.attr('id');
});
if (visible[0]) { // Check if empty
$(options.getActiveElement(visible[0].attr('id'))).addClass(options.activeClass);
}
}
});
return selector;
};
/**
* Listen for window resize events
* @param {Object=} options Optional. Set { throttle: number } to change throttling. Default: 100 ms
* @returns {jQuery} $(window)
*/
$.winSizeSpy = function(options) {
$.winSizeSpy = function() { return jWindow; }; // lock from multiple calls
options = options || {
throttle: 100
};
return jWindow.on('resize', Materialize.throttle(onWinSize, options.throttle || 100));
};
/**
* Enables ScrollSpy on a collection of elements
* e.g. $('.scrollSpy').scrollSpy()
* @param {Object=} options Optional.
throttle : number -> scrollspy throttling. Default: 100 ms
offsetTop : number -> offset from top. Default: 0
offsetRight : number -> offset from right. Default: 0
offsetBottom : number -> offset from bottom. Default: 0
offsetLeft : number -> offset from left. Default: 0
* @returns {jQuery}
*/
$.fn.scrollSpy = function(options) {
return $.scrollSpy($(this), options);
};
})(jQuery);

View file

@ -0,0 +1,414 @@
(function ($) {
var methods = {
init : function(options) {
var defaults = {
menuWidth: 300,
edge: 'left',
closeOnClick: false,
draggable: true,
onOpen: null,
onClose: null
};
options = $.extend(defaults, options);
$(this).each(function(){
var $this = $(this);
var menuId = $this.attr('data-activates');
var menu = $("#"+ menuId);
// Set to width
if (options.menuWidth != 300) {
menu.css('width', options.menuWidth);
}
// Add Touch Area
var $dragTarget = $('.drag-target[data-sidenav="' + menuId + '"]');
if (options.draggable) {
// Regenerate dragTarget
if ($dragTarget.length) {
$dragTarget.remove();
}
$dragTarget = $('<div class="drag-target"></div>').attr('data-sidenav', menuId);
$('body').append($dragTarget);
} else {
$dragTarget = $();
}
if (options.edge == 'left') {
menu.css('transform', 'translateX(-100%)');
$dragTarget.css({'left': 0}); // Add Touch Area
}
else {
menu.addClass('right-aligned') // Change text-alignment to right
.css('transform', 'translateX(100%)');
$dragTarget.css({'right': 0}); // Add Touch Area
}
// If fixed sidenav, bring menu out
if (menu.hasClass('fixed')) {
if (window.innerWidth > 992) {
menu.css('transform', 'translateX(0)');
}
}
// Window resize to reset on large screens fixed
if (menu.hasClass('fixed')) {
$(window).resize( function() {
if (window.innerWidth > 992) {
// Close menu if window is resized bigger than 992 and user has fixed sidenav
if ($('#sidenav-overlay').length !== 0 && menuOut) {
removeMenu(true);
}
else {
// menu.removeAttr('style');
menu.css('transform', 'translateX(0%)');
// menu.css('width', options.menuWidth);
}
}
else if (menuOut === false){
if (options.edge === 'left') {
menu.css('transform', 'translateX(-100%)');
} else {
menu.css('transform', 'translateX(100%)');
}
}
});
}
// if closeOnClick, then add close event for all a tags in side sideNav
if (options.closeOnClick === true) {
menu.on("click.itemclick", "a:not(.collapsible-header)", function(){
if (!(window.innerWidth > 992 && menu.hasClass('fixed'))){
removeMenu();
}
});
}
var removeMenu = function(restoreNav) {
panning = false;
menuOut = false;
// Reenable scrolling
$('body').css({
overflow: '',
width: ''
});
$('#sidenav-overlay').velocity({opacity: 0}, {duration: 200,
queue: false, easing: 'easeOutQuad',
complete: function() {
$(this).remove();
} });
if (options.edge === 'left') {
// Reset phantom div
$dragTarget.css({width: '', right: '', left: '0'});
menu.velocity(
{'translateX': '-100%'},
{ duration: 200,
queue: false,
easing: 'easeOutCubic',
complete: function() {
if (restoreNav === true) {
// Restore Fixed sidenav
menu.removeAttr('style');
menu.css('width', options.menuWidth);
}
}
});
}
else {
// Reset phantom div
$dragTarget.css({width: '', right: '0', left: ''});
menu.velocity(
{'translateX': '100%'},
{ duration: 200,
queue: false,
easing: 'easeOutCubic',
complete: function() {
if (restoreNav === true) {
// Restore Fixed sidenav
menu.removeAttr('style');
menu.css('width', options.menuWidth);
}
}
});
}
// Callback
if (typeof(options.onClose) === 'function') {
options.onClose.call(this, menu);
}
}
// Touch Event
var panning = false;
var menuOut = false;
if (options.draggable) {
$dragTarget.on('click', function(){
if (menuOut) {
removeMenu();
}
});
$dragTarget.hammer({
prevent_default: false
}).on('pan', function(e) {
if (e.gesture.pointerType == "touch") {
var direction = e.gesture.direction;
var x = e.gesture.center.x;
var y = e.gesture.center.y;
var velocityX = e.gesture.velocityX;
// Vertical scroll bugfix
if (x === 0 && y === 0) {
return;
}
// Disable Scrolling
var $body = $('body');
var $overlay = $('#sidenav-overlay');
var oldWidth = $body.innerWidth();
$body.css('overflow', 'hidden');
$body.width(oldWidth);
// If overlay does not exist, create one and if it is clicked, close menu
if ($overlay.length === 0) {
$overlay = $('<div id="sidenav-overlay"></div>');
$overlay.css('opacity', 0).click( function(){
removeMenu();
});
// Run 'onOpen' when sidenav is opened via touch/swipe if applicable
if (typeof(options.onOpen) === 'function') {
options.onOpen.call(this, menu);
}
$('body').append($overlay);
}
// Keep within boundaries
if (options.edge === 'left') {
if (x > options.menuWidth) { x = options.menuWidth; }
else if (x < 0) { x = 0; }
}
if (options.edge === 'left') {
// Left Direction
if (x < (options.menuWidth / 2)) { menuOut = false; }
// Right Direction
else if (x >= (options.menuWidth / 2)) { menuOut = true; }
menu.css('transform', 'translateX(' + (x - options.menuWidth) + 'px)');
}
else {
// Left Direction
if (x < (window.innerWidth - options.menuWidth / 2)) {
menuOut = true;
}
// Right Direction
else if (x >= (window.innerWidth - options.menuWidth / 2)) {
menuOut = false;
}
var rightPos = (x - options.menuWidth / 2);
if (rightPos < 0) {
rightPos = 0;
}
menu.css('transform', 'translateX(' + rightPos + 'px)');
}
// Percentage overlay
var overlayPerc;
if (options.edge === 'left') {
overlayPerc = x / options.menuWidth;
$overlay.velocity({opacity: overlayPerc }, {duration: 10, queue: false, easing: 'easeOutQuad'});
}
else {
overlayPerc = Math.abs((x - window.innerWidth) / options.menuWidth);
$overlay.velocity({opacity: overlayPerc }, {duration: 10, queue: false, easing: 'easeOutQuad'});
}
}
}).on('panend', function(e) {
if (e.gesture.pointerType == "touch") {
var $overlay = $('#sidenav-overlay');
var velocityX = e.gesture.velocityX;
var x = e.gesture.center.x;
var leftPos = x - options.menuWidth;
var rightPos = x - options.menuWidth / 2;
if (leftPos > 0 ) {
leftPos = 0;
}
if (rightPos < 0) {
rightPos = 0;
}
panning = false;
if (options.edge === 'left') {
// If velocityX <= 0.3 then the user is flinging the menu closed so ignore menuOut
if ((menuOut && velocityX <= 0.3) || velocityX < -0.5) {
// Return menu to open
if (leftPos !== 0) {
menu.velocity({'translateX': [0, leftPos]}, {duration: 300, queue: false, easing: 'easeOutQuad'});
}
$overlay.velocity({opacity: 1 }, {duration: 50, queue: false, easing: 'easeOutQuad'});
$dragTarget.css({width: '50%', right: 0, left: ''});
menuOut = true;
}
else if (!menuOut || velocityX > 0.3) {
// Enable Scrolling
$('body').css({
overflow: '',
width: ''
});
// Slide menu closed
menu.velocity({'translateX': [-1 * options.menuWidth - 10, leftPos]}, {duration: 200, queue: false, easing: 'easeOutQuad'});
$overlay.velocity({opacity: 0 }, {duration: 200, queue: false, easing: 'easeOutQuad',
complete: function () {
// Run 'onClose' when sidenav is closed via touch/swipe if applicable
if (typeof(options.onClose) === 'function') {
options.onClose.call(this, menu);
}
$(this).remove();
}});
$dragTarget.css({width: '10px', right: '', left: 0});
}
}
else {
if ((menuOut && velocityX >= -0.3) || velocityX > 0.5) {
// Return menu to open
if (rightPos !== 0) {
menu.velocity({'translateX': [0, rightPos]}, {duration: 300, queue: false, easing: 'easeOutQuad'});
}
$overlay.velocity({opacity: 1 }, {duration: 50, queue: false, easing: 'easeOutQuad'});
$dragTarget.css({width: '50%', right: '', left: 0});
menuOut = true;
}
else if (!menuOut || velocityX < -0.3) {
// Enable Scrolling
$('body').css({
overflow: '',
width: ''
});
// Slide menu closed
menu.velocity({'translateX': [options.menuWidth + 10, rightPos]}, {duration: 200, queue: false, easing: 'easeOutQuad'});
$overlay.velocity({opacity: 0 }, {duration: 200, queue: false, easing: 'easeOutQuad',
complete: function () {
// Run 'onClose' when sidenav is closed via touch/swipe if applicable
if (typeof(options.onClose) === 'function') {
options.onClose.call(this, menu);
}
$(this).remove();
}});
$dragTarget.css({width: '10px', right: 0, left: ''});
}
}
}
});
}
$this.off('click.sidenav').on('click.sidenav', function() {
if (menuOut === true) {
menuOut = false;
panning = false;
removeMenu();
}
else {
// Disable Scrolling
var $body = $('body');
var $overlay = $('<div id="sidenav-overlay"></div>');
var oldWidth = $body.innerWidth();
$body.css('overflow', 'hidden');
$body.width(oldWidth);
// Push current drag target on top of DOM tree
$('body').append($dragTarget);
if (options.edge === 'left') {
$dragTarget.css({width: '50%', right: 0, left: ''});
menu.velocity({'translateX': [0, -1 * options.menuWidth]}, {duration: 300, queue: false, easing: 'easeOutQuad'});
}
else {
$dragTarget.css({width: '50%', right: '', left: 0});
menu.velocity({'translateX': [0, options.menuWidth]}, {duration: 300, queue: false, easing: 'easeOutQuad'});
}
// Overlay close on click
$overlay.css('opacity', 0)
.click(function() {
menuOut = false;
panning = false;
removeMenu();
$overlay.velocity({opacity: 0}, {duration: 300, queue: false, easing: 'easeOutQuad',
complete: function() {
$(this).remove();
}
});
});
// Append body
$('body').append($overlay);
$overlay.velocity({opacity: 1}, {duration: 300, queue: false, easing: 'easeOutQuad',
complete: function () {
menuOut = true;
panning = false;
}
});
// Callback
if (typeof(options.onOpen) === 'function') {
options.onOpen.call(this, menu);
}
}
return false;
});
});
},
destroy: function () {
var $overlay = $('#sidenav-overlay');
var $dragTarget = $('.drag-target[data-sidenav="' + $(this).attr('data-activates') + '"]');
$overlay.trigger('click');
$dragTarget.remove();
$(this).off('click');
$overlay.remove();
},
show : function() {
this.trigger('click');
},
hide : function() {
$('#sidenav-overlay').trigger('click');
}
};
$.fn.sideNav = function(methodOrOptions) {
if ( methods[methodOrOptions] ) {
return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
// Default to "init"
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.sideNav' );
}
}; // Plugin end
}( jQuery ));

View file

@ -0,0 +1,324 @@
(function ($) {
var methods = {
init : function(options) {
var defaults = {
indicators: true,
height: 400,
transition: 500,
interval: 6000
};
options = $.extend(defaults, options);
return this.each(function() {
// For each slider, we want to keep track of
// which slide is active and its associated content
var $this = $(this);
var $slider = $this.find('ul.slides').first();
var $slides = $slider.find('> li');
var $active_index = $slider.find('.active').index();
var $active, $indicators, $interval;
if ($active_index != -1) { $active = $slides.eq($active_index); }
// Transitions the caption depending on alignment
function captionTransition(caption, duration) {
if (caption.hasClass("center-align")) {
caption.velocity({opacity: 0, translateY: -100}, {duration: duration, queue: false});
}
else if (caption.hasClass("right-align")) {
caption.velocity({opacity: 0, translateX: 100}, {duration: duration, queue: false});
}
else if (caption.hasClass("left-align")) {
caption.velocity({opacity: 0, translateX: -100}, {duration: duration, queue: false});
}
}
// This function will transition the slide to any index of the next slide
function moveToSlide(index) {
// Wrap around indices.
if (index >= $slides.length) index = 0;
else if (index < 0) index = $slides.length -1;
$active_index = $slider.find('.active').index();
// Only do if index changes
if ($active_index != index) {
$active = $slides.eq($active_index);
$caption = $active.find('.caption');
$active.removeClass('active');
$active.velocity({opacity: 0}, {duration: options.transition, queue: false, easing: 'easeOutQuad',
complete: function() {
$slides.not('.active').velocity({opacity: 0, translateX: 0, translateY: 0}, {duration: 0, queue: false});
} });
captionTransition($caption, options.transition);
// Update indicators
if (options.indicators) {
$indicators.eq($active_index).removeClass('active');
}
$slides.eq(index).velocity({opacity: 1}, {duration: options.transition, queue: false, easing: 'easeOutQuad'});
$slides.eq(index).find('.caption').velocity({opacity: 1, translateX: 0, translateY: 0}, {duration: options.transition, delay: options.transition, queue: false, easing: 'easeOutQuad'});
$slides.eq(index).addClass('active');
// Update indicators
if (options.indicators) {
$indicators.eq(index).addClass('active');
}
}
}
// Set height of slider
// If fullscreen, do nothing
if (!$this.hasClass('fullscreen')) {
if (options.indicators) {
// Add height if indicators are present
$this.height(options.height + 40);
}
else {
$this.height(options.height);
}
$slider.height(options.height);
}
// Set initial positions of captions
$slides.find('.caption').each(function () {
captionTransition($(this), 0);
});
// Move img src into background-image
$slides.find('img').each(function () {
var placeholderBase64 = 'data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
if ($(this).attr('src') !== placeholderBase64) {
$(this).css('background-image', 'url("' + $(this).attr('src') + '")' );
$(this).attr('src', placeholderBase64);
}
});
// dynamically add indicators
if (options.indicators) {
$indicators = $('<ul class="indicators"></ul>');
$slides.each(function( index ) {
var $indicator = $('<li class="indicator-item"></li>');
// Handle clicks on indicators
$indicator.click(function () {
var $parent = $slider.parent();
var curr_index = $parent.find($(this)).index();
moveToSlide(curr_index);
// reset interval
clearInterval($interval);
$interval = setInterval(
function(){
$active_index = $slider.find('.active').index();
if ($slides.length == $active_index + 1) $active_index = 0; // loop to start
else $active_index += 1;
moveToSlide($active_index);
}, options.transition + options.interval
);
});
$indicators.append($indicator);
});
$this.append($indicators);
$indicators = $this.find('ul.indicators').find('li.indicator-item');
}
if ($active) {
$active.show();
}
else {
$slides.first().addClass('active').velocity({opacity: 1}, {duration: options.transition, queue: false, easing: 'easeOutQuad'});
$active_index = 0;
$active = $slides.eq($active_index);
// Update indicators
if (options.indicators) {
$indicators.eq($active_index).addClass('active');
}
}
// Adjust height to current slide
$active.find('img').each(function() {
$active.find('.caption').velocity({opacity: 1, translateX: 0, translateY: 0}, {duration: options.transition, queue: false, easing: 'easeOutQuad'});
});
// auto scroll
$interval = setInterval(
function(){
$active_index = $slider.find('.active').index();
moveToSlide($active_index + 1);
}, options.transition + options.interval
);
// HammerJS, Swipe navigation
// Touch Event
var panning = false;
var swipeLeft = false;
var swipeRight = false;
$this.hammer({
prevent_default: false
}).on('pan', function(e) {
if (e.gesture.pointerType === "touch") {
// reset interval
clearInterval($interval);
var direction = e.gesture.direction;
var x = e.gesture.deltaX;
var velocityX = e.gesture.velocityX;
var velocityY = e.gesture.velocityY;
$curr_slide = $slider.find('.active');
if (Math.abs(velocityX) > Math.abs(velocityY)) {
$curr_slide.velocity({ translateX: x
}, {duration: 50, queue: false, easing: 'easeOutQuad'});
}
// Swipe Left
if (direction === 4 && (x > ($this.innerWidth() / 2) || velocityX < -0.65)) {
swipeRight = true;
}
// Swipe Right
else if (direction === 2 && (x < (-1 * $this.innerWidth() / 2) || velocityX > 0.65)) {
swipeLeft = true;
}
// Make Slide Behind active slide visible
var next_slide;
if (swipeLeft) {
next_slide = $curr_slide.next();
if (next_slide.length === 0) {
next_slide = $slides.first();
}
next_slide.velocity({ opacity: 1
}, {duration: 300, queue: false, easing: 'easeOutQuad'});
}
if (swipeRight) {
next_slide = $curr_slide.prev();
if (next_slide.length === 0) {
next_slide = $slides.last();
}
next_slide.velocity({ opacity: 1
}, {duration: 300, queue: false, easing: 'easeOutQuad'});
}
}
}).on('panend', function(e) {
if (e.gesture.pointerType === "touch") {
$curr_slide = $slider.find('.active');
panning = false;
curr_index = $slider.find('.active').index();
if (!swipeRight && !swipeLeft || $slides.length <=1) {
// Return to original spot
$curr_slide.velocity({ translateX: 0
}, {duration: 300, queue: false, easing: 'easeOutQuad'});
}
else if (swipeLeft) {
moveToSlide(curr_index + 1);
$curr_slide.velocity({translateX: -1 * $this.innerWidth() }, {duration: 300, queue: false, easing: 'easeOutQuad',
complete: function() {
$curr_slide.velocity({opacity: 0, translateX: 0}, {duration: 0, queue: false});
} });
}
else if (swipeRight) {
moveToSlide(curr_index - 1);
$curr_slide.velocity({translateX: $this.innerWidth() }, {duration: 300, queue: false, easing: 'easeOutQuad',
complete: function() {
$curr_slide.velocity({opacity: 0, translateX: 0}, {duration: 0, queue: false});
} });
}
swipeLeft = false;
swipeRight = false;
// Restart interval
clearInterval($interval);
$interval = setInterval(
function(){
$active_index = $slider.find('.active').index();
if ($slides.length == $active_index + 1) $active_index = 0; // loop to start
else $active_index += 1;
moveToSlide($active_index);
}, options.transition + options.interval
);
}
});
$this.on('sliderPause', function() {
clearInterval($interval);
});
$this.on('sliderStart', function() {
clearInterval($interval);
$interval = setInterval(
function(){
$active_index = $slider.find('.active').index();
if ($slides.length == $active_index + 1) $active_index = 0; // loop to start
else $active_index += 1;
moveToSlide($active_index);
}, options.transition + options.interval
);
});
$this.on('sliderNext', function() {
$active_index = $slider.find('.active').index();
moveToSlide($active_index + 1);
});
$this.on('sliderPrev', function() {
$active_index = $slider.find('.active').index();
moveToSlide($active_index - 1);
});
});
},
pause : function() {
$(this).trigger('sliderPause');
},
start : function() {
$(this).trigger('sliderStart');
},
next : function() {
$(this).trigger('sliderNext');
},
prev : function() {
$(this).trigger('sliderPrev');
}
};
$.fn.slider = function(methodOrOptions) {
if ( methods[methodOrOptions] ) {
return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
// Default to "init"
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.tooltip' );
}
}; // Plugin end
}( jQuery ));

View file

@ -0,0 +1,246 @@
(function ($) {
var methods = {
init : function(options) {
var defaults = {
onShow: null,
swipeable: false,
responsiveThreshold: Infinity, // breakpoint for swipeable
};
options = $.extend(defaults, options);
var namespace = Materialize.objectSelectorString($(this));
return this.each(function(i) {
var uniqueNamespace = namespace+i;
// For each set of tabs, we want to keep track of
// which tab is active and its associated content
var $this = $(this),
window_width = $(window).width();
var $active, $content, $links = $this.find('li.tab a'),
$tabs_width = $this.width(),
$tabs_content = $(),
$tabs_wrapper,
$tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length,
$indicator,
index = 0,
prev_index = 0,
clicked = false,
clickedTimeout,
transition = 300;
// Finds right attribute for indicator based on active tab.
// el: jQuery Object
var calcRightPos = function(el) {
return Math.ceil($tabs_width - el.position().left - el[0].getBoundingClientRect().width - $this.scrollLeft());
};
// Finds left attribute for indicator based on active tab.
// el: jQuery Object
var calcLeftPos = function(el) {
return Math.floor(el.position().left + $this.scrollLeft());
};
// Animates Indicator to active tab.
// prev_index: Number
var animateIndicator = function(prev_index) {
if ((index - prev_index) >= 0) {
$indicator.velocity({"right": calcRightPos($active) }, { duration: transition, queue: false, easing: 'easeOutQuad'});
$indicator.velocity({"left": calcLeftPos($active) }, {duration: transition, queue: false, easing: 'easeOutQuad', delay: 90});
} else {
$indicator.velocity({"left": calcLeftPos($active) }, { duration: transition, queue: false, easing: 'easeOutQuad'});
$indicator.velocity({"right": calcRightPos($active) }, {duration: transition, queue: false, easing: 'easeOutQuad', delay: 90});
}
};
// Change swipeable according to responsive threshold
if (options.swipeable) {
if (window_width > options.responsiveThreshold) {
options.swipeable = false;
}
}
// If the location.hash matches one of the links, use that as the active tab.
$active = $($links.filter('[href="'+location.hash+'"]'));
// If no match is found, use the first link or any with class 'active' as the initial active tab.
if ($active.length === 0) {
$active = $(this).find('li.tab a.active').first();
}
if ($active.length === 0) {
$active = $(this).find('li.tab a').first();
}
$active.addClass('active');
index = $links.index($active);
if (index < 0) {
index = 0;
}
if ($active[0] !== undefined) {
$content = $($active[0].hash);
$content.addClass('active');
}
// append indicator then set indicator width to tab width
if (!$this.find('.indicator').length) {
$this.append('<li class="indicator"></li>');
}
$indicator = $this.find('.indicator');
// we make sure that the indicator is at the end of the tabs
$this.append($indicator);
if ($this.is(":visible")) {
// $indicator.css({"right": $tabs_width - ((index + 1) * $tab_width)});
// $indicator.css({"left": index * $tab_width});
setTimeout(function() {
$indicator.css({"right": calcRightPos($active) });
$indicator.css({"left": calcLeftPos($active) });
}, 0);
}
$(window).off('resize.tabs-'+uniqueNamespace).on('resize.tabs-'+uniqueNamespace, function () {
$tabs_width = $this.width();
$tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length;
if (index < 0) {
index = 0;
}
if ($tab_width !== 0 && $tabs_width !== 0) {
$indicator.css({"right": calcRightPos($active) });
$indicator.css({"left": calcLeftPos($active) });
}
});
// Initialize Tabs Content.
if (options.swipeable) {
// TODO: Duplicate calls with swipeable? handle multiple div wrapping.
$links.each(function () {
var $curr_content = $(Materialize.escapeHash(this.hash));
$curr_content.addClass('carousel-item');
$tabs_content = $tabs_content.add($curr_content);
});
$tabs_wrapper = $tabs_content.wrapAll('<div class="tabs-content carousel"></div>');
$tabs_content.css('display', '');
$('.tabs-content.carousel').carousel({
fullWidth: true,
noWrap: true,
onCycleTo: function(item) {
if (!clicked) {
var prev_index = index;
index = $tabs_wrapper.index(item);
$active.removeClass('active');
$active = $links.eq(index);
$active.addClass('active');
animateIndicator(prev_index);
if (typeof(options.onShow) === "function") {
options.onShow.call($this[0], $content);
}
}
},
});
} else {
// Hide the remaining content
$links.not($active).each(function () {
$(Materialize.escapeHash(this.hash)).hide();
});
}
// Bind the click event handler
$this.off('click.tabs').on('click.tabs', 'a', function(e) {
if ($(this).parent().hasClass('disabled')) {
e.preventDefault();
return;
}
// Act as regular link if target attribute is specified.
if (!!$(this).attr("target")) {
return;
}
clicked = true;
$tabs_width = $this.width();
$tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length;
// Make the old tab inactive.
$active.removeClass('active');
var $oldContent = $content
// Update the variables with the new link and content
$active = $(this);
$content = $(Materialize.escapeHash(this.hash));
$links = $this.find('li.tab a');
var activeRect = $active.position();
// Make the tab active.
$active.addClass('active');
prev_index = index;
index = $links.index($(this));
if (index < 0) {
index = 0;
}
// Change url to current tab
// window.location.hash = $active.attr('href');
// Swap content
if (options.swipeable) {
if ($tabs_content.length) {
$tabs_content.carousel('set', index, function() {
if (typeof(options.onShow) === "function") {
options.onShow.call($this[0], $content);
}
});
}
} else {
if ($content !== undefined) {
$content.show();
$content.addClass('active');
if (typeof(options.onShow) === "function") {
options.onShow.call(this, $content);
}
}
if ($oldContent !== undefined &&
!$oldContent.is($content)) {
$oldContent.hide();
$oldContent.removeClass('active');
}
}
// Reset clicked state
clickedTimeout = setTimeout(function(){ clicked = false; }, transition);
// Update indicator
animateIndicator(prev_index);
// Prevent the anchor's default click action
e.preventDefault();
});
});
},
select_tab : function( id ) {
this.find('a[href="#' + id + '"]').trigger('click');
}
};
$.fn.tabs = function(methodOrOptions) {
if ( methods[methodOrOptions] ) {
return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
// Default to "init"
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.tabs' );
}
};
$(document).ready(function(){
$('ul.tabs').tabs();
});
}( jQuery ));

View file

@ -0,0 +1,187 @@
(function ($) {
var methods = {
init: function (options) {
return this.each(function() {
var origin = $('#'+$(this).attr('data-activates'));
var screen = $('body');
// Creating tap target
var tapTargetEl = $(this);
var tapTargetWrapper = tapTargetEl.parent('.tap-target-wrapper');
var tapTargetWave = tapTargetWrapper.find('.tap-target-wave');
var tapTargetOriginEl = tapTargetWrapper.find('.tap-target-origin');
var tapTargetContentEl = tapTargetEl.find('.tap-target-content');
// Creating wrapper
if (!tapTargetWrapper.length) {
tapTargetWrapper = tapTargetEl.wrap($('<div class="tap-target-wrapper"></div>')).parent();
}
// Creating content
if (!tapTargetContentEl.length) {
tapTargetContentEl = $('<div class="tap-target-content"></div>');
tapTargetEl.append(tapTargetContentEl);
}
// Creating foreground wave
if (!tapTargetWave.length) {
tapTargetWave = $('<div class="tap-target-wave"></div>');
// Creating origin
if (!tapTargetOriginEl.length) {
tapTargetOriginEl = origin.clone(true, true);
tapTargetOriginEl.addClass('tap-target-origin');
tapTargetOriginEl.removeAttr('id');
tapTargetOriginEl.removeAttr('style');
tapTargetWave.append(tapTargetOriginEl);
}
tapTargetWrapper.append(tapTargetWave);
}
// Open
var openTapTarget = function() {
if (tapTargetWrapper.is('.open')) {
return;
}
// Adding open class
tapTargetWrapper.addClass('open');
setTimeout(function() {
tapTargetOriginEl.off('click.tapTarget').on('click.tapTarget', function(e) {
closeTapTarget();
tapTargetOriginEl.off('click.tapTarget');
});
$(document).off('click.tapTarget').on('click.tapTarget', function(e) {
closeTapTarget();
$(document).off('click.tapTarget');
});
var throttledCalc = Materialize.throttle(function() {
calculateTapTarget();
}, 200);
$(window).off('resize.tapTarget').on('resize.tapTarget', throttledCalc);
}, 0);
};
// Close
var closeTapTarget = function(){
if (!tapTargetWrapper.is('.open')) {
return;
}
tapTargetWrapper.removeClass('open');
tapTargetOriginEl.off('click.tapTarget')
$(document).off('click.tapTarget');
$(window).off('resize.tapTarget');
};
// Pre calculate
var calculateTapTarget = function() {
// Element or parent is fixed position?
var isFixed = origin.css('position') === 'fixed';
if (!isFixed) {
var parents = origin.parents();
for(var i = 0; i < parents.length; i++) {
isFixed = $(parents[i]).css('position') == 'fixed';
if (isFixed) {
break;
}
}
}
// Calculating origin
var originWidth = origin.outerWidth();
var originHeight = origin.outerHeight();
var originTop = isFixed ? origin.offset().top - $(document).scrollTop() : origin.offset().top;
var originLeft = isFixed ? origin.offset().left - $(document).scrollLeft() : origin.offset().left;
// Calculating screen
var windowWidth = $(window).width();
var windowHeight = $(window).height();
var centerX = windowWidth / 2;
var centerY = windowHeight / 2;
var isLeft = originLeft <= centerX;
var isRight = originLeft > centerX;
var isTop = originTop <= centerY;
var isBottom = originTop > centerY;
var isCenterX = originLeft >= windowWidth*0.25 && originLeft <= windowWidth*0.75;
var isCenterY = originTop >= windowHeight*0.25 && originTop <= windowHeight*0.75;
// Calculating tap target
var tapTargetWidth = tapTargetEl.outerWidth();
var tapTargetHeight = tapTargetEl.outerHeight();
var tapTargetTop = originTop + originHeight/2 - tapTargetHeight/2;
var tapTargetLeft = originLeft + originWidth/2 - tapTargetWidth/2;
var tapTargetPosition = isFixed ? 'fixed' : 'absolute';
// Calculating content
var tapTargetTextWidth = isCenterX ? tapTargetWidth : tapTargetWidth/2 + originWidth;
var tapTargetTextHeight = tapTargetHeight/2;
var tapTargetTextTop = isTop ? tapTargetHeight/2 : 0;
var tapTargetTextBottom = 0;
var tapTargetTextLeft = isLeft && !isCenterX ? tapTargetWidth/2 - originWidth : 0;
var tapTargetTextRight = 0;
var tapTargetTextPadding = originWidth;
var tapTargetTextAlign = isBottom ? 'bottom' : 'top';
// Calculating wave
var tapTargetWaveWidth = originWidth > originHeight ? originWidth*2 : originWidth*2;
var tapTargetWaveHeight = tapTargetWaveWidth;
var tapTargetWaveTop = tapTargetHeight/2 - tapTargetWaveHeight/2;
var tapTargetWaveLeft = tapTargetWidth/2 - tapTargetWaveWidth/2;
// Setting tap target
var tapTargetWrapperCssObj = {};
tapTargetWrapperCssObj.top = isTop ? tapTargetTop : '';
tapTargetWrapperCssObj.right = isRight ? windowWidth - tapTargetLeft - tapTargetWidth : '';
tapTargetWrapperCssObj.bottom = isBottom ? windowHeight - tapTargetTop - tapTargetHeight : '';
tapTargetWrapperCssObj.left = isLeft ? tapTargetLeft : '';
tapTargetWrapperCssObj.position = tapTargetPosition;
tapTargetWrapper.css(tapTargetWrapperCssObj);
// Setting content
tapTargetContentEl.css({
width: tapTargetTextWidth,
height: tapTargetTextHeight,
top: tapTargetTextTop,
right: tapTargetTextRight,
bottom: tapTargetTextBottom,
left: tapTargetTextLeft,
padding: tapTargetTextPadding,
verticalAlign: tapTargetTextAlign
});
// Setting wave
tapTargetWave.css({
top: tapTargetWaveTop,
left: tapTargetWaveLeft,
width: tapTargetWaveWidth,
height: tapTargetWaveHeight
});
}
if (options == 'open') {
calculateTapTarget();
openTapTarget();
}
if (options == 'close')
closeTapTarget();
});
},
open: function() {},
close: function() {}
};
$.fn.tapTarget = function(methodOrOptions) {
if (methods[methodOrOptions] || typeof methodOrOptions === 'object')
return methods.init.apply( this, arguments );
$.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.tap-target' );
};
}( jQuery ));

View file

@ -0,0 +1,320 @@
(function($, Vel) {
'use strict';
let _defaults = {
displayLength: Infinity,
inDuration: 300,
outDuration: 375,
className: undefined,
completeCallback: undefined,
activationPercent: 0.8
};
class Toast {
constructor(message, displayLength, className, completeCallback) {
if (!message) {
return;
}
/**
* Options for the toast
* @member Toast#options
*/
this.options = {
displayLength: displayLength,
className: className,
completeCallback: completeCallback
};
this.options = $.extend({}, Toast.defaults, this.options);
this.message = message;
/**
* Describes current pan state toast
* @type {Boolean}
*/
this.panning = false;
/**
* Time remaining until toast is removed
*/
this.timeRemaining = this.options.displayLength;
if (Toast._toasts.length === 0) {
Toast._createContainer();
}
// Create new toast
Toast._toasts.push(this);
let toastElement = this.createToast();
toastElement.M_Toast = this;
this.el = toastElement;
this._animateIn();
this.setTimer();
}
static get defaults() {
return _defaults;
}
/**
* Append toast container and add event handlers
*/
static _createContainer() {
let container = document.createElement('div');
container.setAttribute('id', 'toast-container');
// Add event handler
container.addEventListener('touchstart', Toast._onDragStart);
container.addEventListener('touchmove', Toast._onDragMove);
container.addEventListener('touchend', Toast._onDragEnd);
container.addEventListener('mousedown', Toast._onDragStart);
document.addEventListener('mousemove', Toast._onDragMove);
document.addEventListener('mouseup', Toast._onDragEnd);
document.body.appendChild(container);
Toast._container = container;
}
/**
* Remove toast container and event handlers
*/
static _removeContainer() {
// Add event handler
document.removeEventListener('mousemove', Toast._onDragMove);
document.removeEventListener('mouseup', Toast._onDragEnd);
Toast._container.parentNode.removeChild(Toast._container);
Toast._container = null;
}
/**
* Begin drag handler
* @param {Event} e
*/
static _onDragStart(e) {
if (e.target && $(e.target).closest('.toast').length) {
let $toast = $(e.target).closest('.toast');
let toast = $toast[0].M_Toast;
toast.panning = true;
Toast._draggedToast = toast;
toast.el.classList.add('panning');
toast.el.style.transition = '';
toast.startingXPos = Toast._xPos(e);
toast.time = Date.now();
toast.xPos = Toast._xPos(e);
}
}
/**
* Drag move handler
* @param {Event} e
*/
static _onDragMove(e) {
if (!!Toast._draggedToast) {
e.preventDefault();
let toast = Toast._draggedToast;
toast.deltaX = Math.abs(toast.xPos - Toast._xPos(e));
toast.xPos = Toast._xPos(e);
toast.velocityX = toast.deltaX / (Date.now() - toast.time);
toast.time = Date.now();
let totalDeltaX = toast.xPos - toast.startingXPos;
let activationDistance =
toast.el.offsetWidth * toast.options.activationPercent;
toast.el.style.transform = `translateX(${totalDeltaX}px)`;
toast.el.style.opacity = 1-Math.abs(totalDeltaX / activationDistance);
}
}
/**
* End drag handler
* @param {Event} e
*/
static _onDragEnd(e) {
if (!!Toast._draggedToast) {
let toast = Toast._draggedToast;
toast.panning = false;
toast.el.classList.remove('panning');
let totalDeltaX = toast.xPos - toast.startingXPos;
let activationDistance =
toast.el.offsetWidth * toast.options.activationPercent;
let shouldBeDismissed = Math.abs(totalDeltaX) > activationDistance ||
toast.velocityX > 1;
// Remove toast
if (shouldBeDismissed) {
toast.wasSwiped = true;
toast.remove();
// Animate toast back to original position
} else {
toast.el.style.transition = 'transform .2s, opacity .2s';
toast.el.style.transform = '';
toast.el.style.opacity = '';
}
Toast._draggedToast = null;
}
}
/**
* Get x position of mouse or touch event
* @param {Event} e
*/
static _xPos(e) {
if (e.targetTouches && (e.targetTouches.length >= 1)) {
return e.targetTouches[0].clientX;
}
// mouse event
return e.clientX;
}
/**
* Remove all toasts
*/
static removeAll() {
for(let toastIndex in Toast._toasts) {
Toast._toasts[toastIndex].remove();
}
}
/**
* Create toast and append it to toast container
*/
createToast() {
let toast = document.createElement('div');
toast.classList.add('toast');
// Add custom classes onto toast
if (this.options.className) {
let classes = this.options.className.split(' ');
let i, count;
for (i = 0, count = classes.length; i < count; i++) {
toast.classList.add(classes[i]);
}
}
// Set content
if ( typeof HTMLElement === 'object' ?
this.message instanceof HTMLElement :
this.message && typeof this.message === 'object' &&
this.message !== null && this.message.nodeType === 1 &&
typeof this.message.nodeName==='string'
) {
toast.appendChild(this.message);
// Check if it is jQuery object
} else if (this.message instanceof jQuery) {
$(toast).append(this.message);
// Insert as text;
} else {
toast.innerHTML = this.message;
}
// Append toasft
Toast._container.appendChild(toast);
return toast;
}
/**
* Animate in toast
*/
_animateIn() {
// Animate toast in
Vel(this.el, {top: 0, opacity: 1 }, {
duration: 300,
easing: 'easeOutCubic',
queue: false
});
}
/**
* Create setInterval which automatically removes toast when timeRemaining >= 0
* has been reached
*/
setTimer() {
if (this.timeRemaining !== Infinity) {
this.counterInterval = setInterval(() => {
// If toast is not being dragged, decrease its time remaining
if (!this.panning) {
this.timeRemaining -= 20;
}
// Animate toast out
if (this.timeRemaining <= 0) {
this.remove();
}
}, 20);
}
}
/**
* Dismiss toast with animation
*/
remove() {
window.clearInterval(this.counterInterval);
let activationDistance =
this.el.offsetWidth * this.options.activationPercent;
if(this.wasSwiped) {
this.el.style.transition = 'transform .05s, opacity .05s';
this.el.style.transform = `translateX(${activationDistance}px)`;
this.el.style.opacity = 0;
}
Vel(
this.el,
{opacity: 0, marginTop: '-40px'},
{
duration: this.options.outDuration,
easing: 'easeOutExpo',
queue: false,
complete: () => {
// Call the optional callback
if(typeof(this.options.completeCallback) === 'function') {
this.options.completeCallback();
}
// Remove toast from DOM
this.el.parentNode.removeChild(this.el);
Toast._toasts.splice(Toast._toasts.indexOf(this), 1);
if (Toast._toasts.length === 0) {
Toast._removeContainer();
}
}
}
);
}
}
/**
* @static
* @memberof Toast
* @type {Array.<Toast>}
*/
Toast._toasts = [];
/**
* @static
* @memberof Toast
*/
Toast._container = null;
/**
* @static
* @memberof Toast
* @type {Toast}
*/
Toast._draggedToast = null;
Materialize.Toast = Toast;
Materialize.toast = function(message, displayLength, className, completeCallback) {
return new Toast(message, displayLength, className, completeCallback);
};
})(jQuery, Materialize.Vel);

View file

@ -0,0 +1,239 @@
(function ($) {
$.fn.tooltip = function (options) {
var timeout = null,
margin = 5;
// Defaults
var defaults = {
delay: 350,
tooltip: '',
position: 'bottom',
html: false
};
// Remove tooltip from the activator
if (options === "remove") {
this.each(function() {
$('#' + $(this).attr('data-tooltip-id')).remove();
$(this).removeAttr('data-tooltip-id');
$(this).off('mouseenter.tooltip mouseleave.tooltip');
});
return false;
}
options = $.extend(defaults, options);
return this.each(function() {
var tooltipId = Materialize.guid();
var origin = $(this);
// Destroy old tooltip
if (origin.attr('data-tooltip-id')) {
$('#' + origin.attr('data-tooltip-id')).remove();
}
origin.attr('data-tooltip-id', tooltipId);
// Get attributes.
var allowHtml,
tooltipDelay,
tooltipPosition,
tooltipText,
tooltipEl,
backdrop;
var setAttributes = function() {
allowHtml = origin.attr('data-html') ? origin.attr('data-html') === 'true' : options.html;
tooltipDelay = origin.attr('data-delay');
tooltipDelay = (tooltipDelay === undefined || tooltipDelay === '') ?
options.delay : tooltipDelay;
tooltipPosition = origin.attr('data-position');
tooltipPosition = (tooltipPosition === undefined || tooltipPosition === '') ?
options.position : tooltipPosition;
tooltipText = origin.attr('data-tooltip');
tooltipText = (tooltipText === undefined || tooltipText === '') ?
options.tooltip : tooltipText;
};
setAttributes();
var renderTooltipEl = function() {
var tooltip = $('<div class="material-tooltip"></div>');
// Create Text span
if (allowHtml) {
tooltipText = $('<span></span>').html(tooltipText);
} else{
tooltipText = $('<span></span>').text(tooltipText);
}
// Create tooltip
tooltip.append(tooltipText)
.appendTo($('body'))
.attr('id', tooltipId);
// Create backdrop
backdrop = $('<div class="backdrop"></div>');
backdrop.appendTo(tooltip);
return tooltip;
};
tooltipEl = renderTooltipEl();
// Destroy previously binded events
origin.off('mouseenter.tooltip mouseleave.tooltip');
// Mouse In
var started = false, timeoutRef;
origin.on({'mouseenter.tooltip': function(e) {
var showTooltip = function() {
setAttributes();
started = true;
tooltipEl.velocity('stop');
backdrop.velocity('stop');
tooltipEl.css({ visibility: 'visible', left: '0px', top: '0px' });
// Tooltip positioning
var originWidth = origin.outerWidth();
var originHeight = origin.outerHeight();
var tooltipHeight = tooltipEl.outerHeight();
var tooltipWidth = tooltipEl.outerWidth();
var tooltipVerticalMovement = '0px';
var tooltipHorizontalMovement = '0px';
var backdropOffsetWidth = backdrop[0].offsetWidth;
var backdropOffsetHeight = backdrop[0].offsetHeight;
var scaleXFactor = 8;
var scaleYFactor = 8;
var scaleFactor = 0;
var targetTop, targetLeft, newCoordinates;
if (tooltipPosition === "top") {
// Top Position
targetTop = origin.offset().top - tooltipHeight - margin;
targetLeft = origin.offset().left + originWidth/2 - tooltipWidth/2;
newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight);
tooltipVerticalMovement = '-10px';
backdrop.css({
bottom: 0,
left: 0,
borderRadius: '14px 14px 0 0',
transformOrigin: '50% 100%',
marginTop: tooltipHeight,
marginLeft: (tooltipWidth/2) - (backdropOffsetWidth/2)
});
}
// Left Position
else if (tooltipPosition === "left") {
targetTop = origin.offset().top + originHeight/2 - tooltipHeight/2;
targetLeft = origin.offset().left - tooltipWidth - margin;
newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight);
tooltipHorizontalMovement = '-10px';
backdrop.css({
top: '-7px',
right: 0,
width: '14px',
height: '14px',
borderRadius: '14px 0 0 14px',
transformOrigin: '95% 50%',
marginTop: tooltipHeight/2,
marginLeft: tooltipWidth
});
}
// Right Position
else if (tooltipPosition === "right") {
targetTop = origin.offset().top + originHeight/2 - tooltipHeight/2;
targetLeft = origin.offset().left + originWidth + margin;
newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight);
tooltipHorizontalMovement = '+10px';
backdrop.css({
top: '-7px',
left: 0,
width: '14px',
height: '14px',
borderRadius: '0 14px 14px 0',
transformOrigin: '5% 50%',
marginTop: tooltipHeight/2,
marginLeft: '0px'
});
}
else {
// Bottom Position
targetTop = origin.offset().top + origin.outerHeight() + margin;
targetLeft = origin.offset().left + originWidth/2 - tooltipWidth/2;
newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight);
tooltipVerticalMovement = '+10px';
backdrop.css({
top: 0,
left: 0,
marginLeft: (tooltipWidth/2) - (backdropOffsetWidth/2)
});
}
// Set tooptip css placement
tooltipEl.css({
top: newCoordinates.y,
left: newCoordinates.x
});
// Calculate Scale to fill
scaleXFactor = Math.SQRT2 * tooltipWidth / parseInt(backdropOffsetWidth);
scaleYFactor = Math.SQRT2 * tooltipHeight / parseInt(backdropOffsetHeight);
scaleFactor = Math.max(scaleXFactor, scaleYFactor);
tooltipEl.velocity({ translateY: tooltipVerticalMovement, translateX: tooltipHorizontalMovement}, { duration: 350, queue: false })
.velocity({opacity: 1}, {duration: 300, delay: 50, queue: false});
backdrop.css({ visibility: 'visible' })
.velocity({opacity:1},{duration: 55, delay: 0, queue: false})
.velocity({scaleX: scaleFactor, scaleY: scaleFactor}, {duration: 300, delay: 0, queue: false, easing: 'easeInOutQuad'});
};
timeoutRef = setTimeout(showTooltip, tooltipDelay); // End Interval
// Mouse Out
},
'mouseleave.tooltip': function(){
// Reset State
started = false;
clearTimeout(timeoutRef);
// Animate back
setTimeout(function() {
if (started !== true) {
tooltipEl.velocity({
opacity: 0, translateY: 0, translateX: 0}, { duration: 225, queue: false});
backdrop.velocity({opacity: 0, scaleX: 1, scaleY: 1}, {
duration:225,
queue: false,
complete: function(){
backdrop.css({ visibility: 'hidden' });
tooltipEl.css({ visibility: 'hidden' });
started = false;}
});
}
},225);
}
});
});
};
var repositionWithinScreen = function(x, y, width, height) {
var newX = x;
var newY = y;
if (newX < 0) {
newX = 4;
} else if (newX + width > window.innerWidth) {
newX -= newX + width - window.innerWidth;
}
if (newY < 0) {
newY = 4;
} else if (newY + height > window.innerHeight + $(window).scrollTop) {
newY -= newY + height - window.innerHeight;
}
return {x: newX, y: newY};
};
$(document).ready(function(){
$('.tooltipped').tooltip();
});
}( jQuery ));

View file

@ -0,0 +1,169 @@
(function ($) {
// Image transition function
Materialize.fadeInImage = function(selectorOrEl) {
var element;
if (typeof(selectorOrEl) === 'string') {
element = $(selectorOrEl);
} else if (typeof(selectorOrEl) === 'object') {
element = selectorOrEl;
} else {
return;
}
element.css({opacity: 0});
$(element).velocity({opacity: 1}, {
duration: 650,
queue: false,
easing: 'easeOutSine'
});
$(element).velocity({opacity: 1}, {
duration: 1300,
queue: false,
easing: 'swing',
step: function(now, fx) {
fx.start = 100;
var grayscale_setting = now/100;
var brightness_setting = 150 - (100 - now)/1.75;
if (brightness_setting < 100) {
brightness_setting = 100;
}
if (now >= 0) {
$(this).css({
"-webkit-filter": "grayscale("+grayscale_setting+")" + "brightness("+brightness_setting+"%)",
"filter": "grayscale("+grayscale_setting+")" + "brightness("+brightness_setting+"%)"
});
}
}
});
};
// Horizontal staggered list
Materialize.showStaggeredList = function(selectorOrEl) {
var element;
if (typeof(selectorOrEl) === 'string') {
element = $(selectorOrEl);
} else if (typeof(selectorOrEl) === 'object') {
element = selectorOrEl;
} else {
return;
}
var time = 0;
element.find('li').velocity(
{ translateX: "-100px"},
{ duration: 0 });
element.find('li').each(function() {
$(this).velocity(
{ opacity: "1", translateX: "0"},
{ duration: 800, delay: time, easing: [60, 10] });
time += 120;
});
};
$(document).ready(function() {
// Hardcoded .staggered-list scrollFire
// var staggeredListOptions = [];
// $('ul.staggered-list').each(function (i) {
// var label = 'scrollFire-' + i;
// $(this).addClass(label);
// staggeredListOptions.push(
// {selector: 'ul.staggered-list.' + label,
// offset: 200,
// callback: 'showStaggeredList("ul.staggered-list.' + label + '")'});
// });
// scrollFire(staggeredListOptions);
// HammerJS, Swipe navigation
// Touch Event
var swipeLeft = false;
var swipeRight = false;
// Dismissible Collections
$('.dismissable').each(function() {
$(this).hammer({
prevent_default: false
}).on('pan', function(e) {
if (e.gesture.pointerType === "touch") {
var $this = $(this);
var direction = e.gesture.direction;
var x = e.gesture.deltaX;
var velocityX = e.gesture.velocityX;
$this.velocity({ translateX: x
}, {duration: 50, queue: false, easing: 'easeOutQuad'});
// Swipe Left
if (direction === 4 && (x > ($this.innerWidth() / 2) || velocityX < -0.75)) {
swipeLeft = true;
}
// Swipe Right
if (direction === 2 && (x < (-1 * $this.innerWidth() / 2) || velocityX > 0.75)) {
swipeRight = true;
}
}
}).on('panend', function(e) {
// Reset if collection is moved back into original position
if (Math.abs(e.gesture.deltaX) < ($(this).innerWidth() / 2)) {
swipeRight = false;
swipeLeft = false;
}
if (e.gesture.pointerType === "touch") {
var $this = $(this);
if (swipeLeft || swipeRight) {
var fullWidth;
if (swipeLeft) { fullWidth = $this.innerWidth(); }
else { fullWidth = -1 * $this.innerWidth(); }
$this.velocity({ translateX: fullWidth,
}, {duration: 100, queue: false, easing: 'easeOutQuad', complete:
function() {
$this.css('border', 'none');
$this.velocity({ height: 0, padding: 0,
}, {duration: 200, queue: false, easing: 'easeOutQuad', complete:
function() { $this.remove(); }
});
}
});
}
else {
$this.velocity({ translateX: 0,
}, {duration: 100, queue: false, easing: 'easeOutQuad'});
}
swipeLeft = false;
swipeRight = false;
}
});
});
// time = 0
// // Vertical Staggered list
// $('ul.staggered-list.vertical li').velocity(
// { translateY: "100px"},
// { duration: 0 });
// $('ul.staggered-list.vertical li').each(function() {
// $(this).velocity(
// { opacity: "1", translateY: "0"},
// { duration: 800, delay: time, easing: [60, 25] });
// time += 120;
// });
// // Fade in and Scale
// $('.fade-in.scale').velocity(
// { scaleX: .4, scaleY: .4, translateX: -600},
// { duration: 0});
// $('.fade-in').each(function() {
// $(this).velocity(
// { opacity: "1", scaleX: 1, scaleY: 1, translateX: 0},
// { duration: 800, easing: [60, 10] });
// });
});
}( jQuery ));

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,335 @@
/*!
* Waves v0.6.4
* http://fian.my.id/Waves
*
* Copyright 2014 Alfiana E. Sibuea and other contributors
* Released under the MIT license
* https://github.com/fians/Waves/blob/master/LICENSE
*/
;(function(window) {
'use strict';
var Waves = Waves || {};
var $$ = document.querySelectorAll.bind(document);
// Find exact position of element
function isWindow(obj) {
return obj !== null && obj === obj.window;
}
function getWindow(elem) {
return isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView;
}
function offset(elem) {
var docElem, win,
box = {top: 0, left: 0},
doc = elem && elem.ownerDocument;
docElem = doc.documentElement;
if (typeof elem.getBoundingClientRect !== typeof undefined) {
box = elem.getBoundingClientRect();
}
win = getWindow(doc);
return {
top: box.top + win.pageYOffset - docElem.clientTop,
left: box.left + win.pageXOffset - docElem.clientLeft
};
}
function convertStyle(obj) {
var style = '';
for (var a in obj) {
if (obj.hasOwnProperty(a)) {
style += (a + ':' + obj[a] + ';');
}
}
return style;
}
var Effect = {
// Effect delay
duration: 750,
show: function(e, element) {
// Disable right click
if (e.button === 2) {
return false;
}
var el = element || this;
// Create ripple
var ripple = document.createElement('div');
ripple.className = 'waves-ripple';
el.appendChild(ripple);
// Get click coordinate and element witdh
var pos = offset(el);
var relativeY = (e.pageY - pos.top);
var relativeX = (e.pageX - pos.left);
var scale = 'scale('+((el.clientWidth / 100) * 10)+')';
// Support for touch devices
if ('touches' in e) {
relativeY = (e.touches[0].pageY - pos.top);
relativeX = (e.touches[0].pageX - pos.left);
}
// Attach data to element
ripple.setAttribute('data-hold', Date.now());
ripple.setAttribute('data-scale', scale);
ripple.setAttribute('data-x', relativeX);
ripple.setAttribute('data-y', relativeY);
// Set ripple position
var rippleStyle = {
'top': relativeY+'px',
'left': relativeX+'px'
};
ripple.className = ripple.className + ' waves-notransition';
ripple.setAttribute('style', convertStyle(rippleStyle));
ripple.className = ripple.className.replace('waves-notransition', '');
// Scale the ripple
rippleStyle['-webkit-transform'] = scale;
rippleStyle['-moz-transform'] = scale;
rippleStyle['-ms-transform'] = scale;
rippleStyle['-o-transform'] = scale;
rippleStyle.transform = scale;
rippleStyle.opacity = '1';
rippleStyle['-webkit-transition-duration'] = Effect.duration + 'ms';
rippleStyle['-moz-transition-duration'] = Effect.duration + 'ms';
rippleStyle['-o-transition-duration'] = Effect.duration + 'ms';
rippleStyle['transition-duration'] = Effect.duration + 'ms';
rippleStyle['-webkit-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)';
rippleStyle['-moz-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)';
rippleStyle['-o-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)';
rippleStyle['transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)';
ripple.setAttribute('style', convertStyle(rippleStyle));
},
hide: function(e) {
TouchHandler.touchup(e);
var el = this;
var width = el.clientWidth * 1.4;
// Get first ripple
var ripple = null;
var ripples = el.getElementsByClassName('waves-ripple');
if (ripples.length > 0) {
ripple = ripples[ripples.length - 1];
} else {
return false;
}
var relativeX = ripple.getAttribute('data-x');
var relativeY = ripple.getAttribute('data-y');
var scale = ripple.getAttribute('data-scale');
// Get delay beetween mousedown and mouse leave
var diff = Date.now() - Number(ripple.getAttribute('data-hold'));
var delay = 350 - diff;
if (delay < 0) {
delay = 0;
}
// Fade out ripple after delay
setTimeout(function() {
var style = {
'top': relativeY+'px',
'left': relativeX+'px',
'opacity': '0',
// Duration
'-webkit-transition-duration': Effect.duration + 'ms',
'-moz-transition-duration': Effect.duration + 'ms',
'-o-transition-duration': Effect.duration + 'ms',
'transition-duration': Effect.duration + 'ms',
'-webkit-transform': scale,
'-moz-transform': scale,
'-ms-transform': scale,
'-o-transform': scale,
'transform': scale,
};
ripple.setAttribute('style', convertStyle(style));
setTimeout(function() {
try {
el.removeChild(ripple);
} catch(e) {
return false;
}
}, Effect.duration);
}, delay);
},
// Little hack to make <input> can perform waves effect
wrapInput: function(elements) {
for (var a = 0; a < elements.length; a++) {
var el = elements[a];
if (el.tagName.toLowerCase() === 'input') {
var parent = el.parentNode;
// If input already have parent just pass through
if (parent.tagName.toLowerCase() === 'i' && parent.className.indexOf('waves-effect') !== -1) {
continue;
}
// Put element class and style to the specified parent
var wrapper = document.createElement('i');
wrapper.className = el.className + ' waves-input-wrapper';
var elementStyle = el.getAttribute('style');
if (!elementStyle) {
elementStyle = '';
}
wrapper.setAttribute('style', elementStyle);
el.className = 'waves-button-input';
el.removeAttribute('style');
// Put element as child
parent.replaceChild(wrapper, el);
wrapper.appendChild(el);
}
}
}
};
/**
* Disable mousedown event for 500ms during and after touch
*/
var TouchHandler = {
/* uses an integer rather than bool so there's no issues with
* needing to clear timeouts if another touch event occurred
* within the 500ms. Cannot mouseup between touchstart and
* touchend, nor in the 500ms after touchend. */
touches: 0,
allowEvent: function(e) {
var allow = true;
if (e.type === 'touchstart') {
TouchHandler.touches += 1; //push
} else if (e.type === 'touchend' || e.type === 'touchcancel') {
setTimeout(function() {
if (TouchHandler.touches > 0) {
TouchHandler.touches -= 1; //pop after 500ms
}
}, 500);
} else if (e.type === 'mousedown' && TouchHandler.touches > 0) {
allow = false;
}
return allow;
},
touchup: function(e) {
TouchHandler.allowEvent(e);
}
};
/**
* Delegated click handler for .waves-effect element.
* returns null when .waves-effect element not in "click tree"
*/
function getWavesEffectElement(e) {
if (TouchHandler.allowEvent(e) === false) {
return null;
}
var element = null;
var target = e.target || e.srcElement;
while (target.parentNode !== null) {
if (!(target instanceof SVGElement) && target.className.indexOf('waves-effect') !== -1) {
element = target;
break;
}
target = target.parentNode;
}
return element;
}
/**
* Bubble the click and show effect if .waves-effect elem was found
*/
function showEffect(e) {
var element = getWavesEffectElement(e);
if (element !== null) {
Effect.show(e, element);
if ('ontouchstart' in window) {
element.addEventListener('touchend', Effect.hide, false);
element.addEventListener('touchcancel', Effect.hide, false);
}
element.addEventListener('mouseup', Effect.hide, false);
element.addEventListener('mouseleave', Effect.hide, false);
element.addEventListener('dragend', Effect.hide, false);
}
}
Waves.displayEffect = function(options) {
options = options || {};
if ('duration' in options) {
Effect.duration = options.duration;
}
//Wrap input inside <i> tag
Effect.wrapInput($$('.waves-effect'));
if ('ontouchstart' in window) {
document.body.addEventListener('touchstart', showEffect, false);
}
document.body.addEventListener('mousedown', showEffect, false);
};
/**
* Attach Waves to an input element (or any element which doesn't
* bubble mouseup/mousedown events).
* Intended to be used with dynamically loaded forms/inputs, or
* where the user doesn't want a delegated click handler.
*/
Waves.attach = function(element) {
//FUTURE: automatically add waves classes and allow users
// to specify them with an options param? Eg. light/classic/button
if (element.tagName.toLowerCase() === 'input') {
Effect.wrapInput([element]);
element = element.parentNode;
}
if ('ontouchstart' in window) {
element.addEventListener('touchstart', showEffect, false);
}
element.addEventListener('mousedown', showEffect, false);
};
window.Waves = Waves;
document.addEventListener('DOMContentLoaded', function() {
Waves.displayEffect();
}, false);
})(window);

5169
public/css/materialize-src/materialize.css vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,47 @@
// Badges
span.badge {
min-width: 3rem;
padding: 0 6px;
margin-left: 14px;
text-align: center;
font-size: 1rem;
line-height: $badge-height;
height: $badge-height;
color: color('grey', 'darken-1');
float: right;
box-sizing: border-box;
&.new {
font-weight: 300;
font-size: 0.8rem;
color: #fff;
background-color: $badge-bg-color;
border-radius: 2px;
}
&.new:after {
content: " new";
}
&[data-badge-caption]::after {
content: " " attr(data-badge-caption);
}
}
nav ul a span.badge {
display: inline-block;
float: none;
margin-left: 4px;
line-height: $badge-height;
height: $badge-height;
-webkit-font-smoothing: auto;
}
// Line height centering
.collection-item span.badge {
margin-top: calc(#{$collection-line-height / 2} - #{$badge-height / 2});
}
.collapsible span.badge {
margin-left: auto;
}
.side-nav span.badge {
margin-top: calc(#{$sidenav-line-height / 2} - #{$badge-height / 2});
}

View file

@ -0,0 +1,291 @@
// shared styles
.btn,
.btn-flat {
border: $button-border;
border-radius: $button-radius;
display: inline-block;
height: $button-height;
line-height: $button-height;
padding: $button-padding;
text-transform: uppercase;
vertical-align: middle;
// Gets rid of tap active state
-webkit-tap-highlight-color: transparent;
}
// Disabled shared style
.btn.disabled,
.btn-floating.disabled,
.btn-large.disabled,
.btn-flat.disabled,
.btn:disabled,
.btn-floating:disabled,
.btn-large:disabled,
.btn-flat:disabled,
.btn[disabled],
.btn-floating[disabled],
.btn-large[disabled],
.btn-flat[disabled] {
pointer-events: none;
background-color: $button-disabled-background !important;
box-shadow: none;
color: $button-disabled-color !important;
cursor: default;
&:hover {
background-color: $button-disabled-background !important;
color: $button-disabled-color !important;
}
}
// Shared icon styles
.btn,
.btn-floating,
.btn-large,
.btn-flat {
font-size: $button-font-size;
outline: 0;
i {
font-size: $button-icon-font-size;
line-height: inherit;
}
}
// Shared focus button style
.btn,
.btn-floating {
&:focus {
background-color: darken($button-raised-background, 10%);
}
}
// Raised Button
.btn {
text-decoration: none;
color: $button-raised-color;
background-color: $button-raised-background;
text-align: center;
letter-spacing: .5px;
@extend .z-depth-1;
transition: .2s ease-out;
cursor: pointer;
&:hover {
background-color: $button-raised-background-hover;
@extend .z-depth-1-half;
}
}
// Floating button
.btn-floating {
&:hover {
background-color: $button-floating-background-hover;
@extend .z-depth-1-half;
}
&:before {
border-radius: 0;
}
&.btn-large {
&.halfway-fab {
bottom: -$button-floating-large-size / 2;
}
width: $button-floating-large-size;
height: $button-floating-large-size;
i {
line-height: $button-floating-large-size;
}
}
&.halfway-fab {
&.left {
right: auto;
left: 24px;
}
position: absolute;
right: 24px;
bottom: -$button-floating-size / 2;
}
display: inline-block;
color: $button-floating-color;
position: relative;
overflow: hidden;
z-index: 1;
width: $button-floating-size;
height: $button-floating-size;
line-height: $button-floating-size;
padding: 0;
background-color: $button-floating-background;
border-radius: $button-floating-radius;
@extend .z-depth-1;
transition: .3s;
cursor: pointer;
vertical-align: middle;
i {
width: inherit;
display: inline-block;
text-align: center;
color: $button-floating-color;
font-size: $button-large-icon-font-size;
line-height: $button-floating-size;
}
}
// button fix
button.btn-floating {
border: $button-border;
}
// Fixed Action Button
.fixed-action-btn {
&.active {
ul {
visibility: visible;
}
}
&.horizontal {
padding: 0 0 0 15px;
ul {
text-align: right;
right: 64px;
top: 50%;
transform: translateY(-50%);
height: 100%;
left: auto;
width: 500px; /*width 100% only goes to width of button container */
li {
display: inline-block;
margin: 15px 15px 0 0;
}
}
}
&.toolbar {
&.active {
& > a i {
opacity: 0;
}
}
padding: 0;
height: $button-floating-large-size;
ul {
display: flex;
top: 0;
bottom: 0;
z-index: 1;
li {
flex: 1;
display: inline-block;
margin: 0;
height: 100%;
transition: none;
a {
display: block;
overflow: hidden;
position: relative;
width: 100%;
height: 100%;
background-color: transparent;
box-shadow: none;
color: #fff;
line-height: $button-floating-large-size;
z-index: 1;
i {
line-height: inherit;
}
}
}
}
}
position: fixed;
right: 23px;
bottom: 23px;
padding-top: 15px;
margin-bottom: 0;
z-index: 997;
ul {
left: 0;
right: 0;
text-align: center;
position: absolute;
bottom: 64px;
margin: 0;
visibility: hidden;
li {
margin-bottom: 15px;
}
a.btn-floating {
opacity: 0;
}
}
.fab-backdrop {
position: absolute;
top: 0;
left: 0;
z-index: -1;
width: $button-floating-size;
height: $button-floating-size;
background-color: $button-floating-background;
border-radius: $button-floating-radius;
transform: scale(0);
}
}
// Flat button
.btn-flat {
box-shadow: none;
background-color: transparent;
color: $button-flat-color;
cursor: pointer;
transition: background-color .2s;
&:focus,
&:hover {
box-shadow: none;
}
&:focus {
background-color: rgba(0,0,0,.1);
}
&.disabled {
background-color: transparent !important;
color: $button-flat-disabled-color !important;
cursor: default;
}
}
// Large button
.btn-large {
@extend .btn;
height: $button-large-height;
line-height: $button-large-height;
i {
font-size: $button-large-icon-font-size;
}
}
// Block button
.btn-block {
display: block;
}

View file

@ -0,0 +1,196 @@
.card-panel {
transition: box-shadow .25s;
padding: $card-padding;
margin: $element-top-margin 0 $element-bottom-margin 0;
border-radius: 2px;
@extend .z-depth-1;
background-color: $card-bg-color;
}
.card {
position: relative;
margin: $element-top-margin 0 $element-bottom-margin 0;
background-color: $card-bg-color;
transition: box-shadow .25s;
border-radius: 2px;
@extend .z-depth-1;
.card-title {
font-size: 24px;
font-weight: 300;
&.activator {
cursor: pointer;
}
}
// Card Sizes
&.small, &.medium, &.large {
position: relative;
.card-image {
max-height: 60%;
overflow: hidden;
}
.card-image + .card-content {
max-height: 40%;
}
.card-content {
max-height: 100%;
overflow: hidden;
}
.card-action {
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
}
&.small {
height: 300px;
}
&.medium {
height: 400px;
}
&.large {
height: 500px;
}
// Horizontal Cards
&.horizontal {
&.small, &.medium, &.large {
.card-image {
height: 100%;
max-height: none;
overflow: visible;
img {
height: 100%;
}
}
}
display: flex;
.card-image {
max-width: 50%;
img {
border-radius: 2px 0 0 2px;
max-width: 100%;
width: auto;
}
}
.card-stacked {
display: flex;
flex-direction: column;
flex: 1;
position: relative;
.card-content {
flex-grow: 1;
}
}
}
// Sticky Action Section
&.sticky-action {
.card-action {
z-index: 2;
}
.card-reveal {
z-index: 1;
padding-bottom: 64px;
}
}
.card-image {
position: relative;
// Image background for content
img {
display: block;
border-radius: 2px 2px 0 0;
position: relative;
left: 0;
right: 0;
top: 0;
bottom: 0;
width: 100%;
}
.card-title {
color: $card-bg-color;
position: absolute;
bottom: 0;
left: 0;
max-width: 100%;
padding: $card-padding;
}
}
.card-content {
padding: $card-padding;
border-radius: 0 0 2px 2px;
p {
margin: 0;
color: inherit;
}
.card-title {
display: block;
line-height: 32px;
margin-bottom: 8px;
i {
line-height: 32px;
}
}
}
.card-action {
&:last-child {
border-radius: 0 0 2px 2px;
}
position: relative;
background-color: inherit;
border-top: 1px solid rgba(160,160,160,.2);
padding: 16px $card-padding;
a:not(.btn):not(.btn-large):not(.btn-floating) {
color: $card-link-color;
margin-right: $card-padding;
transition: color .3s ease;
text-transform: uppercase;
&:hover { color: $card-link-color-light; }
}
}
.card-reveal {
padding: $card-padding;
position: absolute;
background-color: $card-bg-color;
width: 100%;
overflow-y: auto;
left: 0;
top: 100%;
height: 100%;
z-index: 3;
display: none;
.card-title {
cursor: pointer;
display: block;
}
}
}

View file

@ -0,0 +1,90 @@
.carousel {
&.carousel-slider {
top: 0;
left: 0;
.carousel-fixed-item {
&.with-indicators {
bottom: 68px;
}
position: absolute;
left: 0;
right: 0;
bottom: 20px;
z-index: 1;
}
.carousel-item {
width: 100%;
height: 100%;
min-height: $carousel-height;
position: absolute;
top: 0;
left: 0;
h2 {
font-size: 24px;
font-weight: 500;
line-height: 32px;
}
p {
font-size: 15px;
}
}
}
overflow: hidden;
position: relative;
width: 100%;
height: $carousel-height;
perspective: 500px;
transform-style: preserve-3d;
transform-origin: 0% 50%;
.carousel-item {
display: none;
width: $carousel-item-width;
height: $carousel-item-height;
position: absolute;
top: 0;
left: 0;
& > img {
width: 100%;
}
}
.indicators {
position: absolute;
text-align: center;
left: 0;
right: 0;
bottom: 0;
margin: 0;
.indicator-item {
&.active {
background-color: #fff;
}
display: inline-block;
position: relative;
cursor: pointer;
height: 8px;
width: 8px;
margin: 24px 4px;
background-color: rgba(255,255,255,.5);
transition: background-color .3s;
border-radius: 50%;
}
}
// Materialbox compatibility
&.scrolling .carousel-item .materialboxed,
.carousel-item:not(.active) .materialboxed {
pointer-events: none;
}
}

View file

@ -0,0 +1,89 @@
.chip {
display: inline-block;
height: 32px;
font-size: 13px;
font-weight: 500;
color: rgba(0,0,0,.6);
line-height: 32px;
padding: 0 12px;
border-radius: 16px;
background-color: $chip-bg-color;
margin-bottom: $chip-margin;
margin-right: $chip-margin;
> img {
float: left;
margin: 0 8px 0 -12px;
height: 32px;
width: 32px;
border-radius: 50%;
}
.close {
cursor: pointer;
float: right;
font-size: 16px;
line-height: 32px;
padding-left: 8px;
}
}
.chips {
border: none;
border-bottom: 1px solid $chip-border-color;
box-shadow: none;
margin: $input-margin;
min-height: 45px;
outline: none;
transition: all .3s;
&.focus {
border-bottom: 1px solid $chip-selected-color;
box-shadow: 0 1px 0 0 $chip-selected-color;
}
&:hover {
cursor: text;
}
.chip.selected {
background-color: $chip-selected-color;
color: #fff;
}
.input {
background: none;
border: 0;
color: rgba(0,0,0,.6);
display: inline-block;
font-size: $input-font-size;
height: $input-height;
line-height: 32px;
outline: 0;
margin: 0;
padding: 0 !important;
width: 120px !important;
}
.input:focus {
border: 0 !important;
box-shadow: none !important;
}
// Autocomplete
.autocomplete-content {
margin-top: 0;
margin-bottom: 0;
}
}
// Form prefix
.prefix ~ .chips {
margin-left: 3rem;
width: 92%;
width: calc(100% - 3rem);
}
.chips:empty ~ label {
font-size: 0.8rem;
transform: translateY(-140%);
}

View file

@ -0,0 +1,84 @@
.collapsible {
border-top: 1px solid $collapsible-border-color;
border-right: 1px solid $collapsible-border-color;
border-left: 1px solid $collapsible-border-color;
margin: $element-top-margin 0 $element-bottom-margin 0;
@extend .z-depth-1;
}
.collapsible-header {
display: flex;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
line-height: 1.5;
padding: 1rem;
background-color: $collapsible-header-color;
border-bottom: 1px solid $collapsible-border-color;
i {
width: 2rem;
font-size: 1.6rem;
display: inline-block;
text-align: center;
margin-right: 1rem;
}
}
.collapsible-body {
display: none;
border-bottom: 1px solid $collapsible-border-color;
box-sizing: border-box;
padding: 2rem;
}
// sideNav collapsible styling
.side-nav,
.side-nav.fixed {
.collapsible {
border: none;
box-shadow: none;
li { padding: 0; }
}
.collapsible-header {
background-color: transparent;
border: none;
line-height: inherit;
height: inherit;
padding: 0 $sidenav-padding;
&:hover { background-color: rgba(0,0,0,.05); }
i { line-height: inherit; }
}
.collapsible-body {
border: 0;
background-color: $collapsible-header-color;
li a {
padding: 0 (7.5px + $sidenav-padding)
0 (15px + $sidenav-padding);
}
}
}
// Popout Collapsible
.collapsible.popout {
border: none;
box-shadow: none;
> li {
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
// transform: scaleX(.92);
margin: 0 24px;
transition: margin .35s cubic-bezier(0.250, 0.460, 0.450, 0.940);
}
> li.active {
box-shadow: 0 5px 11px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15);
margin: 16px 0;
// transform: scaleX(1);
}
}

View file

@ -0,0 +1,411 @@
// Utility Color Classes
//.success {
//
//}
// Google Color Palette defined: http://www.google.com/design/spec/style/color.html
$materialize-red: (
"base": #e51c23,
"lighten-5": #fdeaeb,
"lighten-4": #f8c1c3,
"lighten-3": #f3989b,
"lighten-2": #ee6e73,
"lighten-1": #ea454b,
"darken-1": #d0181e,
"darken-2": #b9151b,
"darken-3": #a21318,
"darken-4": #8b1014,
);
$red: (
"base": #F44336,
"lighten-5": #FFEBEE,
"lighten-4": #FFCDD2,
"lighten-3": #EF9A9A,
"lighten-2": #E57373,
"lighten-1": #EF5350,
"darken-1": #E53935,
"darken-2": #D32F2F,
"darken-3": #C62828,
"darken-4": #B71C1C,
"accent-1": #FF8A80,
"accent-2": #FF5252,
"accent-3": #FF1744,
"accent-4": #D50000
);
$pink: (
"base": #e91e63,
"lighten-5": #fce4ec,
"lighten-4": #f8bbd0,
"lighten-3": #f48fb1,
"lighten-2": #f06292,
"lighten-1": #ec407a,
"darken-1": #d81b60,
"darken-2": #c2185b,
"darken-3": #ad1457,
"darken-4": #880e4f,
"accent-1": #ff80ab,
"accent-2": #ff4081,
"accent-3": #f50057,
"accent-4": #c51162
);
$purple: (
"base": #9c27b0,
"lighten-5": #f3e5f5,
"lighten-4": #e1bee7,
"lighten-3": #ce93d8,
"lighten-2": #ba68c8,
"lighten-1": #ab47bc,
"darken-1": #8e24aa,
"darken-2": #7b1fa2,
"darken-3": #6a1b9a,
"darken-4": #4a148c,
"accent-1": #ea80fc,
"accent-2": #e040fb,
"accent-3": #d500f9,
"accent-4": #aa00ff
);
$deep-purple: (
"base": #673ab7,
"lighten-5": #ede7f6,
"lighten-4": #d1c4e9,
"lighten-3": #b39ddb,
"lighten-2": #9575cd,
"lighten-1": #7e57c2,
"darken-1": #5e35b1,
"darken-2": #512da8,
"darken-3": #4527a0,
"darken-4": #311b92,
"accent-1": #b388ff,
"accent-2": #7c4dff,
"accent-3": #651fff,
"accent-4": #6200ea
);
$indigo: (
"base": #3f51b5,
"lighten-5": #e8eaf6,
"lighten-4": #c5cae9,
"lighten-3": #9fa8da,
"lighten-2": #7986cb,
"lighten-1": #5c6bc0,
"darken-1": #3949ab,
"darken-2": #303f9f,
"darken-3": #283593,
"darken-4": #1a237e,
"accent-1": #8c9eff,
"accent-2": #536dfe,
"accent-3": #3d5afe,
"accent-4": #304ffe
);
$blue: (
"base": #27c3f3,
"lighten-5": #E3F2FD,
"lighten-4": #BBDEFB,
"lighten-3": #90CAF9,
"lighten-2": #64B5F6,
"lighten-1": #42A5F5,
"darken-1": #1E88E5,
"darken-2": #1976D2,
"darken-3": #1565C0,
"darken-4": #0D47A1,
"accent-1": #82B1FF,
"accent-2": #448AFF,
"accent-3": #2979FF,
"accent-4": #2962FF
);
$light-blue: (
"base": #03a9f4,
"lighten-5": #e1f5fe,
"lighten-4": #b3e5fc,
"lighten-3": #81d4fa,
"lighten-2": #4fc3f7,
"lighten-1": #29b6f6,
"darken-1": #27c3f3,
"darken-2": #0288d1,
"darken-3": #0277bd,
"darken-4": #01579b,
"accent-1": #80d8ff,
"accent-2": #40c4ff,
"accent-3": #00b0ff,
"accent-4": #0091ea
);
$cyan: (
"base": #00bcd4,
"lighten-5": #e0f7fa,
"lighten-4": #b2ebf2,
"lighten-3": #80deea,
"lighten-2": #4dd0e1,
"lighten-1": #26c6da,
"darken-1": #00acc1,
"darken-2": #0097a7,
"darken-3": #00838f,
"darken-4": #006064,
"accent-1": #84ffff,
"accent-2": #18ffff,
"accent-3": #00e5ff,
"accent-4": #00b8d4
);
$teal: (
"base": #009688,
"lighten-5": #e0f2f1,
"lighten-4": #b2dfdb,
"lighten-3": #80cbc4,
"lighten-2": #4db6ac,
"lighten-1": #26a69a,
"darken-1": #00897b,
"darken-2": #00796b,
"darken-3": #00695c,
"darken-4": #004d40,
"accent-1": #a7ffeb,
"accent-2": #64ffda,
"accent-3": #1de9b6,
"accent-4": #00bfa5
);
$green: (
"base": #4CAF50,
"lighten-5": #E8F5E9,
"lighten-4": #C8E6C9,
"lighten-3": #A5D6A7,
"lighten-2": #81C784,
"lighten-1": #66BB6A,
"darken-1": #43A047,
"darken-2": #388E3C,
"darken-3": #2E7D32,
"darken-4": #1B5E20,
"accent-1": #B9F6CA,
"accent-2": #69F0AE,
"accent-3": #00E676,
"accent-4": #00C853
);
$light-green: (
"base": #8bc34a,
"lighten-5": #f1f8e9,
"lighten-4": #dcedc8,
"lighten-3": #c5e1a5,
"lighten-2": #aed581,
"lighten-1": #9ccc65,
"darken-1": #7cb342,
"darken-2": #689f38,
"darken-3": #558b2f,
"darken-4": #33691e,
"accent-1": #ccff90,
"accent-2": #b2ff59,
"accent-3": #76ff03,
"accent-4": #64dd17
);
$lime: (
"base": #cddc39,
"lighten-5": #f9fbe7,
"lighten-4": #f0f4c3,
"lighten-3": #e6ee9c,
"lighten-2": #dce775,
"lighten-1": #d4e157,
"darken-1": #c0ca33,
"darken-2": #afb42b,
"darken-3": #9e9d24,
"darken-4": #827717,
"accent-1": #f4ff81,
"accent-2": #eeff41,
"accent-3": #c6ff00,
"accent-4": #aeea00
);
$yellow: (
"base": #ffeb3b,
"lighten-5": #fffde7,
"lighten-4": #fff9c4,
"lighten-3": #fff59d,
"lighten-2": #fff176,
"lighten-1": #ffee58,
"darken-1": #fdd835,
"darken-2": #fbc02d,
"darken-3": #f9a825,
"darken-4": #f57f17,
"accent-1": #ffff8d,
"accent-2": #ffff00,
"accent-3": #ffea00,
"accent-4": #ffd600
);
$amber: (
"base": #ffc107,
"lighten-5": #fff8e1,
"lighten-4": #ffecb3,
"lighten-3": #ffe082,
"lighten-2": #ffd54f,
"lighten-1": #ffca28,
"darken-1": #ffb300,
"darken-2": #ffa000,
"darken-3": #ff8f00,
"darken-4": #ff6f00,
"accent-1": #ffe57f,
"accent-2": #ffd740,
"accent-3": #ffc400,
"accent-4": #ffab00
);
$orange: (
"base": #ff9800,
"lighten-5": #fff3e0,
"lighten-4": #ffe0b2,
"lighten-3": #ffcc80,
"lighten-2": #ffb74d,
"lighten-1": #ffa726,
"darken-1": #fb8c00,
"darken-2": #f57c00,
"darken-3": #ef6c00,
"darken-4": #e65100,
"accent-1": #ffd180,
"accent-2": #ffab40,
"accent-3": #ff9100,
"accent-4": #ff6d00
);
$deep-orange: (
"base": #ff5722,
"lighten-5": #fbe9e7,
"lighten-4": #ffccbc,
"lighten-3": #ffab91,
"lighten-2": #ff8a65,
"lighten-1": #ff7043,
"darken-1": #f4511e,
"darken-2": #e64a19,
"darken-3": #d84315,
"darken-4": #bf360c,
"accent-1": #ff9e80,
"accent-2": #ff6e40,
"accent-3": #ff3d00,
"accent-4": #dd2c00
);
$brown: (
"base": #795548,
"lighten-5": #efebe9,
"lighten-4": #d7ccc8,
"lighten-3": #bcaaa4,
"lighten-2": #a1887f,
"lighten-1": #8d6e63,
"darken-1": #6d4c41,
"darken-2": #5d4037,
"darken-3": #4e342e,
"darken-4": #3e2723
);
$blue-grey: (
"base": #607d8b,
"lighten-5": #eceff1,
"lighten-4": #cfd8dc,
"lighten-3": #b0bec5,
"lighten-2": #90a4ae,
"lighten-1": #78909c,
"darken-1": #546e7a,
"darken-2": #455a64,
"darken-3": #37474f,
"darken-4": #263238
);
$grey: (
"base": #9e9e9e,
"lighten-5": #fafafa,
"lighten-4": #f5f5f5,
"lighten-3": #eeeeee,
"lighten-2": #e0e0e0,
"lighten-1": #bdbdbd,
"darken-1": #757575,
"darken-2": #616161,
"darken-3": #424242,
"darken-4": #212121
);
$shades: (
"black": #000000,
"white": #FFFFFF,
"transparent": transparent
);
$colors: (
"materialize-red": $materialize-red,
"red": $red,
"pink": $pink,
"purple": $purple,
"deep-purple": $deep-purple,
"indigo": $indigo,
"blue": $blue,
"light-blue": $light-blue,
"cyan": $cyan,
"teal": $teal,
"green": $green,
"light-green": $light-green,
"lime": $lime,
"yellow": $yellow,
"amber": $amber,
"orange": $orange,
"deep-orange": $deep-orange,
"brown": $brown,
"blue-grey": $blue-grey,
"grey": $grey,
"shades": $shades
) !default;
// Color Classes
@each $color_name, $color in $colors {
@each $color_type, $color_value in $color {
@if $color_type == "base" {
.#{$color_name} {
background-color: $color_value !important;
}
.#{$color_name}-text {
color: $color_value !important;
}
}
@else if $color_name != "shades" {
.#{$color_name}.#{$color_type} {
background-color: $color_value !important;
}
.#{$color_name}-text.text-#{$color_type} {
color: $color_value !important;
}
}
}
}
// Shade classes
@each $color, $color_value in $shades {
.#{$color} {
background-color: $color_value !important;
}
.#{$color}-text {
color: $color_value !important;
}
}
// usage: color("name_of_color", "type_of_color")
// to avoid to repeating map-get($colors, ...)
@function color($color, $type) {
@if map-has-key($colors, $color) {
$curr_color: map-get($colors, $color);
@if map-has-key($curr_color, $type) {
@return map-get($curr_color, $type);
}
}
@warn "Unknown `#{$color}` - `#{$type}` in $colors.";
@return null;
}

View file

@ -0,0 +1,68 @@
.dropdown-content {
@extend .z-depth-1;
background-color: $dropdown-bg-color;
margin: 0;
display: none;
min-width: 100px;
max-height: 650px;
overflow-y: auto;
opacity: 0;
position: absolute;
z-index: 999;
will-change: width, height;
li {
clear: both;
color: $off-black;
cursor: pointer;
min-height: $dropdown-item-height;
line-height: 1.5rem;
width: 100%;
text-align: left;
text-transform: none;
&:hover, &.active, &.selected {
background-color: $dropdown-hover-bg-color;
}
&.active.selected {
background-color: darken($dropdown-hover-bg-color, 5%);
}
&.divider {
min-height: 0;
height: 1px;
}
& > a, & > span {
font-size: 16px;
color: $dropdown-color;
display: block;
line-height: 22px;
padding: (($dropdown-item-height - 22) / 2) 16px;
}
& > span > label {
top: 1px;
left: 0;
height: 18px;
}
// Icon alignment override
& > a > i {
height: inherit;
line-height: inherit;
float: left;
margin: 0 24px 0 0;
width: 24px;
}
}
}
// Input field specificity bugfix
.input-field.col .dropdown-content [type="checkbox"] + label {
top: 1px;
left: 0;
height: 18px;
}

View file

@ -0,0 +1,723 @@
//Default styles
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
// display: flex;
// min-height: 100vh;
// flex-direction: column;
}
main {
// flex: 1 0 auto;
}
a {
color: $link-color;
text-decoration: none;
// Gets rid of tap active state
-webkit-tap-highlight-color: transparent;
}
// Positioning
.valign-wrapper {
display: flex;
align-items: center;
}
// classic clearfix
.clearfix {
clear: both;
}
// Z-levels
.z-depth-0 {
box-shadow: none !important;
}
.z-depth-1 {
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
}
.z-depth-1-half {
box-shadow: 0 3px 3px 0 rgba(0, 0, 0, 0.14), 0 1px 7px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -1px rgba(0, 0, 0, 0.2);
}
.z-depth-2 {
box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
}
.z-depth-3 {
box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.3);
}
.z-depth-4 {
box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.3);
}
.z-depth-5 {
box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.3);
}
.hoverable {
transition: box-shadow .25s;
&:hover {
box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
}
// Dividers
.divider {
height: 1px;
overflow: hidden;
background-color: color("grey", "lighten-2");
}
// Blockquote
blockquote {
margin: 20px 0;
padding-left: 1.5rem;
border-left: 5px solid $primary-color;
}
// Icon Styles
i {
line-height: inherit;
&.left {
float: left;
margin-right: 15px;
}
&.right {
float: right;
margin-left: 15px;
}
&.tiny {
font-size: 1rem;
}
&.small {
font-size: 2rem;
}
&.medium {
font-size: 4rem;
}
&.large {
font-size: 6rem;
}
}
// Images
img.responsive-img,
video.responsive-video {
max-width: 100%;
height: auto;
}
// Pagination
.pagination {
li {
display: inline-block;
border-radius: 2px;
text-align: center;
vertical-align: top;
height: 30px;
a {
color: #444;
display: inline-block;
font-size: 1.2rem;
padding: 0 10px;
line-height: 30px;
}
&.active a { color: #fff; }
&.active { background-color: $primary-color; }
&.disabled a {
cursor: default;
color: #999;
}
i {
font-size: 2rem;
}
}
li.pages ul li {
display: inline-block;
float: none;
}
}
@media #{$medium-and-down} {
.pagination {
width: 100%;
li.prev,
li.next {
width: 10%;
}
li.pages {
width: 80%;
overflow: hidden;
white-space: nowrap;
}
}
}
// Breadcrumbs
.breadcrumb {
font-size: 18px;
color: rgba(255,255,255, .7);
i,
[class^="mdi-"], [class*="mdi-"],
i.material-icons {
display: inline-block;
float: left;
font-size: 24px;
}
&:before {
content: '\E5CC';
color: rgba(255,255,255, .7);
vertical-align: top;
display: inline-block;
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 25px;
margin: 0 10px 0 8px;
-webkit-font-smoothing: antialiased;
}
&:first-child:before {
display: none;
}
&:last-child {
color: #fff;
}
}
// Parallax
.parallax-container {
position: relative;
overflow: hidden;
height: 500px;
.parallax {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
img {
display: none;
position: absolute;
left: 50%;
bottom: 0;
min-width: 100%;
min-height: 100%;
transform: translate3d(0,0,0);
transform: translateX(-50%);
}
}
}
// Pushpin
.pin-top, .pin-bottom {
position: relative;
}
.pinned {
position: fixed !important;
}
/*********************
Transition Classes
**********************/
ul.staggered-list li {
opacity: 0;
}
.fade-in {
opacity: 0;
transform-origin: 0 50%;
}
/*********************
Media Query Classes
**********************/
.hide-on-small-only, .hide-on-small-and-down {
@media #{$small-and-down} {
display: none !important;
}
}
.hide-on-med-and-down {
@media #{$medium-and-down} {
display: none !important;
}
}
.hide-on-med-and-up {
@media #{$medium-and-up} {
display: none !important;
}
}
.hide-on-med-only {
@media only screen and (min-width: $small-screen) and (max-width: $medium-screen) {
display: none !important;
}
}
.hide-on-large-only {
@media #{$large-and-up} {
display: none !important;
}
}
.show-on-large {
@media #{$large-and-up} {
display: block !important;
}
}
.show-on-medium {
@media only screen and (min-width: $small-screen) and (max-width: $medium-screen) {
display: block !important;
}
}
.show-on-small {
@media #{$small-and-down} {
display: block !important;
}
}
.show-on-medium-and-up {
@media #{$medium-and-up} {
display: block !important;
}
}
.show-on-medium-and-down {
@media #{$medium-and-down} {
display: block !important;
}
}
// Center text on mobile
.center-on-small-only {
@media #{$small-and-down} {
text-align: center;
}
}
// Footer
.page-footer {
padding-top: 20px;
color: $footer-font-color;
background-color: $footer-bg-color;
.footer-copyright {
overflow: hidden;
min-height: 50px;
display: flex;
align-items: center;
padding: 10px 0px;
color: $footer-copyright-font-color;
background-color: $footer-copyright-bg-color;
@extend .light;
}
}
// Tables
table, th, td {
border: none;
}
table {
width:100%;
display: table;
&.bordered > thead > tr,
&.bordered > tbody > tr {
border-bottom: 1px solid $table-border-color;
}
&.striped > tbody {
> tr:nth-child(odd) {
background-color: $table-striped-color;
}
> tr > td {
border-radius: 0;
}
}
&.highlight > tbody > tr {
transition: background-color .25s ease;
&:hover {
background-color: $table-striped-color;
}
}
&.centered {
thead tr th, tbody tr td {
text-align: center;
}
}
}
thead {
border-bottom: 1px solid $table-border-color;
}
td, th{
padding: 15px 5px;
display: table-cell;
text-align: left;
vertical-align: middle;
border-radius: 2px;
}
// Responsive Table
@media #{$medium-and-down} {
table.responsive-table {
width: 100%;
border-collapse: collapse;
border-spacing: 0;
display: block;
position: relative;
td:empty:before {
content: '\00a0';
}
th,
td {
margin: 0;
vertical-align: top;
}
th { text-align: left; }
thead {
display: block;
float: left;
tr {
display: block;
padding: 0 10px 0 0;
th::before {
content: "\00a0";
}
}
}
tbody {
display: block;
width: auto;
position: relative;
overflow-x: auto;
white-space: nowrap;
tr {
display: inline-block;
vertical-align: top;
}
}
th {
display: block;
text-align: right;
}
td {
display: block;
min-height: 1.25em;
text-align: left;
}
tr { padding: 0 10px; }
/* sort out borders */
thead {
border: 0;
border-right: 1px solid $table-border-color;
}
&.bordered {
th { border-bottom: 0; border-left: 0; }
td { border-left: 0; border-right: 0; border-bottom: 0; }
tr { border: 0; }
tbody tr { border-right: 1px solid $table-border-color; }
}
}
}
// Collections
.collection {
margin: $element-top-margin 0 $element-bottom-margin 0;
border: 1px solid $collection-border-color;
border-radius: 2px;
overflow: hidden;
position: relative;
.collection-item {
background-color: $collection-bg-color;
line-height: $collection-line-height;
padding: 10px 20px;
margin: 0;
border-bottom: 1px solid $collection-border-color;
// Avatar Collection
&.avatar {
min-height: 84px;
padding-left: 72px;
position: relative;
// Don't style circles inside preloader classes.
&:not(.circle-clipper) > .circle,
:not(.circle-clipper) > .circle {
position: absolute;
width: 42px;
height: 42px;
overflow: hidden;
left: 15px;
display: inline-block;
vertical-align: middle;
}
i.circle {
font-size: 18px;
line-height: 42px;
color: #fff;
background-color: #999;
text-align: center;
}
.title {
font-size: 16px;
}
p {
margin: 0;
}
.secondary-content {
position: absolute;
top: 16px;
right: 16px;
}
}
&:last-child {
border-bottom: none;
}
&.active {
background-color: $collection-active-bg-color;
color: $collection-active-color;
.secondary-content {
color: #fff;
}
}
}
a.collection-item{
display: block;
transition: .25s;
color: $collection-link-color;
&:not(.active) {
&:hover {
background-color: $collection-hover-bg-color;
}
}
}
&.with-header {
.collection-header {
background-color: $collection-bg-color;
border-bottom: 1px solid $collection-border-color;
padding: 10px 20px;
}
.collection-item {
padding-left: 30px;
}
.collection-item.avatar {
padding-left: 72px;
}
}
}
// Made less specific to allow easier overriding
.secondary-content {
float: right;
color: $secondary-color;
}
.collapsible .collection {
margin: 0;
border: none;
}
// Responsive Videos
.video-container {
position: relative;
padding-bottom: 56.25%;
height: 0;
overflow: hidden;
iframe, object, embed {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}
// Progress Bar
.progress {
position: relative;
height: 4px;
display: block;
width: 100%;
background-color: lighten($progress-bar-color, 40%);
border-radius: 2px;
margin: $element-top-margin 0 $element-bottom-margin 0;
overflow: hidden;
.determinate {
position: absolute;
top: 0;
left: 0;
bottom: 0;
background-color: $progress-bar-color;
transition: width .3s linear;
}
.indeterminate {
background-color: $progress-bar-color;
&:before {
content: '';
position: absolute;
background-color: inherit;
top: 0;
left:0;
bottom: 0;
will-change: left, right;
// Custom bezier
animation: indeterminate 2.1s cubic-bezier(0.650, 0.815, 0.735, 0.395) infinite;
}
&:after {
content: '';
position: absolute;
background-color: inherit;
top: 0;
left:0;
bottom: 0;
will-change: left, right;
// Custom bezier
animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.840, 0.440, 1.000) infinite;
animation-delay: 1.15s;
}
}
}
@keyframes indeterminate {
0% {
left: -35%;
right:100%;
}
60% {
left: 100%;
right: -90%;
}
100% {
left: 100%;
right: -90%;
}
}
@keyframes indeterminate-short {
0% {
left: -200%;
right: 100%;
}
60% {
left: 107%;
right: -8%;
}
100% {
left: 107%;
right: -8%;
}
}
/*******************
Utility Classes
*******************/
.hide {
display: none !important;
}
// Text Align
.left-align {
text-align: left;
}
.right-align {
text-align: right
}
.center, .center-align {
text-align: center;
}
.left {
float: left !important;
}
.right {
float: right !important;
}
// No Text Select
.no-select {
user-select: none;
}
.circle {
border-radius: 50%;
}
.center-block {
display: block;
margin-left: auto;
margin-right: auto;
}
.truncate {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.no-padding {
padding: 0 !important;
}

View file

@ -0,0 +1,156 @@
.container {
margin: 0 auto;
max-width: 1280px;
width: 90%;
}
@media #{$medium-and-up} {
.container {
width: 85%;
}
}
@media #{$large-and-up} {
.container {
width: 70%;
}
}
.container .row {
margin-left: (-1 * $gutter-width / 2);
margin-right: (-1 * $gutter-width / 2);
}
.section {
padding-top: 1rem;
padding-bottom: 1rem;
&.no-pad {
padding: 0;
}
&.no-pad-bot {
padding-bottom: 0;
}
&.no-pad-top {
padding-top: 0;
}
}
// Mixins to eliminate code repitition
@mixin reset-offset {
margin-left: auto;
left: auto;
right: auto;
}
@mixin grid-classes($size, $i, $perc) {
&.offset-#{$size}#{$i} {
margin-left: $perc;
}
&.pull-#{$size}#{$i} {
right: $perc;
}
&.push-#{$size}#{$i} {
left: $perc;
}
}
.row {
margin-left: auto;
margin-right: auto;
margin-bottom: 20px;
// Clear floating children
&:after {
content: "";
display: table;
clear: both;
}
.col {
float: left;
box-sizing: border-box;
padding: 0 $gutter-width / 2;
min-height: 1px;
&[class*="push-"],
&[class*="pull-"] {
position: relative;
}
$i: 1;
@while $i <= $num-cols {
$perc: unquote((100 / ($num-cols / $i)) + "%");
&.s#{$i} {
width: $perc;
@include reset-offset;
}
$i: $i + 1;
}
$i: 1;
@while $i <= $num-cols {
$perc: unquote((100 / ($num-cols / $i)) + "%");
@include grid-classes("s", $i, $perc);
$i: $i + 1;
}
@media #{$medium-and-up} {
$i: 1;
@while $i <= $num-cols {
$perc: unquote((100 / ($num-cols / $i)) + "%");
&.m#{$i} {
width: $perc;
@include reset-offset;
}
$i: $i + 1
}
$i: 1;
@while $i <= $num-cols {
$perc: unquote((100 / ($num-cols / $i)) + "%");
@include grid-classes("m", $i, $perc);
$i: $i + 1;
}
}
@media #{$large-and-up} {
$i: 1;
@while $i <= $num-cols {
$perc: unquote((100 / ($num-cols / $i)) + "%");
&.l#{$i} {
width: $perc;
@include reset-offset;
}
$i: $i + 1;
}
$i: 1;
@while $i <= $num-cols {
$perc: unquote((100 / ($num-cols / $i)) + "%");
@include grid-classes("l", $i, $perc);
$i: $i + 1;
}
}
@media #{$extra-large-and-up} {
$i: 1;
@while $i <= $num-cols {
$perc: unquote((100 / ($num-cols / $i)) + "%");
&.xl#{$i} {
width: $perc;
@include reset-offset;
}
$i: $i + 1;
}
$i: 1;
@while $i <= $num-cols {
$perc: unquote((100 / ($num-cols / $i)) + "%");
@include grid-classes("xl", $i, $perc);
$i: $i + 1;
}
}
}
}

View file

@ -0,0 +1,5 @@
/* This is needed for some mobile phones to display the Google Icon font properly */
.material-icons {
text-rendering: optimizeLegibility;
font-feature-settings: 'liga';
}

View file

@ -0,0 +1,43 @@
.materialboxed {
&:hover {
&:not(.active) {
opacity: .8;
}
}
display: block;
cursor: zoom-in;
position: relative;
transition: opacity .4s;
-webkit-backface-visibility: hidden;
&.active {
cursor: zoom-out;
}
}
#materialbox-overlay {
position:fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: #292929;
z-index: 1000;
will-change: opacity;
}
.materialbox-caption {
position: fixed;
display: none;
color: #fff;
line-height: 50px;
bottom: 0;
left: 0;
width: 100%;
text-align: center;
padding: 0% 15%;
height: 50px;
z-index: 1000;
-webkit-font-smoothing: antialiased;
}

View file

@ -0,0 +1,90 @@
.modal {
@extend .z-depth-4;
display: none;
position: fixed;
left: 0;
right: 0;
background-color: #fafafa;
padding: 0;
max-height: 70%;
width: 55%;
margin: auto;
overflow-y: auto;
border-radius: 2px;
will-change: top, opacity;
@media #{$medium-and-down} {
width: 80%;
}
h1,h2,h3,h4 {
margin-top: 0;
}
.modal-content {
padding: 24px;
}
.modal-close {
cursor: pointer;
}
.modal-footer {
border-radius: 0 0 2px 2px;
background-color: #fafafa;
padding: 4px 6px;
height: 56px;
width: 100%;
text-align: right;
.btn, .btn-flat {
margin: 6px 0;
}
}
}
.modal-overlay {
position: fixed;
z-index: 999;
top: -25%;
left: 0;
bottom: 0;
right: 0;
height: 125%;
width: 100%;
background: #000;
display: none;
will-change: opacity;
}
// Modal with fixed action footer
.modal.modal-fixed-footer {
padding: 0;
height: 70%;
.modal-content {
position: absolute;
height: calc(100% - 56px);
max-height: 100%;
width: 100%;
overflow-y: auto;
}
.modal-footer {
border-top: 1px solid rgba(0,0,0,.1);
position: absolute;
bottom: 0;
}
}
// Modal Bottom Sheet Style
.modal.bottom-sheet {
top: auto;
bottom: -100%;
margin: 0;
width: 100%;
max-height: 45%;
border-radius: 0;
will-change: bottom, opacity;
}

View file

@ -0,0 +1,208 @@
nav {
&.nav-extended {
height: auto;
.nav-wrapper {
min-height: $navbar-height-mobile;
height: auto;
}
.nav-content {
position: relative;
line-height: normal;
}
}
color: $navbar-font-color;
@extend .z-depth-1;
background-color: $primary-color;
width: 100%;
height: $navbar-height-mobile;
line-height: $navbar-line-height-mobile;
a { color: $navbar-font-color; }
i,
[class^="mdi-"], [class*="mdi-"],
i.material-icons {
display: block;
font-size: 24px;
height: $navbar-height-mobile;
line-height: $navbar-line-height-mobile;
}
.nav-wrapper {
position: relative;
height: 100%;
}
@media #{$large-and-up} {
a.button-collapse { display: none; }
}
// Collapse button
.button-collapse {
float: left;
position: relative;
z-index: 1;
height: $navbar-height-mobile;
margin: 0 18px;
i {
height: $navbar-height-mobile;
line-height: $navbar-line-height-mobile;
}
}
// Logo
.brand-logo {
position: absolute;
color: $navbar-font-color;
display: inline-block;
font-size: $navbar-brand-font-size;
padding: 0;
&.center {
left: 50%;
transform: translateX(-50%);
}
@media #{$medium-and-down} {
left: 50%;
transform: translateX(-50%);
&.left, &.right {
padding: 0;
transform: none;
}
&.left { left: 0.5rem; }
&.right {
right: 0.5rem;
left: auto;
}
}
&.right {
right: 0.5rem;
padding: 0;
}
i,
[class^="mdi-"], [class*="mdi-"],
i.material-icons {
float: left;
margin-right: 15px;
}
}
// Title
.nav-title {
display: inline-block;
font-size: 32px;
padding: 28px 0;
}
// Navbar Links
ul {
margin: 0;
li {
transition: background-color .3s;
float: left;
padding: 0;
&.active {
background-color: rgba(0,0,0,.1);
}
}
a {
transition: background-color .3s;
font-size: $navbar-font-size;
color: $navbar-font-color;
display: block;
padding: 0 15px;
cursor: pointer;
&.btn, &.btn-large, &.btn-flat, &.btn-floating {
margin-top: -2px;
margin-left: 15px;
margin-right: 15px;
& > .material-icons {
height: inherit;
line-height: inherit;
}
}
&:hover {
background-color: rgba(0,0,0,.1);
}
}
&.left {
float: left;
}
}
// Navbar Search Form
form {
height: 100%;
}
.input-field {
margin: 0;
height: 100%;
input {
height: 100%;
font-size: 1.2rem;
border: none;
padding-left: 2rem;
&:focus, &[type=text]:valid, &[type=password]:valid,
&[type=email]:valid, &[type=url]:valid, &[type=date]:valid {
border: none;
box-shadow: none;
}
}
label {
top: 0;
left: 0;
i {
color: rgba(255,255,255,.7);
transition: color .3s;
}
&.active i { color: $navbar-font-color; }
}
}
}
// Fixed Navbar
.navbar-fixed {
position: relative;
height: $navbar-height-mobile;
z-index: 997;
nav {
position: fixed;
}
}
@media #{$medium-and-up} {
nav.nav-extended .nav-wrapper {
min-height: $navbar-height;
}
nav, nav .nav-wrapper i, nav a.button-collapse, nav a.button-collapse i {
height: $navbar-height;
line-height: $navbar-line-height;
}
.navbar-fixed {
height: $navbar-height;
}
}

View file

@ -0,0 +1,424 @@
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS and IE text size adjust after device orientation change,
* without disabling user zoom.
*/
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined for any HTML5 element in IE 8/9.
* Correct `block` display not defined for `details` or `summary` in IE 10/11
* and Firefox.
* Correct `block` display not defined for `main` in IE 11.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
menu,
nav,
section,
summary {
display: block;
}
/**
* 1. Correct `inline-block` display not defined in IE 8/9.
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
*/
audio,
canvas,
progress,
video {
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Address `[hidden]` styling not present in IE 8/9/10.
* Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
*/
[hidden],
template {
display: none;
}
/* Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* Improve readability of focused elements when they are also in an
* active/hover state.
*/
a:active,
a:hover {
outline: 0;
}
/* Text-level semantics
========================================================================== */
/**
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
}
/**
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
*/
b,
strong {
font-weight: bold;
}
/**
* Address styling not present in Safari and Chrome.
*/
dfn {
font-style: italic;
}
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9.
*/
mark {
background: #ff0;
color: #000;
}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9/10.
*/
img {
border: 0;
}
/**
* Correct overflow not hidden in IE 9/10/11.
*/
svg:not(:root) {
overflow: hidden;
}
/* Grouping content
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari.
*/
figure {
margin: 1em 40px;
}
/**
* Address differences between Firefox and other browsers.
*/
hr {
box-sizing: content-box;
height: 0;
}
/**
* Contain overflow in all browsers.
*/
pre {
overflow: auto;
}
/**
* Address odd `em`-unit font size rendering in all browsers.
*/
code,
kbd,
pre,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
/* Forms
========================================================================== */
/**
* Known limitation: by default, Chrome and Safari on OS X allow very limited
* styling of `select`, unless a `border` property is set.
*/
/**
* 1. Correct color not being inherited.
* Known issue: affects color of disabled elements.
* 2. Correct font properties not being inherited.
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
*/
button,
input,
optgroup,
select,
textarea {
color: inherit; /* 1 */
font: inherit; /* 2 */
margin: 0; /* 3 */
}
/**
* Address `overflow` set to `hidden` in IE 8/9/10/11.
*/
button {
overflow: visible;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
* Correct `select` style inheritance in Firefox.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
input {
line-height: normal;
}
/**
* It's recommended that you don't attempt to style these elements.
* Firefox's implementation doesn't respect box-sizing, padding, or width.
*
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
* `font-size` values of the `input`, it causes the cursor style of the
* decrement button to change from `default` to `text`.
*/
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
*/
input[type="search"] {
-webkit-appearance: textfield; /* 1 */
box-sizing: content-box; /* 2 */
}
/**
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
* Safari (but not Chrome) clips the cancel button when the search input has
* padding (and `textfield` appearance).
*/
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Define consistent border, margin, and padding.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/**
* 1. Correct `color` not being inherited in IE 8/9/10/11.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
}
/**
* Remove default vertical scrollbar in IE 8/9/10/11.
*/
textarea {
overflow: auto;
}
/**
* Don't inherit the `font-weight` (applied by a rule above).
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
*/
optgroup {
font-weight: bold;
}
/* Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}
td,
th {
padding: 0;
}

View file

@ -0,0 +1,334 @@
/*
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
/**************************/
/* STYLES FOR THE SPINNER */
/**************************/
/*
* Constants:
* STROKEWIDTH = 3px
* ARCSIZE = 270 degrees (amount of circle the arc takes up)
* ARCTIME = 1333ms (time it takes to expand and contract arc)
* ARCSTARTROT = 216 degrees (how much the start location of the arc
* should rotate each time, 216 gives us a
* 5 pointed star shape (it's 360/5 * 3).
* For a 7 pointed star, we might do
* 360/7 * 3 = 154.286)
* CONTAINERWIDTH = 28px
* SHRINK_TIME = 400ms
*/
.preloader-wrapper {
display: inline-block;
position: relative;
width: 50px;
height: 50px;
&.small {
width: 36px;
height: 36px;
}
&.big {
width: 64px;
height: 64px;
}
&.active {
/* duration: 360 * ARCTIME / (ARCSTARTROT + (360-ARCSIZE)) */
-webkit-animation: container-rotate 1568ms linear infinite;
animation: container-rotate 1568ms linear infinite;
}
}
@-webkit-keyframes container-rotate {
to { -webkit-transform: rotate(360deg) }
}
@keyframes container-rotate {
to { transform: rotate(360deg) }
}
.spinner-layer {
position: absolute;
width: 100%;
height: 100%;
opacity: 0;
border-color: $spinner-default-color;
}
.spinner-blue,
.spinner-blue-only {
border-color: #4285f4;
}
.spinner-red,
.spinner-red-only {
border-color: #db4437;
}
.spinner-yellow,
.spinner-yellow-only {
border-color: #f4b400;
}
.spinner-green,
.spinner-green-only {
border-color: #0f9d58;
}
/**
* IMPORTANT NOTE ABOUT CSS ANIMATION PROPERTIES (keanulee):
*
* iOS Safari (tested on iOS 8.1) does not handle animation-delay very well - it doesn't
* guarantee that the animation will start _exactly_ after that value. So we avoid using
* animation-delay and instead set custom keyframes for each color (as redundant as it
* seems).
*
* We write out each animation in full (instead of separating animation-name,
* animation-duration, etc.) because under the polyfill, Safari does not recognize those
* specific properties properly, treats them as -webkit-animation, and overrides the
* other animation rules. See https://github.com/Polymer/platform/issues/53.
*/
.active .spinner-layer.spinner-blue {
/* durations: 4 * ARCTIME */
-webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
.active .spinner-layer.spinner-red {
/* durations: 4 * ARCTIME */
-webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
.active .spinner-layer.spinner-yellow {
/* durations: 4 * ARCTIME */
-webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
.active .spinner-layer.spinner-green {
/* durations: 4 * ARCTIME */
-webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
.active .spinner-layer,
.active .spinner-layer.spinner-blue-only,
.active .spinner-layer.spinner-red-only,
.active .spinner-layer.spinner-yellow-only,
.active .spinner-layer.spinner-green-only {
/* durations: 4 * ARCTIME */
opacity: 1;
-webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
@-webkit-keyframes fill-unfill-rotate {
12.5% { -webkit-transform: rotate(135deg); } /* 0.5 * ARCSIZE */
25% { -webkit-transform: rotate(270deg); } /* 1 * ARCSIZE */
37.5% { -webkit-transform: rotate(405deg); } /* 1.5 * ARCSIZE */
50% { -webkit-transform: rotate(540deg); } /* 2 * ARCSIZE */
62.5% { -webkit-transform: rotate(675deg); } /* 2.5 * ARCSIZE */
75% { -webkit-transform: rotate(810deg); } /* 3 * ARCSIZE */
87.5% { -webkit-transform: rotate(945deg); } /* 3.5 * ARCSIZE */
to { -webkit-transform: rotate(1080deg); } /* 4 * ARCSIZE */
}
@keyframes fill-unfill-rotate {
12.5% { transform: rotate(135deg); } /* 0.5 * ARCSIZE */
25% { transform: rotate(270deg); } /* 1 * ARCSIZE */
37.5% { transform: rotate(405deg); } /* 1.5 * ARCSIZE */
50% { transform: rotate(540deg); } /* 2 * ARCSIZE */
62.5% { transform: rotate(675deg); } /* 2.5 * ARCSIZE */
75% { transform: rotate(810deg); } /* 3 * ARCSIZE */
87.5% { transform: rotate(945deg); } /* 3.5 * ARCSIZE */
to { transform: rotate(1080deg); } /* 4 * ARCSIZE */
}
@-webkit-keyframes blue-fade-in-out {
from { opacity: 1; }
25% { opacity: 1; }
26% { opacity: 0; }
89% { opacity: 0; }
90% { opacity: 1; }
100% { opacity: 1; }
}
@keyframes blue-fade-in-out {
from { opacity: 1; }
25% { opacity: 1; }
26% { opacity: 0; }
89% { opacity: 0; }
90% { opacity: 1; }
100% { opacity: 1; }
}
@-webkit-keyframes red-fade-in-out {
from { opacity: 0; }
15% { opacity: 0; }
25% { opacity: 1; }
50% { opacity: 1; }
51% { opacity: 0; }
}
@keyframes red-fade-in-out {
from { opacity: 0; }
15% { opacity: 0; }
25% { opacity: 1; }
50% { opacity: 1; }
51% { opacity: 0; }
}
@-webkit-keyframes yellow-fade-in-out {
from { opacity: 0; }
40% { opacity: 0; }
50% { opacity: 1; }
75% { opacity: 1; }
76% { opacity: 0; }
}
@keyframes yellow-fade-in-out {
from { opacity: 0; }
40% { opacity: 0; }
50% { opacity: 1; }
75% { opacity: 1; }
76% { opacity: 0; }
}
@-webkit-keyframes green-fade-in-out {
from { opacity: 0; }
65% { opacity: 0; }
75% { opacity: 1; }
90% { opacity: 1; }
100% { opacity: 0; }
}
@keyframes green-fade-in-out {
from { opacity: 0; }
65% { opacity: 0; }
75% { opacity: 1; }
90% { opacity: 1; }
100% { opacity: 0; }
}
/**
* Patch the gap that appear between the two adjacent div.circle-clipper while the
* spinner is rotating (appears on Chrome 38, Safari 7.1, and IE 11).
*/
.gap-patch {
position: absolute;
top: 0;
left: 45%;
width: 10%;
height: 100%;
overflow: hidden;
border-color: inherit;
}
.gap-patch .circle {
width: 1000%;
left: -450%;
}
.circle-clipper {
display: inline-block;
position: relative;
width: 50%;
height: 100%;
overflow: hidden;
border-color: inherit;
.circle {
width: 200%;
height: 100%;
border-width: 3px; /* STROKEWIDTH */
border-style: solid;
border-color: inherit;
border-bottom-color: transparent !important;
border-radius: 50%;
-webkit-animation: none;
animation: none;
position: absolute;
top: 0;
right: 0;
bottom: 0;
}
&.left .circle {
left: 0;
border-right-color: transparent !important;
-webkit-transform: rotate(129deg);
transform: rotate(129deg);
}
&.right .circle {
left: -100%;
border-left-color: transparent !important;
-webkit-transform: rotate(-129deg);
transform: rotate(-129deg);
}
}
.active .circle-clipper.left .circle {
/* duration: ARCTIME */
-webkit-animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
.active .circle-clipper.right .circle {
/* duration: ARCTIME */
-webkit-animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
@-webkit-keyframes left-spin {
from { -webkit-transform: rotate(130deg); }
50% { -webkit-transform: rotate(-5deg); }
to { -webkit-transform: rotate(130deg); }
}
@keyframes left-spin {
from { transform: rotate(130deg); }
50% { transform: rotate(-5deg); }
to { transform: rotate(130deg); }
}
@-webkit-keyframes right-spin {
from { -webkit-transform: rotate(-130deg); }
50% { -webkit-transform: rotate(5deg); }
to { -webkit-transform: rotate(-130deg); }
}
@keyframes right-spin {
from { transform: rotate(-130deg); }
50% { transform: rotate(5deg); }
to { transform: rotate(-130deg); }
}
#spinnerContainer.cooldown {
/* duration: SHRINK_TIME */
-webkit-animation: container-rotate 1568ms linear infinite, fade-out 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
animation: container-rotate 1568ms linear infinite, fade-out 400ms cubic-bezier(0.4, 0.0, 0.2, 1);
}
@-webkit-keyframes fade-out {
from { opacity: 1; }
to { opacity: 0; }
}
@keyframes fade-out {
from { opacity: 1; }
to { opacity: 0; }
}

View file

@ -0,0 +1,34 @@
.pulse {
&::before {
content: '';
display: block;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: inherit;
border-radius: inherit;
transition: opacity .3s, transform .3s;
animation: pulse-animation 1s cubic-bezier(0.24, 0, 0.38, 1) infinite;
z-index: -1;
}
overflow: initial;
position: relative;
}
@keyframes pulse-animation {
0% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0;
transform: scale(1.5);
}
100% {
opacity: 0;
transform: scale(1.5);
}
}

View file

@ -0,0 +1,39 @@
@font-face {
font-family: "Roboto";
src: local(Roboto Thin),
url("#{$roboto-font-path}Roboto-Thin.woff2") format("woff2"),
url("#{$roboto-font-path}Roboto-Thin.woff") format("woff");
font-weight: 100;
}
@font-face {
font-family: "Roboto";
src: local(Roboto Light),
url("#{$roboto-font-path}Roboto-Light.woff2") format("woff2"),
url("#{$roboto-font-path}Roboto-Light.woff") format("woff");
font-weight: 300;
}
@font-face {
font-family: "Roboto";
src: local(Roboto Regular),
url("#{$roboto-font-path}Roboto-Regular.woff2") format("woff2"),
url("#{$roboto-font-path}Roboto-Regular.woff") format("woff");
font-weight: 400;
}
@font-face {
font-family: "Roboto";
src: local(Roboto Medium),
url("#{$roboto-font-path}Roboto-Medium.woff2") format("woff2"),
url("#{$roboto-font-path}Roboto-Medium.woff") format("woff");
font-weight: 500;
}
@font-face {
font-family: "Roboto";
src: local(Roboto Bold),
url("#{$roboto-font-path}Roboto-Bold.woff2") format("woff2"),
url("#{$roboto-font-path}Roboto-Bold.woff") format("woff");
font-weight: 700;
}

View file

@ -0,0 +1,214 @@
.side-nav {
position: fixed;
width: 300px;
left: 0;
top: 0;
margin: 0;
transform: translateX(-100%);
height: 100%;
height: calc(100% + 60px);
height: -moz-calc(100%); //Temporary Firefox Fix
padding-bottom: 60px;
background-color: $sidenav-bg-color;
z-index: 999;
overflow-y: auto;
will-change: transform;
backface-visibility: hidden;
transform: translateX(-105%);
@extend .z-depth-1;
// Right Align
&.right-aligned {
right: 0;
transform: translateX(105%);
left: auto;
transform: translateX(100%);
}
.collapsible {
margin: 0;
}
li {
float: none;
line-height: $sidenav-line-height;
&.active { background-color: rgba(0,0,0,.05); }
}
li > a {
color: $sidenav-font-color;
display: block;
font-size: $sidenav-font-size;
font-weight: 500;
height: $sidenav-item-height;
line-height: $sidenav-line-height;
padding: 0 ($sidenav-padding * 2);
&:hover { background-color: rgba(0,0,0,.05);}
&.btn, &.btn-large, &.btn-flat, &.btn-floating {
margin: 10px 15px;
}
&.btn,
&.btn-large,
&.btn-floating { color: $button-raised-color; }
&.btn-flat { color: $button-flat-color; }
&.btn:hover,
&.btn-large:hover { background-color: lighten($button-raised-background, 5%); }
&.btn-floating:hover { background-color: $button-raised-background; }
& > i,
& > [class^="mdi-"], li > a > [class*="mdi-"],
& > i.material-icons {
float: left;
height: $sidenav-item-height;
line-height: $sidenav-line-height;
margin: 0 ($sidenav-padding * 2) 0 0;
width: $sidenav-item-height / 2;
color: rgba(0,0,0,.54);
}
}
.divider {
margin: ($sidenav-padding / 2) 0 0 0;
}
.subheader {
&:hover {
background-color: transparent;
}
cursor: initial;
pointer-events: none;
color: rgba(0,0,0,.54);
font-size: $sidenav-font-size;
font-weight: 500;
line-height: $sidenav-line-height;
}
.user-view,
.userView {
position: relative;
padding: ($sidenav-padding * 2) ($sidenav-padding * 2) 0;
margin-bottom: $sidenav-padding / 2;
& > a {
&:hover { background-color: transparent; }
height: auto;
padding: 0;
}
.background {
overflow: hidden;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: -1;
}
.circle, .name, .email {
display: block;
}
.circle {
height: 64px;
width: 64px;
}
.name,
.email {
font-size: $sidenav-font-size;
line-height: $sidenav-line-height / 2;
}
.name {
margin-top: 16px;
font-weight: 500;
}
.email {
padding-bottom: 16px;
font-weight: 400;
}
}
}
// Touch interaction
.drag-target {
height: 100%;
width: 10px;
position: fixed;
top: 0;
z-index: 998;
}
// Fixed side-nav shown
.side-nav.fixed {
left: 0;
transform: translateX(0);
position: fixed;
// Right Align
&.right-aligned {
right: 0;
left: auto;
}
}
// Fixed sideNav hide on smaller
@media #{$medium-and-down} {
.side-nav {
&.fixed {
transform: translateX(-105%);
&.right-aligned {
transform: translateX(105%);
}
}
a {
padding: 0 $sidenav-padding;
}
.user-view,
.userView {
padding: $sidenav-padding $sidenav-padding 0;
}
}
}
.side-nav .collapsible-body > ul:not(.collapsible) > li.active,
.side-nav.fixed .collapsible-body > ul:not(.collapsible) > li.active {
background-color: $primary-color;
a {
color: $sidenav-bg-color;
}
}
.side-nav .collapsible-body {
padding: 0;
}
#sidenav-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 120vh;
background-color: rgba(0,0,0,.5);
z-index: 997;
will-change: opacity;
}

View file

@ -0,0 +1,92 @@
.slider {
position: relative;
height: 400px;
width: 100%;
// Fullscreen slider
&.fullscreen {
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
ul.slides {
height: 100%;
}
ul.indicators {
z-index: 2;
bottom: 30px;
}
}
.slides {
background-color: $slider-bg-color;
margin: 0;
height: 400px;
li {
opacity: 0;
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: inherit;
overflow: hidden;
img {
height: 100%;
width: 100%;
background-size: cover;
background-position: center;
}
.caption {
color: #fff;
position: absolute;
top: 15%;
left: 15%;
width: 70%;
opacity: 0;
p { color: $slider-bg-color-light; }
}
&.active {
z-index: 2;
}
}
}
.indicators {
position: absolute;
text-align: center;
left: 0;
right: 0;
bottom: 0;
margin: 0;
.indicator-item {
display: inline-block;
position: relative;
cursor: pointer;
height: 16px;
width: 16px;
margin: 0 12px;
background-color: $slider-bg-color-light;
transition: background-color .3s;
border-radius: 50%;
&.active {
background-color: $slider-indicator-color;
}
}
}
}

View file

@ -0,0 +1,33 @@
/***************
Nav List
***************/
.table-of-contents {
&.fixed {
position: fixed;
}
li {
padding: 2px 0;
}
a {
display: inline-block;
font-weight: 300;
color: #757575;
padding-left: 20px;
height: 1.5rem;
line-height: 1.5rem;
letter-spacing: .4;
display: inline-block;
&:hover {
color: lighten(#757575, 20%);
padding-left: 19px;
border-left: 1px solid $primary-color;
}
&.active {
font-weight: 500;
padding-left: 18px;
border-left: 2px solid $primary-color;
}
}
}

Some files were not shown because too many files have changed in this diff Show more